unfied style

This commit is contained in:
root
2026-05-23 04:35:47 -04:00
parent fd10d0db6a
commit 07fba16ff2
57 changed files with 565 additions and 263 deletions
+11 -10
View File
@@ -87,6 +87,8 @@ const languageMeta = {
ar: { flag: '🇲🇦', shortLabel: 'AR' },
} as const
const SHARED_THEME_KEY = 'rentaldrivego-theme'
type AdminI18nContext = {
language: AdminLanguage
setLanguage: (value: AdminLanguage) => void
@@ -99,14 +101,14 @@ const Context = createContext<AdminI18nContext | null>(null)
export function AdminI18nProvider({ children }: { children: React.ReactNode }) {
const [language, setLanguage] = useState<AdminLanguage>('en')
const [theme, setTheme] = useState<AdminTheme>('dark')
const [theme, setTheme] = useState<AdminTheme>('light')
// Skip the very first write so we don't overwrite a stored preference with
// the default 'en' value before the hydration read-effect has applied it.
const skipFirstLangWrite = useRef(true)
useEffect(() => {
const stored = window.localStorage.getItem('admin-language')
const storedTheme = window.localStorage.getItem('admin-theme')
const storedTheme = window.localStorage.getItem(SHARED_THEME_KEY) ?? window.localStorage.getItem('admin-theme')
if (stored === 'en' || stored === 'fr' || stored === 'ar') {
setLanguage(stored)
}
@@ -136,6 +138,8 @@ export function AdminI18nProvider({ children }: { children: React.ReactNode }) {
document.documentElement.classList.add(theme)
document.documentElement.style.colorScheme = theme
document.body.dataset.theme = theme
document.cookie = `${SHARED_THEME_KEY}=${encodeURIComponent(theme)}; path=/; max-age=31536000; SameSite=Lax`
window.localStorage.setItem(SHARED_THEME_KEY, theme)
window.localStorage.setItem('admin-theme', theme)
}, [theme])
@@ -163,8 +167,8 @@ export function AdminLanguageSwitcher() {
if (embedded) return null
return (
<div className="flex items-center gap-1 rounded-full border border-zinc-700 bg-zinc-900 px-2 py-1 shadow-sm transition-colors">
<span className="px-2 text-[11px] font-semibold uppercase tracking-[0.16em] text-zinc-500">{dict.language}</span>
<div className="flex items-center gap-1 rounded-full border border-stone-200/80 bg-white/95 px-2 py-1 shadow-sm transition-colors dark:border-stone-700 dark:bg-stone-900/85">
<span className="px-2 text-[11px] font-semibold uppercase tracking-[0.16em] text-stone-500 dark:text-stone-400">{dict.language}</span>
{(['en', 'fr', 'ar'] as AdminLanguage[]).map((value) => {
const active = value === language
const meta = languageMeta[value]
@@ -174,7 +178,7 @@ export function AdminLanguageSwitcher() {
type="button"
onClick={() => setLanguage(value)}
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
active ? 'bg-zinc-100 text-zinc-950' : 'text-zinc-300 hover:bg-zinc-800'
active ? 'bg-stone-900 text-white dark:bg-amber-400 dark:text-stone-950' : 'text-stone-600 hover:bg-stone-100 dark:text-stone-300 dark:hover:bg-stone-800'
}`}
>
<span className="inline-flex items-center gap-1.5">
@@ -199,10 +203,7 @@ export function AdminThemeSwitcher() {
if (embedded) return null
return (
<div className="flex items-center gap-1 rounded-full border border-zinc-700 bg-zinc-900 px-2 py-1 shadow-sm transition-colors">
<span className="px-2 text-[11px] font-semibold uppercase tracking-[0.16em] text-zinc-500">
{dict.theme}
</span>
<div className="flex items-center gap-1 rounded-full border border-stone-200/80 bg-white/95 px-2 py-1 shadow-sm transition-colors dark:border-stone-700 dark:bg-stone-900/85">
{(['light', 'dark'] as AdminTheme[]).map((value) => {
const active = value === theme
return (
@@ -211,7 +212,7 @@ export function AdminThemeSwitcher() {
type="button"
onClick={() => setTheme(value)}
className={`rounded-full px-3 py-1.5 text-xs font-semibold transition ${
active ? 'bg-zinc-100 text-zinc-950' : 'text-zinc-300 hover:bg-zinc-800'
active ? 'bg-stone-900 text-white dark:bg-amber-400 dark:text-stone-950' : 'text-stone-600 hover:bg-stone-100 dark:text-stone-300 dark:hover:bg-stone-800'
}`}
>
{value === 'light' ? dict.light : dict.dark}
+3 -3
View File
@@ -28,11 +28,11 @@ export default function PublicFooter() {
}[language]
return (
<footer className="border-t border-stone-200 bg-white/90 px-4 py-4 backdrop-blur-md transition-colors dark:border-zinc-800 dark:bg-zinc-950/90">
<footer className="border-t border-stone-200/80 bg-white/72 px-4 py-4 backdrop-blur-xl transition-colors dark:border-stone-800 dark:bg-stone-950/72">
<div className="mx-auto flex max-w-6xl flex-col items-center justify-between gap-3 lg:flex-row">
<div className="flex items-center gap-3 text-xs font-medium uppercase tracking-[0.16em] text-stone-400 dark:text-zinc-500">
<div className="flex items-center gap-3 text-xs font-medium uppercase tracking-[0.16em] text-stone-400 dark:text-stone-500">
<p>{dict.preferences}</p>
<span className="inline-flex items-center gap-1 rounded-full border border-zinc-700 bg-zinc-900 px-2.5 py-1 text-zinc-200">
<span className="inline-flex items-center gap-1 rounded-full border border-stone-200/80 bg-white/95 px-2.5 py-1 text-stone-700 dark:border-stone-700 dark:bg-stone-900/85 dark:text-stone-200">
<span aria-hidden="true">{currentLanguage.flag}</span>
<span>{currentLanguage.shortLabel}</span>
</span>
+5 -5
View File
@@ -28,18 +28,18 @@ export default function PublicHeader() {
}[language]
return (
<header className="sticky top-0 z-30 border-b border-zinc-800 bg-zinc-950/90 backdrop-blur-md transition-colors">
<header className="sticky top-0 z-30 border-b border-stone-200/80 bg-white/78 backdrop-blur-xl transition-colors dark:border-stone-800 dark:bg-stone-950/76">
<div className="mx-auto flex max-w-6xl items-center justify-between gap-4 px-4 py-4">
<Link href="/" className="flex items-center gap-3">
<span className="text-xs font-semibold uppercase tracking-[0.24em] text-emerald-400">RentalDriveGo</span>
<span className="hidden text-sm font-semibold text-zinc-400 sm:inline">{dict.admin}</span>
<span className="text-xs font-semibold uppercase tracking-[0.24em] text-amber-700 dark:text-amber-300">RentalDriveGo</span>
<span className="hidden text-sm font-semibold text-stone-500 dark:text-stone-400 sm:inline">{dict.admin}</span>
</Link>
<nav className="flex items-center gap-2">
<span className="inline-flex min-w-[3.5rem] items-center justify-center gap-1 rounded-full border border-zinc-700 bg-zinc-900 px-2.5 py-2 text-xs font-semibold text-zinc-200">
<span className="inline-flex min-w-[3.5rem] items-center justify-center gap-1 rounded-full border border-stone-200/80 bg-white/95 px-2.5 py-2 text-xs font-semibold text-stone-700 dark:border-stone-700 dark:bg-stone-900/85 dark:text-stone-200">
<span aria-hidden="true">{currentLanguage.flag}</span>
<span>{currentLanguage.shortLabel}</span>
</span>
<Link href="/login" className="rounded-full bg-zinc-100 px-4 py-2 text-sm font-semibold text-zinc-950 transition hover:bg-zinc-300">
<Link href="/login" className="rounded-full bg-stone-900 px-4 py-2 text-sm font-semibold text-white transition hover:bg-stone-700 dark:bg-amber-400 dark:text-stone-950 dark:hover:bg-amber-300">
{dict.signIn}
</Link>
</nav>
+1 -1
View File
@@ -5,7 +5,7 @@ import PublicHeader from '@/components/PublicHeader'
export default function PublicShell({ children }: { children: React.ReactNode }) {
return (
<div className="flex min-h-screen flex-col bg-zinc-950 text-zinc-100 transition-colors">
<div className="flex min-h-screen flex-col bg-[linear-gradient(180deg,#f8f5ef_0%,#f4efe6_28%,#fffdf8_58%,#ffffff_100%)] text-stone-900 transition-colors dark:bg-[linear-gradient(180deg,#14110f_0%,#17120d_35%,#0c0a09_100%)] dark:text-stone-100">
<PublicHeader />
<div className="flex flex-1 flex-col">{children}</div>
<PublicFooter />