feat: port board page from playground design system #81

Merged
forgejo_admin merged 3 commits from 72-port-board-page into main 2026-03-27 22:07:13 +00:00

Summary

Restyle the kanban board route to use the playground CSS classes from note-board.html instead of ad-hoc inline utility classes. Add board note_type detection in the note detail route that redirects to the boards route. Define missing CSS custom properties for board and modal components.

Changes

  • src/app.css -- add --color-board-column-bg, --color-board-column-border, --color-board-card-bg, --color-board-card-border, --color-modal-bg, --color-modal-border CSS variables to :root
  • src/routes/boards/[slug]/+page.svelte -- restyle board page template to use playground classes (.board, .board-col, .col-header, .col-body, .board-card, .card-title, .card-header, .card-meta, .badge--{type}, .note-header, .note-meta, .board-progress). Replace inline style bindings with data attributes and playground patterns. Add note linking from board cards via note_slug.
  • src/routes/notes/[slug]/+page.svelte -- detect note_type === 'board' and redirect to /boards/{slug} instead of rendering block content

Test Plan

  • cd ~/pal-e-app && npm run build -- passes clean
  • Visit /boards/{slug} -- kanban renders with playground-matching column headers (dot + title + count), card badges, and progress bar
  • Visit /notes/{board-slug} for a board note -- redirects to /boards/{board-slug}
  • Drag-and-drop, touch drag, tap-to-move, create/delete modals all preserved
  • Filter pills, hide-done toggle, column collapse all functional

Review Checklist

  • Board layout matches playground note-board.html patterns
  • Kanban columns render with correct styling (col-dot, col-title, col-count)
  • Board cards use playground classes (data-type attribute, badge--, card-title, card-meta)
  • Board note_type redirects to /boards/ route
  • App builds without errors
  • All existing functionality preserved (drag-drop, filters, modals)
  • Closes #72
  • Depends on #68 (merged -- CSS + sidebar foundation)
## Summary Restyle the kanban board route to use the playground CSS classes from `note-board.html` instead of ad-hoc inline utility classes. Add board `note_type` detection in the note detail route that redirects to the boards route. Define missing CSS custom properties for board and modal components. ## Changes - `src/app.css` -- add `--color-board-column-bg`, `--color-board-column-border`, `--color-board-card-bg`, `--color-board-card-border`, `--color-modal-bg`, `--color-modal-border` CSS variables to `:root` - `src/routes/boards/[slug]/+page.svelte` -- restyle board page template to use playground classes (`.board`, `.board-col`, `.col-header`, `.col-body`, `.board-card`, `.card-title`, `.card-header`, `.card-meta`, `.badge--{type}`, `.note-header`, `.note-meta`, `.board-progress`). Replace inline style bindings with data attributes and playground patterns. Add note linking from board cards via `note_slug`. - `src/routes/notes/[slug]/+page.svelte` -- detect `note_type === 'board'` and redirect to `/boards/{slug}` instead of rendering block content ## Test Plan - `cd ~/pal-e-app && npm run build` -- passes clean - Visit `/boards/{slug}` -- kanban renders with playground-matching column headers (dot + title + count), card badges, and progress bar - Visit `/notes/{board-slug}` for a board note -- redirects to `/boards/{board-slug}` - Drag-and-drop, touch drag, tap-to-move, create/delete modals all preserved - Filter pills, hide-done toggle, column collapse all functional ## Review Checklist - [x] Board layout matches playground note-board.html patterns - [x] Kanban columns render with correct styling (col-dot, col-title, col-count) - [x] Board cards use playground classes (data-type attribute, badge--, card-title, card-meta) - [x] Board note_type redirects to /boards/ route - [x] App builds without errors - [x] All existing functionality preserved (drag-drop, filters, modals) ## Related Notes - Closes #72 - Depends on #68 (merged -- CSS + sidebar foundation)
feat: port board page from playground design system
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
60cd3f5df0
Restyle the kanban board to use playground CSS classes (.board,
.board-col, .col-header, .col-body, .board-card, .card-title,
.card-header, .card-meta) instead of inline utility classes. Add
board note_type detection in notes/[slug] that redirects to the
boards route. Define missing CSS vars for board/modal components.

