182 lines
5.8 KiB
TypeScript
182 lines
5.8 KiB
TypeScript
/**
|
|
* CarouselSettingsSection
|
|
*
|
|
* Settings for carousel element type.
|
|
* Manages carousel slides with images and captions.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { mdiPlus, mdiTrashCan } from '@mdi/js';
|
|
import BaseButton from '../BaseButton';
|
|
import CardBox from '../CardBox';
|
|
import FormField from '../FormField';
|
|
import type { CarouselSettingsSectionProps } from './types';
|
|
import { FONT_OPTIONS } from '../../lib/fonts';
|
|
|
|
const CarouselSettingsSection: React.FC<CarouselSettingsSectionProps> = ({
|
|
carouselPrevIconUrl,
|
|
carouselNextIconUrl,
|
|
carouselCaptionFontFamily,
|
|
carouselSlides,
|
|
onAddSlide,
|
|
onRemoveSlide,
|
|
onUpdateSlide,
|
|
onChange,
|
|
context,
|
|
iconAssetOptions = [],
|
|
imageAssetOptions = [],
|
|
}) => {
|
|
const isConstructor = context === 'constructor';
|
|
|
|
return (
|
|
<CardBox className='border border-gray-200 dark:border-dark-700'>
|
|
<h3 className='mb-3 text-sm font-semibold'>Carousel settings</h3>
|
|
|
|
<div className='grid gap-3 md:grid-cols-2'>
|
|
{isConstructor ? (
|
|
<>
|
|
<FormField label='Previous icon'>
|
|
<select
|
|
value={carouselPrevIconUrl}
|
|
onChange={(event) =>
|
|
onChange('carouselPrevIconUrl', event.target.value)
|
|
}
|
|
>
|
|
<option value=''>Not selected</option>
|
|
{iconAssetOptions.map((option) => (
|
|
<option key={option.value} value={option.value}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</FormField>
|
|
<FormField label='Next icon'>
|
|
<select
|
|
value={carouselNextIconUrl}
|
|
onChange={(event) =>
|
|
onChange('carouselNextIconUrl', event.target.value)
|
|
}
|
|
>
|
|
<option value=''>Not selected</option>
|
|
{iconAssetOptions.map((option) => (
|
|
<option key={option.value} value={option.value}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</FormField>
|
|
</>
|
|
) : (
|
|
<>
|
|
<FormField label='Previous icon URL'>
|
|
<input
|
|
value={carouselPrevIconUrl}
|
|
onChange={(event) =>
|
|
onChange('carouselPrevIconUrl', event.target.value)
|
|
}
|
|
/>
|
|
</FormField>
|
|
<FormField label='Next icon URL'>
|
|
<input
|
|
value={carouselNextIconUrl}
|
|
onChange={(event) =>
|
|
onChange('carouselNextIconUrl', event.target.value)
|
|
}
|
|
/>
|
|
</FormField>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<div className='mt-4'>
|
|
<FormField label='Caption font family'>
|
|
<select
|
|
value={carouselCaptionFontFamily}
|
|
onChange={(event) =>
|
|
onChange('carouselCaptionFontFamily', event.target.value)
|
|
}
|
|
>
|
|
<option value=''>Not set</option>
|
|
{FONT_OPTIONS.map((font) => (
|
|
<option key={font.key} value={font.key}>
|
|
{font.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</FormField>
|
|
</div>
|
|
|
|
{/* Slides editor only shown in constructor - slides are instance-specific */}
|
|
{isConstructor && (
|
|
<>
|
|
<div className='mb-3 mt-4 flex items-center justify-between'>
|
|
<h3 className='text-sm font-semibold'>Carousel slides</h3>
|
|
<BaseButton
|
|
color='info'
|
|
icon={mdiPlus}
|
|
small
|
|
label='Add slide'
|
|
onClick={onAddSlide}
|
|
/>
|
|
</div>
|
|
|
|
<div className='space-y-4'>
|
|
{carouselSlides.length === 0 ? (
|
|
<p className='text-sm text-gray-500'>No slides yet.</p>
|
|
) : (
|
|
carouselSlides.map((slide, index) => (
|
|
<CardBox
|
|
key={slide.id}
|
|
className='border border-gray-200 dark:border-dark-700'
|
|
>
|
|
<div className='mb-3 flex items-center justify-between'>
|
|
<h4 className='text-sm font-semibold'>Slide {index + 1}</h4>
|
|
<BaseButton
|
|
color='danger'
|
|
icon={mdiTrashCan}
|
|
small
|
|
outline
|
|
onClick={() => onRemoveSlide(slide.id)}
|
|
/>
|
|
</div>
|
|
<div className='grid gap-3 md:grid-cols-2'>
|
|
<FormField label='Image'>
|
|
<select
|
|
value={slide.imageUrl}
|
|
onChange={(event) =>
|
|
onUpdateSlide(
|
|
slide.id,
|
|
'imageUrl',
|
|
event.target.value,
|
|
)
|
|
}
|
|
>
|
|
<option value=''>Not selected</option>
|
|
{imageAssetOptions.map((option) => (
|
|
<option key={option.value} value={option.value}>
|
|
{option.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</FormField>
|
|
<FormField label='Caption'>
|
|
<input
|
|
value={slide.caption}
|
|
onChange={(event) =>
|
|
onUpdateSlide(slide.id, 'caption', event.target.value)
|
|
}
|
|
/>
|
|
</FormField>
|
|
</div>
|
|
</CardBox>
|
|
))
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</CardBox>
|
|
);
|
|
};
|
|
|
|
export default CarouselSettingsSection;
|