Skip to content

UI-05: Board card and board-surface polish pass#501

Merged
Chris0Jeky merged 8 commits intomainfrom
ui/board-card-surface-polish
Mar 29, 2026
Merged

UI-05: Board card and board-surface polish pass#501
Chris0Jeky merged 8 commits intomainfrom
ui/board-card-surface-polish

Conversation

@Chris0Jeky
Copy link
Copy Markdown
Owner

Summary

  • Standardize all board card visual states (hover, focus, selected, dragging) using CSS custom properties from the design token system (--td-* variables)
  • Normalize typography hierarchy across card title, description, labels, badges, and due date metadata using the token font scale
  • Replace hardcoded inline Tailwind utility classes in ColumnLane, BoardCanvas, BoardToolbar, BoardActionRail, and BoardView with scoped token-based CSS
  • Add consistent focus-visible rings for keyboard navigation accessibility on all interactive elements

What changed

Component Change
CardItem.vue Token-based card states (hover/focus/selected/drag), typography hierarchy, ember indicator, label chips
ColumnLane.vue Token-based column header, card count badge, WIP warning, add-card button, card form
BoardCanvas.vue Token-based canvas spacing and empty state
BoardToolbar.vue Token-based toolbar buttons, presence badges, board title, filter count
BoardActionRail.vue Token-based action rail layout, buttons, hint text
BoardView.vue Token-based create column form

What did NOT change

  • No board logic, drag-drop behavior, keyboard shortcuts, or data flow was modified
  • No component APIs (props/emits) were changed
  • All existing tests pass (1039/1039)

Test plan

  • npm run build passes (typecheck + vite build)
  • npx vitest --run passes (115 test files, 1039 tests)
  • Visual inspection: card hover shows ember indicator + elevated shadow
  • Visual inspection: card focus-visible shows ember focus ring
  • Visual inspection: selected card shows ember border + dim background
  • Visual inspection: dragging card shows reduced opacity + scale
  • Keyboard navigation: j/k/h/l moves selection with visible focus
  • Light theme: verify token overrides render correctly

Closes #247

Replace hardcoded shadows, borders, and colors in CardItem with
token-based CSS custom properties. Add clear visual distinction for
hover, focus, selected, disabled, and dragging states. Normalize
badge, label, and metadata typography hierarchy using the font scale.
Replace inline Tailwind classes in ColumnLane with scoped CSS using
design tokens for spacing, borders, typography, and interactive states.
Adds consistent focus-visible rings and token-based card count badges.
Replace hardcoded gap/padding values in BoardCanvas with CSS custom
property references from the design token scale.
Replace inline Tailwind utility classes in BoardToolbar with scoped
token-based CSS. Adds consistent focus-visible states and normalizes
button sizing, typography, and presence badge styling.
Replace inline Tailwind classes in BoardActionRail with scoped CSS
using design tokens for spacing, borders, and typography.
Replace inline Tailwind classes in the column creation form with
scoped CSS using design tokens for consistent input and button styles.
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Self-review finding: the filter count indicator used a hardcoded 10px
instead of var(--td-font-xs) from the design token scale.
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Adversarial Self-Review

Reviewed the full diff critically. Findings:

Fixed

  • Hardcoded font-size: 10px in filter count badge (BoardToolbar) -- replaced with var(--td-font-xs). Fixed in commit 3320cef.

Accepted trade-offs

  • color: white in label chips (CardItem td-board-card__label) -- intentional. Labels use arbitrary user-defined background colors; a token like --td-text-inverse would be wrong since the surface isn't from the token palette. White is the correct accessible contrast choice.
  • 1px padding on pill badges -- sub-token value for tight badge padding. The spacing scale starts at --td-space-1: 0.2rem (3.2px), which is too large for a pill's vertical padding. Acceptable.
  • Selected card ring uses hardcoded rgba (0 0 0 2px rgba(255, 83, 82, 0.2)) -- there is no dedicated selection ring token in the design system. The value matches the ember palette. Could be extracted to a token in a future design-tokens pass if needed.
  • WIP warning lost the emoji prefix -- the old text was "warning-emoji WIP limit exceeded". Removed to keep text content clean and consistent with other warning patterns in the codebase. The count badge already turns red as the visual signal.

Behavior preservation check

  • No props/emits changed on any component
  • No logic, drag-drop, keyboard shortcuts, or data flow modified
  • tabindex="0" and aria-selected added to CardItem for keyboard accessibility (additive, non-breaking)
  • aria-label="Back to boards" added to toolbar back button (additive)
  • All 1039 tests pass

