Commit Graph

9 Commits

Author SHA1 Message Date
shadowdao 65a10a1ef9 refactor(builder): remove dead component settings UI
Each component defined a .craft.related.settings panel that was never
rendered -- the right panel renders only GuidedStyles (per-type
*StylePanel components), never .related.settings. Removed all dead
settings components across every component, their settings-only helpers
(including the dead uploadToWhp/showBrowser/handleBrowse asset-browse
blocks in Logo/Navbar/VideoBlock/FeaturesGrid, and CtasEditor in
_cta-helpers), and dropped the now-empty related keys. Render output,
.craft props/rules, and toHtml statics are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 13:16:53 -07:00
shadowdao 7179287087 fix(builder): sanitize HtmlBlock/Countdown/Gallery JS contexts
Entity-escaping alone doesn't protect JS-string or raw-HTML sinks:

- HtmlBlock.toHtml exported props.code raw; now runs it through the
  same purifyHtml (DOMPurify) config already used for the live editor
  preview, so <script>/on*= payloads can't survive export either.
- Countdown.toHtml interpolated targetDate directly into
  `new Date("${targetDate}")` inside an inline <script> -- a value
  like `2026-01-01");alert(1)//` broke out of the string literal. Now
  validated against a strict date/datetime shape and JSON.stringify'd
  before embedding, falling back to `new Date()` for anything invalid.
- Gallery.toHtml's lightbox used
  `onclick="${id}_open('${esc(img.src)}')"`, which a single quote in
  img.src could break out of. Replaced with a `data-lb-src` attribute
  per thumbnail and one delegated click listener on the grid
  (`e.target.closest('[data-lb-src]')`) instead of a per-item inline
  handler string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 12:06:07 -07:00
shadowdao 48d0441be3 fix(builder): neutralize javascript:/breakout URLs in export
Every user-controlled URL emitted by a component's static toHtml (href,
src, action, and CSS url()) now runs through escapeAttr(safeUrl(...))
before hitting the exported HTML string, closing the XSS gaps flagged
in the A2 review (PricingTable buttonHref was fully unescaped, Gallery/
HeroSimple/ImageBlock/VideoBlock/etc. lacked scheme filtering) plus a
few more found via a grep sweep of href=/src=/action=/url( inside
toHtml template strings: MapEmbed's iframe src and the shared
form-relay-wiring fallback form action (a javascript: form action
executes on submit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 12:05:57 -07:00
shadowdao fad1882117 refactor(builder): use shared escaper everywhere, drop 26 local copies
Replace divergent, buggy local esc/escapeHtml helpers across 26 files with
imports from src/utils/escape (escapeHtml/escapeAttr). Attribute call sites use
escapeAttr, text-content sites use escapeHtml. Several toHtml outputs now
correctly escape & where old local escapers omitted it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 11:49:10 -07:00
shadowdao 53c40f856f site-builder: feedback batch (social, features, header menu, spacer)
Five of six items from user feedback (Contact Form email delivery split
into a focused, live-tested follow-up):

- Social Links: add Spotify + Twitch (FA 4.7.0 already ships both glyphs).
- Features Grid: per-feature icon/image toggle (upload + URL) and an
  optional button (text + url); render, settings, and HTML export updated,
  backward compatible with existing icon-only features.
- Header: seed the default header with a Navbar (logo + Home/About/Services/
  Contact) so new sites open with an editable menu-with-links instead of an
  empty header zone. Adds a vitest guard that the seed deserializes and
  exports a real <nav>.
- Canvas: slim the empty header/footer placeholder from a padded band to a
  thin hint line so an empty zone no longer reads as a stray spacer.

Design spec: docs/superpowers/specs/2026-07-06-site-builder-feedback-batch-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 17:53:22 -07:00
shadowdao 906695379b sitesmith: null-safe esc() in Navbar/Menu/Logo + clear chat button
The prior null-safe esc patch only matched 'const esc =' declarations;
Menu/Navbar/Logo use 'function esc(str: string)' syntax and slipped
through. Patched those three to coerce non-strings the same way.

Added "Clear chat" button in the modal header that appears when there's
any message history. Confirms with the user before posting to the new
clear_history endpoint, which deletes all messages + the thread row
for the current site (usage rows are preserved for billing).
2026-05-24 16:03:02 -07:00
shadowdao 069ea1235a sitesmith: null-safe esc() across all toHtml + WorkingIndicator
Real-world AI output frequently sends mismatched prop names (e.g.
items vs features, cta object vs buttonText/Href). The toHtml functions
of section/form/sections-folder components each defined a local
esc = (s: string) => s.replace(...) that crashed when called with
undefined, taking the auto-save export with it.

Patched every local esc() to coerce non-strings:
  const esc = (s: any) => String(s ?? "").replace(...)
17 files touched; behavior unchanged for valid string inputs.

Also adds a WorkingIndicator (Claude Code-style spinner + rotating
phrase + elapsed seconds) shown in the modal footer while a generation
is in flight, replacing the disabled "Thinking..." placeholder.
2026-05-24 15:54:48 -07:00
shadowdao bd15a33984 sitesmith: harden HtmlBlock with DOMPurify + add Vitest setup
Closes XSS hole in HtmlBlock by sanitizing user/AI-supplied markup
through DOMPurify before passing to dangerouslySetInnerHTML. Adds
Vitest + jsdom for unit testing with 5 passing tests covering script
stripping, on-event handler removal, javascript: URL blocking, iframe
allowlist, and form/input stripping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:13:42 -07:00
shadowdao 91a6b6f34b Add Craft.js site builder (v2) - complete rebuild from GrapesJS
Rebuilt the visual site builder from scratch using Craft.js, React 18,
and TypeScript. The new editor renders directly in the DOM (no iframe),
supports 40+ components, multi-page with shared header/footer, 16
templates, full-spectrum color/gradient controls, custom head code
injection, save/publish workflow, and auto-save.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:31:16 -07:00