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
37
README.md
37
README.md
|
|
@ -5,9 +5,9 @@
|
||||||
It's an **editorial-style personal site** in a **gruvbox** palette, with the whole KDE
|
It's an **editorial-style personal site** in a **gruvbox** palette, with the whole KDE
|
||||||
desktop simulation kept behind a "Desktop mode" button. Two modes, one content set:
|
desktop simulation kept behind a "Desktop mode" button. Two modes, one content set:
|
||||||
|
|
||||||
- **Gruvbox editorial** (default) — a technical-print layout: serif headlines, mono labels in
|
- **Web** (default) — the editorial site: a technical-print layout painted in the gruvbox
|
||||||
the margin, hairline rules and a data strip. No images at all; the only graphics are the
|
palette, with serif headlines, mono labels in the margin, hairline rules and a data strip. No
|
||||||
social icons, used as monochrome CSS masks.
|
images at all; the only graphics are the social icons, used as monochrome CSS masks.
|
||||||
- **Desktop mode** — the KDE Plasma / Windows-style **desktop simulation**: draggable
|
- **Desktop mode** — the KDE Plasma / Windows-style **desktop simulation**: draggable
|
||||||
snap-to-grid icons, resizable/floating windows, a Start menu, taskbar, live clock and a
|
snap-to-grid icons, resizable/floating windows, a Start menu, taskbar, live clock and a
|
||||||
working in-browser terminal (Alacritty). Reachable from the "Desktop mode" button and hidden
|
working in-browser terminal (Alacritty). Reachable from the "Desktop mode" button and hidden
|
||||||
|
|
@ -19,13 +19,13 @@ heatmap**, gym SBD and links to friends' sites.
|
||||||
|
|
||||||
## ✨ Features
|
## ✨ Features
|
||||||
|
|
||||||
- **Gruvbox editorial by default** — a technical-print layout: serif headlines, mono labels in
|
- **Web theme is the landing view** — the site always opens on the editorial page; the theme is
|
||||||
the margin, hairline rules, a data strip. Text and type only — the sole graphics are the
|
deliberately not persisted, so a reload never drops you into the desktop. A technical-print
|
||||||
social icons, rendered as monochrome CSS masks.
|
layout with serif headlines, mono labels in the margin, hairline rules and a data strip. Text
|
||||||
- **Desktop mode (desktop-only)** — a "Desktop mode" button swaps to the KDE-style desktop;
|
and type only — the sole graphics are the social icons, rendered as monochrome CSS masks.
|
||||||
the choice persists in `localStorage` (applied pre-paint to avoid a flash). Phones never get
|
- **Desktop mode (desktop-only)** — a "Desktop mode" button swaps to the KDE-style desktop for
|
||||||
it: the pre-paint script forces gruvbox and CSS hides the button, so the old iOS-style phone
|
the session. Phones never get it: the buttons are hidden, so the old iOS-style phone home
|
||||||
home screen is gone.
|
screen is gone.
|
||||||
- **Draggable desktop icons** — free placement that snaps to a measured grid, one icon per
|
- **Draggable desktop icons** — free placement that snaps to a measured grid, one icon per
|
||||||
cell, with a follow-the-cursor drag ghost. Icons shrink on cramped viewports so they never
|
cell, with a follow-the-cursor drag ghost. Icons shrink on cramped viewports so they never
|
||||||
collide.
|
collide.
|
||||||
|
|
@ -61,10 +61,11 @@ heatmap**, gym SBD and links to friends' sites.
|
||||||
|
|
||||||
- **Framework:** Next.js 16 (App Router, Turbopack)
|
- **Framework:** Next.js 16 (App Router, Turbopack)
|
||||||
- **Language:** TypeScript, React 19 (client components everywhere interactivity lives)
|
- **Language:** TypeScript, React 19 (client components everywhere interactivity lives)
|
||||||
- **Styling:** `src/app/globals.css` is the gruvbox editorial design system (CSS custom
|
- **Styling:** `src/app/globals.css` is the web editorial design system — the gruvbox palette as
|
||||||
properties, Tailwind v4 `@theme`/`@utility`, base + scroll reveals). `editorial.css` holds
|
CSS custom properties, plus Tailwind v4 `@theme`/`@utility`, base and scroll reveals.
|
||||||
page helpers; `page.css` keeps the shared component styles the desktop apps still use, and
|
`editorial.css` holds page helpers; `page.css` keeps the shared component styles the desktop
|
||||||
`skeuo.css` is the KDE desktop. The editorial page itself is built from Tailwind utilities.
|
apps still use, and `skeuo.css` is the KDE desktop. The editorial page is built from Tailwind
|
||||||
|
utilities.
|
||||||
- **Fonts:** Newsreader (display) + IBM Plex Sans/Mono (body/labels) via `next/font/google`;
|
- **Fonts:** Newsreader (display) + IBM Plex Sans/Mono (body/labels) via `next/font/google`;
|
||||||
the desktop keeps its system sans stack.
|
the desktop keeps its system sans stack.
|
||||||
- **Images:** `next/image` — but the editorial page uses none (social SVGs as monochrome masks only).
|
- **Images:** `next/image` — but the editorial page uses none (social SVGs as monochrome masks only).
|
||||||
|
|
@ -170,7 +171,7 @@ they contend for `:3000` and `.next/dev/lock`.
|
||||||
src/app/
|
src/app/
|
||||||
page.tsx → renders <ThemeRoot/>, imports the theme stylesheets
|
page.tsx → renders <ThemeRoot/>, imports the theme stylesheets
|
||||||
layout.tsx → html shell + metadata; loads the fonts; injects ThemeScript
|
layout.tsx → html shell + metadata; loads the fonts; injects ThemeScript
|
||||||
globals.css → gruvbox editorial design system (tokens, @utility classes, base)
|
globals.css → web editorial design system (gruvbox palette; tokens, @utility classes, base)
|
||||||
editorial.css → editorial page helpers (social masks, heatmap)
|
editorial.css → editorial page helpers (social masks, heatmap)
|
||||||
page.css → shared component styles still used by the desktop apps
|
page.css → shared component styles still used by the desktop apps
|
||||||
skeuo.css → KDE desktop styles
|
skeuo.css → KDE desktop styles
|
||||||
|
|
@ -182,10 +183,10 @@ src/app/
|
||||||
frame/route.ts → header-stripping proxy for unframeable friend sites
|
frame/route.ts → header-stripping proxy for unframeable friend sites
|
||||||
ping/route.ts → service health check (HTTP + Minecraft)
|
ping/route.ts → service health check (HTTP + Minecraft)
|
||||||
components/
|
components/
|
||||||
ThemeRoot.tsx → gruvbox editorial vs. Desktop mode
|
ThemeRoot.tsx → web editorial vs. Desktop mode
|
||||||
ThemeScript.tsx → pre-paint script: theme + device detection
|
ThemeScript.tsx → pre-paint script: device detection
|
||||||
useTheme.ts → theme state via useSyncExternalStore
|
useTheme.ts → theme state via useSyncExternalStore
|
||||||
EditorialSite.tsx → the gruvbox editorial page (nav, hero, sections)
|
EditorialSite.tsx → the web editorial page (nav, hero, sections)
|
||||||
editorial-ui.tsx → editorial primitives: Section, ServiceRow, Contributions, …
|
editorial-ui.tsx → editorial primitives: Section, ServiceRow, Contributions, …
|
||||||
WindowsDesktop.tsx → desktop shell: icons, windows, taskbar, Start menu
|
WindowsDesktop.tsx → desktop shell: icons, windows, taskbar, Start menu
|
||||||
WinWindow.tsx → one draggable/resizable window
|
WinWindow.tsx → one draggable/resizable window
|
||||||
|
|
|
||||||
19
agents.md
19
agents.md
|
|
@ -34,7 +34,7 @@ When in doubt, prefer updating. A stale README **or** agents.md is treated as a
|
||||||
## What this project is
|
## What this project is
|
||||||
|
|
||||||
Personal portfolio site for **dvorakmortonxd.dev**. The default view is a
|
Personal portfolio site for **dvorakmortonxd.dev**. The default view is a
|
||||||
**gruvbox editorial page** (a technical-print layout, no images); a "Desktop mode"
|
**web editorial page** (a technical-print layout, no images); a "Desktop mode"
|
||||||
button swaps to a **KDE Plasma desktop simulation**. Phones only ever get the
|
button swaps to a **KDE Plasma desktop simulation**. Phones only ever get the
|
||||||
editorial page.
|
editorial page.
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ token.** Do not print it, copy it into new files, or push it anywhere else.
|
||||||
src/app/
|
src/app/
|
||||||
page.tsx → renders <ThemeRoot/>, imports the theme stylesheets
|
page.tsx → renders <ThemeRoot/>, imports the theme stylesheets
|
||||||
layout.tsx → html shell, metadata, next/font, ThemeScript
|
layout.tsx → html shell, metadata, next/font, ThemeScript
|
||||||
globals.css → gruvbox editorial design system (tokens, @utility, base, reveals)
|
globals.css → web editorial design system (gruvbox palette; tokens, @utility, base, reveals)
|
||||||
editorial.css → editorial page helpers (social masks, heatmap)
|
editorial.css → editorial page helpers (social masks, heatmap)
|
||||||
page.css → shared component styles used by the desktop apps
|
page.css → shared component styles used by the desktop apps
|
||||||
skeuo.css → KDE Plasma desktop styles
|
skeuo.css → KDE Plasma desktop styles
|
||||||
|
|
@ -90,7 +90,7 @@ src/app/
|
||||||
frame/route.ts → header-stripping proxy so an unframeable friend site loads in a window; host allowlist
|
frame/route.ts → header-stripping proxy so an unframeable friend site loads in a window; host allowlist
|
||||||
components/
|
components/
|
||||||
ThemeRoot.tsx → editorial page by default, desktop when theme === "skeuo"
|
ThemeRoot.tsx → editorial page by default, desktop when theme === "skeuo"
|
||||||
EditorialSite.tsx → the gruvbox editorial page (nav, hero, sections)
|
EditorialSite.tsx → the web editorial page (nav, hero, sections)
|
||||||
editorial-ui.tsx → editorial primitives: Reveal, Section, ServiceRow, Contributions, …
|
editorial-ui.tsx → editorial primitives: Reveal, Section, ServiceRow, Contributions, …
|
||||||
WindowsDesktop.tsx → "skeuo" theme, desktop: icons, windows, taskbar
|
WindowsDesktop.tsx → "skeuo" theme, desktop: icons, windows, taskbar
|
||||||
WinWindow.tsx → a single draggable/resizable window
|
WinWindow.tsx → a single draggable/resizable window
|
||||||
|
|
@ -109,19 +109,18 @@ scripts/
|
||||||
```
|
```
|
||||||
|
|
||||||
### How UI selection works
|
### How UI selection works
|
||||||
1. `ThemeScript` runs before paint. It reads `localStorage.theme` and sets
|
1. `ThemeScript` runs before paint and sets `data-device` (`phone` | `desktop`)
|
||||||
`data-theme` (`gruvbox` | `skeuo`) and `data-device` (`phone` | `desktop`) on
|
from a user-agent sniff. It does **not** read a stored theme, so the page always
|
||||||
`<html>` from a user-agent sniff. On a phone it forces `gruvbox` and CSS hides
|
lands on `web`. CSS hides every `.desktop-toggle` on phones.
|
||||||
every `.desktop-toggle`, so the desktop is unreachable there.
|
|
||||||
2. `useTheme()` (in `useTheme.ts`) reads `data-theme` via `useSyncExternalStore`;
|
2. `useTheme()` (in `useTheme.ts`) reads `data-theme` via `useSyncExternalStore`;
|
||||||
`setTheme` writes the attribute, persists to `localStorage`, and dispatches
|
`setTheme` sets the attribute and dispatches `theme-change`. Nothing is
|
||||||
`theme-change`.
|
persisted, so a reload returns to `web`.
|
||||||
3. `ThemeRoot` renders `EditorialSite` unless `theme === "skeuo"`, in which case it
|
3. `ThemeRoot` renders `EditorialSite` unless `theme === "skeuo"`, in which case it
|
||||||
mounts `WindowsDesktop` instead. The editorial page stays mounted (hidden) while
|
mounts `WindowsDesktop` instead. The editorial page stays mounted (hidden) while
|
||||||
the desktop is up so its scroll position survives; the desktop mounts on demand
|
the desktop is up so its scroll position survives; the desktop mounts on demand
|
||||||
(phones can never reach `skeuo`).
|
(phones can never reach `skeuo`).
|
||||||
|
|
||||||
Modes: `gruvbox` = the default editorial site, `skeuo` = KDE Plasma desktop.
|
Modes: `web` = the editorial site (default/landing), `skeuo` = KDE Plasma desktop.
|
||||||
|
|
||||||
The editorial page is **asset-free** apart from the social SVGs, which are used as
|
The editorial page is **asset-free** apart from the social SVGs, which are used as
|
||||||
monochrome CSS masks (`.social-mask` in `editorial.css`). `linkedin.svg` is a filled
|
monochrome CSS masks (`.social-mask` in `editorial.css`). `linkedin.svg` is a filled
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ import { useTheme } from "./useTheme";
|
||||||
import EditorialSite from "./EditorialSite";
|
import EditorialSite from "./EditorialSite";
|
||||||
import WindowsDesktop from "./WindowsDesktop";
|
import WindowsDesktop from "./WindowsDesktop";
|
||||||
|
|
||||||
// The gruvbox editorial site is the default. Phones can never reach the KDE
|
// The web editorial site is the default and always the landing view (the theme
|
||||||
// desktop: ThemeScript forces gruvbox there (ignoring a stored "skeuo") and CSS
|
// is not persisted). Phones can never reach the KDE desktop: the Desktop-mode
|
||||||
// hides the Desktop-mode buttons, so `theme === "skeuo"` is desktop-only.
|
// buttons are hidden there, so `theme === "skeuo"` only happens on desktop.
|
||||||
//
|
//
|
||||||
// The editorial page stays mounted (hidden) while the desktop is up, so its
|
// The editorial page stays mounted (hidden) while the desktop is up, so its
|
||||||
// scroll position survives a round-trip. The desktop mounts on demand.
|
// scroll position survives a round-trip. The desktop mounts on demand.
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,10 @@
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { useServerInsertedHTML } from "next/navigation";
|
import { useServerInsertedHTML } from "next/navigation";
|
||||||
|
|
||||||
// Runs before paint so the saved theme and the phone/desktop split are applied
|
// Runs before paint to set the phone/desktop split. The theme itself is not
|
||||||
// without a flash. It is injected with useServerInsertedHTML so the <script>
|
// read from storage — the web theme is always the landing view — so this only
|
||||||
// lives in the SSR HTML stream instead of inside the React tree — React 19
|
// tags the device, which CSS uses to hide the Desktop-mode button on phones.
|
||||||
// logs an error for script tags rendered by components on the client.
|
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){}})();`;
|
||||||
//
|
|
||||||
// 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){}})();`;
|
|
||||||
|
|
||||||
export default function ThemeScript() {
|
export default function ThemeScript() {
|
||||||
// useServerInsertedHTML can fire several times during a single render pass;
|
// useServerInsertedHTML can fire several times during a single render pass;
|
||||||
|
|
|
||||||
|
|
@ -577,10 +577,10 @@ export default function WindowsDesktop() {
|
||||||
type="button"
|
type="button"
|
||||||
className="win-theme-toggle"
|
className="win-theme-toggle"
|
||||||
onClick={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 aria-hidden="true">{theme === "skeuo" ? "▚" : "❖"}</span>
|
||||||
<span>{theme === "skeuo" ? "Gruvbox" : "Desktop"}</span>
|
<span>{theme === "skeuo" ? "Web" : "Desktop"}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Clock className="win-clock" />
|
<Clock className="win-clock" />
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,14 @@ function WelcomeApp() {
|
||||||
<li>Drag windows around by their title bar.</li>
|
<li>Drag windows around by their title bar.</li>
|
||||||
<li>Use the buttons at the top-right to minimize, maximize or close.</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>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>
|
</ul>
|
||||||
<p className="app-preference">
|
<p className="app-preference">
|
||||||
If you'd prefer a normal website{" "}
|
If you'd prefer a normal website{" "}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="app-inline-link"
|
className="app-inline-link"
|
||||||
onClick={() => setTheme("gruvbox")}
|
onClick={() => setTheme("web")}
|
||||||
>
|
>
|
||||||
click here
|
click here
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -2,37 +2,30 @@
|
||||||
|
|
||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
|
|
||||||
// "gruvbox" is the editorial site (the default). "skeuo" is the KDE desktop,
|
// "web" is the editorial site and always the landing view. "skeuo" is the KDE
|
||||||
// reachable from the editorial page's Desktop-mode button on non-phones.
|
// desktop, reachable from the editorial page's Desktop-mode button. The choice
|
||||||
export type Theme = "gruvbox" | "skeuo";
|
// 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";
|
const EVENT = "theme-change";
|
||||||
|
|
||||||
function subscribe(callback: () => void) {
|
function subscribe(callback: () => void) {
|
||||||
window.addEventListener(EVENT, callback);
|
window.addEventListener(EVENT, callback);
|
||||||
window.addEventListener("storage", callback);
|
return () => window.removeEventListener(EVENT, callback);
|
||||||
return () => {
|
|
||||||
window.removeEventListener(EVENT, callback);
|
|
||||||
window.removeEventListener("storage", callback);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSnapshot(): Theme {
|
function getSnapshot(): Theme {
|
||||||
return document.documentElement.getAttribute("data-theme") === "skeuo" ? "skeuo" : "gruvbox";
|
return document.documentElement.getAttribute("data-theme") === "skeuo" ? "skeuo" : "web";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerSnapshot(): Theme {
|
function getServerSnapshot(): Theme {
|
||||||
return "gruvbox";
|
return "web";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setTheme(theme: Theme) {
|
export function setTheme(theme: Theme) {
|
||||||
if (typeof document === "undefined") return;
|
if (typeof document === "undefined") return;
|
||||||
document.documentElement.setAttribute("data-theme", theme);
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
try {
|
|
||||||
localStorage.setItem("theme", theme);
|
|
||||||
} catch {
|
|
||||||
/* ignore */
|
|
||||||
}
|
|
||||||
window.dispatchEvent(new Event(EVENT));
|
window.dispatchEvent(new Event(EVENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +34,6 @@ export function useTheme() {
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
toggle: () => setTheme(theme === "skeuo" ? "gruvbox" : "skeuo"),
|
toggle: () => setTheme(theme === "skeuo" ? "web" : "skeuo"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
GRUVBOX EDITORIAL THEME (default)
|
WEB THEME (default)
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
A "technical print" layout in gruvbox dark-hard. Tokens live
|
A "technical print" layout painted in the gruvbox dark-hard
|
||||||
here; the page markup uses Tailwind utilities plus the
|
palette. Tokens live here; the page markup uses Tailwind
|
||||||
@utility classes below. Everything visual is scoped to
|
utilities plus the @utility classes below. Everything visual
|
||||||
html[data-theme="gruvbox"] so the skeuo desktop (which reads
|
is scoped to html[data-theme="web"] so the skeuo desktop
|
||||||
its own vars from skeuo.css) is never affected.
|
(which reads its own vars from skeuo.css) is never affected.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Beats page.css's :root when the editorial theme is active. */
|
/* Beats page.css's :root when the editorial theme is active. */
|
||||||
html[data-theme="gruvbox"] {
|
html[data-theme="web"] {
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
--accent: #fe8019;
|
--accent: #fe8019;
|
||||||
--accent2: #d65d0e;
|
--accent2: #d65d0e;
|
||||||
|
|
@ -64,13 +64,13 @@ html[data-theme="gruvbox"] {
|
||||||
--font-display: var(--font-news);
|
--font-display: var(--font-news);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="gruvbox"] {
|
html[data-theme="web"] {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
scroll-padding-top: 5.5rem;
|
scroll-padding-top: 5.5rem;
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="gruvbox"] body {
|
html[data-theme="web"] body {
|
||||||
background-color: var(--bg);
|
background-color: var(--bg);
|
||||||
background-image: radial-gradient(120% 60% at 50% -10%, rgba(254, 128, 25, 0.05), transparent 70%);
|
background-image: radial-gradient(120% 60% at 50% -10%, rgba(254, 128, 25, 0.05), transparent 70%);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
@ -82,29 +82,29 @@ html[data-theme="gruvbox"] body {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="gruvbox"] ::selection {
|
html[data-theme="web"] ::selection {
|
||||||
background: rgba(254, 128, 25, 0.28);
|
background: rgba(254, 128, 25, 0.28);
|
||||||
color: var(--ink);
|
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: 2px solid var(--accent);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="gruvbox"] ::-webkit-scrollbar {
|
html[data-theme="web"] ::-webkit-scrollbar {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-track {
|
html[data-theme="web"] ::-webkit-scrollbar-track {
|
||||||
background: var(--bg-well);
|
background: var(--bg-well);
|
||||||
}
|
}
|
||||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-thumb {
|
html[data-theme="web"] ::-webkit-scrollbar-thumb {
|
||||||
background: #3c3836;
|
background: #3c3836;
|
||||||
border: 3px solid var(--bg-well);
|
border: 3px solid var(--bg-well);
|
||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
}
|
}
|
||||||
html[data-theme="gruvbox"] ::-webkit-scrollbar-thumb:hover {
|
html[data-theme="web"] ::-webkit-scrollbar-thumb:hover {
|
||||||
background: #504945;
|
background: #504945;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ html[data-device="phone"] .desktop-toggle {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
html[data-theme="gruvbox"] {
|
html[data-theme="web"] {
|
||||||
scroll-behavior: auto;
|
scroll-behavior: auto;
|
||||||
}
|
}
|
||||||
.reveal {
|
.reveal {
|
||||||
|
|
@ -284,7 +284,7 @@ html[data-device="phone"] .desktop-toggle {
|
||||||
Helpers
|
Helpers
|
||||||
------------------------------------------------------------------ */
|
------------------------------------------------------------------ */
|
||||||
|
|
||||||
html[data-theme="gruvbox"] .link {
|
html[data-theme="web"] .link {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-decoration-thickness: 1px;
|
text-decoration-thickness: 1px;
|
||||||
|
|
@ -292,13 +292,13 @@ html[data-theme="gruvbox"] .link {
|
||||||
text-decoration-color: rgba(254, 128, 25, 0.4);
|
text-decoration-color: rgba(254, 128, 25, 0.4);
|
||||||
transition: text-decoration-color 150ms ease-out;
|
transition: text-decoration-color 150ms ease-out;
|
||||||
}
|
}
|
||||||
html[data-theme="gruvbox"] .link:hover {
|
html[data-theme="web"] .link:hover {
|
||||||
text-decoration-color: var(--accent);
|
text-decoration-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-theme="gruvbox"] .hide-scrollbar {
|
html[data-theme="web"] .hide-scrollbar {
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
html[data-theme="gruvbox"] .hide-scrollbar::-webkit-scrollbar {
|
html[data-theme="web"] .hide-scrollbar::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export default function RootLayout({
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
lang="en"
|
lang="en"
|
||||||
data-theme="gruvbox"
|
data-theme="web"
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
className={`${news.variable} ${plex.variable} ${plexMono.variable}`}
|
className={`${news.variable} ${plex.variable} ${plexMono.variable}`}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
SKEUOMORPHIC THEME
|
SKEUOMORPHIC THEME
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
Desktop -> KDE Plasma (Breeze)
|
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
|
site is the default; this is the alternate, reachable from
|
||||||
the editorial page's Desktop-mode button or the tray.
|
the editorial page's Desktop-mode button or the tray.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue