Board card detail drawer (traceability triangle) + remove orphaned Tailwind + wrap long titles #116

Open
opened 2026-05-03 14:53:07 +00:00 by forgejo_admin · 1 comment
Contributor

Type

Feature

Lineage

Standalone — discovered 2026-05-03 during Lucas review of board-westside-mcp UX. Three visual/UX defects on the kanban page bundled into one ticket because they all touch the same Svelte file and splitting would create merge churn for no benefit.

Repo

forgejo_admin/pal-e-app

User Story

As a platform owner, I want to see the full traceability triangle (story / arch / spec / PRs) for any board card I click in pal-e-app, so that I can navigate from any ticket to why it exists, what part of the system it touches, and what code came from it — without leaving pal-e-app or hand-grepping Forgejo.

Full story note (with success metric and AC): story-pal-e-app-board-card-traceability

Context

Today the board page (src/routes/boards/[slug]/+page.svelte) renders cards as opaque tokens.

  • Cards WITH note_slug → render as <a href="/notes/{slug}">, click navigates to the linked note (works).
  • Cards WITHOUT note_slug → render as <div>, click calls tapItem() which only sets selectedItem for the tap-to-move flow. There is no detail view. The .mobile-hint div ("Tap a column to move ...") appears, but the card's actual data (labels, type, column, linked Forgejo issue) is invisible to the user.

Every board item already carries story:X / arch:X / type:X labels enforced by the create_board_item hook. The data is in the database. The UI just doesn't surface it. This ticket closes that gap.

Two adjacent defects discovered during the same investigation, bundled because they share the file:

  1. Orphaned Tailwind classes. Lines 476 and 572 use class="fixed inset-0 z-50 flex items-center justify-center" on the Create-Item and Delete-Item modals. Tailwind is NOT installed (vite.config.ts has only sveltekit(), no PostCSS, no UnoCSS). The classes produce no CSS — modals render as inline block divs in normal page flow with no overlay, no centering, no z-index.
  2. Long-token title overflow. .card-title in src/app.css:759 has no overflow-wrap. Underscored identifiers (e.g. draft_tournament_email) are treated as unbreakable tokens and overflow narrow columns.

File Targets

Files to modify:

  • src/routes/boards/[slug]/+page.svelte — add inline drawer markup (or extract to component, see below); change card onclick to open drawer instead of tapItem(); replace Tailwind utility classes on Create/Delete modal wrappers with raw CSS classes; remove the tapItem / tapColumn / selectedItem state OR migrate it inside the drawer's "Move to Column" section
  • src/app.css — add overflow-wrap: anywhere to .card-title (line 759); add .card-drawer, .card-drawer-backdrop, .card-drawer-section, .card-drawer-label-chip, .modal-overlay styles using existing design tokens
  • (Optional, recommended for reuse) src/lib/components/BoardCardDetail.svelte — new component encapsulating the drawer; keeps the page file thin

Files NOT to touch:

  • src/lib/api-client.ts — no API changes; backend already returns everything (labels, note_slug, forgejo_issue_url, item_type, column)
  • Any other route — scope is the board renderer only

