Files
reui-blocks/blocks/user-profile9.tsx
T

262 lines
7.8 KiB
TypeScript

import {
ArrowDown,
ArrowUp,
Calendar,
Eye,
FileText,
Github,
Globe,
Linkedin,
MapPin,
MessageSquare,
Star,
Twitter,
Users,
} from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
interface Stat {
label: string;
value: string;
change?: number;
icon: "eye" | "users" | "star" | "file" | "message";
}
interface User {
name: string;
avatar?: string;
coverImage?: string;
role?: string;
company?: string;
location?: string;
joinedAt?: string;
bio?: string;
socialLinks?: {
twitter?: string;
linkedin?: string;
github?: string;
website?: string;
};
}
interface UserProfile9Props {
user?: User;
stats?: Stat[];
className?: string;
}
const statIcons = {
eye: Eye,
users: Users,
star: Star,
file: FileText,
message: MessageSquare,
};
const UserProfile9 = ({
user = {
name: "امیر رضایی",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar5.webp",
coverImage:
"/block-media/shadcnblocks/block/photos/pawel-czerwinski-O4fAgtXLRwI-unsplash.jpg",
role: "مهندس ارشد نرم‌افزار",
company: "ورسل",
location: "تهران، ایران",
joinedAt: "فروردین ۱۴۰۰",
bio: "ساخت آینده توسعه وب. مشارکت‌کننده متن‌باز، علاقه‌مند به TypeScript و عاشق قهوه. سابقه کار در استرایپ و گوگل.",
socialLinks: {
twitter: "https://twitter.com",
linkedin: "https://linkedin.com",
github: "https://github.com",
website: "https://example.com",
},
},
stats = [
{
label: "بازدید پروفایل",
value: "۱۲٬۸۴۷",
change: 12.5,
icon: "eye",
},
{
label: "دنبال‌کننده",
value: "۸٬۴۲۰",
change: 8.2,
icon: "users",
},
{
label: "ستاره دریافت‌شده",
value: "۲٬۱۵۶",
change: -3.1,
icon: "star",
},
{ label: "پست‌ها", value: "۱۴۲", change: 24.8, icon: "file" },
],
className,
}: UserProfile9Props) => {
const initials = user.name
.split(" ")
.map((n) => n[0])
.join("");
return (
<div
dir="rtl"
lang="fa"
className={cn("w-full max-w-4xl space-y-6", className)}
>
<Card className="overflow-hidden pt-0">
<div
className="h-32 bg-muted bg-cover bg-center sm:h-40"
style={{
backgroundImage: user.coverImage
? `url(${user.coverImage})`
: undefined,
}}
/>
<CardContent className="relative pb-6">
<div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:gap-6">
<Avatar className="-mt-12 size-24 border-4 border-card shadow-lg sm:-mt-16 sm:size-32">
<AvatarImage
src={user.avatar}
alt={user.name}
className="object-cover"
/>
<AvatarFallback className="text-3xl font-semibold">
{initials}
</AvatarFallback>
</Avatar>
<div className="flex-1 space-y-1">
<h1 className="text-xl font-bold">{user.name}</h1>
<p className="text-muted-foreground">
{user.role}
{user.company && (
<span>
{" "}
در <span className="font-medium">{user.company}</span>
</span>
)}
</p>
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-muted-foreground">
{user.location && (
<span className="flex items-center gap-1">
<MapPin className="size-3.5" />
{user.location}
</span>
)}
{user.joinedAt && (
<span className="flex items-center gap-1">
<Calendar className="size-3.5" />
عضویت از {user.joinedAt}
</span>
)}
</div>
</div>
<div className="flex gap-2">
<Button>دنبال کردن</Button>
<Button variant="outline">پیام</Button>
</div>
</div>
{user.bio && (
<p className="mt-4 text-sm text-muted-foreground">{user.bio}</p>
)}
<div className="mt-4 flex items-center gap-2">
{user.socialLinks?.twitter && (
<Button variant="ghost" size="icon" className="size-8" asChild>
<a
href={user.socialLinks.twitter}
target="_blank"
rel="noopener noreferrer"
>
<Twitter className="size-4" />
</a>
</Button>
)}
{user.socialLinks?.linkedin && (
<Button variant="ghost" size="icon" className="size-8" asChild>
<a
href={user.socialLinks.linkedin}
target="_blank"
rel="noopener noreferrer"
>
<Linkedin className="size-4" />
</a>
</Button>
)}
{user.socialLinks?.github && (
<Button variant="ghost" size="icon" className="size-8" asChild>
<a
href={user.socialLinks.github}
target="_blank"
rel="noopener noreferrer"
>
<Github className="size-4" />
</a>
</Button>
)}
{user.socialLinks?.website && (
<Button variant="ghost" size="icon" className="size-8" asChild>
<a
href={user.socialLinks.website}
target="_blank"
rel="noopener noreferrer"
>
<Globe className="size-4" />
</a>
</Button>
)}
</div>
</CardContent>
</Card>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{stats.map((stat) => {
const Icon = statIcons[stat.icon];
const isPositive = stat.change && stat.change > 0;
const isNegative = stat.change && stat.change < 0;
return (
<Card key={stat.label}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{stat.label}
</CardTitle>
<Icon className="size-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-xl font-bold">{stat.value}</div>
{stat.change !== undefined && (
<p
className={cn(
"mt-1 flex items-center gap-1 text-xs",
isPositive && "text-emerald-600",
isNegative && "text-red-600",
!isPositive && !isNegative && "text-muted-foreground",
)}
>
{isPositive && <ArrowUp className="size-3" />}
{isNegative && <ArrowDown className="size-3" />}
{Math.abs(stat.change).toLocaleString("fa-IR", {
useGrouping: false,
})}
٪ نسبت به ماه قبل
</p>
)}
</CardContent>
</Card>
);
})}
</div>
</div>
);
};
export { UserProfile9 };