Commit Graph
61 Commits
Author SHA1 Message Date
shadowdao 0ac420a23c Merge issue-55-fe (Refs #55)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 12:09:09 -07:00
shadowdao 05c39961ce Merge issue-52-fe (Refs #52)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
#	craft/src/styles/editor.css
2026-10-07 12:09:09 -07:00
shadowdao 1d34d1b3b1 Merge issue-53 (Refs #53)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 12:09:09 -07:00
shadowdao d39e1ecc31 Merge issue-56 (Refs #56)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
#	craft/src/styles/editor.css
2026-10-07 12:06:59 -07:00
shadowdao 0a59294fee Merge issue-54-fe (Refs #54)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 12:06:59 -07:00
shadowdao 4a81d0b89f Merge issue-51-fe (Refs #51)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
#	craft/src/styles/editor.css
2026-10-07 12:06:59 -07:00
shadowdao 1eaf8e39fb Merge issue-49 (Refs #49)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 12:06:59 -07:00
shadowdao eb87a39619 Merge issue-48 (Refs #48)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 12:06:59 -07:00
shadowdao c0fd183c11 feat(site-builder): pre-publish checklist and canonical link
Publish now runs client-side checks (image alt, meta description, title
length, H1, empty links, contrast, noindex landing, empty page) over the
current state and shows a grouped checklist with Fix links and
"Publish anyway". Adds ExportOptions.canonicalUrl -> <link rel="canonical">
after the favicon line in both Preview and export.

Refs #54
2026-10-07 12:05:28 -07:00
shadowdaoandClaude Sonnet 5.5 a9c8f4d65a feat(site-builder): version history modal with preview and restore
Adds a site.history command (WHP mode, only when history_list answers) opening
a modal of saves/publishes by day. Preview opens the snapshot re-exported with
its own design; Restore site / Restore one page load the snapshot as unsaved
state (history cleared, dirty marked) so the user still clicks Save.

Refs #51

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:04:17 -07:00
shadowdaoandClaude Sonnet 5.5 0bd6b74ba5 feat(site-builder): copy/paste style and saved style presets
Refs #48

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:03:27 -07:00
shadowdaoandClaude Sonnet 5.5 a80667dfe6 feat(site-builder): multi-select with bulk styling and mixed-type actions
Shift/cmd/ctrl-click multi-select via DefaultEventHandlers, same-type bulk
styling as one undo step, mixed-type Delete/Duplicate/Move block, grouped
undo for array-aware edit.* commands.

Refs #50

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:03:26 -07:00
shadowdaoandClaude Opus 5.5 52477bff45 feat(site-builder): menus that follow pages, with dropdowns
- utils/nav-links.ts: shared NavLink type (source/pageId/children),
  pageHref, buildPageLinks, mergeLinks, adoptPageLinks, rewriteHeaderLinks
- PageData.nav {show, parentId, label} + updatePageNav; a nav-sync effect in
  PageProvider materialises page-following links into the stored header
  (or the live header nodes while it is being edited); string/identity
  guards keep it a no-op when nothing changed
- Navbar/Menu: followPages prop (default false; the default header seed is
  true), one-level dropdowns (hover/focus-within + inline click toggle,
  indented in the hamburger layout), hover/CTA colours default to the
  primary token
- NavStylePanel: Follow pages toggle (adopts matching manual links, keeps
  custom text as the page's menu label), read-only page rows with Hide from
  menu, sub-link editor for manual links, LinkPicker records pageId
- Page Settings: Show in menu / Menu label / Nest under; Pages panel badge
- useWhpApi: nav passes through pages_craft_state on save and load

Legacy navs (no followPages) are never rewritten.

Refs #53

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:03:16 -07:00
shadowdaoandClaude Sonnet 5.5 1512cb7645 feat(site-builder): Cmd+K command palette
Refs #49

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 12:03:07 -07:00
shadowdao 092c8f6747 feat(site-builder): drag padding handles on the canvas
Edge handles on a selected Section/Container/Columns write padding via the
per-device setter as one undo burst; Alt = opposite side, Shift = all four,
Ctrl/Cmd snaps to 8px, Escape cancels.

Refs #56
2026-10-07 12:02:32 -07:00
shadowdao 5430f13877 Merge issue-45 (Refs #45)
# Conflicts:
#	craft/src/panels/right/styles/ButtonStylePanel.tsx
#	craft/src/panels/right/styles/shared.tsx
#	craft/src/styles/editor.css
2026-10-07 11:58:40 -07:00
shadowdao 68a3734eaf Merge issue-47 (Refs #47)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 11:58:26 -07:00
shadowdao 2b41cd46ba Merge issue-39 (Refs #39)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 11:58:26 -07:00
shadowdao c0e0003460 feat(site-builder): asset search/filter, stock photo tab and background focal point
Search + type chips in the Assets panel and picker library; Stock photos
entry in the picker (feature-detected, hidden when stock_disabled/absent);
bgPosition focal point for Hero and Background Section.

Refs #55
2026-10-07 11:52:32 -07:00
shadowdaoandClaude Sonnet 5.5 6e819f1ef2 feat(site-builder): section library catalog, modal and insertion
Catalog skeleton with per-family files (one seed each for hero, services,
contact), live token-styled thumbnails, insert-after-selection, and
save-as-section into project extras.

Refs #52

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:52:25 -07:00
shadowdao c2a90cd7a7 feat(site-builder): tablet/mobile style overrides that never touch desktop
On tablet/mobile the useNodeProp style setters now route responsive keys
(spacing, font size, line height, letter spacing, alignment, size, flex
layout) into styleTablet/styleMobile; colours and other keys still write
style. An empty value removes the override. Continuous-burst keys include
the device so a desktop drag and a mobile drag never merge.

- shared.tsx: device-aware setters, new setResponsiveStyleProp /
  clearResponsiveStyleProp exports, setPropStylesContinuous
- responsive-panel.tsx: useResolvedStyle, useOverrideState, DeviceBanner
- OverrideDot: filled dot resets the override (one undo step), hollow dot
  marks an inherited value; wired into Text/Button/Container/Image/Media/
  BackgroundSection panels and both box-model sections
- Columns: "Stack on this device" toggle (flexDirection override)
- GuidedStyles: device banner under the type header
- RenderNode: every component node renders through one stable
  ResolvedRender so gaining/losing an override or switching device no
  longer remounts the node (the remount dropped inline-edit focus/caret
  and blanked a selected Heading)

Refs #45
2026-10-07 11:51:53 -07:00
shadowdao 2dd362e858 Merge issue-44 (Refs #44)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 11:47:58 -07:00
shadowdao c68e459430 feat(site-builder): complete shortcut set on the command registry with a cheat sheet
Core editor shortcuts become registry commands run by the single
useCommandShortcuts dispatcher: undo/redo, delete, duplicate (after +
select), copy/paste, Alt+arrow move, 1/2/3 device, Cmd+S/Shift+P/P site
commands and Cmd+/ cheat sheet. Tab/Esc no longer fire from buttons or
dialogs. Context menu labels come from formatShortcut.

Refs #39
2026-10-07 11:47:55 -07:00
shadowdao 98e32a68b9 Merge issue-46 (Refs #44 #46)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
#	craft/src/styles/editor.css
2026-10-07 11:47:54 -07:00
shadowdaoandClaude Sonnet 5.5 8edc426986 feat(site-builder): layers drag reorder, rename, hide/show, collapse
Refs #47

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:47:10 -07:00
shadowdao d8ff295093 fix(site-builder): rebuild editor.css after union merge interleaved #41/#34 regions 2026-10-07 11:42:32 -07:00
shadowdaoandClaude Opus 5.5 7e8812a752 feat(site-builder): inline bold/italic/underline/links on Heading and Text
Select text inside a selected Heading or Text block and a floating
toolbar offers B / I / U / Link / Unlink (execCommand; mousedown is
prevented so the selection survives; mod+b/i/u handled on the editable).

Storage: new `html` prop holding sanitised inline HTML, with `text` kept
as the plain mirror for AI summaries, search and legacy content.
Unmarked edits store html '' so legacy nodes keep their shape. The
allowlist (b strong i em u a br span; style=color only, hex/rgb/
var(--wsb-*); href via DOMPurify URI check AND safeUrl, unsafe links
unwrapped; target only _blank with forced rel=noopener) runs on commit,
on canvas render and again at export. If `text` was changed without
`html` (Sitesmith update_props), the stale html is ignored.

Each edit commits once (blur, or deselect if no blur came first) as one
setProp = one undo step; the old blur+deselect double commit is gone.
Heading colour default now tokenRef('text'). Sitesmith canvas summary
skips `html`.

Refs #46

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:41:56 -07:00
shadowdao 74df8a3b70 Merge issue-34 (Refs #34) 2026-10-07 11:41:22 -07:00
shadowdao d756a723de Merge issue-43 (Refs #43)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
2026-10-07 11:41:22 -07:00
shadowdao 817028df89 Merge issue-41 (Refs #41) 2026-10-07 11:40:54 -07:00
shadowdaoandClaude Sonnet 5.5 fad34f3e71 feat(site-builder): actionable empty canvas and inline add for empty containers
Refs #41

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:39:34 -07:00
shadowdao 22c59eb970 feat(site-builder): tablet/mobile canvas emulates published hide, stacking and full-width
Frame gets data-device; RenderNode mirrors hide flags and selection onto the
dom; editor.css emulates the exported breakpoints inside the narrowed frame.
Also: data-wsb-overridden counts only set values, responsive scope ids are
zone-prefixed (h-/b-/f-) so ROOT no longer collides, and comment delimiters
are stripped from responsive declarations.

Refs #37
2026-10-07 11:39:25 -07:00
shadowdaoandClaude Sonnet 5.5 af460f23e6 feat(site-builder): precise drop indicator with target glow and empty-container label
Restyle Craft's insertion bar via the Editor indicator prop and mirror the
live placement onto the DOM (data-drop-target/-error/-empty, is-dragging).

Refs #43

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:38:22 -07:00
shadowdao dd7a50cf3d feat(site-builder): token-aware colour controls and Try a palette
Colour controls offer the site palette first, show the resolved colour for
var(--wsb-*) values with a token chip, and keep the stored reference.
autoTextColor resolves tokens. Site Design gains six one-click palettes.

Refs #44
2026-10-07 11:38:17 -07:00
shadowdaoandClaude Sonnet 5.5 2a6055d863 feat(site-builder): selection breadcrumb, Esc selects parent, Tab cycles siblings
Refs #34

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:36:40 -07:00
shadowdao 136e3ce6ea fix(site-builder): restore closing brace lost in #36/#38 editor.css merge 2026-10-07 11:31:10 -07:00
shadowdao 1f5cac2cca Merge issue-38 (Refs #38)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 11:30:20 -07:00
shadowdao e5119174e7 feat(site-builder): Element/Site tabs in the right panel
Refs #36
2026-10-07 11:25:28 -07:00
shadowdao 7b082c8d2e feat(site-builder): searchable blocks panel, remembered collapse state and left tab
Refs #38
2026-10-07 11:23:00 -07:00
shadowdao 2180f9a776 Merge W0-registry-notices (Refs #38 #41 #49 #48 #57 #58)
# Conflicts:
#	craft/src/state/NoticeContext.tsx
#	craft/src/styles/editor.css
2026-10-07 11:20:30 -07:00
shadowdao ae871c9cdc Merge W0-commands (Refs #39 #49 #34)
# Conflicts:
#	craft/src/styles/editor.css
2026-10-07 11:20:25 -07:00
shadowdaoandClaude Opus 5.5 f8ac1fbe42 feat(site-builder): token module, canvas token variables, palette swatch row
Make var(--wsb-*) a first-class style value in the editor:

- utils/tokens.ts: TokenKey, TOKEN_VARS (moved from html-export.ts, same
  order/content as the backend), COLOR_TOKENS palette order, tokenRef,
  isTokenRef, tokenKeyOf, resolveTokenValue and buildCanvasTokenCss, which
  defines the 16 vars + token base CSS scoped to .canvas-device-frame
  (never :root) with every value through cssValue().
- editor/CanvasTokenStyle.tsx: <style data-wsb-canvas-tokens> driven by
  useSiteDesign(), mounted in App inside SiteDesignProvider, so design
  edits recolour token-backed values on the canvas instantly.
- panels/right/styles/TokenSwatchRow.tsx: palette-first swatch row that
  emits token references; .token-swatch styles appended to editor.css.
- html-export.ts imports TOKEN_VARS; export output pinned byte-identical
  to the pre-move baseline by hash in html-export.test.ts.

Refs #44

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:16:29 -07:00
shadowdaoandClaude Sonnet 5.5 73aa35ac96 feat(site-builder): command registry, shortcut matcher, tree walkers and top-bar command menu
Library only; nothing is mounted. Adds minimal DeviceContext/NoticeContext
stubs (owned by W0-breakpoints / W0-registry-notices) that expose the
agreed interfaces.

Refs #39 #49 #34

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:14:52 -07:00
shadowdaoandClaude Sonnet 5.5 21c2776c88 feat(site-builder): block registry, notices, local prefs, project extras, overlay slot
Add an exported block registry (keywords, search, insertBlock) consumed by
BlocksPanel, a NoticeProvider/NoticeHost toast stack, a guarded localStorage
prefs helper, a ProjectExtras store persisted as project.json 'extras', and a
CanvasOverlays mount point.

Refs #38
Refs #41
Refs #49
Refs #48
Refs #57
Refs #58

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 11:14:51 -07:00
shadowdaoandClaude Opus 5.5 97ccbee461 fix(site-builder): serialise all saves; honest pill for conflicts and new sites
A manual Save during Publish sent a second save with the same base_rev; the
loser 409'd against its own tab (and could abort the publish).

- useWhpApi: every save runs through one in-flight promise (SaveGuard
  saveInFlight). A save requested while one is out waits, then sends only
  if still dirty, with the rev the first returned; payload is read from the
  editor at send time. Forced (empty/overwrite) saves always send.
- Save buttons are disabled while publishing.
- Pill: a conflict reads 'Unsaved changes' (modal open) from Save and from
  Publish alike; a never-saved site (load rev null) reads 'Not saved yet'.
- Autosave interval reads runSave through a ref, so editing can't keep
  restarting it and starve autosave.
- Fix stale 'Throws like exportBodyHtml' comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:35:11 -07:00
shadowdaoandClaude Sonnet 5.5 a6db5438b2 feat(site-builder): detect two-tab save conflicts; Reload latest / Keep mine modal
Refs #31

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 10:19:07 -07:00
shadowdaoandClaude Sonnet 5.5 9418444916 fix(site-builder): honest save state (dirty tracking, status pill, beforeunload, error notice)
Track dirty from Craft node changes and page/design/header/footer state, cleared
only by a successful save. Persistent Unsaved/Saving/Saved/Published/Save failed
pill, beforeunload prompt while dirty or saving, one persistent error notice,
resp.ok/non-JSON handling for save and publish, and publish refuses to run
after a failed save. Draft badge no longer flips on a no-op autosave.

Refs #30

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-07 10:07:03 -07:00
shadowdao a406ff8548 fix(site-builder): fail load on unreadable page state; disable editing controls until loaded
Refs #28
2026-10-07 10:00:11 -07:00
shadowdao 66e669fa01 fix(site-builder): never save before a successful load; guard empty overwrites
Refs #28
2026-10-07 09:57:11 -07:00
shadowdaoandClaude Opus 5 2438777462 feat(site-builder): Layers shows array-prop items, unplaced nodes, and scrolls
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 07:15:17 -07:00