Files
aramesh-backend/frontend/src/pages/Projects.tsx
T
2026-09-12 10:35:17 +03:30

93 lines
3.8 KiB
TypeScript

import React, { useState } from 'react';
import { PageHero } from '../components/PageHero';
import { Reveal } from '../components/Reveal';
import { ProjectCard } from '../components/ProjectCard';
import { Gallery } from '../components/home/Gallery';
import { ContactSection } from '../components/ContactSection';
import type { ProjectStatus } from '../data/site';
import { useSite, useStatusLabel } from '../api';
import { useFieldSaver } from '../admin/AdminContext';
import { InlineEdit } from '../components/admin/InlineEdit';
import { AddItemButton, EditableItem } from '../admin/Editable';
export function Projects() {
const { projects, status_labels } = useSite();
const save = useFieldSaver();
const saveStatusLabel = (key: string, value: string) => {
const label = status_labels.find((s) => s.key === key);
if (!label) return;
void save('status-labels', label.id, { label: value }, (d) => {
const s = d.status_labels.find((x) => x.id === label.id);
if (s) s.label = value;
});
};
const doneLabel = useStatusLabel('done');
const progressLabel = useStatusLabel('progress');
const FILTERS: {key: ProjectStatus;label: string;}[] = [
{ key: 'done', label: doneLabel },
{ key: 'progress', label: progressLabel }
];
const [status, setStatus] = useState<ProjectStatus>('done');
const list = projects.filter((p) => p.status === status);
return (
<>
<PageHero pageKey="projects" />
<section className="bg-ink py-24 lg:py-32" aria-label="فهرست پروژه‌ها">
<div className="mx-auto max-w-site px-6 lg:px-10">
{/* دکمه‌های فیلتر مینیمال و شیشه‌ای (وسط‌چین و بدون کادر) */}
<div className="flex items-center justify-center gap-4 md:gap-6" role="tablist" aria-label="فیلتر وضعیت پروژه">
{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-12 grid gap-6 lg:grid-cols-3">
{list.map((project, i) => (
<Reveal key={project.id} delay={0.05 * i} className="h-full">
<EditableItem resource="projects" item={project} className="h-full">
<ProjectCard project={project} imageClass="h-80" />
</EditableItem>
</Reveal>
))}
<AddItemButton resource="projects" />
</div>
</div>
</section>
<Gallery />
<ContactSection />
</>
);
}