summaryrefslogtreecommitdiffhomepage
path: root/src/features/workspaces/ui/HomeTileGrid.test.ts
AgeCommit message (Collapse)Author
2026-09-20feat(workspaces): archive option + archived-workspaces viewAdam Malczewski
Consume the backend's archive contract (feature/archive-workspaces): - adapter/http: archive(id)/unarchive(id) (PUT/DELETE /workspaces/:id/archive); list(archived?) passes the ?archived= query - logic/view-model: pure applyArchived(list, id, archived) - store.svelte: setArchived(id, archived) (optimistic + revert-on-error + reconciling refresh); archivedList + refreshArchived() for the archived view - ui/TileActionBar: new Archive action (the right-click→select action bar) - ui/HomeHeader: new Archived button opens the archived view - ui/ArchivedWorkspaces (new): modal listing archived workspaces with Unarchive + View (navigates to /<id>) - ui/WorkspacesHome: wire the Archive action + the Archived modal - .dispatch/wire.reference.md + backend-handoff.md: record the contract delta
2026-09-07feat(workspaces): content-driven canvas while dragging — scrollbar ↵Adam Malczewski
grows/shrinks with the gesture Revert the fixed append-canvas reservation (9ede1f0): pre-reserving the 3 spaces at drag start made the view jump right and created far too much free canvas. The grid is back to hugging its content (width: max-content / auto), so the preview extends the canvas as the tile reaches toward the edge and it shrinks back when the gesture ends — the scrollbar moves with the drag, as intended. The drag-target clamp (dragAppendLimit, +3 past the committed edge) still bounds how far the preview can extend, so the "endless growth" problem stays solved without reserving anything up front. Dots restore the one-pitch padding extension for the append slot; the scroll-measure effect still re-runs on drag start/end (the canvas shrinks back on cancel). Test reverted to the content-driven assertions. Verification: svelte-check 0 errors/0 warnings; vitest 1693/1693; biome clean on touched files; build ok.
2026-09-07feat(workspaces): reserve the append canvas for the whole drag — no ↵Adam Malczewski
scrollbar change mid-drag Previously the grid kept `width: max-content` during a drag, so the canvas grew/shrunk as the preview placed the tile at each hovered cell — the scrollbar resized mid-drag, making placement harder. Now the moment a drag starts the grid's growth axis becomes a FIXED reservation: the append limit (committed content edge + 3, span-aware) computed at drag start, so the 3 spaces "pop in" immediately, the scroller size is constant for the entire gesture, and the unused reservation disappears when the drag ends (the canvas returns to max-content / auto). The dragged tile's span room is included so its body always stays inside the reserved canvas. Also: the scroll-measure effect now tracks `dragging`, so canPan and the scroll indicator re-measure when the reservation appears and disappears. Test: the drag test now asserts the grid's style is a fixed px width while dragging (never max-content) and back to max-content after the drop. (This caught a missing `px` unit that would have silently voided the reservation.) Update the handoff bullet to describe the reservation. Verification: svelte-check 0 errors/0 warnings; vitest 1693/1693; biome clean on touched files; build ok.
2026-09-07feat(workspaces): pinned tiles with displacement reflow + FLIP drag previewAdam Malczewski
Tiles can now be dropped onto specific cells; empty cells are real estate that persists (notes/pinned-tiles-plan.md). Data (v2): each tile carries an optional pinned anchor in a UNIVERSAL 4-row frame (tall folds its 2 columns onto frame column 1; a wide col>1 pin reads as unpinned in tall). v1 documents migrate in memory to all-unpinned (render-identical) and write back as v2 on the next change. sanitizeLayout drops garbage anchors. Packing: pinned-first (first-wins on overlap, one-ply), then unpinned tiles first-fit into the REMAINING cells — holes between pins count and never compact. displacePlace: the user-specified semantics — the dragged tile leaves a gap at its origin (nothing slides backward), anchors at the drop cell, and the contiguous filled run pushes FORWARD until the first empty cell absorbs it (X_X + Y@1 → YXX; _XZ_ + Y@2 → _YXZ). placeAtCell commits the displacement and pins every tile; pinAtFirstEmpty pins the create-flow tile at the first truly-empty slot; sortByRecentActivity now also clears pins (an explicit arrangement reset — the menu item says so). Drag UX: pointer → cell hit-math (empty cells are drop targets); a faint dot marks every cell center during a drag (CSS radial-gradient overlay, one extra pitch of end padding for the append slot); the dragged tile element itself follows the pointer (lifted via transform, pointer-events none); a dashed tone-colored ghost marks the landing footprint. The preview recomputes from the COMMITTED layout on every hover-cell change (as if the user moved straight from the original to there) while GSAP Flip animates from wherever the tiles currently are (re-entrant — mid-flight positions captured). Escape/pointercancel discards the preview and flies the tile home; a drop settles it onto its new cell. Tests: displacement (both user examples + internal moves + spans + tall stream), pinned pack (anchors, gaps kept, first-wins, universal-frame mapping, deleted-leaves-holes), v1→v2 migration + anchor sanitization, store placeAtCell/no-op write guard, Escape-cancels-drag component test. 1689 green.
2026-09-07feat(workspaces): Win8 Start-style tile-grid home pageAdam Malczewski
Rebuild the workspace home as a Windows 8 Start-screen-style tile grid, replacing the max-w-3xl vertical card list. Pure core (zero DOM/Svelte/fetch, fully unit-tested): - logic/tile-layout.ts — geometryFor(width, height) resolves WIDE (4 fixed ~120px rows, column-wise flow, 4x2 span cap) or TALL (2 fixed columns, row-wise flow, 2x2 cap); pack() is the ONLY order->coordinates transform (greedy first-fit in fill order, hole-free, render-clamped per geometry); firstEmptySlot/insertAtFirstEmptySlot/mergeLayout/resizeTile/moveTile/ sortByRecentActivity/sanitizeLayout. Persisted data is orientation-independent {version:1, tiles:[{id,colSpan,rowSpan,order}]} — order + spans only, never positions; the same data renders in either geometry (spans clamp for the render, persisted values untouched). - logic/drag-controller.ts — pure pointer/press state machine: mouse threshold-drag + tap-open; touch long-press lifts + selects, pre-lift movement cancels so vertical scrolling never fights the gesture. Shell: - tile-layout-store.svelte.ts — thin reactive wrapper persisting through the injected createLocalStore adapter (dispatch.workspaces.tiles), ops: sync/resize/move/placeFirstEmpty/sortByRecentActivity. - ui/HomeTileGrid.svelte — CSS-grid tile canvas (wide: horizontal scroll + snap + wheel pan + pan arrow + scroll indicator; tall: native vertical scroll), FLIP-animated reflow, drag ghost, transient resize preview. - ui/HomeHeader.svelte — fixed chrome: Dispatch display title, New workspace popover (same slug validation; creates via create-on-miss and does NOT navigate — the new tile lands in the first empty slot in fill order and enters rename mode), global Plugins button, sort-by-recent overflow; compact icon buttons + bottom sheet on tall screens. - ui/WorkspaceTile.svelte — tile face (title, /slug, conversation count, relative last-activity, live active dots, starred tint); inline rename with the old card's semantics. - ui/TileActionBar.svelte — slides up on select (right-click / long-press): Open, Rename, Resize, Star/Unstar, Details, Plugins, Delete (old confirm + store call preserved). - ui/ResizePicker.svelte — Word-style insert-table hover grid (wide 4x2 / tall 2x2) with arrow/Enter/Escape support and ghost preview on commit. - ui/WorkspaceDetails.svelte — flyout holding the old card's default-cwd input + default-computer select (same store calls + error states). - WorkspacesHome.svelte orchestrates; App.svelte untouched (same props). - WorkspaceCard.svelte is removed (replaced by the tile system). Manual tile order rules; starred workspaces get a tint (star is no longer a sort key); workspaces unknown to the layout append at the end. vitest: jsdom gains PointerEvent (MouseEvent-based) + Element.animate stubs — the pointer logic is the outermost edge for the drag tests. Verification: svelte-check 0/0, vitest 1655 passed (102 files, twice), biome clean, vite build OK.