From 14c4e820700ada54652df650eb70a1e60c35551b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 15 Feb 2026 20:51:53 +0200 Subject: [PATCH] docs: add motion, dark mode & custom titlebar design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design document covering three visual improvements: - Playful bouncy Framer Motion animations for every interaction - Subtle dark mode lift for HDR monitors (18-22% → 25-30% lightness) - Custom window titlebar merged into TopBar with accent-colored controls --- ...6-02-15-motion-darkmode-titlebar-design.md | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/plans/2026-02-15-motion-darkmode-titlebar-design.md diff --git a/docs/plans/2026-02-15-motion-darkmode-titlebar-design.md b/docs/plans/2026-02-15-motion-darkmode-titlebar-design.md new file mode 100644 index 0000000..064b0f1 --- /dev/null +++ b/docs/plans/2026-02-15-motion-darkmode-titlebar-design.md @@ -0,0 +1,188 @@ +# Motion, Dark Mode & Custom Titlebar Design + +**Date:** 2026-02-15 +**Goal:** Add playful bouncy animations everywhere, lighten dark mode for HDR monitors, and implement custom window decorations merged into the TopBar +**Approach:** Centralized motion system + CSS variable tuning + Tauri decoration override + +--- + +## 1. Motion System Foundation + +Create `src/lib/motion.ts` — shared animation config imported by all components. + +### Spring Presets (Bouncy Profile) +- **bouncy** — stiffness: 400, damping: 15, mass: 0.8 (main preset, visible overshoot) +- **snappy** — stiffness: 500, damping: 20 (micro-interactions — buttons, toggles) +- **gentle** — stiffness: 200, damping: 20 (larger elements — modals, page transitions) +- **wobbly** — stiffness: 300, damping: 10 (playful emphasis — toasts, notifications) + +### Reusable Variants +- `fadeSlideUp` — enters from below with opacity fade (cards, list items) +- `fadeSlideDown` — enters from above (dropdowns, menus) +- `scaleIn` — scales from 0.9 to 1 with bounce (modals, popovers) +- `staggerContainer` — parent variant that staggers children + +### Stagger Helper +`staggerChildren(delay = 0.04)` — generates parent transition variants for cascading entrances. + +--- + +## 2. Component-by-Component Motion Rollout + +### Page Transitions (App.tsx) +- Wrap view switch in `AnimatePresence mode="wait"` +- Board-list exits with fade+slide-left, board enters with fade+slide-right +- Uses `gentle` spring + +### Board List (BoardList.tsx) +- Board cards stagger in on mount using `staggerContainer` +- Each BoardCard uses `fadeSlideUp` entrance +- Empty state fades in + +### Board View (BoardView.tsx) +- Columns stagger in from left to right on mount (0.06s delay each) +- Cards within each column stagger in (0.03s delay) + +### Card Thumbnails (CardThumbnail.tsx) +- Migrate existing spring to shared `bouncy` preset +- `whileHover` scale 1.02 with shadow elevation +- `whileTap` scale 0.98 + +### Card Detail Modal (CardDetailModal.tsx) +- **Shared layout animation** — CardThumbnail gets `layoutId={card-${card.id}}`, modal wrapper gets same layoutId +- Card morphs into the modal on open — hero transition +- Backdrop blurs in with animated opacity + backdropFilter +- Modal content sections stagger in after layout animation + +### Column Header (ColumnHeader.tsx) +- Dropdown menu items stagger in with `fadeSlideDown` + +### TopBar +- Buttons have `whileHover` and `whileTap` micro-animations +- Saving status text fades in/out with AnimatePresence + +### Toast Notifications (ToastContainer.tsx) +- Migrate to `wobbly` spring for extra personality +- Exit slides down + fades + +### Settings Dialog +- Tab content crossfades with AnimatePresence +- Accent color swatches have `whileHover` scale pulse + +### Command Palette +- Results stagger in as you type + +--- + +## 3. Gesture-Reactive Drag & Drop + +Override dnd-kit's default drag overlay with Framer Motion-powered custom overlay. + +- **On drag start:** Card lifts with `scale: 1.05`, box-shadow, slight rotate based on grab offset +- **During drag:** Card tilts based on pointer velocity (useMotionValue + useTransform). Max tilt: ~5 degrees +- **On drop:** Spring back to `scale: 1, rotate: 0`. Target column cards spring apart using `layout` prop +- dnd-kit handles position/sorting logic; we layer gesture transforms on top + +--- + +## 4. Dark Mode — Subtle Lift for HDR + +### Pylon Dark Variables (in `.dark {}`) + +| Variable | Current | New | +|----------|---------|-----| +| `--pylon-bg` | `oklch(18% 0.01 50)` | `oklch(25% 0.012 50)` | +| `--pylon-surface` | `oklch(22% 0.01 50)` | `oklch(29% 0.012 50)` | +| `--pylon-column` | `oklch(20% 0.012 50)` | `oklch(27% 0.014 50)` | +| `--pylon-text` | `oklch(90% 0.01 50)` | `oklch(92% 0.01 50)` | +| `--pylon-text-secondary` | `oklch(55% 0.01 50)` | `oklch(58% 0.01 50)` | +| `--pylon-accent` | `oklch(60% 0.12 160)` | `oklch(62% 0.13 160)` | +| `--pylon-danger` | `oklch(60% 0.18 25)` | `oklch(62% 0.18 25)` | + +### Shadcn Dark Variables + +| Variable | Current | New | +|----------|---------|-----| +| `--background` | `oklch(0.145 0 0)` | `oklch(0.22 0 0)` | +| `--card`, `--popover` | `oklch(0.205 0 0)` | `oklch(0.27 0 0)` | +| `--secondary`, `--muted`, `--accent` | `oklch(0.269 0 0)` | `oklch(0.32 0 0)` | +| `--border` | `oklch(1 0 0 / 10%)` | `oklch(1 0 0 / 12%)` | +| `--input` | `oklch(1 0 0 / 15%)` | `oklch(1 0 0 / 18%)` | +| `--sidebar` | `oklch(0.205 0 0)` | `oklch(0.27 0 0)` | +| `--sidebar-accent` | `oklch(0.269 0 0)` | `oklch(0.32 0 0)` | + +Color scheme (hue 50 warmth) preserved. Slight chroma bump for HDR vibrancy. + +--- + +## 5. Custom Window Titlebar + +### Tauri Configuration +Set `"decorations": false` in `tauri.conf.json` to remove native OS titlebar. + +### TopBar Integration +Window controls added to far right of existing TopBar, after a thin vertical separator: + +``` +[Back] .......... [Board Title] .......... [Undo][Redo][Settings][Save][Search][Gear] | [—][□][×] +``` + +### WindowControls Component +Inline in TopBar or extracted to `src/components/layout/WindowControls.tsx`. + +**Buttons:** +- Minimize: `Minus` icon from Lucide → `getCurrentWindow().minimize()` +- Maximize/Restore: `Square` / `Copy` icon → `getCurrentWindow().toggleMaximize()` +- Close: `X` icon → `getCurrentWindow().close()` + +**Styling:** +- 32x32px hit area, 16x16px icons +- Default: `text-pylon-text-secondary` +- Hover: Background with accent at 10% opacity +- Close hover: `pylon-danger` at 15% opacity (red highlight — convention) +- All have Framer Motion `whileHover` and `whileTap` springs + +**State tracking:** +- Listen to `getCurrentWindow().onResized()` for maximize state +- Query `isMaximized()` on mount for initial icon +- `data-tauri-drag-region` stays on header; window buttons do NOT propagate drag + +--- + +## Files Affected + +### New Files +- `src/lib/motion.ts` — shared spring presets, variants, helpers + +### Modified Files +- `src/App.tsx` — AnimatePresence page transitions +- `src/index.css` — dark mode color value updates +- `src/components/layout/TopBar.tsx` — window controls, motion on buttons +- `src/components/layout/AppShell.tsx` — support page transition wrapper +- `src/components/boards/BoardList.tsx` — stagger animation on board cards +- `src/components/boards/BoardCard.tsx` — fadeSlideUp entrance, hover/tap +- `src/components/board/BoardView.tsx` — column stagger, gesture-reactive drag overlay +- `src/components/board/KanbanColumn.tsx` — card stagger, layout animation for reorder +- `src/components/board/CardThumbnail.tsx` — shared layoutId, bouncy preset, hover/tap +- `src/components/board/ColumnHeader.tsx` — dropdown animation +- `src/components/card-detail/CardDetailModal.tsx` — shared layout animation (hero), content stagger +- `src/components/toast/ToastContainer.tsx` — wobbly spring +- `src/components/settings/SettingsDialog.tsx` — tab crossfade, swatch hover +- `src/components/command-palette/CommandPalette.tsx` — result stagger +- `src/components/shortcuts/ShortcutHelpModal.tsx` — entrance animation +- `src-tauri/tauri.conf.json` — decorations: false + +## Implementation Order + +1. Motion system foundation (`src/lib/motion.ts`) +2. Dark mode CSS variable updates +3. Custom titlebar (Tauri config + WindowControls) +4. Page transitions (App.tsx + AnimatePresence) +5. Board list animations (stagger + BoardCard) +6. Board view column stagger + card stagger +7. Card thumbnail hover/tap + shared layoutId +8. Card detail modal shared layout animation +9. Gesture-reactive drag overlay +10. Micro-interactions (TopBar, ColumnHeader dropdowns) +11. Toast, Settings, Command Palette, ShortcutHelp animations +12. Polish pass — verify all springs feel cohesive, test reduced-motion