پرتوپرتو

نوار ناوبری (NavRail)

نوار آیکونی باریک که با اشاره‌گر باز می‌شود و برچسب‌ها را نشان می‌دهد — دقیقاً مثل سایدبار استودیوی Supabase

معرفی

NavRail نوار ناوبری اصلی برنامه است: در حالت جمع فقط آیکون‌ها را در عرض ۴۸ پیکسل نشان می‌دهد و با اشاره‌گر (hover) به ۲۰۸ پیکسل باز می‌شود و برچسب‌ها را آشکار می‌کند — به‌صورت یک لایهٔ روی محتوا، بنابراین چیدمان صفحه هرگز جابه‌جا نمی‌شود. سه حالت رفتاری دارد که در localStorage ذخیره می‌شود.

چه زمانی استفاده کنیم:

  • برنامه‌ای چند‌صفحه‌ای با ناوبری سطح‌بالای همیشه‌حاضر (مثل استودیوی Supabase).
  • می‌خواهید نوار در حالت عادی جمع باشد و فضای کمی بگیرد، اما دسترسی سریع با اشاره‌گر داشته باشد.

چه زمانی استفاده نکنیم:

  • به یک پوستهٔ کامل و آماده نیاز دارید → از AppShell استفاده کنید که همین نوار را با هدر و بوم می‌بندد.
  • ناوبری ساده و تک‌سطحی بدون آیکون → از Sidebar یا NavTree استفاده کنید.
  • برای محتوای فرعی هر بخش (فیلترها، ساب‌ناوبری) → از AppSecondary + SecondaryNav در کنار نوار استفاده کنید.

محتوای صفحه

نوار در حالت پیش‌فرض جمع (۴۸px) است و با اشاره‌گر باز می‌شود؛ از کنترل پایین می‌توانید حالت را به «همیشه باز» یا «همیشه جمع» تغییر دهید.

زمین بازی

با تغییر تنظیمات زیر، پیش‌نمایش زنده را مشاهده کنید.

زمین بازی
تنظیمات
حالت
داده
4
کد این نمونه به‌صورت خودکار قابل تولید نیست — برای کد آماده‌ی copy/paste به بخش «استفاده» در بالای صفحه مراجعه کنید.

استفاده

import {
  NavRailProvider,
  NavRail,
  NavRailHeader,
  NavRailContent,
  NavRailItem,
  NavRailFooter,
  NavRailBehaviorToggle,
  AppLayout,
  AppLayoutContent,
} from '@partodata/ui'
import { LayoutDashboard, Search, Settings } from 'lucide-react'

export default function MyApp() {
  const [active, setActive] = React.useState('dashboard')

  return (
    <NavRailProvider side="start" defaultBehavior="expandable">
      <AppLayout>
        <NavRail>
          <NavRailHeader>
            <Logo />
          </NavRailHeader>
          <NavRailContent>
            <NavRailItem
              itemId="dashboard"
              icon={<LayoutDashboard />}
              label="داشبورد"
              isActive={active === 'dashboard'}
              onClick={() => setActive('dashboard')}
            />
            <NavRailItem
              itemId="search"
              icon={<Search />}
              label="جستجو"
              isActive={active === 'search'}
              onClick={() => setActive('search')}
            />
          </NavRailContent>
          <NavRailFooter>
            <NavRailItem itemId="settings" icon={<Settings />} label="تنظیمات" />
            <NavRailBehaviorToggle />
          </NavRailFooter>
        </NavRail>

        <AppLayoutContent>{/* محتوای صفحه */}</AppLayoutContent>
      </AppLayout>
    </NavRailProvider>
  )
}

حالت‌ها و انواع

حالت‌های رفتاری

نوار سه حالت دارد که کاربر از طریق کنترل پایین (NavRailBehaviorToggle، آیکون PanelLeftDashed) عوض می‌کند و انتخابش در localStorage با کلید parto-sidebar-behavior ذخیره می‌شود:

حالترفتار
expandableپیش‌فرض — جمع (۴۸px)، با اشاره‌گر به ۲۰۸px باز می‌شود (لایهٔ روی محتوا، بدون جابه‌جایی)
openهمیشه باز — چیدمان کل ۲۰۸px را رزرو می‌کند (بدون overlay)
closedهمیشه جمع — اشاره‌گر کاری نمی‌کند
<NavRailProvider defaultBehavior="open">{/* ... */}</NavRailProvider>

