2026-07-12 13:00:10 -07:00
import React , { useCallback } from 'react' ;
2026-04-05 18:31:16 -07:00
import { useEditor } from '@craftjs/core' ;
import {
StylePanelProps ,
CollapsibleSection ,
ColorPickerField ,
labelStyle ,
inputStyle ,
btnActiveStyle ,
sectionGap ,
} from './shared' ;
2026-07-12 13:00:10 -07:00
import { AssetPicker } from '../../../ui/AssetPicker' ;
2026-04-05 18:31:16 -07:00
/* ---------- HERO STYLE PANEL ---------- */
export const HeroStylePanel : React.FC < StylePanelProps > = ({ selectedId , nodeProps }) => {
const { actions } = useEditor ();
const setProp = useCallback (( key : string , value : any ) => {
actions . setProp ( selectedId , ( props : any ) => { props [ key ] = value ; });
}, [ actions , selectedId ]);
const bgType = nodeProps . bgType || 'color' ;
return (
<>
< CollapsibleSection title = "Content" >
< div style = { sectionGap }>
< label style = { labelStyle }> Heading </ label >
< input type = "text" value = { nodeProps . heading || '' } onChange = {( e ) => setProp ( 'heading' , e . target . value )} style = { inputStyle } />
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Subtitle </ label >
< textarea value = { nodeProps . subtitle || '' } onChange = {( e ) => setProp ( 'subtitle' , e . target . value )} rows = { 3 } style = {{ ... inputStyle , resize : 'vertical' as const }} />
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Button Text </ label >
< input type = "text" value = { nodeProps . buttonText || '' } onChange = {( e ) => setProp ( 'buttonText' , e . target . value )} style = { inputStyle } />
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Button URL </ label >
< input type = "text" value = { nodeProps . buttonHref || '' } onChange = {( e ) => setProp ( 'buttonHref' , e . target . value )} placeholder = "#" style = { inputStyle } />
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Secondary Button </ label >
< input type = "text" value = { nodeProps . secondaryButtonText || '' } onChange = {( e ) => setProp ( 'secondaryButtonText' , e . target . value )} placeholder = "Leave blank to hide" style = { inputStyle } />
</ div >
</ CollapsibleSection >
< CollapsibleSection title = "Background" >
< div style = { sectionGap }>
< label style = { labelStyle }> Type </ label >
< div style = {{ display : 'flex' , gap : 4 }}>
{([ 'color' , 'gradient' , 'image' , 'video' ] as const ). map (( t ) => (
< button key = { t } onClick = {() => setProp ( 'bgType' , t )} style = { btnActiveStyle ( bgType === t )}>
{ t . charAt ( 0 ). toUpperCase () + t . slice ( 1 )}
</ button >
))}
</ div >
</ div >
{ bgType === 'color' && (
< ColorPickerField label = "Color" value = { nodeProps . bgColor || '#1e293b' } onChange = {( v ) => setProp ( 'bgColor' , v )} />
)}
{ bgType === 'gradient' && (
<>
< div style = {{ display : 'flex' , gap : 8 , ... sectionGap }}>
< div style = {{ flex : 1 }}>
< ColorPickerField label = "From" value = { nodeProps . bgGradientFrom || '#667eea' } onChange = {( v ) => setProp ( 'bgGradientFrom' , v )} />
</ div >
< div style = {{ flex : 1 }}>
< ColorPickerField label = "To" value = { nodeProps . bgGradientTo || '#764ba2' } onChange = {( v ) => setProp ( 'bgGradientTo' , v )} />
</ div >
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Angle : { nodeProps . bgGradientAngle || 135 } ° </ label >
< input type = "range" min = { 0 } max = { 360 } value = { nodeProps . bgGradientAngle || 135 } onChange = {( e ) => setProp ( 'bgGradientAngle' , parseInt ( e . target . value ))} style = {{ width : '100%' }} />
</ div >
{ /* Gradient preview */ }
< div style = {{ height : 24 , borderRadius : 4 , background : `linear-gradient( ${ nodeProps . bgGradientAngle || 135 } deg, ${ nodeProps . bgGradientFrom || '#667eea' } , ${ nodeProps . bgGradientTo || '#764ba2' } )` , border : '1px solid #3f3f46' }} />
</>
)}
{ bgType === 'image' && (
< div style = { sectionGap }>
< label style = { labelStyle }> Background Image </ label >
2026-07-12 13:00:10 -07:00
< AssetPicker value = { nodeProps . bgImage || '' } onChange = {( url ) => setProp ( 'bgImage' , url )} variant = "full" />
2026-04-05 18:31:16 -07:00
</ div >
)}
{ bgType === 'video' && (
< div style = { sectionGap }>
< label style = { labelStyle }> Background Video </ label >
2026-07-12 13:00:10 -07:00
< AssetPicker
mediaType = "video"
variant = "full"
value = { nodeProps . bgVideo || '' }
onChange = {( url ) => setProp ( 'bgVideo' , url )}
placeholder = "YouTube, Vimeo, or .mp4 URL"
/>
2026-04-05 18:31:16 -07:00
</ div >
)}
< div style = { sectionGap }>
< label style = { labelStyle }> Overlay ({ nodeProps . overlayOpacity || 0 } % )</ label >
< div style = {{ display : 'flex' , gap : 6 , alignItems : 'center' }}>
< input type = "color" value = { nodeProps . overlayColor || '#000000' } onChange = {( e ) => setProp ( 'overlayColor' , e . target . value )} style = {{ width : 30 , height : 26 , border : 'none' , cursor : 'pointer' , background : 'none' }} />
< input type = "range" min = { 0 } max = { 100 } value = { nodeProps . overlayOpacity || 0 } onChange = {( e ) => setProp ( 'overlayOpacity' , parseInt ( e . target . value ))} style = {{ flex : 1 }} />
</ div >
</ div >
</ CollapsibleSection >
< CollapsibleSection title = "Colors" >
< ColorPickerField label = "Text Color" value = { nodeProps . textColor || '#ffffff' } onChange = {( v ) => setProp ( 'textColor' , v )} />
< div style = {{ display : 'flex' , gap : 8 , ... sectionGap }}>
< div style = {{ flex : 1 }}>
< ColorPickerField label = "Button BG" value = { nodeProps . buttonBgColor || '#3b82f6' } onChange = {( v ) => setProp ( 'buttonBgColor' , v )} />
</ div >
< div style = {{ flex : 1 }}>
< ColorPickerField label = "Button Text" value = { nodeProps . buttonTextColor || '#ffffff' } onChange = {( v ) => setProp ( 'buttonTextColor' , v )} />
</ div >
</ div >
</ CollapsibleSection >
< CollapsibleSection title = "Layout" >
< div style = { sectionGap }>
< label style = { labelStyle }> Minimum Height </ label >
< div style = {{ display : 'flex' , gap : 4 }}>
{[ '300px' , '400px' , '500px' , '600px' , '100vh' ]. map (( h ) => (
< button key = { h } onClick = {() => setProp ( 'minHeight' , h )} style = { btnActiveStyle ( nodeProps . minHeight === h )}>
{ h === '100vh' ? 'Full' : h }
</ button >
))}
</ div >
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Vertical </ label >
< div style = {{ display : 'flex' , gap : 4 }}>
{([ 'top' , 'center' , 'bottom' ] as const ). map (( v ) => (
< button key = { v } onClick = {() => setProp ( 'verticalAlign' , v )} style = { btnActiveStyle ( nodeProps . verticalAlign === v )}>{ v }</ button >
))}
</ div >
</ div >
< div style = { sectionGap }>
< label style = { labelStyle }> Text Align </ label >
< div style = {{ display : 'flex' , gap : 4 }}>
{([ 'left' , 'center' , 'right' ] as const ). map (( a ) => (
< button key = { a } onClick = {() => setProp ( 'textAlign' , a )} style = { btnActiveStyle ( nodeProps . textAlign === a )}>
< i className = { `fa fa-align- ${ a } ` } />
</ button >
))}
</ div >
</ div >
</ CollapsibleSection >
</>
);
};