feat: add illustration and content alignment options to hero section

This commit is contained in:
swve 2025-03-05 11:53:54 +01:00
parent 1c02a2bc6c
commit 570d6d61bb
3 changed files with 195 additions and 27 deletions

View file

@ -174,7 +174,9 @@ const OrgEditLanding = () => {
color: '#666666',
size: 'medium'
},
buttons: []
buttons: [],
illustration: undefined,
contentAlign: 'center'
}
case 'text-and-image':
return {
@ -950,6 +952,135 @@ const HeroSectionEditor: React.FC<{
)}
</div>
</div>
{/* Illustration */}
<div className="space-y-4">
<Label>Illustration</Label>
<div className="border rounded-lg p-4 space-y-4">
<div className="space-y-2">
<Label>Illustration Image</Label>
<Input
value={section.illustration?.image.url || ''}
onChange={(e) => {
if (e.target.value) {
onChange({
...section,
illustration: {
image: { url: e.target.value, alt: section.illustration?.image.alt || '' },
position: 'left',
verticalAlign: 'center',
size: 'medium'
}
})
}
}}
placeholder="Illustration URL"
/>
<Input
value={section.illustration?.image.alt || ''}
onChange={(e) => {
if (section.illustration?.image.url) {
onChange({
...section,
illustration: {
...section.illustration,
image: { ...section.illustration.image, alt: e.target.value }
}
})
}
}}
placeholder="Alt text"
/>
<ImageUploader
id="hero-illustration"
onImageUploaded={(url) => onChange({
...section,
illustration: {
image: { url, alt: section.illustration?.image.alt || '' },
position: 'left',
verticalAlign: 'center',
size: 'medium'
}
})}
buttonText="Upload Illustration"
/>
{section.illustration?.image.url && (
<img
src={section.illustration?.image.url}
alt={section.illustration?.image.alt}
className="h-12 object-contain"
/>
)}
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label>Position</Label>
<Select
value={section.illustration?.position || 'left'}
onValueChange={(value: 'left' | 'right') => onChange({
...section,
illustration: {
...section.illustration,
position: value,
image: section.illustration?.image || { url: '', alt: '' },
size: section.illustration?.size || 'medium',
verticalAlign: section.illustration?.verticalAlign || 'center'
}
})}
>
<SelectTrigger>
<SelectValue placeholder="Select position" />
</SelectTrigger>
<SelectContent>
<SelectItem value="left">Left</SelectItem>
<SelectItem value="right">Right</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>Size</Label>
<Select
value={section.illustration?.size || 'medium'}
onValueChange={(value: 'small' | 'medium' | 'large') => onChange({
...section,
illustration: {
...section.illustration,
size: value,
image: section.illustration?.image || { url: '', alt: '' },
position: (section.illustration?.position || 'left') as 'left' | 'right',
verticalAlign: section.illustration?.verticalAlign || 'center'
}
})}
>
<SelectTrigger>
<SelectValue placeholder="Select size" />
</SelectTrigger>
<SelectContent>
<SelectItem value="small">Small</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="large">Large</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{section.illustration?.image.url && (
<Button
variant="ghost"
onClick={() => onChange({
...section,
illustration: undefined
})}
className="text-red-500 hover:text-red-600 hover:bg-red-50 w-full"
>
<Trash2 className="h-4 w-4 mr-2" />
Remove Illustration
</Button>
)}
</div>
</div>
</div>
</div>
)

View file

@ -74,6 +74,13 @@ export interface LandingHeroSection {
heading: LandingHeading;
subheading: LandingHeading;
buttons: LandingButton[];
illustration?: {
image: LandingImage;
position: 'left' | 'right';
verticalAlign: 'top' | 'center' | 'bottom';
size: 'small' | 'medium' | 'large';
};
contentAlign?: 'left' | 'center' | 'right';
}
export type LandingSection = LandingTextAndImageSection | LandingHeroSection | LandingLogos | LandingPeople | LandingFeaturedCourses;

View file

@ -41,33 +41,63 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
: `url(${section.background.image}) center/cover`
}}
>
<div className="text-center w-full max-w-4xl mx-auto px-4 sm:px-6">
<h1
className="text-xl sm:text-2xl md:text-3xl font-bold mb-2 sm:mb-4"
style={{ color: section.heading.color }}
>
{section.heading.text}
</h1>
<h2
className="text-sm sm:text-base md:text-lg mb-4 sm:mb-6 md:mb-8 font-medium px-4 max-w-2xl mx-auto"
style={{ color: section.subheading.color }}
>
{section.subheading.text}
</h2>
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center items-center">
{section.buttons.map((button, index) => (
<a
key={index}
href={button.link}
className="w-full sm:w-auto px-6 py-2.5 rounded-lg text-sm font-extrabold shadow transition-transform hover:scale-105"
style={{
backgroundColor: button.background,
color: button.color
}}
<div className={`w-full h-full flex flex-col sm:flex-row ${
section.illustration?.position === 'right' ? 'sm:flex-row-reverse' : 'sm:flex-row'
} items-stretch`}>
{/* Logo */}
{section.illustration?.image.url && (
<div className={`flex items-${section.illustration.verticalAlign} p-6 w-full ${
section.illustration.size === 'small' ? 'sm:w-1/4' :
section.illustration.size === 'medium' ? 'sm:w-1/3' :
'sm:w-2/5'
}`}>
<img
src={section.illustration.image.url}
alt={section.illustration.image.alt}
className="w-full object-contain"
/>
</div>
)}
{/* Content */}
<div className={`flex-1 flex items-center ${
section.contentAlign === 'left' ? 'justify-start text-left' :
section.contentAlign === 'right' ? 'justify-end text-right' :
'justify-center text-center'
} p-6`}>
<div className="max-w-2xl">
<h1
className="text-xl sm:text-2xl md:text-3xl font-bold mb-2 sm:mb-4"
style={{ color: section.heading.color }}
>
{button.text}
</a>
))}
{section.heading.text}
</h1>
<h2
className="text-sm sm:text-base md:text-lg mb-4 sm:mb-6 md:mb-8 font-medium"
style={{ color: section.subheading.color }}
>
{section.subheading.text}
</h2>
<div className={`flex flex-col sm:flex-row gap-3 sm:gap-4 ${
section.contentAlign === 'left' ? 'justify-start' :
section.contentAlign === 'right' ? 'justify-end' :
'justify-center'
} items-center`}>
{section.buttons.map((button, index) => (
<a
key={index}
href={button.link}
className="w-full sm:w-auto px-6 py-2.5 rounded-lg text-sm font-extrabold shadow transition-transform hover:scale-105"
style={{
backgroundColor: button.background,
color: button.color
}}
>
{button.text}
</a>
))}
</div>
</div>
</div>
</div>
</div>