redraw the desk as cartoon skeuomorphism: CSS-only materials (no textures), light cream desk, per-item hues, cork board, receipt, scoreboard

This commit is contained in:
Martin Dvořák 2026-09-30 09:59:00 +00:00
commit 1880a5b0db
14 changed files with 1165 additions and 989 deletions

View file

@ -27,6 +27,17 @@ const NAV = [
{ href: "#contact", label: "contact" },
];
/** One hue per item, so every list reads as separate pieces of hardware. */
const TONES = [
"var(--orange)",
"var(--teal)",
"var(--blue)",
"var(--lilac)",
"var(--mint)",
"var(--coral)",
"var(--yellow)",
];
const SERVICES: {
name: string;
desc: string;
@ -72,11 +83,11 @@ export default function WebSite() {
return (
<div className="w-page">
{/* -------------------------------------------------------------- rail */}
<header className="w-rail w-mt-metal-flush" style={{ borderRadius: 0 }}>
<header className="w-rail">
<div className="mx-auto flex h-16 w-full max-w-[1120px] items-center gap-5 px-5 sm:px-8">
<a href="#top" className="flex shrink-0 items-center gap-2.5" aria-label="Back to top">
<Led kind="on" pulse slow />
<span className="w-wordmark w-engrave">dvorakmortonxd</span>
<span className="w-wordmark">dvorakmortonxd</span>
</a>
<nav className="ml-auto hidden items-center gap-6 md:flex" aria-label="Main">
@ -95,7 +106,7 @@ export default function WebSite() {
className="desktop-toggle flex items-center gap-3"
title="Flip to Desktop mode"
>
<span className="w-mono hidden text-[0.6rem] tracking-[0.2em] text-[var(--ftext-faint)] sm:inline">
<span className="w-mono hidden text-[0.6rem] tracking-[0.2em] text-[var(--ink-soft)] sm:inline">
DESKTOP
</span>
<span className="w-rocker">
@ -110,7 +121,7 @@ export default function WebSite() {
onClick={() => setMenuOpen((v) => !v)}
aria-expanded={menuOpen}
aria-label={menuOpen ? "Close menu" : "Open menu"}
className="w-keybtn !px-3 !py-2"
className="w-keybtn"
>
{menuOpen ? "close" : "menu"}
</button>
@ -120,7 +131,7 @@ export default function WebSite() {
{menuOpen ? (
<nav
className="w-mt-metal-flush mx-auto mb-3 flex w-[calc(100%-2.5rem)] max-w-[1120px] flex-col gap-1 rounded-lg p-3 md:hidden"
className="w-plastic mx-auto mb-3 flex w-[calc(100%-2.5rem)] max-w-[1120px] flex-col gap-1 p-3 md:hidden"
aria-label="Main"
>
{NAV.map((item) => (
@ -128,7 +139,7 @@ export default function WebSite() {
key={item.href}
href={item.href}
onClick={() => setMenuOpen(false)}
className="w-mono border-b border-[rgba(255,226,180,0.07)] py-3 text-[0.78rem] text-[var(--ftext-dim)] last:border-b-0"
className="w-display border-b-2 border-dashed border-[var(--plastic-edge)] py-3 text-[0.9rem] text-[var(--plastic-ink)] last:border-b-0"
>
{item.label}
</a>
@ -149,18 +160,18 @@ export default function WebSite() {
<span className="a">martin@dvorakmortonxd</span>:~$ whoami
<span className="w-caret ml-2" />
</p>
<h1 className="w-display mt-5 text-[clamp(1.8rem,4.1vw,2.75rem)] text-[var(--ftext)]">
<h1 className="w-display mt-5 text-[clamp(1.8rem,4.1vw,2.75rem)] text-[var(--glass-ink)]">
My own little internet — one rack, zero subscriptions.
</h1>
<p className="w-prose mt-5 max-w-[54ch] text-[var(--ftext-dim)]">
<p className="w-prose mt-5 max-w-[54ch] text-[var(--glass-dim)]">
I&rsquo;m Martin Dvořák. Git, media, music, an AI box and a Minecraft server all run on a
Proxmox machine in my room — plus the hardware graveyard I keep rescuing from e-waste.
</p>
<p className="mt-7 flex flex-wrap gap-x-8 gap-y-3">
<p className="mt-7 flex flex-wrap gap-3">
<a href="#services" className="w-cmd">
$ open rack --services
</a>
<a href="#projects" className="w-cmd">
<a href="#projects" className="w-cmd w-cmd--quiet">
$ open drawer --projects
</a>
</p>
@ -175,10 +186,10 @@ export default function WebSite() {
<div className="flex flex-col gap-6">
<MiniRack />
<div className="grid grid-cols-2 gap-3">
<Plaque value={String(SERVICES.length)} label="services" />
<Plaque value={String(codingProjects.length)} label="projects" />
<Plaque value={String(techProjects.length)} label="machines" />
<Plaque value="401" label="kg best SBD" />
<Plaque value={String(SERVICES.length)} label="services" tone="var(--orange)" />
<Plaque value={String(codingProjects.length)} label="projects" tone="var(--teal)" />
<Plaque value={String(techProjects.length)} label="machines" tone="var(--blue)" />
<Plaque value="401" label="kg best SBD" tone="var(--coral)" />
</div>
</div>
</Reveal>
@ -193,7 +204,7 @@ export default function WebSite() {
</Reveal>
<div className="grid gap-7 lg:grid-cols-[minmax(0,1.55fr)_minmax(0,1fr)] lg:items-start">
<Reveal delay={60}>
<article className="w-mt-paper w-sheet">
<article className="w-paper w-sheet">
<div className="w-sheet__head">
<span>manifest.txt</span>
<span className="ml-auto">printed on the desk</span>
@ -224,15 +235,13 @@ export default function WebSite() {
</Reveal>
<Reveal delay={150}>
<aside className="w-mt-paper w-cardindex lg:mt-12">
<p className="w-mono text-[0.62rem] tracking-[0.16em] text-[var(--ink-soft)]">
INDEX CARD
</p>
<p className="w-serif mt-3 text-[1.15rem] text-[var(--ink)]">
<aside className="w-paper w-cardindex lg:mt-14" style={{ "--tone": "var(--teal)" } as CSSProperties}>
<p className="w-kicker">index card</p>
<p className="w-serif mt-3 text-[1.2rem] text-[var(--ink)]">
&ldquo;If it has a fan, I&rsquo;ll find a use for it.&rdquo;
</p>
<div className="w-rule my-4" />
<ul className="w-mono space-y-2 text-[0.66rem] text-[var(--ink-soft)]">
<ul className="w-mono space-y-2 text-[0.68rem] text-[var(--ink-soft)]">
<li>school · sssvt.cz</li>
<li>gym · PPL 3–5×/week</li>
<li>games · Terraria, Minecraft</li>
@ -251,14 +260,13 @@ export default function WebSite() {
<div className="grid gap-7 lg:grid-cols-[minmax(0,1.3fr)_minmax(0,1fr)] lg:items-start">
<Reveal delay={60}>
<div className="w-note">
<p className="w-mono text-[0.62rem] tracking-[0.16em] text-[#6b7075]">
NOW.TXT · UPDATED 09/2026
</p>
<p className="w-prose mt-4 text-[#34383b]">
<span className="w-pin" aria-hidden="true" />
<p className="w-kicker !text-[#8a7420]">now.txt · updated 09/2026</p>
<p className="w-prose mt-4 text-[#5c4a1f]">
I&rsquo;m hosting an SMP — message me on Discord if you want in. I&rsquo;m also cooking most
days, bulking through the non-summer seasons.
</p>
<p className="w-prose mt-3 text-[#34383b]">
<p className="w-prose mt-3 text-[#5c4a1f]">
Me and my friend{" "}
<a className="w-link" href="https://skopec.dev" target="_blank" rel="noopener noreferrer">
Pepa
@ -278,24 +286,25 @@ export default function WebSite() {
</Reveal>
<Reveal delay={140}>
<div className="flex flex-col gap-6">
<div className="w-mt-paper w-cardindex w-cardindex--alt">
<p className="w-mono text-[0.62rem] tracking-[0.16em] text-[var(--ink-soft)]">
BENCH STATUS
</p>
<ul className="w-mono mt-3 space-y-2 text-[0.7rem] text-[var(--ink)]">
<li className="flex items-center gap-2">
<div className="flex flex-col gap-8">
<div className="w-paper w-cardindex w-cardindex--alt" style={{ "--tone": "var(--coral)" } as CSSProperties}>
<p className="w-kicker">bench status</p>
<ul className="w-display mt-4 space-y-2.5 text-[0.82rem] text-[var(--ink)]">
<li className="flex items-center gap-2.5">
<Led kind="on" /> smp · accepting players
</li>
<li className="flex items-center gap-2">
<li className="flex items-center gap-2.5">
<Led kind="amber" pulse /> maturita.c · in development
</li>
<li className="flex items-center gap-2">
<li className="flex items-center gap-2.5">
<Led kind="on" /> gym · PPL 3–5×/week
</li>
</ul>
</div>
<i className="w-pen ml-6 w-44" aria-hidden="true" />
<div className="flex items-end gap-6">
<i className="w-pen mb-3 w-40" aria-hidden="true" />
<span className="w-mug mr-6" aria-hidden="true" />
</div>
</div>
</Reveal>
</div>
@ -307,11 +316,13 @@ export default function WebSite() {
<SectionHead index="03" label="rack" title="Six machines, one shelf" />
</Reveal>
<Reveal delay={60}>
<div className="w-mt-metal w-rack">
<div className="w-chassis w-rack">
<div className="w-rack__top">
<Led kind="on" pulse slow />
<span className="w-engrave text-[0.62rem] tracking-[0.2em]">RACK 01 · SERVICES</span>
<span className="w-mono ml-auto hidden text-[0.6rem] tracking-[0.14em] text-[var(--ftext-faint)] sm:inline">
<span className="w-display text-[0.7rem] tracking-[0.18em] text-[var(--chassis-ink)]">
RACK 01 · SERVICES
</span>
<span className="w-mono ml-auto hidden text-[0.62rem] tracking-[0.12em] text-[var(--chassis-faint)] sm:inline">
health checked from this page
</span>
<span className="w-rack__vent w-vents" />
@ -319,8 +330,8 @@ export default function WebSite() {
<div className="w-rack__grid">
<span className="w-rails" />
<div>
{SERVICES.map((s) => (
<ServiceUnit key={s.name} {...s} />
{SERVICES.map((s, i) => (
<ServiceUnit key={s.name} tone={TONES[i % TONES.length]} {...s} />
))}
</div>
<span className="w-rails" />
@ -335,8 +346,8 @@ export default function WebSite() {
<SectionHead index="04" label="drawer" title="Eighteen drives, all labelled" />
</Reveal>
<Reveal delay={60}>
<div className="w-mt-metal w-drawer">
<div className="w-mt-plastic w-drawer__inner w-scroll">
<div className="w-chassis w-drawer">
<div className="w-well w-drawer__inner w-scroll">
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
{codingProjects.map((p, i) => {
const { name, status } = splitStatus(p.title);
@ -347,7 +358,12 @@ export default function WebSite() {
target="_blank"
rel="noopener noreferrer"
className="w-drive"
style={{ "--tilt": `${i % 2 ? 0.5 : -0.6}deg` } as CSSProperties}
style={
{
"--tilt": `${i % 2 ? 0.6 : -0.7}deg`,
"--tone": TONES[i % TONES.length],
} as CSSProperties
}
title={p.desc}
>
<span className="w-drive__port" aria-hidden="true" />
@ -364,7 +380,7 @@ export default function WebSite() {
})}
</div>
</div>
<div className="w-mt-metal-flush w-drawer__front">
<div className="w-chassis-2 w-drawer__front">
<i className="w-screw" aria-hidden="true" />
<span className="w-drawer__handle" aria-hidden="true" />
<i className="w-screw" aria-hidden="true" />
@ -376,18 +392,22 @@ export default function WebSite() {
{/* ------------------------------------------------------ hardware */}
<section id="hardware" className="scroll-mt-28">
<Reveal>
<SectionHead index="05" label="machines" title="Tagged on the pegboard" />
<SectionHead index="05" label="machines" title="Pinned to the cork board" />
</Reveal>
<Reveal delay={60}>
<div className="w-mt-metal w-pegboard">
<div className="w-pegboard">
<div className="w-pegboard__face">
<div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
{techProjects.map((t) => (
<article key={t.title} className="w-mt-paper w-hangtag">
<span className="w-hangtag__clip" aria-hidden="true" />
<h3 className="w-display text-[1rem] text-[var(--ink)]">{t.title}</h3>
<p className="w-prose mb-4 mt-2 text-[0.8rem] text-[var(--ink-soft)]">{t.desc}</p>
<span className="w-barcode w-hangtag__bar" aria-hidden="true" />
<div className="grid gap-5 sm:grid-cols-2 xl:grid-cols-3">
{techProjects.map((t, i) => (
<article
key={t.title}
className="w-paper w-hangtag"
style={{ "--tone": TONES[i % TONES.length] } as CSSProperties}
>
<span className="w-pin" aria-hidden="true" />
<h3 className="w-display text-[1.05rem] text-[var(--ink)]">{t.title}</h3>
<span className="w-hangtag__rule" aria-hidden="true" />
<p className="w-prose text-[0.84rem] text-[var(--ink-soft)]">{t.desc}</p>
</article>
))}
</div>
@ -399,7 +419,7 @@ export default function WebSite() {
{/* -------------------------------------------------- activity feed */}
<section id="gitdxd" className="scroll-mt-28">
<Reveal>
<SectionHead index="06" label="gitdxd" title="The printer spits out the forge" />
<SectionHead index="06" label="gitdxd" title="The receipt for this year's commits" />
</Reveal>
<Reveal delay={60}>
<Report />
@ -418,11 +438,16 @@ export default function WebSite() {
href={f.realUrl || f.url}
target="_blank"
rel="noopener noreferrer"
className="w-mt-paper w-bizcard"
style={{ "--tilt": `${i === 1 ? 0.9 : i === 2 ? -1 : -1.4}deg` } as CSSProperties}
className="w-bizcard"
style={
{
"--tilt": `${i === 1 ? 0.9 : i === 2 ? -1 : -1.4}deg`,
"--tone": TONES[(i + 1) % TONES.length],
} as CSSProperties
}
>
<p className="w-serif text-[1.15rem] text-[var(--ink)]">{f.name}</p>
<p className="w-mono mt-1 text-[0.66rem] text-[var(--ink-soft)]">{f.desc}</p>
<p className="w-serif text-[1.2rem] text-[var(--ink)]">{f.name}</p>
<p className="w-mono mt-1 text-[0.68rem] text-[var(--ink-soft)]">{f.desc}</p>
</a>
</Reveal>
))}
@ -432,29 +457,32 @@ export default function WebSite() {
{/* ----------------------------------------------------------- gym */}
<section id="gym" className="scroll-mt-28">
<Reveal>
<SectionHead index="08" label="strength" title="Numbers on the clipboard" />
<SectionHead index="08" label="strength" title="Numbers on the scoreboard" />
</Reveal>
<Reveal delay={60}>
<div className="w-clipboard">
<div className="w-mt-metal w-clipboard__clip" aria-hidden="true" />
<div className="w-mt-paper w-logsheet">
<div className="w-sheet__head">
<span>training log</span>
<span className="ml-auto">73 kg bodyweight</span>
</div>
<div className="mt-3">
{LIFTS.map((l) => (
<div key={l.lift} className="w-logrow">
<span className="w-logrow__lift">{l.lift}</span>
<span className="w-logrow__weight">{l.weight} kg</span>
<span className="w-logrow__date">{l.date}</span>
</div>
))}
</div>
<p className="w-mono mt-4 text-[0.62rem] tracking-[0.14em] text-[var(--ink-soft)]">
BEST SBD TOTAL · 401 KG · 165 + 111 + 125
</p>
<div className="w-chassis w-score">
<div className="w-score__head">
<Led kind="on" pulse slow />
<span>TRAINING LOG · 73 KG BODYWEIGHT</span>
<span className="ml-auto hidden sm:inline">3 LIFTS</span>
</div>
<div className="w-score__tiles">
{LIFTS.map((l, i) => (
<div
key={l.lift}
className="w-score__tile"
style={{ "--tone": TONES[(i + 2) % TONES.length] } as CSSProperties}
>
<span className="w-score__num">
{l.weight}
<small>kg</small>
</span>
<span className="w-score__lift">{l.lift}</span>
<span className="w-score__date">{l.date}</span>
</div>
))}
</div>
<p className="w-score__foot">BEST SBD TOTAL · 401 KG · 165 + 111 + 125</p>
</div>
</Reveal>
</section>
@ -465,16 +493,23 @@ export default function WebSite() {
<SectionHead index="09" label="patch panel" title="Twelve ports, all live" />
</Reveal>
<Reveal delay={60}>
<div className="w-mt-metal w-patch">
<div className="w-mt-metal-flush w-patch__face">
<div className="w-chassis w-patch">
<div className="w-chassis-2 w-patch__face">
<div className="w-patch__head">
<i className="w-screw" aria-hidden="true" />
<span className="w-engrave text-[0.62rem] tracking-[0.2em]">PATCH 01 · SOCIALS</span>
<span>PATCH 01 · SOCIALS</span>
<i className="w-screw ml-auto" aria-hidden="true" />
</div>
<div className="grid gap-2.5 sm:grid-cols-2 xl:grid-cols-3">
{socials.map((s) => (
<a key={s.name} href={s.url} target="_blank" rel="noopener noreferrer" className="w-port">
{socials.map((s, i) => (
<a
key={s.name}
href={s.url}
target="_blank"
rel="noopener noreferrer"
className="w-port"
style={{ "--tone": TONES[i % TONES.length] } as CSSProperties}
>
<span className="w-port__jack" aria-hidden="true">
<span className="w-port__slot" />
</span>
@ -485,7 +520,7 @@ export default function WebSite() {
</a>
))}
</div>
<p className="w-mono mt-5 text-[0.64rem] tracking-[0.06em] text-[var(--ftext-faint)]">
<p className="w-mono mt-5 text-[0.66rem] text-[var(--chassis-faint)]">
fastest reply is Discord or Instagram · mail{" "}
<a className="w-link" href="mailto:dvorak@dvorakmortonxd.dev">
dvorak@dvorakmortonxd.dev
@ -501,11 +536,13 @@ export default function WebSite() {
{/* ------------------------------------------------------------ footer */}
<footer className="mx-auto w-full max-w-[1120px] px-5 pb-16 sm:px-8">
<Reveal>
<div className="w-mt-alu relative flex flex-col gap-5 px-6 py-5 sm:flex-row sm:items-center sm:justify-between">
<div className="w-plastic relative flex flex-col gap-5 px-6 py-5 sm:flex-row sm:items-center sm:justify-between">
<div className="min-w-0">
<p className="w-mono text-[0.72rem] tracking-[0.2em]">DVORAKMORTONXD.LOCAL</p>
<p className="w-mono mt-1.5 text-[0.62rem] opacity-80">
v3.3.0 · GPL-3.0-only · built with Next.js · textures CC0 via{" "}
<p className="w-display text-[0.8rem] tracking-[0.16em] text-[var(--plastic-ink)]">
DVORAKMORTONXD.LOCAL
</p>
<p className="w-mono mt-1.5 text-[0.64rem] text-[var(--ink-soft)]">
v4.0.0 · GPL-3.0-only · built with Next.js · no textures, all CSS ·{" "}
<a className="w-link" href="/credits">
credits
</a>
@ -514,15 +551,15 @@ export default function WebSite() {
<button
type="button"
onClick={() => setTheme("skeuo")}
className="w-keybtn desktop-toggle shrink-0 self-start sm:self-auto"
className="w-keybtn w-btn-accent desktop-toggle shrink-0 self-start sm:self-auto"
title="Flip to Desktop mode"
>
<Led kind="amber" /> desktop mode
<Led kind="on" /> desktop mode
</button>
<i className="w-screw w-screw--alu w-corner-tr" aria-hidden="true" />
<i className="w-screw w-screw--alu w-corner-bl" aria-hidden="true" />
<i className="w-screw w-corner-tr" aria-hidden="true" />
<i className="w-screw w-corner-bl" aria-hidden="true" />
</div>
<p className="w-mono mt-4 text-[0.62rem] text-[var(--ftext-faint)]">
<p className="w-mono mt-4 text-[0.64rem] text-[var(--ink-soft)]">
© 2025–2026 Martin Dvořák — follow the licence or don&rsquo;t, I don&rsquo;t mind
</p>
</Reveal>

View file

@ -79,22 +79,34 @@ export function Led({
);
}
export function Screws({ count = 2, alu = false, className = "" }: { count?: number; alu?: boolean; className?: string }) {
export function Screws({ count = 2, className = "" }: { count?: number; className?: string }) {
return (
<span className={`w-unit__screws ${className}`}>
{Array.from({ length: count }).map((_, i) => (
<i key={i} className={`w-screw${alu ? " w-screw--alu" : ""}`} />
<i key={i} className="w-screw" />
))}
</span>
);
}
/** Section heading: an etched aluminium tab on the desk + painted title. */
/** Section heading: a coloured chip on the desk + a painted title. */
export function SectionHead({ index, label, title }: { index: string; label: string; title: string }) {
const tones = [
"var(--orange)",
"var(--teal)",
"var(--blue)",
"var(--lilac)",
"var(--mint)",
"var(--coral)",
"var(--yellow)",
];
const n = Number.parseInt(index, 10);
const tone = tones[Number.isFinite(n) ? (n - 1) % tones.length : 0];
return (
<div className="w-sechead">
<span className="w-mt-alu w-sechead__tab">
<b>{index}</b> {label}
<span className="w-chip w-sechead__tab" style={{ "--tone": tone } as CSSProperties}>
{index} · {label}
</span>
<h2 className="w-display w-paint w-sechead__title">{title}</h2>
</div>
@ -107,9 +119,9 @@ export function Monitor({ children, className = "" }: { children: ReactNode; cla
return (
<div className={`w-monitor ${className}`}>
<div className="w-monitor__frame">
<div className="w-mt-glass w-monitor__glass">{children}</div>
<div className="w-glass w-monitor__glass">{children}</div>
<div className="w-monitor__chin">
<Led kind="amber" />
<Led kind="on" />
<span className="w-monitor__brand">DXD</span>
<span className="w-monitor__osd" aria-hidden="true">
<i className="w-osdkey" />
@ -127,6 +139,7 @@ export function Monitor({ children, className = "" }: { children: ReactNode; cla
}
const KEY_ROWS = ["1234567890-=".split(""), "qwertyuiop[]".split(""), "asdfghjkl;'".split("")];
const CAP_TONES = ["var(--mint)", "var(--blue)", "var(--yellow)", "var(--coral)", "var(--lilac)", "var(--teal)"];
export function Keyboard() {
return (
@ -134,16 +147,20 @@ export function Keyboard() {
<div className="w-keyboard__deck">
<div className="w-keyboard__row">
<span className="w-key w-key--accent">esc</span>
{KEY_ROWS[0].map((k) => (
<span key={k} className="w-key">
{KEY_ROWS[0].map((k, i) => (
<span key={k} className="w-key" style={{ "--tone": CAP_TONES[i % CAP_TONES.length] } as CSSProperties}>
{k}
</span>
))}
</div>
{KEY_ROWS.slice(1).map((row, i) => (
<div key={i} className="w-keyboard__row">
{row.map((k) => (
<span key={k} className="w-key">
{KEY_ROWS.slice(1).map((row, r) => (
<div key={r} className="w-keyboard__row">
{row.map((k, i) => (
<span
key={k}
className="w-key"
style={{ "--tone": CAP_TONES[(i + r + 2) % CAP_TONES.length] } as CSSProperties}
>
{k}
</span>
))}
@ -158,24 +175,27 @@ export function Keyboard() {
);
}
const RACK_TONES = ["var(--mint)", "var(--blue)", "var(--yellow)", "var(--coral)"];
/** A small rack that sits on the desk in the hero. */
export function MiniRack({ label = "DXD-01" }: { label?: string }) {
return (
<div className="w-rack w-mt-metal" aria-hidden="true">
<div className="w-chassis w-rack" aria-hidden="true">
<div className="w-rack__top">
<Led kind="on" pulse />
<span className="w-engrave text-[0.62rem] tracking-[0.2em]">{label}</span>
<span className="w-display text-[0.68rem] tracking-[0.2em] text-[var(--chassis-ink)]">{label}</span>
<span className="w-rack__vent w-vents" />
</div>
<div className="w-rack__grid">
<span className="w-rails" />
<div>
{[0, 1, 2, 3].map((i) => (
<div key={i} className="w-unit !min-h-[46px] !gap-[10px] !py-2">
<span className="w-unit__grille !h-6 !w-9" />
<div key={i} className="w-unit !min-h-[48px] !gap-[10px] !py-2" style={{ "--tone": RACK_TONES[i] } as CSSProperties}>
<span className="w-unit__grip !h-7 !w-3" />
<span className="w-unit__grille !h-7 !w-10" />
<Led kind="on" pulse style={{ animationDelay: `${i * 0.5}s` }} />
<Led kind="amber" pulse slow style={{ animationDelay: `${i * 0.3}s` }} />
<span className="ml-auto w-engrave text-[0.58rem] tracking-[0.14em]">
<span className="w-display ml-auto text-[0.6rem] tracking-[0.14em] text-[var(--chassis-dim)]">
{["pxe", "aio", "nas", "web"][i]}
</span>
</div>
@ -187,13 +207,13 @@ export function MiniRack({ label = "DXD-01" }: { label?: string }) {
);
}
/** A machined aluminium plate with one number etched into it. */
export function Plaque({ value, label }: { value: string; label: string }) {
/** A big coloured sticker with one number on it. */
export function Plaque({ value, label, tone = "var(--orange)" }: { value: string; label: string; tone?: string }) {
return (
<div className="w-mt-alu w-plaque">
<div className="w-sticker w-plaque" style={{ "--tone": tone } as CSSProperties}>
<span className="w-plaque__value">{value}</span>
<span className="w-plaque__label">{label}</span>
<Led kind="amber" className="w-plaque__dot" />
<i className="w-plaque__dot" aria-hidden="true" />
</div>
);
}
@ -209,6 +229,7 @@ export function ServiceUnit({
access,
checkUrl,
disabled,
tone = "var(--teal)",
}: {
name: string;
desc: string;
@ -216,6 +237,7 @@ export function ServiceUnit({
access?: ServiceAccess;
checkUrl?: string;
disabled?: boolean;
tone?: string;
}) {
const [status, setStatus] = useState<"pending" | "up" | "down">("pending");
@ -237,6 +259,7 @@ export function ServiceUnit({
const live = disabled ? "up" : status;
const kind = live === "up" ? "on" : live === "down" ? "off" : "amber";
const stateClass = disabled ? "is-wait" : live === "up" ? "is-on" : live === "down" ? "is-off" : "is-wait";
const label = disabled ? "STANDBY" : live === "up" ? "ONLINE" : live === "down" ? "OFFLINE" : "POLLING";
const accessLabel = access === "public" ? "public" : access === "private" ? "private" : access === "on_request" ? "on request" : null;
@ -253,8 +276,8 @@ export function ServiceUnit({
<span className="w-unit__grip" aria-hidden="true" />
<span className="w-unit__grille w-grille" aria-hidden="true" />
<span className="w-unit__id">
<span className="w-unit__name w-engrave">{name}</span>
<span className="w-tape mt-1">
<span className="w-unit__name">{name}</span>
<span className="w-tape mt-1.5">
{host}
{accessLabel ? ` · ${accessLabel}` : ""}
</span>
@ -262,7 +285,7 @@ export function ServiceUnit({
</span>
<span className="w-unit__state">
<Led kind={kind} pulse={live === "up"} />
<span className="w-unit__status w-engrave">{label}</span>
<span className={`w-unit__status ${stateClass}`}>{label}</span>
</span>
<Screws />
</>
@ -270,13 +293,20 @@ export function ServiceUnit({
if (disabled) {
return (
<span className="w-unit" aria-disabled="true">
<span className="w-unit" style={{ "--tone": tone } as CSSProperties} aria-disabled="true">
{inner}
</span>
);
}
return (
<a href={url} target="_blank" rel="noopener noreferrer" className="w-unit w-unit--link" title={desc}>
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="w-unit w-unit--link"
style={{ "--tone": tone } as CSSProperties}
title={desc}
>
{inner}
</a>
);
@ -295,7 +325,7 @@ interface Activity {
repo?: { full_name?: string };
}
const DOT_OPACITY = [0.07, 0.3, 0.48, 0.64, 0.82];
const DOT_OPACITY = [0.12, 0.35, 0.55, 0.75, 1];
export function Report() {
const [weeks, setWeeks] = useState<{ date: string; contribs: number; level: number }[][]>([]);
@ -377,7 +407,7 @@ export function Report() {
return (
<div className="w-printout">
<div className="w-mt-paper w-printout__paper">
<div className="w-printout__paper">
<p className="w-print__head">
<span>GITDXD · ACTIVITY REPORT · 12 MONTHS</span>
<span className="ml-auto flex items-center gap-3">
@ -387,20 +417,20 @@ export function Report() {
</p>
{state === "error" ? (
<p className="w-mono mt-5 text-[0.72rem] text-[#4a4133]">could not reach the forge.</p>
<p className="w-mono mt-5 text-[0.74rem] text-[var(--ink-soft)]">could not reach the forge.</p>
) : (
<>
<div className="mt-5 flex flex-wrap items-end gap-x-6 gap-y-2">
<div>
<p className="w-mono text-[0.62rem] tracking-[0.16em] text-[#4a4133]">TOTAL / 12 MONTHS</p>
<p className="w-display text-[2.6rem] leading-none text-[var(--ink)]">
<p className="w-kicker">total / 12 months</p>
<p className="w-display mt-1 text-[2.6rem] leading-none text-[var(--ink)]">
{state === "loading" ? "—" : total}
</p>
</div>
<p className="w-mono text-[0.62rem] leading-relaxed text-[#6f6450]">
each dot = one day
<p className="w-mono text-[0.64rem] leading-relaxed text-[var(--ink-soft)]">
each square = one day
<br />
darkest = busiest
strongest orange = busiest
</p>
</div>

View file

@ -4,34 +4,32 @@ import "../web.css";
export const metadata: Metadata = {
title: "credits · dvorakmortonxd.dev",
description: "Textures, type and other borrowed work used on dvorakmortonxd.dev.",
description: "Type and other borrowed work used on dvorakmortonxd.dev.",
};
const TEXTURES = [
{ file: "desk.jpg", asset: "Wood 028", id: "Wood028", use: "the near-black desk" },
{ file: "metal.jpg", asset: "Metal 051 C", id: "Metal051C", use: "rack, monitor, panel hardware" },
{ file: "paper.jpg", asset: "Paper 003", id: "Paper003", use: "sheets, labels, tape, the report" },
{ file: "carbon.jpg", asset: "Fabric 004", id: "Fabric004", use: "the keyboard deck" },
{ file: "plastic.jpg", asset: "Plastic 012 A", id: "Plastic012A", use: "the drawer interior" },
];
const FONTS = [
{
name: "Nunito",
by: "Vernon Adams, Cyreal, Jacques Le Bailly",
use: "hardware labels, headings, buttons",
href: "https://fonts.google.com/specimen/Nunito",
},
{
name: "Newsreader",
by: "Production Type",
use: "printed headlines, sheet copy, stamped numbers",
use: "anything printed on paper",
href: "https://fonts.google.com/specimen/Newsreader",
},
{
name: "IBM Plex Sans",
by: "IBM",
use: "body text on the desk",
use: "body copy",
href: "https://fonts.google.com/specimen/IBM+Plex+Sans",
},
{
name: "IBM Plex Mono",
by: "IBM",
use: "engraved labels, terminal text, index cards",
use: "terminal text, receipt, technical labels",
href: "https://fonts.google.com/specimen/IBM+Plex+Mono",
},
];
@ -41,70 +39,34 @@ export default function Credits() {
<div className="w-page">
<main className="mx-auto w-full max-w-[1120px] px-5 pt-24 pb-20 sm:px-8">
<div className="w-sechead">
<span className="w-mt-alu w-sechead__tab">credits</span>
<span className="w-chip w-sechead__tab" style={{ "--tone": "var(--mint)" } as React.CSSProperties}>
credits
</span>
<h1 className="w-display w-paint w-sechead__title">Everything borrowed, credited.</h1>
</div>
<p className="w-prose w-paint max-w-[64ch] text-[var(--ftext-dim)]">
The desk is built out of five CC0 textures and three open-licensed typefaces. Nothing is scraped
or unlicensed — the authors are named even where the licence does not require it.
<p className="w-prose w-paint max-w-[62ch] text-[var(--ink-soft)]">
The desk contains <strong>no images at all</strong> — every surface, screw, LED, paper sheet and coffee
mug is drawn in CSS. That means there are no photography or texture licences to track: the only
borrowed work is type.
</p>
<section className="mt-14">
<div className="w-sechead !mb-6">
<span className="w-mt-alu w-sechead__tab">textures</span>
<h2 className="w-display w-paint w-sechead__title !text-[1.3rem]">ambientCG — CC0 1.0</h2>
</div>
<p className="w-prose w-paint max-w-[64ch] text-[var(--ftext-dim)]">
All five materials come from{" "}
<a className="w-link" href="https://ambientcg.com" target="_blank" rel="noopener noreferrer">
ambientCG
</a>{" "}
(Struffel Productions) under the{" "}
<a
className="w-link"
href="https://creativecommons.org/publicdomain/zero/1.0/"
target="_blank"
rel="noopener noreferrer"
>
CC0 1.0
</a>{" "}
public-domain dedication. I downloaded the 1K JPG colour maps, downscaled them to 512&nbsp;px and
tint them in CSS.
</p>
<ul className="mt-7 grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
{TEXTURES.map((t) => (
<li key={t.id} className="w-mt-paper w-cardindex">
<p className="w-serif text-[1.05rem] text-[var(--ink)]">{t.asset}</p>
<p className="w-mono mt-2 text-[0.64rem] leading-relaxed text-[var(--ink-soft)]">
source:{" "}
<a
className="w-link"
href={`https://ambientcg.com/view?id=${t.id}`}
target="_blank"
rel="noopener noreferrer"
>
ambientCG / {t.id}
</a>
<br />
licence: CC0 1.0
<br />
used as <code>{`/textures/${t.file}`}</code> — {t.use}
</p>
</li>
))}
</ul>
</section>
<section className="mt-16">
<div className="w-sechead !mb-6">
<span className="w-mt-alu w-sechead__tab">type</span>
<h2 className="w-display w-paint w-sechead__title !text-[1.3rem]">Google Fonts — SIL OFL 1.1</h2>
<span className="w-chip w-sechead__tab" style={{ "--tone": "var(--teal)" } as React.CSSProperties}>
type
</span>
<h2 className="w-display w-paint w-sechead__title !text-[1.3rem]">
Google Fonts — SIL Open Font License 1.1
</h2>
</div>
<ul className="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
{FONTS.map((f) => (
<li key={f.name} className="w-mt-paper w-cardindex w-cardindex--alt">
<p className="w-serif text-[1.05rem] text-[var(--ink)]">{f.name}</p>
<ul className="grid gap-5 sm:grid-cols-2 xl:grid-cols-4">
{FONTS.map((f, i) => (
<li
key={f.name}
className="w-paper w-cardindex"
style={{ "--tone": ["var(--orange)", "var(--blue)", "var(--lilac)", "var(--mint)"][i % 4] } as React.CSSProperties}
>
<p className="w-display text-[1.05rem] text-[var(--ink)]">{f.name}</p>
<p className="w-mono mt-2 text-[0.64rem] leading-relaxed text-[var(--ink-soft)]">
by {f.by}
<br />
@ -122,13 +84,15 @@ export default function Credits() {
<section className="mt-16">
<div className="w-sechead !mb-6">
<span className="w-mt-alu w-sechead__tab">notes</span>
<span className="w-chip w-sechead__tab" style={{ "--tone": "var(--lilac)" } as React.CSSProperties}>
notes
</span>
<h2 className="w-display w-paint w-sechead__title !text-[1.3rem]">Other marks</h2>
</div>
<p className="w-prose w-paint max-w-[64ch] text-[var(--ftext-dim)]">
The social ports use brand marks that remain the property of their owners and are used only to
link to those accounts. Everything written on the paper is mine. The desktop mode (the KDE
simulation) uses its own separate assets.
<p className="w-prose w-paint max-w-[62ch] text-[var(--ink-soft)]">
The patch panel uses brand marks that remain the property of their owners and are used only to
link to those accounts. Everything written on the paper — and every pixel of the desk itself — is
mine. The desktop mode (the KDE simulation) uses its own separate assets.
</p>
</section>

View file

@ -37,15 +37,20 @@
--ease-cinematic: cubic-bezier(0.22, 1, 0.36, 1);
}
/* Beats page.css's :root when the editorial theme is active. */
/* Beats page.css's :root when the web theme is active. The desk is a light,
colourful, cartoon-skeuomorphic surface — the dark gruvbox values in :root
are only the fallback for the desktop mode. */
html[data-theme="web"] {
color-scheme: dark;
--accent: #fe8019;
--accent2: #d65d0e;
--accent3: #fabd2f;
--green: #b8bb26;
--red: #fb4934;
--gray: #a89984;
color-scheme: light;
--bg: #f7e7c6;
--bg-raised: #fffdf6;
--bg-well: #eed9b0;
--accent: #f4823a;
--accent2: #d4611c;
--accent3: #f2c14e;
--green: #58bd72;
--red: #ea6f6a;
--gray: #7f7768;
}
@theme inline {
@ -71,7 +76,7 @@ html[data-theme="web"] {
}
html[data-theme="web"] ::selection {
background: rgba(254, 128, 25, 0.28);
background: rgba(244, 130, 58, 0.3);
color: var(--ink);
}
@ -88,12 +93,12 @@ html[data-theme="web"] ::-webkit-scrollbar-track {
background: var(--bg-well);
}
html[data-theme="web"] ::-webkit-scrollbar-thumb {
background: #3c3836;
background: #d9c49b;
border: 3px solid var(--bg-well);
border-radius: 99px;
}
html[data-theme="web"] ::-webkit-scrollbar-thumb:hover {
background: #504945;
background: #c9b184;
}
/* Phones never get the desktop-mode button. */

View file

@ -1,10 +1,10 @@
import type { Metadata } from "next";
import { Newsreader, IBM_Plex_Sans, IBM_Plex_Mono } from "next/font/google";
import { Newsreader, IBM_Plex_Sans, IBM_Plex_Mono, Nunito } from "next/font/google";
import "./globals.css";
import ThemeScript from "./components/ThemeScript";
// Display serif for headlines, Plex for body/labels — same pairing as the
// reference editorial site.
// The web desk pairs a rounded sans (hardware labels, headings) with a printed
// serif (anything on paper) and a mono (terminal text + technical labels).
const news = Newsreader({
variable: "--font-news",
subsets: ["latin"],
@ -24,6 +24,12 @@ const plexMono = IBM_Plex_Mono({
weight: ["400", "500"],
display: "swap",
});
const round = Nunito({
variable: "--font-round",
subsets: ["latin"],
weight: ["600", "700", "800"],
display: "swap",
});
export const metadata: Metadata = {
title: "dvorakmortonxd.dev",
@ -51,7 +57,7 @@ export default function RootLayout({
lang="en"
data-theme="web"
suppressHydrationWarning
className={`${news.variable} ${plex.variable} ${plexMono.variable}`}
className={`${news.variable} ${plex.variable} ${plexMono.variable} ${round.variable}`}
>
<body className="antialiased">
<noscript>

File diff suppressed because it is too large Load diff