release: v0.20.0

This commit is contained in:
Ralksta
2026-10-02 18:14:23 +02:00
committed by GitHub
parent 81ce886b01
commit 5f831f719a
209 changed files with 13807 additions and 803 deletions

View File

@@ -15,11 +15,12 @@ import { ScrollToTop } from '@/components/ScrollToTop';
import { Footer } from '@/components/Footer';
import { SetupScreen } from '@/components/SetupScreen';
import { getConfigOrNull, getThemeFontsUrl, AppConfig } from '@/lib/config';
import { accentForMode, onAccent } from '@/lib/config/theme';
import { accentForMode, accentText, onAccent } from '@/lib/config/theme';
import { isAdminPath } from '@/lib/admin/paths';
import { isInstallPath } from '@/lib/install';
import { isSiteLocked, isSiteUnlocked } from '@/lib/auth';
import { ogImageUrl } from '@/lib/ogImage';
import { THEME_INIT_SCRIPT } from '@/lib/themeScript';
// DevToolbarLoader is a Client Component (ssr: false is only allowed there)
import { DevToolbarLoader } from '@/components/DevToolbarLoader';
import AssetProtection from '@/components/AssetProtection';
@@ -81,7 +82,8 @@ export async function generateMetadata(): Promise<Metadata> {
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const config = getConfigOrNull();
const pathname = (await headers()).get('x-pathname');
const requestHeaders = await headers();
const pathname = requestHeaders.get('x-pathname');
// gallery.yaml exists but cannot be derived — an empty gallery, a nameless
// subpage, a subpage with no albums. The admin page builder can write all
@@ -106,6 +108,8 @@ export default async function RootLayout({ children }: { children: React.ReactNo
'--accent-light': accentForMode(theme, 'light'),
'--on-accent-dark': onAccent(accentForMode(theme, 'dark')),
'--on-accent-light': onAccent(accentForMode(theme, 'light')),
'--accent-text-dark': accentText(accentForMode(theme, 'dark'), 'dark'),
'--accent-text-light': accentText(accentForMode(theme, 'light'), 'light'),
'--font-serif': `'${theme.fonts.heading}', Georgia, 'Times New Roman', serif`,
'--font-sans': `'${theme.fonts.body}', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif`,
'--font-caption': `'${theme.fonts.caption}', Georgia, serif`,
@@ -140,6 +144,10 @@ export default async function RootLayout({ children }: { children: React.ReactNo
* (`app/gate/page.tsx`) that `proxy.ts` rewrites to; all the layout does is
* strip the chrome around it, because a header listing every subpage would
* give away the shape of a site that is supposed to be shut.
*
* The same holds for the pages the proxy serves to a locked site
* (`UNGATED_PAGES` in proxy.ts): /impressum, /privacy and /contact render
* bare here until the visitor has unlocked the site.
*/
const cookieStore = await cookies();
const siteGated =
@@ -158,11 +166,21 @@ export default async function RootLayout({ children }: { children: React.ReactNo
/* The configured starting mode is rendered server-side so the first paint
is already right; `auto` deliberately carries no data-theme and lets the
inline script below decide from the OS. data-default-theme is what
ThemeToggle reads for a visitor who has never chosen (#512). */
that script and ThemeToggle read for a visitor who has never chosen
(#512). */
{...(config.colorMode === 'auto' ? {} : { 'data-theme': config.colorMode })}
data-default-theme={config.colorMode}
>
<head>
{/* Applies a stored or OS-derived mode before the first paint, on
every page this layout renders — the gate and /admin included.
The nonce is the one proxy.ts put in the CSP; without it the
script is blocked silently. */}
<script
nonce={requestHeaders.get('x-nonce') ?? undefined}
suppressHydrationWarning
dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }}
/>
<link rel="stylesheet" href={fontsUrl} />
</head>
<body>