کاستومایز
پسندِ تپندهPulse Heart
قرصِ پسندیدنی که با هر فشار میتپه: قلب جمع میشه، از جاش فنر میزنه و رقمِ شمارنده با رولِ اودومتری یکی بالا میره.
وابستگیها
نوع تعامل
روی قرص کلیک کن یا با `Enter`/`Space` فشارش بده تا وضعیت بین پسندیده و نپسندیده بچرخه و شمار یکی بالا یا پایین بره. با ماوس و لمس، ضربان کامل اجرا میشه — قلب تا `dotSize` جمع میشه و با `overshoot` از جاش رد میشه، قرص به اندازهی `beat` درصد کم میشه و رقمِ عوضشده با `rollDuration` میچرخه. با صفحهکلید ضربان رد میشه: وضعیت و شمار بیدرنگ عوض میشن تا کاربر منتظرِ انیمیشن نمونه. اگه `prefers-reduced-motion` روشن باشه، مسیرِ اشارهگر هم به همون تعویضِ بیدرنگ تبدیل میشه.
پراپها
گزینههایی که میتونی به کامپوننت بدی؛ ستارهدارها اجباریاند.
likedbooleanحالتِ controlled؛ بده تا مالکیتِ وضعیت با تو باشه. تغییرِ بیرونی بدونِ اجرای ضربان مینشینه.
defaultLikedbooleanپیشفرض: falseوضعیتِ اولیه توی حالتِ uncontrolled.
countnumberپیشفرض: 0عددی که نشون داده میشه؛ هر فشار یکی اضافه یا کم میکنه. نمایش با ارقامِ فارسی و جداکنندهی «٬»ـه.
onChange(liked: boolean, count: number) => voidبا هر فشار، وضعیت و شمارِ تازه رو میده.
showCountbooleanپیشفرض: trueنمایشِ شمار؛ خاموشکردنش قرص رو به دایره جمع میکنه.
icon"heart" | "star" | "thumb" | ReactNodeپیشفرض: "heart"heart · star · thumbگلیفِ آماده یا هر عنصرِ دلخواه.
نصب
۱. این آدرس رو یکبار توی components.json بذار تا shadcn مخزن فارسیفای رو بشناسه.
{
"registries": {
"@farsify": "https://farsify.ir/r/{name}.json"
}
}۲. بعد با دستورِ زیر کامپوننت رو نصب کن.
npx shadcn@latest add @farsify/pulse-heartپیشنیاز: Tailwind CSS v4 و صفحهٔ راستبهچپ dir="rtl".
نمونه
"use client";
import { useState } from "react";
import { PulseHeart } from "@/components/farsify/pulse-heart";
export function PostLike() {
const [liked, setLiked] = useState(false);
const [count, setCount] = useState(1204);
return (
<PulseHeart
liked={liked}
count={count}
onChange={(next, total) => {
setLiked(next);
setCount(total);
}}
/>
);
}
// بدون کنترل — خودش وضعیت و شمار را نگه میدارد
<PulseHeart count={1204} />
// ستاره بهجای قلب، بدونِ شمار
<PulseHeart icon="star" showCount={false} likedColor="#f5b942" />نکتهها
- برای اتصال به سرور، `onChange` رو بگیر و **بعد** از پاسخِ موفق `liked` و `count` رو بده — حالتِ controlled تغییرِ بیرونی رو بدونِ اجرای ضربان مینشونه، پس دوبار نمیتپه.
- دمو با `count={1204}` شروع میشه ولی خودِ کامپوننت پیشفرضِ `0` داره؛ شمارِ واقعی (مثلاً جمعِ پسندهای سرور) رو از والد بده و به مقدارِ دمو تکیه نکن.
- رولِ اودومتری فقط وقتی یه رقم عوض شه همون یه خونه رو میچرخونه؛ اگه طولِ رشته عوض شه (۹۹۹ ← ۱٬۰۰۰) کلِ عدد یهجا جابهجا میشه — عیناً رفتارِ مرجع.
- iconِ آماده داخلِ گروهِ مقیاسشدنیِ SVG مینشینه و ضخامتِ خط از `--ph-stroke` میآد (`1.5 × size / 24`). اگه `icon` رو یه `ReactNode` بدی، اون عنصر جای کلِ `<svg>` رو میگیره و ضربان روی `<span>`ِ بیرونی اعمال میشه — پس ضخامتِ خطش رو خودت با `size` هماهنگ کن.
- با `prefers-reduced-motion`، هم ضربان و هم رول خاموش میشن و رنگ با گذارِ ملایم عوض میشه؛ شمار هنوز فوراً بهروز میشه، پس چیزی از قلم نمیافته.
- این پورت **راستبهچپ نمیشه** و این عمدیه: چیدمان LTR-safeـه (`inline-flex` و `padding-inline-end` خودشون آینه میشن) و محورِ ضربان مقیاسِ متقارنِ دورِ مرکزه. فقط متن و ارقام فارسی شدن — همون قاعدهی `jelly-radio`.
مجوز
کد بعد از نصب مالِ خودته؛ هر تغییری خواستی بده و توی پروژهی خودت نگهش دار. برای پروژههای شخصی و تجاری آزاده، حتی اگه کدت بسته باشه. فقط اسم و لینک فارسیفای رو یه جا توی پروژه نگه دار.