feat: add scoped theme builder system with per-route, per-module, and multi-site support
- 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
This commit is contained in:
1 parent
b57697b2e0
commit
a98b194386
19 files changed
+1843
No files matched your search
@@ -0,0 +1,79 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { getThemeBuilderData } from "@/actions/theme-builder";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
import { ScopeForm } from "./scope-form";
|
||||
import { ScopeTree } from "./scope-tree";
|
||||
import { ThemeEditor } from "./theme-editor";
|
||||
|
||||
export const metadata = { title: "Theme Builder" };
|
||||
|
||||
export default async function ThemeBuilderPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<Record<string, string | undefined>>;
|
||||
}) {
|
||||
const ctx = await getAdminContext();
|
||||
if (!ctx || !canAccess(ctx.permissions, PERMS.SETTINGS_VIEW)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const sp = await searchParams;
|
||||
const { scopes, tree, moduleIds } = await getThemeBuilderData();
|
||||
|
||||
const selectedId = sp.scope ? Number(sp.scope) : (scopes[0]?.id ?? null);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="admin-section-title mb-4">Theme Builder</h1>
|
||||
<p className="text-xs text-[var(--admin-text-muted)] mb-6">
|
||||
Create and manage scoped themes for different parts of your site. Themes
|
||||
inherit from parent scopes — only override what you need.
|
||||
</p>
|
||||
|
||||
{sp.created ? (
|
||||
<div className="mb-4 p-3 rounded-lg theme-status-success text-xs">
|
||||
Scope created.
|
||||
</div>
|
||||
) : null}
|
||||
{sp.updated ? (
|
||||
<div className="mb-4 p-3 rounded-lg theme-status-success text-xs">
|
||||
Scope updated.
|
||||
</div>
|
||||
) : null}
|
||||
{sp.deleted ? (
|
||||
<div className="mb-4 p-3 rounded-lg theme-status-success text-xs">
|
||||
Scope deleted.
|
||||
</div>
|
||||
) : null}
|
||||
{sp.saved ? (
|
||||
<div className="mb-4 p-3 rounded-lg theme-status-success text-xs">
|
||||
Theme values saved.
|
||||
</div>
|
||||
) : null}
|
||||
{sp.duplicated ? (
|
||||
<div className="mb-4 p-3 rounded-lg theme-status-success text-xs">
|
||||
Scope duplicated.
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
||||
<div className="lg:col-span-3">
|
||||
<ScopeTree tree={tree} selectedId={selectedId} />
|
||||
<div className="mt-4">
|
||||
<ScopeForm moduleIds={moduleIds} scopeCount={scopes.length} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="lg:col-span-9">
|
||||
{selectedId ? (
|
||||
<ThemeEditor scopeId={selectedId} scopes={scopes} />
|
||||
) : (
|
||||
<div className="admin-card p-8 text-center text-[var(--admin-text-muted)]">
|
||||
Select or create a scope to start editing.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user