Skip to content

fix(custom-v2): wire markdown + text-code viewers to real v2 design tokens#202

Merged
zjean merged 2 commits into
mainfrom
fix/v2-markdown-dark-bg
May 19, 2026
Merged

fix(custom-v2): wire markdown + text-code viewers to real v2 design tokens#202
zjean merged 2 commits into
mainfrom
fix/v2-markdown-dark-bg

Conversation

@zjean
Copy link
Copy Markdown
Owner

@zjean zjean commented May 19, 2026

Problem

In the just-merged v2 TipTap markdown viewer (#201), the editor area renders white text on a white background — completely unreadable.

The classic text-code-view had the same latent bug, just less visible because CodeMirror paints its own background over the editor body. The chrome around the editor (status bar, error states) was still rendering against a misplaced white sheet.

Root cause

Both viewers used var(--si-bg, #fff) and var(--si-danger, #c0392b), but v2's design system has no such tokens. The tokens that do exist (defined at .v2-root from PR #195 — the Stack navy palette) are --si-bg0--si-bg6 for surfaces, --si-fg / --si-fg-muted / etc. for text, and --si-rose for warm-red status.

So var(--si-bg, #fff) falls back to #fff (white sheet), while var(--si-fg, #111) correctly resolves to v2's near-white. White text on white sheet.

Verified the variable inventory at .v2-root via chrome-devtools — --si-bg is genuinely absent; --si-bg0--si-bg6 are the navy ramp.

Fix

Two components touched, identical pattern:

markdown-view.component.ts

  • :host and .md-view__body background → --si-bg0 (the same canvas the surrounding .detail__stage uses).
  • .md-view__state--error color → --si-rose.
  • Drop the now-dead .md-view__editor--dark selector and its [class.md-view__editor--dark] template binding — v2's palette is always-dark by design.
  • Drop the spurious var() fallbacks on .ProseMirror color and :host color.

text-code-view.component.ts

  • :host and .text-view__body background → --si-bg0.
  • .text-view__state--error color → --si-rose.
  • Drop the spurious var() fallbacks on :host bg/color.

Verification

  • npm --prefix frontend run build clean.
  • npm --prefix frontend run lint clean.
  • Browser-verified via chrome-devtools at 192.168.1.133:8080:
    • /v2/file?path=/files/personal/tiptap-test.md — navy --si-bg0 background, readable near-white text, all markdown elements render with proper contrast.
    • /v2/file?path=/files/personal/text-test.txt — CodeMirror gutter/content unchanged; surrounding chrome (status bar, body) now navy and consistent with the rest of v2.

Merge strategy

Squash and merge per CLAUDE.md (fix PR).

zjean added 2 commits May 19, 2026 20:50
The TipTap markdown viewer was using a `--si-bg` / `--si-danger` token
that doesn't exist in v2's design system, so the var() fallbacks (`#fff`,
`#c0392b`) painted a white sheet across the editor while text inherited
the navy-palette near-white --si-fg — i.e. white text on white.

v2's tokens (set at .v2-root) are a navy ramp: --si-bg0…bg6 for surfaces,
--si-fg/--si-fg-muted/etc for text, --si-rose for warm-red status. Point
the viewer at those:

- :host and .md-view__body background → --si-bg0 (matches the file-detail
  stage so the editor blends with surrounding chrome instead of stamping
  a sheet).
- .md-view__state--error color → --si-rose (v2's red).
- Dropped the dead .md-view__editor--dark selector and the corresponding
  [class.md-view__editor--dark] template binding — v2's palette is always
  dark by design, so the WYSIWYG body always uses --si-fg directly.
- Removed the spurious var() fallbacks on .ProseMirror color and :host
  color; the tokens always exist under .v2-root.

Browser-verified via chrome-devtools: navy bg, readable near-white text,
all markdown elements (headings, lists, blockquote, fenced code, inline
code, accent-colored link) render correctly.
Same broken --si-bg / --si-danger references as the markdown viewer's
prior bug, just less visible because CodeMirror paints its own
background. The surrounding chrome (status bar above the editor, error
states) was still latently broken.

- :host + .text-view__body bg → --si-bg0 (matches .detail__stage)
- .text-view__state--error color → --si-rose
- Drop the spurious var() fallbacks on :host bg/color now that the
  tokens are guaranteed under .v2-root.

Browser-verified: text-test.txt opens with the navy canvas matching
the rest of v2 chrome.
@zjean zjean changed the title fix(custom-v2): wire markdown viewer to real v2 design tokens fix(custom-v2): wire markdown + text-code viewers to real v2 design tokens May 19, 2026
@zjean zjean merged commit 301942c into main May 19, 2026
1 check passed
@zjean zjean deleted the fix/v2-markdown-dark-bg branch May 19, 2026 18:57
zjean added a commit that referenced this pull request May 19, 2026
#203)

## Summary

Two changes to `.claude/skills/` based on lessons from this session's PR
#200 / #201 / #202 cycle:

1. **Refines `sync-in-fork-maintenance`** to capture friction that hit
today and would hit again.
2. **Adds `v2-dev-loop-verify`** — a new browser-verification skill
specifically for catching v2-specific bugs (like the PR #202
white-on-white token miss) that pass build + lint cleanly.

Both skills are tooling-only and ship under `.claude/skills/` — no
application code is changed.

## `sync-in-fork-maintenance` refinements

- **`gh CLI gotchas`** — generalize the `rtk proxy` JSON rule to *any*
`gh ... --json` call you depend on a field of, not just `gh api`. Hit
today: `gh pr view 199 --json mergeable,mergeStateStatus,...` silently
hid the `CONFLICTING` state until re-run through `rtk proxy`.
- **`gh CLI gotchas`** — extend the rtk-rejects-`--allow-empty` note to
also cover `--no-edit`. The merge-commit step in task 2 now uses `rtk
proxy git commit --no-edit` so rtk doesn't strip the flag.
- **Task 2 \"Verify before committing\"** — drop `git add -A`.
Conflict-resolved files are already staged via per-file `git add` during
resolution; cleanly-auto-merged files are staged by `git merge` itself.
`git add -A` would also sweep in unrelated
`.claude/scheduled_tasks.lock` + `.claude/settings.local.json`
working-tree state. Stage regenerated files (e.g. `package-lock.json`
after `npm install`) by name and commit.
- **New \"Aftermath — once the sync PR is merged\" subsection** —
fast-forward local `main`, delete the local sync branch. Notes the
SHA-divergence quirk where GitHub's \"Create a merge commit\" produces a
new merge commit on the server side, so the local merge-commit SHA won't
match origin's after pull (today: local `ad0979a7` ≠ origin's `07a8bce1`
— same tree, different SHA).
- **Task 3 classification table** — adds a 4th bucket for \"New
component / styles in classic UI\" pointing into the new
style-translation section.
- **New \"Style token translation (when porting classic UI into
custom-v2)\" section** — codifies the PR #202 white-on-white root cause
as a generalizable port-with-care guideline. Lists `.v2-root`'s actual
token inventory (the `--si-bg0`–`--si-bg6` navy ramp,
`--si-fg`/`--si-fg-muted`/etc., `--si-rose`, accent variants). Provides
a rewrite table for the common bad patterns (`var(--si-bg, #fff)` →
`var(--si-bg0)`, `var(--si-danger, #c0392b)` → `var(--si-rose)`, classic
light-mode fallbacks → drop). Codifies the \"drop fallbacks; drop dead
light/dark plumbing; verify via chrome-devtools\" procedure.
- **evals.json** — tightens eval #2 (conflict-resolution) to assert `rtk
proxy git commit --no-edit` and absence of `git add -A`. Adds eval #4
(`port-classic-styles-to-v2-tokens`) exercising the design-token
translation end-to-end against the PR #201/#202 scenario.

## New `v2-dev-loop-verify` skill

8-step browser-verification recipe via the `chrome-devtools` MCP against
the local dev server. Triggers proactively after any visual or
behavioural change under `custom-v2/`. Covers, in order:

1. **Dodge the loopback hijack** — `127.0.0.1:8080` / `localhost:8080`
are hijacked by VS Code's helper process; use the active LAN IP
(`/sbin/ifconfig en0` for the active interface).
2. **Log in** via the UI form with `sync-in` / `password` (per CLAUDE.md
memory).
3. **Create fixtures** via the CSRF-authenticated API. The file-creation
flow is non-obvious: `POST upload` alone returns `405 Resource already
exists` because the URL treats `files/personal` as a parent dir. Right
flow is `POST make → UNLOCK → PATCH upload → UNLOCK` (the last UNLOCK
release matters — without it the v2 viewer opens in read-only because of
the lock the upload left).
4. **Navigate + snapshot** to confirm the right viewer mounted
(`.ProseMirror` for TipTap, `.cm-editor` for CodeMirror, etc.).
5. **Computed-styles audit** for v2 design-token bugs — walk from the
leaf (`.ProseMirror`) up to `.v2-root` capturing `color` +
`background-color` at each layer. Smoking gun for the PR #202 bug class:
`color: oklch(0.9x ...)` (near-white) over an `rgb(255,255,255)`
ancestor — a `var()` fallback fired because the token doesn't exist.
6. **Drive signal-backed editors** via `window.ng.getComponent(host)` —
`component.editor.chain().insertContent()` for TipTap,
`component.content.set()` for CodeMirror-via-ngModel. Synthetic
`InputEvent('beforeinput', ...)` and `document.execCommand` **don't**
trigger TipTap's `onUpdate`, so dirty-flag never flips.
7. **Save round-trip** — click Save, `wait_for ['Opgeslagen', 'Saved']`,
then `GET /api/app/spaces/operation/<path>` and confirm the new content
is in the response body.
8. **Cleanup** — release locks, optionally `DELETE` test fixtures.

Path gotcha worth flagging: `chrome-devtools` enforces workspace roots
on screenshot saves; `/tmp/foo.png` is denied. `$TMPDIR` (resolves to
`/var/folders/zc/.../T/` on macOS) and the repo path both work.

evals.json — 3 test cases: `verify-after-styling-change` (proactive),
`debug-v2-styling-bug` (regression test for the PR #202 class),
`verify-edit-save-round-trip` (exercises the Angular debug-API trick).

## Merge strategy

Squash and merge per CLAUDE.md (chore PR).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant