274 lines
9.4 KiB
TypeScript
274 lines
9.4 KiB
TypeScript
"use client";
|
|
import { BLOCK_KEY_PREFIX, getBlocksByCategory } from "@/lib/theme-blocks";
|
|
import { ColorField } from "./color-field";
|
|
import {
|
|
COLOR_FIELDS,
|
|
EFFECT_FIELDS,
|
|
getVal,
|
|
LAYOUT_FIELDS,
|
|
MEDIA_FIELDS,
|
|
type ScopeValues,
|
|
} from "./theme-editor-fields";
|
|
// ─── Colors Tab ──────────────────────────────────────────────────────────────
|
|
|
|
export function ColorsTab({
|
|
values,
|
|
mode,
|
|
}: {
|
|
values: ScopeValues;
|
|
mode: "light" | "dark";
|
|
}) {
|
|
return (
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Colors ({mode} mode)
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Only values you set here override the parent scope. Leave empty to
|
|
inherit.
|
|
</p>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{COLOR_FIELDS.map((field) => (
|
|
<ColorField
|
|
key={`${field.key}-${mode}`}
|
|
name={`${field.key}_${mode}`}
|
|
label={field.label}
|
|
description={field.desc}
|
|
defaultValue={getVal(values, field.key, mode) || field.def}
|
|
backgroundColorKey={
|
|
field.bgKey ? `${field.bgKey}_${mode}` : undefined
|
|
}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Blocks Tab ──────────────────────────────────────────────────────────────
|
|
|
|
export function BlocksTab({ values }: { values: ScopeValues }) {
|
|
const grouped = getBlocksByCategory();
|
|
|
|
const categoryLabels: Record<string, string> = {
|
|
chrome: "Site Chrome",
|
|
layout: "Layout",
|
|
components: "Components",
|
|
effects: "Effects",
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
{Object.entries(grouped).map(([category, blocks]) => (
|
|
<div key={category} className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-1">
|
|
{categoryLabels[category] ?? category}
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Toggle visibility of blocks in this scope. Hidden blocks use{" "}
|
|
<code className="bg-[var(--admin-surface-elevated)] px-1 rounded">
|
|
display: none
|
|
</code>
|
|
.
|
|
</p>
|
|
|
|
<div className="space-y-2">
|
|
{blocks.map((block) => {
|
|
const key = `${BLOCK_KEY_PREFIX}${block.id}`;
|
|
const currentVal = values.blocks[key];
|
|
const isChecked =
|
|
currentVal === "true" ||
|
|
(currentVal === undefined && block.defaultVisible);
|
|
|
|
return (
|
|
<label
|
|
key={block.id}
|
|
className="flex items-center gap-3 p-2 rounded-lg hover:bg-[var(--admin-surface-elevated)] cursor-pointer"
|
|
>
|
|
<input
|
|
type="checkbox"
|
|
name={key}
|
|
defaultChecked={isChecked}
|
|
className="h-4 w-4 rounded border-[var(--admin-border)] text-[var(--admin-accent)] focus:ring-[var(--admin-accent)]"
|
|
/>
|
|
<div className="flex-1 min-w-0">
|
|
<span className="text-sm text-[var(--admin-text)]">
|
|
{block.label}
|
|
</span>
|
|
<span className="text-xs text-[var(--admin-text-muted)] ml-2">
|
|
{block.description}
|
|
</span>
|
|
</div>
|
|
<code className="text-[10px] text-[var(--admin-text-muted)] font-mono">
|
|
{block.selector}
|
|
</code>
|
|
</label>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Layout Tab ──────────────────────────────────────────────────────────────
|
|
|
|
export function LayoutTab({ values }: { values: ScopeValues }) {
|
|
return (
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Layout Settings
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Control spacing, width, and grid settings for this scope. Values are
|
|
applied as CSS custom properties.
|
|
</p>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{LAYOUT_FIELDS.map((field) => (
|
|
<div key={field.key} className="rounded-lg p-2">
|
|
<label className="block text-sm font-semibold text-[var(--admin-text)] mb-1">
|
|
{field.label}
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-2 font-normal">
|
|
{field.desc}
|
|
</p>
|
|
<input
|
|
type={field.type || "text"}
|
|
name={field.key}
|
|
defaultValue={getVal(values, field.key, "light") || field.def}
|
|
className="w-full px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-sm font-mono"
|
|
style={{ borderColor: "var(--admin-border)" }}
|
|
/>
|
|
</label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Effects Tab ─────────────────────────────────────────────────────────────
|
|
|
|
export function EffectsTab({ values }: { values: ScopeValues }) {
|
|
return (
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Effects & Transitions
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Control shadows, borders, and animation timing for this scope.
|
|
</p>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{EFFECT_FIELDS.map((field) => (
|
|
<div key={field.key} className="rounded-lg p-2">
|
|
<label className="block text-sm font-semibold text-[var(--admin-text)] mb-1">
|
|
{field.label}
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-2 font-normal">
|
|
{field.desc}
|
|
</p>
|
|
<input
|
|
type={field.type || "text"}
|
|
name={field.key}
|
|
defaultValue={getVal(values, field.key, "light") || field.def}
|
|
className="w-full px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-sm font-mono"
|
|
style={{ borderColor: "var(--admin-border)" }}
|
|
/>
|
|
</label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Media Tab ───────────────────────────────────────────────────────────────
|
|
|
|
export function MediaTab({ values }: { values: ScopeValues }) {
|
|
return (
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Media & Backgrounds
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Set custom logos, background images, and background properties for this
|
|
scope.
|
|
</p>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{MEDIA_FIELDS.map((field) => (
|
|
<div key={field.key} className="rounded-lg p-2">
|
|
<label className="block text-sm font-semibold text-[var(--admin-text)] mb-1">
|
|
{field.label}
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-2 font-normal">
|
|
{field.desc}
|
|
</p>
|
|
<input
|
|
type={field.type || "text"}
|
|
name={field.key}
|
|
defaultValue={getVal(values, field.key, "light") || field.def}
|
|
placeholder={field.def}
|
|
className="w-full px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-sm"
|
|
style={{ borderColor: "var(--admin-border)" }}
|
|
/>
|
|
</label>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Custom Tab ──────────────────────────────────────────────────────────────
|
|
|
|
export function CustomTab({ values }: { values: ScopeValues }) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Custom CSS
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Add custom CSS that applies within this scope. Use{" "}
|
|
<code className="bg-[var(--admin-surface-elevated)] px-1 rounded">
|
|
&{" "}
|
|
</code>{" "}
|
|
as a placeholder for the scope selector (e.g.{" "}
|
|
<code className="bg-[var(--admin-surface-elevated)] px-1 rounded">
|
|
& .content-card {"{"} border: 2px solid red; {"}"}
|
|
</code>
|
|
).
|
|
</p>
|
|
<textarea
|
|
name="custom:css"
|
|
defaultValue={getVal(values, "custom:css", "light")}
|
|
rows={8}
|
|
placeholder={".content-card { border-radius: 20px; }"}
|
|
className="w-full px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-sm font-mono resize-y"
|
|
style={{ borderColor: "var(--admin-border)" }}
|
|
/>
|
|
</div>
|
|
|
|
<div className="admin-card p-4">
|
|
<h3 className="text-sm font-semibold text-[var(--admin-text)] mb-4">
|
|
Custom HTML
|
|
</h3>
|
|
<p className="text-xs text-[var(--admin-text-muted)] mb-4">
|
|
Add custom HTML that injects into the page for this scope. Use for
|
|
custom banners, scripts, or content blocks.
|
|
</p>
|
|
<textarea
|
|
name="custom:html"
|
|
defaultValue={getVal(values, "custom:html", "light")}
|
|
rows={6}
|
|
placeholder='<div class="my-banner">Welcome!</div>'
|
|
className="w-full px-3 py-2 rounded-lg border bg-[var(--admin-canvas)] text-[var(--admin-text)] text-sm font-mono resize-y"
|
|
style={{ borderColor: "var(--admin-border)" }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|