2026-07-12 15:13:35 -07:00
import React from 'react' ;
2026-04-05 18:31:16 -07:00
import { useEditor } from '@craftjs/core' ;
import {
BG_COLORS ,
SPACING_PRESETS ,
RADIUS_PRESETS ,
} from '../../../constants/presets' ;
import {
StylePanelProps ,
SectionLabel ,
ColorSwatchGrid ,
PresetButtonGrid ,
CollapsibleSection ,
ColorPickerField ,
ArrayPropEditor ,
labelStyle ,
inputStyle ,
smallInputStyle ,
sectionGap ,
2026-07-12 15:13:35 -07:00
useNodeProp ,
2026-04-05 18:31:16 -07:00
} from './shared' ;
2026-07-12 13:00:10 -07:00
import { AssetPicker } from '../../../ui/AssetPicker' ;
2026-04-05 18:31:16 -07:00
/* ---------- MEDIA (Video / Gallery / Map / Slider) ---------- */
export const MediaStylePanel : React.FC < StylePanelProps > = ({ selectedId , nodeProps }) => {
const { actions } = useEditor ();
2026-07-12 15:13:35 -07:00
const { setProp , setPropStyle } = useNodeProp ( selectedId );
2026-04-05 18:31:16 -07:00
const style = nodeProps . style || {};
return (
<>
{ /* Video URL */ }
{ nodeProps . videoUrl !== undefined && (
< div style = { sectionGap }>
< label style = { labelStyle }> Video URL </ label >
< input type = "text" value = { nodeProps . videoUrl || '' } onChange = {( e ) => setProp ( 'videoUrl' , e . target . value )} placeholder = "YouTube, Vimeo, or .mp4 URL" style = { inputStyle } />
</ div >
)}
{ /* Map URL */ }
{ nodeProps . embedUrl !== undefined && nodeProps . videoUrl === undefined && (
< div style = { sectionGap }>
< label style = { labelStyle }> Embed URL </ label >
< input type = "text" value = { nodeProps . embedUrl || '' } onChange = {( e ) => setProp ( 'embedUrl' , e . target . value )} placeholder = "Google Maps embed URL" style = { inputStyle } />
</ div >
)}
{ /* Map address */ }
{ nodeProps . address !== undefined && (
< div style = { sectionGap }>
< label style = { labelStyle }> Address </ label >
< input type = "text" value = { nodeProps . address || '' } onChange = {( e ) => setProp ( 'address' , e . target . value )} placeholder = "123 Main St..." style = { inputStyle } />
</ div >
)}
{ /* Video options */ }
{ nodeProps . autoplay !== undefined && (
< div style = { sectionGap }>
< label style = {{ ... labelStyle , display : 'flex' , alignItems : 'center' , gap : 6 , cursor : 'pointer' }}>
< input type = "checkbox" checked = { nodeProps . autoplay || false } onChange = {( e ) => setProp ( 'autoplay' , e . target . checked )} />
Autoplay
</ label >
</ div >
)}
{ nodeProps . loop !== undefined && (
< div style = { sectionGap }>
< label style = {{ ... labelStyle , display : 'flex' , alignItems : 'center' , gap : 6 , cursor : 'pointer' }}>
< input type = "checkbox" checked = { nodeProps . loop || false } onChange = {( e ) => setProp ( 'loop' , e . target . checked )} />
Loop
</ label >
</ div >
)}
{ nodeProps . controls !== undefined && (
< div style = { sectionGap }>
< label style = {{ ... labelStyle , display : 'flex' , alignItems : 'center' , gap : 6 , cursor : 'pointer' }}>
< input type = "checkbox" checked = { nodeProps . controls !== false } onChange = {( e ) => setProp ( 'controls' , e . target . checked )} />
Show Controls
</ label >
</ div >
)}
{ /* Gallery items */ }
{ nodeProps . images !== undefined && Array . isArray ( nodeProps . images ) && (
< CollapsibleSection title = "Images" >
< ArrayPropEditor
selectedId = { selectedId }
propKey = "images"
items = { nodeProps . images }
renderItem = {( item : any , index : number ) => (
< div style = {{ display : 'flex' , flexDirection : 'column' , gap : 3 }}>
{ item . src !== undefined && (
2026-07-12 13:00:10 -07:00
< AssetPicker
variant = "compact"
value = { item . src || '' }
onChange = {( url ) => {
actions . setProp ( selectedId , ( props : any ) => {
const updated = [...( props . images || [])];
updated [ index ] = { ... updated [ index ], src : url };
props . images = updated ;
});
}}
/>
2026-04-05 18:31:16 -07:00
)}
{ item . caption !== undefined && (
< input type = "text" value = { item . caption || '' } onChange = {( e ) => {
actions . setProp ( selectedId , ( props : any ) => {
const updated = [...( props . images || [])];
updated [ index ] = { ... updated [ index ], caption : e.target.value };
props . images = updated ;
});
}} placeholder = "Caption" style = { smallInputStyle } />
)}
</ div >
)}
emptyItem = {{ src : '' , caption : '' }}
/>
</ CollapsibleSection >
)}
{ /* Slides */ }
{ nodeProps . slides !== undefined && Array . isArray ( nodeProps . slides ) && (
< CollapsibleSection title = "Slides" >
< ArrayPropEditor
selectedId = { selectedId }
propKey = "slides"
items = { nodeProps . slides }
renderItem = {( item : any , index : number ) => (
< div style = {{ display : 'flex' , flexDirection : 'column' , gap : 3 }}>
{ item . heading !== undefined && (
< input type = "text" value = { item . heading || '' } onChange = {( e ) => {
actions . setProp ( selectedId , ( props : any ) => {
const updated = [...( props . slides || [])];
updated [ index ] = { ... updated [ index ], heading : e.target.value };
props . slides = updated ;
});
}} placeholder = "Heading" style = { smallInputStyle } />
)}
{ item . text !== undefined && (
< textarea value = { item . text || '' } onChange = {( e ) => {
actions . setProp ( selectedId , ( props : any ) => {
const updated = [...( props . slides || [])];
updated [ index ] = { ... updated [ index ], text : e.target.value };
props . slides = updated ;
});
}} placeholder = "Text" rows = { 2 } style = {{ ... smallInputStyle , resize : 'vertical' }} />
)}
{ item . image !== undefined && (
2026-07-12 13:00:10 -07:00
< AssetPicker
variant = "compact"
value = { item . image || '' }
onChange = {( url ) => {
actions . setProp ( selectedId , ( props : any ) => {
const updated = [...( props . slides || [])];
updated [ index ] = { ... updated [ index ], image : url };
props . slides = updated ;
});
}}
/>
2026-04-05 18:31:16 -07:00
)}
</ div >
)}
emptyItem = {{ heading : 'New Slide' , text : '' , image : '' }}
/>
</ CollapsibleSection >
)}
{ /* Overlay */ }
{ nodeProps . overlayColor !== undefined && (
< CollapsibleSection title = "Overlay" defaultOpen = { false }>
< ColorPickerField label = "Color" value = { nodeProps . overlayColor || '#000000' } onChange = {( v ) => setProp ( 'overlayColor' , v )} />
{ nodeProps . overlayOpacity !== undefined && (
< div style = { sectionGap }>
< label style = { labelStyle }> Opacity : { nodeProps . overlayOpacity ?? 0 } % </ label >
< input type = "range" min = { 0 } max = { 100 } value = { nodeProps . overlayOpacity ?? 0 } onChange = {( e ) => setProp ( 'overlayOpacity' , parseInt ( e . target . value ))} style = {{ width : '100%' }} />
</ div >
)}
</ CollapsibleSection >
)}
{ /* Background & padding */ }
< CollapsibleSection title = "Style" defaultOpen = { false }>
< div className = "guided-section" >
< SectionLabel > Background </ SectionLabel >
< ColorSwatchGrid colors = { BG_COLORS } activeValue = { style . backgroundColor } onSelect = {( v : string ) => setPropStyle ( 'backgroundColor' , v )} />
</ div >
< div className = "guided-section" >
< SectionLabel > Padding </ SectionLabel >
< PresetButtonGrid presets = { SPACING_PRESETS } activeValue = { style . padding as string } onSelect = {( v ) => setPropStyle ( 'padding' , v )} />
</ div >
< div className = "guided-section" >
< SectionLabel > Border Radius </ SectionLabel >
< PresetButtonGrid presets = { RADIUS_PRESETS } activeValue = { style . borderRadius as string } onSelect = {( v ) => setPropStyle ( 'borderRadius' , v )} />
</ div >
</ CollapsibleSection >
</>
);
};