ناوبریِ ژله‌ایGooey Nav

نوارِ ناوبریِ قرصی که قرصِ فعالش با انتخابِ هر آیتم به قطره‌های ژله‌ای می‌شکنه، روی آیتمِ تازه پرواز می‌کنه و دوباره یک‌پارچه می‌شه.

محمدجواد

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

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

وابستگی‌ها

بدون وابستگی

نوع تعامل

روی هر آیتم بزن تا قرصِ فعال به قطره‌های ریز بشکنه، از روی نوار رد شه و روی آیتمِ تازه دوباره جمع شه. با عبورِ نشانگر، پشتِ آیتمِ زیرِ انگشت یه هاله‌ی نرم روشن می‌شه. نوار با صفحه‌کلید هم کار می‌کنه: هر آیتم یه پیوند یا دکمه‌ی واقعیه و حلقه‌ی فوکوس داره. اگه `href` ندی، آیتم دکمه می‌شه و فقط `onChange` رو صدا می‌زنه.

پراپ‌ها

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

items
GooeyNavItem[]پیش‌فرض: ["خانه", "محصولات", "درباره", "تماس"]

آیتم‌ها. هر آیتم `label` و اختیاری `href` و `icon` دارد؛ بدونِ `href` به‌صورت دکمه رندر می‌شود.

initialActiveIndex
numberپیش‌فرض: 0

کدام آیتم از اول انتخاب‌شده باشد.

activeIndex
number

حالتِ کنترل‌شده؛ با `onChange` بدهید تا خودتان مالکِ انتخاب باشید.

onChange
(index: number, item: GooeyNavItem) => void

با هر انتخاب، ایندکس و خودِ آیتم را برمی‌گردونه.

theme
"dark" | "light"پیش‌فرض: "dark"dark · light

تمِ قاب و متن؛ رنگِ قرص از روشناییِ خودش حساب می‌شه.

color
stringپیش‌فرض: تم‌آگاه (#f4f4f5 / #27272a)

رنگِ قرصِ فعال. هگز یا `rgb()` بدهید؛ رنگِ متنِ داخلش خودکار انتخاب می‌شود.

نصب

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

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

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

npx shadcn@latest add @farsify/gooey-nav

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

نمونه

gooey-nav.tsxtsx
"use client";

import { useState } from "react";
import { GooeyNav } from "@/components/farsify/gooey-nav";

const items = [
  { label: "خانه", href: "/" },
  { label: "محصولات", href: "/products" },
  { label: "درباره", href: "/about" },
  { label: "تماس", href: "/contact" },
];

export function MainMenu() {
  const [active, setActive] = useState(0);

  return (
    <GooeyNav
      items={items}
      activeIndex={active}
      onChange={(index) => setActive(index)}
      ariaLabel="منوی اصلی"
    />
  );
}

// تمِ روشن، رنگِ برند و قرصِ بزرگ‌تر
<GooeyNav
  items={items}
  theme="light"
  color="#007bff"
  size="lg"
/>

// بدونِ ناوبری: آیتم‌ها دکمه می‌شوند و فقط onChange می‌آید
<GooeyNav
  items={[{ label: "روزانه" }, { label: "هفتگی" }, { label: "ماهانه" }]}
  onChange={(index) => console.log(index)}
/>

نکته‌ها

  • برچسب‌ها رو فارسی بده و کوتاه نگه دار؛ نوار با `flex-wrap` می‌شکنه ولی یک‌خطی‌بودن همیشه خواناتره.
  • اگه آیتم‌ها مقصدِ واقعی دارن `href` بده؛ بدونِ اون‌ها دکمه می‌شن و ناوبری رو خودت توی `onChange` انجام می‌دی.
  • برای رنگِ قطره‌ها `colors` بده تا موقعِ شکستن، چند فامِ نزدیک به هم ببینی؛ خالی بذار تا همون رنگِ قرص بمونه.
  • قرصِ فعال با روشناییِ `color` انتخاب می‌کنه متنش سفید باشه یا تیره؛ اگه رنگِ خیلی روشن یا خیلی تیره دادی و نتیجه رو نپسندیدی، `activeTextColor` رو صریح بده.
  • توی دستگاه‌های لمسی `hoverEffect` اثری نداره؛ هاله فقط با نشانگرِ واقعی ظاهر می‌شه.
  • حرکتِ قطره‌ها توی `prefers-reduced-motion` خاموش می‌شه و انتخاب مستقیم می‌نشینه — مقدار و دسترس‌پذیری دست‌نخورده می‌مونن.

مجوز

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