x
This commit is contained in:
1 parent
5c09629b6f
commit
2e00715142
5 files changed
+27
-14
No files matched your search
@@ -1,12 +1,13 @@
|
|||||||
import { UploadCloud, Image as ImageIcon } from 'lucide-react';
|
import { UploadCloud, Image as ImageIcon } from 'lucide-react';
|
||||||
import { type PageSection } from '@homaroma/types';
|
import { type PageSection } from '@homaroma/types';
|
||||||
|
import FocalPointPicker from './FocalPointPicker';
|
||||||
|
|
||||||
interface HeroV2FormProps {
|
interface HeroV2FormProps {
|
||||||
editingSection: Partial<PageSection>;
|
editingSection: Partial<PageSection>;
|
||||||
editingLang: string;
|
editingLang: string;
|
||||||
getLocalizedValue: (payload: any, field: string) => string;
|
getLocalizedValue: (payload: any, field: string) => string;
|
||||||
updateLocalizedValue: (field: string, value: string) => void;
|
updateLocalizedValue: (field: string, value: string) => void;
|
||||||
updatePayloadValue: (field: string, value: string | number | boolean) => void;
|
updatePayloadValue: (field: string, value: any) => void;
|
||||||
setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void;
|
setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void;
|
||||||
setIsMediaModalOpen: (open: boolean) => void;
|
setIsMediaModalOpen: (open: boolean) => void;
|
||||||
}
|
}
|
||||||
@@ -47,6 +48,16 @@ export default function HeroV2Form({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{editingSection.payload?.imageUrl && (
|
||||||
|
<div className="md:col-span-2">
|
||||||
|
<FocalPointPicker
|
||||||
|
imageUrl={editingSection.payload.imageUrl}
|
||||||
|
focalPoint={editingSection.payload.focalPoint}
|
||||||
|
onChange={(focalPoint) => updatePayloadValue('focalPoint', focalPoint)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">Alignment</label>
|
<label className="text-[10px] uppercase font-bold tracking-widest text-slate-400">Alignment</label>
|
||||||
<select
|
<select
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ export default function DynamicHero({ payload }: DynamicHeroProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="ui-hero-shell">
|
<section className="relative w-full flex flex-col md:block md:h-[90vh] md:aspect-[21/9] bg-[#EBE7E0] overflow-hidden">
|
||||||
<div className="absolute inset-0 z-0">
|
<div className="relative w-full h-[50vh] min-h-[400px] md:absolute md:inset-0 md:h-full md:z-0">
|
||||||
<img
|
<img
|
||||||
src={imageUrl || `${import.meta.env.VITE_API_URL.replace('/api', '')}/assets/hero.png`}
|
src={imageUrl || `${import.meta.env.VITE_API_URL.replace('/api', '')}/assets/hero.png`}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
@@ -49,7 +49,7 @@ export default function DynamicHero({ payload }: DynamicHeroProps) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="ui-hero-content animate-fade-in">
|
<div className="relative z-10 mx-auto py-12 w-full max-w-4xl space-y-6 px-8 text-center md:py-0 md:h-full md:flex md:flex-col md:justify-center md:items-center animate-fade-in">
|
||||||
<p className="text-pop-black/70 font-semibold tracking-[0.3em] text-xs md:text-sm uppercase drop-shadow-md">
|
<p className="text-pop-black/70 font-semibold tracking-[0.3em] text-xs md:text-sm uppercase drop-shadow-md">
|
||||||
{tagline || t('hero.defaultTagline')}
|
{tagline || t('hero.defaultTagline')}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -46,18 +46,17 @@ export default function DynamicHeroV2({ payload }: DynamicHeroV2Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative w-full h-[80vh] min-h-[600px] bg-white flex items-center overflow-hidden">
|
<section className="relative w-full flex flex-col md:block md:h-[80vh] md:min-h-[600px] bg-white overflow-hidden">
|
||||||
<div className="absolute inset-0 w-full h-full">
|
<div className="relative w-full h-[50vh] min-h-[400px] md:absolute md:inset-0 md:h-full">
|
||||||
<img
|
<img
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
alt={title || 'Hero'}
|
alt={title || 'Hero'}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-gradient-to-r from-white/90 via-white/50 to-transparent pointer-events-none" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative z-10 w-full max-w-7xl mx-auto px-6 md:px-12">
|
<div className="relative z-10 w-full max-w-7xl mx-auto px-6 py-12 md:py-0 md:h-full md:flex md:items-center md:px-12">
|
||||||
<div className={`max-w-xl flex flex-col gap-6 ${alignClass}`}>
|
<div className={`max-w-xl flex flex-col gap-6 ${alignClass}`}>
|
||||||
{tagline && (
|
{tagline && (
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|||||||
@@ -107,16 +107,18 @@ function HeroSection({ payload, lang }: { payload: Record<string, unknown>, lang
|
|||||||
const focalPoint = typeof payload.focalPoint === 'object' && payload.focalPoint ? (payload.focalPoint as { x: string, y: string }) : undefined
|
const focalPoint = typeof payload.focalPoint === 'object' && payload.focalPoint ? (payload.focalPoint as { x: string, y: string }) : undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="ui-hero-shell">
|
<section className="relative w-full flex flex-col md:block md:h-[90vh] md:aspect-[21/9] bg-surface-page overflow-hidden">
|
||||||
|
<div className="relative w-full h-[50vh] min-h-[400px] md:absolute md:inset-0 md:h-full">
|
||||||
<Image
|
<Image
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
alt={title || ''}
|
alt={title || ''}
|
||||||
fill
|
fill
|
||||||
unoptimized
|
unoptimized
|
||||||
className="absolute inset-0 h-full w-full scale-[1.02] object-cover"
|
className="object-cover md:scale-[1.02]"
|
||||||
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
style={{ objectPosition: focalPoint ? `${focalPoint.x} ${focalPoint.y}` : undefined }}
|
||||||
/>
|
/>
|
||||||
<div className="relative z-10 mx-auto mt-16 w-full max-w-4xl space-y-6 px-8 text-center md:mt-0">
|
</div>
|
||||||
|
<div className="relative z-10 mx-auto py-12 w-full max-w-4xl space-y-6 px-8 text-center md:py-0 md:h-full md:flex md:flex-col md:justify-center md:items-center">
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{tagline && (
|
{tagline && (
|
||||||
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-[#EAEFEA] drop-shadow-md md:text-sm">
|
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-[#EAEFEA] drop-shadow-md md:text-sm">
|
||||||
@@ -221,8 +223,8 @@ function HeroV2Section({ payload, lang }: { payload: Record<string, unknown>, la
|
|||||||
const alignClass = align === 'center' ? 'text-center items-center mx-auto' : align === 'right' ? 'text-right items-end ml-auto' : 'text-left items-start'
|
const alignClass = align === 'center' ? 'text-center items-center mx-auto' : align === 'right' ? 'text-right items-end ml-auto' : 'text-left items-start'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative w-full h-[80vh] min-h-[600px] bg-surface-page flex items-center overflow-hidden">
|
<section className="relative w-full flex flex-col md:block md:h-[80vh] md:min-h-[600px] bg-surface-page overflow-hidden">
|
||||||
<div className="absolute inset-0 w-full h-full">
|
<div className="relative w-full h-[50vh] min-h-[400px] md:absolute md:inset-0 md:h-full">
|
||||||
<Image
|
<Image
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
alt={title || 'Hero'}
|
alt={title || 'Hero'}
|
||||||
@@ -233,7 +235,7 @@ function HeroV2Section({ payload, lang }: { payload: Record<string, unknown>, la
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative z-10 w-full max-w-7xl mx-auto px-6 md:px-12">
|
<div className="relative z-10 w-full max-w-7xl mx-auto px-6 py-12 md:py-0 md:h-full md:flex md:items-center md:px-12">
|
||||||
<div className={`max-w-xl flex flex-col gap-6 ${alignClass}`}>
|
<div className={`max-w-xl flex flex-col gap-6 ${alignClass}`}>
|
||||||
{tagline && (
|
{tagline && (
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|||||||
@@ -572,6 +572,7 @@ export const HeroV2SectionPayloadSchema = z.object({
|
|||||||
primaryButtonLink: z.string().optional(),
|
primaryButtonLink: z.string().optional(),
|
||||||
secondaryButtonText: LocalizedStringSchema.optional(),
|
secondaryButtonText: LocalizedStringSchema.optional(),
|
||||||
secondaryButtonLink: z.string().optional(),
|
secondaryButtonLink: z.string().optional(),
|
||||||
|
focalPoint: z.object({ x: z.string(), y: z.string() }).optional(),
|
||||||
});
|
});
|
||||||
export type HeroV2SectionPayload = z.infer<typeof HeroV2SectionPayloadSchema>;
|
export type HeroV2SectionPayload = z.infer<typeof HeroV2SectionPayloadSchema>;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user