@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Adversarial Code Review — PR #501

I read every line of the diff and every changed file in full, cross-referenced all token references against design-tokens.css, and checked accessibility, drag-drop, state coverage, and specificity. Here are my findings.


Bug: Missing combined selected + focus-visible state on CardItem

File: CardItem.vue, scoped CSS (lines 153-156 and 159-163)

.td-board-card:focus-visible has specificity (0,1,1) and .td-board-card--selected has specificity (0,1,0). When a card is both selected AND focused (the normal case during keyboard navigation with j/k/h/l), the :focus-visible box-shadow overwrites the selected box-shadow entirely. The user loses the ember border + dim background visual cues for selection.

Fix needed: Add a .td-board-card--selected:focus-visible rule that combines both states:

.td-board-card--selected:focus-visible {
  outline: none;
  box-shadow: var(--td-focus-ring), 0 0 0 4px rgba(255, 83, 82, 0.15);
  border-color: var(--td-border-ember);
  background: var(--td-color-ember-dim);
}

Inconsistency: Drag handle button not tokenized in CardItem

File: CardItem.vue:78

The drag handle button uses a td-card-drag-handle class (referenced in CardItem.spec.ts:32) but no corresponding scoped CSS rule exists. The button still relies entirely on Tailwind utilities (text-on-surface/60, hover:bg-surface-bright, etc.) while everything else in the card was migrated. The class name also doesn't follow the BEM convention used everywhere else — should be td-board-card__drag-handle.

This isn't a regression (the Tailwind classes still work), but it's a notable gap in the stated goal of "replacing hardcoded inline Tailwind utility classes."


Inconsistency: Column DnD wrapper not tokenized in BoardCanvas

File: BoardCanvas.vue:36-40

The column drag-and-drop wrapper still uses raw Tailwind utilities (transition-all, opacity-50, transform scale-105) for drag states. Every other element in the file was migrated to token-based CSS. These drag states are exactly the kind of visual polish this PR targets.


Behavior change: WIP warning lost emoji indicator

File: ColumnLane.vue:207-209

The old WIP warning was ⚠️ WIP limit exceeded and is now just WIP limit exceeded. The warning emoji served as a quick visual signal. Since the new CSS only colors the text red (--td-color-error), it's now just plain red text without the icon. This may be intentional, but worth confirming since the PR says "no behavior changes."


Token verification: All clear

Every var(--td-*) reference in the diff was verified against design-tokens.css. All 41 unique tokens exist in both dark (:root) and light ([data-theme="light"]) themes.


Accessibility: Mostly improved

  • Good: tabindex="0" and aria-selected added to CardItem (new)
  • Good: aria-label="Back to boards" added to back button (new)
  • Good: aria-hidden="true" on ember indicator (new)
  • Good: Consistent focus-visible rings on all interactive elements
  • Issue: The selected + focus-visible conflict described above effectively hides the selection state during keyboard navigation

Drag-drop: No interference

  • transform and opacity transitions are present on .td-board-card--dragging but only applied when isDragging is true
  • pointer-events is not affected anywhere
  • Column drag states in BoardCanvas still work via Tailwind (see inconsistency above)

Summary

Category Status
Token existence All 41 tokens verified
Functional bugs 1 — selected+focus box-shadow conflict
Inconsistencies 2 — drag handle + column DnD wrapper not tokenized
Behavior changes 1 — WIP emoji removed, 1 — selected card no longer scales 105%
Accessibility Net positive, but selected+focus conflict undermines keyboard nav
Drag-drop No interference
Test gaps Existing tests pass; no class-name dependencies broken

The selected+focus-visible conflict is the only item I'd call a blocking issue — it undermines the keyboard navigation experience that this PR explicitly added tabindex and aria-selected for.

When a card is both selected and focused (the normal case during
keyboard navigation), the :focus-visible box-shadow was overriding
the selected state due to higher CSS specificity. Add an explicit
.td-board-card--selected:focus-visible rule that preserves both
the ember selection indicators and the focus ring.
@Chris0Jeky Chris0Jeky merged commit e15c206 into main Mar 29, 2026
18 checks passed
@Chris0Jeky Chris0Jeky deleted the ui/board-card-surface-polish branch March 29, 2026 03:46
@github-project-automation github-project-automation bot moved this from Pending to Done in Taskdeck Execution Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

UI-05: Board card and board-surface polish pass (density, typography, state consistency)

1 participant