fix(theme): align initial theme and visual tokens
This commit is contained in:
@@ -15,13 +15,24 @@ export const metadata: Metadata = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const themeScript = `
|
||||||
|
try {
|
||||||
|
const savedTheme = localStorage.getItem('portfolio-theme');
|
||||||
|
const systemTheme = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
document.documentElement.dataset.theme = savedTheme || systemTheme;
|
||||||
|
} catch {}
|
||||||
|
`;
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" data-theme="light">
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
<head>
|
||||||
|
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<ThemeProvider>{children}</ThemeProvider>
|
<ThemeProvider>{children}</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -18,14 +18,15 @@ const ThemeContext = createContext<ThemeContextType>({
|
|||||||
|
|
||||||
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [theme, setThemeState] = useState<Theme>('light');
|
const [theme, setThemeState] = useState<Theme>('light');
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const savedTheme = localStorage.getItem('portfolio-theme') as Theme | null;
|
const savedTheme = localStorage.getItem('portfolio-theme') as Theme | null;
|
||||||
const initialTheme = savedTheme || 'light';
|
const systemTheme: Theme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
? 'dark'
|
||||||
|
: 'light';
|
||||||
|
const initialTheme = savedTheme || systemTheme;
|
||||||
setThemeState(initialTheme);
|
setThemeState(initialTheme);
|
||||||
document.documentElement.setAttribute('data-theme', initialTheme);
|
document.documentElement.setAttribute('data-theme', initialTheme);
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setTheme = (newTheme: Theme) => {
|
const setTheme = (newTheme: Theme) => {
|
||||||
|
|||||||
@@ -21,18 +21,6 @@ html {
|
|||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
html {
|
|
||||||
font-size: 93.75%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
|
||||||
html {
|
|
||||||
font-size: 87.5%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="dark"] {
|
html[data-theme="dark"] {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
}
|
}
|
||||||
@@ -117,9 +105,11 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: var(--font-size-h2);
|
max-width: 24ch;
|
||||||
line-height: var(--line-height-h2);
|
font-size: clamp(1.875rem, 3vw, 2.5rem);
|
||||||
font-weight: 700;
|
line-height: 1.15;
|
||||||
|
font-weight: 760;
|
||||||
|
letter-spacing: -0.035em;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -158,6 +148,20 @@ body {
|
|||||||
box-shadow var(--motion-duration-default) ease,
|
box-shadow var(--motion-duration-default) ease,
|
||||||
transform var(--motion-duration-fast) var(--motion-ease-out);
|
transform var(--motion-duration-fast) var(--motion-ease-out);
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-btn:focus-visible,
|
||||||
|
a:focus-visible,
|
||||||
|
button:focus-visible,
|
||||||
|
input:focus-visible {
|
||||||
|
outline: 3px solid var(--focus-ring);
|
||||||
|
outline-offset: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pill-btn:active,
|
||||||
|
button:active:not(:disabled) {
|
||||||
|
transform: translateY(1px) scale(0.99);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill-btn-outline {
|
.pill-btn-outline {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
--color-blue-800: #091C3F;
|
--color-blue-800: #091C3F;
|
||||||
--color-blue-900: #07132F;
|
--color-blue-900: #07132F;
|
||||||
--color-blue-950: #010D27;
|
--color-blue-950: #010D27;
|
||||||
--color-blue-white: #FFFFFF;
|
--color-blue-white: #F8FAFF;
|
||||||
--color-slate-300: #C3CFE0;
|
--color-slate-300: #C3CFE0;
|
||||||
--color-slate-400: #A3B1C6;
|
--color-slate-400: #A3B1C6;
|
||||||
--color-slate-600: #667085;
|
--color-slate-600: #667085;
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
--color-border-dark: #1E3458;
|
--color-border-dark: #1E3458;
|
||||||
--color-border-strong-light: #A9BEDA;
|
--color-border-strong-light: #A9BEDA;
|
||||||
--color-border-strong-dark: #426B9D;
|
--color-border-strong-dark: #426B9D;
|
||||||
--color-black: #000000;
|
--color-black: #07132F;
|
||||||
--space-0: 0;
|
--space-0: 0;
|
||||||
--space-1: 0.25rem;
|
--space-1: 0.25rem;
|
||||||
--space-2: 0.5rem;
|
--space-2: 0.5rem;
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
--font-size-h3: 1.25rem;
|
--font-size-h3: 1.25rem;
|
||||||
--font-size-body-large: 1.125rem;
|
--font-size-body-large: 1.125rem;
|
||||||
--font-size-body-default: 1rem;
|
--font-size-body-default: 1rem;
|
||||||
--font-size-body-small: 0.875rem;
|
--font-size-body-small: 0.9375rem;
|
||||||
--font-size-label-small: 0.75rem;
|
--font-size-label-small: 0.75rem;
|
||||||
--font-size-button: 0.9375rem;
|
--font-size-button: 0.9375rem;
|
||||||
--line-height-display-hero: 4.5rem;
|
--line-height-display-hero: 4.5rem;
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
--line-height-h3: 1.75rem;
|
--line-height-h3: 1.75rem;
|
||||||
--line-height-body-large: 1.875rem;
|
--line-height-body-large: 1.875rem;
|
||||||
--line-height-body-default: 1.625rem;
|
--line-height-body-default: 1.625rem;
|
||||||
--line-height-body-small: 1.375rem;
|
--line-height-body-small: 1.5rem;
|
||||||
--line-height-label-small: 1.125rem;
|
--line-height-label-small: 1.125rem;
|
||||||
--line-height-button: 1.25rem;
|
--line-height-button: 1.25rem;
|
||||||
--letter-spacing-eyebrow: 0.16em;
|
--letter-spacing-eyebrow: 0.16em;
|
||||||
@@ -87,9 +87,9 @@
|
|||||||
--motion-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
|
--motion-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
|
||||||
|
|
||||||
/* Semantic Tokens (Light) */
|
/* Semantic Tokens (Light) */
|
||||||
--bg-page: #FFFFFF;
|
--bg-page: #F8FAFF;
|
||||||
--bg-surface: #FAFAFA;
|
--bg-surface: #F1F6FD;
|
||||||
--bg-raised: #FFFFFF;
|
--bg-raised: #FCFDFF;
|
||||||
--bg-subtle: #E6F0FE;
|
--bg-subtle: #E6F0FE;
|
||||||
--text-primary: #0B2F5F;
|
--text-primary: #0B2F5F;
|
||||||
--text-secondary: #38526E;
|
--text-secondary: #38526E;
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
--accent-default: #3D8AFA;
|
--accent-default: #3D8AFA;
|
||||||
--action-link: #1557A6;
|
--action-link: #1557A6;
|
||||||
--action-primary-bg: #103F7F;
|
--action-primary-bg: #103F7F;
|
||||||
--action-primary-fg: #FFFFFF;
|
--action-primary-fg: #F8FAFF;
|
||||||
--action-primary-hover: #0B3268;
|
--action-primary-hover: #0B3268;
|
||||||
--action-primary-pressed: #08284F;
|
--action-primary-pressed: #08284F;
|
||||||
--brand-band: #103F7F;
|
--brand-band: #103F7F;
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
--text-primary: #F8FAFF;
|
--text-primary: #F8FAFF;
|
||||||
--text-secondary: #C3CFE0;
|
--text-secondary: #C3CFE0;
|
||||||
--text-muted: #A3B1C6;
|
--text-muted: #A3B1C6;
|
||||||
--text-on-band: #FFFFFF;
|
--text-on-band: #F8FAFF;
|
||||||
--border-default: #1E3458;
|
--border-default: #1E3458;
|
||||||
--border-strong: #426B9D;
|
--border-strong: #426B9D;
|
||||||
--accent-default: #82B5FF;
|
--accent-default: #82B5FF;
|
||||||
|
|||||||
Reference in New Issue
Block a user