ページ補助PageAsideExperimental

ページ内リンク、ページステータス、関連リンクなどの補助情報を、広い画面では右レール、狭い画面では本文内の折りたたみ領域へ配置します。

プレビュー

状態とバリエーション

ページステータス

公開状態、最終更新、レビュー状況など、ページを読みながら確認したい情報をまとめます。

本文の流れから外したい関連資料やページ内リンクを補助領域にまとめます。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
titleReactNode-モバイルのアコーディオン見出しと補助領域のラベル。
renderAside() => ReactNode-右レールと折りたたみ領域に表示する補助情報を返します。関数propのため Client Component からのみ渡すこと(Server Component から渡すと next build が落ちる)。JSX を返すため serializable な代替は無く、RSC からは "use client" ラッパーで包む。(#338)
childrenReactNode-主コンテンツ領域に表示する本文。
widthstring"w-72"デスクトップ時の RightRail 幅を指定する Tailwind クラス。
defaultOpenbooleantrue狭い画面で補助情報を初期表示するか。
mobileDescriptionReactNode-狭い画面の折りたたみ領域に表示する補足説明。
contentClassNamestring-本文領域に追加するクラス。
railClassNamestring-デスクトップの RightRail に追加するクラス。

使い方

import { Badge, PageAside } from "@gunjo/ui"

const pageLinks = [
  { id: "overview", label: "概要" },
  { id: "quality", label: "品質指標" },
  { id: "release", label: "公開前確認" },
]

const pageStatuses = [
  { label: "状態", value: "公開前確認", tone: "default" },
  { label: "最終更新", value: "5分前", tone: "secondary" },
  { label: "レビュー", value: "2件対応待ち", tone: "secondary" },
]

function PageLinks() {
  return (
    <section className="space-y-2">
      <h3 className="text-sm font-semibold">ページ内</h3>
      <nav aria-label="ページ内リンク">
        <ul className="space-y-1">
          {pageLinks.map((item) => (
            <li key={item.id}>
              <a className="block rounded-sm px-2 py-1.5 text-sm text-muted-foreground hover:bg-muted hover:text-foreground" href={`#${item.id}`}>
                {item.label}
              </a>
            </li>
          ))}
        </ul>
      </nav>
    </section>
  )
}

function PageStatus() {
  return (
    <section className="space-y-2">
      <h3 className="text-sm font-semibold">ページステータス</h3>
      <dl className="space-y-2">
        {pageStatuses.map((item) => (
          <div key={item.label} className="flex items-center justify-between gap-3 rounded-md border bg-muted/20 px-3 py-2">
            <dt className="text-xs text-muted-foreground">{item.label}</dt>
            <dd className="shrink-0 text-xs font-medium">
              {item.tone === "default" ? <Badge>{item.value}</Badge> : item.value}
            </dd>
          </div>
        ))}
      </dl>
    </section>
  )
}

function AsideContent() {
  return (
    <div className="space-y-5">
      <PageLinks />
      <PageStatus />
    </div>
  )
}

export function DocsPageWithAside() {
  return (
    <PageAside
      title="補助情報"
      asideLabel="ページの補助情報"
      contentLabel="主コンテンツ"
      mobileDescription="狭い画面では、右レールの内容を本文内で開閉します。"
      openLabel="補助情報を開く"
      closeLabel="補助情報を閉じる"
      contentClassName="space-y-4 bg-muted/30 p-4"
      renderAside={() => <AsideContent />}
    >
      <h3 className="text-base font-semibold">分析レポート</h3>
      <p className="max-w-xl text-sm text-muted-foreground">
        広い画面では補助情報を右側へ、狭い画面では本文内の折りたたみ領域へ配置します。
      </p>
      <section id="overview" className="rounded-md border bg-background p-3">
        <h4 className="text-sm font-semibold">概要</h4>
      </section>
    </PageAside>
  )
}

使用コンポーネント