Registers site.download-zip (WHP mode only; shows in the ⋯ menu and the
palette) via ExportCommand, mounted in CanvasOverlays. useSiteExport POSTs
?action=export_zip with the CSRF header: a zip answer is saved through a
Blob + anchor click, anything else (JSON error, older backend, network
failure, a stream cut short) becomes an error notice.
Refs #42
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Token-based sections (21 total across four families) with tests covering
insert, export (no stray hex, alt on images, relative links) and tree shape.
Refs #52
URL/anchor/tel/mailto edits from LinkPicker now go through
continuousSetProp (key link:<i>:href); a page pick stays a discrete
step via discreteSetProp. source/pageId stripping and the followPages
mergeLinks re-merge remain inside the updater.
Refs #53
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
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>
- 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>
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
SectionType, Social, Pricing, Form and the generic props editor already
wrote tablet/mobile overrides through the device-aware useNodeProp setters
but still read nodeProps.style, so a mobile padding/margin/alignment edit
looked like a no-op and had no reset dot. They now read useResolvedStyle()
and show OverrideDots on Padding, Margin and Text Alignment.
NavStylePanel has the same gap but is outside this task's files.
Refs #45
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5-step profile wizard (name/type, services, area, tone, palette preview) saved to
extras.sitesmithProfile and sent with every Sitesmith request. Regenerate this
section rewrites the selected block for the business as a single undo step.
Refs #58
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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
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>
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
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
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>
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
Palette and heading fonts become var(--wsb-*) refs; mutedTextColor added to
each template's design. Gradient companion stops stay hex.
Refs #44
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>