アプリレールAppRailExperimental

左側の細いプライマリナビゲーションです。

プレビュー

選択中

ホーム

最近の更新、タスク、概要を確認します。

状態とバリエーション

主要ナビゲーション

アプリ全体の移動先をアイコンボタンで縦に並べます。アイコンのみのため、ツールチップと aria-label を必ず合わせます。

選択中

ホーム

最近の更新、タスク、概要を確認します。

少数アクション

アクションが少ない場合も、設定などの補助操作は下端に寄せて役割を分けます。

選択中

ホーム

最近の更新、タスク、概要を確認します。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
classNamestring-レール本体に追加するクラス名。
childrenReact.ReactNode-レール内に配置するナビゲーションや操作。

使い方

import { AppRail, TooltipButton } from "@gunjo/ui"
import { IconBell as Bell, IconHome as Home, IconSearch as Search, IconSettings as Settings, IconUserCircle as UserRound } from "@tabler/icons-react"
import type { ReactNode } from "react"
import { useState } from "react"

function RailAction({
  label,
  children,
  active,
  onSelect,
}: {
  label: string
  children: ReactNode
  active?: boolean
  onSelect: () => void
}) {
  return (
    <TooltipButton
      type="button"
      variant="ghost"
      size="icon"
      tooltip={label}
      tooltipSide="right"
      tooltipOpenOnClick
      aria-label={label}
      aria-pressed={active}
      onClick={onSelect}
      className={[
        "h-10 w-10 text-muted hover:bg-background/10 hover:text-background",
        active ? "bg-background/20 text-background ring-1 ring-background/25" : "",
      ].join(" ")}
    >
      {children}
    </TooltipButton>
  )
}

export function AppRailExample() {
  const items = [
    {
      key: "home",
      label: "ホーム",
      icon: <Home className="h-5 w-5" />,
      title: "ホーム",
      description: "最近の更新、タスク、概要を確認します。",
    },
    {
      key: "search",
      label: "検索",
      icon: <Search className="h-5 w-5" />,
      title: "検索",
      description: "ワークスペース全体からドキュメントや操作を探します。",
    },
    {
      key: "notifications",
      label: "通知",
      icon: <Bell className="h-5 w-5" />,
      title: "通知",
      description: "未読通知と重要な更新を確認します。",
    },
    {
      key: "account",
      label: "アカウント",
      icon: <UserRound className="h-5 w-5" />,
      title: "アカウント",
      description: "プロフィール、チーム、請求情報を管理します。",
    },
  ]
  const settingsItem = {
    key: "settings",
    label: "設定",
    icon: <Settings className="h-5 w-5" />,
    title: "設定",
    description: "表示、通知、権限などの環境設定を変更します。",
  }
  const allItems = [...items, settingsItem]
  const [activeKey, setActiveKey] = useState(allItems[0].key)
  const activeItem = allItems.find((item) => item.key === activeKey) ?? allItems[0]

  return (
    <div className="flex h-[340px] w-full max-w-3xl overflow-hidden rounded-md border bg-background">
      <AppRail>
        {items.map((item) => (
          <RailAction
            key={item.key}
            label={item.label}
            active={activeItem.key === item.key}
            onSelect={() => setActiveKey(item.key)}
          >
            {item.icon}
          </RailAction>
        ))}
        <div className="mt-auto">
          <RailAction
            label={settingsItem.label}
            active={activeItem.key === settingsItem.key}
            onSelect={() => setActiveKey(settingsItem.key)}
          >
            {settingsItem.icon}
          </RailAction>
        </div>
      </AppRail>
      <main className="flex min-w-0 flex-1 items-center justify-center bg-secondary/50 p-6">
        <div className="max-w-sm space-y-2 text-center">
          <p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
            選択中
          </p>
          <h3 className="text-2xl font-semibold tracking-tight">{activeItem.title}</h3>
          <p className="text-sm leading-6 text-muted-foreground">
            {activeItem.description}
          </p>
        </div>
      </main>
    </div>
    )
}

設計の判断(UIXHERO)

「いつ・なぜ使うか」の判断は、姉妹サイト UIXHERO の記事で解説しています。