Header
Headerは、Webサイトやアプリケーションのページ上部に表示されるコンポーネントです。
ナビゲーションやメニューなどの主要な要素を表示します。
header/default is coming soon.
<script lang="ts">
import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
import type { GlobalNavigationItem } from '$lib/components/ui/modules/GlobalNavigation.svelte';
import Header from '$lib/components/ui/modules/Header.svelte';
// PC時のメニューの値
let desktopMenus: GlobalNavigationItem[] = [
{
id: 'menu1',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu2',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu3',
label: 'メニュー',
link: { href: '#', blank: false },
},
];
// SP時のメニューの値
const mobileMenus: MenuItem[] = [
{
id: 'menu1',
label: 'メニュー',
options: [
{ id: 'menu1-1', label: 'メニュー' },
{ id: 'menu1-2', label: 'メニュー' },
{ id: 'menu1-3', label: 'メニュー' },
],
},
{
id: 'menu2',
label: 'メニュー',
options: [
{ id: 'menu2-1', label: 'メニュー' },
{ id: 'menu2-2', label: 'メニュー' },
{ id: 'menu2-3', label: 'メニュー' },
],
},
{
id: 'menu3',
label: 'メニュー',
},
];
// 現在表示中のページの位置を示すメニュー用のハイライト
const currentIndex = 2;
// プロフィール画像のURL
const profileImgUrl = '/images/sample.png';
// プレースホルダー
const placeholder = '検索';
</script>
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder}>
<!-- PC時のサブメニューの値 -->
{#snippet desktopMenusChildren(item)}
{#if item.id === 'menu1'}
PCサブメニュー1の要素が入ります。
{/if}
{#if item.id === 'menu2'}
PCサブメニュー2の要素が入ります。
{/if}
{/snippet}
</Header>
プロパティ
Headerは、以下のプロパティをサポートしています。
| 名前 | 型 | デフォルト値 | 説明 |
|---|---|---|---|
desktopMenus |
GlobalNavigationItem[] |
[] | PC用のメニューとして表示する値の配列です。 |
mobileMenus |
MenuItem[] |
[] | SP用のメニューとして表示する値の配列です。 |
currentIndex |
number |
現在選択されているメニューを示すハイライト用の数値です。 | |
profileImgUrl |
string |
'' | プロフィール画像のURLです。 |
placeholder |
string |
'' | 検索窓のプレースホルダーです。 |
インストールの手順
以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。
modules/Header.svelte
<!--
@component
## 概要
- Header は、検索・ナビゲーション・プロフィール画像をひとまとめにしたレスポンシブヘッダーです。
PCではグローバルナビゲーション、SPではハンバーガー+ドロワーでメニューを表示し、渡した配列から項目を生成します。生成された項目(メニュー)ごとに追加でサブメニューを表示することができます。PCではスニペットを渡し、SPではmobileMenusのoptionsに値を書くことで、任意のサブメニューを表示可能です。
## 機能
- 渡した配列をそのままメニューとしてレンダリング
- 検索窓を表示
- プロフィール画像を表示。
## Props
- desktopMenus: PC時のメニュー。グローバルナビゲーションコンポーネントに渡す配列。省略可能で、省略した場合は項目が表示されない。
- mobileMenus: SP時(Drawer内)のメニュー。メニューコンポーネントに渡す配列。省略可能で、省略した場合は項目が表示されない。
- currentIndex: 現在表示中のページの位置を示すハイライト。省略可能で、省略した場合はハイライトが表示されない。
- profileImgUrl: 右上に表示するプロフィール画像URL。省略可能で、省略した場合はデフォルトの灰色アイコンになる。
- placeholder: 検索窓のプレースホルダー。省略可能で、省略した場合はプレースホルダーが表示されない。
- class: ヘッダー全体に付与する追加クラス。省略可能。
- desktopMenusChildren: PC時のサブメニュー用のスニペット。省略可能で、省略した場合はサブメニューが表示されない。
## Usage
```svelte
サブメニューがない場合
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder} />
サブメニューがある場合
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder}>
{#snippet desktopMenusChildren(item)}
{#if item.id === 'menu1'}
PCサブメニュー1の要素が入ります。
{/if}
{#if item.id === 'menu2'}
PCサブメニュー2の要素が入ります。
{/if}
{/snippet}
</Header>
```
-->
<script module lang="ts">
import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
import type { GlobalNavigationItem } from '$lib/components/ui/modules/GlobalNavigation.svelte';
import type { Snippet } from 'svelte';
import type { ClassValue } from 'svelte/elements';
export interface HeaderProps {
/** メニューとして表示する値の配列(PC用)。グローバルナビゲーションコンポーネント用 */
desktopMenus?: GlobalNavigationItem[];
/** メニューとして表示する値の配列(SP用)。メニューコンポーネント用 */
mobileMenus?: MenuItem[];
/** 現在選択されているメニューを示すハイライト用の数値 */
currentIndex?: number;
/** プロフィール画像のURL */
profileImgUrl?: string;
/** 検索窓のプレースホルダー */
placeholder?: string;
/** 追加クラス */
class?: ClassValue;
/** PC用のサブメニュー */
desktopMenusChildren?: Snippet<[GlobalNavigationItem, number]>;
}
</script>
<script lang="ts">
import Button from '$lib/components/ui/atoms/Button.svelte';
import Input from '$lib/components/ui/atoms/Input.svelte';
import Menu from '$lib/components/ui/atoms/Menu.svelte';
import Drawer from '$lib/components/ui/modules/Drawer.svelte';
import GlobalNavigation from '$lib/components/ui/modules/GlobalNavigation.svelte';
import { Menu as Hamburger, Search, UserRound, X } from '@lucide/svelte';
let { desktopMenus = [], mobileMenus = [], currentIndex, profileImgUrl = '', placeholder = '', class: className, desktopMenusChildren }: HeaderProps = $props();
/** レスポンシブ切り替えの境界値(この値を下回るとモバイル表示、以上でデスクトップ表示) */
const RESPONSIVE_BREAKPOINT_PX = 768;
let searchText = $state('');
let isOpen = $state(false);
let viewportWidth = $state<number>(0);
$effect(() => {
// SPからPCの幅に切り替わった場合、ドロワーを閉じる。
if (viewportWidth >= RESPONSIVE_BREAKPOINT_PX) {
isOpen = false;
}
});
/**
* ドロワーの開閉状態をトグルする。
* @param e クリックイベント(バブリングを止める)
*/
function openDrawer(e: MouseEvent): void {
e.stopPropagation();
isOpen = !isOpen;
}
</script>
<header class={[className, 'relative flex items-center justify-between w-full h-15 px-6 z-50 after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-base-stroke-default after:content-[\'\'] after:-z-10 max-md:py-3 max-md:px-4 max-md:h-16']} bind:clientWidth={viewportWidth}>
<!-- メニュー(PC用) -->
<div class="hidden md:block">
<GlobalNavigation menus={desktopMenus} {currentIndex}>
{#snippet children(item, index)}
{@render desktopMenusChildren?.(item, index)}
{/snippet}
</GlobalNavigation>
</div>
{#if mobileMenus?.length}
<!-- ハンバーガーアイコン(SP) -->
<div class="mr-4 md:hidden">
<Button class="border border-base-stroke-default" type="button" variant="secondary" size="small" tone="solid" isSquare onclick={openDrawer}>
<Hamburger size="1.125rem" />
</Button>
</div>
<!-- ハンバーガーアイコンのクリック時に開くドロワー(SP) -->
<Drawer class="md:hidden" direction="left" bind:open={isOpen}>
{#snippet children()}
<div class="relative flex flex-col justify-between h-full px-4 pt-14">
<Button class="absolute top-2 right-2" variant="secondary" size="small" tone="ghost" isSquare onclick={() => (isOpen = false)}><X size="1rem" /></Button>
<!-- メニュー(SP用) -->
<div class="h-full overflow-y-auto">
{#each mobileMenus as menu, index}
<Menu class="w-auto" item={menu} current={currentIndex === index ? menu.id : ''} />
{/each}
</div>
</div>
{/snippet}
</Drawer>
{/if}
<div class="flex items-center shrink-0 gap-4 max-md:shrink max-md:w-full">
<!-- 検索窓 -->
<div class="w-75 max-md:w-full">
<Input type="text" {placeholder} bind:value={searchText}>
{#snippet startContent()}
<Search class="text-base-foreground-muted pointer-events-none" size="1rem" />
{/snippet}
</Input>
</div>
<!-- ユーザー画像 -->
<div class="shrink-0 size-10">
{#if profileImgUrl}
<img class="size-full rounded-full object-cover" src={profileImgUrl} alt="プロフィール画像" />
{:else}
<div class="flex items-center justify-center size-10 border border-base-stroke-default rounded-full">
<UserRound class="size-3 object-contain text-base-foreground-subtle" />
</div>
{/if}
</div>
</div>
</header>
依存コンポーネント
Headerを使うときは、以下のコンポーネントもダウンロードが必要です。
使い方
header/default is coming soon.
<script lang="ts">
import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
import type { GlobalNavigationItem } from '$lib/components/ui/modules/GlobalNavigation.svelte';
import Header from '$lib/components/ui/modules/Header.svelte';
// PC時のメニューの値
let desktopMenus: GlobalNavigationItem[] = [
{
id: 'menu1',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu2',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu3',
label: 'メニュー',
link: { href: '#', blank: false },
},
];
// SP時のメニューの値
const mobileMenus: MenuItem[] = [
{
id: 'menu1',
label: 'メニュー',
options: [
{ id: 'menu1-1', label: 'メニュー' },
{ id: 'menu1-2', label: 'メニュー' },
{ id: 'menu1-3', label: 'メニュー' },
],
},
{
id: 'menu2',
label: 'メニュー',
options: [
{ id: 'menu2-1', label: 'メニュー' },
{ id: 'menu2-2', label: 'メニュー' },
{ id: 'menu2-3', label: 'メニュー' },
],
},
{
id: 'menu3',
label: 'メニュー',
},
];
// 現在表示中のページの位置を示すメニュー用のハイライト
const currentIndex = 2;
// プロフィール画像のURL
const profileImgUrl = '/images/sample.png';
// プレースホルダー
const placeholder = '検索';
</script>
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder}>
<!-- PC時のサブメニューの値 -->
{#snippet desktopMenusChildren(item)}
{#if item.id === 'menu1'}
PCサブメニュー1の要素が入ります。
{/if}
{#if item.id === 'menu2'}
PCサブメニュー2の要素が入ります。
{/if}
{/snippet}
</Header>
サンプル
Default
特に操作が行われていない、デフォルトの状態です。
header/default is coming soon.
<script lang="ts">
import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
import type { GlobalNavigationItem } from '$lib/components/ui/modules/GlobalNavigation.svelte';
import Header from '$lib/components/ui/modules/Header.svelte';
// PC時のメニューの値
let desktopMenus: GlobalNavigationItem[] = [
{
id: 'menu1',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu2',
label: 'メニュー',
hasSubMenu: true,
},
{
id: 'menu3',
label: 'メニュー',
link: { href: '#', blank: false },
},
];
// SP時のメニューの値
const mobileMenus: MenuItem[] = [
{
id: 'menu1',
label: 'メニュー',
options: [
{ id: 'menu1-1', label: 'メニュー' },
{ id: 'menu1-2', label: 'メニュー' },
{ id: 'menu1-3', label: 'メニュー' },
],
},
{
id: 'menu2',
label: 'メニュー',
options: [
{ id: 'menu2-1', label: 'メニュー' },
{ id: 'menu2-2', label: 'メニュー' },
{ id: 'menu2-3', label: 'メニュー' },
],
},
{
id: 'menu3',
label: 'メニュー',
},
];
// 現在表示中のページの位置を示すメニュー用のハイライト
const currentIndex = 2;
// プロフィール画像のURL
const profileImgUrl = '/images/sample.png';
// プレースホルダー
const placeholder = '検索';
</script>
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder}>
<!-- PC時のサブメニューの値 -->
{#snippet desktopMenusChildren(item)}
{#if item.id === 'menu1'}
PCサブメニュー1の要素が入ります。
{/if}
{#if item.id === 'menu2'}
PCサブメニュー2の要素が入ります。
{/if}
{/snippet}
</Header>