x
This commit is contained in:
1 parent
f9c4046d35
commit
c365add07f
3 files changed
+120
-9
No files matched your search
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -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} />
|
||||
|
||||
@@ -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%),
|
||||
|
||||
Reference in new issue
Block a user