This commit is contained in:
Your Name committed 2026-10-06 16:58:21 +07:00
1 parent 641cc4e42b
commit 46968782b6
17 files changed
+265 -30

No files matched your search

+2 -1
View File
@@ -3,6 +3,7 @@ import type { BannerSectionPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getHeroPositionClasses } from './DynamicHero';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicBannerProps {
payload: BannerSectionPayload;
@@ -66,7 +67,7 @@ export default function DynamicBanner({ payload }: DynamicBannerProps) {
);
return (
<section className="ui-section-band bg-pop-bg relative overflow-hidden">
<section className={`bg-pop-bg relative overflow-hidden ${getSectionPaddingClasses(payload)}`}>
{linkUrl ? (
<Link to={linkUrl} className={`ui-banner-shell group flex flex-col ${shellWidthClass} ${wrapperClasses} cursor-pointer`}>
{bannerInner}
@@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
import { getCategoryImage, resolveCategoryMediaUrl, type Category, type CategoriesSectionPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicCategoriesProps {
payload: CategoriesSectionPayload;
@@ -26,7 +27,7 @@ export default function DynamicCategories({ payload, categories, loading }: Dyna
}, [categories, categoryIds]);
return (
<section id="categories" className="ui-section-band relative overflow-hidden bg-pop-bg">
<section id="categories" className={`relative overflow-hidden bg-pop-bg ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner space-y-16 relative z-10">
<div className="space-y-4 text-center">
<h2 className="text-4xl font-bold tracking-tight text-pop-black md:text-5xl">
@@ -2,6 +2,7 @@ import { Link } from 'react-router-dom';
import type { EditorialTileSectionPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicEditorialTileProps {
payload: EditorialTileSectionPayload;
@@ -54,7 +55,7 @@ export default function DynamicEditorialTile({ payload }: DynamicEditorialTilePr
return (
<section
className="ui-section-band w-full overflow-hidden"
className={`w-full overflow-hidden ${getSectionPaddingClasses(payload)}`}
style={{ backgroundColor: payload.backgroundColor, color: payload.textColor }}
>
<div className="ui-section-inner grid grid-cols-1 items-center gap-12 md:grid-cols-2 md:gap-20">
@@ -3,6 +3,7 @@ import { useRef } from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicProductCarouselProps {
payload: any;
@@ -21,7 +22,7 @@ export default function DynamicProductCarousel({ payload }: DynamicProductCarous
const scrollRight = () => carouselRef.current?.scrollBy({ left: 300, behavior: 'smooth' });
return (
<section className="ui-section-band bg-pop-bg">
<section className={`bg-pop-bg ${getSectionPaddingClasses(p)}`}>
<div className="ui-section-inner">
{(title || description) && (
<div className="text-center mb-12">
+2 -1
View File
@@ -5,6 +5,7 @@ import ProductCard from './ProductCard';
import type { Category, Product, ProductsSectionPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicProductsProps {
payload: ProductsSectionPayload & { products?: Product[] };
@@ -24,7 +25,7 @@ export default function DynamicProducts({ payload, categories = [] }: DynamicPro
const scrollRight = () => carouselRef.current?.scrollBy({ left: 300, behavior: 'smooth' });
return (
<section className="ui-section-band relative bg-pop-bg">
<section className={`relative bg-pop-bg ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner relative z-10 space-y-12">
<div className="flex flex-col md:flex-row items-start md:items-end justify-between gap-6 border-b border-pop-black/10 pb-6">
<div>
@@ -1,6 +1,7 @@
import type { QuoteCalloutPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicQuoteCalloutProps {
payload: QuoteCalloutPayload & { role?: string };
@@ -14,7 +15,7 @@ export default function DynamicQuoteCallout({ payload }: DynamicQuoteCalloutProp
const role = getLocalizedField(payload.role, lang);
return (
<section className="ui-section-band bg-pop-bg">
<section className={`bg-pop-bg ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner text-center">
<div className="bg-pop-black/5 rounded-3xl p-8 max-w-4xl mx-auto">
<svg className="w-12 h-12 mx-auto text-pop-black/40 mb-8" fill="currentColor" viewBox="0 0 24 24">
+2 -1
View File
@@ -1,6 +1,7 @@
import type { PageSection } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicRichTextProps {
section: PageSection;
@@ -17,7 +18,7 @@ export default function DynamicRichText({ section }: DynamicRichTextProps) {
if (!content) return null;
return (
<section className="ui-section-band bg-pop-bg relative">
<section className={`bg-pop-bg relative ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner space-y-6">
{title && (
<h2 className="font-serif text-3xl font-semibold text-pop-black md:text-4xl text-center">
@@ -1,6 +1,7 @@
import type { ScentNotesBreakdownPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicScentNotesBreakdownProps {
payload: ScentNotesBreakdownPayload;
@@ -28,7 +29,7 @@ export default function DynamicScentNotesBreakdown({ payload }: DynamicScentNote
const baseNotes = notes(payload.baseNotes);
return (
<section className="ui-section-band bg-pop-bg">
<section className={`bg-pop-bg ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner text-center">
<h2 className="mb-6 font-serif text-3xl text-pop-black md:text-5xl">
{title || 'Scent Notes'}
+2 -1
View File
@@ -1,6 +1,7 @@
import type { TextSectionPayload } from '@homaroma/types';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../utils/localization';
import { getSectionPaddingClasses } from '../utils/spacing';
interface DynamicTextProps {
payload: TextSectionPayload;
@@ -20,7 +21,7 @@ export default function DynamicText({ payload }: DynamicTextProps) {
}[textAlign] || 'text-left';
return (
<section className="ui-section-band bg-pop-bg relative">
<section className={`bg-pop-bg relative ${getSectionPaddingClasses(payload)}`}>
<div className={`ui-section-inner space-y-6 ${alignClass}`}>
{title && (
<h2 className="font-serif text-3xl font-semibold text-pop-black md:text-4xl">
@@ -3,6 +3,7 @@ import type { AccordionSectionPayload } from '@homaroma/types';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../../utils/localization';
import { getSectionPaddingClasses } from '../../utils/spacing';
interface AccordionSectionProps {
payload: AccordionSectionPayload & { title?: string };
@@ -20,7 +21,7 @@ export default function AccordionSection({ payload }: AccordionSectionProps) {
return (
<section
className="ui-section-band w-full px-4 md:px-8"
className={`w-full px-4 md:px-8 ${getSectionPaddingClasses(payload)}`}
style={{ backgroundColor: payload.backgroundColor, color: payload.textColor }}
>
<div className="ui-section-inner">
@@ -3,6 +3,7 @@ import type { ContactInfoSectionPayload } from '@homaroma/types';
import { MapPin, Mail, MessageCircle, Clock } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { getLocalizedField } from '../../utils/localization';
import { getSectionPaddingClasses } from '../../utils/spacing';
interface ContactInfoSectionProps {
payload: ContactInfoSectionPayload & { title?: string };
@@ -30,7 +31,7 @@ export default function ContactInfoSection({ payload }: ContactInfoSectionProps)
] as const;
return (
<section className="ui-section-band w-full bg-pop-bg px-4 md:px-8">
<section className={`w-full bg-pop-bg px-4 md:px-8 ${getSectionPaddingClasses(payload)}`}>
<div className="ui-section-inner">
{title && (
<div className="mb-10 text-center">
+37
View File
@@ -0,0 +1,37 @@
export function getSectionPaddingClasses(
payload?: Record<string, any>,
fallback: 'normal' | 'none' | 'compact' | 'spacious' = 'normal',
): string {
const padTop = payload?.paddingTop || payload?.sectionPadding || fallback;
const padBottom = payload?.paddingBottom || payload?.sectionPadding || fallback;
const getPt = (p: string) => {
switch (p) {
case 'none':
return 'pt-0';
case 'compact':
return 'pt-6 md:pt-10';
case 'spacious':
return 'pt-20 md:pt-28';
case 'normal':
default:
return 'pt-10 md:pt-16';
}
};
const getPb = (p: string) => {
switch (p) {
case 'none':
return 'pb-0';
case 'compact':
return 'pb-6 md:pb-10';
case 'spacious':
return 'pb-20 md:pb-28';
case 'normal':
default:
return 'pb-10 md:pb-16';
}
};
return `${getPt(padTop)} ${getPb(padBottom)}`;
}