Commit Graph
76 Commits
Author SHA1 Message Date
shadowdaoandClaude Sonnet 5.5 a20e728824 stock photos: short Pixabay licence reminder in the Stock tab
One line (no standalone resale; recognisable people / trademark limits) with a
link to the Pixabay licence summary, shown with the "Images by Pixabay" credit
in every Stock tab state. Craft unit test added.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185ukXgk6UunFCKyXqLe2Cq
2026-11-02 10:37:33 -08:00
shadowdaoandClaude Opus 5.5 ed50732d58 sitesmith: readable form inputs on dark sections + sRGB color-mix() in contrast repair
Eval 2026-11-01 (ttm-likes): a ContactForm on a dark band had dark typed text
and UA-grey placeholders on a color-mix() input surface, and its inputBorder
"1px solid X" came out as the invalid "1px solid 1px solid X".

- ContactForm: new inputTextColor prop (typed text); placeholders now follow
  the input's own text colour via a scoped form[data-wsb-form] ::placeholder
  rule (export + editor canvas); an inputBorder that is a whole border is used
  as-is. Without inputTextColor the legacy derivation is unchanged.
- contrast repair: resolves opaque color-mix(in srgb, A p%, B) surfaces (the
  brief prescribes these tints; translucent / other spaces stay unchecked),
  checks ContactForm labelColor against its section and the derived input text
  colour against an explicitly set inputBg, writing inputTextColor on failure.
