124 lines
4.8 KiB
TypeScript
124 lines
4.8 KiB
TypeScript
import React from 'react'
|
|
import { ArrowLeftIcon } from 'lucide-react'
|
|
import { Reveal } from '../Reveal'
|
|
import { ButtonLink } from '../Button'
|
|
import { useSite } from '../../api'
|
|
import { useLang } from '../../i18n/lang'
|
|
import { useFieldSaver } from '../../admin/AdminContext'
|
|
import { InlineEdit } from '../admin/InlineEdit'
|
|
import { SingletonPill } from '../../admin/Editable'
|
|
|
|
type StoryProps = {
|
|
showLink?: boolean;
|
|
showLabel?: boolean;
|
|
showQuote?: boolean;
|
|
alignTop?: boolean;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
export function Story({ showLink = true, showLabel = true, showQuote = false, alignTop = false, children }: StoryProps) {
|
|
const { story } = useSite()
|
|
const { href } = useLang()
|
|
const save = useFieldSaver()
|
|
|
|
const saveStory = (field: string, value: unknown) =>
|
|
save('story', story.id, { [field]: value }, (d) => {
|
|
;(d.story as unknown as Record<string, unknown>)[field] = value
|
|
})
|
|
|
|
const saveParagraph = (index: number, value: string) => {
|
|
const paragraphs = [...story.paragraphs]
|
|
paragraphs[index] = value
|
|
void saveStory('paragraphs', paragraphs)
|
|
}
|
|
|
|
return (
|
|
<section id="story" className="bg-ink py-24 lg:py-32" aria-labelledby="story-title">
|
|
<div className={`mx-auto grid max-w-site gap-14 px-6 lg:grid-cols-2 lg:px-10 ${alignTop ? 'items-start' : 'items-center'}`}>
|
|
<div>
|
|
{showLabel && (
|
|
<Reveal>
|
|
<h2 id="story-title" className="text-section font-bold text-ivory">
|
|
<InlineEdit value={story.title} onSave={(v) => saveStory('title', v)} />
|
|
</h2>
|
|
<div className="mt-6 h-px w-24 bg-copper/70" />
|
|
</Reveal>
|
|
)}
|
|
|
|
<Reveal delay={0.08}>
|
|
{story.paragraphs.map((paragraph, i) => (
|
|
<p key={i} className={`text-base font-light leading-9 text-ivory/65 ${i === 0 ? 'mt-8' : 'mt-5'}`}>
|
|
<InlineEdit multiline value={paragraph} onSave={(v) => saveParagraph(i, v)} />
|
|
</p>
|
|
))}
|
|
</Reveal>
|
|
|
|
<Reveal delay={0.16}>
|
|
<div className="mt-10 grid grid-cols-2 gap-8 border-t border-ivory/10 pt-8">
|
|
<div>
|
|
<p className="text-2xl font-bold text-copper">
|
|
<InlineEdit value={story.stat1_value} onSave={(v) => saveStory('stat1_value', v)} />
|
|
</p>
|
|
<p className="mt-2 text-sm font-light text-ivory/55">
|
|
<InlineEdit value={story.stat1_label} onSave={(v) => saveStory('stat1_label', v)} />
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold text-copper">
|
|
<InlineEdit value={story.stat2_value} onSave={(v) => saveStory('stat2_value', v)} />
|
|
</p>
|
|
<p className="mt-2 text-sm font-light text-ivory/55">
|
|
<InlineEdit value={story.stat2_label} onSave={(v) => saveStory('stat2_label', v)} />
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</Reveal>
|
|
|
|
{showQuote && story.quote && (
|
|
<Reveal delay={0.2}>
|
|
<div className="mt-12 border-r-2 border-copper bg-char/40 p-6">
|
|
<p className="text-sm font-light leading-8 text-ivory/80">
|
|
<InlineEdit multiline value={story.quote} onSave={(v) => saveStory('quote', v)} />
|
|
</p>
|
|
<p className="mt-5 text-sm font-bold text-copper">
|
|
<InlineEdit value={story.quote_author} onSave={(v) => saveStory('quote_author', v)} />
|
|
</p>
|
|
</div>
|
|
</Reveal>
|
|
)}
|
|
|
|
{showLink && (
|
|
<Reveal delay={0.22}>
|
|
<ButtonLink to={href(story.link_href)} variant="outline" className="mt-10 font-light">
|
|
<InlineEdit value={story.link_label} onSave={(v) => saveStory('link_label', v)} />
|
|
<ArrowLeftIcon className="h-4 w-4 ltr:-scale-x-100" />
|
|
</ButtonLink>
|
|
</Reveal>
|
|
)}
|
|
|
|
{children && (
|
|
<Reveal delay={0.24}>
|
|
{children}
|
|
</Reveal>
|
|
)}
|
|
</div>
|
|
|
|
<div className="relative grid grid-cols-2 gap-4">
|
|
<SingletonPill resource="story" label="تصاویر و نقلقول بخش درباره ما" className="absolute -top-10 ltr:left-0 rtl:right-0" />
|
|
{story.bento.map((item, i) => (
|
|
<Reveal key={item.src + i} delay={0.06 * i}>
|
|
<div className="overflow-hidden">
|
|
<img
|
|
src={item.src}
|
|
alt={item.alt}
|
|
className="aspect-square w-full object-cover transition-transform duration-500 ease-lux hover:scale-105"
|
|
/>
|
|
</div>
|
|
</Reveal>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|