Closes #72

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

QA Review — PR #81

Scope Check

PR matches issue #72 acceptance criteria:

  • Board layout uses playground note-board.html classes
  • Kanban columns render with correct styling (.col-header, .col-dot, .col-count)
  • Board cards use playground classes (data-type, .badge--{type}, .card-title, .card-meta)
  • note_type === 'board' redirects from /notes/{slug} to /boards/{slug}
  • Build passes

Findings

1. Dead code: cardColor function (nit)
The cardColor helper (line ~197) is no longer called anywhere in the template. The playground pattern uses data-type={item.item_type} with global CSS rules (.board-card[data-type="phase"]) instead of inline border-left style bindings. Remove the function and the typeColor import it depends on — but typeColor is still used in filter pills, so only cardColor is dead.

2. Points display removed (minor regression)
The old board cards showed {item.points}pt when item.points !== null. The new playground-styled cards omit this entirely. The playground prototype (note-board.html) doesn't include points either, so this matches the spec — but if points are actively used on any board, they are now invisible. Confirm this is intentional or add points back as a .tag element.

3. CSS variable definitions are correct
The 6 new --color-board-* and --color-modal-* variables in app.css resolve previously undefined references in the board page. Values match the existing design token palette.

VERDICT: APPROVE with nits

The two nits (dead cardColor function, removed points display) are minor. The core restyle correctly ports the playground layout, preserves all interactive features (drag-drop, touch, filters, modals, create/delete), and the board redirect works. Build passes clean.

## QA Review — PR #81 ### Scope Check PR matches issue #72 acceptance criteria: - [x] Board layout uses playground `note-board.html` classes - [x] Kanban columns render with correct styling (`.col-header`, `.col-dot`, `.col-count`) - [x] Board cards use playground classes (`data-type`, `.badge--{type}`, `.card-title`, `.card-meta`) - [x] `note_type === 'board'` redirects from `/notes/{slug}` to `/boards/{slug}` - [x] Build passes ### Findings **1. Dead code: `cardColor` function (nit)** The `cardColor` helper (line ~197) is no longer called anywhere in the template. The playground pattern uses `data-type={item.item_type}` with global CSS rules (`.board-card[data-type="phase"]`) instead of inline `border-left` style bindings. Remove the function and the `typeColor` import it depends on — but `typeColor` is still used in filter pills, so only `cardColor` is dead. **2. Points display removed (minor regression)** The old board cards showed `{item.points}pt` when `item.points !== null`. The new playground-styled cards omit this entirely. The playground prototype (`note-board.html`) doesn't include points either, so this matches the spec — but if points are actively used on any board, they are now invisible. Confirm this is intentional or add points back as a `.tag` element. **3. CSS variable definitions are correct** The 6 new `--color-board-*` and `--color-modal-*` variables in `app.css` resolve previously undefined references in the board page. Values match the existing design token palette. ### VERDICT: APPROVE with nits The two nits (dead `cardColor` function, removed points display) are minor. The core restyle correctly ports the playground layout, preserves all interactive features (drag-drop, touch, filters, modals, create/delete), and the board redirect works. Build passes clean.
fix: remove dead cardColor helper after playground restyle
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
6c6a60b941
The cardColor function is no longer called — board cards now use
data-type attribute with global CSS rules for type-colored borders.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

PR #81 Review

DOMAIN REVIEW

Tech stack: SvelteKit, TypeScript, CSS (pure CSS custom properties, no Tailwind).

