rename the editorial theme to "web" and make it the landing view (stop persisting the theme, so a reload never opens the desktop)
This commit is contained in:
parent
39f383b7cf
commit
40824dbcb1
10 changed files with 70 additions and 81 deletions
|
|
@ -4,9 +4,9 @@ import { useTheme } from "./useTheme";
|
|||
import EditorialSite from "./EditorialSite";
|
||||
import WindowsDesktop from "./WindowsDesktop";
|
||||
|
||||
// The gruvbox editorial site is the default. Phones can never reach the KDE
|
||||
// desktop: ThemeScript forces gruvbox there (ignoring a stored "skeuo") and CSS
|
||||
// hides the Desktop-mode buttons, so `theme === "skeuo"` is desktop-only.
|
||||
// The web editorial site is the default and always the landing view (the theme
|
||||
// is not persisted). Phones can never reach the KDE desktop: the Desktop-mode
|
||||
// buttons are hidden there, so `theme === "skeuo"` only happens on desktop.
|
||||
//
|
||||
// The editorial page stays mounted (hidden) while the desktop is up, so its
|
||||
// scroll position survives a round-trip. The desktop mounts on demand.
|
||||
|
|
|
|||
|
|
@ -3,14 +3,10 @@
|
|||
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.
|
||||
//
|
||||
// Phones always get gruvbox: the desktop mode is mouse-oriented, so we ignore a
|
||||
// stored "skeuo" there and the CSS also hides the Desktop-mode button.
|
||||
const INIT_SCRIPT = `(function(){try{var t=localStorage.getItem('theme');var ua=navigator.userAgent||'';var phone=/(iPhone|iPod|Android.+Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini|Mobile)/i.test(ua);document.documentElement.setAttribute('data-device',phone?'phone':'desktop');if(phone){t='gruvbox';}if(t==='gruvbox'||t==='skeuo'){document.documentElement.setAttribute('data-theme',t);}}catch(e){}})();`;
|
||||
// Runs before paint to set the phone/desktop split. The theme itself is not
|
||||
// read from storage — the web theme is always the landing view — so this only
|
||||
// tags the device, which CSS uses to hide the Desktop-mode button on phones.
|
||||
const INIT_SCRIPT = `(function(){try{var ua=navigator.userAgent||'';var phone=/(iPhone|iPod|Android.+Mobile|Windows Phone|IEMobile|BlackBerry|Opera Mini|Mobile)/i.test(ua);document.documentElement.setAttribute('data-device',phone?'phone':'desktop');}catch(e){}})();`;
|
||||
|
||||
export default function ThemeScript() {
|
||||
// useServerInsertedHTML can fire several times during a single render pass;
|
||||
|
|
|
|||
|
|
@ -577,10 +577,10 @@ export default function WindowsDesktop() {
|
|||
type="button"
|
||||
className="win-theme-toggle"
|
||||
onClick={toggle}
|
||||
title={`Switch to ${theme === "skeuo" ? "gruvbox" : "Desktop"} theme`}
|
||||
title={`Switch to ${theme === "skeuo" ? "web" : "Desktop"} theme`}
|
||||
>
|
||||
<span aria-hidden="true">{theme === "skeuo" ? "▚" : "❖"}</span>
|
||||
<span>{theme === "skeuo" ? "Gruvbox" : "Desktop"}</span>
|
||||
<span>{theme === "skeuo" ? "Web" : "Desktop"}</span>
|
||||
</button>
|
||||
|
||||
<Clock className="win-clock" />
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ function WelcomeApp() {
|
|||
<li>Drag windows around by their title bar.</li>
|
||||
<li>Use the buttons at the top-right to minimize, maximize or close.</li>
|
||||
<li>Open apps from the Gentoo launcher, bottom-left.</li>
|
||||
<li>Switch back to the Gruvbox theme from the panel tray, bottom-right.</li>
|
||||
<li>Switch back to the web theme from the panel tray, bottom-right.</li>
|
||||
</ul>
|
||||
<p className="app-preference">
|
||||
If you'd prefer a normal website{" "}
|
||||
<button
|
||||
type="button"
|
||||
className="app-inline-link"
|
||||
onClick={() => setTheme("gruvbox")}
|
||||
onClick={() => setTheme("web")}
|
||||
>
|
||||
click here
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -2,37 +2,30 @@
|
|||
|
||||
import { useSyncExternalStore } from "react";
|
||||
|
||||
// "gruvbox" is the editorial site (the default). "skeuo" is the KDE desktop,
|
||||
// reachable from the editorial page's Desktop-mode button on non-phones.
|
||||
export type Theme = "gruvbox" | "skeuo";
|
||||
// "web" is the editorial site and always the landing view. "skeuo" is the KDE
|
||||
// desktop, reachable from the editorial page's Desktop-mode button. The choice
|
||||
// is deliberately NOT persisted, so a reload always comes back to the web theme
|
||||
// (and there is no wrong-theme flash on load).
|
||||
export type Theme = "web" | "skeuo";
|
||||
|
||||
const EVENT = "theme-change";
|
||||
|
||||
function subscribe(callback: () => void) {
|
||||
window.addEventListener(EVENT, callback);
|
||||
window.addEventListener("storage", callback);
|
||||
return () => {
|
||||
window.removeEventListener(EVENT, callback);
|
||||
window.removeEventListener("storage", callback);
|
||||
};
|
||||
return () => window.removeEventListener(EVENT, callback);
|
||||
}
|
||||
|
||||
function getSnapshot(): Theme {
|
||||
return document.documentElement.getAttribute("data-theme") === "skeuo" ? "skeuo" : "gruvbox";
|
||||
return document.documentElement.getAttribute("data-theme") === "skeuo" ? "skeuo" : "web";
|
||||
}
|
||||
|
||||
function getServerSnapshot(): Theme {
|
||||
return "gruvbox";
|
||||
return "web";
|
||||
}
|
||||
|
||||
export function setTheme(theme: Theme) {
|
||||
if (typeof document === "undefined") return;
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
try {
|
||||
localStorage.setItem("theme", theme);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
window.dispatchEvent(new Event(EVENT));
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +34,6 @@ export function useTheme() {
|
|||
return {
|
||||
theme,
|
||||
setTheme,
|
||||
toggle: () => setTheme(theme === "skeuo" ? "gruvbox" : "skeuo"),
|
||||
toggle: () => setTheme(theme === "skeuo" ? "web" : "skeuo"),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
/* ============================================================
|
||||
GRUVBOX EDITORIAL THEME (default)
|
||||
WEB THEME (default)
|
||||
------------------------------------------------------------
|
||||
A "technical print" layout in gruvbox dark-hard. Tokens live
|
||||
here; the page markup uses Tailwind utilities plus the
|
||||
@utility classes below. Everything visual is scoped to
|
||||
html[data-theme="gruvbox"] so the skeuo desktop (which reads
|
||||
its own vars from skeuo.css) is never affected.
|
||||
A "technical print" layout painted in the gruvbox dark-hard
|
||||
palette. Tokens live here; the page markup uses Tailwind
|
||||
utilities plus the @utility classes below. Everything visual
|
||||
is scoped to html[data-theme="web"] so the skeuo desktop
|
||||
(which reads its own vars from skeuo.css) is never affected.
|
||||
============================================================ */
|
||||
|
||||
:root {
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
|
||||
/* Beats page.css's :root when the editorial theme is active. */
|
||||
html[data-theme="gruvbox"] {
|
||||
html[data-theme="web"] {
|
||||
color-scheme: dark;
|
||||
--accent: #fe8019;
|
||||
--accent2: #d65d0e;
|
||||
|
|
@ -64,13 +64,13 @@ html[data-theme="gruvbox"] {
|
|||
--font-display: var(--font-news);
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] {
|
||||
html[data-theme="web"] {
|
||||
scroll-behavior: smooth;
|
||||
scroll-padding-top: 5.5rem;
|
||||
background-color: var(--bg);
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] body {
|
||||
html[data-theme="web"] body {
|
||||
background-color: var(--bg);
|
||||
background-image: radial-gradient(120% 60% at 50% -10%, rgba(254, 128, 25, 0.05), transparent 70%);
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -82,29 +82,29 @@ html[data-theme="gruvbox"] body {
|
|||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] ::selection {
|
||||
html[data-theme="web"] ::selection {
|
||||
background: rgba(254, 128, 25, 0.28);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
|
||||
html[data-theme="web"] :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] ::-webkit-scrollbar {
|
||||
html[data-theme="web"] ::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-track {
|
||||
html[data-theme="web"] ::-webkit-scrollbar-track {
|
||||
background: var(--bg-well);
|
||||
}
|
||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-thumb {
|
||||
html[data-theme="web"] ::-webkit-scrollbar-thumb {
|
||||
background: #3c3836;
|
||||
border: 3px solid var(--bg-well);
|
||||
border-radius: 99px;
|
||||
}
|
||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-thumb:hover {
|
||||
html[data-theme="web"] ::-webkit-scrollbar-thumb:hover {
|
||||
background: #504945;
|
||||
}
|
||||
|
||||
|
|
@ -264,7 +264,7 @@ html[data-device="phone"] .desktop-toggle {
|
|||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html[data-theme="gruvbox"] {
|
||||
html[data-theme="web"] {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
.reveal {
|
||||
|
|
@ -284,7 +284,7 @@ html[data-device="phone"] .desktop-toggle {
|
|||
Helpers
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
html[data-theme="gruvbox"] .link {
|
||||
html[data-theme="web"] .link {
|
||||
color: var(--accent);
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 1px;
|
||||
|
|
@ -292,13 +292,13 @@ html[data-theme="gruvbox"] .link {
|
|||
text-decoration-color: rgba(254, 128, 25, 0.4);
|
||||
transition: text-decoration-color 150ms ease-out;
|
||||
}
|
||||
html[data-theme="gruvbox"] .link:hover {
|
||||
html[data-theme="web"] .link:hover {
|
||||
text-decoration-color: var(--accent);
|
||||
}
|
||||
|
||||
html[data-theme="gruvbox"] .hide-scrollbar {
|
||||
html[data-theme="web"] .hide-scrollbar {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
html[data-theme="gruvbox"] .hide-scrollbar::-webkit-scrollbar {
|
||||
html[data-theme="web"] .hide-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default function RootLayout({
|
|||
return (
|
||||
<html
|
||||
lang="en"
|
||||
data-theme="gruvbox"
|
||||
data-theme="web"
|
||||
suppressHydrationWarning
|
||||
className={`${news.variable} ${plex.variable} ${plexMono.variable}`}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
SKEUOMORPHIC THEME
|
||||
------------------------------------------------------------
|
||||
Desktop -> KDE Plasma (Breeze)
|
||||
Active when <html data-theme="skeuo">. The gruvbox editorial
|
||||
Active when <html data-theme="skeuo">. The web editorial
|
||||
site is the default; this is the alternate, reachable from
|
||||
the editorial page's Desktop-mode button or the tray.
|
||||
============================================================ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue