Makes the Craft.js editor usable on phones (≤768px) without touching desktop
layout/behavior: a useIsMobile() hook gates a bottom tab bar + sheets (hosting
the existing Blocks/Pages/Layers/Assets/Styles panels unchanged) in place of
the side panels, a collapsed TopBar with a "..." overflow menu, 44px touch
targets, 16px inputs, dvh/safe-area-aware sizing, and small copy/overflow
fixes (empty-canvas hint, Templates modal tabs + close button).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- PagesPanel: add fa-home glyph (8px, inherits badge text color) before
"Landing" text in the landing-page badge, restoring the icon dropped
in an earlier polish pass.
- editor.css: split [data-craft-hovered] and [data-layer-hovered] into
distinct rules. Layer-hover now uses a solid 2px accent outline (vs
the dashed structural guides) and is excluded from the .guides-off
suppression list, so the Layers-panel hover->canvas locator still
works when "Show guides" is off. Structural guides/hover
([data-craft-node], [data-craft-hovered]) remain correctly gated.
- Canvas.tsx: move the header/footer ZonePreview separator border to a
.zone-preview-sep class, recolor it from amber
(rgba(245,158,11,0.3)) to neutral (rgba(148,163,184,0.25)) to match
the empty-state variant, and gate it on .guides-off via CSS
descendant selector so it disappears with the rest of the guides.
Item 10: dashed canvas "guide" outlines were applied via blanket tag
selectors (div/section/header/...), so a finished section showed 3-4
nested dashed boxes. RenderNode.tsx (the <Editor onRender> override) now
tags each Craft.js droppable container's real DOM node with a
`data-craft-node` attribute (node.data.isCanvas, excluding ROOT), and
editor.css's guide rules target that attribute instead — a component's own
internal wrapper markup is no longer mistaken for a drop target. Added a
"Show guides" topbar toggle (default ON, persisted to localStorage),
state lifted in EditorShell.tsx (mirrors how `device` is already lifted),
flips `.guides-off` on Canvas.tsx's `.canvas-device-frame`.
Item 12: Layers panel rows get per-type FA icons (keyed off the same
craft.displayName used for the row label, seeded from BlocksPanel's
choices), indent-guide lines connecting nested rows, and row hover
highlights the matching canvas element (`data-layer-hovered`, written
directly to the node's DOM via `query.node(id).get().dom` — NOT via
`actions.setNodeEvent`, which is stripped from useEditor()'s public
`actions` at runtime, not just in its TS type, and threw when called).
Along the way, Craft.js's own connect() was found to already wire mouse
hover to the same `hovered` node event internally (previously invisible
because the matching CSS was dead) — RenderNode now also mirrors that
onto `data-craft-hovered` for a real-mouse-hover canvas highlight, and
both hover attributes plus the guide attribute are suppressed under
`.guides-off` so the toggle stays airtight.
Item 13: unified the topbar to one button radius (`.topbar-btn` 20px pill
-> var(--radius-md)), demoted Code/Preview to icon-only with
`data-tooltip`. Fixed a latent bug the new tooltips exposed: `[data-tooltip]`
tooltips render above their trigger, but the topbar has no room above it
(`body { overflow: hidden }`) — added a `.topbar` override to render
those below instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.component-indicator existed in editor.css but was never rendered
anywhere. Add RenderNode.tsx as a Craft.js <Editor onRender> override
and wire it in App.tsx: for the currently-selected node (excluding
ROOT) it portals a floating badge showing the node's displayName plus
a "select parent" chevron wired to actions.selectNode(parentId). Every
other node's render passes through untouched (a Fragment, no extra
DOM), and the badge portals to document.body positioned via
getBoundingClientRect rather than wrapping nodes in extra DOM, so it
can't perturb canvas layout and never appears in toHtml export.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.empty-canvas-hint existed in editor.css but was never rendered
anywhere. Wire it up in Canvas.tsx: an EmptyCanvasHint component reads
Craft's ROOT node via useEditor and shows the hint once ROOT exists
with zero children, hiding again the instant something is dropped in
or while a drag is in progress. It's absolutely positioned over the
Frame with pointer-events: none so it never intercepts clicks/drops
meant for the underlying (empty) canvas -- scoped to regular page
editing only, not the header/footer editing mode.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>