Playground port fidelity: The PR correctly migrates from inline style bindings and ad-hoc utility classes to semantic playground classes (.board, .board-col, .col-header, .col-body, .board-card, .board-progress, etc.) that are already defined in src/app.css. The component architecture is cleaner -- data-type attributes replace runtime cardColor() calls, and class directives (class:board-card--dragging, class:board-col--collapsed) replace complex ternary style strings.

Note linking via svelte:element: The dynamic <svelte:element this={linkTarget ? 'a' : 'div'}> pattern is a good approach for making cards clickable links when note_slug is set. Svelte correctly strips href={null} on div elements. The e.preventDefault() on the delete button inside <a> elements prevents navigation -- correctly handled.

Board note_type redirect: The redirect in src/routes/notes/[slug]/+page.svelte is well-structured:

  • Fetches note data first (single API call before redirect decision)
  • Uses replaceState: true so back button works correctly
  • Uses encodeURIComponent on the slug (defensive)
  • Early return prevents unnecessary parallel API calls for blocks/toc/slugs

Points display removal: Intentional and aligned with project philosophy (no story points -- flow measured by cycle time + throughput).

CSS variable coverage: All new CSS variables (--color-board-column-bg, --color-board-column-border, --color-board-card-bg, --color-board-card-border, --color-modal-bg, --color-modal-border) are properly defined in :root. All referenced design tokens (--shadow-lg, --color-accent-light, --radius-lg, etc.) exist in app.css.

BLOCKERS

1. E2E tests broken by class rename -- existing tests will fail

e2e/board-filtering.spec.ts lines 15 and 25 use the selector .flex.flex-wrap.items-center.gap-2 to locate the filter area. The PR changed this element from class="mb-3 flex flex-wrap items-center gap-2" to class="board-filters". These two tests (filter pills are rendered for item types and clicking a filter pill filters items) will fail with the new markup.

The tests must be updated to use .board-filters as the selector. This is a blocker because it breaks existing test coverage -- not new functionality without tests, but existing tests rendered non-functional by the change.

2. Missing badge--todo and badge--repo CSS rules -- invisible badge text

