90 lines
3.9 KiB
TypeScript
90 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { ArrowUpLeft, ArrowUpRight, FolderKanban } from "lucide-react";
|
|
import { Portfolio } from "@/utilities/types/portfolio.type";
|
|
import { useTranslations, useLocale } from "next-intl";
|
|
import Image from "next/image";
|
|
import { BACKEND_URL } from "@/utilities/constants/urls.constant";
|
|
|
|
const tabs = ["all", "software", "network"] as const;
|
|
|
|
export default function Projects({ data }: { data: Portfolio[] }) {
|
|
const [activeTab, setActiveTab] = useState<string>("all");
|
|
const t = useTranslations("home.projects");
|
|
const locale = useLocale();
|
|
|
|
const filteredPortfolios = data.filter((p) => (activeTab === "all" ? true : p.category === activeTab));
|
|
|
|
const ArrowIcon = locale === "en" ? ArrowUpRight : ArrowUpLeft;
|
|
|
|
return (
|
|
<section className="py-12 border-t border-slate-800/50" id="portfolios_form">
|
|
<div className="flex flex-col justify-between gap-6 mb-12 md:flex-row md:items-end">
|
|
<div>
|
|
<h2 className="flex items-center gap-3 mb-4 text-3xl font-bold text-white">
|
|
<FolderKanban className="text-orange-500" />
|
|
{t("title")}
|
|
</h2>
|
|
<p className="text-gray-400">{t("subtitle")}</p>
|
|
</div>
|
|
|
|
{/* Tabs */}
|
|
<div className="flex flex-wrap items-center gap-2 p-1 border bg-slate-900/50 rounded-xl border-slate-800 w-fit">
|
|
{tabs.map((tab) => (
|
|
<button
|
|
key={tab}
|
|
onClick={() => setActiveTab(tab)}
|
|
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
activeTab === tab ? "bg-orange-500 text-white shadow-lg shadow-orange-500/20" : "text-gray-400 hover:text-white hover:bg-slate-800/50"
|
|
}`}
|
|
>
|
|
{t(`tabs.${tab}`)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
{filteredPortfolios.map((p) => (
|
|
<div
|
|
key={p.id}
|
|
className="flex flex-col h-full overflow-hidden transition-all duration-300 border cursor-pointer group bg-slate-900/30 border-slate-800 rounded-2xl hover:border-orange-500/50"
|
|
>
|
|
{/* Image placeholder */}
|
|
<div className="relative w-full h-48 overflow-hidden shrink-0">
|
|
<Image
|
|
src={`${BACKEND_URL}/uploads/${p.featuredImage}`}
|
|
fill
|
|
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
className="object-cover transition-transform duration-500 group-hover:scale-105"
|
|
alt={`تصویر ${p.title}`}
|
|
/>
|
|
<div className="absolute px-3 py-1 text-xs text-gray-300 border rounded-full top-4 right-4 rtl:right-auto rtl:left-4 bg-black/50 backdrop-blur-sm border-slate-700">
|
|
{t(`tabs.${p.category}`)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content wrapper taking remaining height */}
|
|
<div className="flex flex-col flex-1 p-6">
|
|
{/* Title & Desc wrapper pushed to top */}
|
|
<div className="mb-auto">
|
|
<h3 className="mb-2 text-xl font-bold text-white transition-colors group-hover:text-orange-500 line-clamp-2">{p.title}</h3>
|
|
<p className="mb-6 text-sm text-gray-400 line-clamp-2">{p.description}</p>
|
|
</div>
|
|
|
|
{/* View Project button pushed to bottom */}
|
|
<div className="flex items-center justify-between mt-4 text-sm font-medium text-orange-500">
|
|
<span>{t("view_project")}</span>
|
|
<ArrowIcon
|
|
className={`w-5 h-5 transition-transform group-hover:-translate-y-1 ${locale === "en" ? "group-hover:translate-x-1" : "group-hover:-translate-x-1"}`}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|