feat(home): پروژه‌های شاخص بدون تب وضعیت — سه کارت ثابت (بابک، میرزاطاهر ۳، میرزا طاهر ۵)

This commit is contained in:
aramesh-site deploy
2026-10-09 14:49:42 +00:00
parent adcb288064
commit 3c17bd5081
@@ -1,87 +1,37 @@
import React, { useState } from 'react' import React from 'react'
import { AnimatePresence, motion } from 'framer-motion' import { AnimatePresence, motion } from 'framer-motion'
import { Reveal } from '../Reveal' import { Reveal } from '../Reveal'
import { PremiumButton } from '../PremiumButton' import { PremiumButton } from '../PremiumButton'
import { ProjectCard } from '../ProjectCard' import { ProjectCard } from '../ProjectCard'
import { SectionHeading } from '../SectionHeading' import { SectionHeading } from '../SectionHeading'
import { useSectionHeading, useSite, useStatusLabel } from '../../api' import { useSectionHeading, useSite } from '../../api'
import { useFieldSaver } from '../../admin/AdminContext' import { useFieldSaver } from '../../admin/AdminContext'
import { useLang } from '../../i18n/lang' import { useLang } from '../../i18n/lang'
import { InlineEdit } from '../admin/InlineEdit' import { InlineEdit } from '../admin/InlineEdit'
import type { ProjectStatus } from '../../data/site'
export function FeaturedProjects() { export function FeaturedProjects() {
const { status_labels, projects } = useSite() const { projects } = useSite()
const { t, href } = useLang() const { href } = useLang()
const heading = useSectionHeading('featured_projects') const heading = useSectionHeading('featured_projects')
const save = useFieldSaver() const save = useFieldSaver()
const saveStatusLabel = (key: string, value: string) => { // سه پروژهٔ ثابت صفحهٔ اصلی — بدون تب وضعیت؛ ویرایش پنل همان‌جا اعمال می‌شود
const label = status_labels.find((s) => s.key === key) const FEATURED_TITLES = ['آرامش - بابک', 'آرامش - میرزاطاهر 3', 'آرامش - میرزا طاهر 5']
if (!label) return const list = projects.filter((p) => FEATURED_TITLES.includes(p.title))
void save('status-labels', label.id, { label: value }, (d) => { .sort((a, b) => FEATURED_TITLES.indexOf(a.title) - FEATURED_TITLES.indexOf(b.title))
const s = d.status_labels.find((x) => x.id === label.id)
if (s) s.label = value
})
}
const FILTERS: { key: ProjectStatus; label: string }[] = [
{ key: 'done', label: useStatusLabel('done') },
{ key: 'progress', label: useStatusLabel('progress') },
]
const [status, setStatus] = useState<ProjectStatus>('done')
// سه پروژه از دیتابیس — ویرایش پنل همان‌جا اعمال می‌شود
const list = projects.filter((p) => p.status === status).slice(0, 3)
const BASE_IMG_URL = "/seed-media/2026/09/";
return ( return (
<section className="bg-ink py-24 lg:py-32" aria-labelledby="projects-title"> <section className="bg-ink py-24 lg:py-32" aria-labelledby="projects-title">
<div className="mx-auto max-w-site px-6 lg:px-10"> <div className="mx-auto max-w-site px-6 lg:px-10">
<SectionHeading title={heading.title} lead={heading.lead} headingKey="featured_projects" /> <SectionHeading title={heading.title} lead={heading.lead} headingKey="featured_projects" />
{/* دکمه‌های فیلتر مینیمال و شیشه‌ای (بدون کادر) */}
<div className="mt-10 flex items-center justify-center gap-4 md:gap-6" role="tablist" aria-label={t('projectFilterAria')}>
{FILTERS.map((filter, index) => {
const isSelected = status === filter.key
return (
<React.Fragment key={filter.key}>
{index > 0 && (
<span className="h-6 w-[2px] rounded-full bg-ivory/10" aria-hidden="true" />
)}
<button
type="button"
role="tab"
aria-selected={isSelected}
onClick={() => setStatus(filter.key)}
className={`group relative rounded-lg px-6 py-2.5 text-sm font-medium transition-all duration-300 ease-lux active:scale-95 cursor-pointer select-none backdrop-blur-md ${
isSelected
? 'bg-copper/15 text-copper shadow-[0_4px_15px_rgba(197,143,92,0.1)]'
: 'bg-transparent text-ivory/60 hover:bg-white/5 hover:text-ivory'
}`}
>
<span className="relative z-10 transition-colors duration-300 ease-out">
<InlineEdit
value={filter.label}
onSave={(v) => saveStatusLabel(filter.key, v)}
/>
</span>
</button>
</React.Fragment>
)
})}
</div>
<div className="mt-10 min-h-[420px]"> <div className="mt-10 min-h-[420px]">
<AnimatePresence mode="wait"> <AnimatePresence mode="wait">
<motion.div <motion.div
key={status} key="featured"
initial={{ opacity: 0, y: 15 }} initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }} animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -15 }}
transition={{ duration: 0.3, ease: [0.23, 1, 0.32, 1] }} transition={{ duration: 0.3, ease: [0.23, 1, 0.32, 1] }}
className="grid gap-6 lg:grid-cols-3" className="grid gap-6 lg:grid-cols-3"
> >