disable theme switching + fixed some visual bugs

This commit is contained in:
2026-05-15 19:15:40 +02:00
parent dcec203378
commit 86e2c9dbfa
3 changed files with 37 additions and 98 deletions
@@ -1,58 +0,0 @@
import { useState, useEffect, useRef } from 'react';
const THEMES = [
{ value: 'salon', label: 'Salon' },
{ value: 'salon-noir', label: 'Salon Noir' },
{ value: 'gothic', label: 'Gothic' },
{ value: 'breakcore', label: 'Breakcore' },
];
interface Props {
defaultTheme?: string;
}
export default function ThemeSwitcher({ defaultTheme = 'salon' }: Props) {
const [theme, setTheme] = useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('user-theme') || defaultTheme;
}
return defaultTheme;
});
const [toast, setToast] = useState<string | null>(null);
const isFirst = useRef(true);
useEffect(() => {
const html = document.documentElement;
THEMES.forEach(t => html.classList.remove(t.value));
html.classList.add(theme);
localStorage.setItem('user-theme', theme);
if (isFirst.current) {
isFirst.current = false;
return;
}
const label = THEMES.find(t => t.value === theme)?.label ?? theme;
setToast(`Theme: ${label}`);
const id = setTimeout(() => setToast(null), 1200);
return () => clearTimeout(id);
}, [theme]);
return (
<div className="relative inline-block text-left">
<select
value={theme}
onChange={(e) => setTheme(e.target.value)}
aria-label="Theme"
className="topbar-control theme-select"
>
{THEMES.map(t => (
<option key={t.value} value={t.value}>{t.label}</option>
))}
</select>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-[var(--subtext0)]">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/></svg>
</div>
{toast && <div className="toast" role="status">{toast}</div>}
</div>
);
}
+5 -5
View File
@@ -3,7 +3,6 @@ import '../styles/global.css';
import '@fontsource-variable/fraunces';
import '@fontsource-variable/eb-garamond';
import '@fontsource-variable/jetbrains-mono';
import ThemeSwitcher from '../components/react/ThemeSwitcher';
import Search from '../components/react/Search';
import LogoutButton from '../components/react/LogoutButton';
import EditableText from '../components/react/EditableText';
@@ -77,9 +76,11 @@ const hasContact = (siteConfig.contact_links?.length ?? 0) > 0;
{image && <meta name="twitter:image" content={image} />}
<link rel="alternate" type="application/rss+xml" title={siteConfig.title} href="/feed.xml" />
{siteConfig.custom_css && <style set:html={siteConfig.custom_css} />}
<script is:inline define:vars={{ defaultTheme: siteConfig.theme }}>
const savedTheme = localStorage.getItem('user-theme') || defaultTheme || 'salon';
document.documentElement.classList.add(savedTheme);
<script is:inline define:vars={{ siteTheme: siteConfig.theme }}>
// Theme is owner-controlled (site config). Drop any legacy
// per-visitor override so everyone sees the configured theme.
try { localStorage.removeItem('user-theme'); } catch (e) {}
document.documentElement.classList.add(siteTheme || 'salon');
</script>
<script is:inline>
// When a page is restored from the back/forward cache (e.g. after
@@ -129,7 +130,6 @@ const hasContact = (siteConfig.contact_links?.length ?? 0) > 0;
<a href="/contact" class="topbar-control">Contact</a>
)}
<Search client:idle />
<ThemeSwitcher client:only="react" defaultTheme={siteConfig.theme} />
<span class="topbar-divider" aria-hidden="true"></span>
{isAdmin ? (
<LogoutButton client:idle />
+32 -35
View File
@@ -790,17 +790,35 @@ code, pre, kbd, samp {
}
.plate-tag-mini {
position: absolute;
bottom: 18px;
right: 18px;
background: color-mix(in srgb, var(--crust) 78%, transparent);
bottom: 16px;
right: 16px;
background: color-mix(in srgb, var(--crust) 70%, transparent);
color: var(--rosewater);
border: 1px solid color-mix(in srgb, var(--rosewater) 22%, transparent);
font-family: var(--font-display);
font-size: 0.7rem;
letter-spacing: 0.16em;
padding: 3px 8px;
border: 1px solid color-mix(in srgb, var(--rosewater) 18%, transparent);
border-radius: 999px;
font-family: var(--font-sans);
font-size: 0.6rem;
font-weight: 600;
letter-spacing: 0.22em;
padding: 4px 11px;
text-transform: uppercase;
backdrop-filter: blur(2px);
backdrop-filter: blur(3px);
}
/* Breakcore: hard neon catalogue tag — sharp rect, offset shadow, glow.
* Matches the layer's hazard-tape / hard-offset chrome language. */
.breakcore .plate-tag-mini {
background: var(--crust);
color: var(--green);
border: 1px solid var(--mauve);
border-radius: 0;
font-family: var(--font-mono);
font-weight: 500;
letter-spacing: 0.14em;
text-shadow: 0 0 6px color-mix(in srgb, var(--green) 60%, transparent);
box-shadow:
2px 2px 0 var(--mauve),
0 0 14px -2px color-mix(in srgb, var(--mauve) 65%, transparent);
backdrop-filter: none;
}
/* Nameplate — the museum-style header used in the site chrome */
@@ -811,19 +829,6 @@ code, pre, kbd, samp {
gap: 2px;
position: relative;
}
.nameplate::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -6px;
height: 2px;
background: linear-gradient(to right,
var(--mauve) 0%,
var(--mauve) 35%,
var(--surface2) 35%,
var(--surface2) 100%);
}
.nameplate-title {
font-family: var(--font-display);
font-weight: 600;
@@ -831,7 +836,10 @@ code, pre, kbd, samp {
font-size: 1.6rem;
letter-spacing: -0.01em;
color: var(--text);
line-height: 1.12;
/* Loose enough that italic-Fraunces descenders (g, y, p) and the
* breakcore chromatic glow clear the line box — nothing slices them. */
line-height: 1.2;
padding-bottom: 0.06em;
}
.nameplate-subtitle {
font-family: var(--font-sans);
@@ -1275,18 +1283,7 @@ input[type="date"] { color-scheme: light; }
);
}
/* Nameplate — striped datamosh underline + glitch-shear burst on hover. */
.breakcore .nameplate::after {
height: 3px;
bottom: -6px;
opacity: 0.9;
background: repeating-linear-gradient(
90deg,
var(--mauve) 0 6px,
var(--green) 6px 12px,
var(--blue) 12px 18px
);
}
/* Nameplate — glitch-shear burst on hover (underline removed site-wide). */
@keyframes bc-shear {
0% { clip-path: inset(0 0 0 0); transform: translateX(0);
text-shadow: -1px 0 0 var(--teal), 1px 0 0 var(--mauve); }