- catalog generator: (rebased onto main 01a78c9, which already omits the
  clock-derived Countdown.targetDate default via VOLATILE_DEFAULTS + the
  date-frozen drift test; this commit's duplicate inline check was dropped.)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:43:01 -08:00
shadowdaoandClaude Opus 5.5 542f5efc78 Mobile guard: drop the HtmlBlock table rule; colour e2e baseline = first 2026.11.4-head commit
- Tables inside HtmlBlocks are left alone on phones: display:block (the only way to make one scroll)
  shrank a fitting width:100% table's rows from 349px to 77px at 390. Wide tables stay clipped as before.
  The <pre> rule (max-width:100%;overflow-x:auto, no display change) and the media rules stay.
- Browser suite: width:100% table still spans the screen (fails on cfeeef3's rule: first row 78px); the
  10-column bare table moved to htmlwide (clipped, page never scrolls sideways).
- e2e-color-system: default COLOR_BASE_COMMIT ab7a100 -> 69fd34b, the first commit with the 2026.11.4
  published head (ColumnLayout stacking + Navbar wrap) and none of the colour feature. ab7a100 predates
  that head, so check 5 failed on main itself. This branch's own head change (mobile guard) is folded back
  by exact string, asserted present once, before comparing, so the check still proves the colour feature
  changed nothing else. Passes on 69fd34b; fails (as it should) against ab7a100.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:16:53 -08:00
shadowdaoandClaude Opus 5.5 cfeeef37ce Mobile guard: HtmlBlock wrapper never gets a box; phone net is media + per-table/pre scroll only
Review of bb4fb75: overflow-x:auto on [data-wsb-html] forced overflow-y:auto (clipped dropdowns/shadows),
broke position:sticky inside customer HTML, and display:block!important merged multi-root blocks that are
direct flex/grid items. Now the wrapper stays display:contents on every viewport and no rule targets it;
at <=767px only its descendants are touched: media max-width:100% (img/video height:auto), and a table or
<pre> becomes its own sideways scroller (not when already inside an inline overflow wrapper). No
overflow-wrap:anywhere (it shrank min-content); body{overflow-wrap:break-word} inherits through the wrapper.
Deliberately wide customer markup (fixed widths, px grids) is clipped as before; the publish warning is
its guard, and its wording now says the excess is cut off. width= attributes are no longer flagged (they
size only media and tables, which the net handles). stripMediaBlocks lowercases once.

Browser suite: htmlblocks probes at every width (wrapper display:contents, sticky sticks, absolutely
positioned dropdown visible on top, multi-root block = separate flex items / grid cells, bare table
scrolls on its own); new htmlwide doc asserts wide blocks stay clipped and the page never scrolls sideways.
All probes fail on bb4fb75's net and pass now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:09:22 -08:00
shadowdaoandClaude Opus 5.5 bb4fb7548b Mobile guard: real-browser overflow suite, card-grid + HtmlBlock mobile hooks, wide custom HTML publish warning
- scripts/e2e-mobile-guard.mjs (npm run test:browser:mobile-guard): Chromium + Firefox at 360/390/768/1280 over
  exporter-built pages (navbar, columns, FeaturesGrid/Testimonials/NumberCounter/Gallery/Pricing/Reviews, big
  image, long word/URL, wide customer HtmlBlocks). Asserts body.scrollWidth and every visible box/text right edge
  (html,body{overflow-x:clip} hides overflow from documentElement.scrollWidth), stacking on phones, columns kept
  on tablet, navbar wrap, intentional overflow-x:auto still scrolls, and 1280 box + pixel identity with the hooks
  removed (optional cross-commit baseline).
- OLS home overflow was FeaturesGrid (inline repeat(3,1fr)), not an HtmlBlock. FeaturesGrid, Testimonials and
  NumberCounter grids carry data-wsb-grid; the <=767px head block makes them one column.
- HtmlBlock output is exported inside <div data-wsb-html style="display:contents"> (applied after attr
  injection, toHtml().html unchanged); on phones it becomes a max-width:100% sideways-scrolling box, media
  shrink, long words break. body{overflow-wrap:break-word} on phones. Navbar link wrap now up to 991px
  (8 links + long logo overflowed at 768).
- Head parity pins updated (mirror in WHP generateCompiledHTML); editor.css mirrors for the mobile frame.
- publish-checks: warn when an HtmlBlock's inline/<style> CSS sets widths, flex sizes or grids over 390px or a
  3+ column grid with no phone @media rule; says what is not checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:58:39 -08:00
shadowdaoandClaude Opus 5.5 6decf8cdb0 Merge feat/color-system into release/sitesmith-colors
Conflicts: package.json (kept both test:browser:mobile and the colour scripts);
head-parity test (kept E_icons from mobile-parity/main AND the E_brand_swatches /
F_swatches_no_brand cases from color-system; pinned bytes re-derived later
against the merged WHP script).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:54:46 -08:00
shadowdaoandClaude Sonnet 5.5 2e5492600e Editor: mirror default mobile column stacking (canvas emulation + Stack toggle)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:10:15 -08:00
shadowdaoandClaude Sonnet 5.5 c34690d08b Colour fields: hex validation, brand chips, pick tools, save colour, inline contrast prop; gradient parse accepts brand refs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:58:55 -08:00
shadowdaoandClaude Sonnet 5.5 150c84065b TokenSwatchRow: saved colours after the site tokens (brand = live ring + token ref)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:57:17 -08:00
shadowdaoandClaude Sonnet 5.5 dc415db2d3 fix(site-builder): editor canvas renders content with the published base reset
Published pages/Preview ship a head reset (*{margin:0;padding:0}, img block,
a inherit, body line-height 1.6 / #1f2937 / 16px); the editor canvas had none,
so h1-h6/p margins, line-height and inherited size/colour differed.

- editor.css: one commented block scoping the reset to .canvas-device-frame,
  every selector zero-specificity (:where) so inline styles / class rules win
  exactly as when published; editor chrome untouched (snapshot identical).
- tokens.ts: canvas heading/link token rules made zero-specificity too.
- utils/css-reset.ts: single source for the reset declarations (html-export
  imports it; test asserts byte-identity with the backend head and that the
  editor.css block carries the same declarations).
- scripts/e2e-canvas-parity.mjs (npm run test:browser:canvas): real editor vs
  published HTML in Firefox + Chromium, boxes within 1px + computed styles.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 08:23:19 -08:00
shadowdaoandClaude Opus 5.5 e20c604413 fix(editor): mobile column stacking follows the desktop style, as published
Published mobile stacking is the global RESPONSIVE_CSS rule matching the
DESKTOP inline style, so un-stacking Columns on mobile under a stacked tablet
(styleMobile.flexDirection 'row') publishes un-stacked. The editor's
device-emulation copy matched the resolved inline style and showed it stacked.
RenderNode now marks nodes with a flexDirection/display override with
data-wsb-base-stack (baseStacksOnMobile) and editor.css keys off it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:40:54 -07:00
shadowdaoandClaude Opus 5.5 9697dc95a3 feat(editor): wire business panel, section commands and Layers follow-ups
- GuidedStyles classifies Opening Hours / Call Bar / Reviews / Booking to
  BusinessStylePanel (#60) and shows a Regenerate button in the type
  header, hidden when edit.regenerate-section's when() is false (#58)
- LayersPanel TYPE_ICONS for the four business blocks (FA 4.7) (#60)
- Context menu entries 'Save as section…' and 'Regenerate this section'
  invoke site.save-as-section / edit.regenerate-section (#52, #58)
- commands: useCommandState(id) hook (registered/enabled/run)
- Layers: keep dropEffect 'move' on refused targets so drop fires and the
  refusal notice shows; renaming to the default name stores no
  custom.label (#47)

Refs #60
Refs #58
Refs #52
Refs #47

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:45:16 -07:00
shadowdaoandClaude Opus 5.5 dd8b99be06 feat(site-builder): reusable global sections with per-page overrides
Make a top-level section global (context menu), place instances from the
Section library's new Global tab, edit the master once in its own zone
("Editing global section" banner, Done - update N instances) and every
instance on every page/header/footer is rebuilt from it. Instances are real
inlined subtrees (custom.global on the root, custom.gkey on every node), so
export and published output are unchanged static HTML.

- utils/global-sections.ts: pure model (createMaster, instantiate,
  syncInstances, collectOverridesFromInstance, applyOverrides, detach,
  findInstanceRoot, master zone round trip). Unchanged input returns the
  identical string; sync keeps the instance root id and the instance's own
  inner ids per gkey.
- PageContext: __global__:<id> zone (editGlobal / finishGlobal); leaving it
  commits the master (rev + 1 only when it changed), syncs every stored
  slot and applies the sync to the returned-to canvas as ONE undo step.
- GlobalSectionsContext: makeGlobal / insertInstance / detach / setOverride
  / resetOverride / remove (refused while used), one undo step each.
- Inline text edits inside an instance record an override (text + html)
  via useGlobalOverrideCommit; GuidedStyles shows a Global section panel
  (Edit master, Detach, content override fields) instead of style panels.
- RenderNode: Global badge, dashed outline, lock icon on inner nodes.
- buildSavePayload: a master zone on the canvas is never saved into a page.

Refs #57

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:28:53 -07:00
shadowdao edae0d6107 Merge issue-58-fe (Refs #58)
# Conflicts:
#	craft/src/editor/CanvasOverlays.tsx
#	craft/src/styles/editor.css
2026-10-07 12:09:09 -07:00
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
shadowdaoandClaude Sonnet 5.5 220f560972 feat(site-builder): Sitesmith business profile wizard and one-click section regenerate
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>
2026-10-07 11:55:33 -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