feat: add 6 more skins (PS1, PS3, Wii, NDS, Dreamcast, JV2002)

Brings the catalog to nine. Each is a single scoped [data-theme="..."]
CSS file plus a registry entry — no markup changes.

- ps1: charcoal BIOS, gray panels, uppercase letterspacing
- ps3: animated XMB sky gradient + drifting wave, black glass
- wii: white channels, rounded pills, soft blue glow
- nds: silver shell with content framed as the touch screen
- dreamcast: cream BIOS, conic-gradient orange swirl, lowercase blue
- jv2002: dense boxy portal, Verdana 11px, red masthead, blue nav tabs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 00:49:52 +02:00
parent 37ba9b3e19
commit 91244a5a2b
32 changed files with 3093 additions and 29 deletions
+27 -14
View File
@@ -1,12 +1,14 @@
import Link from "next/link";
import type { ReactNode } from "react";
import { type ThemeId } from "@/themes/registry";
import { THEMES, type ThemeId } from "@/themes/registry";
import { getSettings } from "@/lib/settings";
import { isAdmin } from "@/lib/auth";
import ThemeSwitcher from "./ThemeSwitcher";
import Clock from "./Clock";
// Shared, theme-agnostic page chrome. Every theme restyles these `rb-` classes
// to look like its own OS/console. The HTML skeleton never changes.
export default function Shell({
export default async function Shell({
theme,
title,
children,
@@ -15,12 +17,24 @@ export default function Shell({
title: string;
children: ReactNode;
}) {
const settings = getSettings();
const admin = await isAdmin();
// Admins always get the switcher with every skin; the public only sees it when
// enabled, and only the allowed skins.
const showSwitcher = admin || settings.publicThemeToggle;
const switcherThemes = admin
? THEMES
: THEMES.filter((t) => settings.allowedThemes.includes(t.id));
return (
<div className="rb-desktop">
<div className="rb-window" role="application">
<div className="rb-titlebar">
<span className="rb-titlebar-icon" aria-hidden />
<span className="rb-titlebar-text">{title} RetroBlog</span>
<span className="rb-titlebar-text">
{title} {settings.title}
</span>
<div className="rb-titlebar-buttons" aria-hidden>
<button className="rb-tb-btn rb-tb-min" tabIndex={-1}>
<span>_</span>
@@ -41,16 +55,15 @@ export default function Shell({
<Link className="rb-menu-link" href="/about">
About
</Link>
<a
className="rb-menu-link"
href="https://github.com"
target="_blank"
rel="noreferrer"
>
Links
</a>
{admin && (
<Link className="rb-menu-link" href="/admin">
Admin
</Link>
)}
<span className="rb-spacer" />
<ThemeSwitcher initial={theme} />
{showSwitcher && (
<ThemeSwitcher initial={theme} themes={switcherThemes} />
)}
</nav>
<div className="rb-content">{children}</div>
@@ -58,7 +71,7 @@ export default function Shell({
<div className="rb-statusbar">
<span className="rb-status-cell">Ready</span>
<span className="rb-status-cell rb-status-grow">
RetroBlog v0.1
{settings.footer}
</span>
</div>
</div>
@@ -71,7 +84,7 @@ export default function Shell({
<div className="rb-tasks">
<button className="rb-task rb-task-active">
<span className="rb-task-icon" aria-hidden />
RetroBlog
{settings.title}
</button>
</div>
<div className="rb-tray">