diff --git a/apps/admin/src/components/page-builder/FeaturedTilesForm.tsx b/apps/admin/src/components/page-builder/FeaturedTilesForm.tsx index c3988e9..3914a7a 100644 --- a/apps/admin/src/components/page-builder/FeaturedTilesForm.tsx +++ b/apps/admin/src/components/page-builder/FeaturedTilesForm.tsx @@ -31,13 +31,18 @@ export default function FeaturedTilesForm({ if (preset === 'editorial') { // Style 1: Clean Editorial (4 Columns, Landscape, Left aligned, Arrow link, Warm Cream) updatePayloadValue('layoutPreset', 'editorial'); + updatePayloadValue('headerAlign', 'left'); + updatePayloadValue('showHeading', true); updatePayloadValue('columns', 4); + updatePayloadValue('containerWidth', 'wide'); updatePayloadValue('imageAspectRatio', 'landscape'); updatePayloadValue('textAlign', 'left'); updatePayloadValue('ctaStyle', 'arrow_link'); updatePayloadValue('imageRounded', 'md'); updatePayloadValue('backgroundColor', '#F7F4EE'); updatePayloadValue('textColor', '#1E293B'); + updatePayloadValue('paddingTop', 'compact'); + updatePayloadValue('paddingBottom', 'normal'); // Update tiles' aspect ratio to match const updatedTiles = tiles.map((t: any) => ({ @@ -49,13 +54,18 @@ export default function FeaturedTilesForm({ } else { // Style 2: Campaign Spotlight (2 Columns, Square, Center aligned, Pill button, White) updatePayloadValue('layoutPreset', 'spotlight'); + updatePayloadValue('headerAlign', 'center'); + updatePayloadValue('showHeading', true); updatePayloadValue('columns', 2); + updatePayloadValue('containerWidth', 'standard'); updatePayloadValue('imageAspectRatio', 'square'); updatePayloadValue('textAlign', 'center'); updatePayloadValue('ctaStyle', 'pill_button'); updatePayloadValue('imageRounded', '3xl'); updatePayloadValue('backgroundColor', '#FFFFFF'); updatePayloadValue('textColor', '#111827'); + updatePayloadValue('paddingTop', 'normal'); + updatePayloadValue('paddingBottom', 'normal'); const updatedTiles = tiles.map((t: any) => ({ ...t, @@ -201,44 +211,74 @@ export default function FeaturedTilesForm({
- + + +
+ + +
+
+
-
-
- + + +
+ +
+
- + updatePayloadValue('ctaStyle', e.target.value)} className="admin-input w-full text-xs bg-slate-900 border-white/10" > - - - - + + + +
- + +
+
+ + {/* ── Padding & Spacing Controls (Full Control) ── */} +
+
+
+ + {payload.paddingTop || payload.sectionPadding || 'normal'} +
+ +
+ +
+
+ + {payload.paddingBottom || payload.sectionPadding || 'normal'} +
+
diff --git a/apps/admin/src/locales/en/translation.json b/apps/admin/src/locales/en/translation.json index 1c65db2..334d4d4 100644 --- a/apps/admin/src/locales/en/translation.json +++ b/apps/admin/src/locales/en/translation.json @@ -1348,27 +1348,43 @@ "hidePayload": "Hide Payload", "copyPayload": "Copy Payload", "copied": "Copied", + "copyLlmPrompt": "Copy LLM Prompt", + "llmPromptCopied": "Prompt Copied", + "schemaSpec": "Schema Spec", + "hideSchema": "Hide Spec", + "desktopView": "Desktop (100%)", + "mobileView": "Mobile (375px)", "categories": { "all": "All Blocks", "hero": "Banner & Hero", + "minimal": "Minimal & Luxury", "products": "Products & Shop", "editorial": "Story & Editorial", "articles": "Article Elements", - "forms": "Forms & Info" + "forms": "Forms & Info", + "layout": "Layout & Custom" }, "blocks": { "ANNOUNCEMENT_BAR": "Top notice bar with custom styling and scrolling announcements.", "HERO": "Premium full-screen cover with headline, background image, and CTA.", "HERO_V2": "Split Layout Hero featuring text on one side and a premium image card on the other.", "HERO_VIDEO": "Cinema-quality full background video banner with animated overlay typography and dual CTA buttons.", + "HERO_CAROUSEL": "Mega promotional banner carousel with auto-sliding timer, navigation arrows, dots, and mobile aspect ratios.", + "HERO_MINIMAL": "Quiet Luxury full-width centered typography hero with adjustable overlay darkness.", + "HERO_SPLIT_MINIMAL": "Minimalist split layout hero with pure typography on one side and curated imagery on the other.", + "HERO_VIDEO_MINIMAL": "Atmospheric silent video hero showcasing nature and serene motion.", + "BANNER_MINIMAL": "Quiet luxury typographic banner with concise headline and destination link.", + "ANNOUNCEMENT_BAR_MINIMAL": "Minimalist scrolling announcements ticker with dot separators.", + "USP_MINIMAL": "Horizontal brand commitments and USP ticker with dot/pipe delimiters.", "USP_BAR": "Unique Selling Proposition Bar highlighting product perks (Icons & Labels).", "BANNER": "Clickable promotional block with headline overlay, ideal for campaigns.", "CATEGORIES": "Visual category grid showcase to guide users to specific collections.", "PRODUCTS": "Showcase grid or carousel for featured products, brand items, or a customized list with Quick Shop option.", "PRODUCT_CAROUSEL": "Swipeable horizontal card carousel displaying specific product collections.", + "PRODUCT_LAYOUT": "Full product detail page layout template including media gallery, buy box, specs tabs, and reviews.", "RELATED_PRODUCTS": "Dynamic block recommending items from the same category for the product page layout.", - "EDITORIAL_TILE": "Stunning editorial grid block presenting storytelling text alongside a curated campaign photo.", - "FEATURED_TILES": "Side-by-side campaign grid featuring square or tall images with centered titles and outline CTA buttons (Jo Malone aesthetic).", + "EDITORIAL_TILE": "Stunning editorial grid block presenting storytelling text alongside a curated campaign photo with adjustable aspect ratio.", + "FEATURED_TILES": "Side-by-side campaign grid featuring square or landscape images with dual-level links (Jo Malone aesthetic).", "EDITORIAL_CAROUSEL": "Stories and values slider displaying image slideshows side-by-side with localized editorial statements.", "SCENT_NOTES_BREAKDOWN": "Fragrance profile breakdowns containing Top, Heart/Middle, and Base notes lists.", "QUOTE_CALLOUT": "Elegant text banner presenting callout quotations, ideal for customer testimonials.", @@ -1387,7 +1403,9 @@ "NEWSLETTER": "Email subscription block to attract newsletter sign-ups.", "ACCORDION": "Question-answer accordions for FAQs, divided by custom categories.", "CONTACT_INFO": "Beautiful information box showing address, telephone, and social details.", - "CONTACT_FORM": "General support email inquiry contact form." + "CONTACT_FORM": "General support email inquiry contact form.", + "DIVIDER": "Section separation line with configurable style, thickness, spacing, color, and container width.", + "CUSTOM": "Dynamic extensible white-label block supporting custom components and flexible props." } }, "repeatCustomers": { diff --git a/apps/admin/src/locales/th/translation.json b/apps/admin/src/locales/th/translation.json index 6e931e6..d490d56 100644 --- a/apps/admin/src/locales/th/translation.json +++ b/apps/admin/src/locales/th/translation.json @@ -1347,27 +1347,43 @@ "hidePayload": "ซ่อน Payload", "copyPayload": "คัดลอก Payload", "copied": "คัดลอกแล้ว", + "copyLlmPrompt": "คัดลอก LLM Prompt", + "llmPromptCopied": "คัดลอก Prompt แล้ว", + "schemaSpec": "สเปกโครงสร้าง (Schema)", + "hideSchema": "ซ่อนสเปก", + "desktopView": "เดสก์ท็อป (100%)", + "mobileView": "มือถือ (375px)", "categories": { "all": "ทุกบล็อก", "hero": "แบนเนอร์ & Hero", + "minimal": "มินิมอล & ลักชูรี", "products": "สินค้า & ร้านค้า", "editorial": "เรื่องราว & บทความ", "articles": "องค์ประกอบบทความ", - "forms": "ฟอร์ม & ข้อมูลติดต่อ" + "forms": "ฟอร์ม & ข้อมูลติดต่อ", + "layout": "เลย์เอาต์ & ส่วนเสริม" }, "blocks": { "ANNOUNCEMENT_BAR": "แถบประกาศด้านบนสุด พร้อมข้อความวิ่งและการจัดสไตล์ที่กำหนดเองได้", "HERO": "แบนเนอร์เต็มจอระดับพรีเมียม พร้อมหัวข้อ รูปพื้นหลัง และปุ่ม Call-to-Action", "HERO_V2": "แบนเนอร์ Hero แบบแยกสองฝั่ง จัดวางข้อความเด่นฝั่งหนึ่งและการ์ดภาพสินค้าอีกฝั่ง", "HERO_VIDEO": "แบนเนอร์วิดีโอพื้นหลังคุณภาพระดับภาพยนตร์ พร้อมตัวอักษรและปุ่ม CTA คู่", + "HERO_CAROUSEL": "สไลด์แบนเนอร์โปรโมชันขนาดใหญ่ พร้อมตัวตั้งเวลาเลื่อนอัตโนมัติ ปุ่มลูกศร และปรับสัดส่วนจอมือถือได้", + "HERO_MINIMAL": "แบนเนอร์ภาพเต็มจอข้อความกึ่งกลางสไตล์ Quiet Luxury พร้อมชั้นเลเยอร์สีทึบปรับความเข้มได้", + "HERO_SPLIT_MINIMAL": "แบนเนอร์ข้อความสลับภาพครึ่งฝั่งแบบเรียบหรูระดับพรีเมียม", + "HERO_VIDEO_MINIMAL": "แบนเนอร์วิดีโอแบบเงียบสงบ มินิมอล พร้อมสโลแกนและหัวข้อบรรยากาศธรรมชาติ", + "BANNER_MINIMAL": "แบนเนอร์ข้อความและลิงก์แนวเรียบง่ายแต่ทรงพลัง สำหรับแจ้งสิทธิพิเศษ", + "ANNOUNCEMENT_BAR_MINIMAL": "แถบประกาศเลื่อนข้อความสไตล์ลักชูรี พร้อมตัวคั่นจุด", + "USP_MINIMAL": "แถบจุดเด่นสินค้าแบบ Ticker แนวนอน พร้อมตัวคั่นจุดหรือเส้น", "USP_BAR": "แถบจุดเด่นสินค้า (USP) แสดงไอคอนและข้อความการันตีคุณภาพ", "BANNER": "แบนเนอร์โปรโมชันแบบคลิกได้ พร้อมข้อความทับบนรูปภาพ เหมาะสำหรับแคมเปญ", "CATEGORIES": "กริดแสดงหมวดหมู่สินค้าเพื่อนำทางลูกค้าไปยังคอลเลกชันที่ต้องการ", "PRODUCTS": "บล็อกแสดงสินค้าแบบกริดหรือสไลด์สำหรับสินค้าแนะนำ หรือเลือกสินค้าพร้อมระบบสั่งด่วน", "PRODUCT_CAROUSEL": "สไลด์การ์ดสินค้าแนวนอน เลื่อนดูสินค้าในคอลเลกชันได้อย่างลื่นไหล", + "PRODUCT_LAYOUT": "โครงสร้างหน้าแสดงรายละเอียดสินค้าแบบครบวงจร (แกลเลอรี, ตะกร้า, แท็บสเปก, รีวิว)", "RELATED_PRODUCTS": "บล็อกแนะนำสินค้าที่เกี่ยวข้องจากหมวดหมู่เดียวกัน สำหรับหน้ารายละเอียดสินค้า", - "EDITORIAL_TILE": "บล็อกเล่าเรื่องสไตล์ Editorial จัดวางเนื้อหาคู่กับภาพถ่ายแคมเปญ", - "FEATURED_TILES": "กริดแคมเปญภาพคู่แบบจัตุรัสหรือแนวตั้ง พร้อมหัวข้อกึ่งกลางและปุ่มเรียบหรู (Jo Malone Style)", + "EDITORIAL_TILE": "บล็อกเล่าเรื่องสไตล์ Editorial จัดวางเนื้อหาคู่กับภาพถ่ายแคมเปญ พร้อมปรับสัดส่วนภาพได้", + "FEATURED_TILES": "กริดแคมเปญภาพคู่แบบจัตุรัส/แนวนอน พร้อมหัวข้อกึ่งกลางหรือชิดซ้าย และปุ่มลิงก์สองระดับ", "EDITORIAL_CAROUSEL": "สไลด์เรื่องราวและคุณค่าของแบรนด์ แสดงภาพคู่กับข้อความบรรยายอย่างลงตัว", "SCENT_NOTES_BREAKDOWN": "โครงสร้างจำแนกระดับกลิ่นหอม แสดงโน้ต Top, Heart/Middle และ Base", "QUOTE_CALLOUT": "กล่องโควทข้อความและคำคมระดับพรีเมียม เหมาะสำหรับรีวิวและคำนิยม", @@ -1386,7 +1402,9 @@ "NEWSLETTER": "ฟอร์มรับสมัครจดหมายข่าว เพื่อรับส่วนลดและข่าวสารโปรโมชัน", "ACCORDION": "แถบพับเปิด-ปิดสำหรับคำถามที่พบบ่อย (FAQs) แยกตามหมวดหมู่", "CONTACT_INFO": "กล่องข้อมูลติดต่อ แสดงที่อยู่ เบอร์โทร อีเมล และโซเชียลมีเดียอย่างสวยงาม", - "CONTACT_FORM": "ฟอร์มส่งข้อความติดต่อสอบถามทั่วไปทางอีเมล" + "CONTACT_FORM": "ฟอร์มส่งข้อความติดต่อสอบถามทั่วไปทางอีเมล", + "DIVIDER": "เส้นคั่นแบ่งส่วน ปรับสไตล์ ความหนา ช่องไฟ สี และความกว้างได้", + "CUSTOM": "บล็อกส่วนต่อขยายไดนามิกสำหรับแบรนด์และหมวดหมู่เฉพาะ (White-label Extensible Block)" } }, "repeatCustomers": { diff --git a/apps/admin/src/pages/CmsMockupPage.tsx b/apps/admin/src/pages/CmsMockupPage.tsx index 3e17cc6..49a989f 100644 --- a/apps/admin/src/pages/CmsMockupPage.tsx +++ b/apps/admin/src/pages/CmsMockupPage.tsx @@ -6,35 +6,47 @@ import { Check, Code, Sparkles, - HelpCircle, Mail, - Phone, MapPin, - Clock, Play, Download, - Info, ChevronDown, Search, - X + X, + Smartphone, + Monitor, + Bot, + Sliders, + ShoppingBag, + Quote, + ShieldCheck, + RotateCcw } from 'lucide-react'; -// Define categories for easy filtering +// Categories for filter tabs const CATEGORY_KEYS = [ { id: 'all', key: 'cmsMockup.categories.all', fallback: 'All Blocks' }, { id: 'hero', key: 'cmsMockup.categories.hero', fallback: 'Banner & Hero' }, + { id: 'minimal', key: 'cmsMockup.categories.minimal', fallback: 'Minimal & Luxury' }, { id: 'products', key: 'cmsMockup.categories.products', fallback: 'Products & Shop' }, { id: 'editorial', key: 'cmsMockup.categories.editorial', fallback: 'Story & Editorial' }, { id: 'articles', key: 'cmsMockup.categories.articles', fallback: 'Article Elements' }, - { id: 'forms', key: 'cmsMockup.categories.forms', fallback: 'Forms & Info' } + { id: 'forms', key: 'cmsMockup.categories.forms', fallback: 'Forms & Info' }, + { id: 'layout', key: 'cmsMockup.categories.layout', fallback: 'Layout & Custom' } ]; interface MockBlock { type: string; - category: string; + category: 'hero' | 'minimal' | 'products' | 'editorial' | 'articles' | 'forms' | 'layout'; description: string; + badge?: 'new' | 'updated'; payload: any; - renderPreview: () => React.ReactNode; + fieldsSpec: { + required: string[]; + optional: string[]; + description: string; + }; + renderPreview: (isMobile: boolean) => React.ReactNode; } export default function CmsMockupPage() { @@ -42,7 +54,20 @@ export default function CmsMockupPage() { const [activeCategory, setActiveCategory] = useState('all'); const [searchQuery, setSearchQuery] = useState(''); const [copiedType, setCopiedType] = useState(null); + const [copiedPromptType, setCopiedPromptType] = useState(null); const [showJsonFor, setShowJsonFor] = useState(null); + const [showSpecFor, setShowSpecFor] = useState(null); + const [globalMobileView, setGlobalMobileView] = useState(false); + const [perBlockMobile, setPerBlockMobile] = useState>({}); + + const isBlockMobile = (type: string) => perBlockMobile[type] ?? globalMobileView; + + const toggleBlockMobile = (type: string) => { + setPerBlockMobile(prev => ({ + ...prev, + [type]: !(prev[type] ?? globalMobileView) + })); + }; const copyPayload = (type: string, payload: any) => { navigator.clipboard.writeText(JSON.stringify(payload, null, 2)); @@ -50,74 +75,118 @@ export default function CmsMockupPage() { setTimeout(() => setCopiedType(null), 2000); }; + const copyLlmPrompt = (block: MockBlock) => { + const prompt = `คุณคือ Content Director และ E-commerce Specialist สำหรับแบรนด์พรีเมียม +โปรดช่วยสร้างเนื้อหาข้อมูล JSON สำหรับ CMS Section Block ประเภท: "${block.type}" + +[ข้อกำหนดโครงสร้าง Block Type: ${block.type}]: +- สไตล์และโทนเสียง: เรียบหรู พรีเมียม อบอุ่น น่าเชื่อถือ (Quiet Luxury & Botanical Wellness) +- รองรับภาษา: ภาษาไทย (th) และ ภาษาอังกฤษ (en) +- ฟิลด์ที่จำเป็น (Required): ${block.fieldsSpec.required.length > 0 ? block.fieldsSpec.required.join(', ') : 'ไม่มี (Optional ทั้งหมด)'} +- ฟิลด์เพิ่มเติม (Optional): ${block.fieldsSpec.optional.join(', ')} + +[คำอธิบายการทำงาน]: +${block.fieldsSpec.description} + +[ตัวอย่าง JSON Payload ที่ถูกต้องตาม Schema]: +${JSON.stringify(block.payload, null, 2)} + +[คำสั่งการตอบกลับ]: +โปรดสร้างข้อมูล JSON ที่สวยงามและถูกต้องตามสเปกด้านบน โดยส่งคำตอบเฉพาะโค้ด JSON ภายในแท็ก \`\`\`json ... \`\`\` เท่านั้น ห้ามใส่คำอธิบายเพิ่มเติม`; + + navigator.clipboard.writeText(prompt); + setCopiedPromptType(block.type); + setTimeout(() => setCopiedPromptType(null), 2000); + }; + const mockBlocks: MockBlock[] = [ - // 1. ANNOUNCEMENT_BAR + // ========================================== + // HERO & BANNERS (Category: hero) + // ========================================== { type: 'ANNOUNCEMENT_BAR', category: 'hero', description: 'Top notice bar with custom styling and scrolling announcements.', + fieldsSpec: { + required: ['slides'], + optional: ['backgroundColor', 'textColor', 'speed'], + description: 'แถบข้อความวิ่งด้านบนสุดของเว็บ กำหนดข้อความประกาศ (Array of strings หรือ Localized string) ปรับความเร็วและสีพื้นหลังได้' + }, payload: { - slides: ['[FREE SHIPPING] on orders over ฿1,500', 'New Premium Collection is out now!'], + slides: [ + '[FREE SHIPPING] on orders over ฿1,500', + 'New Botanical Sanctuary Collection is out now!' + ], backgroundColor: '#1F3D2D', textColor: '#FDFDF9', speed: 3000 }, renderPreview: () => (
- ✨ [FREE SHIPPING] on orders over ฿1,500 | New Premium Collection is out now! + ✨ [FREE SHIPPING] on orders over ฿1,500 | New Botanical Sanctuary Collection is out now!
) }, - // 2. HERO { type: 'HERO', category: 'hero', description: 'Premium full-screen cover with headline, background image, and CTA.', + fieldsSpec: { + required: ['title', 'imageUrl'], + optional: ['tagline', 'description', 'buttonText', 'buttonLink'], + description: 'แบนเนอร์หลักขนาดใหญ่เต็มตา รองรับข้อความหัวข้อ คำบรรยาย และปุ่มสั่งซื้อ' + }, payload: { - tagline: 'Vibrant Elegance', - title: 'New Scent [Sanctuary]', - description: 'Transform your room into a peaceful escape.', - imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=800&q=80', - buttonText: 'Explore Collection', + tagline: { th: 'ความสง่างามจากธรรมชาติ', en: 'Vibrant Elegance' }, + title: { th: 'กลิ่นหอมแห่งการพักผ่อน [Sanctuary]', en: 'New Scent [Sanctuary]' }, + description: { th: 'เปลี่ยนบรรยากาศห้องของคุณให้เป็นสถานที่แห่งความเงียบสงบ', en: 'Transform your room into a peaceful escape.' }, + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1200&q=80', + buttonText: { th: 'เลือกชมคอลเลกชัน', en: 'Explore Collection' }, buttonLink: '/shop' }, - renderPreview: () => ( -
+ renderPreview: (isMobile) => ( +
Vibrant Elegance -

New Scent [Sanctuary]

-

Transform your room into a peaceful escape.

-
) }, - // 3. HERO_V2 { type: 'HERO_V2', category: 'hero', description: 'Split Layout Hero featuring text on one side and a premium image card on the other.', + fieldsSpec: { + required: ['title', 'imageUrl'], + optional: ['tagline', 'description', 'buttonText', 'buttonLink', 'imagePosition'], + description: 'แบนเนอร์ Hero แบบแบ่งครึ่ง ซ้าย-ขวา เหมาะสำหรับเล่าเรื่องสินค้าตัวเด่นพร้อมภาพประกอบ' + }, payload: { - tagline: 'Pure Wellness', - title: 'The Organic [Reed Diffuser]', - description: 'Crafted with hand-harvested lavender and sweet orange essential oils.', + tagline: { th: 'สุขภาวะบริสุทธิ์', en: 'Pure Wellness' }, + title: { th: 'ก้านไม้หอมออร์แกนิก [Reed Diffuser]', en: 'The Organic [Reed Diffuser]' }, + description: { th: 'ผสมผสานน้ำมันหอมระเหยลาเวนเดอร์และส้มแท้จากธรรมชาติ 100%', en: 'Crafted with hand-harvested lavender and sweet orange essential oils.' }, imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=800&q=80', - buttonText: 'Shop Diffusers', + buttonText: { th: 'เลือกซื้อก้านไม้หอม', en: 'Shop Diffusers' }, buttonLink: '/shop/diffusers', imagePosition: 'right' }, - renderPreview: () => ( -
+ renderPreview: (isMobile) => ( +
Pure Wellness -

The Organic [Reed Diffuser]

+

The Organic [Reed Diffuser]

Crafted with hand-harvested lavender and sweet orange essential oils.

) }, - // 2.5 HERO_VIDEO { type: 'HERO_VIDEO', category: 'hero', description: 'Cinema-quality full background video banner with animated overlay typography and dual CTA buttons.', + fieldsSpec: { + required: ['videoUrl'], + optional: ['tagline', 'title', 'description', 'posterImageUrl', 'buttonText', 'buttonLink', 'secondaryButtonText', 'secondaryButtonLink', 'overlayOpacity', 'height', 'autoplay', 'loop', 'muted'], + description: 'วิดีโอแบนเนอร์เต็มจอ รองรับปุ่ม CTA หลักและปุ่มรอง ปรับความมืด Overlay ได้' + }, payload: { - tagline: 'Cinema of Scents', - title: 'Pure Botanical [Sanctuary]', - description: 'Immerse yourself in moving sensory atmospheres hand-blended for quiet luxury.', + tagline: { th: 'ภาพยนตร์แห่งกลิ่นหอม', en: 'Cinema of Scents' }, + title: { th: 'กลิ่นหอมธรรมชาติ [Sanctuary]', en: 'Pure Botanical [Sanctuary]' }, + description: { th: 'ดื่มด่ำกับบรรยากาศอันเงียบสงบ ผสมผสานด้วยมือเพื่อความหรูหราที่ผ่อนคลาย', en: 'Immerse yourself in moving sensory atmospheres hand-blended for quiet luxury.' }, videoUrl: 'https://cdn.coverr.co/videos/coverr-essential-oils-and-diffuser-5374/1080p.mp4', posterImageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1200&q=80', - buttonText: 'Discover Collection', + buttonText: { th: 'ค้นพบคอลเลกชัน', en: 'Discover Collection' }, buttonLink: '/shop', - secondaryButtonText: 'Watch Story', + secondaryButtonText: { th: 'ชมเรื่องราว', en: 'Watch Story' }, secondaryButtonLink: '/about', overlayOpacity: 40, height: 'large', @@ -150,852 +223,1086 @@ export default function CmsMockupPage() { loop: true, muted: true }, - renderPreview: () => ( -
-
- mock video -
- - Cinema of Scents - -

