Commit Graph

4 Commits

Author SHA1 Message Date
shadowdao 88df4f2888 feat(builder): CodeMirror 6 code editor for HTML/CSS/JS with lazy loading
Replaces the plain single-line input (HtmlBlock's `code` prop, via
GenericPropsEditor) and the plain <textarea> (HeadCodeModal's site-wide
head code) with a proper syntax-highlighted, tab-completing code editor.

- New src/ui/CodeEditor.tsx: reusable CodeMirror 6 editor (state/view/
  commands/autocomplete/language/lang-html/lang-css/lang-javascript/
  theme-one-dark). All @codemirror/* packages are pulled in via a single
  dynamic import() inside the component so they land in separate lazy
  chunks instead of the main bundle -- confirmed via `npm run build`:
  main editor.js grew by only ~5.5KB (657KB -> 663KB raw) while ~570KB of
  CodeMirror source split into index*.js chunks that only load when a
  code editor modal is actually opened. While that import is in flight,
  or if it ever fails, the component renders a plain <textarea> so typing
  never breaks.
- GenericPropsEditor.tsx: special-cases the `code` prop (used only by
  HtmlBlock today) into an "Edit HTML" button that opens the CodeEditor
  in a modal (language="html"), instead of rendering it as a single-line
  text input alongside the component's other string props.
- HeadCodeModal.tsx: swaps its <textarea> for CodeEditor (language="html"
  -- head code is HTML with embedded <script>/<style>), keeping the
  existing SiteDesignContext.updateDesign({ headCode }) wiring.

GuidedStyles.tsx untouched: HtmlBlock's displayName ("HTML") already
matches GuidedStyles' `isUtility` regex and routes to GenericPropsEditor,
so no dispatcher change was needed.

HtmlBlock.tsx untouched: purifyHtml/toHtml sanitization is unchanged, as
specified. Skipped the optional AnimationControl/VisibilityControl
addition -- HtmlBlock has no dedicated StylePanel (it shares
GenericPropsEditor with Divider/Spacer/every unmatched type), and doing
it well would mean adding real Animation/Visibility widgets to that
shared editor for every consumer, which is a bigger change than "trivial"
for this package's scope.

Tests: CodeEditor.test.tsx and HeadCodeModal.test.tsx both exploit the
fact that dynamic import() always resolves on a later microtask, so
asserting against the DOM immediately after the initial synchronous
render deterministically exercises the <textarea> fallback path (value
display, onChange wiring, language prop plumbing) without needing to
mock @codemirror/*.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 06:42:59 -07:00
shadowdao 8f51b5144a refactor(builder): extract shared ArrayItemFieldsEditor from SectionTypePanel/GenericPropsEditor
Both panels had a ~90-line near-byte-identical per-item field editor
(boolean->checkbox, number->number, /color/->color, long->textarea, else
text, fields derived from Object.keys(items[0])). Moved into a new
ArrayItemFieldsEditor component in ArrayItemFields.tsx used by both.
SectionTypePanel keeps its own FeaturesGrid special-case (key === 'features'
-> FeaturesEditor) and its empty-array guard ahead of the shared call.
Behavior-preserving (task E4.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:15:34 -07:00
shadowdao 4733fe84b5 refactor(builder): extract useNodeProp hook, dedup StylePanel setProp boilerplate
Adopted in BackgroundSectionStylePanel, ButtonStylePanel, ContainerStylePanel,
FormStylePanel, GenericPropsEditor, HeroStylePanel, ImageStylePanel,
MediaStylePanel, NavStylePanel, SectionTypePanel, SocialStylePanel,
TextStylePanel — only where the inline setProp/setPropStyle were behaviorally
identical to the hook. PricingStylePanel and FeaturesEditor keep their own
array-mutation logic since it differs. Behavior-preserving (task E4.1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 15:13:35 -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