منوی خط‌چینHook Sidebar

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

محمدجواد

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

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

وابستگی‌ها

motion

نوع تعامل

روی هر ردیف بزن تا انتخاب شه؛ خطِ رنگی از بالای فهرست تا مرکزِ همون ردیف می‌آد و با یه گوشه‌ی ۶پیکسلی بهش وصل می‌شه. با عبورِ نشانگر (یا فوکوس با Tab) یه خطِ خط‌چینِ کم‌رنگ از ردیفِ فعال تا ردیفِ زیرِ نشانگر کشیده می‌شه تا معلوم باشه با زدن کجا می‌ری. خط با فنر جابه‌جا می‌شه، نه با پرش. اگه `href` بدی ردیف پیوند می‌شه، وگرنه دکمه؛ در هر دو حالت `onChange` صدا زده می‌شه.

پراپ‌ها

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

items*
HookSidebarItem[]پیش‌فرض: ["حساب کاربری", "اعلان‌ها", "امنیت"]

ردیف‌ها. هر آیتم یا رشته است یا `{ label, href }`؛ هر آیتم `href` دار به‌صورت پیوند رندر می‌شه، بقیه دکمه.

label
string

عنوانِ بالای ستون. همون‌جا `aria-label`ِ ناوبری هم می‌شه، مگر خودت `aria-label` بدهی.

value
number

ایندکسِ انتخاب‌شده در حالتِ کنترل‌شده. برای هم‌گام‌کردن با مسیر (مثلاً با `usePathname`) همینه.

defaultValue
numberپیش‌فرض: 0

ایندکسِ اولیه در حالتِ نام‌کنترل‌شده.

onChange
(index: number) => void

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

color
stringپیش‌فرض: var(--brand, currentColor)

رنگِ خطِ فعال. هر مقدارِ CSS قبوله؛ اگه پروژه‌ات `--brand` نداره، رنگِ متن می‌شه.

نصب

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

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

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

npx shadcn@latest add @farsify/hook-sidebar

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

نمونه

hook-sidebar.tsxtsx
"use client";

import { useState } from "react";
import { HookSidebar } from "@/components/farsify/hook-sidebar";

const items = [
  { label: "حساب کاربری", href: "/settings/account" },
  { label: "اعلان‌ها", href: "/settings/notifications" },
  { label: "امنیت", href: "/settings/security" },
  { label: "صورت‌حساب", href: "/settings/billing" },
];

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

  return (
    <HookSidebar
      label="تنظیمات"
      className="w-52"
      items={items}
      value={active}
      onChange={setActive}
    />
  );
}

// خطِ یک‌دست با رنگِ دلخواه، بدونِ عنوان
<HookSidebar
  className="w-44"
  items={["خانه", "محصولات", "درباره"]}
  dashed={false}
  color="#007bff"
/>

// هم‌گام با مسیر — خودِ کامپوننت به Next وابسته نیست، پس مسیر را شما می‌دهید
const pathname = usePathname();
const index = items.findIndex((item) => item.href === pathname);

<HookSidebar items={items} value={index} />

نکته‌ها

  • عرضِ ستون رو خودِ کامپوننت نمی‌سازه؛ `className="w-52"` یا هر عرضِ دیگه‌ای بده تا ردیف‌ها هم‌عرضِ هم بشن.
  • `next/link` عمداً import نشده — نسخه‌ی تحویلی باید در پروژه‌ی بدونِ Next هم کامپایل شه. اگه ناوبریِ نرم می‌خوای، `value` رو از مسیر بده.
  • موقعیتِ خط با اندازه‌گیریِ DOM حساب می‌شه، پس متنِ بلند یا اندازه‌ی فونتِ متفاوت چیز رو نمی‌شکنه؛ `ResizeObserver` هم‌زمانِ ردیف‌ها و کلِ فهرست رو نگاه می‌کنه.
  • ستون در راست‌به‌چپ از سمتِ راست می‌آد و قلاب به چپ برمی‌گرده؛ چیزی رو دستی آینه نکن.
  • برای فهرست‌های بلند ارتفاعِ ثابت با `overflow-y-auto` بهتره تا ستونِ بی‌پایان؛ خط داخلِ همون قاب اندازه‌گیری می‌شه.

مجوز

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