feat: theming system, documentation, and photo grid regression tests
- Add configurable theme system with 4 presets (studio, minimal, editorial, classic)
- Theme controls fonts, colors, accent, photo frames, grain, and header dot
- Resolve themes from gallery.yaml: string shorthand or full object override
- Inject theme as CSS custom properties on <html> element
- Dynamic Google Fonts loading based on theme config
- OG image route reads accent/background from theme
- Refactor Studio overrides into conditional CSS via data-attributes
Documentation:
- Add docs/gallery-config.md with comprehensive configuration reference
- Add docs/theming.md with preset reference and custom theme guide
- Slim README to link to detailed docs
Fix CSS regression:
- Fix passepartout frame overflow:visible breaking next/image fill rendering
- Remove duplicate .photo-grid__item block that stripped overflow:hidden
Testing:
- Add e2e/photo-grid.spec.ts with 3 regression tests:
- Grid items render with real dimensions
- overflow:hidden CSS guard (catches the exact bug fixed)
- Images load with real pixel data (not blurhash)
Tooling:
- Add scripts/screenshots.ts for automated theme screenshot generation
- Handles dev server lifecycle, theme cycling, FadeIn + lazy image handling
2026-02-15 12:21:02 +01:00
|
|
|
/* Fonts are loaded dynamically via layout.tsx based on theme config */
|
2026-02-14 11:47:26 +01:00
|
|
|
|
feat: theming system, documentation, and photo grid regression tests
- Add configurable theme system with 4 presets (studio, minimal, editorial, classic)
- Theme controls fonts, colors, accent, photo frames, grain, and header dot
- Resolve themes from gallery.yaml: string shorthand or full object override
- Inject theme as CSS custom properties on <html> element
- Dynamic Google Fonts loading based on theme config
- OG image route reads accent/background from theme
- Refactor Studio overrides into conditional CSS via data-attributes
Documentation:
- Add docs/gallery-config.md with comprehensive configuration reference
- Add docs/theming.md with preset reference and custom theme guide
- Slim README to link to detailed docs
Fix CSS regression:
- Fix passepartout frame overflow:visible breaking next/image fill rendering
- Remove duplicate .photo-grid__item block that stripped overflow:hidden
Testing:
- Add e2e/photo-grid.spec.ts with 3 regression tests:
- Grid items render with real dimensions
- overflow:hidden CSS guard (catches the exact bug fixed)
- Images load with real pixel data (not blurhash)
Tooling:
- Add scripts/screenshots.ts for automated theme screenshot generation
- Handles dev server lifecycle, theme cycling, FadeIn + lazy image handling
2026-02-15 12:21:02 +01:00
|
|
|
/* ── Design Tokens (Fallback Defaults) ───────────── */
|
|
|
|
|
/* These are overridden at runtime by CSS vars injected from gallery.yaml theme config. */
|
2026-02-14 11:47:26 +01:00
|
|
|
:root {
|
2026-02-14 12:14:56 +01:00
|
|
|
--bg-primary: #1a1a1a;
|
|
|
|
|
--bg-secondary: #141414;
|
|
|
|
|
--bg-card: #1e1e1e;
|
|
|
|
|
--bg-card-hover: #242424;
|
|
|
|
|
--bg-overlay: rgba(0, 0, 0, 0.98);
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--text-primary: #f5f5f0;
|
|
|
|
|
--text-secondary: #a0a09a;
|
|
|
|
|
--text-muted: #706f6a;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--border-subtle: #2a2a28;
|
|
|
|
|
--border-hover: #3a3a38;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--accent: #e60012;
|
|
|
|
|
--accent-dim: rgba(230, 0, 18, 0.12);
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--font-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
2026-02-14 11:47:26 +01:00
|
|
|
--font-serif: 'Playfair Display', Georgia, 'Times New Roman', serif;
|
2026-02-14 12:14:56 +01:00
|
|
|
--font-caption: 'EB Garamond', Georgia, serif;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--radius-sm: 0px;
|
|
|
|
|
--radius-md: 0px;
|
|
|
|
|
--radius-lg: 0px;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--transition-fast: 200ms ease;
|
|
|
|
|
--transition-normal: 400ms ease;
|
|
|
|
|
--transition-slow: 600ms ease;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
|
|
|
|
--max-width: 1400px;
|
|
|
|
|
--header-height: 64px;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
/* ── Light Theme (Studio Light) ──────────────────── */
|
2026-02-14 11:47:26 +01:00
|
|
|
[data-theme='light'] {
|
2026-02-14 12:14:56 +01:00
|
|
|
--bg-primary: #f5f5f0;
|
|
|
|
|
--bg-secondary: #eaeae5;
|
2026-02-14 11:47:26 +01:00
|
|
|
--bg-card: #ffffff;
|
2026-02-14 12:14:56 +01:00
|
|
|
--bg-card-hover: #f0f0eb;
|
|
|
|
|
--bg-overlay: rgba(245, 245, 240, 0.96);
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--text-primary: #1a1a18;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #4a4a45;
|
|
|
|
|
--text-muted: #6a6a65;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--border-subtle: #ddddd8;
|
|
|
|
|
--border-hover: #c5c5c0;
|
2026-02-14 11:47:26 +01:00
|
|
|
|
2026-02-14 12:14:56 +01:00
|
|
|
--accent: #c8000f;
|
|
|
|
|
--accent-dim: rgba(200, 0, 15, 0.08);
|
2026-02-14 11:47:26 +01:00
|
|
|
}
|
|
|
|
|
|
feat: restyle themes to be visually distinct
- Minimal: Swiss Brutalist — fullbleed hero, true B&W, zero-gap grid, Geist font
- Editorial: Cinematic Magazine — warm charcoal, Bodoni Moda serif, slow transitions
- Classic: Gilded Gallery — gold accents, Cinzel headings, passepartout, ornamental dividers
Updated config presets, per-theme color palettes, ~550 lines of scoped CSS overrides,
data-preset attribute on html element, responsive breakpoints, screenshots, and docs.
2026-02-15 17:17:25 +01:00
|
|
|
/* ── Minimal: Swiss Brutalist Palette ────────────── */
|
|
|
|
|
[data-preset='minimal'] {
|
|
|
|
|
--bg-primary: #000000;
|
|
|
|
|
--bg-secondary: #0a0a0a;
|
|
|
|
|
--bg-card: #111111;
|
|
|
|
|
--bg-card-hover: #1a1a1a;
|
|
|
|
|
--bg-overlay: rgba(0, 0, 0, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #ffffff;
|
|
|
|
|
--text-secondary: #888888;
|
|
|
|
|
--text-muted: #555555;
|
|
|
|
|
|
|
|
|
|
--border-subtle: #1a1a1a;
|
|
|
|
|
--border-hover: #333333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-preset='minimal'][data-theme='light'] {
|
|
|
|
|
--bg-primary: #ffffff;
|
|
|
|
|
--bg-secondary: #f7f7f7;
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
--bg-card-hover: #fafafa;
|
|
|
|
|
--bg-overlay: rgba(255, 255, 255, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #000000;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #475569;
|
|
|
|
|
--text-muted: #64748b;
|
feat: restyle themes to be visually distinct
- Minimal: Swiss Brutalist — fullbleed hero, true B&W, zero-gap grid, Geist font
- Editorial: Cinematic Magazine — warm charcoal, Bodoni Moda serif, slow transitions
- Classic: Gilded Gallery — gold accents, Cinzel headings, passepartout, ornamental dividers
Updated config presets, per-theme color palettes, ~550 lines of scoped CSS overrides,
data-preset attribute on html element, responsive breakpoints, screenshots, and docs.
2026-02-15 17:17:25 +01:00
|
|
|
|
|
|
|
|
--border-subtle: #eeeeee;
|
|
|
|
|
--border-hover: #cccccc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Editorial: Cinematic Magazine Palette ────────── */
|
|
|
|
|
[data-preset='editorial'] {
|
|
|
|
|
--bg-primary: #1a1714;
|
|
|
|
|
--bg-secondary: #141210;
|
|
|
|
|
--bg-card: #1e1b17;
|
|
|
|
|
--bg-card-hover: #252119;
|
|
|
|
|
--bg-overlay: rgba(20, 18, 16, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #ede8e0;
|
|
|
|
|
--text-secondary: #9a9086;
|
|
|
|
|
--text-muted: #6b6359;
|
|
|
|
|
|
|
|
|
|
--border-subtle: #2a2620;
|
|
|
|
|
--border-hover: #3a3530;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-preset='editorial'][data-theme='light'] {
|
|
|
|
|
--bg-primary: #faf8f4;
|
|
|
|
|
--bg-secondary: #f0ece4;
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
--bg-card-hover: #f5f2ec;
|
|
|
|
|
--bg-overlay: rgba(250, 248, 244, 0.96);
|
|
|
|
|
|
|
|
|
|
--text-primary: #1a1714;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #4a4540;
|
|
|
|
|
--text-muted: #6a655f;
|
feat: restyle themes to be visually distinct
- Minimal: Swiss Brutalist — fullbleed hero, true B&W, zero-gap grid, Geist font
- Editorial: Cinematic Magazine — warm charcoal, Bodoni Moda serif, slow transitions
- Classic: Gilded Gallery — gold accents, Cinzel headings, passepartout, ornamental dividers
Updated config presets, per-theme color palettes, ~550 lines of scoped CSS overrides,
data-preset attribute on html element, responsive breakpoints, screenshots, and docs.
2026-02-15 17:17:25 +01:00
|
|
|
|
|
|
|
|
--border-subtle: #e5e0d8;
|
|
|
|
|
--border-hover: #ccc7c0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Classic: Gilded Gallery Palette ─────────────── */
|
|
|
|
|
[data-preset='classic'] {
|
|
|
|
|
--bg-primary: #121210;
|
|
|
|
|
--bg-secondary: #0e0e0c;
|
|
|
|
|
--bg-card: #181816;
|
|
|
|
|
--bg-card-hover: #1e1e1a;
|
|
|
|
|
--bg-overlay: rgba(14, 14, 12, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #f0ece4;
|
|
|
|
|
--text-secondary: #a09888;
|
|
|
|
|
--text-muted: #706858;
|
|
|
|
|
|
|
|
|
|
--border-subtle: #2a2822;
|
|
|
|
|
--border-hover: #3a3830;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-preset='classic'][data-theme='light'] {
|
|
|
|
|
--bg-primary: #fdfbf5;
|
|
|
|
|
--bg-secondary: #f5f0e6;
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
--bg-card-hover: #faf6ee;
|
|
|
|
|
--bg-overlay: rgba(253, 251, 245, 0.96);
|
|
|
|
|
|
|
|
|
|
--text-primary: #1a1810;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #4a4535;
|
|
|
|
|
--text-muted: #6a6555;
|
feat: restyle themes to be visually distinct
- Minimal: Swiss Brutalist — fullbleed hero, true B&W, zero-gap grid, Geist font
- Editorial: Cinematic Magazine — warm charcoal, Bodoni Moda serif, slow transitions
- Classic: Gilded Gallery — gold accents, Cinzel headings, passepartout, ornamental dividers
Updated config presets, per-theme color palettes, ~550 lines of scoped CSS overrides,
data-preset attribute on html element, responsive breakpoints, screenshots, and docs.
2026-02-15 17:17:25 +01:00
|
|
|
|
|
|
|
|
--border-subtle: #e5dfcf;
|
|
|
|
|
--border-hover: #d0c8b5;
|
|
|
|
|
}
|
|
|
|
|
|
feat: add noir, monograph, botanica presets + stacked/typographic/mosaic hero styles + showcase/filmstrip/editorial-flow gallery layouts
- 3 new theme presets: noir (darkroom analog), monograph (typographic book), botanica (organic nature)
- 3 new hero styles: stacked (fullbleed + thumbnail strip), typographic (text-only), mosaic (multi-image grid)
- 3 new gallery layouts: showcase (featured + grid), filmstrip (horizontal scroll), editorial-flow (alternating pairs)
- Extended config types, validation, and CSS tokens for all new options
- Updated theming docs with new presets table, descriptions, and example configs
2026-02-15 21:58:31 +01:00
|
|
|
/* ── Noir: Darkroom Analog Palette ───────────────── */
|
|
|
|
|
[data-preset='noir'] {
|
|
|
|
|
--bg-primary: #111014;
|
|
|
|
|
--bg-secondary: #0c0b0f;
|
|
|
|
|
--bg-card: #16141a;
|
|
|
|
|
--bg-card-hover: #1e1c22;
|
|
|
|
|
--bg-overlay: rgba(11, 10, 15, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #f0ebe0;
|
|
|
|
|
--text-secondary: #998f80;
|
|
|
|
|
--text-muted: #665c50;
|
|
|
|
|
|
|
|
|
|
--border-subtle: #252228;
|
|
|
|
|
--border-hover: #3a3540;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-preset='noir'][data-theme='light'] {
|
|
|
|
|
--bg-primary: #faf5ef;
|
|
|
|
|
--bg-secondary: #f0ebe3;
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
--bg-card-hover: #f5f0e8;
|
|
|
|
|
--bg-overlay: rgba(250, 245, 239, 0.96);
|
|
|
|
|
|
|
|
|
|
--text-primary: #1a1610;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #4a4538;
|
|
|
|
|
--text-muted: #6a6558;
|
feat: add noir, monograph, botanica presets + stacked/typographic/mosaic hero styles + showcase/filmstrip/editorial-flow gallery layouts
- 3 new theme presets: noir (darkroom analog), monograph (typographic book), botanica (organic nature)
- 3 new hero styles: stacked (fullbleed + thumbnail strip), typographic (text-only), mosaic (multi-image grid)
- 3 new gallery layouts: showcase (featured + grid), filmstrip (horizontal scroll), editorial-flow (alternating pairs)
- Extended config types, validation, and CSS tokens for all new options
- Updated theming docs with new presets table, descriptions, and example configs
2026-02-15 21:58:31 +01:00
|
|
|
|
|
|
|
|
--border-subtle: #e5dfd5;
|
|
|
|
|
--border-hover: #ccc5b8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Monograph: Typographic / Book Palette ────────── */
|
|
|
|
|
[data-preset='monograph'] {
|
|
|
|
|
--bg-primary: #151515;
|
|
|
|
|
--bg-secondary: #0f0f0f;
|
|
|
|
|
--bg-card: #1a1a1a;
|
|
|
|
|
--bg-card-hover: #222222;
|
|
|
|
|
--bg-overlay: rgba(15, 15, 15, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #e8e8e8;
|
|
|
|
|
--text-secondary: #888888;
|
|
|
|
|
--text-muted: #555555;
|
|
|
|
|
|
|
|
|
|
--border-subtle: #222222;
|
|
|
|
|
--border-hover: #3a3a3a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[data-preset='monograph'][data-theme='light'] {
|
|
|
|
|
--bg-primary: #fafafa;
|
|
|
|
|
--bg-secondary: #f2f2f2;
|
|
|
|
|
--bg-card: #ffffff;
|
|
|
|
|
--bg-card-hover: #f7f7f7;
|
|
|
|
|
--bg-overlay: rgba(250, 250, 250, 0.98);
|
|
|
|
|
|
|
|
|
|
--text-primary: #111111;
|
2026-03-08 18:05:34 +01:00
|
|
|
--text-secondary: #475569;
|
|
|
|
|
--text-muted: #64748b;
|
feat: add noir, monograph, botanica presets + stacked/typographic/mosaic hero styles + showcase/filmstrip/editorial-flow gallery layouts
- 3 new theme presets: noir (darkroom analog), monograph (typographic book), botanica (organic nature)
- 3 new hero styles: stacked (fullbleed + thumbnail strip), typographic (text-only), mosaic (multi-image grid)
- 3 new gallery layouts: showcase (featured + grid), filmstrip (horizontal scroll), editorial-flow (alternating pairs)
- Extended config types, validation, and CSS tokens for all new options
- Updated theming docs with new presets table, descriptions, and example configs
2026-02-15 21:58:31 +01:00
|
|
|
|
|
|
|
|
--border-subtle: #e5e5e5;
|
|
|
|
|
--border-hover: #cccccc;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
/* ── Reset ────────────────────────────────────────── */
|
|
|
|
|
*,
|
|
|
|
|
*::before,
|
|
|
|
|
*::after {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
html {
|
|
|
|
|
-webkit-font-smoothing: antialiased;
|
|
|
|
|
-moz-osx-font-smoothing: grayscale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
font-family: var(--font-sans);
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a {
|
|
|
|
|
color: inherit;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-08 18:05:34 +01:00
|
|
|
button {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
font-family: inherit;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
img {
|
|
|
|
|
display: block;
|
|
|
|
|
max-width: 100%;
|
2026-03-08 18:05:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a:focus-visible,
|
|
|
|
|
button:focus-visible,
|
2026-04-21 22:52:08 +02:00
|
|
|
input:focus-visible,
|
|
|
|
|
[role='button']:focus-visible {
|
2026-03-08 18:05:34 +01:00
|
|
|
outline: 2px solid var(--text-primary);
|
|
|
|
|
outline-offset: 2px;
|
2026-03-12 11:30:45 +00:00
|
|
|
}
|