گالریِ حلقویCircular Gallery

نوارِ قوسیِ کارت‌های تصویر روی یه استوانه‌ی نامرئی: با کشیدن یا چرخِ ماوس می‌چرخه، توی دو لبه محو می‌شه و با چرخشِ تند موجِ ظریفی برمی‌داره. کلیک روی هر کارت بازش می‌کنه — بزرگ می‌شه، توضیحش می‌آد و بقیه کم‌نور و بی‌رنگ می‌شن.

محمدجواد

ساخته شده توسط محمدجواد

سازنده فارسی‌فای، بچه دولوپر

وابستگی‌ها

بدون وابستگی

نوع تعامل

بکش یا با چرخِ ماوس بچرخون — حرکت فنریه و موقعِ توقف به نزدیک‌ترین کارت می‌چسبه. فلش‌ها و PageUp/PageDown (کلیدهای جهت) قدم‌به‌قدم می‌رن و Home/End به دو سر می‌جهن. کلیک روی کارت بازش می‌کنه (کلیکِ دوباره یا Escape می‌بنده) و هاور کمی کارت رو بلند می‌کنه.

پراپ‌ها

گزینه‌هایی که می‌تونی به کامپوننت بدی؛ ستاره‌دارها اجباری‌اند.

items
Array<{ image: string; text?: string; description?: string; alt?: string }>پیش‌فرض: ۱۲ عکسِ نمونه

تصویرهای گالری؛ `text` برچسبِ زیرِ کارت، `description` توضیحِ حالتِ باز و `alt` متنِ جایگزین است. برشِ تصویر مرکزی است، پس نسبتِ نزدیک به کارت تمیزترین نتیجه را می‌دهد.

bend
numberپیش‌فرض: 3

عمقِ قوسِ ریل؛ صفر یعنی ردیفِ تخت. منفی، قوس را به سمتِ دیگر خم می‌کنه.

textColor
stringپیش‌فرض: '#ffffff'

رنگِ برچسب‌ها، حلقه‌ی فوکوسِ کیبورد و جای‌نگاهِ تصویرِ در حالِ بارگذاری.

borderRadius
numberپیش‌فرض: 0.05

گردیِ گوشه‌ی کارت‌ها به نسبتِ ضلعِ کوچک‌ترشان (۰ تا ۰٫۵).

font
stringپیش‌فرض: 'bold 30px Figtree'

فونتِ برچسب‌ها به شکلِ shorthand کاملِ CSS. اگر همان پیش‌فرض بماند، قلم از گوگل‌فونت بار می‌شود؛ برای فارسی قلمِ خودتان را بدهید.

fontUrl
stringپیش‌فرض: —

نشانیِ فایل یا شیته‌ی فونتِ دلخواه؛ اگر بدهید `font` نادیده از واکشیِ پیش‌فرض می‌شود و خانواده از همین‌جا می‌آید.

نصب

۱. این آدرس رو یک‌بار توی components.json بذار تا shadcn مخزن فارسی‌فای رو بشناسه.

components.jsonjson
{
  "registries": {
    "@farsify": "https://farsify.ir/r/{name}.json"
  }
}

۲. بعد با دستورِ زیر کامپوننت رو نصب کن.

npx shadcn@latest add @farsify/circular-gallery

پیش‌نیاز: Tailwind CSS v4 و صفحهٔ راست‌به‌چپ dir="rtl".

نمونه

circular-gallery.tsxtsx
"use client";

import CircularGallery from "@/components/farsify/circular-gallery";

const shots = [
  { image: "/images/mountain.jpg", text: "قله", description: "شبِ کوهستان زیرِ ستاره‌ها" },
  { image: "/images/forest.jpg", text: "جنگل", description: "نورِ صبح میانِ تنه‌ها" },
  { image: "/images/falls.jpg", text: "آبشار", description: "رودخانه‌ای از دلِ دره" },
];

export function CurvedWall() {
  return (
    <div style={{ height: 480 }}>
      <CircularGallery items={shots} />
    </div>
  );
}

// قوسِ تندِ درشت‌گوشه با موجِ قوی و سایه‌ی عمیق
<CircularGallery items={shots} bend={4.5} itemSize={1.25} wave={2} shadow={0.45} />

// ردیفِ تقریباً تخت و پرفاصله با چرخشِ کشسان
<CircularGallery items={shots} bend={1.5} gap={0.5} scrollEase={0.02} wave={0} />

// کارت‌های غیرفعال سیاه‌وسفید؛ رنگ فقط با هاور و فعال‌شدن
<CircularGallery items={shots} grayscale />

// راندشِ آرامِ خودکار پس از سکون — با هاور می‌ایستد
<CircularGallery items={shots} autoScroll={0.7} />

// قلمِ فارسیِ خودتان برای برچسب‌ها (به‌جای واکشیِ گوگل‌فونت)
<CircularGallery items={shots} font='700 30px "Peyda"' />

نکته‌ها

  • بدونِ هیچ وابستگی: موتور، WebGL2ِ خامه — اطلسِ بافتِ همه‌ی تصویرها یه‌بار ساخته می‌شه و هر کارت با یه فراخوانِ رسم کشیده می‌شه.
  • اگه WebGL2 در دسترس نباشه صحنه ساکت می‌مونه — مرجع هم همین رفتار رو داره؛ برچسب‌های دسترس‌پذیری برای کیبورد همیشه هست.
  • برای گالریِ «ردیفِ ویترینی» `itemAspect` رو زیرِ ۱ بذار و `gap` رو بالا؛ برای جدولِ عریض، `itemAspect` بالای ۱ با `bend` کم.
  • توی `prefers-reduced-motion` اینترو فوری می‌شه، موج و راندش خاموشه و چسبیدن بی‌درنگ می‌افته؛ کشیدنِ دستی سرِ جاشه.
  • فونتِ پیش‌فرضِ مرجع (Figtree) از گوگل‌فونت می‌آد؛ برای فارسی، `font` رو به قلمِ خودت بده تا هیچ درخواستِ بیرونی زده نشه.

مجوز

کد بعد از نصب مالِ خودته؛ هر تغییری خواستی بده و توی پروژه‌ی خودت نگهش دار. برای پروژه‌های شخصی و تجاری آزاده، حتی اگه کدت بسته باشه. فقط اسم و لینک فارسی‌فای رو یه جا توی پروژه نگه دار.