320 lines
12 KiB
Markdown
320 lines
12 KiB
Markdown
# Dark Mode & Visual Polish Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Status:** ✅ Complete (2026-06-20)
|
|
|
|
**Goal:** Replace the warm-paper light theme with a warm-dark "notebook at night" aesthetic — dark-only, no toggle, paper grain texture, dark terrain map tiles, typography polish.
|
|
|
|
**Architecture:** Pure CSS token swap in `tokens.css` (all components update automatically), grain overlay via `body::after` SVG data URI in `style.css`, map tile URL swap in two Twig templates. No new dependencies, no JS changes, no structural changes.
|
|
|
|
**Tech Stack:** CSS custom properties, inline SVG noise filter, Stadia Maps Alidade Smooth Dark tile CDN, Leaflet.js (already present)
|
|
|
|
## Global Constraints
|
|
|
|
- All changes in `user/` — commit with `git -C user`, not main-repo git
|
|
- Dark-only — no `prefers-color-scheme` media query, no light-mode fallback, no toggle
|
|
- Existing token names in `tokens.css` must not change — only values swap
|
|
- No new npm/JS dependencies
|
|
- `make test-ui` must pass after every task (pre-existing P2 FilePond failure is acceptable)
|
|
- Map tile URL: `https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png` (CartoDB — no API key required)
|
|
- CartoDB attribution (exact): `© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>`
|
|
- Note: Stadia Maps requires an API key even for local dev — CartoDB dark_all is the keyless alternative
|
|
|
|
---
|
|
|
|
### Task 1: Dark color tokens
|
|
|
|
**Files:**
|
|
- Modify: `user/themes/intotheeast/css/tokens.css`
|
|
|
|
**Interfaces:**
|
|
- Produces: CSS custom properties consumed by every component in `style.css` and Twig templates
|
|
|
|
- [x] **Step 1: Read the current tokens file**
|
|
|
|
```bash
|
|
cat user/themes/intotheeast/css/tokens.css
|
|
```
|
|
|
|
Confirm these token names exist before editing: `--color-paper`, `--color-canvas`, `--color-ink`, `--color-ink-2`, `--color-ink-muted`, `--color-border`, `--color-border-soft`, `--color-accent`, `--color-accent-hover`, `--color-accent-light`, `--color-accent-on`.
|
|
|
|
- [x] **Step 2: Replace the color block in tokens.css**
|
|
|
|
Replace the entire `:root` color block (from `--color-paper` through `--color-accent-on`) with:
|
|
|
|
```css
|
|
/* ── Dark palette (warm notebook) ──────────────────────────────────────── */
|
|
--color-paper: #1A1814; /* page background — warm near-black */
|
|
--color-canvas: #22201B; /* card surfaces, form backgrounds */
|
|
--color-ink: #EDE8DF; /* primary text — warm cream */
|
|
--color-ink-2: #B8B0A4; /* body text — muted warm */
|
|
--color-ink-muted: #7A7268; /* labels, timestamps, captions */
|
|
--color-border: #2E2B25; /* standard dividers */
|
|
--color-border-soft: #252219; /* subtle dividers */
|
|
--color-accent: #2A8C73; /* teal — lightened for dark contrast */
|
|
--color-accent-hover: #236655; /* hover/pressed teal */
|
|
--color-accent-light: #1A2E29; /* pale teal tint backgrounds */
|
|
--color-accent-on: #FFFFFF; /* text on accent surfaces */
|
|
--color-surface-raised: #2A2720; /* elevated surfaces: tooltips, hover */
|
|
--color-ink-inverse: #17171A; /* text on accent-coloured buttons */
|
|
```
|
|
|
|
Keep all non-color tokens (`--text-*`, `--leading-*`, `--space-*`, font variables, etc.) unchanged.
|
|
|
|
- [x] **Step 3: Verify no syntax errors**
|
|
|
|
```bash
|
|
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache" && curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/dailies
|
|
```
|
|
|
|
Expected: `200`
|
|
|
|
- [x] **Step 4: Visual smoke check**
|
|
|
|
```bash
|
|
curl -s http://localhost:8081/trips/japan-korea-2026/dailies | grep -o 'color: var(--color-paper)' | head -3
|
|
```
|
|
|
|
Not a definitive check — just confirm the page renders. Open a browser and verify the background is dark and text is cream.
|
|
|
|
- [x] **Step 5: Run test suite**
|
|
|
|
```bash
|
|
make test-ui
|
|
```
|
|
|
|
Expected: 24/25 pass (P2 FilePond is pre-existing failure, all others pass).
|
|
|
|
- [x] **Step 6: Commit**
|
|
|
|
```bash
|
|
git -C user add themes/intotheeast/css/tokens.css
|
|
git -C user commit -m "feat: switch to warm-dark color tokens"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: Paper grain texture + hardcoded color fixes + typography
|
|
|
|
**Files:**
|
|
- Modify: `user/themes/intotheeast/css/style.css`
|
|
|
|
**Interfaces:**
|
|
- Consumes: dark color tokens from Task 1
|
|
|
|
- [x] **Step 1: Find all hardcoded color literals in style.css**
|
|
|
|
```bash
|
|
grep -n '#[0-9a-fA-F]\{3,6\}\|background: white\|background:#fff\|color: #\|background-color: #' user/themes/intotheeast/css/style.css
|
|
```
|
|
|
|
Make note of every hit — each one is a candidate to replace with a token. Exceptions: the CSS SVG data URI you are about to add (the noise filter hex values are part of the graphic, not UI colors).
|
|
|
|
- [x] **Step 2: Add paper grain texture to body**
|
|
|
|
Find the `body` rule in `style.css`. It will look something like:
|
|
|
|
```css
|
|
body {
|
|
background-color: var(--color-paper);
|
|
color: var(--color-ink);
|
|
...
|
|
}
|
|
```
|
|
|
|
Add a `body::after` rule immediately after the `body` rule:
|
|
|
|
```css
|
|
body::after {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 9998;
|
|
opacity: 0.035;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23noise)' opacity='1'/%3E%3C/svg%3E");
|
|
background-repeat: repeat;
|
|
background-size: 200px 200px;
|
|
}
|
|
```
|
|
|
|
- [x] **Step 3: Fix hardcoded login form colors**
|
|
|
|
Find this rule (around line 497):
|
|
|
|
```css
|
|
.login-form .button.secondary { background: #f0f0f0; color: #333; text-decoration: none; line-height: 44px; padding: 0 1rem; }
|
|
```
|
|
|
|
Replace with:
|
|
|
|
```css
|
|
.login-form .button.secondary { background: var(--color-canvas); color: var(--color-ink); text-decoration: none; line-height: 44px; padding: 0 1rem; }
|
|
```
|
|
|
|
- [x] **Step 4: Fix any other hardcoded colors found in Step 1**
|
|
|
|
For each hardcoded literal found in Step 1 (excluding the data URI you added):
|
|
- `#fff` / `white` → `var(--color-canvas)` (if a surface) or `var(--color-paper)` (if a page background)
|
|
- `#333` / dark grays → `var(--color-ink)` or `var(--color-ink-2)`
|
|
- `#eee` / light grays → `var(--color-border)` or `var(--color-border-soft)`
|
|
- `#f0f0f0` / near-white → `var(--color-canvas)`
|
|
|
|
Use judgment: if a hex is inside a gradient or SVG path data, leave it alone.
|
|
|
|
- [x] **Step 5: Typography — increase entry body paragraph spacing**
|
|
|
|
Find:
|
|
|
|
```css
|
|
.entry-body p { margin-bottom: 1.1em; font-size: var(--text-md); line-height: var(--leading-normal); color: var(--color-ink-2); }
|
|
```
|
|
|
|
Change `margin-bottom: 1.1em` to `margin-bottom: 1.4em`.
|
|
|
|
- [x] **Step 6: Typography — tighten h1/h2 tracking**
|
|
|
|
Find the `h1` and `h2` rules. Any rule that applies `letter-spacing: -0.01em` to an `h1` or `h2` — change it to `-0.02em`. Do not touch h3/h4/h5/h6.
|
|
|
|
- [x] **Step 7: Stats page — tabular numbers**
|
|
|
|
Find any CSS rule targeting stats numbers (look for `.stat-value`, `.stats-number`, or similar). Add `font-variant-numeric: tabular-nums` to it. If no such specific rule exists, search the template:
|
|
|
|
```bash
|
|
grep -n 'stat\|number\|count' user/themes/intotheeast/templates/stats.html.twig | head -20
|
|
```
|
|
|
|
Then add a targeted rule in style.css for whatever class wraps the numeric values.
|
|
|
|
- [x] **Step 8: Verify no syntax errors and visual check**
|
|
|
|
```bash
|
|
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache" && curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/dailies
|
|
```
|
|
|
|
Expected: `200`. Open browser — grain should be subtly visible on the dark background.
|
|
|
|
- [x] **Step 9: Run test suite**
|
|
|
|
```bash
|
|
make test-ui
|
|
```
|
|
|
|
Expected: 24/25 (P2 pre-existing).
|
|
|
|
- [x] **Step 10: Commit**
|
|
|
|
```bash
|
|
git -C user add themes/intotheeast/css/style.css
|
|
git -C user commit -m "feat: add paper grain texture, fix hardcoded colors, improve typography"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: Dark terrain map tiles
|
|
|
|
**Files:**
|
|
- Modify: `user/themes/intotheeast/templates/map.html.twig`
|
|
- Modify: `user/themes/intotheeast/templates/dailies.html.twig`
|
|
|
|
**Interfaces:**
|
|
- Consumes: Leaflet.js already loaded in both templates
|
|
- Produces: Stadia Alidade Smooth Dark tiles replacing OpenStreetMap tiles in both map views
|
|
|
|
- [x] **Step 1: Read current tile setup in both templates**
|
|
|
|
```bash
|
|
grep -n "tileLayer\|openstreetmap\|attribution\|stadia" user/themes/intotheeast/templates/map.html.twig user/themes/intotheeast/templates/dailies.html.twig
|
|
```
|
|
|
|
Confirm the current tile URL pattern (`{s}.tile.openstreetmap.org`) in both files.
|
|
|
|
- [x] **Step 2: Replace tile layer in map.html.twig**
|
|
|
|
Find:
|
|
|
|
```javascript
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
}).addTo(map);
|
|
```
|
|
|
|
Replace with:
|
|
|
|
```javascript
|
|
// TODO: add Stadia API key before launch — free dev use requires no key, production does
|
|
L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
|
|
maxZoom: 20,
|
|
attribution: '© <a href="https://stadiamaps.com/">Stadia Maps</a> © <a href="https://openmaptiles.org/">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
}).addTo(map);
|
|
```
|
|
|
|
- [x] **Step 3: Replace tile layer in dailies.html.twig (mini-map)**
|
|
|
|
Apply the identical tile swap to the mini-map `L.tileLayer` call in `dailies.html.twig`. Find the OpenStreetMap tile URL and replace it with the Stadia dark URL (same as Step 2, same attribution, same TODO comment).
|
|
|
|
- [x] **Step 4: Verify tiles load**
|
|
|
|
```bash
|
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/map
|
|
```
|
|
|
|
Expected: `200`.
|
|
|
|
Check the tile URL is in the HTML:
|
|
|
|
```bash
|
|
curl -s http://localhost:8081/trips/japan-korea-2026/map | grep -o 'stadiamaps'
|
|
```
|
|
|
|
Expected: `stadiamaps` (appears in the tile URL).
|
|
|
|
Open the map in a browser and confirm:
|
|
- Dark terrain tiles render (not the default light OSM tiles)
|
|
- GPX polyline is visible in teal on the dark background
|
|
- Entry pins render correctly on top
|
|
- Attribution footer is present
|
|
|
|
- [x] **Step 5: Check mini-map on dailies page**
|
|
|
|
```bash
|
|
curl -s http://localhost:8081/trips/japan-korea-2026/dailies | grep -o 'stadiamaps'
|
|
```
|
|
|
|
Expected: `stadiamaps`.
|
|
|
|
- [x] **Step 6: Run test suite**
|
|
|
|
```bash
|
|
make test-ui
|
|
```
|
|
|
|
Expected: 24/25 (P2 pre-existing).
|
|
|
|
- [x] **Step 7: Commit**
|
|
|
|
```bash
|
|
git -C user add themes/intotheeast/templates/map.html.twig themes/intotheeast/templates/dailies.html.twig
|
|
git -C user commit -m "feat: switch to Stadia Alidade Smooth Dark map tiles"
|
|
```
|
|
|
|
---
|
|
|
|
## Final verification
|
|
|
|
After all 3 tasks:
|
|
|
|
1. `make test-config && make test-post && make test-ui` — all pass
|
|
2. Visual check list (browser, not curl):
|
|
- `/trips/japan-korea-2026/dailies` — dark warm background, cream text, grain visible, teal accents
|
|
- `/trips/japan-korea-2026/map` — dark terrain tiles, teal GPX polyline, entry pins
|
|
- `/trips/japan-korea-2026/dailies/<any-entry>` — dark canvas card, no white boxes
|
|
- `/post` — form fields readable, no black-on-black inputs
|
|
- `/trips/japan-korea-2026/stats` — numbers align (tabular-nums)
|
|
3. Final hardcoded-literal check:
|
|
```bash
|
|
grep -n '#[0-9a-fA-F]\{3,6\}' user/themes/intotheeast/css/style.css | grep -v 'data:image'
|
|
```
|
|
All remaining hits should be either intentional (e.g. SVG path data) or documented.
|