Skip to content

Commit 6b97f94

Browse files
committed
docs: update spatial parity
1 parent 1d98f05 commit 6b97f94

2 files changed

Lines changed: 109 additions & 78 deletions

File tree

docs/restart-plan/README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# DeepNotes Restart Plan — Index
22

3-
> **Last updated:** 2026-05-31 (Phase 8 complete; marketing site builds 20 static HTML routes with vue-router + vite-ssg, theme toggle, restored legacy assets)
3+
> **Last updated:** 2026-05-31 (Phase 8 complete; marketing site builds 20 static HTML routes with vue-router + vite-ssg, theme toggle, restored legacy assets. **Phase 6 status corrected: spatial canvas polish is NOT complete.**)
44
> **This document replaces `docs/RESTART_PLAN.md`.** If a prior statement conflicts with this one, this version wins.
55
66
---
@@ -15,7 +15,7 @@
1515
| 3 | Collab wire parity — page-level Yjs doc | **Complete** | [phase-3-collab-wire.md](phase-3-collab-wire.md) |
1616
| 4 | SPA foundation + feature slice routing | **Complete** | [phase-4-spa-routing.md](phase-4-spa-routing.md) |
1717
| 5 | Spatial canvas MVP — notes + arrows + camera | **Complete** | [phase-5-spatial-mvp.md](phase-5-spatial-mvp.md) |
18-
| 6 | Spatial canvas polish | **Complete** | [phase-6-spatial-polish.md](phase-6-spatial-polish.md) |
18+
| 6 | Spatial canvas polish | **In progress** | [phase-6-spatial-polish.md](phase-6-spatial-polish.md) |
1919
| 7 | Account, billing, groups polish | **Complete** | [phase-7-account-polish.md](phase-7-account-polish.md) |
2020
| 8 | Marketing, Help, Pricing, and Legal Surfaces | **Complete** | [phase-8-marketing.md](phase-8-marketing.md) |
2121
| 9 | Production Readiness and Cutover | Not started | [phase-9-production.md](phase-9-production.md) |
@@ -75,6 +75,20 @@ A criterion is **not met** until the verification command or check passes in CI.
7575

7676
## Current gaps (high-level)
7777

78+
### Phase 6 — Spatial canvas polish (NOT complete)
79+
80+
- **Page editor layout is a card stack, not an immersive shell.** `PageEditorView.vue` is rendered inside `DefaultLayout.vue` (`max-w-3xl` centered column). It must become a fullscreen `q-layout`-style shell with sidebars, toolbar, and floating overlays. No sidebars, no toolbar, no floating buttons exist today.
81+
- **Left sidebar missing.** No `CurrentPath`, `RecentPages`, `FavoritePages`, or `SelectedPages` panels on `/pages/:pageId`.
82+
- **Right sidebar missing.** No `NoteProperties` (24 files in legacy), `PageProperties`, or `ArrowProperties` panels. Context-aware editing is impossible.
83+
- **Toolbar missing.** No `MainToolbar` with Basic/Formatting/Object/Alignment buttons, insert dialogs, or page-specific actions.
84+
- **Floating UI overlays missing.** No zoom indicator, undo/redo buttons, back/forward nav, screenshot, find/replace toggle, selection count, or user avatars on the canvas.
85+
- **Arrow rendering is a stub.** `DisplayArrow.vue` draws a single SVG line between note centers. Missing: curve/line body styles, arrow heads (`OpenHead`), labels (TipTap), hitboxes, drag-to-reconnect, interregional logic, anchor positioning.
86+
- **Note rendering is partial.** `DisplayNote.vue` has basic drag, resize, and head/body editors. Missing: Teleport overlay during drag, drop zones, arrow link zones, link icon, read-only opacity states, scroll handling, and advanced visual parity.
87+
- **Page state screens missing.** No dedicated `DisplayErrorScreen`, `DisplayNonExistentScreen`, `DisplayPageDeletedScreen`, etc. Inline error cards only.
88+
- **Context menu missing.** No `TableContextMenu` (right-click on canvas).
89+
90+
### Other gaps
91+
7892
- **Realtime notification toast** — only `/notifications` page exists, no badge/toast.
7993
- **Composable size**`useGroupMembersDetail.ts` (103 lines) and `usePageCollabEditor.ts` (238 lines) are now under the 300-line limit. `useSpatialPage.ts` (308 lines) still exceeds by a small margin.
8094
- **Auth: `rememberDevice` UI missing in login**`LoginView.vue` has no "Remember this device" checkbox for 2FA login; users are re-prompted every time. API schema already supports it.

