diff --git a/docs/plans/2026-02-16-15-improvements-design.md b/docs/plans/2026-02-16-15-improvements-design.md new file mode 100644 index 0000000..92b20e1 --- /dev/null +++ b/docs/plans/2026-02-16-15-improvements-design.md @@ -0,0 +1,296 @@ +# OpenPylon: 15 Improvements Design + +## Overview + +15 improvements to OpenPylon organized into 5 phases (0-4), designed for incremental delivery. Each phase builds on the previous. You can ship after any phase and have a coherent improvement. + +## Decisions + +- **Phasing**: 4 phases (quick wins first, progressively bigger features) +- **Data compatibility**: New fields use Zod `.default()` values. No migration code. Old boards load cleanly. +- **Templates storage**: JSON files in `data/templates/` +- **Backup storage**: Timestamped files in `data/backups/{boardId}/`, keep last 10 + +--- + +## Phase 0: Data Model Foundation + +All type/schema changes that later features depend on. Done first so everything builds on a stable base. + +### Card type additions + +```typescript +// Added to Card interface + cardSchema +priority: "none" | "low" | "medium" | "high" | "urgent"; // default: "none" +comments: Comment[]; // default: [] + +// New type + schema +interface Comment { + id: string; + text: string; + createdAt: string; +} +``` + +### Column type additions + +```typescript +// Added to Column interface + columnSchema +collapsed: boolean; // default: false +wipLimit: number | null; // default: null +``` + +### Files touched + +- `src/types/board.ts` — Add fields to Card, Column interfaces. Add Comment interface. +- `src/lib/schemas.ts` — Add Zod fields with defaults to cardSchema, columnSchema. Add commentSchema. + +--- + +## Phase 1: Quick Wins + +Minimal changes, high value. ~4 files each. + +### #8 — Consume defaultColumnWidth Setting + +In `board-store.ts`, `addColumn` reads `useAppStore.getState().settings.defaultColumnWidth` instead of hardcoding `"standard"`. + +**Files**: `src/stores/board-store.ts` (1 line change) + +### #4 — Due Date Visual Indicators + +Replace binary overdue/not logic in `CardThumbnail` with 4-tier color system: + +| Status | Condition | Color | +|--------|-----------|-------| +| Overdue | past + not today | `pylon-danger` (red) | +| Approaching | due within 2 days | amber `oklch(65% 0.15 70)` | +| Comfortable | due but >2 days | green `oklch(55% 0.12 145)` | +| No date | null | `pylon-text-secondary` (gray) | + +Helper function `getDueDateStatus(dueDate: string | null)` returns `{ color, label }`. + +**Files**: `src/components/board/CardThumbnail.tsx` + +### #9 — Card Aging Visualization + +Compute days since `card.updatedAt`. Apply opacity: + +| Days stale | Opacity | +|------------|---------| +| 0-7 | 1.0 | +| 7-14 | 0.85 | +| 14-30 | 0.7 | +| 30+ | 0.55 | + +Applied as inline `opacity` on the card `motion.button`. + +**Files**: `src/components/board/CardThumbnail.tsx` + +### #12 — Open Attachments + +Add "Open" button to each attachment in `AttachmentSection`. Uses `open()` from `@tauri-apps/plugin-opener` (already registered). + +**Files**: `src/components/card-detail/AttachmentSection.tsx` + +--- + +## Phase 2: Card Interactions & UI Enhancements + +5 features that transform how cards feel to use. + +### #2 — Card Priority Levels + +**Thumbnail indicator**: Colored dot in footer row. Color map: +- `none`: hidden +- `low`: blue +- `medium`: yellow +- `high`: orange +- `urgent`: red with pulse animation + +**Detail modal**: Priority picker section in left column (like LabelPicker). Row of 5 clickable chips with colors. + +**Files**: `CardThumbnail.tsx`, `CardDetailModal.tsx` (new PriorityPicker component inline or separate), `board-store.ts` (no new action needed — `updateCard` handles it) + +### #5 — Card Context Menu + +Wrap `CardThumbnail` in Radix `ContextMenu`. + +**Menu items**: +- Move to → (submenu listing columns except current) +- Set priority → (submenu with 5 options) +- Duplicate (new card with same fields, `(copy)` suffix, new ID, inserted below original) +- Separator +- Delete (confirmation dialog) + +**New store action**: `duplicateCard(cardId): string` — clones card, inserts after original in same column. + +**Files**: `CardThumbnail.tsx`, `board-store.ts` + +### #10 — WIP Limits + +**Column header display**: Shows `3/5` when wipLimit set. Background tint: +- Under limit: normal +- At limit: amber tint `oklch(75% 0.08 70 / 15%)` +- Over limit: red tint `oklch(70% 0.08 25 / 15%)` + +**Setting UI**: New "Set WIP Limit" item in ColumnHeader dropdown menu. Preset choices: None / 3 / 5 / 7 / 10 / Custom. + +**New store action**: `setColumnWipLimit(columnId: string, limit: number | null)` + +**Files**: `ColumnHeader.tsx`, `KanbanColumn.tsx`, `board-store.ts` + +### #3 — Column Collapse/Expand + +When `collapsed`, render a 40px-wide strip instead of full column: +- Vertical text via `writing-mode: vertical-rl; rotate: 180deg` +- Card count badge +- Click to expand + +Animate width from full to 40px using existing `animate={{ width }}` on outer `motion.div` with `springs.bouncy`. + +**New store action**: `toggleColumnCollapse(columnId: string)` + +**Collapse button**: Added to ColumnHeader dropdown menu + a small chevron icon on the collapsed strip. + +**Files**: `KanbanColumn.tsx`, `ColumnHeader.tsx`, `board-store.ts` + +### #11 — Checklist Item Reordering + +Wrap checklist `