feat: add four storefront identities

This commit is contained in:
2026-06-29 12:06:18 +01:00
parent e4bcd7578a
commit 561e948cb4
14 changed files with 391 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
import type { StoreMeta } from './types';
export const collector: StoreMeta = {
name: ['First Mallard', 'Black Lacquer', 'The Porcelain', 'The Bullion', 'Cobalt Reserve', 'The Vermillion'],
blurb: [
'Lot 001 of the founding run — never traded below issue.',
'Hand-lacquered shell; only nine known in this grade.',
'Kiln-pale and flawless. A blue-chip hold.',
'24-duckmark gilt. Tracks the index, lot for lot.',
'Deep cobalt, tightly held by serious hands.',
'Vermillion. Ungraded twins are simply unheard of.',
],
tag: ['MINT 70', 'GEM 68', 'PROOF 69', 'MINT 71', 'GEM 66', 'MINT 70'],
};

View File

@@ -0,0 +1,14 @@
import type { StoreMeta } from './types';
export const crypto: StoreMeta = {
name: ['HODL Duck', 'Whale Duck', 'Degen Duck', 'Lambo Duck', 'Moon Duck', 'Diamond Hands'],
blurb: [
'Refuses to sell. Ever. Not even at -82%.',
'Moves the floor just by entering the pond.',
'Aped in at the top. Still grinning.',
'Gold chrome. Engine noises sold separately.',
'Eyes locked on the chart. wen moon.',
'Grips so tight the duck squeaks diamonds.',
],
tag: ['RARE', 'LEGENDARY', 'COMMON', 'MYTHIC', 'EPIC', 'LEGENDARY'],
};

View File

@@ -0,0 +1,14 @@
import type { StoreMeta } from './types';
export const executive: StoreMeta = {
name: ['The Keynote', 'The Chairman', 'The Closer', 'The Founder', 'The Negotiator', 'The Successor'],
blurb: [
'Hand-finished matte shell for the cold open.',
'Weighted base. Holds your gaze without blinking.',
'The one you rehearse the hard "no" in front of.',
'Carry it into the raise. It has seen bigger rounds.',
'Silent, patient, unimpressed — exactly the audience you need.',
'For the succession talk you keep postponing.',
],
tag: ['No. 001 / 250', 'No. 014 / 180', 'Atelier', 'Signature', 'No. 007 / 90', 'By request'],
};

View File

@@ -0,0 +1,16 @@
import type { StoreMeta } from './types';
import { executive } from './executive';
import { crypto } from './crypto';
import { supper } from './supper';
import { collector } from './collector';
/** Per shop-system copy. Keyed by the shop system (store code up to the first
* `_`), the same rule the PostCSS plugin uses for styles. */
export const metaBySystem: Record<string, StoreMeta> = {
executive,
crypto,
supper,
collector,
};
export type { StoreMeta } from './types';

View File

@@ -0,0 +1,14 @@
import type { StoreMeta } from './types';
export const supper: StoreMeta = {
name: ['Sunday Roast', 'Midnight Snack', 'Porridge Pal', 'Honey Butter', 'Blueberry', 'Tomato Soup'],
blurb: [
'Sits patiently while the gravy settles.',
'Keeps you company at the open fridge, 1am.',
'Slow mornings, warm bowls, no rush.',
'Best friends with toast and a long Sunday.',
'Small, cheerful, smells faintly of muffins.',
'Pairs with grilled cheese and bad weather.',
],
tag: ['Serves 1', 'Serves 1', 'Best with oats', 'Best with toast', 'Brunch', 'Soup season'],
};

View File

@@ -0,0 +1,7 @@
/** Per-store copy for the six shared ducks. Arrays are index-aligned with
* `ducks` in ../products.ts — same product, different voice per storefront. */
export type StoreMeta = {
name: string[];
blurb: string[];
tag: string[];
};

6
src/styles/fonts.css Normal file
View File

@@ -0,0 +1,6 @@
/*
* All storefronts load from the same stylesheet. Each store selects its display
* / ui / mono faces purely through the --font-* tokens set in its @store block
* in globals.css. Only the active store's block survives the build.
*/
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Hanken+Grotesk:wght@400;500;600;700;800&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400;1,6..72,500&family=Spectral:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&display=swap');

127
src/styles/globals.css Normal file
View File

@@ -0,0 +1,127 @@
@import './fonts.css';
@import 'tailwindcss';
/*
* Semantic brand tokens. Every component styles itself from these — the same
* markup, the same classes, across all four storefronts. Each `@store` block
* below rewrites the tokens (and a few layout switches) for one storefront; the
* postcss-storestyles plugin keeps exactly one block at build time, driven by
* NEXT_PUBLIC_STORE_CODE. The shipped CSS carries a single brand, no branching.
*/
@theme {
--color-bg: #0c0d10;
--color-surface: #15161b;
--color-surface2: #1d1f26;
--color-fg: #efeae0;
--color-muted: #9a958a;
--color-line: rgba(220, 210, 190, 0.13);
--color-accent: #c9a86a;
--color-accent2: #8a7a55;
--font-display: 'Cormorant Garamond', Georgia, serif;
--font-ui: 'Hanken Grotesk', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-card: 2px;
}
@keyframes floaty {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-9px);
}
}
@keyframes tick {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
body {
@apply bg-bg text-fg;
font-family: var(--font-ui);
}
a {
color: inherit;
text-decoration: none;
}
/* ── EXECUTIVE · Onyx — luxury, dark, gilt, Cormorant serif ── */
@store executive {
:root {
--color-bg: #0c0d10;
--color-surface: #15161b;
--color-surface2: #1d1f26;
--color-fg: #efeae0;
--color-muted: #9a958a;
--color-line: rgba(220, 210, 190, 0.13);
--color-accent: #c9a86a;
--color-accent2: #8a7a55;
--font-display: 'Cormorant Garamond', Georgia, serif;
--font-ui: 'Hanken Grotesk', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-card: 2px;
}
}
/* ── CRYPTO · DEGEN//DUCKS — neon, dark, glow, Space Grotesk ── */
@store crypto {
:root {
--color-bg: #070a0f;
--color-surface: #0d1219;
--color-surface2: #111927;
--color-fg: #e8f0ff;
--color-muted: #6f7d92;
--color-line: rgba(80, 255, 170, 0.2);
--color-accent: #33ff99;
--color-accent2: #b15bff;
--font-display: 'Space Grotesk', system-ui, sans-serif;
--font-ui: 'Space Grotesk', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-card: 16px;
}
}
/* ── SUPPER · Rubber Dubber — warm cream, cozy, Newsreader serif ── */
@store supper {
:root {
--color-bg: #f6efe3;
--color-surface: #fffaf2;
--color-surface2: #ece0cd;
--color-fg: #3a3128;
--color-muted: #8a7c6a;
--color-line: rgba(80, 60, 40, 0.14);
--color-accent: #cf7d4e;
--color-accent2: #7d8a5a;
--font-display: 'Newsreader', Georgia, serif;
--font-ui: 'Hanken Grotesk', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-card: 22px;
}
}
/* ── COLLECTOR · The Collectors Den — vintage paper, maroon, Spectral ── */
@store collector {
:root {
--color-bg: #e7e3d6;
--color-surface: #f3f0e6;
--color-surface2: #dcd7c6;
--color-fg: #22231d;
--color-muted: #6f6c5d;
--color-line: rgba(40, 40, 28, 0.16);
--color-accent: #8a2f2f;
--color-accent2: #b08a3e;
--font-display: 'Spectral', Georgia, serif;
--font-ui: 'Hanken Grotesk', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-card: 0px;
}
}