Pure Botanical [Sanctuary]

-

Immerse yourself in moving sensory atmospheres hand-blended for quiet luxury.

+ renderPreview: (isMobile) => ( +
+ poster +
+
+ Cinema of Scents +

Pure Botanical [Sanctuary]

+

Immerse yourself in moving sensory atmospheres hand-blended for quiet luxury.

- Discover Collection - Watch Story + +
) }, - // 4. USP_BAR { - type: 'USP_BAR', + type: 'HERO_CAROUSEL', category: 'hero', - description: 'Unique Selling Proposition Bar highlighting product perks (Icons & Labels).', + badge: 'new', + description: 'Mega promotional banner carousel with auto-sliding timer, navigation arrows, dots, and mobile aspect ratios.', + fieldsSpec: { + required: ['slides'], + optional: ['autoplay', 'interval', 'aspectRatio', 'mobileAspectRatio', 'showArrows', 'showDots', 'headerSpacing'], + description: 'สไลด์แบนเนอร์โปรโมชันใหญ่ รองรับรูปหลายสไลด์ สลับอัตโนมัติ และสัดส่วนแยกเดสก์ท็อป/มือถือ' + }, payload: { - items: [ - { icon: 'ShieldCheck', title: '100% Organic', desc: 'Certificated natural oils' }, - { icon: 'Truck', title: 'Free Shipping', desc: 'On orders above ฿1,500' }, - { icon: 'RotateCcw', title: 'Easy Returns', desc: '30-day money back guarantee' } + headerSpacing: 'below_header', + autoplay: true, + interval: 4500, + aspectRatio: '21/7', + mobileAspectRatio: '16/9', + showArrows: true, + showDots: true, + slides: [ + { + imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=1920&q=80', + linkUrl: '/shop', + alt: 'Mega Promotion 1', + title: { th: 'แคมเปญเปิดตัวกลิ่นใหม่', en: 'Seasonal Launch Collection' }, + subtitle: { th: 'รับของขวัญพิเศษเมื่อสั่งซื้อวันนี้', en: 'Complimentary gift with every order' }, + buttonText: { th: 'ช้อปเลย', en: 'Shop Now' } + }, + { + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1920&q=80', + linkUrl: '/shop', + alt: 'Mega Promotion 2' + } ] }, - renderPreview: () => ( -
-
-
-
100% Organic
-
Certificated natural oils
+ renderPreview: (isMobile) => ( +
+ slide +
+
+ Slide 1 of 2 +

Seasonal Launch Collection

+

Complimentary gift with every order

+
-
-
-
Free Shipping
-
On orders above ฿1,500
-
-
-
-
Easy Returns
-
30-day money back guarantee
+
+ +
) }, - // 5. BANNER { type: 'BANNER', category: 'hero', description: 'Clickable promotional block with headline overlay, ideal for campaigns.', + fieldsSpec: { + required: ['imageUrl'], + optional: ['title', 'description', 'buttonText', 'linkUrl'], + description: 'แบนเนอร์โปรโมชันแบบคลิกได้ทั้งบล็อก' + }, payload: { - imageUrl: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=800&q=80', - linkUrl: '/promotions', - title: 'Mid-Year Secret Sale', - description: 'Get up to 30% off on premium scent reed diffusers.', - buttonText: 'Shop Sale' + title: { th: 'โปรโมชันพิเศษประจำเดือน', en: 'Special Promotion' }, + description: { th: 'รับส่วนลดพิเศษสำหรับก้านไม้หอมปรับอากาศ', en: 'Get discount on our reed diffusers.' }, + imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=1200&q=80', + buttonText: { th: 'สั่งซื้อเลย', en: 'Buy Now' }, + linkUrl: '/shop' }, renderPreview: () => ( -
-
-

