Implement achraf's portfolio

This commit is contained in:
achraf
2026-03-31 00:28:00 +02:00
parent fcd8d3d986
commit a4ee12732d
20 changed files with 2734 additions and 87 deletions

219
components/Navigation.tsx Normal file
View File

@@ -0,0 +1,219 @@
"use client";
import { useEffect, useState } from "react";
const links = [
{ label: "Projects", href: "#projects" },
{ label: "Experience", href: "#experience" },
{ label: "Education", href: "#education" },
{ label: "Skills", href: "#skills" },
{ label: "Contact", href: "#contact" },
];
export default function Navigation() {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
const [active, setActive] = useState("");
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 60);
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
<header
style={{
position: "fixed",
top: 0,
left: 0,
right: 0,
zIndex: 100,
transition: "background 0.4s ease, border-color 0.4s ease",
background: scrolled ? "rgba(7,8,10,0.94)" : "transparent",
backdropFilter: scrolled ? "blur(16px)" : "none",
borderBottom: scrolled ? "1px solid #1c1f26" : "1px solid transparent",
}}
>
<nav
style={{
maxWidth: "1200px",
margin: "0 auto",
padding: "0 2.5rem",
height: "68px",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
{/* Logo */}
<a href="#hero" style={{ textDecoration: "none", flexShrink: 0 }}>
<div
style={{
width: "38px",
height: "38px",
border: "1px solid #c8a96e",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontFamily: "var(--font-bebas), sans-serif",
fontSize: "1.15rem",
color: "#c8a96e",
letterSpacing: "0.04em",
transition: "background 0.2s, box-shadow 0.2s",
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = "rgba(200,169,110,0.1)";
e.currentTarget.style.boxShadow = "0 0 16px rgba(200,169,110,0.15)";
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = "transparent";
e.currentTarget.style.boxShadow = "none";
}}
>
AA
</div>
</a>
{/* Desktop links — each wrapped for padding & underline */}
<div
className="hidden md:flex"
style={{ alignItems: "center", gap: "0" }}
>
{links.map((l, i) => (
<a
key={l.href}
href={l.href}
onClick={() => setActive(l.href)}
style={{
fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.72rem",
letterSpacing: "0.16em",
textTransform: "uppercase",
textDecoration: "none",
padding: "0.5rem 1.4rem",
color: active === l.href ? "#c8a96e" : "#4a5060",
position: "relative",
transition: "color 0.2s",
borderLeft: i > 0 ? "1px solid #1c1f26" : "none",
}}
onMouseEnter={(e) => {
(e.currentTarget as HTMLElement).style.color = "#c8a96e";
}}
onMouseLeave={(e) => {
(e.currentTarget as HTMLElement).style.color =
active === l.href ? "#c8a96e" : "#4a5060";
}}
>
{l.label}
{/* bottom accent line on hover */}
<span
style={{
position: "absolute",
bottom: 0,
left: "1.4rem",
right: "1.4rem",
height: "1px",
background: "#c8a96e",
transform: "scaleX(0)",
transformOrigin: "left",
transition: "transform 0.25s ease",
}}
className="nav-underline"
/>
</a>
))}
</div>
{/* Mobile toggle */}
<button
onClick={() => setOpen(!open)}
className="md:hidden flex flex-col"
style={{
background: "none",
border: "none",
cursor: "pointer",
padding: "8px",
gap: "5px",
}}
aria-label="Toggle menu"
>
<span
style={{
display: "block",
width: "22px",
height: "1px",
background: "#c8a96e",
transition: "transform 0.25s ease",
transform: open ? "translateY(6px) rotate(45deg)" : "none",
}}
/>
<span
style={{
display: "block",
width: "22px",
height: "1px",
background: "#c8a96e",
transition: "opacity 0.2s",
opacity: open ? 0 : 1,
}}
/>
<span
style={{
display: "block",
width: "22px",
height: "1px",
background: "#c8a96e",
transition: "transform 0.25s ease",
transform: open ? "translateY(-6px) rotate(-45deg)" : "none",
}}
/>
</button>
</nav>
{/* Hover underline via CSS */}
<style>{`
nav a:hover .nav-underline { transform: scaleX(1) !important; }
`}</style>
{/* Mobile menu */}
<div
style={{
background: "rgba(7,8,10,0.98)",
borderTop: "1px solid #1c1f26",
overflow: "hidden",
maxHeight: open ? "320px" : "0",
transition: "max-height 0.3s ease",
}}
>
<div style={{ padding: "1.5rem 2.5rem", display: "flex", flexDirection: "column", gap: "0" }}>
{links.map((l, i) => (
<a
key={l.href}
href={l.href}
onClick={() => setOpen(false)}
style={{
fontFamily: "var(--font-jetbrains), monospace",
fontSize: "0.78rem",
letterSpacing: "0.16em",
textTransform: "uppercase",
textDecoration: "none",
padding: "1rem 0",
color: "#4a5060",
borderBottom: i < links.length - 1 ? "1px solid #1c1f26" : "none",
transition: "color 0.2s",
}}
onMouseEnter={(e) => (e.currentTarget.style.color = "#c8a96e")}
onMouseLeave={(e) => (e.currentTarget.style.color = "#4a5060")}
>
<span style={{ color: "#c8a96e", marginRight: "0.75rem", fontSize: "0.6rem" }}>
{String(i + 1).padStart(2, "0")}
</span>
{l.label}
</a>
))}
</div>
</div>
</header>
);
}