diff --git a/docs/PLAN.md b/docs/PLAN.md index e1ca6a2..6ae77b5 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -289,6 +289,7 @@ Units, each through the review gate: | L3 | layout | Dock | The center pane tree, controlled: `DockState` = `Pane { tabs, active }` or `Split { axis, ratio, a, b }`; panels are registered descriptors (`id` + view builder); add / close / activate are plain state ops; a pane emptied by closing its last tab collapses its split. Pane headers show titles, the active tab's close button, and a context menu (via core `ContextMenu`). | | L4 | layout | Dock drag-to-split | Dragging a tab: drop on a pane's edge splits a new pane there; drop on a pane's center moves the tab into that pane; a pane emptied by the move collapses. Edge drop zones paint from theme tokens while a drag is live. Split/merge go through the same `DockState` ops L3 exposed — the drag is interaction, not a second API. | | L2.5 | layout | window frame ✅ Landed (2026-11-01) | `window_frame::frame(child, window, cx)` — the client-side window frame for windows the OS does not decorate: under `Decorations::Server` (macOS, Windows, KDE, X11) it passes the child through untouched; under `Decorations::Client` (Wayland/GNOME) it insets the content, draws the hairline border and `Radius::overlay` corners (tiled sides stay square and lose their band), casts the dialog elevation's shadow dimmed to 0.7× when the window is inactive, and turns a 4 px band inside each live edge into resize hits (`start_window_resize`, edge cursors; a maximized window counts as flush everywhere). Requires a transparent window background, and must be the window's root — the bands hit-test against `Window::window_bounds`. **The `Shell` applies it by default**, so the module ships ungated — no separate feature. Adapted from bezel's `window::frame` + gpui-kit's `WindowBorder` (D15/D20), simplified to one inset band and theme-owned tokens | +| L4.5 | layout | Titlebar + window controls | The strips across the shell's top become the window's titlebar: they drag the window (`WindowControlArea::Drag` on the strip) and host the controls where the platform puts them. A `WindowControls` element — minimize, maximize/restore, close, capability-gated by `Window::window_controls()` — renders per platform: **macOS** draws nothing where the system traffic lights sit (they are system-drawn; `TitlebarOptions.appears_transparent` + `traffic_light_position` is app window config), and the shell reserves the pad in the left sidebar's header leading edge — or across the center's strip when the left sidebar is hidden; **Windows** draws native-glyph buttons (`ChromeMinimize`/`ChromeMaximize`/`ChromeClose`, Segoe E921/E922/E8BB verified against the MDL2 table) marked `WindowControlArea::Min/Max/Close` so Windows handles the clicks and snap layouts natively, maximize flipping to Restore via `is_maximized`; **Linux** draws the same ops as click handlers (`minimize_window` / `zoom_window` / `remove_window`) in the platform's own dress — Adwaita's small gray circle wrappers around symbolic glyphs, resolved through the freedesktop cascade with the bundled fallback (`Close` already leads with `window-close-symbolic`; new `WindowMinimize`/`WindowMaximize` roles land in the icons crate). Placement follows the shell's shape: Windows/Linux put the controls at the trailing end of the right-hand strip — the right sidebar's strip when visible, else the center region's titlebar strip, which becomes the dock's tab bar in L3 (in signed the tab bar doubles as the titlebar, 44 px, with 34 px-wide controls and a danger hover on close). Reference: signed's `crates/dock/src/window_controls.rs` | | L5 | layout | Sidebar auto-open | Panels declare `needs_right_sidebar` on their descriptor; activating such a panel opens the right sidebar; closing it leaves visibility to the user. The gallery gains a workspace-style shell page — the bootstrap example apps copy. | Deferred until a real need: layout persistence/serialization, pane zoom (maximize one pane), a bottom dock, collapse-to-edge docks, floating windows, drag between windows. @@ -305,7 +306,7 @@ Deferred until a real need: layout persistence/serialization, pane zoom (maximiz | E+ — motion | Unit 14 (§6): per-component passes, each a few lines on gpui's own primitives — forwarding, Switch thumb, Toast slide, Dialog scrim, Progress cap | ✅ Landed (2026-10-30), each pass reviewed in the gallery; reduce-motion snaps gpui-side with the flag forwarded | | F — platforms + data | ✅ Landed (2026-10-30): `crates/data` (List, Tree, Tabs, Sidebar), the Linux theme sources (Omarchy/KDE/GNOME), the Windows source, the Segoe Fluent + freedesktop icon resolvers, plus per-platform elevation stacks (D24, 2026-11-01) | Remaining acceptance: side-by-side gallery screenshots — a Linux run (Omarchy/KDE/GNOME) and the first Windows hardware build | | G — migration additions (§6.3) | Waves M1–M2: Badge, Select, Segmented, Context menu, Empty state, password + multiline input, Avatar image, then M9+ → 0.1 | Each unit through the review gate; each wave unblocks a real signed screen | -| H — layout crate (§6.4) | ResizeHandle, Shell bootstrap (left sidebar on, right sidebar off, center dock) + the client-side window frame, Dock with drag-to-split, panel-declared sidebar auto-open | Each unit through the review gate; the gallery workspace page doubles as the bootstrap example apps copy | +| H — layout crate (§6.4) | ResizeHandle, Shell bootstrap (left sidebar on, right sidebar off, center dock) + the client-side window frame + titlebar and window controls, Dock with drag-to-split, panel-declared sidebar auto-open | Each unit through the review gate; the gallery workspace page doubles as the bootstrap example apps copy | Gate for every phase: `cargo fmt --check`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test`, gallery smoke run. @@ -375,6 +376,6 @@ Dropped from rev 3: D2, D5, D9 (port-era decisions); the review gate returns in 6. ~~Unit 14 — motion, per component (§6 row 14, D21)~~ ✅ Landed in five passes (2026-10-30): (a) theme `reduce_motion` → `cx.set_reduce_motion` in `reapply`; (b) Switch thumb `with_spring`; (c) Toast 8 px slide-in; (d) Dialog scrim enters with the panel; (e) Progress 30 fps cap. Exits and hover washes stay deferred (§6 deferred list). 7. ~~Phase F, data first~~ ✅ data complete (2026-10-30) — `crates/data` opened with List, then Tree, Tabs, Sidebar (the dead `sheet` feature dropped from core along the way; Table dropped from the roadmap). Also extracted `crates/utils` (2026-10-30): `h_flex`/`v_flex` (core's `common` re-exports them), `focus_handle` (the namespaced keyed handle, 8 call sites), `focus_ring` (7 sites), `adjacent_selectable` + `nav_key` (4 sites), and the selectable-row paint helpers `selectable_label_color`/`paint_selectable_row` (3 sites, reading `&Theme` directly — no intermediate color struct), plus the `StyledExt` trait (`refine_style` — adapted from gpui-kit `base`, D15 — replacing the per-component `style().refine` pattern; 5 sites) — `core` and `data` depend on it; the facade doesn't re-export it. **Linux theme sources landed (2026-10-30)**: Omarchy (colors.toml parse + state-dir detection + inotify on `current`), KDE (kdeglobals `[Colors:*]` + AccentColor + `~/.config` inotify), GNOME/generic (portal `ReadAll` + `SettingChanged` via zbus 5 blocking on its own thread, gsettings fallback with the libadwaita accent table) — `SourceKind::Omarchy/Kde/Gnome`, detection cascade Omarchy → KDE → portal → fallback, all parsers fixture-tested on every OS and the Linux build compile-checked via `cargo check --target x86_64-unknown-linux-gnu`. **Windows source + icon resolvers landed (2026-10-30)**: `SourceKind::Windows` (WinRT `UISettings` + `Personalize` fallback + `ColorValuesChanged`/`HighContrastChanged`, §5.3), the Segoe Fluent codepoint renderer, and the freedesktop theme walker (§4.4); the WinRT surface was verified against the real `windows` 0.62 bindings via a standalone cross-check (gpui's own manifest build needs llvm-rc from macOS). Remaining Phase F: **side-by-side gallery screenshots per platform** — Omarchy/KDE/GNOME need a Linux run, Windows needs its first hardware build. NumberInput stays deferred until needed; multiline landed as §6.3 M7 (2026-11-01). 8. Then — Phase G is the migration additions (§6.3): Badge ✅, Select ✅, Segmented control ✅, Context menu ✅, Empty state ✅, password input ✅, multiline textarea ✅, then Avatar image (M8) — each unblocks a concrete signed screen. Pickers (Calendar/DatePicker, TimeField, ColorPicker) stay decided-at-unit-time. `crates/editor` starts when file viewing (M15) is reached. -9. Then — the layout crate (§6.4): ResizeHandle ✅, Shell ✅, window frame ✅, the center Dock with drag-to-split, and panel-declared sidebar auto-open — each through the review gate, with signed's `crates/dock` as the usage reference and the gallery workspace page as the example. Order against M9+ is decided when the crate starts. +9. Then — the layout crate (§6.4): ResizeHandle ✅, Shell ✅, window frame ✅, titlebar + window controls, the center Dock with drag-to-split, and panel-declared sidebar auto-open — each through the review gate, with signed's `crates/dock` as the usage reference and the gallery workspace page as the example. Order against M9+ is decided when the crate starts. Batched polish candidates between units: scrollbar auto-hide + horizontal thumb, `Undo`/`Redo` menu events.