12 KiB
Raw Permalink Blame History

SLICE 14a — Compact move menu for editable Kanban cards

State-saving rule: update this file after every completed task and whenever work pauses. Keep implementation, automated validation, production packaging, and manual Joplin acceptance as separate status boundaries.

Status

COMPLETE. Phases 15 are complete. Focused and full automation passed, a fresh production JPL was built and inspected, and the user confirmed manual Joplin acceptance on 2026-07-31.

Goal

Reduce visual noise on editable Kanban cards by removing the permanently visible Move to… select. Keep the existing pointer-drag handle and place a compact disclosure arrow directly beneath it. Activating the arrow opens a temporary menu containing the available destination columns.

The menu remains closed by default. All Slice 14 persistence, validation, canonical refresh, error handling, focus restoration, and accessibility behavior remains authoritative.

Confirmed product contract

  • Remove the always-visible Move to… select from every editable card.
  • Keep the existing drag handle at the upper-right of each editable card.
  • Add a compact disclosure arrow directly beneath the drag handle.
  • Activating the arrow opens a temporary dropdown/menu below the arrow.
  • The menu lists the three fixed Kanban destinations: Backlog, In Progress, and Done.
  • The card's current column is unavailable and cannot submit a move.
  • The menu is closed by default and closes after selection or cancellation.
  • Pointer drag remains available and unchanged.
  • Keyboard movement remains fully available; the disclosure and menu must be operable without a pointer.
  • Use the existing constrained moveKanbanCard intent and main-process mutation pathway. This slice must not introduce new write capabilities.
  • Preserve pending/error feedback, canonical refresh, stale-response rejection, focus restoration, and live announcements.
  • Read-only boards continue to expose no drag or move controls.
  • Matrix, calendar, and Gantt rendering remain unchanged.

Interaction model

Closed state

Each editable card shows a compact two-control stack in its upper-right corner:

┌───────────────┐
│ Card title  ↕ │  pointer drag handle
│             ▾ │  move-menu disclosure
└───────────────┘

The disclosure arrow has an accessible name such as Move “Card title” to…. It is a real keyboard-focusable button. The pointer-only drag handle remains out of the tab order as established by Slice 14.

Open state

Activating the disclosure displays a menu immediately beneath it:

              ▾
        ┌─────────────┐
        │ Backlog     │
        │ In Progress │
        │ Done        │
        └─────────────┘
  • The current destination is disabled or omitted consistently; disabling it is preferred so all menus retain the same predictable destination order.
  • Arrow keys move among enabled menu items.
  • Enter or Space selects an item.
  • Escape closes the menu and returns focus to the disclosure.
  • Clicking outside closes the menu without submitting.
  • Selecting a destination closes the menu, submits one move, and enters the existing pending state.
  • Only one move menu should be open within a rendered view at a time.

Accessibility and focus contract

  • The disclosure communicates expanded/collapsed state with aria-expanded and identifies its menu with aria-controls.
  • Use appropriate button/menu semantics and accessible destination names.
  • Opening moves focus predictably to the first enabled destination, or another documented deterministic item.
  • Closing without selection restores focus to the disclosure.
  • After a successful or rejected canonical refresh, restore focus to the moved card's disclosure when the card remains visible.
  • If sorting or pagination removes the card from the current batch, retain Slice 14's status-region focus fallback.
  • Pending, success, stale, and failure announcements continue through the existing live region.
  • Read-only cards gain no new focus stops.

Layout and styling constraints

  • The closed control stack must occupy only the narrow upper-right card area and must not reserve a full row beneath every card title.
  • Card titles and detail text should regain the vertical space previously used by the visible select.
  • The open menu may overlay nearby content and must not resize every card or Kanban column.
  • The menu must remain legible with custom card foreground/background colours and Joplin light/dark themes.
  • Preserve card borders, hover detail, completed styling, glyphs, recurrence marks, pagination, and column sizing.
  • Avoid clipping the menu inside card, column, or notebook-view containers.

Implementation plan

Phase 1 — Menu markup and state

  • Remove the always-visible .gtd-kanban-move-select control.
  • Add an editable-only disclosure button beneath the drag handle.
  • Render a closed-by-default destination menu with fixed destinations.
  • Disable the current destination.
  • Ensure only one menu per rendered view is open at a time.
  • Close on selection, Escape, outside click, rerender, and cancellation.

Phase 1 completion record

  • Replaced the permanent select with an editable-only disclosure button beneath the unchanged pointer drag handle. Its fixed Backlog, In Progress, and Done menu is hidden by default and disables the card's current destination.
  • Per-view openMoveMenu state closes an older menu before opening another. Selection, Escape, outside pointer action, pending submission, and canonical rerender all remove the open state and document-level listener.

Phase 2 — Keyboard, focus, and announcements

  • Add aria-expanded, aria-controls, accessible names, and menu semantics.
  • Implement deterministic arrow-key navigation and Enter/Space selection.
  • Restore focus to the disclosure after cancellation.
  • Restore focus to the moved card's disclosure after canonical refresh.
  • Preserve status fallback when the moved card is no longer visible.
  • Preserve Slice 14 live announcements and pending-state behavior.