Mid-Year Secret Sale

-

Get up to 30% off on premium scent reed diffusers.

- +
+ banner +
+

Special Promotion

+

Get discount on our reed diffusers.

+
) }, - // 6. CATEGORIES + + // ========================================== + // MINIMAL & LUXURY (Category: minimal) + // ========================================== + { + type: 'HERO_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Quiet Luxury full-width centered typography hero with adjustable overlay darkness.', + fieldsSpec: { + required: ['imageUrl', 'title'], + optional: ['tagline', 'contentAlignment', 'overlayOpacity'], + description: 'แบนเนอร์สไตล์ Quiet Luxury ตัวอักษรเรียบหรูตรงกลาง ปรับความมืดของ Overlay ได้' + }, + payload: { + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1200&q=80', + tagline: { th: 'สารสกัดจากพฤกษศาสตร์ธรรมชาติ', en: 'AUTUMN EQUINOX · BOTANICAL ESSENCE' }, + title: { th: 'กลิ่นอายของผืนดินชุ่มน้ำและไม้ซีดาร์ [sanctuary]', en: 'The scent of damp earth and cedar [sanctuary]' }, + contentAlignment: 'center', + overlayOpacity: 25 + }, + renderPreview: () => ( +
+ minimal +
+
+ AUTUMN EQUINOX · BOTANICAL ESSENCE +

The scent of damp earth and cedar [sanctuary]

