openreader/src/app/layout.tsx
Richard R 1f4794a706 feat(auth): implement session gatekeeping and architectural reorganization
- Introduce `USE_ANONYMOUS_AUTH_SESSIONS` to make guest access an opt-in feature.
- Transition root-level pages into `(app)` and `(public)` route groups for improved access control.
- Adopt Figtree as the primary typeface and implement a pre-render theme initialization script.
- Decouple audiobook chapter processing into a standalone API route and harden resource ownership logic.
- Replace the legacy footer with a unified layout and add skeleton loading states for document lists.
- Update environment documentation and test suites to align with the revised routing and auth flows.

BREAKING CHANGE: The audiobook generation API has been restructured, moving specific chapter logic to `/api/audiobook/chapter`.
2026-02-15 11:12:42 -07:00

54 lines
1.6 KiB
TypeScript

import "./globals.css";
import { ReactNode } from "react";
import { Metadata } from "next";
import { Analytics } from "@vercel/analytics/next";
import { Figtree } from "next/font/google";
const figtree = Figtree({
subsets: ["latin"],
weight: ["300", "400", "500", "600", "700", "800"],
display: "swap",
variable: "--font-display",
});
const themeInitScript = `
(() => {
const themes = ['system', 'light', 'dark', 'ocean', 'forest', 'sunset', 'sea', 'mint'];
const root = document.documentElement;
const stored = localStorage.getItem('theme');
const selected = stored && themes.includes(stored) ? stored : 'system';
const effective = selected === 'system'
? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: selected;
root.classList.remove(...themes);
root.classList.add(effective);
root.style.colorScheme = effective === 'dark' ? 'dark' : 'light';
})();
`;
export const metadata: Metadata = {
title: {
default: "OpenReader WebUI",
template: "%s | OpenReader WebUI",
},
manifest: "/manifest.json",
metadataBase: new URL("https://openreader.richardr.dev"),
verification: {
google: "MJXyTudn1kgQF8EtGD-tsnAWev7Iawso9hEvqeGHB3U",
},
};
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en" className={figtree.variable} suppressHydrationWarning>
<head>
<meta name="color-scheme" content="light dark" />
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
</head>
<body className="antialiased">
{children}
<Analytics />
</body>
</html>
);
}