docs/restart-plan/phase-6-spatial-polish.md

Lines changed: 93 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,114 @@
11
# Phase 6: Spatial canvas polish
22

33
> **Prerequisites:** Phase 5 done.
4-
> **Status:** Complete
4+
> **Status:** In progress (2026-05-31 — status corrected after codebase audit)
55
66
---
77

88
## Goal
99

10-
All remaining spatial interactions from the legacy checklist.
10+
Achieve parity with the legacy `/pages/:pageId` immersive spatial canvas experience. A DeepNotes page is **not** a card stack — it is a fullscreen application shell with an infinite canvas at its center, surrounded by toolbars, sidebars, and floating UI.
1111

1212
---
1313

1414
## Deliverables
1515

16-
1. **Selection**
17-
- Multi-select (ctrl/cmd + click).
18-
- Box selection (drag on empty canvas).
19-
- Select all (`Ctrl+A`).
20-
- Active element / active region tracking.
21-
22-
2. **Containers**
23-
- Note can contain child notes (container section enabled).
24-
- Spatial container: children positioned freely inside parent.
25-
- Horizontal container: children arranged in a row.
26-
- Drag child out to detach.
27-
- Drag note into container to attach.
28-
29-
3. **Clipboard**
30-
- Cut / copy / paste notes and arrows.
31-
- Cross-page paste (requires serialization format).
32-
33-
4. **Alignment + distribution**
34-
- Align left / center / right / top / middle / bottom.
35-
- Distribute horizontally / vertically.
36-
37-
5. **Undo / redo**
38-
- `Ctrl+Z` / `Ctrl+Shift+Z` for note operations (move, create, delete, resize).
39-
- Must integrate with Yjs undo manager or a custom command stack.
40-
41-
6. **Immersive page layout and state screens**
42-
- Rebuild `PageEditorView.vue` as a full-screen spatial shell (no scrolling card stack):
43-
- `MainToolbar` (shadcn): breadcrumb path, zoom controls, undo/redo, share, find/replace toggle.
44-
- `LeftSidebar` (shadcn): Recent pages, Favorites, Selected elements, Current path.
45-
- `RightSidebar` (shadcn): Page properties, Snapshots, Management, Backlinks, Collab status — collapsible panels.
46-
- `TableContextMenu` (shadcn): right-click context menu on canvas.
47-
- `LoadingOverlay`: centered spinner during page bootstrap.
48-
- Global CSS for spatial routes: `user-select: none`, `overflow: hidden`, `touch-action: none`, `position: fixed` on body.
49-
- Dedicated fullscreen state screens replacing inline error cards:
50-
- `DisplayErrorScreen`, `DisplayNonExistentScreen`, `DisplayPageDeletedScreen`, `DisplayGroupDeletedScreen`, `DisplayInvitedScreen`, `DisplayRejectedScreen`, `DisplayUnauthorizedScreen`, `DisplayPasswordScreen`.
51-
- Remove `PageEditorTiptapCard.vue` from the page route. The Tiptap rich-text editor becomes the head/body editing surface inside `DisplayNote.vue` only.
52-
53-
7. **Note visual parity (legacy style, no Quasar)**
54-
- `DisplayNote.vue` must match legacy visual behavior using Tailwind/shadcn primitives:
55-
- Background color + border color from `note.color` (or hardcoded legacy color map), with subtle transparency (`/10` tint or legacy equivalent).
56-
- Selection ring: `ring-2 ring-primary` or legacy blue `#2196f3`.
57-
- Drag opacity: `0.7` during drag/resize.
58-
- `Teleport` to a global `.display-overlay` during drag/resize to avoid parent clipping.
59-
- `NoteDropZones`: invisible zones on container notes for drag-to-attach.
60-
- `NoteArrowHandles`: 4 directional handles on selected notes to initiate arrow creation.
61-
- `ArrowLinkZones`: zones on note edges for arrow reconnection.
62-
- `NoteLinkIcon`: external-link indicator when `link.url` is set.
63-
- `NoteResizeHandles`: 8 handles (nw, n, ne, e, se, s, sw, w) with correct cursors.
64-
- Scrollbar handling in `NoteContent`: allow touch scroll inside notes, prevent pull-to-refresh on body.
65-
- Note frame `border-radius` (`rounded-md` or legacy `7px`), shadow, and min-width matching legacy.
66-
- Container section: spatial and horizontal layouts with correct child note positioning and offset math.
67-
68-
8. **Arrow visual parity (legacy style, no Quasar)**
69-
- `DisplayArrow.vue` must support:
70-
- **Curve body** (`CurveArrow.vue`) and **line body** (`LineArrow.vue`).
71-
- **Arrow heads**: `OpenHead.vue` at source/target with rotation.
72-
- **Arrow label**: editable `Y.XmlFragment` rendered as an SVG `foreignObject` or HTML overlay positioned along the curve.
73-
- **Hitbox**: invisible thick stroke (`stroke-width: 20`, `stroke-opacity: 0`) for easy grabbing.
74-
- Drag-to-reconnect: grab an arrow endpoint and drop it onto another note.
75-
- Color matching note color logic.
76-
- All arrow SVG must use `overflow: visible` and absolute positioning within the world coordinate system.
77-
78-
9. **Find and replace**
79-
- Search across all note head/body text.
80-
- Replace text.
81-
82-
10. **Visual polish**
83-
- Grid background.
84-
- Note color inheritance.
85-
- Collapsing notes.
86-
- Z-index ordering.
87-
- Read-only notes.
16+
### 1. Selection
17+
| Item | Status | Notes |
18+
|------|--------|-------|
19+
| Multi-select (ctrl/cmd + click) | **Done** | `SpatialPageView.vue` handles toggle via Ctrl+click |
20+
| Box selection (drag on empty canvas) | **Done** | Threshold-based drag-to-box-select implemented |
21+
| Select all (`Ctrl+A`) | **Done** | `onKeyDown` in `SpatialPageView.vue` |
22+
| Active element / active region tracking | **Partial** | `useSpatialSelection` has `activeId` but no active-region concept |
23+
24+
### 2. Containers
25+
| Item | Status | Notes |
26+
|------|--------|-------|
27+
| Note can contain child notes | **Done** | `container.enabled` and `container.children` wired in Yjs |
28+
| Spatial container (free child positioning) | **Done** | Children rendered with world offset inside parent |
29+
| Horizontal container (children in a row) | **Not started** | No horizontal layout logic |
30+
| Drag child out to detach | **Done** | `onNoteDragEnd` + `moveNoteOutOfContainer` |
31+
| Drag note into container to attach | **Done** | Overlap-area heuristic in `SpatialPageView.vue` |
32+
33+
### 3. Clipboard
34+
| Item | Status | Notes |
35+
|------|--------|-------|
36+
| Cut / copy / paste notes and arrows | **Done** | `copySelection`, `pastePayload` implemented |
37+
| Cross-page paste | **Not started** | Needs serialization format + clipboard persistence |
38+
39+
### 4. Alignment + distribution
40+
| Item | Status | Notes |
41+
|------|--------|-------|
42+
| Align left/center/right/top/middle/bottom | **Done** | Keyboard shortcuts (Ctrl+Shift+L/C/R/T/M/B) |
43+
| Distribute horizontally / vertically | **Done** | Keyboard shortcuts (Ctrl+Shift+H/V) |
44+
45+
### 5. Undo / redo
46+
| Item | Status | Notes |
47+
|------|--------|-------|
48+
| `Ctrl+Z` / `Ctrl+Shift+Z` | **Done** | `useSpatialUndoRedo` wraps Yjs UndoManager |
49+
50+
### 6. Immersive page layout and state screens
51+
| Item | Status | Notes |
52+
|------|--------|-------|
53+
| Fullscreen `PageEditorView.vue` shell | **Not started** | Still a `max-w-3xl` card stack in `DefaultLayout.vue` |
54+
| `MainToolbar` (shadcn) | **Not started** | No page-specific toolbar exists |
55+
| `LeftSidebar` (shadcn) — Recent, Favorites, Selected, Current path | **Not started** | Zero sidebar infrastructure on page route |
56+
| `RightSidebar` (shadcn) — Note/Page/Arrow properties | **Not started** | No property panels exist |
57+
| `TableContextMenu` (shadcn) — right-click on canvas | **Not started** | No context menu on canvas |
58+
| `LoadingOverlay` during page bootstrap | **Partial** | Inline loading text in cards only |
59+
| Global CSS for spatial routes (`user-select: none`, `overflow: hidden`, `touch-action: none`) | **Not started** | `DefaultLayout.vue` does the opposite |
60+
| Remove `PageEditorTiptapCard.vue` from page route | **Not started** | Still rendered at bottom of card stack |
61+
| Dedicated fullscreen state screens (8 total) | **Not started** | No `DisplayErrorScreen`, `DisplayNonExistentScreen`, etc. |
62+
63+
### 7. Note visual parity (legacy style, no Quasar)
64+
| Item | Status | Notes |
65+
|------|--------|-------|
66+
| Background + border color from `note.color` | **Partial** | Hardcoded 10-color map with `/18` opacity tint |
67+
| Selection ring | **Partial** | `ring-2 ring-primary` exists, but not legacy blue `#2196f3` |
68+
| Drag opacity (`0.7`) | **Not started** | No opacity change during drag |
69+
| `Teleport` to global overlay during drag/resize | **Not started** | Notes drag inside parent; no overlay portal |
70+
| `NoteDropZones` | **Not started** | No invisible drop zones on container notes |
71+
| `NoteArrowHandles` — 4 directional arrow handles | **Partial** | 4 small dots exist, but not full arrow-creation flow |
72+
| `ArrowLinkZones` | **Not started** | No edge zones for arrow reconnection |
73+
| `NoteLinkIcon` (external link indicator) | **Not started** | No link icon when `link.url` set |
74+
| `NoteResizeHandles` — 8 handles | **Done** | NW, N, NE, E, SE, S, SW, W with correct cursors |
75+
| Scrollbar handling in `NoteContent` | **Not started** | No pull-to-refresh prevention |
76+
| Note frame `border-radius`, shadow, min-width | **Partial** | `rounded-md border shadow-sm` used; exact pixel parity untested |
77+
| Container section — spatial layout | **Done** | Free child positioning inside parent |
78+
| Container section — horizontal layout | **Not started** | No row layout |
79+
80+
### 8. Arrow visual parity (legacy style, no Quasar)
81+
| Item | Status | Notes |
82+
|------|--------|-------|
83+
| Curve body (`CurveArrow.vue`) | **Not started** | Only straight SVG `<line>` exists |
84+
| Line body (`LineArrow.vue`) | **Partial** | Straight line is default, but no `bodyType` switching |
85+
| Arrow heads (`OpenHead.vue`) | **Not started** | No arrowheads rendered |
86+
| Arrow label (editable `Y.XmlFragment`) | **Not started** | No label support |
87+
| Hitbox (thick invisible stroke) | **Not started** | Thin `cursor-pointer` line only |
88+
| Drag-to-reconnect | **Not started** | No endpoint grabbing |
89+
| Color matching note color logic | **Not started** | Stroke uses `currentColor` or `var(--primary)` |
90+
91+
### 9. Find and replace
92+
| Item | Status | Notes |
93+
|------|--------|-------|
94+
| Search across note head/body | **Partial** | `find-replace.ts` exists but no UI triggered from page editor |
95+
| Replace text | **Partial** | Logic exists but no UI in page editor |
96+
97+
### 10. Visual polish
98+
| Item | Status | Notes |
99+
|------|--------|-------|
100+
| Grid background | **Done** | CSS `linear-gradient` grid in `SpatialWorldCanvas.vue` |
101+
| Note color inheritance | **Done** | `inherit` flag + parent color cascade |
102+
| Collapsing notes | **Done** | Chevron toggle + collapsed state wired |
103+
| Z-index ordering | **Done** | `notesByZIndex` computed sort |
104+
| Read-only notes | **Partial** | `opacity-70` class, but no full read-only styling |
88105

89106
---
90107

91108
## Verification
92109

93-
- Each deliverable has a test (unit, component, or integration).
94-
- Phase 1 checklist is >80% marked done.
110+
- [ ] Each deliverable has a test (unit, component, or integration).
111+
- [ ] Phase 1 checklist is >80% marked done.
95112

96113
---
97114

0 commit comments

Comments
 (0)