+
+
+ ) + }, + { + type: 'HERO_SPLIT_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Minimalist split layout hero with pure typography on one side and curated imagery on the other.', + fieldsSpec: { + required: ['imageUrl', 'title'], + optional: ['subtitle', 'imagePosition', 'backgroundColor'], + description: 'แบนเนอร์แบบสองฝั่งสไตล์มินิมอล เน้นการจัดวางตัวอักษรแบบโมเดิร์น' + }, + payload: { + imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=800&q=80', + title: { th: 'รังสรรค์ด้วยความเงียบสงบ เพื่อช่วงเวลาอันผ่อนคลาย', en: 'Formulated in silence, crafted for quiet moments.' }, + subtitle: { th: 'สกัดจากพฤกษศาสตร์เทือกเขาแอลป์ออร์แกนิก', en: 'Certified organic extraction from alpine botanicals.' }, + imagePosition: 'right', + backgroundColor: '#161917' + }, + renderPreview: (isMobile) => ( +
+
+

Formulated in silence, crafted for quiet moments.

+

Certified organic extraction from alpine botanicals.

+
+
+ split +
+
+ ) + }, + { + type: 'HERO_VIDEO_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Atmospheric silent video hero showcasing nature and serene motion.', + fieldsSpec: { + required: ['videoUrl'], + optional: ['tagline', 'title', 'posterImageUrl', 'height', 'overlayOpacity'], + description: 'วิดีโอแบนเนอร์สไตล์เงียบสงบ ไร้ปุ่มรบกวนสายตา' + }, + payload: { + videoUrl: 'https://cdn.coverr.co/videos/coverr-essential-oils-and-diffuser-5374/1080p.mp4', + posterImageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1200&q=80', + tagline: { th: 'งานศิลปะแห่งชีวิต', en: 'LIVING ARTWORK' }, + title: { th: 'หายใจอย่างมีสติ', en: 'Breathe with Intention' }, + height: 'large', + overlayOpacity: 25 + }, + renderPreview: () => ( +
+ vid-min +
+
+ LIVING ARTWORK +

Breathe with Intention

+
+
+ ) + }, + { + type: 'BANNER_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Quiet luxury typographic banner with concise headline and destination link.', + fieldsSpec: { + required: ['title'], + optional: ['subtitle', 'linkUrl', 'backgroundColor', 'textColor'], + description: 'แบนเนอร์ข้อความสไตล์โมเดิร์นคลาสสิก' + }, + payload: { + title: { th: 'สารสกัดพฤกษศาสตร์บริสุทธิ์ 100% เก็บเกี่ยวด้วยความเคารพธรรมชาติ', en: '100% pure botanical distillates, harvested with intention.' }, + subtitle: { th: 'ส่งฟรีแบบคาร์บอนสุทธิเป็นศูนย์ ทุกคำสั่งซื้อตั้งแต่ ฿1,500', en: 'Free carbon-neutral delivery on all orders over ฿1,500' }, + linkUrl: '/shop', + backgroundColor: '#1A1E1C', + textColor: '#EDEBE6' + }, + renderPreview: () => ( +
+

100% pure botanical distillates, harvested with intention.

+

Free carbon-neutral delivery on all orders over ฿1,500

+
+ ) + }, + { + type: 'ANNOUNCEMENT_BAR_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Minimalist scrolling announcements ticker with dot separators.', + fieldsSpec: { + required: ['slides'], + optional: ['backgroundColor', 'textColor', 'speed'], + description: 'แถบข้อความวิ่งด้านบนแบบมินิมอล' + }, + payload: { + slides: [ + 'COMPLIMENTARY BOTANICAL SAMPLE WITH EVERY ORDER', + 'HAND-POURED IN SMALL BATCHES' + ], + backgroundColor: '#0F1713', + textColor: '#DCE6E0', + speed: 4000 + }, + renderPreview: () => ( +
+ COMPLIMENTARY BOTANICAL SAMPLE WITH EVERY ORDER · HAND-POURED IN SMALL BATCHES +
+ ) + }, + { + type: 'USP_MINIMAL', + category: 'minimal', + badge: 'new', + description: 'Horizontal brand commitments and USP ticker with dot/pipe delimiters.', + fieldsSpec: { + required: ['items'], + optional: ['separator', 'backgroundColor', 'textColor'], + description: 'แถบข้อความการันตีจุดเด่น คั่นด้วยจุดหรือเส้น' + }, + payload: { + items: ['Ethically Sourced', 'Zero Synthetics', 'Hand-Poured', 'Cruelty-Free'], + separator: 'dot', + backgroundColor: '#141816', + textColor: '#C8D1CC' + }, + renderPreview: () => ( +
+ Ethically Sourced + + Zero Synthetics + + Hand-Poured + + Cruelty-Free +
+ ) + }, + + // ========================================== + // PRODUCTS & SHOP (Category: products) + // ========================================== { type: 'CATEGORIES', category: 'products', description: 'Visual category grid showcase to guide users to specific collections.', + fieldsSpec: { + required: [], + optional: ['title', 'subtitle', 'categoryIds'], + description: 'กริดหมวดหมู่สินค้า ดึงข้อมูลจากฐานข้อมูลอัตโนมัติหรือเลือกตาม ID' + }, payload: { - title: 'Shop by Collection', - subtitle: 'Choose your preferred sensory style', + title: { th: 'เลือกชมตามคอลเลกชัน', en: 'Shop by Collection' }, + subtitle: { th: 'เลือกสไตล์กลิ่นหอมที่คุณหลงใหล', en: 'Choose your preferred sensory style' }, categoryIds: [1, 2, 3] }, - renderPreview: () => ( + renderPreview: (isMobile) => (
-
-

Shop by Collection

+
+

Shop by Collection

Choose your preferred sensory style

-
- {[ - { name: 'Essential Oils', img: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=200&q=80' }, - { name: 'Reed Diffusers', img: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=200&q=80' }, - { name: 'Room Sprays', img: 'https://images.unsplash.com/photo-1612817288484-6f916006741a?auto=format&fit=crop&w=200&q=80' } - ].map((cat, i) => ( -
- {cat.name} -
- {cat.name} +
+ {['Essential Oils', 'Reed Diffusers', 'Room Sprays'].map((cat, idx) => ( +
+
+ cat
+ {cat}
))}
) }, - // 7. PRODUCTS { type: 'PRODUCTS', category: 'products', - description: 'Showcase grid or carousel for featured products, brand items, or a customized list with Quick Shop option.', - payload: { - title: 'Our Best Sellers', - subtitle: 'Hand-picked organic favorites', - type: 'featured', - limit: 3, - layout: 'grid', - enableQuickShop: true + description: 'Showcase grid or carousel for featured products, brand items, or a customized list.', + fieldsSpec: { + required: ['type'], + optional: ['title', 'subtitle', 'categoryId', 'brandId', 'productIds', 'limit'], + description: 'กริดแสดงสินค้า รองรับโหมด Featured, Scent, Brand หรือ Custom ID' }, - renderPreview: () => ( + payload: { + title: { th: 'สินค้าขายดีประจำเดือน', en: 'Best Sellers' }, + subtitle: { th: 'คัดสรรกลิ่นยอดนิยมจากลูกค้าของเรา', en: 'Our customer favorite products' }, + type: 'featured', + limit: 3 + }, + renderPreview: (isMobile) => (
-
-

Our Best Sellers

-

Hand-picked organic favorites

+
+

Best Sellers

+

Our customer favorite products

-
+
{[ - { name: 'Ozone Ambient Blend', price: '฿850', img: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=200&q=80' }, - { name: 'Lavender Sanctuary Diffuser', price: '฿1,290', img: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=200&q=80' }, - { name: 'Citrus Zest Room Mist', price: '฿450', img: 'https://images.unsplash.com/photo-1612817288484-6f916006741a?auto=format&fit=crop&w=200&q=80' } - ].map((prod, i) => ( -
-
-
- {prod.name} -
-
{prod.name}
-

{prod.price}

+ { name: 'Pure Lavender Essence', price: '฿890' }, + { name: 'Cedarwood Atmosphere', price: '฿1,250' }, + { name: 'Citrus Dawn Diffuser', price: '฿1,490' } + ].map((p, idx) => ( +
+
+ prod +
+
+ {p.name} + {p.price}
-
))}
) }, - // 8. PRODUCT_CAROUSEL { type: 'PRODUCT_CAROUSEL', category: 'products', description: 'Swipeable horizontal card carousel displaying specific product collections.', + fieldsSpec: { + required: [], + optional: ['title', 'description', 'collectionId', 'limit', 'showPrice', 'showAddToCart'], + description: 'สไลด์การ์ดสินค้าแนวนอน เลื่อนดูสินค้าในคอลเลกชันได้อย่างสะดวก' + }, payload: { - title: 'Featured Collection', - description: 'Selected scents for wellness journeys.', - collectionId: 'wellness-campaign', - limit: 5, + title: { th: 'คอลเลกชันพิเศษ', en: 'Featured Collection' }, + description: { th: 'สินค้าคัดสรรพิเศษสำหรับแคมเปญนี้', en: 'Hand-picked products for this campaign.' }, + limit: 6, showPrice: true, showAddToCart: true }, renderPreview: () => (
-
-
-

Featured Collection

-

Selected scents for wellness journeys

-
- Slide next → +
+

Featured Collection

