- Add theme_scopes and theme_scope_values database tables for scoped themes - Implement theme resolver engine with inheritance: global > site > module > route - Add module detection for 20+ routes (shop, guilds, radio, news, etc.) - Create admin UI at /admin/theme-builder with scope tree and color editor - Add ScopedThemeVars component for injecting scoped CSS via data-attributes - Add ThemeScopeDetector client component for runtime module/route detection - Add site-resolver for multi-site domain detection - Add /api/themes/export endpoint (JSON, CSS, variables formats) - Add /api/themes/export/embed.js for external integration widget - Add server actions for full CRUD on scopes and theme values - Add admin nav link and EN/NL translations
35 lines
931 B
TypeScript
35 lines
931 B
TypeScript
import { headers } from "next/headers";
|
|
|
|
/**
|
|
* Resolve the current site domain from request headers.
|
|
* Used by the theme resolver to apply site-scoped themes.
|
|
*/
|
|
export async function resolveSiteDomain(): Promise<string | null> {
|
|
const h = await headers();
|
|
// Next.js sets host in the Host header
|
|
const host = h.get("host") ?? h.get("x-forwarded-host");
|
|
if (!host) return null;
|
|
// Strip port if present
|
|
return host.split(":")[0];
|
|
}
|
|
|
|
/**
|
|
* Build the full theme context from the current request.
|
|
* Combines site domain + route path + module detection.
|
|
*/
|
|
export async function buildThemeContext(pathname: string): Promise<{
|
|
siteDomain: string | null;
|
|
routePath: string;
|
|
moduleId: string | null;
|
|
}> {
|
|
const siteDomain = await resolveSiteDomain();
|
|
const { detectModule } = await import("@/lib/theme-modules");
|
|
const moduleId = detectModule(pathname);
|
|
|
|
return {
|
|
siteDomain,
|
|
routePath: pathname,
|
|
moduleId,
|
|
};
|
|
}
|