This commit is contained in:
Your Name committed 2026-06-21 00:13:43 -04:00
1 parent f9c4046d35
commit c365add07f
3 files changed
+120 -9

No files matched your search

+69 -4
View File
@@ -17,12 +17,46 @@ const defaultThemeTokens = {
mutedText: '#666666',
linePrimary: '#00B900',
linePrimaryHover: '#009900',
fontBody: 'system-ui, sans-serif',
fontDisplay: 'system-ui, sans-serif',
fontBody: '',
fontDisplay: '',
shadowCard: '0 10px 25px rgba(0,0,0,0.05)',
shadowCardHover: '0 20px 40px rgba(0,0,0,0.1)',
}
const FONT_PRESETS = {
locale: {
label: 'Locale default',
body: '',
display: '',
},
sarabun: {
label: 'Sarabun',
body: 'var(--font-sarabun, "Sarabun"), "Noto Sans Thai", ui-sans-serif, system-ui, sans-serif',
display: 'var(--font-sarabun, "Sarabun"), "Noto Sans Thai", ui-sans-serif, system-ui, sans-serif',
},
kanit: {
label: 'Kanit',
body: 'var(--font-kanit, "Kanit"), "Noto Sans Thai", ui-sans-serif, system-ui, sans-serif',
display: 'var(--font-kanit, "Kanit"), "Noto Sans Thai", ui-sans-serif, system-ui, sans-serif',
},
} as const
type FontPresetKey = keyof typeof FONT_PRESETS
function resolveFontPreset(themeTokens: Record<string, string>) {
const body = themeTokens.fontBody?.trim() || ''
const display = themeTokens.fontDisplay?.trim() || ''
const fontBody = body || display
const fontDisplay = display || body
if (!fontBody && !fontDisplay) return 'locale'
if (fontBody === FONT_PRESETS.sarabun.body && fontDisplay === FONT_PRESETS.sarabun.display) return 'sarabun'
if (fontBody === FONT_PRESETS.kanit.body && fontDisplay === FONT_PRESETS.kanit.display) return 'kanit'
return 'custom'
}
export default function SystemSettingsPage() {
const [loading, setLoading] = useState(true)
const [saving, setSaving] = useState(false)
@@ -49,6 +83,17 @@ export default function SystemSettingsPage() {
const [footerSupportHeading, setFooterSupportHeading] = useState('')
const [footerCopyrightText, setFooterCopyrightText] = useState('')
const [themeTokens, setThemeTokens] = useState<Record<string, string>>(defaultThemeTokens)
const fontPreset = resolveFontPreset(themeTokens)
const applyFontPreset = (preset: FontPresetKey | 'custom') => {
if (preset === 'custom') return
setThemeTokens((current) => ({
...current,
fontBody: FONT_PRESETS[preset].body,
fontDisplay: FONT_PRESETS[preset].display,
}))
}
useEffect(() => {
fetch(`${API_BASE}/settings`)
@@ -365,6 +410,25 @@ export default function SystemSettingsPage() {
<h2 className="text-lg font-bold uppercase tracking-widest text-white">Theme Tokens</h2>
</div>
<div className="space-y-2">
<label className="text-xs uppercase font-bold tracking-widest text-slate-400">Font Preset</label>
<select
value={fontPreset}
onChange={e => applyFontPreset(e.target.value as FontPresetKey | 'custom')}
className="admin-input w-full max-w-sm bg-slate-900 border-white/10"
>
{Object.entries(FONT_PRESETS).map(([key, preset]) => (
<option key={key} value={key}>
{preset.label}
</option>
))}
<option value="custom">Custom</option>
</select>
<p className="text-[10px] text-slate-400">
Select a ready-made font stack, or use custom overrides below when you need a special brand voice.
</p>
</div>
<div className="grid gap-6 md:grid-cols-2">
{[
['brandPrimary', 'Brand Primary'],
@@ -391,8 +455,8 @@ export default function SystemSettingsPage() {
<div className="grid gap-6 md:grid-cols-2">
{[
['fontBody', 'Font Body'],
['fontDisplay', 'Font Display'],
['fontBody', 'Font Body Override'],
['fontDisplay', 'Font Display Override'],
['shadowCard', 'Shadow Card'],
['shadowCardHover', 'Shadow Card Hover'],
].map(([key, label]) => (
@@ -403,6 +467,7 @@ export default function SystemSettingsPage() {
value={themeTokens[key] || ''}
onChange={e => setThemeTokens((current) => ({ ...current, [key]: e.target.value }))}
className="admin-input w-full"
placeholder={key.startsWith('font') ? 'Leave blank to use locale preset' : undefined}
/>
</div>
))}
+18 -3
View File
@@ -1,4 +1,5 @@
import type { Metadata } from 'next';
import { Kanit, Sarabun } from 'next/font/google';
import { notFound } from 'next/navigation';
import '../globals.css';
import Navbar from '@/components/Navbar';
@@ -10,6 +11,20 @@ import type { MenuItem, StoreSettings } from '@homaroma/types';
import { isSupportedLocale } from '@/lib/locales';
import type { CSSProperties } from 'react';
const sarabun = Sarabun({
subsets: ['latin', 'thai'],
display: 'swap',
weight: ['300', '400', '500', '600', '700'],
variable: '--font-sarabun',
});
const kanit = Kanit({
subsets: ['latin', 'thai'],
display: 'swap',
weight: ['300', '400', '500', '600', '700'],
variable: '--font-kanit',
});
export const metadata: Metadata = {
title: 'HomAroma',
description: 'Pure Origins, Artisan Craft, Zero Compromise',
@@ -96,8 +111,8 @@ function buildThemeStyle(settings: StoreSettings | null): CSSProperties | undefi
['--color-muted-text', tokens.mutedText],
['--color-line-primary', tokens.linePrimary],
['--color-line-primary-hover', tokens.linePrimaryHover],
['--font-body', tokens.fontBody],
['--font-display', tokens.fontDisplay],
['--font-body-active', tokens.fontBody],
['--font-display-active', tokens.fontDisplay],
['--shadow-card', tokens.shadowCard],
['--shadow-card-hover', tokens.shadowCardHover],
]
@@ -134,7 +149,7 @@ export default async function RootLayout({
const themeStyle = buildThemeStyle(settings)
return (
<html lang={lang} className="scroll-smooth">
<html lang={lang} className={`${sarabun.variable} ${kanit.variable} scroll-smooth`}>
<body className="min-h-screen bg-surface-page text-text-main font-sans antialiased" style={themeStyle}>
<ClientProviders>
<Navbar categories={categories} initialMenu={initialMenu} settings={settings} />
+33 -2
View File
@@ -1,8 +1,8 @@
@import "tailwindcss";
@theme {
--font-body: var(--font-sarabun, ui-sans-serif), system-ui, sans-serif;
--font-display: var(--font-body);
--font-body: var(--font-body-active, var(--font-body-locale, ui-sans-serif)), system-ui, sans-serif;
--font-display: var(--font-display-active, var(--font-display-locale, var(--font-body-locale, ui-sans-serif))), system-ui, sans-serif;
--font-sans: var(--font-body);
--color-brand-primary: #FF6B6B;
@@ -45,6 +45,37 @@
}
@layer base {
:root,
html {
--font-body-locale: var(--font-sarabun, "Sarabun"), "Noto Sans Thai", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
html[lang="en"] {
--font-body-locale: "Inter", "Segoe UI", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
html[lang="ja"] {
--font-body-locale: "Hiragino Sans", "Yu Gothic", "Noto Sans JP", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
html[lang="zh"] {
--font-body-locale: "PingFang SC", "Microsoft YaHei", "Noto Sans SC", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
html[lang="ko"] {
--font-body-locale: "Apple SD Gothic Neo", "Malgun Gothic", "Noto Sans KR", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
html[lang="vi"] {
--font-body-locale: "Inter", "Segoe UI", ui-sans-serif, system-ui, sans-serif;
--font-display-locale: var(--font-body-locale);
}
body {
@apply bg-surface-page text-text-main font-sans antialiased;
background-image: radial-gradient(circle at top right, rgba(255,107,107,0.15), transparent 40%),