import React from 'react'; import { useEditor } from '@craftjs/core'; import { BG_COLORS, SPACING_PRESETS, SHADOW_PRESETS, } from '../../../constants/presets'; import { StylePanelProps, SectionLabel, ColorSwatchGrid, PresetButtonGrid, CollapsibleSection, ColorPickerField, labelStyle, inputStyle, smallInputStyle, btnActiveStyle, sectionGap, useNodeProp, SpacingControl, BorderControl, BorderValue, buildBorderShorthand, AnimationControl, VisibilityControl, } from './shared'; /** Parses a border shorthand string ("2px solid #hex") produced by * buildBorderShorthand() back into its parts for round-tripping through * BorderControl. See SectionTypePanel.tsx for the identical helper. */ function parseBorderShorthand(v: string | undefined): BorderValue { if (!v || v === 'none') return { width: '', style: 'none', color: '#000000' }; const m = String(v).match(/^([\d.]+[a-z%]*)\s+(\w+)\s+(.+)$/); if (!m) return { width: '', style: 'none', color: '#000000' }; return { width: m[1], style: m[2], color: m[3] }; } const capSide = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1); const ICON_SHAPES = [ { label: 'None', value: 'none' }, { label: 'Circle', value: 'circle' }, { label: 'Square', value: 'square' }, { label: 'Rounded', value: 'rounded' }, ]; /* ---------- SOCIAL / ICON / STAR RATING ---------- */ export const SocialStylePanel: React.FC = ({ selectedId, nodeProps }) => { const { actions } = useEditor(); const { setProp, setPropStyle } = useNodeProp(selectedId); const style = nodeProps.style || {}; return ( <> {/* Social Links list */} {nodeProps.links !== undefined && Array.isArray(nodeProps.links) && (
{(nodeProps.links || []).map((link: any, i: number) => (
{link.platform || 'link'} { actions.setProp(selectedId, (props: any) => { const updated = [...(props.links || [])]; updated[i] = { ...updated[i], url: e.target.value }; props.links = updated; }); }} placeholder="URL" style={{ ...smallInputStyle, flex: 1 }} />
))}
)} {/* Icon name */} {nodeProps.iconName !== undefined && (
setProp('iconName', e.target.value)} placeholder="fa-star" style={inputStyle} />
)} {nodeProps.icon !== undefined && typeof nodeProps.icon === 'string' && (
setProp('icon', e.target.value)} placeholder="fa-star or emoji" style={inputStyle} />
)} {/* Star rating */} {nodeProps.rating !== undefined && (
setProp('rating', parseFloat(e.target.value))} style={{ width: '100%' }} />
)} {nodeProps.maxStars !== undefined && (
setProp('maxStars', parseInt(e.target.value) || 5)} style={inputStyle} />
)} {/* Icon shape (SocialLinks) -- exists on the component (iconShape prop drives the circle/square/rounded background box) but previously had no control. */} {nodeProps.iconShape !== undefined && (
{ICON_SHAPES.map((s) => ( ))}
)} {/* Gap between links (SocialLinks) -- exists on the component but previously had no control. */} {nodeProps.gap !== undefined && (
setProp('gap', e.target.value)} placeholder="10px" style={inputStyle} />
)} {/* Background shape / size / link (Icon component) -- bgColor, bgShape, bgSize, link all already exist on Icon.craft.props but had no control; the generic `color`/`iconColor` checks above never matched Icon's actual prop names. */} {nodeProps.bgShape !== undefined && (
{ICON_SHAPES.map((s) => ( ))}
)} {nodeProps.bgColor !== undefined && ( setProp('bgColor', v)} /> )} {nodeProps.bgSize !== undefined && (
setProp('bgSize', e.target.value)} placeholder="56px" style={inputStyle} />
)} {nodeProps.link !== undefined && (
setProp('link', e.target.value)} placeholder="https://..." style={inputStyle} />
)} {/* Star colors (StarRating) -- exist on the component as filledColor / emptyColor but had no control (the generic `starColor` check above never matched StarRating's actual prop names). */} {nodeProps.filledColor !== undefined && ( setProp('filledColor', v)} /> )} {nodeProps.emptyColor !== undefined && ( setProp('emptyColor', v)} /> )} {/* Colors */} {nodeProps.iconColor !== undefined && ( setProp('iconColor', v)} /> )} {nodeProps.iconBgColor !== undefined && ( setProp('iconBgColor', v)} /> )} {nodeProps.starColor !== undefined && ( setProp('starColor', v)} /> )} {nodeProps.color !== undefined && typeof nodeProps.color === 'string' && ( setProp('color', v)} /> )} {/* Size */} {nodeProps.iconSize !== undefined && (
setProp('iconSize', e.target.value)} style={inputStyle} />
)} {nodeProps.size !== undefined && typeof nodeProps.size === 'string' && (
setProp('size', e.target.value)} style={inputStyle} />
)} {/* Alignment */} {nodeProps.alignment !== undefined && (
{(['left', 'center', 'right'] as const).map((a) => ( ))}
)} {/* Background & padding */}
Background setPropStyle('backgroundColor', v)} />
Padding setPropStyle('padding', v)} />
{/* Box model: margin, padding (per-side), border, shadow, opacity */} setPropStyle(`margin${capSide(side)}`, v)} /> setPropStyle(`padding${capSide(side)}`, v)} /> setPropStyle('border', buildBorderShorthand(v))} />
Shadow setPropStyle('boxShadow', v)} />
Opacity setPropStyle('opacity', String(Number(e.target.value) / 100))} style={{ width: '100%' }} />
{/* Entrance animation */} { setProp('animation', v.animation); setProp('animationDelay', v.animationDelay); }} /> {/* Responsive visibility */} { setProp('hideOnDesktop', !!v.hideOnDesktop); setProp('hideOnTablet', !!v.hideOnTablet); setProp('hideOnMobile', !!v.hideOnMobile); }} /> ); };