60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { Bebas_Neue, JetBrains_Mono, Lora } from "next/font/google";
|
|
import "./globals.css";
|
|
import GridCanvas from "@/components/GridCanvas";
|
|
|
|
const bebas = Bebas_Neue({
|
|
weight: "400",
|
|
variable: "--font-bebas",
|
|
subsets: ["latin"],
|
|
});
|
|
|
|
const jetbrains = JetBrains_Mono({
|
|
variable: "--font-jetbrains",
|
|
subsets: ["latin"],
|
|
weight: ["400", "500"],
|
|
});
|
|
|
|
const lora = Lora({
|
|
variable: "--font-lora",
|
|
subsets: ["latin"],
|
|
weight: ["400", "500"],
|
|
});
|
|
|
|
export const metadata: Metadata = {
|
|
title: "Achraf Achkari — Technical Lead & Software Engineer",
|
|
description:
|
|
"Personal portfolio and project hub. Technical Lead at Kereval, building software with Java, TypeScript, and modern frameworks.",
|
|
icons: {
|
|
icon: "/favicon.svg",
|
|
},
|
|
};
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: Readonly<{ children: React.ReactNode }>) {
|
|
return (
|
|
<html
|
|
lang="en"
|
|
className={`${bebas.variable} ${jetbrains.variable} ${lora.variable} h-full`}
|
|
>
|
|
<body className="min-h-full flex flex-col antialiased" suppressHydrationWarning>
|
|
<GridCanvas />
|
|
{/* Noise texture — real DOM element so pointer-events:none is reliable on Android touch */}
|
|
<div
|
|
aria-hidden="true"
|
|
style={{
|
|
position: "fixed",
|
|
inset: 0,
|
|
backgroundImage: "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E\")",
|
|
pointerEvents: "none",
|
|
zIndex: 1,
|
|
opacity: 0.35,
|
|
}}
|
|
/>
|
|
{children}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|