2026-07-12 13:00:10 -07:00
import React from 'react' ;
2026-07-07 17:19:37 -07:00
import { useEditor } from '@craftjs/core' ;
import { labelStyle , inputStyle , sectionGap } from './shared' ;
2026-07-12 13:00:10 -07:00
import { AssetPicker } from '../../../ui/AssetPicker' ;
2026-07-07 17:19:37 -07:00
interface Feature {
title? : string ; description? : string ; icon? : string ;
image? : string ; imageAlt? : string ; buttonText? : string ; buttonUrl? : string ;
}
/**
* Dedicated per-feature editor for the FeaturesGrid guided panel. Unlike the
* generic array editor (which only shows fields already present on the item),
* this always exposes icon / image (upload or URL) / button controls, so it
* works on template-created features that lack those keys. An image renders in
* place of the icon whenever `image` is set.
*/
export const FeaturesEditor : React.FC < { selectedId : string ; features : unknown } > = ({ selectedId , features }) => {
const { actions } = useEditor ();
const list : Feature [] = Array . isArray ( features ) ? ( features as Feature []) : [];
const mutate = ( fn : ( arr : Feature []) => Feature []) =>
actions . setProp ( selectedId , ( p : any ) => { p . features = fn ([...( p . features || [])]); });
const update = ( i : number , field : keyof Feature , value : string ) =>
mutate (( arr ) => { arr [ i ] = { ... arr [ i ], [ field ] : value }; return arr ; });
const add = () =>
mutate (( arr ) => [... arr , { title : 'New Feature' , description : 'Describe this feature.' , icon : '🔧' , image : '' , imageAlt : '' , buttonText : '' , buttonUrl : '' }]);
const remove = ( i : number ) => mutate (( arr ) => { arr . splice ( i , 1 ); return arr ; });
return (
< div style = {{ display : 'flex' , flexDirection : 'column' , gap : 8 }}>
{ list . map (( feat , i ) => (
< div key = { i } style = {{ background : '#1e1e22' , borderRadius : 6 , padding : 8 , display : 'flex' , flexDirection : 'column' , gap : 6 }}>
< div style = {{ display : 'flex' , gap : 4 , alignItems : 'center' }}>
< input type = "text" value = { feat . title || '' } onChange = {( e ) => update ( i , 'title' , e . target . value )} placeholder = "Title" style = {{ ... inputStyle , flex : 1 }} />
< button onClick = {() => remove ( i )} title = "Remove" style = {{ padding : '2px 8px' , fontSize : 11 , background : '#ef4444' , color : '#fff' , border : 'none' , borderRadius : 4 , cursor : 'pointer' , flex : 'none' }}> × </ button >
</ div >
< textarea value = { feat . description || '' } onChange = {( e ) => update ( i , 'description' , e . target . value )} placeholder = "Description" rows = { 2 } style = {{ ... inputStyle , resize : 'vertical' }} />
{ /* Media: image (upload/URL) takes precedence over the icon when set */ }
2026-07-12 13:00:10 -07:00
< div style = {{ display : 'flex' , gap : 4 , alignItems : 'center' }}>
< input type = "text" value = { feat . icon || '' } onChange = {( e ) => update ( i , 'icon' , e . target . value )} placeholder = "Icon (emoji)" style = {{ ... inputStyle , width : 60 , flex : 'none' , textAlign : 'center' }} />
< div style = {{ flex : 1 }}>
< AssetPicker variant = "compact" value = { feat . image || '' } onChange = {( url ) => update ( i , 'image' , url )} placeholder = "or image URL" />
2026-07-07 17:19:37 -07:00
</ div >
2026-07-12 13:00:10 -07:00
</ div >
2026-07-07 17:19:37 -07:00
{ /* Optional button */ }
< div style = {{ display : 'flex' , gap : 4 }}>
< input type = "text" value = { feat . buttonText || '' } onChange = {( e ) => update ( i , 'buttonText' , e . target . value )} placeholder = "Button text (optional)" style = {{ ... inputStyle , flex : 1 }} />
< input type = "text" value = { feat . buttonUrl || '' } onChange = {( e ) => update ( i , 'buttonUrl' , e . target . value )} placeholder = "Button URL" style = {{ ... inputStyle , flex : 1 }} />
</ div >
</ div >
))}
< button onClick = { add } style = {{ ... labelStyle , padding : '6px' , fontSize : 11 , background : '#27272a' , color : '#e4e4e7' , border : '1px solid #3f3f46' , borderRadius : 4 , cursor : 'pointer' , textAlign : 'center' }}>
+ Add Feature
</ button >
</ div >
);
};