188 lines
7.4 KiB
TypeScript
188 lines
7.4 KiB
TypeScript
import React, { useState } from "react";
|
|
import {
|
|
Palette,
|
|
Folder,
|
|
FileCode,
|
|
CheckCircle2,
|
|
RefreshCw,
|
|
Layout,
|
|
Layers,
|
|
ShieldCheck,
|
|
Code,
|
|
} from "lucide-react";
|
|
import { ThemeConfig } from "../types";
|
|
|
|
interface ThemeTabProps {
|
|
theme: ThemeConfig;
|
|
onValidateTheme: () => Promise<void>;
|
|
}
|
|
|
|
export const ThemeTab: React.FC<ThemeTabProps> = ({
|
|
theme,
|
|
onValidateTheme,
|
|
}) => {
|
|
const [isValidating, setIsValidating] = useState(false);
|
|
const [statusMsg, setStatusMsg] = useState<string | null>(null);
|
|
|
|
const handleValidate = async () => {
|
|
setIsValidating(true);
|
|
await onValidateTheme();
|
|
setStatusMsg(
|
|
"Theme /.theme validated successfully. All required templates, CSS resets, and package supports are valid.",
|
|
);
|
|
setIsValidating(false);
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* HEADER */}
|
|
<div className="bg-[#111111] rounded-sm border border-[#1F1F1F] p-6 shadow-xs flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div>
|
|
<div className="flex items-center space-x-2">
|
|
<h1 className="text-xl font-serif italic text-white">
|
|
Theme Management
|
|
</h1>
|
|
<span className="px-2.5 py-0.5 rounded-xs text-[10px] uppercase font-bold tracking-widest bg-[#C5A059]/10 text-[#C5A059] border border-[#C5A059]/30">
|
|
PRD AC-10 Standard Location: /.theme
|
|
</span>
|
|
</div>
|
|
<p className="text-xs text-neutral-400 mt-1">
|
|
Loads active theme from{" "}
|
|
<code className="text-[#C5A059] font-mono">/.theme</code>, validates{" "}
|
|
<code className="text-neutral-300 font-mono">theme.yaml</code>,
|
|
templates, assets, and supported package layouts.
|
|
</p>
|
|
</div>
|
|
|
|
<button
|
|
onClick={handleValidate}
|
|
disabled={isValidating}
|
|
className="px-4 py-2 bg-[#C5A059] hover:bg-[#b38f4a] text-black font-semibold rounded-sm text-xs transition-all flex items-center space-x-1.5 uppercase tracking-wider"
|
|
>
|
|
<RefreshCw
|
|
className={`w-3.5 h-3.5 ${isValidating ? "animate-spin" : ""}`}
|
|
/>
|
|
<span>
|
|
{isValidating ? "Validating Theme..." : "Validate Theme Manifest"}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
{statusMsg && (
|
|
<div className="p-4 bg-emerald-950/40 border border-emerald-500/20 rounded-sm text-xs text-emerald-400 flex items-center space-x-2">
|
|
<CheckCircle2 className="w-4 h-4 text-emerald-400 shrink-0" />
|
|
<span>{statusMsg}</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* THEME STRUCTURE GRID */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6">
|
|
{/* LEFT COLUMN: THEME METADATA & MANIFEST (5 COLS) */}
|
|
<div className="lg:col-span-5 bg-[#111111] rounded-sm border border-[#1F1F1F] p-6 shadow-xs space-y-4">
|
|
<div className="flex items-center justify-between border-b border-[#1F1F1F] pb-3">
|
|
<div className="flex items-center space-x-2">
|
|
<Palette className="w-5 h-5 text-[#C5A059]" />
|
|
<h2 className="text-base font-bold text-white">{theme.name}</h2>
|
|
</div>
|
|
<span className="px-2.5 py-0.5 bg-[#1A1A1A] text-neutral-300 rounded-xs font-mono text-xs font-semibold border border-[#262626]">
|
|
v{theme.version}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-3 text-xs">
|
|
<div className="p-3 bg-[#0A0A0A] rounded-sm border border-[#1F1F1F] space-y-1 font-mono">
|
|
<span className="text-[10px] text-neutral-500 font-bold uppercase tracking-widest block">
|
|
Theme Root Location
|
|
</span>
|
|
<span className="text-[#C5A059] font-bold text-xs">
|
|
{theme.path}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="p-3 bg-[#0A0A0A] rounded-sm border border-[#1F1F1F] space-y-1 font-mono">
|
|
<span className="text-[10px] text-neutral-500 font-bold uppercase tracking-widest block">
|
|
Theme ID
|
|
</span>
|
|
<span className="text-white font-semibold">{theme.id}</span>
|
|
</div>
|
|
|
|
<div className="p-3 bg-[#0A0A0A] rounded-sm border border-[#1F1F1F] space-y-2">
|
|
<span className="text-[10px] text-neutral-500 font-bold uppercase tracking-widest block font-mono">
|
|
Supported Style Packages ({theme.supportsPackages.length})
|
|
</span>
|
|
<div className="flex flex-wrap gap-1.5">
|
|
{theme.supportsPackages.map((pkg) => (
|
|
<span
|
|
key={pkg}
|
|
className="px-2 py-0.5 bg-[#1A1A1A] text-[#C5A059] border border-[#2A2A2A] rounded-xs font-mono text-[10px]"
|
|
>
|
|
builtin:{pkg}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* RIGHT COLUMN: TEMPLATES & ASSETS INSPECTOR (7 COLS) */}
|
|
<div className="lg:col-span-7 bg-[#111111] rounded-sm border border-[#1F1F1F] p-6 shadow-xs space-y-6">
|
|
<h2 className="text-base font-bold text-white">
|
|
Theme Assets & Templates Catalog
|
|
</h2>
|
|
|
|
{/* TEMPLATES LIST */}
|
|
<div className="space-y-2">
|
|
<span className="text-[10px] font-bold text-neutral-500 uppercase tracking-widest block">
|
|
Required Templates
|
|
</span>
|
|
<div className="bg-[#0A0A0A] rounded-sm p-4 text-neutral-200 font-mono text-xs space-y-2 border border-[#1F1F1F]">
|
|
{Object.entries(theme.templates).map(([key, val]) => (
|
|
<div
|
|
key={key}
|
|
className="flex items-center justify-between py-1 border-b border-[#1A1A1A] last:border-0"
|
|
>
|
|
<span className="text-[#C5A059] font-semibold">{key}</span>
|
|
<span className="text-neutral-400 text-[11px]">{val}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* STYLES & SCRIPTS */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 text-xs font-mono">
|
|
<div className="p-3.5 bg-[#0A0A0A] border border-[#1F1F1F] rounded-sm space-y-1.5">
|
|
<span className="font-bold text-neutral-400 uppercase tracking-widest text-[10px] block">
|
|
CSS Style Assets
|
|
</span>
|
|
{theme.styles.map((s) => (
|
|
<div
|
|
key={s}
|
|
className="text-neutral-300 text-[11px] flex items-center space-x-1.5"
|
|
>
|
|
<span className="w-1.5 h-1.5 rounded-full bg-[#C5A059]"></span>
|
|
<span>{s}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div className="p-3.5 bg-[#0A0A0A] border border-[#1F1F1F] rounded-sm space-y-1.5">
|
|
<span className="font-bold text-neutral-400 uppercase tracking-widest text-[10px] block">
|
|
JS Script Assets
|
|
</span>
|
|
{theme.scripts.map((s) => (
|
|
<div
|
|
key={s}
|
|
className="text-neutral-300 text-[11px] flex items-center space-x-1.5"
|
|
>
|
|
<span className="w-1.5 h-1.5 rounded-full bg-amber-500"></span>
|
|
<span>{s}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|