mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: add illustration and content alignment options to hero section
This commit is contained in:
parent
1c02a2bc6c
commit
570d6d61bb
3 changed files with 195 additions and 27 deletions
|
|
@ -174,7 +174,9 @@ const OrgEditLanding = () => {
|
||||||
color: '#666666',
|
color: '#666666',
|
||||||
size: 'medium'
|
size: 'medium'
|
||||||
},
|
},
|
||||||
buttons: []
|
buttons: [],
|
||||||
|
illustration: undefined,
|
||||||
|
contentAlign: 'center'
|
||||||
}
|
}
|
||||||
case 'text-and-image':
|
case 'text-and-image':
|
||||||
return {
|
return {
|
||||||
|
|
@ -950,6 +952,135 @@ const HeroSectionEditor: React.FC<{
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,13 @@ export interface LandingHeroSection {
|
||||||
heading: LandingHeading;
|
heading: LandingHeading;
|
||||||
subheading: LandingHeading;
|
subheading: LandingHeading;
|
||||||
buttons: LandingButton[];
|
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;
|
export type LandingSection = LandingTextAndImageSection | LandingHeroSection | LandingLogos | LandingPeople | LandingFeaturedCourses;
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,31 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
||||||
: `url(${section.background.image}) center/cover`
|
: `url(${section.background.image}) center/cover`
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="text-center w-full max-w-4xl mx-auto px-4 sm:px-6">
|
<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
|
<h1
|
||||||
className="text-xl sm:text-2xl md:text-3xl font-bold mb-2 sm:mb-4"
|
className="text-xl sm:text-2xl md:text-3xl font-bold mb-2 sm:mb-4"
|
||||||
style={{ color: section.heading.color }}
|
style={{ color: section.heading.color }}
|
||||||
|
|
@ -49,12 +73,16 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
||||||
{section.heading.text}
|
{section.heading.text}
|
||||||
</h1>
|
</h1>
|
||||||
<h2
|
<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"
|
className="text-sm sm:text-base md:text-lg mb-4 sm:mb-6 md:mb-8 font-medium"
|
||||||
style={{ color: section.subheading.color }}
|
style={{ color: section.subheading.color }}
|
||||||
>
|
>
|
||||||
{section.subheading.text}
|
{section.subheading.text}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center items-center">
|
<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) => (
|
{section.buttons.map((button, index) => (
|
||||||
<a
|
<a
|
||||||
key={index}
|
key={index}
|
||||||
|
|
@ -71,6 +99,8 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
case 'text-and-image':
|
case 'text-and-image':
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue