Translate admin panel to all 6 languages
This commit is contained in:
1 parent
f381aa987f
commit
befa4ec282
63 files changed
+9353
-1443
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { applyPreset, saveTheme } from "@/actions/admin-theme";
|
||||
import { siteSettings } from "@/lib/services/site-settings";
|
||||
import { FONTS, PRESETS } from "@/lib/theme-presets";
|
||||
@@ -35,7 +36,6 @@ const HEADINGS: { key: string; label: string; def: string }[] = [
|
||||
|
||||
const ALL_COLORS = [...COLOR_FIELDS, ...BUTTON_FIELDS];
|
||||
|
||||
/** A <input type=color> needs #rrggbb — fall back to the default otherwise. */
|
||||
function toHex(value: string | null, def: string): string {
|
||||
return value && /^#[0-9a-fA-F]{6}$/.test(value) ? value : def;
|
||||
}
|
||||
@@ -72,6 +72,8 @@ export default async function AdminTheme({
|
||||
}: {
|
||||
searchParams: Promise<{ saved?: string; preset?: string }>;
|
||||
}) {
|
||||
const t = await getTranslations("pages.admin.theme");
|
||||
|
||||
const sp = await searchParams;
|
||||
|
||||
const current = Object.fromEntries(
|
||||
@@ -95,27 +97,26 @@ export default async function AdminTheme({
|
||||
<span className="text-lg">🎨</span>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="m-0 text-xl font-extrabold text-[var(--color-text)]">Theme</h1>
|
||||
<h1 className="m-0 text-xl font-extrabold text-[var(--color-text)]">{t("title")}</h1>
|
||||
<p className="m-0 text-xs text-[var(--color-text-muted)] mt-0.5">
|
||||
Restyle the whole site. Values are written to <code>website_settings</code> and applied
|
||||
live (no rebuild).
|
||||
{t.rich("subtitle", { code: (chunks) => <code>{chunks}</code> })}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{sp.saved ? (
|
||||
<div className="mb-4 p-3 rounded-lg bg-green-600/10 text-green-600 dark:text-green-400 text-xs">
|
||||
Theme saved
|
||||
{t("saved")}
|
||||
</div>
|
||||
) : null}
|
||||
{sp.preset ? (
|
||||
<div className="mb-4 p-3 rounded-lg bg-green-600/10 text-green-600 dark:text-green-400 text-xs">
|
||||
Applied preset “{sp.preset}”
|
||||
{t("presetApplied", { preset: sp.preset })}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<section className="mt-6">
|
||||
<h2 className="admin-section-title">Presets</h2>
|
||||
<h2 className="admin-section-title">{t("presetsTitle")}</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{Object.entries(PRESETS).map(([name, palette]) => (
|
||||
<form key={name} action={applyPreset}>
|
||||
@@ -148,25 +149,25 @@ export default async function AdminTheme({
|
||||
|
||||
<form action={saveTheme}>
|
||||
<section className="mt-6">
|
||||
<h2 className="admin-section-title">Colours</h2>
|
||||
<h2 className="admin-section-title">{t("colours")}</h2>
|
||||
<div className="admin-card">
|
||||
{colorGrid(COLOR_FIELDS, current)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="mt-6">
|
||||
<h2 className="admin-section-title">Buttons & links</h2>
|
||||
<h2 className="admin-section-title">{t("buttonsLinks")}</h2>
|
||||
<div className="admin-card">
|
||||
{colorGrid(BUTTON_FIELDS, current)}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="mt-6">
|
||||
<h2 className="admin-section-title">Typography & layout</h2>
|
||||
<h2 className="admin-section-title">{t("typographyLayout")}</h2>
|
||||
<div className="admin-card">
|
||||
<div className="flex flex-wrap gap-5 items-center">
|
||||
<label className="flex items-center gap-2">
|
||||
<span className="text-sm">Font</span>
|
||||
<span className="text-sm">{t("font")}</span>
|
||||
<select name="font_family" defaultValue={fontKey}>
|
||||
{Object.entries(FONTS).map(([key, f]) => (
|
||||
<option key={key} value={key}>
|
||||
@@ -189,7 +190,7 @@ export default async function AdminTheme({
|
||||
</label>
|
||||
))}
|
||||
<label className="flex items-center gap-2">
|
||||
<span className="text-sm">Border radius (px)</span>
|
||||
<span className="text-sm">{t("borderRadius")}</span>
|
||||
<input
|
||||
name="border_radius"
|
||||
type="number"
|
||||
@@ -204,22 +205,21 @@ export default async function AdminTheme({
|
||||
</section>
|
||||
|
||||
<section className="mt-6">
|
||||
<h2 className="admin-section-title">Custom CSS</h2>
|
||||
<h2 className="admin-section-title">{t("cssTitle")}</h2>
|
||||
<p className="text-xs text-[var(--color-text-muted)] mb-2">
|
||||
Injected raw into every page (after the theme variables). Use it for tweaks the controls
|
||||
above don’t cover.
|
||||
{t("cssSubtitle")}
|
||||
</p>
|
||||
<textarea
|
||||
name="custom_css"
|
||||
defaultValue={customCss}
|
||||
rows={8}
|
||||
spellCheck={false}
|
||||
placeholder={"/* e.g. */\n.nav-item { letter-spacing: 0.5px; }"}
|
||||
placeholder={t("cssPlaceholder")}
|
||||
className="w-full font-mono text-sm"
|
||||
/>
|
||||
<div className="mt-4 text-right">
|
||||
<button type="submit" className="btn btn-primary">
|
||||
Save theme
|
||||
{t("saveCss")}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in new issue
Block a user