+ View All →
-
- {[ - { name: 'Ozone Ambient', price: '฿850', img: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=150&q=80' }, - { name: 'Lavender Sanctuary', price: '฿1,290', img: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=150&q=80' }, - { name: 'Citrus Zest Mist', price: '฿450', img: 'https://images.unsplash.com/photo-1612817288484-6f916006741a?auto=format&fit=crop&w=150&q=80' }, - { name: 'Eucalyptus Mint', price: '฿890', img: 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?auto=format&fit=crop&w=150&q=80' } - ].map((prod, i) => ( -
-
-
- {prod.name} -
-
{prod.name}
-

{prod.price}

+
+ {[1, 2, 3, 4].map((i) => ( +
+
+ car
+ Botanical Diffuser #{i} + ฿1,200
))}
) }, - // 9. RELATED_PRODUCTS + { + type: 'PRODUCT_LAYOUT', + category: 'products', + badge: 'new', + description: 'Full product detail page layout template including media gallery, buy box, specs tabs, and reviews.', + fieldsSpec: { + required: [], + optional: ['showBreadcrumbs', 'enableStickyBuyBox', 'defaultTab'], + description: 'เทมเพลตมาตรฐานสำหรับหน้ารายละเอียดสินค้า ประกอบด้วยแกลเลอรี ป้ายราคา ตัวเลือกกลิ่น และรีวิว' + }, + payload: { + showBreadcrumbs: true, + enableStickyBuyBox: true, + defaultTab: 'description' + }, + renderPreview: (isMobile) => ( +
+
+ detail +
+
+ Signature Series +

Ozone & Wild Mint Reed Diffuser

+
฿1,850
+

Clean, crisp, oceanic botanical diffuser blending spearmint with maritime pine.

+ +
+
+ ) + }, { type: 'RELATED_PRODUCTS', category: 'products', description: 'Dynamic block recommending items from the same category for the product page layout.', + fieldsSpec: { + required: [], + optional: ['title', 'showHeading', 'showViewAllLink'], + description: 'บล็อกแนะนำสินค้าที่เกี่ยวข้องจากหมวดหมู่เดียวกัน' + }, payload: { - title: 'You May Also Like', + title: { th: 'สินค้าที่คุณอาจชอบ', en: 'Related Products' }, showHeading: true, showViewAllLink: true }, renderPreview: () => (
-
-

You May Also Like

- View All +
+

Related Products

+ View all
-
-
-
- mock +
+ {[1, 2, 3].map((i) => ( +
+ rel
-
-

Ozone Ambient Blend

-

฿850

-
-
-
-
- mock -
-
-

Lavender sanctuary

-

฿1,290

-
-
+ ))}
) }, - // 10. EDITORIAL_TILE + + // ========================================== + // STORY & EDITORIAL (Category: editorial) + // ========================================== { type: 'EDITORIAL_TILE', category: 'editorial', - description: 'Stunning editorial grid block presenting storytelling text alongside a curated campaign photo.', - payload: { - title: 'Moodboard [IRL]', - description: 'An expressive mix of texture, shape and movement. Deconstructed details, utilitarian elements and fluid tailoring come together in looks that feel personal.', - imageUrl: 'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?auto=format&fit=crop&w=800&q=80', - imagePosition: 'left', - imageAspectRatio: 'tall', - buttonText: 'Shop the looks', - buttonLink: '/shop', - backgroundColor: '#1E293B', - textColor: '#FFFFFF' + badge: 'updated', + description: 'Stunning editorial grid block presenting storytelling text alongside a curated campaign photo with adjustable aspect ratio.', + fieldsSpec: { + required: ['title', 'description', 'imageUrl', 'imagePosition'], + optional: ['imageAspectRatio', 'buttonText', 'buttonLink', 'backgroundColor', 'textColor'], + description: 'บล็อกเล่าเรื่องสไตล์นิตยสาร รองรับสัดส่วนภาพ landscape, wide, square, portrait, tall' }, - renderPreview: () => ( -
-
- mock + payload: { + title: { th: 'รังสรรค์ด้วยความหลงใหลในประสาทสัมผัส', en: 'Crafted with [Sensory Passion]' }, + description: { th: 'ทุกสูตรคือการคารวะต่อพฤกษศาสตร์ธรรมชาติ เพื่อมอบความสงบให้ทุกวันของคุณ', en: 'Every formulation is a tribute to pure botanical essences, hand-blended to capture nature’s quiet intelligence.' }, + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=800&q=80', + imagePosition: 'left', + imageAspectRatio: 'landscape', + buttonText: { th: 'อ่านเรื่องราวของเรา', en: 'Read Our Story' }, + buttonLink: '/about', + backgroundColor: '#FDFDF9', + textColor: '#1F3D2D' + }, + renderPreview: (isMobile) => ( +
+
+ editorial
-
-

Crafted with [Sensory Passion]

-

- Every formulation at HomAroma is a tribute to pure botanical essences, hand-blended to capture nature’s quiet intelligence. -

- +
+

Crafted with [Sensory Passion]

+

Every formulation is a tribute to pure botanical essences, hand-blended to capture nature’s quiet intelligence.

+
) }, - // 10.5 FEATURED_TILES { type: 'FEATURED_TILES', category: 'editorial', - description: 'Side-by-side campaign grid featuring square or tall images with centered titles and outline CTA buttons (Jo Malone aesthetic).', + badge: 'updated', + description: 'Side-by-side campaign grid featuring square or landscape images with dual-level links (Jo Malone aesthetic).', + fieldsSpec: { + required: ['tiles'], + optional: ['title', 'subtitle', 'headerAlign', 'showHeading', 'columns', 'containerWidth', 'paddingTop', 'paddingBottom', 'sectionPadding', 'layoutPreset', 'imageAspectRatio', 'textAlign', 'imageRounded', 'buttonStyle', 'backgroundColor', 'textColor'], + description: 'บล็อกการ์ดภาพคู่แบบ Jo Malone รองรับ headerAlign: left/center/right/none, containerWidth: standard/wide/full, paddingTop/paddingBottom: none/compact/normal/spacious, layoutPreset: editorial/cards/banner, imageAspectRatio: landscape/wide/square/portrait, ข้อความลิงก์สองระดับ' + }, payload: { - title: 'Summer Campaign', + title: { th: 'แคมเปญเด่นประจำฤดูกาล', en: 'Featured Campaigns' }, + headerAlign: 'left', + showHeading: true, columns: 2, - backgroundColor: '#FDFDF9', - textColor: '#1F3D2D', + containerWidth: 'wide', + paddingTop: 'compact', + paddingBottom: 'normal', + layoutPreset: 'editorial', + imageAspectRatio: 'landscape', + textAlign: 'left', + imageRounded: '2xl', + buttonStyle: 'link', tiles: [ { - title: 'Here Comes The Sun', - description: '', - imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=600&q=80', - buttonText: 'Shop Beach Blossom', + title: { th: 'วันหยุดแสนสะอาดสดชื่น', en: 'Weekend Clean' }, + description: { th: 'สัมผัสความอบอุ่นของแสงแดดยามเช้า', en: 'Embrace the crisp morning sun' }, + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=800&q=80', + imageAspectRatio: 'landscape', + buttonText: { th: 'เลือกซื้อชุดพักผ่อน →', en: 'Shop Relaxed Sets →' }, buttonLink: '/shop' }, { - title: 'The Scent Of A New Adventure', - description: '', - imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=600&q=80', - buttonText: 'Be The First To Know', + title: { th: 'ความสบายที่นุ่มนวล', en: 'Soft Casual' }, + description: { th: 'กลิ่นหอมผ่อนคลายตลอดทั้งวัน', en: 'Relaxing ambient notes for all day' }, + imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=800&q=80', + imageAspectRatio: 'landscape', + buttonText: { th: 'เลือกซื้อคอลเลกชันหญิง →', en: 'Shop Women →' }, buttonLink: '/shop' } ] }, - renderPreview: () => ( -
-
-
- mock -
-
Here Comes The Sun
- + renderPreview: (isMobile) => ( +
+
+

Featured Campaigns

-
-
- mock -
-
The Scent Of A New Adventure
- +
+ {[ + { title: 'Weekend Clean', link: 'Shop Relaxed Sets →', img: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=600&q=80' }, + { title: 'Soft Casual', link: 'Shop Women →', img: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=600&q=80' } + ].map((t, idx) => ( +
+
+ {t.title} +
+
+
{t.title}
+ {t.link} +
+
+ ))}
) }, - // 11. EDITORIAL_CAROUSEL { type: 'EDITORIAL_CAROUSEL', category: 'editorial', description: 'Stories and values slider displaying image slideshows side-by-side with localized editorial statements.', + fieldsSpec: { + required: ['slides'], + optional: ['title'], + description: 'สไลด์เล่าเรื่องราวคุณค่าของแบรนด์' + }, payload: { - title: 'The Wellness Philosophy', + title: { th: 'ปรัชญาแห่งสุขภาวะ', en: 'The Wellness [Philosophy]' }, slides: [ { category: 'Heritage', - title: 'Rooted in Nature', - description: 'Our ingredients are sustainably sourced from organic growers who share our respect for ecological balance.', - imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=400&q=80', - buttonText: 'Discover Sourcing', + title: { th: 'หยั่งรากในธรรมชาติ', en: 'Rooted in Nature' }, + description: { th: 'วัตถุดิบทั้งหมดมาจากผู้ปลูกเกษตรอินทรีย์ที่ยั่งยืน', en: 'Our ingredients are sustainably sourced from organic growers who share our respect for ecological balance.' }, + imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=800&q=80', + buttonText: { th: 'ค้นพบแหล่งกำเนิด', en: 'Discover Sourcing' }, buttonLink: '/sourcing' } ] }, renderPreview: () => ( -
-

The Wellness Philosophy

-
-
- mock -
-
- Heritage -
Rooted in Nature
-

Our ingredients are sustainably sourced from organic growers who share our respect for ecological balance.

- -
-
+
+ Heritage +

Rooted in Nature

+

Our ingredients are sustainably sourced from organic growers who share our respect for ecological balance.

) }, - // 12. SCENT_NOTES_BREAKDOWN { type: 'SCENT_NOTES_BREAKDOWN', category: 'editorial', description: 'Fragrance profile breakdowns containing Top, Heart/Middle, and Base notes lists.', + fieldsSpec: { + required: [], + optional: ['title', 'description', 'topNotes', 'heartNotes', 'middleNotes', 'baseNotes'], + description: 'โครงสร้างจำแนกระดับกลิ่นหอม แสดงโน้ต Top, Heart, Base' + }, payload: { - title: 'Scent Signature Breakdown', - description: 'Detailed analysis of fragrance volatility levels.', - topNotes: ['Italian Bergamot', 'Citrus Peel'], - heartNotes: ['Jasmine Absolute', 'French Lavender'], - baseNotes: ['Sandalwood', 'Clean Musk'] + title: { th: 'โครงสร้างกลิ่นหอม', en: 'Scent Notes Breakdown' }, + description: { th: 'การเดินทางของกลิ่นหอมตลอด 3 ระดับสัมผัส', en: 'The fragrance evolution across three olfactory layers.' }, + topNotes: ['Citrus', 'Green Tea', 'Bergamot'], + heartNotes: ['White Jasmine', 'Damask Rose'], + baseNotes: ['White Musk', 'Cedarwood', 'Amber'] }, renderPreview: () => ( -
-
-

Scent Signature Breakdown

-

Detailed analysis of fragrance volatility levels

-
-
-
- Top -

Italian Bergamot, Citrus Peel

+
+

Scent Notes

+
+
+ Top + Bergamot, Citrus
-
- Heart -

Jasmine Absolute, French Lavender

+
+ Heart + Jasmine, Rose
-
- Base -

Sandalwood, Clean Musk

+
+ Base + Cedar, Amber
) }, - // 13. QUOTE_CALLOUT { type: 'QUOTE_CALLOUT', category: 'editorial', description: 'Elegant text banner presenting callout quotations, ideal for customer testimonials.', + fieldsSpec: { + required: ['quote'], + optional: ['author', 'role'], + description: 'กล่องโควทคำคมพรีเมียม สำหรับคำนิยมหรือสโลแกน' + }, payload: { - quote: 'Fragrance is the invisible, unforgettable fashion accessory.', - author: 'Coco Chanel', - role: 'Fashion Designer' + quote: { th: 'กลิ่นหอมคือเครื่องประดับที่มองไม่เห็น แต่ยากจะลืมเลือน', en: 'Fragrance is the invisible, unforgettable accessory.' }, + author: 'Founder', + role: 'HomAroma Atelier' }, renderPreview: () => ( -
- “ -

