diff --git a/README.md b/README.md
index d0a1674..fd8214c 100644
--- a/README.md
+++ b/README.md
@@ -2,27 +2,30 @@
> The source code for my personal website, **[dvorakmortonxd.dev](https://dvorakmortonxd.dev)**.
-This is not a normal portfolio page. It ships **two fully interactive shells** and picks
-which one to show based on the saved theme and the device, all from the same content:
+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:
-- **`skeuo`** (default) — a KDE Plasma / Windows-style **desktop simulation**: draggable
- snap-to-grid icons, resizable/floating windows, a Start menu, taskbar and live clock.
- On phones it becomes an **iOS-style home screen** with a widget grid, dock, drag-to-reorder
- and an iOS launch animation.
-- **`terminal`** — a **Gruvbox TUI** version of the site: TUI panels, an animated ASCII
- train background, a clickable easter-egg logo, and a working in-browser terminal (Alacritty)
- with commands like `help`, `ls`, `cat`, `neofetch`, `emerge`, `ssh` and more.
+- **Gruvbox editorial** (default) — a technical-print layout: serif headlines, mono labels in
+ the margin, hairline rules and a data strip. No 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
+ 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
+ on phones.
-Both shells surface the same personal content: socials, self-hosted services with **live
+Both modes surface the same personal content: socials, self-hosted services with **live
up/down health checks**, a hardware collection, coding projects, a **GitDXD contribution
-heatmap**, a gym SBD panel and links to friends' sites.
+heatmap**, gym SBD and links to friends' sites.
## ✨ Features
-- **Two themes / shells** — KDE-style desktop and Gruvbox terminal, toggled from either UI
- and persisted in `localStorage` (applied pre-paint to avoid a flash).
-- **Phone vs. desktop detection** — a user-agent sniff on `` decides whether
- the desktop or the mobile home screen is shown.
+- **Gruvbox editorial by default** — a technical-print layout: serif headlines, mono labels in
+ the margin, hairline rules, a data strip. Text and type only — the sole graphics are the
+ social icons, rendered as monochrome CSS masks.
+- **Desktop mode (desktop-only)** — a "Desktop mode" button swaps to the KDE-style desktop;
+ the choice persists in `localStorage` (applied pre-paint to avoid a flash). Phones never get
+ it: the pre-paint script forces gruvbox and CSS hides the button, so the old iOS-style phone
+ home screen is gone.
- **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
collide.
@@ -58,13 +61,14 @@ heatmap**, a gym SBD panel and links to friends' sites.
- **Framework:** Next.js 16 (App Router, Turbopack)
- **Language:** TypeScript, React 19 (client components everywhere interactivity lives)
-- **Styling:** hand-written CSS — `src/app/page.css` (terminal theme), `src/app/skeuo.css`
- (desktop + mobile), `src/app/globals.css` (base/reset). Tailwind v4 is imported for the
- base layer but the UI is custom CSS.
-- **Fonts:** Monocraft (self-hosted in `public/`, used by the terminal theme; the desktop
- theme uses the system sans stack)
-- **Images:** `next/image`
-- **Version:** `2.1.0` (see `package.json`)
+- **Styling:** `src/app/globals.css` is the gruvbox editorial design system (CSS custom
+ properties, Tailwind v4 `@theme`/`@utility`, base + scroll reveals). `editorial.css` holds
+ page helpers; `page.css` keeps the shared component styles the desktop apps still use, and
+ `skeuo.css` is the KDE desktop. The editorial page itself is built from Tailwind utilities.
+- **Fonts:** Newsreader (display) + IBM Plex Sans/Mono (body/labels) via `next/font/google`;
+ the desktop keeps its system sans stack.
+- **Images:** `next/image` — but the editorial page uses none (social SVGs as monochrome masks only).
+- **Version:** `3.0.0` (see `package.json`)
## 🚀 Running Locally
@@ -164,33 +168,34 @@ they contend for `:3000` and `.next/dev/lock`.
```
src/app/
- page.tsx → renders , imports the two theme stylesheets
- layout.tsx → html shell + metadata, injects ThemeScript
- globals.css → base/reset styles + Tailwind import
- page.css → terminal theme styles
- skeuo.css → desktop + mobile home styles
+ page.tsx → renders , imports the theme stylesheets
+ layout.tsx → html shell + metadata; loads the fonts; injects ThemeScript
+ globals.css → gruvbox editorial design system (tokens, @utility classes, base)
+ editorial.css → editorial page helpers (social masks, heatmap)
+ page.css → shared component styles still used by the desktop apps
+ skeuo.css → KDE desktop styles
data.ts → socials, codingProjects, techProjects, friends, wallpapers
revival-inc/page.tsx → embeds the bundled game at /public/revival-inc/index.html
api/
heatmap/route.ts → contribution heatmap proxy
activities/route.ts → GitDXD activity feed proxy
+ frame/route.ts → header-stripping proxy for unframeable friend sites
ping/route.ts → service health check (HTTP + Minecraft)
components/
- ThemeRoot.tsx → picks which shell(s) to mount
+ ThemeRoot.tsx → gruvbox editorial vs. Desktop mode
ThemeScript.tsx → pre-paint script: theme + device detection
useTheme.ts → theme state via useSyncExternalStore
- TerminalLayout.tsx → the Gruvbox terminal shell
+ EditorialSite.tsx → the gruvbox editorial page (nav, hero, sections)
+ editorial-ui.tsx → editorial primitives: Section, ServiceRow, Contributions, …
WindowsDesktop.tsx → desktop shell: icons, windows, taskbar, Start menu
- MobileHome.tsx → phone shell: iOS home screen + app view
WinWindow.tsx → one draggable/resizable window
apps.tsx → APPS registry, window contents, in-app terminal
useDesktopIcons.ts → desktop icon grid + drag/drop logic
- useDragOrder.ts → list reordering (mobile grid/dock)
- ServiceButton.tsx → service link + live status dot
- ContributionHeatmap.tsx → heatmap + recent commits widget
+ useDragOrder.ts → list reordering (used inside apps)
+ ServiceButton.tsx → desktop service link + live status dot
+ ContributionHeatmap.tsx → desktop heatmap + recent commits widget
Clock.tsx → live clock
JokerLogo.tsx → logo with click easter egg
- SlBackground.tsx → animated ASCII train background
scripts/
dev-server.mjs → custom dev server: live updates without the dev-only debug surface
deploy/
diff --git a/agents.md b/agents.md
index d947705..3017000 100644
--- a/agents.md
+++ b/agents.md
@@ -33,16 +33,18 @@ When in doubt, prefer updating. A stale README **or** agents.md is treated as a
## What this project is
-Personal portfolio site for **dvorakmortonxd.dev**. It's not a normal website —
-it ships **two fully interactive desktop/OS simulations** plus a terminal, and
-picks which one to show based on theme and device.
+Personal portfolio site for **dvorakmortonxd.dev**. The default view is a
+**gruvbox editorial page** (a technical-print layout, no images); a "Desktop mode"
+button swaps to a **KDE Plasma desktop simulation**. Phones only ever get the
+editorial page.
- Framework: **Next.js 16** (App Router, Turbopack), **React 19**, TypeScript.
-- Styling: plain CSS files (`page.css`, `skeuo.css`), no CSS-in-JS, no Tailwind
- utilities in the components (Tailwind is present via PostCSS but the look is
- hand-written CSS).
+- Styling: **Tailwind v4** for the editorial page — `globals.css` is the design
+ system (CSS custom properties, `@theme` tokens, `@utility` classes) — plus plain
+ CSS for the desktop (`skeuo.css`) and the shared component styles the desktop
+ apps still use (`page.css`).
- Path alias: `@/*` → `src/*`.
-- Version: `2.1.0` (see `package.json`).
+- Version: `3.0.0` (see `package.json`).
### Scripts
```bash
@@ -73,12 +75,13 @@ token.** Do not print it, copy it into new files, or push it anywhere else.
```
src/app/
- page.tsx → renders , imports page.css + skeuo.css
- layout.tsx → html shell, metadata, ThemeScript
- globals.css → base/reset styles + Tailwind import
+ page.tsx → renders , imports the theme stylesheets
+ layout.tsx → html shell, metadata, next/font, ThemeScript
+ globals.css → gruvbox editorial design system (tokens, @utility, base, reveals)
+ editorial.css → editorial page helpers (social masks, heatmap)
+ page.css → shared component styles used by the desktop apps
+ skeuo.css → KDE Plasma desktop styles
data.ts → socials, codingProjects, techProjects, friends, wallpapers
- page.css → base / terminal theme styles
- skeuo.css → Windows/Plasma desktop + mobile home styles
revival-inc/page.tsx → fullscreen iframe embedding /public/revival-inc/index.html
api/
heatmap/route.ts → proxy for git.dvorakmortonxd.dev contribution heatmap
@@ -86,38 +89,44 @@ src/app/
ping/route.ts → service health check (HTTP + minecraft:// via mcstatus.io); host allowlist
frame/route.ts → header-stripping proxy so an unframeable friend site loads in a window; host allowlist
components/
- ThemeRoot.tsx → picks which shell to show (the router of the UI)
- TerminalLayout.tsx → "terminal" theme (Gruvbox)
+ ThemeRoot.tsx → editorial page by default, desktop when theme === "skeuo"
+ EditorialSite.tsx → the gruvbox editorial page (nav, hero, sections)
+ editorial-ui.tsx → editorial primitives: Reveal, Section, ServiceRow, Contributions, …
WindowsDesktop.tsx → "skeuo" theme, desktop: icons, windows, taskbar
- MobileHome.tsx → "skeuo" theme, phone: app grid + dock
WinWindow.tsx → a single draggable/resizable window
apps.tsx → APPS registry + the content of each app + in-app terminal
+ embedded-site windows + the Minecraft-style SMP menu
useDesktopIcons.ts → desktop icon grid + drag/drop (THE KEY FILE, see below)
- useDragOrder.ts → simple list reordering (mobile home screen only)
+ useDragOrder.ts → simple list reordering (used inside desktop apps)
useTheme.ts → theme state via useSyncExternalStore
ThemeScript.tsx → inline pre-hydration script: theme + device detection
- ServiceButton.tsx → service link + live status dot (pings /api/ping)
- ContributionHeatmap.tsx → heatmap + recent-commit widget (uses the two proxies)
+ ServiceButton.tsx → desktop service link + live status dot (pings /api/ping)
+ ContributionHeatmap.tsx → desktop heatmap + recent-commit widget (uses the two proxies)
Clock.tsx → live clock (useSyncExternalStore + interval)
JokerLogo.tsx → site logo with a click easter egg
- SlBackground.tsx → animated ASCII train background (terminal theme)
scripts/
dev-server.mjs → custom dev server: live updates minus the dev-only debug surface
```
### How UI selection works
1. `ThemeScript` runs before paint. It reads `localStorage.theme` and sets
- `data-theme` (`skeuo` | `terminal`) and `data-device` (`phone` | `desktop`)
- on `` from a user-agent sniff.
-2. `useTheme()` (in `useTheme.ts`) reads `data-theme` via
- `useSyncExternalStore` and dispatches a `theme-change` event on toggle.
-3. `ThemeRoot` shows the terminal when `theme === "terminal"`; otherwise it
- mounts **both** `WindowsDesktop` and `MobileHome` and lets CSS
- (`html[data-device="phone"]`) decide which is visible. The desktop stays
- mounted while hidden so the Welcome window isn't recreated.
+ `data-theme` (`gruvbox` | `skeuo`) and `data-device` (`phone` | `desktop`) on
+ `` from a user-agent sniff. On a phone it forces `gruvbox` and CSS hides
+ every `.desktop-toggle`, so the desktop is unreachable there.
+2. `useTheme()` (in `useTheme.ts`) reads `data-theme` via `useSyncExternalStore`;
+ `setTheme` writes the attribute, persists to `localStorage`, and dispatches
+ `theme-change`.
+3. `ThemeRoot` renders `EditorialSite` unless `theme === "skeuo"`, in which case it
+ mounts `WindowsDesktop` instead. The editorial page stays mounted (hidden) while
+ the desktop is up so its scroll position survives; the desktop mounts on demand
+ (phones can never reach `skeuo`).
-Themes: `skeuo` = KDE Plasma / Windows desktop, `terminal` = Gruvbox terminal.
+Modes: `gruvbox` = the default editorial site, `skeuo` = KDE Plasma desktop.
+
+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
+badge that masks to a plain square, so `editorial-ui.tsx` renders an inline mark for
+it instead. The desktop still uses the image assets.
---
@@ -180,9 +189,9 @@ Guard (already in place, keep it that way):
`e.target` is always the button.
### Related
-`useDragOrder.ts` is a **different, simpler** hook used only by `MobileHome` for
-reordering the phone app grid/dock (drag one item over another to swap). It is
-list reordering, not free placement. Don't confuse the two.
+`useDragOrder.ts` is a **different, simpler** hook used inside the desktop apps
+for reordering lists (drag one item over another to swap). It is list reordering,
+not free placement. Don't confuse the two.
---
@@ -216,11 +225,12 @@ list reordering, not free placement. Don't confuse the two.
- Components are client components (`"use client"` at the top) — they use
pointer events and window APIs freely.
-- CSS classes are prefixed by area: `win-` (desktop), `mobile-` (phone),
- `app-` / `kickoff` / `terminal` etc. Grep by prefix to find styles.
-- Several places deliberately use **imperative DOM work** (drag ghost,
- transform-origin for the mobile launch animation). This is intentional for
- performance; prefer matching the existing pattern over "Reactifying" it.
+- CSS classes are prefixed by area: `win-` (desktop), `app-` / `kickoff` etc.
+ (desktop windows), plus the editorial design-system classes (`shell`, `display`,
+ `label`, `rule*`, `glass*`). Grep by prefix to find styles.
+- Several places deliberately use **imperative DOM work** (e.g. the drag ghost).
+ This is intentional for performance; prefer matching the existing pattern over
+ "Reactifying" it.
- `setState` inside an effect is blocked by the ESLint config
(`react-hooks/set-state-in-effect`). The one intentional exception is the
grid init in `useDesktopIcons.ts`, which carries a scoped
diff --git a/package.json b/package.json
index 0c02d90..4491ef0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "dvorakmortonxd",
- "version": "2.1.0",
+ "version": "3.0.0",
"private": true,
"scripts": {
"dev": "node scripts/dev-server.mjs",
diff --git a/src/app/api/ping/route.ts b/src/app/api/ping/route.ts
index 0bc19d4..ddcddc2 100644
--- a/src/app/api/ping/route.ts
+++ b/src/app/api/ping/route.ts
@@ -8,8 +8,8 @@ import { NextResponse } from 'next/server';
//
// Host matching is exact or by subdomain (e.g. anything under
// dvorakmortonxd.dev). Keep this in sync with the ServiceButton `url`/`checkUrl`
-// values in components/apps.tsx and components/TerminalLayout.tsx, and with the
-// friend list in data.ts.
+// values in components/apps.tsx and the services list in
+// components/EditorialSite.tsx, and with the friend list in data.ts.
const ALLOWED_HOSTS = [
'dvorakmortonxd.dev', // ai / jelly / navidrome / git / proxmox / mc (SMP)
'skopec.dev',
diff --git a/src/app/components/EditorialSite.tsx b/src/app/components/EditorialSite.tsx
new file mode 100644
index 0000000..df660d7
--- /dev/null
+++ b/src/app/components/EditorialSite.tsx
@@ -0,0 +1,453 @@
+"use client";
+
+import { useState } from "react";
+import { useTheme } from "./useTheme";
+import { codingProjects, friends, socials, techProjects } from "../data";
+import {
+ Contributions,
+ Reveal,
+ Section,
+ SectionHeading,
+ ServiceRow,
+ SocialGlyph,
+ Stat,
+ TerminalCard,
+ type ServiceAccess,
+} from "./editorial-ui";
+
+/* --------------------------------------------------------------- content */
+
+const NAV = [
+ { href: "#about", label: "About" },
+ { href: "#services", label: "Services" },
+ { href: "#projects", label: "Projects" },
+ { href: "#hardware", label: "Hardware" },
+ { href: "#friends", label: "Friends" },
+ { href: "#contact", label: "Contact" },
+];
+
+const SERVICES: {
+ name: string;
+ desc: string;
+ url: string;
+ access?: ServiceAccess;
+ checkUrl?: string;
+ disabled?: boolean;
+}[] = [
+ { name: "Proxmox", desc: "Server management — private.", url: "https://proxmox.dvorakmortonxd.dev/", access: "private", disabled: true },
+ { name: "Llama.cpp", desc: "Local AI server on a GPU-passthrough RTX 3070.", url: "https://ai.dvorakmortonxd.dev/", access: "on_request" },
+ { name: "Jellyfin", desc: "Self-hosted media streaming.", url: "https://jelly.dvorakmortonxd.dev/", access: "on_request" },
+ { name: "SMP", desc: "My survival Minecraft server.", url: "https://discord.gg/vyvhk7d8bX", checkUrl: "minecraft://mc.dvorakmortonxd.dev:25565", access: "on_request" },
+ { name: "Navidrome", desc: "My music, streamed from home.", url: "https://navidrome.dvorakmortonxd.dev/", access: "private" },
+ { name: "GitDXD", desc: "My self-hosted Forgejo instance.", url: "https://git.dvorakmortonxd.dev", access: "public" },
+];
+
+const LIFTS = [
+ { lift: "Squat", weight: "125 kg", date: "5 Jan 2025" },
+ { lift: "Bench", weight: "111 kg", date: "29 May 2026" },
+ { lift: "Deadlift", weight: "165 kg", date: "17 Dec 2024" },
+];
+
+/** Titles carry their state in parentheses, e.g. "dxdwm (Discontinued)". */
+function splitStatus(title: string) {
+ const m = title.match(/^(.*?)\s*\(([^)]+)\)\s*$/);
+ return m ? { name: m[1], status: m[2] } : { name: title, status: null };
+}
+
+/* ------------------------------------------------------------------ page */
+
+export default function EditorialSite() {
+ const { setTheme } = useTheme();
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ const stats = [
+ { value: String(SERVICES.length), label: "self-hosted services", sub: "git, media, music, AI, game server" },
+ { value: String(codingProjects.length), label: "coding projects", sub: "games, tools, plugins, forks" },
+ { value: String(techProjects.length), label: "machines collected", sub: "2009 – 2025, mostly e-waste" },
+ { value: "401 kg", label: "best SBD total", sub: "squat 125 · bench 111 · deadlift 165" },
+ ];
+
+ return (
+ <>
+ {/* ------------------------------------------------------------- nav */}
+
+
+ I host my own internet, and I write code for fun.
+
+
+
+ I’m Martin Dvořák — 17 years old, studying network management in Czechia. I self-host
+ everything from Git to music, collect old laptops, build small games, and lift when I’m
+ not doing any of that.
+
+
+
+ {/* ----------------------------------------------------------- about */}
+
+
+ Who is behind the terminal>}
+ lead="A student who would rather run the whole stack himself than rent it. The parts of it that are actually interesting:"
+ />
+
+
+
+
+
+ I’m a sophomore at sssvt.cz
+ , specializing in network management and administration. I wanted to go there since 7th
+ grade, so getting in was a good day. If you’re in middle school and into IT, it’s worth a
+ look.
+
+
+ I’m a homelabber and self-hosting obsessive — I run my own Git, media, music, AI and game
+ servers. I write code for game jams, tinker with GNU/Linux and musl systems, and rescue old
+ hardware. My laptop collection spans 2009 to 2025; most of it came out of e-waste.
+
+
+
+
+
+ {/* ------------------------------------------------------------- now */}
+
+
+ What I’m doing right now>}
+ lead="A snapshot, not a feed."
+ />
+
+
+
+
+
+ I’m hosting an SMP — message me on Discord if you want in. I’m also cooking most days,
+ bulking through the non-summer seasons.
+
+
+ Me and my friend Pepa
+ {" "}are building an education app so we can study more efficiently. It’s called{" "}
+
+ maturita.c
+
+ .
+
+
+
+
+
+ {/* -------------------------------------------------------- services */}
+
+
+ Services I run from home>}
+ lead="Live status is checked through this site. Some are private or shared on request — that’s what the label means."
+ />
+
+
+
+
+ {SERVICES.map((s) => (
+
+
+
+ ))}
+
+
+
+
+ {/* -------------------------------------------------------- projects */}
+
+
+ Things I’ve built>}
+ lead="Games, a browser, a window manager, a stack of abandoned servers and one very persistent Discord bot phase. Status in the margin."
+ />
+
+
+
+ {codingProjects.map((p, i) => {
+ const { name, status } = splitStatus(p.title);
+ return (
+
+ );
+ })}
+
+
+
+ {/* -------------------------------------------------------- hardware */}
+
+
+ The hardware pile>}
+ lead="From a 2009 ThinkPad to a 2025 MacBook Air — specs are whatever the machine actually shipped with."
+ />
+
+
+
+ {techProjects.map((t) => (
+
+
{t.title}
+
{t.desc}
+
+ ))}
+
+
+
+ {/* ----------------------------------------------------- contributions */}
+
+
+ Commits, on my own forge>}
+ lead={
+ <>
+ I run a Forgejo instance at{" "}
+
+ git.dvorakmortonxd.dev
+
+ . It started as a way to stop renting GitHub; it’s public now.
+ >
+ }
+ />
+
+
+
+
+
+
+
+
+
+ {/* --------------------------------------------------------- friends */}
+
+
+ People worth visiting>}
+ lead="Sites built by friends — go look at them."
+ />
+
+
+
+
+
+ {/* --------------------------------------------------------- lifting */}
+
+
+ SBD, five days a week>}
+ lead="A PPL split focused on strength. Current best singles at 73 kg bodyweight:"
+ />
+
+
+
+
- I'm currently hosting an SMP (dm me on discord). Also I'm pretty
- much cooking daily, because im bulking through out the non-summer seasons.
- And me and my pal Pepa are working on an
- education app so we can study more efficiently, It's called{" "}
- maturita.c!
-
-
-
-
-
-
-
-
-
- README.MD
-
-
-
- martin@dvorakmortonxd:
- ~$ cat about_me.md
-
-
-
- Hey, I'm Martin Dvořák — a 17(soon to be 18)-year-old IT student based
- in the Czech Republic, specializing in network management and
- administration at sssvt.cz. I'm a
- sophomore and I have wanted to go to this school since 7th grade (2022) so
- I'm happy I got in in 2025, the school is pretty cool so if you are in
- middle school and interested in IT, make sure to check it out. I'm a
- homelabber and developer heavily focused on self-hosting{" "}
- literally everything, writing code (for example games for gamejams),
- tinkering with GNU/Linux or Musl/Linux systems and retro hardware. I own a
- small collection of laptops ranging from 2009 to 2014 (and ofcourse my 2025
- macbook), most of these found in ewaste. In my free time I mostly spend
- time with my gf {"<"}3, I also spend a bit of time setting up my self
- hosted stuff (like jellyfin or gitdxd), and also when I'm in my gaming
- mood I play terraria (around 1300hr playtime btw) and minecraft modpacks
- with mekanism and/or create. I also go to the gym around 3-5 times a week,
- running a PPL split focused on strength/powerlifting and especially SBD. I
- take a big focus on my health and physique.
-
-
-
-
-
-
-
-
-
-
- SERVICES.HTML
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- GITDXD.GIT
-
-
-
- GitDXD
-
-
- My Self-hosted Git Instance
-
-
-
-
-
-
- My very own forgejo git instance, originally started as a private git
- instance for me and my friends to boycott GitHub but I've made it
- public now so. Join at{" "}
-
- git.dvorakmortonxd.dev
-
- .
-
-
-
-
-
-
-
-
-
- CONTRIBUTIONS@GITDXD.GIT
-
-
-
-
-
-
-
-
-
-
- REVIVAL.INC
-
-
-
- Revival inc.
-
-
-
-
-
- What is it?
-
-
-
- It's a game I made for the game jam "Mini Jame Gam #55", the
- theme was Necromancy and the special item was Milk, the game also includes
- a tutorial so if you wanna try it do it. Check it out at{" "}
-
- itch.io
- {" "}
- or play{" "}
-
- here
-
- .
-
-
-
-
-
-
-
-
-
- RUSTYWOLF.RS
-
-
-
- Introducing RustyWolf
-
-
-
-
-
- What makes it so cool???
-
-
-
- A lightweight browser made in Rust with WebKitGTK. It's the successor
- to my previous project Venturesome, aiming to provide a fast and minimalist
- browsing experience. It's a perfect browser for old machines that
- struggle with modern browsers. Check it out at{" "}
-
-
- GitDXD
-
-
- .
-
- >
- );
-}
diff --git a/src/app/components/ThemeRoot.tsx b/src/app/components/ThemeRoot.tsx
index 8b49383..9366806 100644
--- a/src/app/components/ThemeRoot.tsx
+++ b/src/app/components/ThemeRoot.tsx
@@ -1,32 +1,25 @@
"use client";
import { useTheme } from "./useTheme";
-import TerminalLayout from "./TerminalLayout";
+import EditorialSite from "./EditorialSite";
import WindowsDesktop from "./WindowsDesktop";
-import MobileHome from "./MobileHome";
+// 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 editorial page stays mounted (hidden) while the desktop is up, so its
+// scroll position survives a round-trip. The desktop mounts on demand.
export default function ThemeRoot() {
const { theme } = useTheme();
- const terminal = theme === "terminal";
+ const desktop = theme === "skeuo";
- // The desktop is kept mounted (just hidden) while the Gruvbox/terminal theme
- // is active. That way the Welcome window is only created on a fresh page
- // load and isn't reopened by toggling themes.
return (
<>
-
-
+
+
-
-
-
- {terminal && }
+ {desktop ? : null}
>
);
}
diff --git a/src/app/components/ThemeScript.tsx b/src/app/components/ThemeScript.tsx
index 2546edf..8779772 100644
--- a/src/app/components/ThemeScript.tsx
+++ b/src/app/components/ThemeScript.tsx
@@ -7,7 +7,10 @@ import { useServerInsertedHTML } from "next/navigation";
// without a flash. It is injected with useServerInsertedHTML so the