From f6c188bd93231c1d2c46094e843e862976480782 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 07:30:16 -0400 Subject: [PATCH] x --- .../src/components/page-builder/BannerForm.tsx | 13 ++++++++++++- apps/mcp-server/section-toolkit.ts | 2 +- apps/spa/src/components/DynamicBanner.tsx | 4 ++++ .../src/components/dynamic/DynamicPageRenderer.tsx | 10 +++++++++- packages/types/index.ts | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/admin/src/components/page-builder/BannerForm.tsx b/apps/admin/src/components/page-builder/BannerForm.tsx index 6574d70..dc5890a 100644 --- a/apps/admin/src/components/page-builder/BannerForm.tsx +++ b/apps/admin/src/components/page-builder/BannerForm.tsx @@ -1,12 +1,13 @@ import { UploadCloud, Image as ImageIcon } from 'lucide-react'; import { type PageSection } from '@homaroma/types'; +import FocalPointPicker from './FocalPointPicker'; interface BannerFormProps { editingSection: Partial; editingLang: string; getLocalizedValue: (payload: any, field: string) => string; updateLocalizedValue: (field: string, value: string) => void; - updatePayloadValue: (field: string, value: string | number) => void; + updatePayloadValue: (field: string, value: any) => void; setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void; setIsMediaModalOpen: (open: boolean) => void; } @@ -47,6 +48,16 @@ export default function BannerForm({ + {editingSection.payload?.imageUrl && ( +
+ updatePayloadValue('focalPoint', focalPoint)} + /> +
+ )} +
@@ -24,6 +26,7 @@ export default function DynamicBanner({ payload }: DynamicBannerProps) { src={imageUrl} className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-[1.03]" alt={title || "Banner"} + style={imageStyle} />
@@ -55,6 +58,7 @@ export default function DynamicBanner({ payload }: DynamicBannerProps) { src={imageUrl} className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-[1.03]" alt={title || "Banner"} + style={imageStyle} />
diff --git a/apps/website/src/components/dynamic/DynamicPageRenderer.tsx b/apps/website/src/components/dynamic/DynamicPageRenderer.tsx index 423d6af..836fae1 100644 --- a/apps/website/src/components/dynamic/DynamicPageRenderer.tsx +++ b/apps/website/src/components/dynamic/DynamicPageRenderer.tsx @@ -424,10 +424,18 @@ function BannerSection({ payload, lang }: { payload: Record, la const buttonText = localizedFromRecord(payload, 'buttonText', resolvedLang) const imageUrl = typeof payload.imageUrl === 'string' ? payload.imageUrl : '/images/hero.png' const linkUrl = typeof payload.linkUrl === 'string' ? payload.linkUrl : '' + const focalPoint = typeof payload.focalPoint === 'object' && payload.focalPoint ? (payload.focalPoint as { x: string, y: string }) : undefined const content = (
- {title + {title
{title &&

{title}

} diff --git a/packages/types/index.ts b/packages/types/index.ts index 50e9fe2..215e5a7 100644 --- a/packages/types/index.ts +++ b/packages/types/index.ts @@ -339,6 +339,7 @@ export const BannerSectionPayloadSchema = z.object({ title: LocalizedStringSchema.optional(), description: LocalizedStringSchema.optional(), buttonText: LocalizedStringSchema.optional(), + focalPoint: z.object({ x: z.string(), y: z.string() }).optional(), }); export type BannerSectionPayload = z.infer;