Files

242 lines
7.5 KiB
TypeScript

import {
Calendar,
Github,
Globe,
Linkedin,
MapPin,
Twitter,
} from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
interface SocialLinks {
twitter?: string;
linkedin?: string;
github?: string;
website?: string;
}
interface Stats {
followers: number;
following: number;
contributions: number;
}
interface User {
name: string;
avatar?: string;
coverImage?: string;
role?: string;
company?: string;
bio?: string;
location?: string;
joinedAt?: string;
skills?: string[];
socialLinks?: SocialLinks;
stats?: Stats;
isFollowing?: boolean;
}
interface UserProfile3Props {
user?: User;
className?: string;
}
const formatNumber = (num: number): string => {
if (num >= 1000000) {
const value = num / 1000000;
const formatted = parseFloat(value.toFixed(1).replace(/\.0$/, "")).toLocaleString(
"fa-IR",
{ useGrouping: false },
);
return `${formatted} میلیون`;
}
if (num >= 1000) {
const value = num / 1000;
const formatted = parseFloat(value.toFixed(1).replace(/\.0$/, "")).toLocaleString(
"fa-IR",
{ useGrouping: false },
);
return `${formatted} هزار`;
}
return num.toLocaleString("fa-IR");
};
const UserProfile3 = ({
user = {
name: "سارا احمدی",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar8.jpg",
coverImage:
"/block-media/shadcnblocks/block/photos/pawel-czerwinski-O4fAgtXLRwI-unsplash.jpg",
role: "مهندس طراحی",
company: "لینیر",
bio: "پل زدن بین طراحی و مهندسی برای ساخت تجربه‌های کاربری روان. پیش‌تر سیستم‌های طراحی در نوشن ساخته و به Radix UI مشارکت کرده‌ام. درباره توکن‌های طراحی، معماری کامپوننت و تقاطع زیبایی‌شناسی و کارایی می‌نویسم.",
location: "تهران، ایران",
joinedAt: "فروردین ۱۴۰۰",
skills: [
"React",
"TypeScript",
"Figma",
"سیستم‌های طراحی",
"CSS",
"انیمیشن",
],
socialLinks: {
twitter: "https://twitter.com",
linkedin: "https://linkedin.com",
github: "https://github.com",
website: "https://example.com",
},
stats: {
followers: 8420,
following: 312,
contributions: 1247,
},
isFollowing: false,
},
className,
}: UserProfile3Props) => {
const initials = user.name
.split(" ")
.map((n) => n[0])
.join("");
const socialIcons = [
{ key: "twitter", icon: Twitter, href: user.socialLinks?.twitter },
{ key: "linkedin", icon: Linkedin, href: user.socialLinks?.linkedin },
{ key: "github", icon: Github, href: user.socialLinks?.github },
{ key: "website", icon: Globe, href: user.socialLinks?.website },
].filter((item) => item.href);
return (
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
<div className="container">
<div className="mx-auto max-w-2xl overflow-hidden rounded-xl border bg-card">
<div className="relative h-32 bg-muted sm:h-40">
{user.coverImage && (
<img
src={user.coverImage}
alt=""
className="size-full object-cover"
/>
)}
</div>
<div className="relative px-6 pb-6">
<div className="-mt-12 mb-4 flex items-end justify-between sm:-mt-14">
<Avatar className="size-24 border-4 border-card sm:size-28">
<AvatarImage
src={user.avatar}
alt={user.name}
className="object-cover"
/>
<AvatarFallback className="text-xl font-semibold">
{initials}
</AvatarFallback>
</Avatar>
<div className="flex gap-2">
<Button variant={user.isFollowing ? "outline" : "default"}>
{user.isFollowing ? "دنبال‌شده" : "دنبال کردن"}
</Button>
<Button variant="outline">پیام</Button>
</div>
</div>
<div className="space-y-1">
<h2 className="text-xl font-bold">{user.name}</h2>
<p className="text-muted-foreground">
{user.role}
{user.company && (
<>
{" "}
در <span className="font-medium">{user.company}</span>
</>
)}
</p>
</div>
{user.bio && (
<p className="mt-4 text-sm leading-relaxed text-muted-foreground">
{user.bio}
</p>
)}
<div className="mt-4 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-muted-foreground">
{user.location && (
<div className="flex items-center gap-1.5">
<MapPin className="size-3.5" />
<span>{user.location}</span>
</div>
)}
{user.joinedAt && (
<div className="flex items-center gap-1.5">
<Calendar className="size-3.5" />
<span>عضویت از {user.joinedAt}</span>
</div>
)}
</div>
{socialIcons.length > 0 && (
<div className="mt-4 flex gap-3">
{socialIcons.map(({ key, icon: Icon, href }) => (
<a
key={key}
href={href}
target="_blank"
rel="noopener noreferrer"
className="text-muted-foreground transition-colors hover:text-foreground"
>
<Icon className="size-5" />
</a>
))}
</div>
)}
{user.stats && (
<div className="mt-6 flex gap-6 border-t pt-6">
<div>
<span className="font-semibold">
{formatNumber(user.stats.followers)}
</span>{" "}
<span className="text-muted-foreground">دنبال‌کننده</span>
</div>
<div>
<span className="font-semibold">
{formatNumber(user.stats.following)}
</span>{" "}
<span className="text-muted-foreground">دنبال‌شده</span>
</div>
<div>
<span className="font-semibold">
{formatNumber(user.stats.contributions)}
</span>{" "}
<span className="text-muted-foreground">مشارکت</span>
</div>
</div>
)}
{user.skills && user.skills.length > 0 && (
<div className="mt-6 border-t pt-6">
<h3 className="mb-3 text-sm font-medium">مهارت‌ها</h3>
<div className="flex flex-wrap gap-2">
{user.skills.map((skill) => (
<Badge key={skill} variant="secondary">
{skill}
</Badge>
))}
</div>
</div>
)}
</div>
</div>
</div>
</section>
);
};
export { UserProfile3 };