برای کنترل کامل از بیرون، behavior و onBehaviorChange را بدهید:

const [behavior, setBehavior] = React.useState<NavRailBehavior>('expandable')

<NavRailProvider behavior={behavior} onBehaviorChange={setBehavior}>
  {/* ... */}
</NavRailProvider>

پنل جانبی (Part 2)

برای محتوای فرعیِ ماندگار (فیلترها، ساب‌ناوبری، فهرست گزارش‌ها) از AppSecondary در کنار نوار استفاده کنید و داخلش از خانوادهٔ SecondaryNav بهره بگیرید:

<NavRailProvider>
  <AppLayout>
    <NavRail>{/* ... */}</NavRail>
    <AppSecondary resizable>
      <AppSecondaryHeader>
        <AppSecondaryTitle>گزارش‌ها</AppSecondaryTitle>
      </AppSecondaryHeader>
      <AppSecondaryContent className="p-2">
        <SecondaryNavSearchInput placeholder="جستجو…" aria-label="جستجو" />
        <SecondaryNavTitle>پیشنهادی</SecondaryNavTitle>
        <SecondaryNavItem isActive>نمای کلی هفتگی</SecondaryNavItem>
        <SecondaryNavItem>روند تعامل</SecondaryNavItem>
      </AppSecondaryContent>
    </AppSecondary>
    <AppLayoutContent>{/* محتوا */}</AppLayoutContent>
  </AppLayout>
</NavRailProvider>

رفتار موبایل

در موبایل، نوار به یک Sheet تبدیل می‌شود که با NavRailTrigger باز می‌شود و آیتم‌ها را با برچسب کامل نشان می‌دهد. اگر AppSecondary هم داشته باشید، محتوای آن به‌صورت خودکار داخل همان Sheet، زیر آیتم‌های ناوبری قرار می‌گیرد تا محتوای بخش فعال در موبایل هم در دسترس بماند:

<SiteHeaderStart>
  <NavRailTrigger />
  {/* عنوان */}
</SiteHeaderStart>

راهنمای استفاده

بکنید

  • برای هر مقصد اصلی یک NavRailItem با آیکون و label مشخص بگذارید — برچسب هم tooltip حالت جمع است و هم متن حالت باز. - کنترل حالت (NavRailBehaviorToggle) را در پاورقی نوار قرار دهید تا کاربر بتواند نوار را «همیشه باز» یا «همیشه جمع» کند. - از NavRailSeparator برای گروه‌بندی بصری آیکون‌ها استفاده کنید.

نکنید

  • بیش از ۸ آیکون در نوار نگذارید — اولویت‌بندی کنید. - label را برای هیچ آیتمی خالی نگذارید؛ هم برای tooltip و هم برای دسترس‌پذیری الزامی است. - محتوای فرعی هر بخش را داخل خود نوار نگذارید؛ برای آن AppSecondary هست.

جدول ویژگی‌ها

Prop

Type

Prop

Type

Prop

Type

کنترل پاورقی برای تغییر حالت رفتاری نوار. بدون prop؛ حالت را از NavRailProvider می‌خواند.

AppSecondary

Prop

Type

دسترسی‌پذیری

ویژگی‌های ARIA

  • نوار: role="navigation" با aria-label="ناوبری اصلی".
  • آیتم فعال: aria-current="page".
  • هر آیتم: aria-label از prop label (چه جمع، چه باز).
  • دستهٔ تغییر عرض پنل جانبی: role="separator" با aria-label.

تعاملات کیبورد

کلیدعملکرد
Tabحرکت بین آیتم‌ها (و دستهٔ تغییر عرض پنل جانبی)
Enter / Spaceفعال‌کردن آیتم
/ روی دستهٔ تغییر عرض: تغییر عرض پنل جانبی (گام ۱۶px، بین ۲۵۶ تا ۵۱۲)

نوار عمداً میان‌بر کیبوردیِ باز/بسته ندارد (مطابق استودیوی Supabase)؛ حالت از طریق کنترل پاورقی تغییر می‌کند.

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

  • برای پوستهٔ کامل و آماده با هدر و بوم ← AppShell — همین نوار را می‌بندد.
  • برای محتوای پنل جانبی (Part 2) ← SecondaryNav.
  • برای ناوبری درختی ساده ← NavTree یا Sidebar.
  • برای هدر بالای صفحه ← SiteHeader.