improve fonts and UI

This commit is contained in:
achraf
2026-05-03 19:59:53 +02:00
parent 16e7547fcc
commit 02d7b7918e
11 changed files with 4266 additions and 142 deletions

View File

@@ -33,7 +33,7 @@ html {
body { body {
background: #07080a; background: #07080a;
color: #e2e4e9; color: #e2e4e9;
font-family: var(--font-lora), Georgia, serif; font-family: var(--font-jetbrains), monospace;
overflow-x: hidden; overflow-x: hidden;
} }
@@ -351,6 +351,43 @@ body {
nav a:hover .nav-underline { transform: scaleX(1) !important; } nav a:hover .nav-underline { transform: scaleX(1) !important; }
/* ── Hero creative bento grid ───────────────────────────────── */
.creative-bento-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
width: 100%;
position: relative;
}
.bento-span-2x2 { grid-column: span 2; grid-row: span 2; }
.bento-span-2x1 { grid-column: span 2; grid-row: span 1; }
.bento-span-1x1 { grid-column: span 1; grid-row: span 1; }
@media (max-width: 1024px) {
.creative-bento-grid {
grid-template-columns: repeat(2, 1fr);
}
.bento-span-2x2 { grid-column: span 2; grid-row: span 2; }
.bento-span-2x1 { grid-column: span 2; grid-row: span 1; }
.bento-span-1x1 { grid-column: span 1; grid-row: span 1; }
}
@media (max-width: 600px) {
.creative-bento-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.bento-span-2x2, .bento-span-2x1, .bento-span-1x1 {
grid-column: span 1;
grid-row: auto;
}
}
.glow-text {
text-shadow: 0 0 24px rgba(200, 169, 110, 0.4);
}
.headline-cursor { .headline-cursor {
display: inline-block; display: inline-block;
width: 3px; width: 3px;

View File

@@ -1,5 +1,5 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Bebas_Neue, JetBrains_Mono, Lora } from "next/font/google"; import { Bebas_Neue, JetBrains_Mono } from "next/font/google";
import "./globals.css"; import "./globals.css";
import GridCanvas from "@/components/GridCanvas"; import GridCanvas from "@/components/GridCanvas";
@@ -15,12 +15,6 @@ const jetbrains = JetBrains_Mono({
weight: ["400", "500"], weight: ["400", "500"],
}); });
const lora = Lora({
variable: "--font-lora",
subsets: ["latin"],
weight: ["400", "500"],
});
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Achraf Achkari — Technical Lead & Software Engineer", title: "Achraf Achkari — Technical Lead & Software Engineer",
description: description:
@@ -36,7 +30,7 @@ export default function RootLayout({
return ( return (
<html <html
lang="en" lang="en"
className={`${bebas.variable} ${jetbrains.variable} ${lora.variable} h-full`} className={`${bebas.variable} ${jetbrains.variable} h-full`}
> >
<body className="min-h-full flex flex-col antialiased" suppressHydrationWarning> <body className="min-h-full flex flex-col antialiased" suppressHydrationWarning>
<GridCanvas /> <GridCanvas />

View File

@@ -159,7 +159,7 @@ export default function Contact({ contact, fullName, image }: ContactProps) {
<p <p
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.9rem", fontSize: "0.9rem",
lineHeight: 1.8, lineHeight: 1.8,
color: "#6b7280", color: "#6b7280",
@@ -225,7 +225,7 @@ export default function Contact({ contact, fullName, image }: ContactProps) {
</div> </div>
<div <div
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.9rem", fontSize: "0.9rem",
color: "inherit", color: "inherit",
}} }}

View File

@@ -39,7 +39,6 @@ function EduCard({ item }: { item: EducationItem }) {
onMouseEnter={(e) => (e.currentTarget.style.borderColor = "#6b5730")} onMouseEnter={(e) => (e.currentTarget.style.borderColor = "#6b5730")}
onMouseLeave={(e) => (e.currentTarget.style.borderColor = "#1c1f26")} onMouseLeave={(e) => (e.currentTarget.style.borderColor = "#1c1f26")}
> >
{/* Corner accent */}
<div <div
style={{ style={{
position: "absolute", position: "absolute",
@@ -53,7 +52,6 @@ function EduCard({ item }: { item: EducationItem }) {
/> />
<div <div
className="font-mono"
style={{ style={{
fontFamily: "var(--font-jetbrains), monospace", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.62rem", fontSize: "0.62rem",
@@ -77,7 +75,6 @@ function EduCard({ item }: { item: EducationItem }) {
)} )}
<h3 <h3
className="font-display"
style={{ style={{
fontFamily: "var(--font-bebas), sans-serif", fontFamily: "var(--font-bebas), sans-serif",
fontSize: "1.3rem", fontSize: "1.3rem",
@@ -91,7 +88,7 @@ function EduCard({ item }: { item: EducationItem }) {
</h3> </h3>
<p <p
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.85rem", fontSize: "0.85rem",
color: "#6b7280", color: "#6b7280",
lineHeight: 1.5, lineHeight: 1.5,
@@ -103,70 +100,125 @@ function EduCard({ item }: { item: EducationItem }) {
); );
} }
function CertCard({ item }: { item: CertificateItem }) { function CertCard({ item, index }: { item: CertificateItem; index: number }) {
return ( return (
<div <div
style={{ style={{
border: "1px solid #1c1f26", border: "1px solid #1c1f26",
padding: "1.75rem",
background: "#0e1014", background: "#0e1014",
position: "relative", position: "relative",
overflow: "hidden", overflow: "hidden",
transition: "border-color 0.3s", transition: "border-color 0.3s, box-shadow 0.3s",
flex: 1,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
}} }}
onMouseEnter={(e) => (e.currentTarget.style.borderColor = "#c8a96e")} onMouseEnter={(e) => {
onMouseLeave={(e) => (e.currentTarget.style.borderColor = "#1c1f26")} e.currentTarget.style.borderColor = "#c8a96e";
e.currentTarget.style.boxShadow = "0 8px 32px rgba(200, 169, 110, 0.08)";
}}
onMouseLeave={(e) => {
e.currentTarget.style.borderColor = "#1c1f26";
e.currentTarget.style.boxShadow = "none";
}}
> >
<div <div
className="font-mono"
style={{ style={{
fontFamily: "var(--font-jetbrains), monospace", padding: "1.5rem 1.75rem",
fontSize: "0.62rem", flex: 1,
letterSpacing: "0.12em", display: "flex",
color: "#c8a96e", flexDirection: "column",
marginBottom: "1rem",
}} }}
> >
{item.date} <div style={{ display: "flex", alignItems: "center", gap: "0.75rem", marginBottom: "1.25rem" }}>
</div> <div
style={{
width: "36px",
height: "36px",
borderRadius: "8px",
background: index === 0
? "linear-gradient(135deg, rgba(200,169,110,0.15), rgba(200,169,110,0.05))"
: "rgba(255,255,255,0.03)",
border: "1px solid rgba(200,169,110,0.2)",
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
}}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#c8a96e" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="8" r="6" />
<path d="M15.477 12.89L17 22l-5-3-5 3 1.523-9.11" />
</svg>
</div>
<div
style={{
fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.58rem",
letterSpacing: "0.14em",
color: "#c8a96e",
textTransform: "uppercase",
}}
>
{item.date}
</div>
</div>
<h3 <h3
className="font-display" style={{
style={{ fontFamily: "var(--font-bebas), sans-serif",
fontFamily: "var(--font-bebas), sans-serif", fontSize: "1.25rem",
fontSize: "1.15rem", letterSpacing: "0.04em",
letterSpacing: "0.04em", color: "#e2e4e9",
color: "#e2e4e9", lineHeight: 1.3,
lineHeight: 1.3, marginBottom: "0.5rem",
marginBottom: "0.5rem", }}
}} >
> {item.name}
{item.name} </h3>
</h3>
<p
style={{
fontFamily: "var(--font-lora), serif",
fontSize: "0.85rem",
color: "#6b7280",
lineHeight: 1.5,
marginBottom: "1rem",
}}
>
{item.issuer}
</p>
<div style={{ <p
fontFamily: "var(--font-jetbrains), monospace", style={{
fontSize: "0.55rem", fontFamily: "var(--font-jetbrains), monospace",
color: "#4a5060", fontSize: "0.78rem",
letterSpacing: "0.12em", color: "#6b7280",
textTransform: "uppercase", lineHeight: 1.5,
marginTop: "auto" marginBottom: "1.25rem",
}}> }}
ID: {item.credentialId} >
{item.issuer}
</p>
<div
style={{
marginTop: "auto",
paddingTop: "1rem",
borderTop: "1px solid rgba(255,255,255,0.04)",
display: "flex",
alignItems: "center",
gap: "0.5rem",
}}
>
<div
style={{
width: "6px",
height: "6px",
borderRadius: "50%",
background: "#c8a96e",
opacity: 0.4,
flexShrink: 0,
}}
/>
<span
style={{
fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.55rem",
color: "#4a5060",
letterSpacing: "0.08em",
}}
>
{item.credentialId}
</span>
</div>
</div> </div>
</div> </div>
); );
@@ -179,7 +231,6 @@ export default function Education({ education, certificates }: EducationProps) {
<div style={{ marginBottom: "4rem" }}> <div style={{ marginBottom: "4rem" }}>
<div className="section-label" style={{ marginBottom: "0.75rem" }}>Academic Background</div> <div className="section-label" style={{ marginBottom: "0.75rem" }}>Academic Background</div>
<h2 <h2
className="font-display"
style={{ style={{
fontFamily: "var(--font-bebas), sans-serif", fontFamily: "var(--font-bebas), sans-serif",
fontSize: "clamp(2.5rem, 6vw, 5rem)", fontSize: "clamp(2.5rem, 6vw, 5rem)",
@@ -188,7 +239,7 @@ export default function Education({ education, certificates }: EducationProps) {
lineHeight: 1, lineHeight: 1,
}} }}
> >
Education Education &amp; Certificates
</h2> </h2>
<div style={{ width: "48px", height: "1px", background: "#c8a96e", marginTop: "1rem" }} /> <div style={{ width: "48px", height: "1px", background: "#c8a96e", marginTop: "1rem" }} />
</div> </div>
@@ -210,37 +261,35 @@ export default function Education({ education, certificates }: EducationProps) {
</div> </div>
{certificates && certificates.length > 0 && ( {certificates && certificates.length > 0 && (
<div style={{ marginTop: "6rem" }}> <div style={{ marginTop: "4rem" }}>
<div style={{ marginBottom: "3rem" }}> <div style={{ display: "flex", alignItems: "center", gap: "1rem", marginBottom: "2rem" }}>
<div className="section-label" style={{ marginBottom: "0.75rem" }}>Licenses & Certifications</div> <div
<h3
className="font-display"
style={{ style={{
fontFamily: "var(--font-bebas), sans-serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "clamp(2rem, 4vw, 3.5rem)", fontSize: "0.62rem",
letterSpacing: "0.04em", letterSpacing: "0.22em",
color: "#e2e4e9", textTransform: "uppercase",
lineHeight: 1, color: "#c8a96e",
display: "flex",
alignItems: "center",
gap: "0.6rem",
}} }}
> >
Certificates <span style={{ display: "inline-block", width: "20px", height: "1px", background: "#c8a96e" }} />
</h3> Licenses &amp; Certifications
<div style={{ width: "32px", height: "1px", background: "#c8a96e", marginTop: "1rem" }} /> </div>
<div style={{ flex: 1, height: "1px", background: "#1c1f26" }} />
</div> </div>
<div <div
style={{ style={{
display: "grid", display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 340px), 1fr))", gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 420px), 1fr))",
gap: "1px", gap: "1.25rem",
background: "#1c1f26",
border: "1px solid #1c1f26",
}} }}
> >
{certificates.map((cert) => ( {certificates.map((cert, i) => (
<div key={cert.name} style={{ background: "#07080a", display: "flex" }}> <CertCard key={cert.credentialId} item={cert} index={i} />
<CertCard item={cert} />
</div>
))} ))}
</div> </div>
</div> </div>

View File

@@ -111,7 +111,7 @@ function ExperienceItem({ exp, index }: { exp: Experience; index: number }) {
</h3> </h3>
<p <p
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.9rem", fontSize: "0.9rem",
lineHeight: 1.7, lineHeight: 1.7,
color: "#6b7280", color: "#6b7280",

View File

@@ -189,44 +189,6 @@ export default function Hero({
className="hero-section" className="hero-section"
style={{ minHeight: "100vh", position: "relative", zIndex: 10 }} style={{ minHeight: "100vh", position: "relative", zIndex: 10 }}
> >
<style>{`
.creative-bento-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
width: 100%;
position: relative;
}
.bento-span-2x2 { grid-column: span 2; grid-row: span 2; }
.bento-span-2x1 { grid-column: span 2; grid-row: span 1; }
.bento-span-1x1 { grid-column: span 1; grid-row: span 1; }
@media (max-width: 1024px) {
.creative-bento-grid {
grid-template-columns: repeat(2, 1fr);
}
.bento-span-2x2 { grid-column: span 2; grid-row: span 2; }
.bento-span-2x1 { grid-column: span 2; grid-row: span 1; }
.bento-span-1x1 { grid-column: span 1; grid-row: span 1; }
}
@media (max-width: 600px) {
.creative-bento-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.bento-span-2x2, .bento-span-2x1, .bento-span-1x1 {
grid-column: span 1;
grid-row: auto;
}
}
.glow-text {
text-shadow: 0 0 24px rgba(200, 169, 110, 0.4);
}
`}</style>
<div style={{ maxWidth: "1200px", margin: "0 auto", position: "relative" }}> <div style={{ maxWidth: "1200px", margin: "0 auto", position: "relative" }}>
{/* ── Headline ─────────────────────────────────────────────────── */} {/* ── Headline ─────────────────────────────────────────────────── */}
@@ -236,8 +198,7 @@ export default function Hero({
> >
<h1 <h1
style={{ style={{
fontFamily: "var(--font-lora), Georgia, serif", fontFamily: "var(--font-bebas), sans-serif",
fontStyle: "italic",
fontWeight: 400, fontWeight: 400,
fontSize: "clamp(3rem, 7vw, 7.5rem)", fontSize: "clamp(3rem, 7vw, 7.5rem)",
lineHeight: 1.05, lineHeight: 1.05,
@@ -265,7 +226,7 @@ export default function Hero({
</div> </div>
<div <div
style={{ style={{
fontFamily: "var(--font-bebas), Impact, sans-serif", fontFamily: "var(--font-bebas), sans-serif",
fontSize: "clamp(1.8rem, 4.5vw, 3.5rem)", fontSize: "clamp(1.8rem, 4.5vw, 3.5rem)",
letterSpacing: "0.04em", letterSpacing: "0.04em",
color: "#6b7280", color: "#6b7280",
@@ -278,7 +239,7 @@ export default function Hero({
</div> </div>
<div style={{ maxWidth: "420px" }}> <div style={{ maxWidth: "420px" }}>
<p style={{ fontFamily: "var(--font-lora), serif", fontSize: "0.95rem", lineHeight: 1.75, color: "#8b92a5", margin: 0 }}> <p style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.95rem", lineHeight: 1.75, color: "#8b92a5", margin: 0 }}>
{description} {description}
</p> </p>
<div style={{ display: "flex", alignItems: "center", gap: "0.6rem", marginTop: "1rem" }}> <div style={{ display: "flex", alignItems: "center", gap: "0.6rem", marginTop: "1rem" }}>
@@ -327,7 +288,7 @@ export default function Hero({
</div> </div>
</div> </div>
<p style={{ fontFamily: "var(--font-lora), serif", fontSize: "1rem", lineHeight: 1.7, color: "#9ca3af", marginBottom: "1.5rem" }}> <p style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "1rem", lineHeight: 1.7, color: "#9ca3af", marginBottom: "1.5rem" }}>
{feat1.description} {feat1.description}
</p> </p>
@@ -338,7 +299,7 @@ export default function Hero({
<span style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.7rem", color: "#e2e4e9" }}>{task.name}</span> <span style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.7rem", color: "#e2e4e9" }}>{task.name}</span>
<span className={task.status === "Done" ? "status-done" : "status-progress"} style={{ fontSize: "0.5rem", padding: "2px 4px" }}>{task.status}</span> <span className={task.status === "Done" ? "status-done" : "status-progress"} style={{ fontSize: "0.5rem", padding: "2px 4px" }}>{task.status}</span>
</div> </div>
<div style={{ fontFamily: "var(--font-lora), serif", fontSize: "0.8rem", color: "#6b7280", lineHeight: 1.4 }}> <div style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.8rem", color: "#6b7280", lineHeight: 1.4 }}>
{task.description.length > 80 ? task.description.slice(0, 80) + "..." : task.description} {task.description.length > 80 ? task.description.slice(0, 80) + "..." : task.description}
</div> </div>
</div> </div>
@@ -382,7 +343,7 @@ export default function Hero({
{feat2.name} {feat2.name}
</h3> </h3>
</div> </div>
<p style={{ fontFamily: "var(--font-lora), serif", fontSize: "0.85rem", lineHeight: 1.65, color: "#8b92a5", marginBottom: "1rem", flex: 1 }}> <p style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.85rem", lineHeight: 1.65, color: "#8b92a5", marginBottom: "1rem", flex: 1 }}>
{feat2.description} {feat2.description}
</p> </p>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.5rem" }}> <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "0.5rem" }}>
@@ -486,7 +447,7 @@ export default function Hero({
</div> </div>
<div style={{ display: "flex", flexWrap: "wrap", gap: "0.4rem" }}> <div style={{ display: "flex", flexWrap: "wrap", gap: "0.4rem" }}>
{interests.map((interest) => ( {interests.map((interest) => (
<span key={interest} style={{ fontFamily: "var(--font-lora), serif", fontSize: "0.85rem", fontStyle: "italic", color: "#8b92a5", background: "rgba(255,255,255,0.02)", padding: "2px 8px", borderRadius: "12px" }}> <span key={interest} style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.75rem", color: "#8b92a5", background: "rgba(255,255,255,0.02)", padding: "2px 8px", borderRadius: "12px" }}>
{interest} {interest}
</span> </span>
))} ))}

View File

@@ -5,7 +5,7 @@ import { useEffect, useState } from "react";
const links = [ const links = [
{ label: "Projects", href: "#projects" }, { label: "Projects", href: "#projects" },
{ label: "Experience", href: "#experience" }, { label: "Experience", href: "#experience" },
{ label: "Education", href: "#education" }, { label: "Education & Certs", href: "#education" },
{ label: "Skills", href: "#skills" }, { label: "Skills", href: "#skills" },
{ label: "Contact", href: "#contact" }, { label: "Contact", href: "#contact" },
]; ];

View File

@@ -192,7 +192,7 @@ function ProjectRow({
<p <p
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "1.05rem", fontSize: "1.05rem",
lineHeight: 1.8, lineHeight: 1.8,
color: "#9ca3af", color: "#9ca3af",
@@ -276,7 +276,7 @@ function ProjectRow({
{task.status} {task.status}
</span> </span>
</div> </div>
<p style={{ fontFamily: "var(--font-lora), serif", fontSize: "0.85rem", color: "#6b7280", lineHeight: 1.6, margin: 0 }}> <p style={{ fontFamily: "var(--font-jetbrains), monospace", fontSize: "0.85rem", color: "#6b7280", lineHeight: 1.6, margin: 0 }}>
{task.description} {task.description}
</p> </p>
</div> </div>

View File

@@ -125,7 +125,7 @@ export default function Skills({ skills, languages, interests }: SkillsProps) {
> >
<span <span
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.95rem", fontSize: "0.95rem",
color: "#e2e4e9", color: "#e2e4e9",
}} }}
@@ -172,13 +172,12 @@ export default function Skills({ skills, languages, interests }: SkillsProps) {
<span <span
key={interest} key={interest}
style={{ style={{
fontFamily: "var(--font-lora), serif", fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.85rem", fontSize: "0.75rem",
padding: "4px 14px", padding: "4px 14px",
border: "1px solid #1c1f26", border: "1px solid #1c1f26",
color: "#6b7280", color: "#6b7280",
background: "#0e1014", background: "#0e1014",
fontStyle: "italic",
transition: "all 0.2s", transition: "all 0.2s",
cursor: "default", cursor: "default",
}} }}

View File

@@ -256,7 +256,20 @@
"endDate": "2016" "endDate": "2016"
} }
], ],
"certificates": [], "certificates": [
{
"name": "ISTQB® Certified Tester Foundation Level CTFL",
"issuer": "CFTL (Comité Français des Tests Logiciels)",
"date": "June 2022",
"credentialId": "22-CTFL-89556-FR"
},
{
"name": "Scrum Foundation Professional Certificate",
"issuer": "CertiProf",
"date": "June 2020",
"credentialId": "FLCLDJLTIJ-SSSOKSJF-WHKBDHDODK"
}
],
"about": { "about": {
"title": "Techlead Software Engineer", "title": "Techlead Software Engineer",
"FullName": "Achraf Achkari", "FullName": "Achraf Achkari",

4071
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff