Commit Graph
20 Commits
Author SHA1 Message Date
mats 7362e4730f Cheaper, clearer dropzones: memoize, hatch refused, label slots as words
DropZones re-ran the accept predicates and a DOM walk on every overlay
render (pointermove-driven). Matching now runs once per drag via
matchZones(); scroll/resize ticks only re-measure the cached rects (new
test pins the predicate count across ticks).

Refused slots get a diagonal hatch on top of the red tint so the state is
not color-only, slot tags show handles as words (`3d-accessories` ->
"3d accessories", raw key kept in title), and the ghost pop honours
prefers-reduced-motion.

The mock section template now marks its sidebar slot like a real
template, so slot tests use the fixture instead of hand-injected DOM
(the old palette test asserting "no tagged slots" now expects both
sections' slots).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-09 09:35:16 +01:00
mats a798bc1ad3 Highlight every dropzone on the page while dragging
Palette blueprints, searched nodes and moving blocks shared one engine
but only the single current target line was visible, so there was no way
to see where a dragged item could land. While a drag is active the
overlay now outlines every valid dropzone with the engine's own
predicates (accepts / acceptsInSlot, blueprint refusal, self-exclusion):
containers in green, fitting slots in blue with a name tag, refused slots
dimmed red with a name tag so they read as "exists but not for this".

Tests: palette fit + slot-fallback, blueprint container/refused-slot,
node fit/refuse on the same slot, move self-exclusion; typecheck clean.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-09 09:19:59 +01:00
mats 5c5c34d25a Pin the typecheck to our uniform tiptap set
`tsc --noEmit` (first step of `npm run build`) type-checks the shared
@k6n/cms-editor sources, which resolve tiptap from the backoffice tree:
core 3.30.2 mixed with a nested markdown 3.32.2 whose Extension type no
longer fits the older core's `Extensions`. Our own node_modules holds a
uniform 3.32.2 set, so map @tiptap/* there in tsconfig paths. Vite does
not read tsconfig paths (it aliases @k6n/cms-editor manually), so
bundling and runtime resolution are untouched.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 13:49:16 +01:00
mats b7849c0359 Repair outline rows and add split panels for drag & drop
Outline chevron buttons were matched by a generic `.cms-outline li
button { width: 100% }` rule, so each expand/collapse arrow took a full
row and the tree looked stacked and broken. Scope row styling to
`.cms-orow__main`, fix the chevron to 22px, add rotating chevrons to the
section headers, and turn the blocks palette from centered narrow cards
into left-aligned rows.

Add a split toggle to the panel header: outline stays visible in a left
column while Blocks/Nodes switch as tabs in a right column, so a drag
source and its outline drop gaps are on screen together. Choice and
library tab persist per profile; stacked mode is unchanged.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 13:37:45 +01:00
mats fc0eb2c6be editor: resizable rail, Esc closes panel, dev tab remembered
Rail gets a drag handle on its edge (240-640px, width persisted like
the rest of the panel state). Escape now closes the panel as the last
step of its chain (dialog > inline > selection > panel). The dev panel
remembers its tab across reloads. Panel toggle button title notes the
Esc shortcut. Harness covers resize/persist, Esc-close and dev tab.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 12:40:46 +01:00
mats bb875a0956 editor: friendlier panels - collapsible rail, remembered state, no more overlap
Rail sections (Outline/Blocks/Nodes) collapse via their headers like
Experiments already did, so long pages stay navigable. Rail open state
and section toggles persist in localStorage across reloads (the QA
preview flow reloads constantly). The assistant panel shifts left while
the dev panel is open instead of stacking exactly underneath it, and
the rail/dev/assistant widths cap at the viewport on small screens.

Tests: rail-sections harness (collapse, reload persistence, shifted
assistant); harness boots with a fresh profile unless keepStorage is
passed; in-memory localStorage shim for the origin-less jsdom.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 12:37:09 +01:00
mats 5786712078 editor: outline lists no longer position:fixed (unstack the rail)
.cms-outline was in the shared fixed-panel selector, so every outline
level (tree, nested, slots) broke out of the rail flow and painted as
an opaque floating box stacked over the palette/nodes sections below -
nothing under it was clickable or draggable. The outline only ever
renders inside the rail, so it is now plain in-flow; standalone panels
(bar, dock, dialogs, dev, assistant, toast) keep their fixed rule.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 12:28:28 +01:00
mats 922562e1c2 editor: experiments QA panel (P0 of experiments plan)
New Experiments section in the rail: lists tracking experiment rules
(status, traffic, arms, targeting), shows this session's assignment via
evaluate-experiments, per-arm analytics with winner/significance, a QA
arm override (sets the storefront variant cookie), and a two-step
pause/resume kill-switch. Admin reads degrade when the tracking gate
refuses; eligibility always works. Mock tracking endpoints + harness
tests.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 12:00:37 +01:00
mats 40b33f89a4 editor: explain slot refusals on-page; auto-scroll while dragging\n\nDrag state now records the tagged slot under the pointer. When the\ndragged type does not fit it, a badge on the zone names the accepted\ntypes (from the slot schema) and the pointer chip turns refused -\npreviously a refused slot silently fell back to a container drop.\nHolding the pointer near a viewport edge scrolls the page (ramped\nrAF loop, re-targeting after each step) so long pages are droppable\nend to end. Helpers are unit-tested; harness covers refusal badge,\naccept path and the scroll step.\n\n🤖 Generated with Codebuff\nCo-Authored-By: Codebuff <noreply@codebuff.com> 2026-11-07 11:53:47 +01:00
mats 8e8823421d editor: drop into tagged slot dropzones ([data-cms-slot])
Templates mark visual edge slots with data-cms-slot/-parent. The drag
engine now resolves those zones first (slot-scoped index, acceptsSlot
filter), sorts within the dragged block's own slot, and the overlay
shows a slot add-button so empty zones are discoverable. dnd unit
tests cover slot hit/index/refusal/same-slot sort.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-07 11:26:52 +01:00
mats 33bd5269fd Single panel: outline tree with slots, node search with type filter
The outline and blocks are no longer tabs: one panel shows the
outline tree, the new-block palette and a search over existing
nodes. Outline rows drag to reorder (same snap engine, explicit
gap targets), palette blocks and searched nodes drop onto the
outline gaps as well as the page.

Named slots (x-graph.connections, e.g. a pdp's info-section /
3d-accessories / model) render as groups under their block with
allowed types, live counts and a slot-limited insert picker.
Drops that fit no plain-children rule resolve to the first
accepting slot; existing nodes link via graft tree.link.

Adds Api.searchNodes, schema connections helpers, handle-aware
controller ops (linkExisting, insertIntoSlot, dropExisting) and
mock support for /api/nodes listing and graft links.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-11-06 20:38:31 +01:00
mats a4ed99f13e ai assistant 2026-11-01 14:57:39 +01:00
matsandClaude Sonnet 5.5 d3fb060016 Fix self-inflicted edit conflicts: dialogs no longer pin a stale node version
Properties, Raw JSON and AI proposals sent the version captured when the
dialog opened. Any other edit to the node meanwhile (style chip, drag handle,
inline text, child insert/move) bumped it, so the save 409'd against the
user's own work. Save through ctrl.saveData instead: compare only the keys
being written against the current node (a real conflict is a key someone else
changed) and send no version. 409 toasts now show the server's reason.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 13:57:00 +01:00
mats 2d35df4c7f Merge branch 'main' of git.k6n.net:mats/cms-onpageeditor 2026-11-01 12:11:50 +01:00
mats 20528c8aef more tweaks 2026-11-01 12:11:23 +01:00
matsandClaude Sonnet 5.5 3fdf415847 README: /edit entry point
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 12:08:24 +01:00
matsandClaude Sonnet 5.5 ec4212c113 Device preview + responsive spacing in the Style panel
Style panel gets a real-viewport iframe preview (390/820/1280px) tied to the
breakpoint tab, reloaded after each edit, and spacing/gap controls per
breakpoint. The editor does not boot inside the preview frame. Mock and
tests mirror the new k6n layout template.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 11:02:20 +01:00
matsandClaude Sonnet 5.5 cb7a7a1fab Loader (cms-client.js), submodule-aware editor source path, build:watch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 11:02:20 +01:00
mats 2e0bf1e88e initial ai assistance 2026-11-01 10:27:56 +01:00
matsandClaude Sonnet 5.5 1af9ec3172 Add on-page editor for the go-graph-cms
Injectable React editor that is side-loaded onto the statically rendered
page and edits through the CMS HTTP API (POST /api/edit).

- Shadow-root UI over server HTML; patches morphed in, undo/redo from
  server inverses (reuses @k6n/cms-editor EditClient/morph/markdown editor)
- Sign-in via go-auth device grant as the CMS client (aud matches), token
  refresh + 401 retry; live preview swapped in on load and on tab focus
- Schema-driven property form (arrays, maps, variants, $ref, validation)
- Every string property editable where it is rendered (value-bound inline
  fields and attribute chips), markdown WYSIWYG for marked fields
- Block palette + drag & drop with ghost drop targets, insertion slots,
  sort snapping between siblings (Alt to nest)
- x-style annotations: on-page padding/margin/gap handles, Style panel,
  wrap-in-layout; x-graph label/group for titles and grouping
- Dev workflow: Vite proxy to the live site (token injected server-side)
  or an offline in-memory mock CMS; jsdom test suite

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 22:34:48 +01:00