ヘッダーHeaderExperimental

ロゴ、主要ナビゲーション、右側の操作をページ上部にまとめて表示します。

プレビュー

状態とバリエーション

コンパクト

狭いヘッダーやアプリ内画面では、主要リンクを別ナビゲーションに逃がしてブランドと操作だけにできます。

ドロワーにナビゲーションを格納

タブレットやスマホでは主要リンクをヘッダー上に並べず、右側から開くドロワーにまとめて表示できます。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
Headerheader-ブランド、主要ナビゲーション、操作を横並びにするルート。
HeaderBranddiv-ロゴやサービス名を入れる左側スロット。
HeaderNavLink.activeboolean-現在ページのリンクを強調します。
HeaderActionsdiv-検索、ログイン、テーマ切替などの操作スロット。

使い方

import * as React from "react"
import { IconLanguage as Languages, IconMoon as Moon, IconSearch as Search, IconSun as Sun } from "@tabler/icons-react"
import { useTheme } from "next-themes"
import { Button, CommandPalette, Header, HeaderActions, HeaderBrand, HeaderNav, HeaderNavLink, TooltipButton } from "@gunjo/ui"

type Locale = "ja" | "en"

function getNavLinks(isJa: boolean) {
  return [
    { label: isJa ? "ドキュメント" : "Docs", href: "/docs" },
    { label: isJa ? "コンポーネント" : "Components", href: "/docs/components" },
    { label: isJa ? "料金" : "Pricing", href: "/pricing" },
  ]
}

function BrandLogo() {
  return (
    <span
      aria-label="Gunjo UI"
      role="img"
      className="block h-8 w-[3.75rem] bg-primary [mask:url('/gunjo-logo.svg')_center/contain_no-repeat] [-webkit-mask:url('/gunjo-logo.svg')_center/contain_no-repeat]"
    />
  )
}

export function SiteHeader() {
  const [locale, setLocale] = React.useState<Locale>("ja")
  const [commandOpen, setCommandOpen] = React.useState(false)
  const [mounted, setMounted] = React.useState(false)
  const { resolvedTheme, setTheme } = useTheme()
  const isJa = locale === "ja"
  const isDark = mounted && resolvedTheme === "dark"
  const navLinks = getNavLinks(isJa)
  const commandGroups = [
    {
      heading: isJa ? "ページ" : "Pages",
      items: navLinks.map((link) => ({
        id: link.href,
        label: link.label,
        action: () => setCommandOpen(false),
      })),
    },
  ]

  React.useEffect(() => {
    setMounted(true)
  }, [])

  return (
    <>
      <Header>
        <HeaderBrand>
          <BrandLogo />
        </HeaderBrand>
        <HeaderNav>
          {navLinks.map((link, index) => (
            <HeaderNavLink key={link.href} href={link.href} active={index === 0}>
              {link.label}
            </HeaderNavLink>
          ))}
        </HeaderNav>
        <HeaderActions>
          <TooltipButton
            type="button"
            size="icon"
            variant="ghost"
            tooltip={isJa ? "コマンドパレットを開く" : "Open command palette"}
            aria-label={isJa ? "コマンドパレットを開く" : "Open command palette"}
            onClick={() => setCommandOpen(true)}
          >
            <Search className="h-4 w-4" aria-hidden />
          </TooltipButton>
          <TooltipButton
            type="button"
            size="icon"
            variant="ghost"
            tooltip={isJa ? "英語に切り替え" : "日本語に切り替え"}
            aria-label={isJa ? "英語に切り替え" : "日本語に切り替え"}
            onClick={() => setLocale(isJa ? "en" : "ja")}
          >
            <Languages className="h-4 w-4" aria-hidden />
          </TooltipButton>
          <TooltipButton
            type="button"
            size="icon"
            variant="ghost"
            tooltip={isDark ? "ライトテーマに切り替え" : "ダークテーマに切り替え"}
            aria-label={isDark ? "ライトテーマに切り替え" : "ダークテーマに切り替え"}
            onClick={() => setTheme(isDark ? "light" : "dark")}
          >
            {isDark ? <Sun className="h-4 w-4" aria-hidden /> : <Moon className="h-4 w-4" aria-hidden />}
          </TooltipButton>
          <Button size="sm">{isJa ? "ログイン" : "Sign in"}</Button>
        </HeaderActions>
      </Header>
      <CommandPalette
        open={commandOpen}
        onOpenChange={setCommandOpen}
        groups={commandGroups}
        placeholder={isJa ? "ドキュメントを検索" : "Search documentation"}
        emptyMessage={isJa ? "一致する結果がありません。" : "No matching results."}
        dialogTitle={isJa ? "コマンドパレット" : "Command palette"}
        clearLabel={isJa ? "検索をクリア" : "Clear search"}
      />
    </>
  )
}

使用コンポーネント