- "Fragrance is the invisible, unforgettable fashion accessory." -

-
- — Coco Chanel | Fashion Designer -
+
+ +

"Fragrance is the invisible, unforgettable accessory."

+ — Founder, HomAroma Atelier
) }, - // 14. TEXT { - type: 'TEXT', + type: 'USP_BAR', category: 'editorial', - description: 'Plain text component for headers, centered paragraphs, or brand catchphrases.', + description: 'Unique Selling Proposition Bar highlighting product perks (Icons & Labels).', + fieldsSpec: { + required: ['items'], + optional: [], + description: 'แถบแสดงจุดเด่น 4 ช่องพร้อมไอคอน' + }, payload: { - title: 'Natural & Ecological Policy', - content: 'We use 100% natural, botanically derived ingredients in all formulations. Cruelty-free.', - textAlign: 'center' + items: [ + { title: '100% Pure', description: 'Botanical extracts' }, + { title: 'Free Shipping', description: 'Over ฿1,500' }, + { title: 'Eco Friendly', description: 'Zero carbon footprint' } + ] }, renderPreview: () => ( -
-

Natural & Ecological Policy

-

- We use 100% natural, botanically derived ingredients in all formulations. Cruelty-free. -

+
+
100% Pure
+
Free Shipping
+
Eco Friendly
) }, - // 15. RICH_TEXT - { - type: 'RICH_TEXT', - category: 'editorial', - description: 'Styled markdown block designed for longer stories or HTML embedding.', - payload: { - title: 'Corporate Social Responsibility', - content: '

Our commitments extend beyond scent creation. HomAroma proudly partners with rural farming families in Northern Thailand to source organic lemongrass oil.

  • Sustainable development goals
  • Fair-trade wages
' - }, - renderPreview: () => ( -
-

Corporate Social Responsibility

-
-

Our commitments extend beyond scent creation. HomAroma proudly partners with rural farming families in Northern Thailand to source organic lemongrass oil.

-
    -
  • Sustainable development goals
  • -
  • Fair-trade wages
  • -
-
-
- ) - }, - // 16. HERO_ARTICLE + + // ========================================== + // ARTICLE ELEMENTS (Category: articles) + // ========================================== { type: 'HERO_ARTICLE', category: 'articles', description: 'Editorial article header with background blur, date, author name, and title overlays.', + fieldsSpec: { + required: ['title', 'imageUrl'], + optional: ['subtitle', 'author', 'category', 'publishDate', 'overlayColor'], + description: 'ส่วนหัวบทความสไตล์นิตยสาร' + }, payload: { - title: 'Fragrance & Mindfulness Journey', - subtitle: 'How ambient scent transforms focus and breathing cycles.', - author: 'Dr. Aromatherapist', - category: 'Insights', - publishDate: '2026-07-27', - imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=600&q=80' + title: { th: 'เรื่องราวของกลิ่นหอมและการผ่อนคลาย', en: 'Scent Guide [Article]' }, + subtitle: { th: 'ค้นพบความลับเบื้องหลังน้ำมันหอมระเหย', en: 'Discover the story behind each fragrance.' }, + author: 'Aromatherapist', + category: 'Story', + publishDate: '2026-01-01', + imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=1200&q=80' }, renderPreview: () => ( -
-
-
- Insights - • - 2026-07-27 -
-

Fragrance & Mindfulness Journey

-

How ambient scent transforms focus and breathing cycles.

-

Written by Dr. Aromatherapist

+
+ art +
+ Story · 2026-01-01 +

Scent Guide [Article]

) }, - // 17. ARTICLE_HEADER { type: 'ARTICLE_HEADER', category: 'articles', description: 'Introductory page header for standard text articles.', + fieldsSpec: { + required: ['title'], + optional: ['subtitle'], + description: 'ส่วนหัวบทความมาตรฐาน' + }, payload: { - title: 'The Chemistry of Volatility', - subtitle: 'Understanding high, middle, and low evaporation rates of pure aromatherapy elements.' + title: { th: 'บทความแนะนำ', en: 'Article Title' }, + subtitle: { th: 'คำนำสั้นๆ สำหรับบทความนี้', en: 'A concise introduction to the story.' } }, renderPreview: () => ( -
-

The Chemistry of Volatility

-

Understanding high, middle, and low evaporation rates of pure aromatherapy elements.

+
+

Article Title

+

A concise introduction to the story.

) }, - // 18. ARTICLE_MEDIA { type: 'ARTICLE_MEDIA', category: 'articles', description: 'Article paragraph paired with a side image (left/right alignment).', + fieldsSpec: { + required: ['body'], + optional: ['heading', 'imageUrl', 'imagePosition', 'width'], + description: 'ย่อหน้าบทความคู่กับภาพประกอบ' + }, payload: { - heading: 'Sourcing Lavender Extract', - body: 'Our lavender is harvested at dawn in Provence when oil concentrations are highest, then steam-distilled locally within 4 hours.', - imagePosition: 'right', - imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=100&q=80' + heading: { th: 'หัวข้อย่อย', en: 'Article Section' }, + body: { th: 'เนื้อหาย่อหน้าบทความ...', en: 'Write one focused paragraph here with botanical insights.' }, + imagePosition: 'right' }, renderPreview: () => ( -
-
-
Sourcing Lavender Extract
-

- Our lavender is harvested at dawn in Provence when oil concentrations are highest, then steam-distilled locally within 4 hours. -

-
-
- mock +
+
+
Article Section
+

Write one focused paragraph here with botanical insights.

+
) }, - // 19. ARTICLE_GALLERY { type: 'ARTICLE_GALLERY', category: 'articles', description: 'Photo collection grids to show off multiple illustrations or steps.', + fieldsSpec: { + required: ['images'], + optional: ['layout'], + description: 'แกลเลอรีรูปภาพหลายรูปในบทความ' + }, payload: { layout: 'grid', images: [ - { imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=200&q=80' }, - { imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=200&q=80' } + { imageUrl: 'https://images.unsplash.com/photo-1608571423902-eed4a5ad8108?auto=format&fit=crop&w=400&q=80', alt: 'One' }, + { imageUrl: 'https://images.unsplash.com/photo-1547887537-6158d64c35b3?auto=format&fit=crop&w=400&q=80', alt: 'Two' } ] }, renderPreview: () => ( -
-
- mock -
-
- mock -
+
+
1
+
2
) }, - // 20. ARTICLE_FACTS { type: 'ARTICLE_FACTS', category: 'articles', description: 'Quick summaries or key takeaway bullets for editorial pieces.', + fieldsSpec: { + required: ['items'], + optional: ['title'], + description: 'กล่องสรุปข้อเท็จจริงสำคัญ' + }, payload: { - title: 'Key Scent Benefits', + title: { th: 'ประเด็นสำคัญ', en: 'Key Facts' }, items: [ - { title: 'Relaxation', description: 'Proven scent to lower blood pressure and cortisol levels.' }, - { title: 'Focus Boost', description: 'Peppermint elements trigger sensory wakefulness.' } + { title: '100% Organic', description: 'Certified by ECOCERT' }, + { title: 'Zero Additives', description: 'Pure unadulterated oil' } ] }, renderPreview: () => ( -
-

- Key Scent Benefits -

-
-
- Relaxation: Proven scent to lower blood pressure and cortisol levels. -
-
- Focus Boost: Peppermint elements trigger sensory wakefulness. -
+
+
Key Facts
+
+
• 100% Organic: Certified by ECOCERT
+
• Zero Additives: Pure unadulterated oil
) }, - // 21. ARTICLE_VIDEO { type: 'ARTICLE_VIDEO', category: 'articles', description: 'Embedded video player wrapper for articles.', + fieldsSpec: { + required: ['videoUrl'], + optional: ['aspectRatio'], + description: 'ตัวเล่นวิดีโอฝังในบทความ' + }, payload: { - videoUrl: 'https://www.youtube.com/watch?v=mock', + videoUrl: 'https://www.youtube.com/watch?v=VIDEO_ID', aspectRatio: '16:9' }, renderPreview: () => ( -
-
-
- -
- Watch Youtube Video Preview +
+
) }, - // 22. ARTICLE_REFERENCES { type: 'ARTICLE_REFERENCES', category: 'articles', description: 'Citation list or scientific reference cards.', + fieldsSpec: { + required: ['items'], + optional: ['title'], + description: 'รายการเอกสารอ้างอิง' + }, payload: { - title: 'Study Sources', - items: [ - { title: 'Journal of Aromatherapy Research (Vol. 12)', link: 'https://example.com' }, - { title: 'Clinical Scent Testing & Sleep Induction (2024)', link: 'https://example.com' } - ] + title: { th: 'เอกสารอ้างอิง', en: 'References' }, + items: [{ title: 'International Aromatherapy Journal 2026' }] }, renderPreview: () => ( -
-
Study Sources
- +
+ References + [1] International Aromatherapy Journal 2026
) }, - // 23. ARTICLE_TABLE { type: 'ARTICLE_TABLE', category: 'articles', description: 'Comparison table displaying technical parameters or specs.', + fieldsSpec: { + required: ['columns', 'rows'], + optional: ['title'], + description: 'ตารางเปรียบเทียบข้อมูล' + }, payload: { - title: 'Volatility Comparison', - columns: ['Fragrance Type', 'Top Note Evaporation', 'Average Life'], - rows: [ - { label: 'Essential Oil', cells: ['High (Fast)', '4-6 hours'] }, - { label: 'Carrier Blend', cells: ['Low (Slow)', '24-48 hours'] } - ] + title: { th: 'เปรียบเทียบคุณสมบัติ', en: 'Technical Comparison' }, + columns: ['Property', 'Value'], + rows: [{ label: 'Extraction', cells: ['Steam Distillation', 'Cold Pressed'] }] }, renderPreview: () => ( -
- - - - - - - - - - - - - - - - - - - - -
Fragrance TypeTop Note EvaporationAverage Life
Essential OilHigh (Fast)4-6 hours
Carrier BlendLow (Slow)24-48 hours
+
+
+ PropertyValue +
+
+ ExtractionSteam Distillation +
) }, - // 24. ARTICLE_DOWNLOAD { type: 'ARTICLE_DOWNLOAD', category: 'articles', description: 'File attachments download cards (PDF guides, catalogues).', + fieldsSpec: { + required: ['files'], + optional: ['title'], + description: 'กล่องดาวน์โหลดไฟล์แนบ' + }, payload: { - title: 'Available Resources', - files: [ - { title: 'Organic Certification PDF', fileType: 'PDF', url: '#' }, - { title: 'Aromatherapy Scent Catalogue', fileType: 'PDF', url: '#' } - ] + title: { th: 'ดาวน์โหลดเอกสาร', en: 'Downloads' }, + files: [{ title: 'Botanical Guide 2026', url: 'https://example.com/guide.pdf', fileType: 'PDF' }] }, renderPreview: () => ( -
-
Available Resources
-
- {[ - { title: 'Organic Certification PDF', size: '2.4 MB' }, - { title: 'Scent Catalogue', size: '4.8 MB' } - ].map((f, i) => ( -
-
-

{f.title}

-

{f.size} • PDF

-
- -
- ))} +
+
+ + Botanical Guide 2026 (PDF)
+
) }, - // 25. ARTICLE_CTA { type: 'ARTICLE_CTA', category: 'articles', description: 'Call-to-action blocks prompting next-step user clicks.', + fieldsSpec: { + required: ['title', 'primaryText', 'primaryLink'], + optional: ['alignment'], + description: 'บล็อกกระตุ้นการตัดสินใจปิดท้ายบทความ' + }, payload: { - title: 'Ready to start your wellness journey?', - primaryText: 'Explore Collection', - primaryLink: '/shop', - alignment: 'center' + title: { th: 'ต้องการข้อมูลเพิ่มเติม?', en: 'Need more information?' }, + primaryText: { th: 'ติดต่อเรา', en: 'Contact Us' }, + primaryLink: '/contact' }, renderPreview: () => ( -
-

