Commit Graph

2 Commits

Author SHA1 Message Date
saravanakumardb1
8562711f49 fix(workspace+theme): sanitise corrupt spans, short-circuit re-reconcile, drop unreachable regex
──────────────────────────────────────────────────────────────────
customizable-workspace
──────────────────────────────────────────────────────────────────

Two issues caught in the audit pass:

1. **Corrupt persisted spans broke the grid layout.**
   localStorage entries from older versions (or hand-edited debug
   sessions) could contain span=NaN / 0 / -3 / 99. These flowed
   straight into `grid-column: span <bad>` which silently broke
   the whole row. The visual symptom was a tile rendering at zero
   width or pushing every sibling off-screen.
   Fix: `reconcile()` now clamps every span (including newly
   appended tiles' defaultSpan) to the legal `[1, 4]` range via
   `sanitiseSpan()`.

2. **Re-reconcile effect could loop when callers forget to memoise.**
   The `useEffect([tiles, hydrated])` always called `setLayout`
   with a fresh `{ entries: [...] }` object reference, even when
   the content was identical. If `tiles` itself was a fresh
   reference per parent render (e.g. `tiles=[{...}]` inline),
   every render \u2192 setLayout \u2192 save effect \u2192 (no loop because
   tiles ref same), but constant unnecessary writes to
   localStorage.
   Fix: added `sameLayout(a, b)` structural-equality check;
   setLayout now short-circuits to the previous state when the
   reconciled output is identical.

Tests: 10 \u2192 11
  reconcile  \u00b7 sanitises corrupt spans (NaN/0/negative/>4) \u2192 clamp

──────────────────────────────────────────────────────────────────
generative-theme
──────────────────────────────────────────────────────────────────

Cosmetic but worth fixing: the `rose` palette regex included
`warm` as a keyword, but the `citrus` palette \u2014 listed earlier in
the PALETTES table \u2014 also matched `warm`. Since first-match wins,
`warm` was unreachable in rose and the entry was misleading.

Dropped `warm` from the rose regex. Citrus retains it (was always
where it routed in practice). All 18 existing tests still pass.
2026-05-27 18:46:19 -07:00
saravanakumardb1
2affd1aba0 feat(customizable-workspace): @bytelyst/customizable-workspace@0.1.0 — Wave 13.F
Drag-reorderable tile grid with per-tile width control + view-scoped
persistence. Native HTML5 drag — zero runtime deps (no @dnd-kit).

──────────────────────────────────────────────────────────────────
Module surface
──────────────────────────────────────────────────────────────────
  <Workspace tiles storageKey persistence? columns? readOnly?>
    Wave 13.F.1 + .2

    - Native HTML5 drag-and-drop (draggable + dragover + drop)
    - role=grid + per-cell role=gridcell + tabIndex=0
    - Keyboard shortcuts on focused tile:
        ← / →   resize span down/up (clamped 1..columns)
        ↑ / ↓   move tile up/down by one slot
    - Per-tile 1/2/3/4 size buttons (suppressed in readOnly)
    - Drop target gets dashed accent outline
    - Reset-layout CTA (suppressed in readOnly)

  useWorkspaceLayout(tiles, { storageKey, persistence })
    - move(from, to) / resize(id, span) / reset()
    - hydrated flag — true once initial load resolves
    - One-shot load on mount, save on every change (post-hydration)

  reconcile(layout, tiles)  ·  exported pure fn
    - Drops entries referencing removed tiles
    - Appends new tiles in registry order with defaultSpan fallback
    - Used by the hook on every tile-registry change
      (defensive against schema drift between releases)

  localStoragePersistence  ·  default; SSR-safe (returns null when
                                 window is absent)

──────────────────────────────────────────────────────────────────
Quality gates
──────────────────────────────────────────────────────────────────
  ✓ 10/10 tests passing
    - reconcile: 3 cases (drop unknown / append new / preserve order)
    - hook:      4 cases (hydrate defaults / move / resize / reset)
    - component: 3 cases (renders cells / keyboard resize / readOnly)
  ✓ tsc build clean

──────────────────────────────────────────────────────────────────
Roadmap (lands in subsequent commit)
──────────────────────────────────────────────────────────────────
  13.F.1  Drag-resize tiles
  13.F.2  Saved views per route + persistence layer

Showcase /futurism/workspace (MAG.6) lands in the paired showcase
commit.
2026-05-27 17:30:33 -07:00