Phase 2 completion record

  • The disclosure is a named button with aria-expanded, aria-controls, and aria-haspopup. The popup and destination buttons use menu/menuitem semantics.
  • Arrow Down opens and focuses the first enabled item. Arrow Up/Down, Home/End, native Enter/Space activation, Escape restoration, outside dismissal, and Tab closure are implemented deterministically.
  • Canonical refresh now restores focus to the disclosure rather than the removed select. Slice 14's status fallback, live regions, duplicate guard, and pending control disabling remain shared and unchanged.

Phase 3 — Styling and regression

  • Stack the disclosure beneath the drag handle without restoring a full-width control row.
  • Position the open menu beneath the disclosure without resizing cards.
  • Verify theme compatibility, custom colours, long titles, completed cards, hover details, grouped boards, scrolling, and paginated columns.
  • Confirm pointer drag and normal card click/open behavior do not regress.
  • Confirm read-only Kanban, matrix, calendar, and Gantt DOM remain unchanged.

Phase 3 completion record

  • Added a narrow absolute-positioned control stack and overlay menu. The compact arrow consumes no full-width content row; the menu uses Joplin theme colours, overlays neighboring content, and leaves card/column widths unchanged.
  • Styling remains scoped to editable Kanban control classes. Shared card title, detail, completion, click, pointer drag, grouping, scrolling, pagination, read-only, matrix, calendar, and Gantt paths were not structurally changed.

Phase 4 — Documentation, automation, and packaging

  • Update README.md keyboard-control wording and any screenshots/examples that imply the select is permanently visible.
  • Update SPEC.md interaction and accessibility details.
  • Add the Slice 14a UI refinement to the unreleased CHANGELOG entry.
  • Run focused protocol/mutation/handler and practical rendering-contract checks.
  • Run the complete Jest suite, TypeScript, webview syntax, whitespace, and prohibited-reference audits.
  • Build and inspect a fresh production JPL without publishing or versioning.

Phase 4 completion record

  • README, SPEC, and the unreleased 2.0.0 CHANGELOG entry now describe the compact disclosure and closed-by-default keyboard menu. No screenshot in the repository depicted the removed select.
  • Added a practical source/CSS rendering-contract suite covering removal of the permanent select, disclosure/menu semantics, fixed destinations, current-state disabling, keyboard/outside dismissal markers, and overlay styling.
  • Focused validation passed: 4 suites, 46 tests. Full validation passed: 20 suites, 298 tests. TypeScript with --skipLibCheck, webview syntax, git diff --check, stale-select wording, and packaged-output prohibited-path/ planning-reference audits passed.
  • npm run dist produced and the archive inspection verified publish/com.victorwiebe.joplin.plugin.gtd-calendar.jpl (180,736 bytes, embedded manifest version 1.0.0, SHA-256 80ec9c230ab2dad2a3fb11cb0c0390403a84e6655d31e10af58ba7a665305318). The five expected files and compiled disclosure/menu/accessibility markers are present. Nothing was versioned, published, pushed, or committed.
  • No manual Joplin acceptance was performed; every Phase 5 item remains open.

Phase 5 — Manual Joplin acceptance

  • Editable cards no longer show an always-visible Move to… select.
  • Every editable card shows the drag handle with a disclosure arrow directly beneath it.
  • The menu is closed by default and opening one does not resize all cards.
  • Pointer activation opens the correct card's menu beneath the disclosure.
  • Keyboard activation, arrow navigation, Enter/Space selection, and Escape cancellation work.
  • The current destination is unavailable and cannot submit.
  • Outside click closes the menu without writing.
  • Only one menu is open per rendered view.
  • Selecting every valid destination persists the same exact note/to-do state accepted in Slice 14.
  • Focus returns to the disclosure after cancellation and canonical refresh; the status fallback works when sorting/pagination hides the card.
  • Pending/error states, live announcements, and duplicate-request prevention remain correct.
  • Pointer drag, click-to-open, hover details, pagination, grouped boards, multiple blocks, long scrolling, custom colours, and completed styling do not regress.
  • Read-only Kanban boards expose neither control; matrix, calendar, and Gantt remain unchanged.
  • Record explicit user sign-off separately from automation.

Phase 5 acceptance record

  • PASSED — USER SIGN-OFF RECEIVED 2026-07-31. After testing the inspected Slice 14a JPL, the user reported the compact move-menu result was perfect and asked that Slice 14a be marked complete and pushed.
  • This manual acceptance is recorded separately from Phase 4 automation and packaging. Slice 15 has not begun.

Out of scope

  • Changing Slice 14 transition semantics or persistence rules.
  • Adding destinations, arbitrary tag editing, or free-form ordering.
  • Moving cards between notebook groups or blocks.
  • Matrix or Skeleton editing.
  • Changing card content, dates, note type, or notebook ownership.
  • Replacing pointer drag with the menu.
  • Publishing or bumping the plugin version.

Acceptance criteria

  • Editable cards are visually quieter because the full-width move select is absent while the move menu remains discoverable beneath the drag handle.
  • Pointer and keyboard users can reach every valid destination through compact, accessible controls.
  • Slice 14's mutation safety, canonical refresh, errors, announcements, focus, sorting, pagination, grouping, and read-only defaults do not regress.
  • Automated validation, production packaging, and explicit manual Joplin acceptance are completed and recorded separately.