import type { Metadata, Viewport } from "next";
import { Geist, Sora, JetBrains_Mono } from "next/font/google";
import "../globals.css";
import {
locales,
getDictionary,
isValidLocale,
defaultLocale,
type Locale,
} from "@/lib/dictionaries";
import { SITE_URL, localeAlternates } from "@/lib/seo";
import Navbar from "@/components/layout/Navbar";
import Footer from "@/components/layout/Footer";
import ScanlineOverlay from "@/components/ui/ScanlineOverlay";
import LangBanner from "@/components/ui/LangBanner";
const geistSans = Geist({
subsets: ["latin"],
variable: "--font-geist-sans",
display: "swap",
});
const sora = Sora({
subsets: ["latin"],
variable: "--font-sora",
display: "swap",
weight: ["300", "400", "500", "600", "700"],
});
const jetbrains = JetBrains_Mono({
subsets: ["latin"],
variable: "--font-jetbrains",
display: "swap",
weight: ["400", "500"],
});
// Pre-render both locale shells at build time
export function generateStaticParams() {
return locales.map((locale) => ({ locale }));
}
// Tell the browser the document is dark before any CSS/JS runs. This sets the
// / theme-color in the SSR
so the initial
// canvas (and mobile browser chrome) paints dark, never white.
export const viewport: Viewport = {
colorScheme: "dark",
themeColor: "#0F1117",
};
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>;
}): Promise {
const { locale } = await params;
const isSR = locale === "sr";
return {
title: {
default: isSR
? "Name — Full-stack inženjering, od početka do kraja"
: "Name — Full-stack engineering, end to end",
template: "%s · Name",
},
description: isSR
? "Premium full-stack razvoj, deployment i self-hosted infrastruktura."
: "Premium full-stack development, deployment, and self-hosted infrastructure.",
metadataBase: new URL(SITE_URL),
// Canonical — self-referencing within each locale.
// Subpages override this with their own path via localeAlternates().
alternates: localeAlternates(locale),
openGraph: {
title: isSR
? "Name — Full-stack inženjering"
: "Name — Full-stack engineering, end to end",
description: isSR
? "Premium full-stack razvoj i self-hosted infrastruktura."
: "Premium full-stack development and self-hosted infrastructure.",
type: "website",
locale: isSR ? "sr_RS" : "en_US",
alternateLocale: isSR ? ["en_US"] : ["sr_RS"],
siteName: "ksan.dev",
url: `${SITE_URL}/${locale}`,
},
twitter: {
card: "summary_large_image",
title: isSR ? "Name — Full-stack inženjering" : "Name — Full-stack engineering",
},
robots: {
index: true,
follow: true,
"max-image-preview": "large",
"max-snippet": -1,
},
};
}
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale: rawLocale } = await params;
const locale: Locale = isValidLocale(rawLocale) ? rawLocale : defaultLocale;
const dict = getDictionary(locale);
return (
{children}
);
}