Files
pinkudex/mockups/page-archetype-mockups.html
2026-05-26 22:46:00 +02:00

312 lines
18 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pinkudex — Spacing Pass per Archetype (No Layout Changes)</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root {
--color-bg-0: oklch(0.13 0.025 280);
--color-bg-1: oklch(0.17 0.04 285);
--color-bg-2: oklch(0.22 0.05 290);
--color-fg: oklch(0.97 0.01 280);
--color-fg-dim: oklch(0.72 0.025 280);
--color-fg-muted: oklch(0.55 0.02 280);
--color-glass: color-mix(in oklch, white 6%, transparent);
--color-glass-strong: color-mix(in oklch, white 10%, transparent);
--color-glass-border: color-mix(in oklch, white 14%, transparent);
--color-glass-border-strong: color-mix(in oklch, white 22%, transparent);
--color-cyan: oklch(0.82 0.16 200);
--color-violet: oklch(0.72 0.22 305);
--color-mint: oklch(0.80 0.16 155);
--color-coral: oklch(0.72 0.20 25);
--spacing-card: 15px;
--spacing-card-gap: 9px;
--spacing-section: 15px;
--spacing-chip: 7px;
--spacing-label: 7px;
}
body {
background: var(--color-bg-0);
color: var(--color-fg);
font-family: ui-sans-serif, system-ui, -apple-system, sans-serif;
}
.glass { background: var(--color-glass); border: 1px solid var(--color-glass-border); }
.glass-strong { background: var(--color-glass-strong); border: 1px solid var(--color-glass-border-strong); }
.label-mono {
font-family: ui-monospace, monospace; font-size: 10px;
text-transform: uppercase; letter-spacing: 0.1em;
color: var(--color-fg-muted);
}
.archetype-frame {
background: oklch(0.10 0.025 280);
border: 1px solid var(--color-glass-border);
border-radius: 12px;
overflow: hidden;
}
.archetype-header {
padding: 14px 18px;
background: oklch(0.20 0.04 285);
border-bottom: 1px solid var(--color-glass-border);
display: flex; align-items: baseline; justify-content: space-between;
}
.archetype-header h2 {
font-size: 14px; font-weight: 600;
font-family: ui-monospace, monospace;
text-transform: uppercase; letter-spacing: 0.08em;
color: var(--color-cyan);
}
.archetype-header .desc { font-size: 12px; color: var(--color-fg-muted); }
.archetype-body { padding: 24px; }
.why { font-size: 12px; color: var(--color-fg-muted); }
.ba-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start;
}
.ba-label {
font-family: ui-monospace, monospace; font-size: 11px;
text-transform: uppercase; letter-spacing: 0.08em;
color: var(--color-fg-muted);
margin-bottom: 8px;
}
.ba-label.after { color: var(--color-cyan); }
.thumb {
aspect-ratio: 800/538; border-radius: 6px;
background: linear-gradient(135deg, oklch(0.30 0.05 290), oklch(0.20 0.04 280));
border: 1px solid var(--color-glass-border);
position: relative;
}
.thumb .id { position: absolute; bottom: 4px; left: 6px; font-family: ui-monospace, monospace; font-size: 9px; color: var(--color-cyan); font-weight: 600; }
.stat-num { font-family: ui-monospace, monospace; font-size: 22px; font-weight: 600; tabular-nums: tabular-nums; }
.stat-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-fg-muted); }
.pill {
display: inline-flex; align-items: center; justify-content: center;
padding: 0 10px; height: 28px;
border-radius: 999px; font-size: 11px; font-family: ui-monospace, monospace;
text-transform: uppercase; letter-spacing: 0.06em;
border: 1px solid var(--color-glass-border); color: var(--color-fg-muted);
}
.pill.on { color: var(--color-cyan); border-color: oklch(0.82 0.16 200 / 0.4); background: oklch(0.82 0.16 200 / 0.10); }
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
height: 32px; padding: 0 12px;
border-radius: 8px; font-size: 12px;
border: 1px solid var(--color-glass-border); background: var(--color-glass);
color: var(--color-fg);
}
.btn-coral { color: var(--color-coral); background: oklch(0.72 0.20 25 / 0.10); border-color: oklch(0.72 0.20 25 / 0.30); }
</style>
</head>
<body class="space-y-8 max-w-[1600px] mx-auto p-6">
<header class="space-y-1">
<h1 class="text-2xl font-semibold tracking-tight">Spacing-Only Pass · Per Archetype</h1>
<p class="why max-w-[820px]">
<strong class="text-[var(--color-fg)]">No layout changes</strong>. Each archetype is reproduced as-is from the actual app, then the AFTER column applies only the snug+1 spacing tokens — padding, gaps, margins. Same components, same columns, same visual hierarchy. Only the rhythm changes.
</p>
</header>
<!-- ====================================================================
1 · INDEX (home, /collection/[slug], /actress/[slug], etc.)
Real layout: stats inline + UploadCard right · FilterBar · LetterBar · MasonryGrid
OR an empty-state Panel when no items match.
==================================================================== -->
<section class="archetype-frame">
<div class="archetype-header">
<h2>1 · Index / Grid</h2>
<span class="desc">Stats + upload (top) · FilterBar · LetterBar · Masonry — or empty-state Panel</span>
</div>
<div class="archetype-body space-y-6">
<p class="why">Spacing changes here are limited: the masonry grid, FilterBar, and LetterBar already have their own (correct) rhythm. The only thing that adopts the new tokens is the <strong>empty-state Panel</strong> shown when nothing matches.</p>
<div class="ba-grid">
<!-- BEFORE empty state -->
<div>
<div class="ba-label">BEFORE — empty state · <code class="text-[var(--color-cyan)]">p-16</code> + <code class="text-[var(--color-cyan)]">mb-3</code></div>
<div class="glass rounded-2xl text-center" style="padding: 64px;">
<div style="width: 40px; height: 40px; margin: 0 auto; border-radius: 999px; background: oklch(0.82 0.16 200 / 0.2); display: grid; place-items: center; color: var(--color-cyan); margin-bottom: 12px;"></div>
<h2 class="text-xl font-medium">Nothing Matches</h2>
<p class="text-[var(--color-fg-dim)] mt-1">All filtered out — switch back to All.</p>
</div>
</div>
<!-- AFTER empty state -->
<div>
<div class="ba-label after">AFTER — Panel · <code class="text-[var(--color-cyan)]">p-card</code> + <code class="text-[var(--color-cyan)]">mb-label</code></div>
<div class="glass rounded-2xl text-center" style="padding: var(--spacing-card);">
<div style="width: 40px; height: 40px; margin: 0 auto; border-radius: 999px; background: oklch(0.82 0.16 200 / 0.2); display: grid; place-items: center; color: var(--color-cyan); margin-bottom: var(--spacing-label);"></div>
<h2 class="text-xl font-medium">Nothing Matches</h2>
<p class="text-[var(--color-fg-dim)] mt-1">All filtered out — switch back to All.</p>
</div>
</div>
</div>
<ul class="text-[11px] font-mono text-[var(--color-fg-muted)] space-y-0.5 list-disc list-inside">
<li>FilterBar, LetterBar, MasonryGrid: <strong>NOT changed</strong> — they have their own rhythm</li>
<li>only the empty-state card uses Panel tokens (one-line edit per page route)</li>
<li>top stats / UploadCard section: <strong>NOT changed</strong> — page intro, not a panel</li>
</ul>
</div>
</section>
<!-- ====================================================================
2 · DETAIL (already migrated — for reference)
Real layout: 800px cover left + aside right with stacked Panels.
==================================================================== -->
<section class="archetype-frame">
<div class="archetype-header">
<h2>2 · Detail</h2>
<span class="desc">Already shipped on /id/[code] — reference only</span>
</div>
<div class="archetype-body space-y-3">
<p class="why">No further changes. Showing the spec for cross-checking.</p>
<ul class="text-[11px] font-mono text-[var(--color-fg-muted)] space-y-0.5 list-disc list-inside">
<li>aside = PanelStack with <code class="text-[var(--color-cyan)]">gap-card-gap</code> (9 px) between Panels</li>
<li>each Panel = <code class="text-[var(--color-cyan)]">p-card</code> (15 px) interior</li>
<li>identity Panel uses PanelSection internally with <code class="text-[var(--color-cyan)]">gap-section</code> (15 px)</li>
<li>chip rows = <code class="text-[var(--color-cyan)]">gap-chip</code> (7 px)</li>
<li>label → content = <code class="text-[var(--color-cyan)]">mb-label</code> (7 px)</li>
<li>action bar (Edit / Import / Delete) lives outside Panels but inside the same PanelStack rhythm</li>
</ul>
</div>
</section>
<!-- ====================================================================
3 · SETTINGS — sidebar nav + scrollable Card stack on right
Real layout: <SettingsPanel> sidebar + content. Card helper renders
glass rounded-2xl p-5 with a 'text-sm font-medium mb-3' header.
==================================================================== -->
<section class="archetype-frame">
<div class="archetype-header">
<h2>3 · Settings</h2>
<span class="desc">Existing sidebar + Card stack · only Card padding/header spacing changes</span>
</div>
<div class="archetype-body space-y-4">
<p class="why">Layout stays exactly as-is — sidebar nav on the left, stacked cards on the right. The only thing that changes is the <code class="text-[var(--color-cyan)]">Card</code> helper inside <code class="text-[var(--color-cyan)]">SettingsPanel.tsx</code>: <code class="text-[var(--color-cyan)]">p-5</code><code class="text-[var(--color-cyan)]">p-card</code> (20→15) and header margin <code class="text-[var(--color-cyan)]">mb-3</code><code class="text-[var(--color-cyan)]">mb-label</code> (12→7). Card-to-card stacking gap also tightens to <code class="text-[var(--color-cyan)]">gap-card-gap</code> (9 px) from the existing <code class="text-[var(--color-cyan)]">space-y-4</code> (16 px).</p>
<div class="ba-grid">
<!-- BEFORE -->
<div>
<div class="ba-label">BEFORE — <code class="text-[var(--color-cyan)]">p-5 · mb-3 · space-y-4</code></div>
<div style="display: flex; flex-direction: column; gap: 16px;">
<div class="glass rounded-2xl" style="padding: 20px;">
<div style="font-size: 14px; font-weight: 500; margin-bottom: 12px;">General</div>
<div style="display: flex; flex-direction: column; gap: 12px;">
<div>
<div class="label-mono" style="margin-bottom: 8px;">Default sort</div>
<div style="display: flex; gap: 6px; flex-wrap: wrap;">
<span class="pill on">Newest ↓</span><span class="pill">Oldest</span><span class="pill">Title</span>
</div>
</div>
<div>
<div class="label-mono" style="margin-bottom: 8px;">Fade transitions</div>
<div style="display: flex; gap: 6px;"><span class="pill on">On</span><span class="pill">Off</span></div>
</div>
</div>
</div>
<div class="glass rounded-2xl" style="padding: 20px;">
<div style="font-size: 14px; font-weight: 500; margin-bottom: 12px;">Display</div>
<div>
<div class="label-mono" style="margin-bottom: 8px;">Cover columns</div>
<div style="display: flex; gap: 6px;"><span class="pill">2</span><span class="pill on">3</span><span class="pill">4</span></div>
</div>
</div>
</div>
</div>
<!-- AFTER -->
<div>
<div class="ba-label after">AFTER — <code class="text-[var(--color-cyan)]">p-card · mb-label · gap-card-gap</code></div>
<div style="display: flex; flex-direction: column; gap: var(--spacing-card-gap);">
<div class="glass rounded-2xl" style="padding: var(--spacing-card);">
<div style="font-size: 14px; font-weight: 500; margin-bottom: var(--spacing-label);">General</div>
<div style="display: flex; flex-direction: column; gap: var(--spacing-section);">
<div>
<div class="label-mono" style="margin-bottom: var(--spacing-label);">Default sort</div>
<div style="display: flex; gap: var(--spacing-chip); flex-wrap: wrap;">
<span class="pill on">Newest ↓</span><span class="pill">Oldest</span><span class="pill">Title</span>
</div>
</div>
<div>
<div class="label-mono" style="margin-bottom: var(--spacing-label);">Fade transitions</div>
<div style="display: flex; gap: var(--spacing-chip);"><span class="pill on">On</span><span class="pill">Off</span></div>
</div>
</div>
</div>
<div class="glass rounded-2xl" style="padding: var(--spacing-card);">
<div style="font-size: 14px; font-weight: 500; margin-bottom: var(--spacing-label);">Display</div>
<div>
<div class="label-mono" style="margin-bottom: var(--spacing-label);">Cover columns</div>
<div style="display: flex; gap: var(--spacing-chip);"><span class="pill">2</span><span class="pill on">3</span><span class="pill">4</span></div>
</div>
</div>
</div>
</div>
</div>
<ul class="text-[11px] font-mono text-[var(--color-fg-muted)] space-y-0.5 list-disc list-inside">
<li>same Card helper, same sidebar — only the spacing constants change</li>
<li><code class="text-[var(--color-cyan)]">p-5</code> (20px) → <code class="text-[var(--color-cyan)]">p-card</code> (15px)</li>
<li><code class="text-[var(--color-cyan)]">mb-3</code> (12px) → <code class="text-[var(--color-cyan)]">mb-label</code> (7px) on the title</li>
<li><code class="text-[var(--color-cyan)]">space-y-4</code> (16px) → <code class="text-[var(--color-cyan)]">gap-card-gap</code> (9px) between Cards</li>
<li>internal <code class="text-[var(--color-cyan)]">space-y-3</code> blocks → <code class="text-[var(--color-cyan)]">gap-section</code> (15px) — wider, since these are full sub-sections</li>
</ul>
</div>
</section>
<!-- ====================================================================
4 · LIST (trash, queue) — header card + grid/list rows.
Real trash layout: header strip with title + close, then the body
is either an empty state Panel or a TrashGrid (uses MasonryGrid).
Real queue layout: header summary + list rows.
Spacing-only tweak: empty-state Panel padding + outer body padding.
==================================================================== -->
<section class="archetype-frame">
<div class="archetype-header">
<h2>4 · List (trash, queue)</h2>
<span class="desc">Header strip + body · only empty-state Panel padding changes</span>
</div>
<div class="archetype-body space-y-4">
<p class="why">Same layout as today: header at the top of the modal/page, scrollable body below. Body is either an empty-state Panel or a grid. Only the empty-state Panel adopts the new tokens (<code class="text-[var(--color-cyan)]">p-16</code><code class="text-[var(--color-cyan)]">p-card</code>). Header strip and grid stay untouched.</p>
<div class="ba-grid">
<!-- BEFORE -->
<div>
<div class="ba-label">BEFORE — empty trash · <code class="text-[var(--color-cyan)]">p-16</code></div>
<div class="glass rounded-2xl text-center max-w-md mx-auto" style="padding: 64px;">
<div style="width: 40px; height: 40px; margin: 0 auto; border-radius: 999px; background: oklch(0.20 0.04 285); display: grid; place-items: center; color: var(--color-fg-dim); margin-bottom: 12px;">🗑</div>
<h3 class="text-xl font-medium">Trash Is Empty</h3>
<p class="text-[var(--color-fg-dim)] mt-1 text-sm">Deleted images appear here for 30 days before they're gone for good.</p>
</div>
</div>
<!-- AFTER -->
<div>
<div class="ba-label after">AFTER — Panel · <code class="text-[var(--color-cyan)]">p-card</code></div>
<div class="glass rounded-2xl text-center max-w-md mx-auto" style="padding: var(--spacing-card);">
<div style="width: 40px; height: 40px; margin: 0 auto; border-radius: 999px; background: oklch(0.20 0.04 285); display: grid; place-items: center; color: var(--color-fg-dim); margin-bottom: var(--spacing-label);">🗑</div>
<h3 class="text-xl font-medium">Trash Is Empty</h3>
<p class="text-[var(--color-fg-dim)] mt-1 text-sm">Deleted images appear here for 30 days before they're gone for good.</p>
</div>
</div>
</div>
<ul class="text-[11px] font-mono text-[var(--color-fg-muted)] space-y-0.5 list-disc list-inside">
<li>trash modal header strip: <strong>NOT changed</strong></li>
<li>TrashGrid / queue rows: <strong>NOT changed</strong> — they have their own rhythm</li>
<li>only the empty-state Panel inherits the tokens (one line per file)</li>
</ul>
</div>
</section>
<footer class="text-[11px] text-[var(--color-fg-muted)]">
Net effect of this pass:
<ul class="list-disc list-inside mt-1 space-y-0.5">
<li>11 empty-state cards across the app: <code class="text-[var(--color-cyan)]">p-12</code>/<code class="text-[var(--color-cyan)]">p-16</code><code class="text-[var(--color-cyan)]">p-card</code></li>
<li>Settings panel Card helper: <code class="text-[var(--color-cyan)]">p-5</code> + <code class="text-[var(--color-cyan)]">mb-3</code> + <code class="text-[var(--color-cyan)]">space-y-4</code> → tokens</li>
<li>Detail page: already shipped</li>
<li>List (trash/queue) header strips, rows, grids: untouched</li>
<li>FilterBar / LetterBar / MasonryGrid: untouched</li>
</ul>
</footer>
</body>
</html>