site-builder: dynamic CTAs, section anchors, edit-with-Sitesmith
Three related features: 1. Dynamic CTA buttons on HeroSimple, CTASection, CallToAction. New shared ctas[] array (text + href + variant + target) replaces the primary/secondary pair. Settings panel gets add/remove/reorder controls. Legacy fields stay readable for backwards compat — first user edit migrates the section onto the new array. 2. Anchor IDs on all layout/section components (Container, Section, BackgroundSection, ColumnLayout, plus 6 section blocks done by parallel subagent, plus Hero/CTA/CallToAction). Anchor input lives in the settings panel with an "auto from heading" button that walks the subtree for the first Heading.text. Renders as id="..." on the outermost element so #anchor URLs resolve. 3. Edit-with-Sitesmith targeted invocation. Right-click → "Ask Sitesmith" and a button at the top of the right-side settings panel both open the modal pre-targeted at the selected node. The node's serialized subtree is sent to the server; system prompt is augmented to require a patch with replace_node. Editor lifts modal state into a new SitesmithContext. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,8 @@ import React from 'react';
|
||||
import { useEditor } from '@craftjs/core';
|
||||
import { componentResolver } from '../../components/resolver';
|
||||
import { SiteDesignPanel } from './SiteDesignPanel';
|
||||
import { useSitesmithModal } from '../../state/SitesmithContext';
|
||||
import { buildSitesmithTarget } from '../../utils/sitesmith-target';
|
||||
import {
|
||||
TextStylePanel,
|
||||
ButtonStylePanel,
|
||||
@@ -30,6 +32,8 @@ import {
|
||||
|
||||
export const GuidedStyles: React.FC = () => {
|
||||
const resolverMap = componentResolver as Record<string, any>;
|
||||
const { open: openSitesmith } = useSitesmithModal();
|
||||
const { query } = useEditor();
|
||||
|
||||
const { selected, selectedType, nodeProps, resolvedName } = useEditor((state) => {
|
||||
const currentNodeId = state.events.selected
|
||||
@@ -97,14 +101,33 @@ export const GuidedStyles: React.FC = () => {
|
||||
: isUtility ? 'fa-ellipsis-h'
|
||||
: 'fa-cube';
|
||||
|
||||
const handleAskSitesmith = () => {
|
||||
if (!selected || selected === 'ROOT') return;
|
||||
const target = buildSitesmithTarget(query, selected);
|
||||
if (target) openSitesmith(target);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="guided-styles">
|
||||
{/* Component type badge */}
|
||||
<div className="guided-section guided-type-header">
|
||||
<span className="guided-type-badge">
|
||||
{/* Component type badge + Sitesmith shortcut */}
|
||||
<div className="guided-section guided-type-header" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<span className="guided-type-badge" style={{ flex: 1 }}>
|
||||
<i className={`fa ${typeIcon}`} />
|
||||
{' '}{typeName}
|
||||
</span>
|
||||
<button
|
||||
onClick={handleAskSitesmith}
|
||||
title="Ask Sitesmith to edit this block"
|
||||
style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 4,
|
||||
padding: '4px 8px', fontSize: 11, fontWeight: 600,
|
||||
color: '#a78bfa', background: 'rgba(139,92,246,0.12)',
|
||||
border: '1px solid rgba(139,92,246,0.4)',
|
||||
borderRadius: 'var(--radius-sm)', cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-magic" /> Ask Sitesmith
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* TEXT */}
|
||||
|
||||
Reference in New Issue
Block a user