x
This commit is contained in:
1 parent
ac08f4490b
commit
f8da2cceaf
8 files changed
+427
-2
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
import Image from 'next/image'
|
||||
import Link from '../LocalizedLink'
|
||||
import { Clock, Mail, MapPin, MessageCircle, Send, ChevronLeft, ChevronRight, Leaf, Droplet, Sparkles, Gift, CheckCircle, ShieldCheck, Heart } from 'lucide-react'
|
||||
import { Clock, Mail, MapPin, MessageCircle, Send, ChevronLeft, ChevronRight, Leaf, Droplet, Sparkles, Gift, CheckCircle, ShieldCheck, Heart, Download, FileText } from 'lucide-react'
|
||||
import { useState, useRef } from 'react'
|
||||
import type { Category, PageSection, Product } from '@homaroma/types'
|
||||
import { getCategoryImage } from '@homaroma/types'
|
||||
@@ -736,6 +736,128 @@ function ArticleReferencesSection({ payload, lang }: { payload: Record<string, u
|
||||
)
|
||||
}
|
||||
|
||||
function ArticleTableSection({ payload, lang }: { payload: Record<string, unknown>, lang: string }) {
|
||||
const i18nLang = useLang()
|
||||
const resolvedLang = lang === 'all' ? i18nLang : lang
|
||||
const title = localizedFromRecord(payload, 'title', resolvedLang)
|
||||
const note = localizedFromRecord(payload, 'note', resolvedLang)
|
||||
const columns = Array.isArray(payload.columns) ? payload.columns : []
|
||||
const rows = Array.isArray(payload.rows) ? payload.rows : []
|
||||
|
||||
if (columns.length < 2 || rows.length === 0) return null
|
||||
|
||||
return (
|
||||
<section className="bg-surface-page ui-section-band">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
{title && <h2 className="mb-8 text-3xl font-semibold text-text-main md:text-4xl">{title}</h2>}
|
||||
<div className="overflow-x-auto rounded-lg border border-line-primary/20">
|
||||
<table className="w-full min-w-[42rem] border-collapse text-left">
|
||||
<thead className="bg-surface-card">
|
||||
<tr>
|
||||
<th className="px-5 py-4 text-sm font-semibold text-text-main" scope="col" />
|
||||
{columns.map((column, index) => (
|
||||
<th key={index} className="px-5 py-4 text-sm font-semibold text-text-main" scope="col">
|
||||
{localizedValue(column, resolvedLang)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, rowIndex) => {
|
||||
const record = toRecord(row)
|
||||
const cells = Array.isArray(record.cells) ? record.cells : []
|
||||
return (
|
||||
<tr key={rowIndex} className="border-t border-line-primary/20">
|
||||
<th className="px-5 py-4 font-semibold text-text-main" scope="row">
|
||||
{localizedFromRecord(record, 'label', resolvedLang)}
|
||||
</th>
|
||||
{cells.map((cell, cellIndex) => (
|
||||
<td key={cellIndex} className="px-5 py-4 leading-7 text-muted-text">
|
||||
{localizedValue(cell, resolvedLang)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{note && <p className="mt-4 text-sm leading-6 text-muted-text">{note}</p>}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function ArticleDownloadSection({ payload, lang }: { payload: Record<string, unknown>, lang: string }) {
|
||||
const i18nLang = useLang()
|
||||
const resolvedLang = lang === 'all' ? i18nLang : lang
|
||||
const title = localizedFromRecord(payload, 'title', resolvedLang)
|
||||
const description = localizedFromRecord(payload, 'description', resolvedLang)
|
||||
const files = Array.isArray(payload.files) ? payload.files : []
|
||||
|
||||
if (files.length === 0) return null
|
||||
|
||||
return (
|
||||
<section className="bg-surface-card ui-section-band">
|
||||
<div className="mx-auto max-w-5xl">
|
||||
{title && <h2 className="text-3xl font-semibold text-text-main md:text-4xl">{title}</h2>}
|
||||
{description && <p className="mt-4 max-w-3xl leading-7 text-muted-text">{description}</p>}
|
||||
<div className="mt-8 divide-y divide-line-primary/20 border-y border-line-primary/20">
|
||||
{files.map((file, index) => {
|
||||
const record = toRecord(file)
|
||||
const fileTitle = localizedFromRecord(record, 'title', resolvedLang)
|
||||
const url = typeof record.url === 'string' ? record.url : ''
|
||||
const meta = [record.fileType, record.fileSize].filter((value) => typeof value === 'string' && value).join(' · ')
|
||||
if (!url) return null
|
||||
return (
|
||||
<a key={index} href={url} target="_blank" rel="noreferrer" className="flex items-center gap-4 py-5 text-text-main transition-opacity hover:opacity-70">
|
||||
<FileText className="h-6 w-6 shrink-0 text-brand-primary" aria-hidden="true" />
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block font-semibold">{fileTitle}</span>
|
||||
{meta && <span className="mt-1 block text-sm text-muted-text">{meta}</span>}
|
||||
</span>
|
||||
<Download className="h-5 w-5 shrink-0" aria-hidden="true" />
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function ArticleCtaSection({ payload, lang }: { payload: Record<string, unknown>, lang: string }) {
|
||||
const i18nLang = useLang()
|
||||
const resolvedLang = lang === 'all' ? i18nLang : lang
|
||||
const title = localizedFromRecord(payload, 'title', resolvedLang)
|
||||
const description = localizedFromRecord(payload, 'description', resolvedLang)
|
||||
const primaryText = localizedFromRecord(payload, 'primaryText', resolvedLang)
|
||||
const secondaryText = localizedFromRecord(payload, 'secondaryText', resolvedLang)
|
||||
const primaryLink = typeof payload.primaryLink === 'string' ? payload.primaryLink : ''
|
||||
const secondaryLink = typeof payload.secondaryLink === 'string' ? payload.secondaryLink : ''
|
||||
const centered = payload.alignment !== 'left'
|
||||
|
||||
if (!title || !primaryText || !primaryLink) return null
|
||||
|
||||
const primaryClass = "inline-flex min-h-12 items-center justify-center rounded-lg bg-brand-primary px-6 py-3 font-semibold text-surface-card transition-opacity hover:opacity-85"
|
||||
const secondaryClass = "inline-flex min-h-12 items-center justify-center rounded-lg border border-line-primary px-6 py-3 font-semibold text-text-main transition-colors hover:bg-surface-page"
|
||||
|
||||
return (
|
||||
<section className="bg-surface-card ui-section-band">
|
||||
<div className={`mx-auto max-w-5xl ${centered ? 'text-center' : 'text-left'}`}>
|
||||
<h2 className="text-3xl font-semibold text-text-main md:text-4xl">{title}</h2>
|
||||
{description && <p className={`mt-4 max-w-2xl leading-7 text-muted-text ${centered ? 'mx-auto' : ''}`}>{description}</p>}
|
||||
<div className={`mt-8 flex flex-wrap gap-3 ${centered ? 'justify-center' : 'justify-start'}`}>
|
||||
{primaryLink.startsWith('/') ? <Link href={primaryLink} className={primaryClass}>{primaryText}</Link> : <a href={primaryLink} className={primaryClass}>{primaryText}</a>}
|
||||
{secondaryText && secondaryLink && (
|
||||
secondaryLink.startsWith('/') ? <Link href={secondaryLink} className={secondaryClass}>{secondaryText}</Link> : <a href={secondaryLink} className={secondaryClass}>{secondaryText}</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function NewsletterSection({ payload, lang }: { payload: Record<string, unknown>, lang: string }) {
|
||||
const i18nLang = useLang()
|
||||
const resolvedLang = lang === 'all' ? i18nLang : lang
|
||||
@@ -1389,6 +1511,12 @@ export default function DynamicPageRenderer({ sections, categories, lang: langPr
|
||||
return <ArticleVideoSection key={section.id} payload={payload} lang={lang} />
|
||||
case 'ARTICLE_REFERENCES':
|
||||
return <ArticleReferencesSection key={section.id} payload={payload} lang={lang} />
|
||||
case 'ARTICLE_TABLE':
|
||||
return <ArticleTableSection key={section.id} payload={payload} lang={lang} />
|
||||
case 'ARTICLE_DOWNLOAD':
|
||||
return <ArticleDownloadSection key={section.id} payload={payload} lang={lang} />
|
||||
case 'ARTICLE_CTA':
|
||||
return <ArticleCtaSection key={section.id} payload={payload} lang={lang} />
|
||||
case 'SCENT_NOTES_BREAKDOWN':
|
||||
return (
|
||||
<ScrollReveal key={section.id}>
|
||||
|
||||
Reference in new issue
Block a user