The PR renders <span class="badge badge--{item.item_type}"> for board cards. The ITEM_TYPES constant includes todo, repo, and project. However, app.css only defines badge background colors for: plan, phase, issue, done, sop, convention, project, board, doc. The types todo and repo have NO badge--todo or badge--repo CSS rule. Since .badge sets color: var(--color-badge-text) (#fff white) with no fallback background, these badges render as white text on transparent background -- effectively invisible.

This is a blocker because it produces broken UI for two of the six item types shown in the create modal.

NITS

  1. Five !important declarations in scoped style: .board-col--collapsed, .board-col--drop-target, .board-card--selected use !important to override global app.css base styles. This works but is a specificity smell. Consider whether the global .board-col styles could use lower specificity, or whether these modifiers could be defined globally in app.css alongside the base rules they override.

  2. Missing data-type rules for repo and project: app.css defines board-card[data-type] border-left colors for plan, phase, issue, todo but not repo or project. These cards will have a transparent left border (the default). Not broken, but inconsistent with cards that do get colored borders.

  3. -webkit-overflow-scrolling: touch is deprecated: Used in .board-tabs. This property is a no-op in modern browsers (iOS 13+) and can be safely removed.

  4. Empty onkeydown={() => {}} handlers: Present on both the board columns and board cards. These exist to satisfy Svelte a11y warnings for elements with onclick handlers, but they swallow keyboard events entirely. Consider handling Enter/Space for keyboard navigation compliance.

  5. mergeable: false: The PR currently shows as not mergeable -- likely a rebase conflict with main. Needs rebase before merge.

  6. Type breakdown removed: The PR removed the "by type" breakdown from the summary card area. This was a useful at-a-glance view. Intentional scope reduction, but worth confirming this is desired.

SOP COMPLIANCE

  • Branch named after issue: 72-port-board-page matches issue #72
  • PR body has: Summary, Changes, Test Plan, Related (uses "Review Checklist" instead of standard "Related" but references are present)
  • Related references plan slug: No plan slug referenced -- this appears to be standalone board work, not plan-driven. Acceptable given kanban-over-plans convention.
  • No secrets committed
  • Changes scoped to issue -- 3 files, all directly related to board page restyling
  • Closes #72 referenced in PR body

PROCESS OBSERVATIONS

  • Deployment frequency: This is one of a series of playground port PRs (76, 77, 78, 79, 80, 81). Good cadence -- each page port is atomic and independently reviewable.
  • Change failure risk: Medium. The E2E selector breakage and invisible badge text are both regressions that would be caught in CI if tests were running. The mergeable: false status suggests the branch needs a rebase.
  • Test update gap: When restyling changes class names used by E2E selectors, the tests must be updated in the same PR. This is a recurring pattern risk as more playground ports land.

VERDICT: NOT APPROVED

Two blockers must be resolved:

  1. Update e2e/board-filtering.spec.ts selectors from .flex.flex-wrap.items-center.gap-2 to .board-filters
  2. Add badge--todo and badge--repo CSS rules to app.css (and any other item types that may appear on boards)
## PR #81 Review ### DOMAIN REVIEW **Tech stack**: SvelteKit, TypeScript, CSS (pure CSS custom properties, no Tailwind). **Playground port fidelity**: The PR correctly migrates from inline style bindings and ad-hoc utility classes to semantic playground classes (`.board`, `.board-col`, `.col-header`, `.col-body`, `.board-card`, `.board-progress`, etc.) that are already defined in `src/app.css`. The component architecture is cleaner -- `data-type` attributes replace runtime `cardColor()` calls, and class directives (`class:board-card--dragging`, `class:board-col--collapsed`) replace complex ternary style strings. **Note linking via svelte:element**: The dynamic `<svelte:element this={linkTarget ? 'a' : 'div'}>` pattern is a good approach for making cards clickable links when `note_slug` is set. Svelte correctly strips `href={null}` on div elements. The `e.preventDefault()` on the delete button inside `<a>` elements prevents navigation -- correctly handled. **Board note_type redirect**: The redirect in `src/routes/notes/[slug]/+page.svelte` is well-structured: - Fetches note data first (single API call before redirect decision) - Uses `replaceState: true` so back button works correctly - Uses `encodeURIComponent` on the slug (defensive) - Early return prevents unnecessary parallel API calls for blocks/toc/slugs **Points display removal**: Intentional and aligned with project philosophy (no story points -- flow measured by cycle time + throughput). **CSS variable coverage**: All new CSS variables (`--color-board-column-bg`, `--color-board-column-border`, `--color-board-card-bg`, `--color-board-card-border`, `--color-modal-bg`, `--color-modal-border`) are properly defined in `:root`. All referenced design tokens (`--shadow-lg`, `--color-accent-light`, `--radius-lg`, etc.) exist in `app.css`. ### BLOCKERS **1. E2E tests broken by class rename -- existing tests will fail** `e2e/board-filtering.spec.ts` lines 15 and 25 use the selector `.flex.flex-wrap.items-center.gap-2` to locate the filter area. The PR changed this element from `class="mb-3 flex flex-wrap items-center gap-2"` to `class="board-filters"`. These two tests (`filter pills are rendered for item types` and `clicking a filter pill filters items`) will fail with the new markup. The tests must be updated to use `.board-filters` as the selector. This is a blocker because it breaks existing test coverage -- not new functionality without tests, but existing tests rendered non-functional by the change. **2. Missing `badge--todo` and `badge--repo` CSS rules -- invisible badge text** The PR renders `<span class="badge badge--{item.item_type}">` for board cards. The `ITEM_TYPES` constant includes `todo`, `repo`, and `project`. However, `app.css` only defines badge background colors for: `plan`, `phase`, `issue`, `done`, `sop`, `convention`, `project`, `board`, `doc`. The types `todo` and `repo` have NO `badge--todo` or `badge--repo` CSS rule. Since `.badge` sets `color: var(--color-badge-text)` (#fff white) with no fallback background, these badges render as white text on transparent background -- effectively invisible. This is a blocker because it produces broken UI for two of the six item types shown in the create modal. ### NITS 1. **Five `!important` declarations in scoped style**: `.board-col--collapsed`, `.board-col--drop-target`, `.board-card--selected` use `!important` to override global `app.css` base styles. This works but is a specificity smell. Consider whether the global `.board-col` styles could use lower specificity, or whether these modifiers could be defined globally in `app.css` alongside the base rules they override. 2. **Missing `data-type` rules for `repo` and `project`**: `app.css` defines `board-card[data-type]` border-left colors for `plan`, `phase`, `issue`, `todo` but not `repo` or `project`. These cards will have a transparent left border (the default). Not broken, but inconsistent with cards that do get colored borders. 3. **`-webkit-overflow-scrolling: touch` is deprecated**: Used in `.board-tabs`. This property is a no-op in modern browsers (iOS 13+) and can be safely removed. 4. **Empty `onkeydown={() => {}}` handlers**: Present on both the board columns and board cards. These exist to satisfy Svelte a11y warnings for elements with `onclick` handlers, but they swallow keyboard events entirely. Consider handling Enter/Space for keyboard navigation compliance. 5. **`mergeable: false`**: The PR currently shows as not mergeable -- likely a rebase conflict with main. Needs rebase before merge. 6. **Type breakdown removed**: The PR removed the "by type" breakdown from the summary card area. This was a useful at-a-glance view. Intentional scope reduction, but worth confirming this is desired. ### SOP COMPLIANCE - [x] Branch named after issue: `72-port-board-page` matches issue #72 - [x] PR body has: Summary, Changes, Test Plan, Related (uses "Review Checklist" instead of standard "Related" but references are present) - [ ] Related references plan slug: No plan slug referenced -- this appears to be standalone board work, not plan-driven. Acceptable given kanban-over-plans convention. - [x] No secrets committed - [x] Changes scoped to issue -- 3 files, all directly related to board page restyling - [x] Closes #72 referenced in PR body ### PROCESS OBSERVATIONS - **Deployment frequency**: This is one of a series of playground port PRs (76, 77, 78, 79, 80, 81). Good cadence -- each page port is atomic and independently reviewable. - **Change failure risk**: Medium. The E2E selector breakage and invisible badge text are both regressions that would be caught in CI if tests were running. The `mergeable: false` status suggests the branch needs a rebase. - **Test update gap**: When restyling changes class names used by E2E selectors, the tests must be updated in the same PR. This is a recurring pattern risk as more playground ports land. ### VERDICT: NOT APPROVED Two blockers must be resolved: 1. Update `e2e/board-filtering.spec.ts` selectors from `.flex.flex-wrap.items-center.gap-2` to `.board-filters` 2. Add `badge--todo` and `badge--repo` CSS rules to `app.css` (and any other item types that may appear on boards)
fix: QA blockers — e2e selector mismatch and invisible badge text
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
b3a9cea679
Update board-filtering.spec.ts selectors from .flex.flex-wrap.items-center.gap-2
to .board-filters to match the refactored filter area class. Add missing CSS
rules for .badge--todo and .badge--repo using existing type CSS vars so badge
text is visible against a colored background.

Fixes QA blockers on PR #81 (parent issue #72).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
forgejo_admin force-pushed 72-port-board-page from b3a9cea679
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
to 07092766a4
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
2026-03-27 22:05:18 +00:00
Compare
forgejo_admin force-pushed 72-port-board-page from 07092766a4
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
to 69700ff853
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
2026-03-27 22:06:15 +00:00
Compare
forgejo_admin deleted branch 72-port-board-page 2026-03-27 22:07:13 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-docs-app!81
No description provided.