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>
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import React, { CSSProperties } from 'react';
|
||||
import { useNode, UserComponent } from '@craftjs/core';
|
||||
import { cssPropsToString } from '../../utils/style-helpers';
|
||||
import { CtaButton, CtasEditor, normalizeCtas, ctaInlineStyle, ctasToHtml } from './_cta-helpers';
|
||||
import { AnchorIdField } from '../../ui/AnchorIdField';
|
||||
import { CtaButton, normalizeCtas, ctaInlineStyle, ctasToHtml } from './_cta-helpers';
|
||||
import { escapeHtml, escapeAttr, safeUrl } from '../../utils/escape';
|
||||
|
||||
interface HeroProps {
|
||||
@@ -163,215 +162,6 @@ export const HeroSimple: UserComponent<HeroProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
/* ---------- Settings panel ---------- */
|
||||
|
||||
const inputStyle: React.CSSProperties = {
|
||||
width: '100%', padding: '6px 8px', background: '#27272a',
|
||||
color: '#e4e4e7', border: '1px solid #3f3f46', borderRadius: 4, fontSize: 12,
|
||||
};
|
||||
const labelStyle: React.CSSProperties = {
|
||||
fontSize: 11, color: '#a1a1aa', display: 'block', marginBottom: 4,
|
||||
};
|
||||
const btnStyle = (active: boolean): React.CSSProperties => ({
|
||||
flex: 1, padding: '6px 4px', fontSize: 11, borderRadius: 4, cursor: 'pointer',
|
||||
border: '1px solid #3f3f46',
|
||||
background: active ? '#3b82f6' : '#27272a',
|
||||
color: active ? '#fff' : '#a1a1aa',
|
||||
fontWeight: active ? 600 : 400,
|
||||
});
|
||||
|
||||
const HeroSettings: React.FC = () => {
|
||||
const { actions: { setProp }, props } = useNode((node) => ({
|
||||
props: node.data.props as HeroProps,
|
||||
}));
|
||||
|
||||
const effectiveCtas = normalizeCtas(props);
|
||||
|
||||
return (
|
||||
<div style={{ padding: 12, display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
<AnchorIdField />
|
||||
{/* Content */}
|
||||
<div>
|
||||
<label style={labelStyle}>Heading</label>
|
||||
<input type="text" value={props.heading || ''} onChange={(e) => setProp((p: HeroProps) => { p.heading = e.target.value; })} style={inputStyle} />
|
||||
</div>
|
||||
<div>
|
||||
<label style={labelStyle}>Subtitle</label>
|
||||
<textarea value={props.subtitle || ''} onChange={(e) => setProp((p: HeroProps) => { p.subtitle = e.target.value; })} rows={3} style={{ ...inputStyle, resize: 'vertical' as const }} />
|
||||
</div>
|
||||
|
||||
{/* Dynamic CTAs */}
|
||||
<CtasEditor
|
||||
ctas={effectiveCtas}
|
||||
onChange={(next) => setProp((p: HeroProps) => {
|
||||
p.ctas = next;
|
||||
// Once the user touches CTAs, the legacy fields are no longer
|
||||
// authoritative — clear them so the array is the only source.
|
||||
p.buttonText = undefined;
|
||||
p.buttonHref = undefined;
|
||||
p.secondaryButtonText = undefined;
|
||||
p.secondaryButtonHref = undefined;
|
||||
})}
|
||||
/>
|
||||
|
||||
{/* Background Type */}
|
||||
<div>
|
||||
<label style={labelStyle}>Background Type</label>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
{(['color', 'gradient', 'image', 'video'] as const).map((t) => (
|
||||
<button key={t} onClick={() => setProp((p: HeroProps) => { p.bgType = t; })}
|
||||
style={btnStyle(props.bgType === t)}>
|
||||
{t === 'color' ? 'Color' : t === 'gradient' ? 'Gradient' : t === 'image' ? 'Image' : 'Video'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Background controls based on type */}
|
||||
{props.bgType === 'color' && (
|
||||
<div>
|
||||
<label style={labelStyle}>Background Color</label>
|
||||
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
|
||||
<input type="color" value={props.bgColor || '#1e293b'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgColor = e.target.value; })}
|
||||
style={{ width: 36, height: 30, border: 'none', cursor: 'pointer', background: 'none' }} />
|
||||
<input type="text" value={props.bgColor || '#1e293b'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgColor = e.target.value; })}
|
||||
style={{ ...inputStyle, flex: 1 }} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.bgType === 'gradient' && (
|
||||
<>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<label style={labelStyle}>From</label>
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
<input type="color" value={props.bgGradientFrom || '#667eea'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgGradientFrom = e.target.value; })}
|
||||
style={{ width: 30, height: 26, border: 'none', cursor: 'pointer', background: 'none' }} />
|
||||
<input type="text" value={props.bgGradientFrom || '#667eea'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgGradientFrom = e.target.value; })}
|
||||
style={{ ...inputStyle, fontSize: 10 }} />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<label style={labelStyle}>To</label>
|
||||
<div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||
<input type="color" value={props.bgGradientTo || '#764ba2'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgGradientTo = e.target.value; })}
|
||||
style={{ width: 30, height: 26, border: 'none', cursor: 'pointer', background: 'none' }} />
|
||||
<input type="text" value={props.bgGradientTo || '#764ba2'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgGradientTo = e.target.value; })}
|
||||
style={{ ...inputStyle, fontSize: 10 }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label style={labelStyle}>Angle: {props.bgGradientAngle || 135}°</label>
|
||||
<input type="range" min={0} max={360} value={props.bgGradientAngle || 135}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgGradientAngle = parseInt(e.target.value); })}
|
||||
style={{ width: '100%' }} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{props.bgType === 'image' && (
|
||||
<div>
|
||||
<label style={labelStyle}>Background Image URL</label>
|
||||
<input type="text" value={props.bgImage || ''} placeholder="https://..."
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgImage = e.target.value; })} style={inputStyle} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.bgType === 'video' && (
|
||||
<div>
|
||||
<label style={labelStyle}>Background Video URL</label>
|
||||
<input type="text" value={props.bgVideo || ''} placeholder="https://...mp4"
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.bgVideo = e.target.value; })} style={inputStyle} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Overlay */}
|
||||
{(props.bgType === 'image' || props.bgType === 'video') && (
|
||||
<div>
|
||||
<label style={labelStyle}>Overlay ({props.overlayOpacity || 0}%)</label>
|
||||
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
|
||||
<input type="color" value={props.overlayColor || '#000000'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.overlayColor = e.target.value; })}
|
||||
style={{ width: 30, height: 26, border: 'none', cursor: 'pointer', background: 'none' }} />
|
||||
<input type="range" min={0} max={100} value={props.overlayOpacity || 0}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.overlayOpacity = parseInt(e.target.value); })}
|
||||
style={{ flex: 1 }} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Text & Button Colors */}
|
||||
<div>
|
||||
<label style={labelStyle}>Text Color</label>
|
||||
<div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
|
||||
<input type="color" value={props.textColor || '#ffffff'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.textColor = e.target.value; })}
|
||||
style={{ width: 36, height: 30, border: 'none', cursor: 'pointer', background: 'none' }} />
|
||||
<input type="text" value={props.textColor || '#ffffff'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.textColor = e.target.value; })}
|
||||
style={{ ...inputStyle, flex: 1 }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<label style={labelStyle}>Button BG</label>
|
||||
<input type="color" value={props.buttonBgColor || '#3b82f6'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.buttonBgColor = e.target.value; })}
|
||||
style={{ width: '100%', height: 30, border: '1px solid #3f3f46', borderRadius: 4, cursor: 'pointer' }} />
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<label style={labelStyle}>Button Text</label>
|
||||
<input type="color" value={props.buttonTextColor || '#ffffff'}
|
||||
onChange={(e) => setProp((p: HeroProps) => { p.buttonTextColor = e.target.value; })}
|
||||
style={{ width: '100%', height: 30, border: '1px solid #3f3f46', borderRadius: 4, cursor: 'pointer' }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Layout */}
|
||||
<div>
|
||||
<label style={labelStyle}>Min Height</label>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
{['300px', '400px', '500px', '600px', '100vh'].map((h) => (
|
||||
<button key={h} onClick={() => setProp((p: HeroProps) => { p.minHeight = h; })}
|
||||
style={btnStyle(props.minHeight === h)}>{h === '100vh' ? 'Full' : h}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={labelStyle}>Vertical Align</label>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
{(['top', 'center', 'bottom'] as const).map((v) => (
|
||||
<button key={v} onClick={() => setProp((p: HeroProps) => { p.verticalAlign = v; })}
|
||||
style={btnStyle(props.verticalAlign === v)}>{v}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label style={labelStyle}>Text Align</label>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
{(['left', 'center', 'right'] as const).map((a) => (
|
||||
<button key={a} onClick={() => setProp((p: HeroProps) => { p.textAlign = a; })}
|
||||
style={btnStyle(props.textAlign === a)}>
|
||||
<i className={`fa fa-align-${a}`} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/* ---------- Craft config ---------- */
|
||||
|
||||
HeroSimple.craft = {
|
||||
@@ -405,9 +195,6 @@ HeroSimple.craft = {
|
||||
canMoveIn: () => false,
|
||||
canMoveOut: () => true,
|
||||
},
|
||||
related: {
|
||||
settings: HeroSettings,
|
||||
},
|
||||
};
|
||||
|
||||
/* ---------- HTML export ---------- */
|
||||
|
||||
Reference in New Issue
Block a user