v0.0.4 — co-edit polish + large-file pipeline + UX rounds 1–7
Highlights
Co-editing
- Polished share dialog — file picker / password / role (edit | view-only), two copyable share URLs, password stash so the owner skips their own prompt.
- Presence in the title bar — avatar stack with initials, color per peer, "Active now / Last seen Ns ago" tooltips, idle fade past 8 s.
- Live cursors on the grid — peer selection rendered as a colored rect with name label, tracks scroll via
api.Event.Scroll. - Live-typing ghost — peers see characters appear in your cell as you type, not just on commit. 30 ms-throttled awareness broadcast on
SheetEditChanging. - View-only role — joiner's edits stay local; bridge skips outbound op-log writes.
- Server: SHA-256 +
timingSafeEqualpassword gate on the WS upgrade;/api/rooms/:id/infopreflight;/seed+/snapshotupload+fetch.
Large-file pipeline (docs/LARGE_FILE_PIPELINE.md)
- Stage 0 —
initialFormulaComputing: NO_CALCULATION,INITIAL_COLUMNS128 → 26, singlewb.save()per export. - Stage 1 — xlsx parser in a Web Worker.
- Stage 1b — xlsx exporter in a Web Worker. Main bundle 8.3 MB → 6.3 MB (ExcelJS now only in worker chunks).
- Stage 2 — server-cached gzipped
IWorkbookDatasnapshot for joiners; skips ExcelJS entirely on the fast path. - Stage 3 —
WorkbookMeta+snapshotRef: fullIWorkbookDatano longer lives in React state alongside Univer's copy. ~30–50% peak heap cut on big files. - Stage 4 — lazy plugin loader. CF / DV / hyperlink / drawing / note / thread-comment / table / sort / filter / find-replace each ship as their own chunk. Eager-loaded on snapshot inspection when the workbook needs them.
- Stage 5 — hyperlinks inline in
cell.p.body.customRanges; no more O(N)AddHyperLinkCommandreplay at mount. - Stage 7 —
apps/web/src/perf.tsprofiling harness wrapping the five hot paths, locked in byperf-harness.spec.ts. - Op-log batching — collab bridge transacts a microtask's worth of mutations. One paste / sort / fill = one Yjs encode = one WS frame.
- Selection-stats cap — Cmd+A on a million-row sheet no longer freezes computing Count / Sum / Avg.
Loading + error UX
- Phase-aware loading overlay — "Reading file…" → "Parsing…" → "Loading into editor…", with elapsed timer, step indicator, and a "this is a large workbook" hint above
VITE_SOFT_WARN_MB. - Hard reject above
VITE_MAX_OPEN_MB(default 100 MB) instead of letting the worker OOM-crash the tab. - Retry button on the error card.
Excel-fidelity UX + 7 polish rounds
- Range picker, keybindings, toolbar overflow + shortcut hints, disabled-state contrast, tooltip snappiness, dialog focus trap + scroll lock, hidden-sheet visibility + unhide affordance, peer label collision avoidance, multi-line formula paste, Excel-paste merge / column-width / row-height preservation, tables empty-state CTA.
Configuration
New .env.example documents every knob — wired through docker-compose.yml (env + build args) and Dockerfile:
| Knob | Default | What for |
|---|---|---|
MAX_UPLOAD_MB |
100 | Server seed/snapshot upload cap |
ROOM_TTL_MIN |
15 | Idle room eviction window |
REDIS_URL |
unset | Y.Doc persistence (7-day TTL) |
VITE_MAX_OPEN_MB |
100 | Hard reject for File → Open |
VITE_SOFT_WARN_MB |
25 | "Large workbook" hint threshold |
VITE_COLLAB_ENABLED |
1 (Docker) / unset (Pages) | Ship co-edit code |
Docker
```sh
docker run --rm -p 3000:3000 schnsrw/casual-sheets:0.0.4
```
Note: :0.0.4 lands on Docker Hub once the Publish Docker image workflow succeeds — currently blocked on DOCKERHUB_USERNAME / DOCKERHUB_TOKEN secrets being added to the repo's Actions scope.
Tests
181 Playwright specs passing (+ 4 fixme).