Acceptance Criteria

  • Click any board card → drawer slides in from right (CSS transform: translateX transition); does not navigate away from the board page
  • Drawer shows: card title (wrapped), <span class="badge badge--{item_type}"> type badge, current column name, every label as a clickable chip
  • Label chip resolution:
    • story:X/notes/story-{board's project_slug}-{X} (e.g. story-pal-e-app-board-card-traceability)
    • arch:X/notes/arch-{X} if globally canonical (per convention-architecture-ids), else /notes/arch-dataflow-{project_slug} as fallback
    • type:X → no link, visual chip only
    • Other labels (scope:X, etc.) → visual chip only
  • If forgejo_issue_url set → "View Forgejo Issue ↗" link in drawer (opens in new tab)
  • If note_slug set → "Open Linked Note →" link in drawer (in-app navigation)
  • "Move to Column" section in drawer renders one button per column except the current one; clicking calls existing doMoveItem and closes the drawer
  • Drawer closes on: Escape key, backdrop click, dedicated × close button
  • Tap-on-card no longer triggers tap-to-move flow (replaced by drawer's move buttons). HTML5 drag-and-drop (desktop) and long-press touch drag (mobile) still work unchanged
  • .card-title wraps long unbreakable tokens (verify visually with the existing card "Scaffold westside-mcp + draft_tournament_email tool")
  • Create-Item modal renders centered with semi-opaque backdrop (no Tailwind classes)
  • Delete-Item modal renders centered with semi-opaque backdrop (no Tailwind classes)
  • All new styles use existing CSS vars: var(--color-surface), var(--color-border), var(--color-text), var(--radius-md), var(--radius-lg), var(--shadow-lg), var(--transition-fast)

Test Expectations

  • Manual: navigate to https://pal-e-app.tail5b443a.ts.net/boards/board-westside-mcp, click the "Scaffold westside-mcp + draft_tournament_email tool" card, verify drawer opens with full traceability content, verify all label chips resolve to live notes
  • Manual: same flow on Lucas's phone (iOS Safari) — drawer slides in, content scrolls, close works
  • Manual: Create-Item modal opens centered with backdrop on both desktop and mobile
  • Manual: Delete-Item modal opens centered with backdrop on both desktop and mobile
  • No Playwright test required for this PR — visual verification by Lucas is the gate per feedback_frontend_iteration

Constraints

  • No Tailwind. No tailwindcss package, no utility classes anywhere in this PR's diff. Per feedback_no_tailwind. If you spot any other Tailwind classes elsewhere in +page.svelte (e.g. flex, gap-4 on form rows), leave them for a separate ticket but list them in the PR description under "Discovered scope."
  • Pure CSS vars. Use design tokens already in app.css. Do not hardcode hex colors or px values for spacing.
  • Match existing patterns. The .touch-ghost and .mobile-hint classes in the file's <style> block are the reference for drawer styling — position: fixed, var() tokens, CSS transition for slide-in.
  • Accessibility. Drawer has role="dialog", aria-modal="true", aria-label="Card details: {title}". Focus moves to drawer's close button on open and returns to the card on close. Backdrop is a <button> with aria-label="Close drawer".
  • No new dependencies. No Svelte UI library, no animation library, no CSS framework. Native CSS transitions only.
  • Bundled scope is intentional. All three defects share one file. Splitting causes merge churn. PR description should note this explicitly.

Checklist

  • PR opened against main
  • Lucas visually verified on desktop AND mobile (gate per feedback_frontend_iteration — code review alone does not pass this PR)
  • No unrelated changes
  • PR description lists any remaining Tailwind classes elsewhere in the file (discovered scope)
  • pal-e-app — project this affects
  • story-pal-e-app-board-card-traceability — user story driving this work
  • convention-architecture-ids — defines arch: labels the drawer surfaces
  • arch-dataflow-pal-e-app — needs Components-table update for "Board Renderer" (separate follow-up ticket)
  • feedback_no_tailwind, feedback_traceability_triangle, feedback_block_component_model, feedback_frontend_iteration

Discovered scope (separate backlog tickets, not this PR):

  1. Update arch-dataflow-pal-e-app Components table to add "Board Renderer" entry pointing at this drawer pattern.
  2. Create convention-admin-surface-ui codifying the drawer pattern (raw CSS vars, label-as-link, traceability triangle visible) for cross-project reuse.
  3. Apply the drawer pattern to westside-admin admin row surfaces (CRUD pages: players, teams, users, schedule, commerce) — feeds story-westside-admin-admin-row-crud.
### Type Feature ### Lineage Standalone — discovered 2026-05-03 during Lucas review of `board-westside-mcp` UX. Three visual/UX defects on the kanban page bundled into one ticket because they all touch the same Svelte file and splitting would create merge churn for no benefit. ### Repo `forgejo_admin/pal-e-app` ### User Story As a platform owner, I want to see the full traceability triangle (story / arch / spec / PRs) for any board card I click in pal-e-app, so that I can navigate from any ticket to why it exists, what part of the system it touches, and what code came from it — without leaving pal-e-app or hand-grepping Forgejo. Full story note (with success metric and AC): `story-pal-e-app-board-card-traceability` ### Context Today the board page (`src/routes/boards/[slug]/+page.svelte`) renders cards as opaque tokens. - Cards WITH `note_slug` → render as `<a href="/notes/{slug}">`, click navigates to the linked note (works). - Cards WITHOUT `note_slug` → render as `<div>`, click calls `tapItem()` which only sets `selectedItem` for the tap-to-move flow. **There is no detail view.** The `.mobile-hint` div ("Tap a column to move ...") appears, but the card's actual data (labels, type, column, linked Forgejo issue) is invisible to the user. Every board item already carries `story:X` / `arch:X` / `type:X` labels enforced by the `create_board_item` hook. The data is in the database. The UI just doesn't surface it. This ticket closes that gap. Two adjacent defects discovered during the same investigation, bundled because they share the file: 1. **Orphaned Tailwind classes.** Lines 476 and 572 use `class="fixed inset-0 z-50 flex items-center justify-center"` on the Create-Item and Delete-Item modals. Tailwind is NOT installed (`vite.config.ts` has only `sveltekit()`, no PostCSS, no UnoCSS). The classes produce no CSS — modals render as inline block divs in normal page flow with no overlay, no centering, no z-index. 2. **Long-token title overflow.** `.card-title` in `src/app.css:759` has no `overflow-wrap`. Underscored identifiers (e.g. `draft_tournament_email`) are treated as unbreakable tokens and overflow narrow columns. ### File Targets Files to modify: - `src/routes/boards/[slug]/+page.svelte` — add inline drawer markup (or extract to component, see below); change card `onclick` to open drawer instead of `tapItem()`; replace Tailwind utility classes on Create/Delete modal wrappers with raw CSS classes; remove the `tapItem` / `tapColumn` / `selectedItem` state OR migrate it inside the drawer's "Move to Column" section - `src/app.css` — add `overflow-wrap: anywhere` to `.card-title` (line 759); add `.card-drawer`, `.card-drawer-backdrop`, `.card-drawer-section`, `.card-drawer-label-chip`, `.modal-overlay` styles using existing design tokens - (Optional, recommended for reuse) `src/lib/components/BoardCardDetail.svelte` — new component encapsulating the drawer; keeps the page file thin Files NOT to touch: - `src/lib/api-client.ts` — no API changes; backend already returns everything (`labels`, `note_slug`, `forgejo_issue_url`, `item_type`, `column`) - Any other route — scope is the board renderer only ### Acceptance Criteria - [ ] Click any board card → drawer slides in from right (CSS `transform: translateX` transition); does not navigate away from the board page - [ ] Drawer shows: card title (wrapped), `<span class="badge badge--{item_type}">` type badge, current column name, every label as a clickable chip - [ ] Label chip resolution: - `story:X` → `/notes/story-{board's project_slug}-{X}` (e.g. `story-pal-e-app-board-card-traceability`) - `arch:X` → `/notes/arch-{X}` if globally canonical (per `convention-architecture-ids`), else `/notes/arch-dataflow-{project_slug}` as fallback - `type:X` → no link, visual chip only - Other labels (`scope:X`, etc.) → visual chip only - [ ] If `forgejo_issue_url` set → "View Forgejo Issue ↗" link in drawer (opens in new tab) - [ ] If `note_slug` set → "Open Linked Note →" link in drawer (in-app navigation) - [ ] "Move to Column" section in drawer renders one button per column except the current one; clicking calls existing `doMoveItem` and closes the drawer - [ ] Drawer closes on: Escape key, backdrop click, dedicated × close button - [ ] Tap-on-card no longer triggers tap-to-move flow (replaced by drawer's move buttons). HTML5 drag-and-drop (desktop) and long-press touch drag (mobile) still work unchanged - [ ] `.card-title` wraps long unbreakable tokens (verify visually with the existing card "Scaffold westside-mcp + draft_tournament_email tool") - [ ] Create-Item modal renders centered with semi-opaque backdrop (no Tailwind classes) - [ ] Delete-Item modal renders centered with semi-opaque backdrop (no Tailwind classes) - [ ] All new styles use existing CSS vars: `var(--color-surface)`, `var(--color-border)`, `var(--color-text)`, `var(--radius-md)`, `var(--radius-lg)`, `var(--shadow-lg)`, `var(--transition-fast)` ### Test Expectations - [ ] Manual: navigate to `https://pal-e-app.tail5b443a.ts.net/boards/board-westside-mcp`, click the "Scaffold westside-mcp + draft_tournament_email tool" card, verify drawer opens with full traceability content, verify all label chips resolve to live notes - [ ] Manual: same flow on Lucas's phone (iOS Safari) — drawer slides in, content scrolls, close works - [ ] Manual: Create-Item modal opens centered with backdrop on both desktop and mobile - [ ] Manual: Delete-Item modal opens centered with backdrop on both desktop and mobile - [ ] No Playwright test required for this PR — visual verification by Lucas is the gate per `feedback_frontend_iteration` ### Constraints - **No Tailwind.** No `tailwindcss` package, no utility classes anywhere in this PR's diff. Per `feedback_no_tailwind`. If you spot any other Tailwind classes elsewhere in `+page.svelte` (e.g. `flex`, `gap-4` on form rows), leave them for a separate ticket but list them in the PR description under "Discovered scope." - **Pure CSS vars.** Use design tokens already in `app.css`. Do not hardcode hex colors or px values for spacing. - **Match existing patterns.** The `.touch-ghost` and `.mobile-hint` classes in the file's `<style>` block are the reference for drawer styling — `position: fixed`, `var()` tokens, CSS `transition` for slide-in. - **Accessibility.** Drawer has `role="dialog"`, `aria-modal="true"`, `aria-label="Card details: {title}"`. Focus moves to drawer's close button on open and returns to the card on close. Backdrop is a `<button>` with `aria-label="Close drawer"`. - **No new dependencies.** No Svelte UI library, no animation library, no CSS framework. Native CSS transitions only. - **Bundled scope is intentional.** All three defects share one file. Splitting causes merge churn. PR description should note this explicitly. ### Checklist - [ ] PR opened against `main` - [ ] Lucas visually verified on desktop AND mobile (gate per `feedback_frontend_iteration` — code review alone does not pass this PR) - [ ] No unrelated changes - [ ] PR description lists any remaining Tailwind classes elsewhere in the file (discovered scope) ### Related - `pal-e-app` — project this affects - `story-pal-e-app-board-card-traceability` — user story driving this work - `convention-architecture-ids` — defines `arch:` labels the drawer surfaces - `arch-dataflow-pal-e-app` — needs Components-table update for "Board Renderer" (separate follow-up ticket) - `feedback_no_tailwind`, `feedback_traceability_triangle`, `feedback_block_component_model`, `feedback_frontend_iteration` **Discovered scope (separate backlog tickets, not this PR):** 1. Update `arch-dataflow-pal-e-app` Components table to add "Board Renderer" entry pointing at this drawer pattern. 2. Create `convention-admin-surface-ui` codifying the drawer pattern (raw CSS vars, label-as-link, traceability triangle visible) for cross-project reuse. 3. Apply the drawer pattern to `westside-admin` admin row surfaces (CRUD pages: players, teams, users, schedule, commerce) — feeds `story-westside-admin-admin-row-crud`.
Author
Contributor

Scope Review: APPROVED

Review note: review-1133-2026-05-03

All three defects verified to live in src/routes/boards/[slug]/+page.svelte (with .card-title in src/app.css:759). Bundling rationale holds — splitting forces three sequential PRs against the same Svelte file. File targets, line numbers (476, 572, 759, 285), and all cited CSS vars (--color-surface, --color-border, --color-text, --radius-md, --radius-lg, --shadow-lg, --transition-fast) verified present. No Tailwind/PostCSS in vite.config.ts — orphaned-classes claim is correct. No .card-drawer/.modal-overlay collision. Story note story-pal-e-app-board-card-traceability exists with full AC. arch:sveltekit-ssr is canonical per convention-architecture-ids. No blocking dependencies on the board.

13 AC items technically trips the >5 AC decomposition heuristic, but ~10 are sub-aspects of the single drawer feature; remaining 3 are 1-line edits. Estimated agent time within the 5-min rule. No decomposition needed.

One follow-up [SCOPE] recommendation (non-blocking): add a board-card-traceability entry to the project-pal-e-app user-stories section so the story note is reachable from the project page. The story note exists and is linked from this issue, so the dev agent isn't blocked — this is a Dottie/Ava follow-up.

Ticket can move backlog → todo.

## Scope Review: APPROVED Review note: `review-1133-2026-05-03` All three defects verified to live in `src/routes/boards/[slug]/+page.svelte` (with `.card-title` in `src/app.css:759`). Bundling rationale holds — splitting forces three sequential PRs against the same Svelte file. File targets, line numbers (476, 572, 759, 285), and all cited CSS vars (`--color-surface`, `--color-border`, `--color-text`, `--radius-md`, `--radius-lg`, `--shadow-lg`, `--transition-fast`) verified present. No Tailwind/PostCSS in `vite.config.ts` — orphaned-classes claim is correct. No `.card-drawer`/`.modal-overlay` collision. Story note `story-pal-e-app-board-card-traceability` exists with full AC. `arch:sveltekit-ssr` is canonical per `convention-architecture-ids`. No blocking dependencies on the board. 13 AC items technically trips the `>5 AC` decomposition heuristic, but ~10 are sub-aspects of the single drawer feature; remaining 3 are 1-line edits. Estimated agent time within the 5-min rule. No decomposition needed. One follow-up `[SCOPE]` recommendation (non-blocking): add a `board-card-traceability` entry to the `project-pal-e-app` user-stories section so the story note is reachable from the project page. The story note exists and is linked from this issue, so the dev agent isn't blocked — this is a Dottie/Ava follow-up. Ticket can move backlog → todo.
Commenting is not possible because the repository is archived.
No milestone
No project
No assignees
1 participant
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
ldraney/pal-e-app#116
No description provided.