Ready to start your wellness journey?

- +
+

Need more information?

+
) }, - // 26. NEWSLETTER + + // ========================================== + // FORMS & INFO (Category: forms) + // ========================================== { type: 'NEWSLETTER', category: 'forms', description: 'Email subscription block to attract newsletter sign-ups.', + fieldsSpec: { + required: ['title'], + optional: ['description', 'buttonText', 'placeholderText', 'showPrivacyCheckbox', 'privacyText'], + description: 'ฟอร์มรับสมัครจดหมายข่าวพร้อมกล่องยอมรับนโยบาย' + }, payload: { - title: 'Begin Your Wellness Journey', - description: 'Subscribe to receive 10% off your first purchase and exclusive updates.', - buttonText: 'Subscribe', - placeholderText: 'Enter your email address', - showPrivacyCheckbox: true, - privacyText: 'I agree to the privacy policy.' + title: { th: 'เริ่มต้นการเดินทางแห่งสุขภาวะ', en: 'Begin Your Wellness Journey' }, + description: { th: 'รับส่วนลด 10% สำหรับคำสั่งซื้อแรก', en: 'Subscribe to receive 10% off your first purchase.' }, + buttonText: { th: 'สมัครรับข่าวสาร', en: 'Subscribe' }, + placeholderText: 'Enter your email address' }, renderPreview: () => ( -
-
-

Begin Your Wellness Journey

-

Subscribe to receive 10% off your first purchase and exclusive updates.

-
+
+

Begin Your Wellness Journey

+

Subscribe to receive 10% off your first purchase.

- - -
-
- - I agree to the privacy policy. + +
) }, - // 27. ACCORDION { type: 'ACCORDION', category: 'forms', description: 'Question-answer accordions for FAQs, divided by custom categories.', + fieldsSpec: { + required: ['categories'], + optional: ['title'], + description: 'แถบพับคำถามที่พบบ่อย (FAQs) แยกหมวดหมู่' + }, payload: { - title: 'Frequently Asked Questions', + title: { th: 'คำถามที่พบบ่อย', en: 'Frequently Asked Questions' }, categories: [ { - name: 'General Policy', - icon: 'HelpCircle', + name: { th: 'ทั่วไป', en: 'General' }, questions: [ - { q: 'How long do Reed Diffusers last?', a: 'Normally, they evaporate gradually over 4 to 6 weeks depending on temperature levels.' }, - { q: 'Are essential oils safe for pets?', a: 'Some oils are toxic to dogs/cats. Please consult a veterinarian before diffusing.' } + { + q: { th: 'สินค้าเป็นออร์แกนิก 100% หรือไม่?', en: 'Are all products 100% organic?' }, + a: { th: 'ใช่วัตถุดิบทั้งหมดผ่านการรับรองมาตรฐานสากล', en: 'Yes, all extracts are certified organic.' } + } ] } ] }, renderPreview: () => ( -
-

- Frequently Asked Questions (General Policy) -

-
- {[ - { q: 'How long do Reed Diffusers last?', a: 'Normally, they evaporate gradually over 4 to 6 weeks depending on temperature levels.' }, - { q: 'Are essential oils safe for pets?', a: 'Some oils are toxic to dogs/cats. Please consult a veterinarian before diffusing.' } - ].map((faq, i) => ( -
-
- {faq.q} - -
-

{faq.a}

-
- ))} +
+
FAQs
+
+ Are all products 100% organic? +
) }, - // 28. CONTACT_INFO { type: 'CONTACT_INFO', category: 'forms', description: 'Beautiful information box showing address, telephone, and social details.', + fieldsSpec: { + required: ['title'], + optional: ['address', 'email', 'line', 'hours'], + description: 'กล่องข้อมูลติดต่อร้านค้า' + }, payload: { - title: 'Contact Details', - address: '123 Sukhumvit Rd, Bangkok, Thailand', - email: 'hello@homaroma.com', + title: { th: 'ติดต่อเรา', en: 'Contact Us' }, + address: '123 Sukhumvit Road, Bangkok', + email: 'hello@homaroma.shop', line: '@homaroma', - hours: 'Mon-Fri: 9AM - 6PM' + hours: 'Mon-Fri 9AM-6PM' }, renderPreview: () => ( -
-

Contact Details

-
-
- - 123 Sukhumvit Rd, Bangkok -
-
- - hello@homaroma.com -
-
- - Line: @homaroma -
-
- - Mon-Fri: 9AM - 6PM -
-
+
+
Bangkok, Thailand
+
hello@homaroma.shop
) }, - // 29. CONTACT_FORM { type: 'CONTACT_FORM', category: 'forms', description: 'General support email inquiry contact form.', + fieldsSpec: { + required: ['title'], + optional: ['subtitle'], + description: 'ฟอร์มส่งข้อความติดต่อสอบถาม' + }, payload: { - title: 'Get In Touch', - subtitle: 'We would love to hear from you.' + title: { th: 'ส่งข้อความหาเรา', en: 'Get In Touch' }, + subtitle: { th: 'เรายินดีตอบทุกคำถามของคุณ', en: 'We would love to hear from you.' } }, renderPreview: () => ( -
-
-

Get In Touch

-

We would love to hear from you.

-
-
- - - - -
+
+
Get In Touch
+ + +
+ ) + }, + + // ========================================== + // LAYOUT & CUSTOM (Category: layout) + // ========================================== + { + type: 'TEXT', + category: 'layout', + description: 'Plain text component for headers, centered paragraphs, or brand catchphrases.', + fieldsSpec: { + required: ['content'], + optional: ['title', 'textAlign'], + description: 'บล็อกข้อความตัวอักษรเรียบง่าย' + }, + payload: { + title: { th: 'คำมั่นสัญญาของเรา', en: 'Our Commitment' }, + content: { th: 'เรามุ่งมั่นคัดสรรเฉพาะสิ่งที่ดีที่สุดเพื่อคุณ', en: 'We only use 100% natural and sustainably sourced botanicals.' }, + textAlign: 'center' + }, + renderPreview: () => ( +
+

Our Commitment

+

We only use 100% natural and sustainably sourced botanicals.

