- rename the theme everywhere: id terminal -> skeuo, desktop sim skeuo -> desktop, skeleton terminal shell -> SkeuoLayout, page.css -> shared.css (shared components), old skeuo.css -> desktop.css, storage key theme -> dmx-theme (with migration) - rebuild the theme as a walnut-and-aluminium home-lab console: brass plates, patch bay, analogue gym gauges, clipboard, stitched leather logbook, service rack with pilot lamps, framed print, chart recorder, cartridge, software box, pegboard tags, card-index drawer - all materials are CSS + inline-SVG noise (no texture images); Barlow Semi Condensed + Courier Prime via next/font with fallbacks - desktop mode is now phone-only (<=768px): switch hidden above that, stored desktop preference overridden, sim never mounted on wide viewports - drop the ASCII train background and its gruvbox.webp asset
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useRef } from "react";
|
|
import { useServerInsertedHTML } from "next/navigation";
|
|
|
|
// Runs before paint so the saved theme and the phone/desktop split are applied
|
|
// without a flash. It is injected with useServerInsertedHTML so the <script>
|
|
// lives in the SSR HTML stream instead of inside the React tree — React 19
|
|
// logs an error for script tags rendered by components on the client.
|
|
//
|
|
// Theme ids were renamed (skeuo = the site, desktop = the KDE sim) and the
|
|
// storage key moved from `theme` to `dmx-theme`, so this migrates the old
|
|
// values once: terminal -> skeuo, skeuo -> desktop.
|
|
const INIT_SCRIPT = `(function(){try{
|
|
var d=document.documentElement;
|
|
var mq=window.matchMedia('(max-width:768px)');
|
|
var stored=null;
|
|
try{stored=localStorage.getItem('dmx-theme');}catch(e){}
|
|
if(stored!=='skeuo'&&stored!=='desktop'){
|
|
var legacy=null;
|
|
try{legacy=localStorage.getItem('theme');}catch(e){}
|
|
if(legacy==='terminal'||legacy==='skeuo')stored=legacy==='terminal'?'skeuo':'desktop';
|
|
if(legacy!==null){try{localStorage.setItem('dmx-theme',stored||'skeuo');localStorage.removeItem('theme');}catch(e){}}
|
|
}
|
|
var theme=(stored==='desktop'&&mq.matches)?'desktop':'skeuo';
|
|
d.setAttribute('data-theme',theme);
|
|
var ua=navigator.userAgent||'';
|
|
var phone=/(iPhone|iPod|Android.+Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini|Mobile)/i.test(ua);
|
|
d.setAttribute('data-device',phone?'phone':'desktop');
|
|
}catch(e){}})();`;
|
|
|
|
export default function ThemeScript() {
|
|
// useServerInsertedHTML can fire several times during a single render pass;
|
|
// guard so the script only lands in the document once.
|
|
const inserted = useRef(false);
|
|
|
|
useServerInsertedHTML(() => {
|
|
if (inserted.current) return null;
|
|
inserted.current = true;
|
|
return (
|
|
<script
|
|
id="theme-init"
|
|
suppressHydrationWarning
|
|
dangerouslySetInnerHTML={{ __html: INIT_SCRIPT }}
|
|
/>
|
|
);
|
|
});
|
|
|
|
return null;
|
|
}
|