Complete admin panel for content management: - SQLite database with better-sqlite3, seed script from content.ts - Simple password auth with HMAC-signed cookies (Edge + Node compatible) - 9 section editors: meta, hero, about, team, classes, schedule, pricing, FAQ, contact - Team CRUD with image upload and drag reorder - Schedule editor with Google Calendar-style visual timeline (colored blocks, overlap detection, click-to-add) - All public components refactored to accept data props from DB (with fallback to static content) - Middleware protecting /admin/* and /api/admin/* routes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
45 lines
930 B
TypeScript
45 lines
930 B
TypeScript
import type { Metadata } from "next";
|
|
import { Inter, Oswald } from "next/font/google";
|
|
import { getContent } from "@/lib/content";
|
|
import "./globals.css";
|
|
|
|
const inter = Inter({
|
|
variable: "--font-inter",
|
|
subsets: ["latin", "cyrillic"],
|
|
});
|
|
|
|
const oswald = Oswald({
|
|
variable: "--font-oswald",
|
|
subsets: ["latin", "cyrillic"],
|
|
});
|
|
|
|
export function generateMetadata(): Metadata {
|
|
const { meta } = getContent();
|
|
return {
|
|
title: meta.title,
|
|
description: meta.description,
|
|
openGraph: {
|
|
title: meta.title,
|
|
description: meta.description,
|
|
locale: "ru_RU",
|
|
type: "website",
|
|
},
|
|
};
|
|
}
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<html lang="ru" className="dark">
|
|
<body
|
|
className={`${inter.variable} ${oswald.variable} surface-base font-sans antialiased`}
|
|
>
|
|
{children}
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|