پرتوپرتو

کارت متریک (Metric Card)

کامپوننت نمایش معیارها و آمار به صورت خلاصه با پشتیبانی از نمودار و درصد تغییر

معرفی

کامپوننت Metric Card برای نمایش معیارها و آمارهای مهم به صورت خلاصه استفاده می‌شود. این کامپوننت شامل عنوان، مقدار، درصد تغییر و نمودار کوچک (Sparkline) است.

استفاده پایه

کاربران فعال

۴,۶۰۵
۰.۱٪-
import {
  MetricCard,
  MetricCardHeader,
  MetricCardLabel,
  MetricCardContent,
  MetricCardValue,
  MetricCardDifferential,
  MetricCardSparkline,
} from '@parto-system-design/ui';
import { Users } from 'lucide-react';

export default function MyComponent() {
  const data = [
    { value: 4000, timestamp: '2024-01-01' },
    { value: 4200, timestamp: '2024-01-02' },
    { value: 4100, timestamp: '2024-01-03' },
    // ...
  ];

  return (
    <MetricCard>
      <MetricCardHeader>
        <MetricCardLabel icon={<Users className="h-3.5 w-3.5" />}>
          کاربران فعال
        </MetricCardLabel>
      </MetricCardHeader>
      <MetricCardContent>
        <MetricCardValue>4,605</MetricCardValue>
        <MetricCardDifferential variant="negative">
          -0.1%
        </MetricCardDifferential>
      </MetricCardContent>
      <MetricCardSparkline data={data} dataKey="value" />
    </MetricCard>
  );
}

حالت‌های مختلف

با آیکون و Tooltip

کاربران فعال

۴,۳۶۰
۴.۳٪-
import { Users } from 'lucide-react';

<MetricCard>
  <MetricCardHeader>
    <MetricCardLabel 
      icon={<Users className="h-3.5 w-3.5" />}
      tooltip="تعداد کاربران فعال در 24 ساعت گذشته"
    >
      کاربران فعال
    </MetricCardLabel>
  </MetricCardHeader>
  <MetricCardContent>
    <MetricCardValue>4,605</MetricCardValue>
    <MetricCardDifferential variant="positive">
      +2.5%
    </MetricCardDifferential>
  </MetricCardContent>
  <MetricCardSparkline data={data} dataKey="value" />
</MetricCard>

با لینک خارجی

درآمد ماهانه

۲۵۰M
۱۲.۳٪+
<MetricCard>
  <MetricCardHeader href="https://example.com/analytics">
    <MetricCardLabel>درآمد ماهانه</MetricCardLabel>
  </MetricCardHeader>
  <MetricCardContent>
    <MetricCardValue>۲۵۰M</MetricCardValue>
    <MetricCardDifferential variant="positive">
      +12.3%
    </MetricCardDifferential>
  </MetricCardContent>
  <MetricCardSparkline data={revenueData} dataKey="value" />
</MetricCard>

بدون نمودار

کاربران جدید

۱,۲۳۴
۵.۲٪+
<MetricCard>
  <MetricCardHeader>
    <MetricCardLabel>کاربران جدید</MetricCardLabel>
  </MetricCardHeader>
  <MetricCardContent>
    <MetricCardValue>1,234</MetricCardValue>
    <MetricCardDifferential variant="positive">
      +5.2%
    </MetricCardDifferential>
  </MetricCardContent>
</MetricCard>

حالت بارگذاری

<MetricCard isLoading={true} />

حالت انگلیسی (LTR)

Active Users

4,870
36.0%+
<MetricCard dir="ltr">
  <MetricCardHeader href="https://example.com">
    <MetricCardLabel tooltip="Number of active users in the last 24 hours">
      Active Users
    </MetricCardLabel>
  </MetricCardHeader>
  <MetricCardContent>
    <MetricCardValue>4,605</MetricCardValue>
    <MetricCardDifferential variant="negative">
      -0.1%
    </MetricCardDifferential>
  </MetricCardContent>
  <MetricCardSparkline data={data} dataKey="value" />