+
+ ) + }, + { + type: 'RICH_TEXT', + category: 'layout', + description: 'Styled markdown block designed for longer stories or HTML embedding.', + fieldsSpec: { + required: ['content'], + optional: ['title'], + description: 'บล็อกข้อความจัดรูปแบบ HTML หรือ Markdown' + }, + payload: { + title: { th: 'เรื่องราวของแบรนด์', en: 'Brand Story' }, + content: { th: '

เรื่องราวความเป็นมาของแบรนด์...

', en: '

Tell the authentic story of your botanical journey here.

' } + }, + renderPreview: () => ( +
+
Brand Story
+

Tell the authentic story of your botanical journey here.

+
+ ) + }, + { + type: 'DIVIDER', + category: 'layout', + badge: 'new', + description: 'Section separation line with configurable style, thickness, spacing, color, and container width.', + fieldsSpec: { + required: [], + optional: ['width', 'style', 'thickness', 'spacing', 'color'], + description: 'เส้นคั่นปรับ style (solid/dashed/dotted), width (full/container), spacing (sm/md/lg) และสีได้' + }, + payload: { + width: 'container', + style: 'solid', + thickness: 1, + spacing: 'md', + color: '#334155' + }, + renderPreview: () => ( +
+
+
+ ) + }, + { + type: 'CUSTOM', + category: 'layout', + badge: 'new', + description: 'Dynamic extensible white-label block supporting custom components and flexible props.', + fieldsSpec: { + required: ['componentId'], + optional: ['props'], + description: 'บล็อกส่วนขยายสำหรับเพิ่ม Component พิเศษเฉพาะแบรนด์ เช่น BakeryCategories' + }, + payload: { + componentId: 'BakeryCategories', + props: { + title: { th: 'หมวดหมู่เบเกอรี่', en: 'Bakery Categories' }, + subtitle: { th: 'เลือกซื้อขนมอบตามหมวดหมู่ที่คุณชอบ', en: 'Explore fresh-baked favorites by collection.' }, + layout: 'horizontal' + } + }, + renderPreview: () => ( +
+ Custom Component: BakeryCategories +

Explore fresh-baked favorites by collection.

) } @@ -1035,25 +1342,52 @@ export default function CmsMockupPage() {

- {/* Search Input Bar */} -
- - setSearchQuery(e.target.value)} - className="w-full bg-night-900/80 border border-white/10 text-white rounded-2xl pl-10 pr-9 py-2.5 text-xs focus:outline-none focus:border-cyan-glow/50 focus:ring-1 focus:ring-cyan-glow/50 transition-all placeholder:text-slate-500" - /> - {searchQuery && ( + {/* Global Controls & Search */} +
+ {/* Device Preview Switcher */} +
- )} + +
+ + {/* Search Input */} +
+ + setSearchQuery(e.target.value)} + className="w-full bg-night-900/80 border border-white/10 text-white rounded-2xl pl-10 pr-9 py-2 text-xs focus:outline-none focus:border-cyan-glow/50 focus:ring-1 focus:ring-cyan-glow/50 transition-all placeholder:text-slate-500" + /> + {searchQuery && ( + + )} +
@@ -1065,7 +1399,7 @@ export default function CmsMockupPage() { key={cat.id} type="button" onClick={() => setActiveCategory(cat.id)} - className={`px-5 py-2 text-xs font-bold transition-all rounded-xl whitespace-nowrap cursor-pointer ${ + className={`px-4 py-2 text-xs font-bold transition-all rounded-xl whitespace-nowrap cursor-pointer ${ activeCategory === cat.id ? 'bg-cyan-glow text-night-900 shadow-lg shadow-cyan-glow/20' : 'text-slate-400 hover:text-white hover:bg-white/5' @@ -1111,11 +1445,12 @@ export default function CmsMockupPage() { {filteredBlocks.map((block) => { const localizedDesc = t(`cmsMockup.blocks.${block.type}`, block.description); const localizedCategory = t(`cmsMockup.categories.${block.category}`, block.category); + const isMobile = isBlockMobile(block.type); return (
{/* Block Header Info */}
@@ -1127,12 +1462,54 @@ export default function CmsMockupPage() { {localizedCategory} + {block.badge && ( + + {block.badge === 'new' ? '✨ NEW' : '⚡ UPDATED'} + + )}

{localizedDesc}

{/* Action buttons */} -
+
+ {/* Copy LLM Prompt Button */} + + + {/* View Schema Spec Button */} + + + {/* View JSON Payload Button */} + + {/* Copy JSON Payload Button */}
+ {/* Schema Spec Box */} + {showSpecFor === block.type && ( +
+
+ + {block.type} Schema Specification +
+

{block.fieldsSpec.description}

+
+
+ Required Fields +
+ {block.fieldsSpec.required.length > 0 ? ( + block.fieldsSpec.required.map((f) => ( + {f} + )) + ) : ( + None (all fields optional) + )} +
+
+
+ Optional Fields +
+ {block.fieldsSpec.optional.map((f) => ( + {f} + ))} +
+
+
+
+ )} + {/* JSON Code view */} {showJsonFor === block.type && ( -
+
{JSON.stringify(block.payload, null, 2)}
)} - {/* Live Visual Preview Frame */} -
-
- {block.renderPreview()} + {/* Live Visual Preview Frame with Responsive Toggle */} +
+
+ Preview: + +
+ +
+
+ {block.renderPreview(isMobile)} +
diff --git a/apps/backend/src/routes/pages.ts b/apps/backend/src/routes/pages.ts index 0519646..94b8dff 100644 --- a/apps/backend/src/routes/pages.ts +++ b/apps/backend/src/routes/pages.ts @@ -1,6 +1,6 @@ import { Elysia, t } from "elysia"; import prisma from "../lib/prisma"; -// Trigger reload: support landscape and wide aspect ratios for FEATURED_TILES and EDITORIAL_TILE +// Trigger reload: support paddingTop, paddingBottom, and sectionPadding for FEATURED_TILES import { LocalizedStringSchema, HeroSectionPayloadSchema, diff --git a/apps/mcp-server/section-toolkit.ts b/apps/mcp-server/section-toolkit.ts index 8211d6e..8fb1f6a 100644 --- a/apps/mcp-server/section-toolkit.ts +++ b/apps/mcp-server/section-toolkit.ts @@ -199,8 +199,8 @@ const PAGE_BLOCK_METADATA: Record = { FEATURED_TILES: { type: "FEATURED_TILES", requiredFields: ["tiles[].title", "tiles[].imageUrl"], - optionalFields: ["title", "subtitle", "columns", "backgroundColor", "textColor", "tiles[].description", "tiles[].buttonText", "tiles[].buttonLink", "tiles[].imageAspectRatio"], - renderedFields: ["title", "subtitle", "columns", "backgroundColor", "textColor", "tiles[].title", "tiles[].description", "tiles[].imageUrl", "tiles[].buttonText", "tiles[].buttonLink", "tiles[].imageAspectRatio"], + optionalFields: ["title", "subtitle", "headerAlign", "showHeading", "columns", "containerWidth", "paddingTop", "paddingBottom", "sectionPadding", "layoutPreset", "textAlign", "ctaStyle", "imageRounded", "backgroundColor", "textColor", "tiles[].description", "tiles[].buttonText", "tiles[].buttonLink", "tiles[].imageAspectRatio"], + renderedFields: ["title", "subtitle", "headerAlign", "showHeading", "columns", "containerWidth", "paddingTop", "paddingBottom", "sectionPadding", "layoutPreset", "textAlign", "ctaStyle", "imageRounded", "backgroundColor", "textColor", "tiles[].title", "tiles[].description", "tiles[].imageUrl", "tiles[].buttonText", "tiles[].buttonLink", "tiles[].imageAspectRatio"], storedOnlyFields: [], discoveryToolsNeeded: [], warnings: ["columns should be 2, 3, or 4."], diff --git a/apps/spa/src/components/DynamicFeaturedTiles.tsx b/apps/spa/src/components/DynamicFeaturedTiles.tsx index 0cf03e9..bf82d05 100644 --- a/apps/spa/src/components/DynamicFeaturedTiles.tsx +++ b/apps/spa/src/components/DynamicFeaturedTiles.tsx @@ -71,6 +71,47 @@ export default function DynamicFeaturedTiles({ payload }: DynamicFeaturedTilesPr } }; + const containerWidth = payload.containerWidth || 'standard'; + + const getContainerWidthClass = (width: string) => { + switch (width) { + case 'full': + return 'w-full max-w-none'; + case 'wide': + return 'w-full max-w-[1600px] mx-auto'; + case 'standard': + default: + return 'ui-section-inner'; + } + }; + + const headerAlign = payload.headerAlign || (layoutPreset === 'editorial' ? 'left' : 'center'); + const showHeading = payload.showHeading !== false && headerAlign !== 'none'; + + const getHeaderAlignClass = (align: string) => { + switch (align) { + case 'left': + return 'text-left mr-auto items-start'; + case 'right': + return 'text-right ml-auto items-end'; + case 'center': + default: + return 'text-center mx-auto items-center'; + } + }; + + const getAccentLineClass = (align: string) => { + switch (align) { + case 'left': + return 'mr-auto'; + case 'right': + return 'ml-auto'; + case 'center': + default: + return 'mx-auto'; + } + }; + const isLeftAlign = textAlign === 'left'; const isRightAlign = textAlign === 'right'; const alignContainerClass = isLeftAlign @@ -79,15 +120,46 @@ export default function DynamicFeaturedTiles({ payload }: DynamicFeaturedTilesPr ? 'items-end text-right' : 'items-center text-center'; + const padTop = payload.paddingTop || payload.sectionPadding || 'normal'; + const padBottom = payload.paddingBottom || payload.sectionPadding || 'normal'; + + const getPaddingTopClass = (pad: string) => { + switch (pad) { + 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 getPaddingBottomClass = (pad: string) => { + switch (pad) { + 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 (
-
+
{/* Optional Section Header */} - {(sectionTitle || sectionSubtitle) && ( -
+ {showHeading && (sectionTitle || sectionSubtitle) && ( +
{sectionTitle && (

{sectionTitle} @@ -98,7 +170,7 @@ export default function DynamicFeaturedTiles({ payload }: DynamicFeaturedTilesPr {sectionSubtitle}

)} -
+

)} diff --git a/apps/website/src/components/dynamic/DynamicPageRenderer.tsx b/apps/website/src/components/dynamic/DynamicPageRenderer.tsx index 43a8a24..b868435 100644 --- a/apps/website/src/components/dynamic/DynamicPageRenderer.tsx +++ b/apps/website/src/components/dynamic/DynamicPageRenderer.tsx @@ -1710,6 +1710,19 @@ function FeaturedTilesSection({ payload, lang }: { payload: Record { + switch (width) { + case 'full': + return 'w-full max-w-none' + case 'wide': + return 'w-full max-w-[1600px] mx-auto' + case 'standard': + default: + return 'w-full max-w-7xl mx-auto' + } + } const getColsClass = (cols: number) => { switch (cols) { @@ -1760,6 +1773,35 @@ function FeaturedTilesSection({ payload, lang }: { payload: Record { + switch (align) { + case 'left': + return 'text-left mr-auto items-start' + case 'right': + return 'text-right ml-auto items-end' + case 'center': + default: + return 'text-center mx-auto items-center' + } + } + + const getAccentLineClass = (align: string) => { + switch (align) { + case 'left': + return 'mr-auto' + case 'right': + return 'ml-auto' + case 'center': + default: + return 'mx-auto' + } + } + const isLeftAlign = textAlign === 'left' const isRightAlign = textAlign === 'right' const alignContainerClass = isLeftAlign @@ -1768,18 +1810,57 @@ function FeaturedTilesSection({ payload, lang }: { payload: Record { + switch (pad) { + 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 getPaddingBottomClass = (pad: string) => { + switch (pad) { + 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 ( -
-
- {(title || subtitle) && ( -
+
+
+ {showHeading && (title || subtitle) && ( +
{title && (

{renderAccentTitle(title)}

)} {subtitle &&

{subtitle}

} -
+
)} diff --git a/packages/types/index.ts b/packages/types/index.ts index 20ebca6..fb9f382 100644 --- a/packages/types/index.ts +++ b/packages/types/index.ts @@ -729,10 +729,16 @@ export const FeaturedTilesSectionPayloadSchema = z.object({ subtitle: LocalizedStringSchema.optional(), columns: z.number().optional().default(2), layoutPreset: z.enum(['editorial', 'spotlight', 'custom']).optional(), + headerAlign: z.enum(['left', 'center', 'right', 'none']).optional().default('center'), + showHeading: z.boolean().optional().default(true), textAlign: z.enum(['left', 'center', 'right']).optional(), ctaStyle: z.enum(['arrow_link', 'pill_button', 'solid_button', 'none']).optional(), imageAspectRatio: z.enum(['landscape', 'wide', 'square', 'portrait', 'tall', 'auto']).optional(), imageRounded: z.enum(['none', 'sm', 'md', 'xl', '2xl', '3xl', 'full']).optional(), + containerWidth: z.enum(['standard', 'wide', 'full']).optional().default('standard'), + paddingTop: z.enum(['none', 'compact', 'normal', 'spacious']).optional(), + paddingBottom: z.enum(['none', 'compact', 'normal', 'spacious']).optional(), + sectionPadding: z.enum(['none', 'compact', 'normal', 'spacious']).optional().default('normal'), backgroundColor: z.string().optional(), textColor: z.string().optional(), tiles: z.array(z.object({