</MetricCard>

Props

MetricCard

Prop

Type

MetricCardHeader

Prop

Type

MetricCardLabel

Prop

Type

MetricCardDifferential

Prop

Type

MetricCardSparkline

Prop

Type

مثال‌های کاربردی

داشبورد آنالیتیکس

const metrics = [
  {
    label: "کاربران فعال",
    value: "4,605",
    differential: "-0.1%",
    variant: "negative",
    data: activeUsersData,
  },
  {
    label: "فروش امروز",
    value: "۱۲۳M",
    differential: "+5.2%",
    variant: "positive",
    data: salesData,
  },
  {
    label: "نرخ تبدیل",
    value: "3.24%",
    differential: "+0.8%",
    variant: "positive",
    data: conversionData,
  },
];

<div className="grid grid-cols-1 md:grid-cols-3 gap-4" dir="rtl">
  {metrics.map((metric) => (
    <MetricCard key={metric.label}>
      <MetricCardHeader>
        <MetricCardLabel>{metric.label}</MetricCardLabel>
      </MetricCardHeader>
      <MetricCardContent>
        <MetricCardValue>{metric.value}</MetricCardValue>
        <MetricCardDifferential variant={metric.variant}>
          {metric.differential}
        </MetricCardDifferential>
      </MetricCardContent>
      <MetricCardSparkline data={metric.data} dataKey="value" />
    </MetricCard>
  ))}
</div>

با React Query

import { useQuery } from '@tanstack/react-query';

function MetricCardWithQuery() {
  const { data, isLoading } = useQuery({
    queryKey: ['metrics'],
    queryFn: fetchMetrics,
  });

  return (
    <MetricCard isLoading={isLoading}>
      <MetricCardHeader>
        <MetricCardLabel>کاربران فعال</MetricCardLabel>
      </MetricCardHeader>
      <MetricCardContent>
        <MetricCardValue>
          {data?.value.toLocaleString('fa-IR')}
        </MetricCardValue>
        <MetricCardDifferential variant={data?.trend > 0 ? 'positive' : 'negative'}>
          {data?.trend > 0 ? '+' : ''}{data?.trend}%
        </MetricCardDifferential>
      </MetricCardContent>
      <MetricCardSparkline data={data?.history || []} dataKey="value" />
    </MetricCard>
  );
}

نکات مهم

ساختار داده Sparkline

نمودار Sparkline نیاز به آرایه‌ای از داده دارد که هر آیتم شامل:

type SparklineData = {
  value: number;      // مقدار عددی
  timestamp: string;  // زمان (برای reference، در نمودار نمایش داده نمی‌شود)
}

رنگ‌بندی Differential

  • variant="positive": سبز (برند) - برای تغییرات مثبت
  • variant="negative": قرمز (destructive) - برای تغییرات منفی

نمایش علامت مثبت/منفی

علامت مثبت (+) یا منفی (-) به صورت خودکار در سمت چپ عدد نمایش داده می‌شود، حتی در حالت RTL. می‌توانید مقدار را با یا بدون علامت پاس دهید:

// هر دو حالت درست کار می‌کنند:
<MetricCardDifferential variant="negative">-۰.۱٪</MetricCardDifferential>
<MetricCardDifferential variant="negative">۰.۱٪-</MetricCardDifferential>
// هر دو به صورت "-۰.۱٪" نمایش داده می‌شوند

RTL Support

کامپوننت به طور کامل از RTL پشتیبانی می‌کند. برای استفاده در محیط انگلیسی، dir="ltr" را به MetricCard اضافه کنید:

<MetricCard dir="ltr">
  {/* ... */}
</MetricCard>

رابطه با کامپوننت‌های دیگر

  • Card: پایه کامپوننت
  • Tooltip: برای نمایش اطلاعات بیشتر
  • Skeleton: برای حالت loading
  • Badge: می‌توان در کنار differential استفاده کرد

الهام‌گیری

این کامپوننت از Supabase Design System الهام گرفته شده است.