# 画面設計書 2-Header（ナビゲーションバー）

## 概要

本ドキュメントは、SFC Playground の上部ナビゲーションバー（Header.vue）の画面設計書である。ロゴ表示、Vueバージョン選択、TypeScriptバージョン選択、DEV/PROD切替、SSR切替、AutoSave切替、テーマ切替、Share、Download、Reload、GitHubリンクの各機能を提供するナビゲーションコンポーネントについて定義する。

### 本画面の処理概要

**業務上の目的・背景**：SFC Playground の各種設定・操作機能を統一的なUIで提供するナビゲーションバーである。開発者がコンパイルモード（DEV/PROD）、レンダリングモード（CSR/SSR）、エディタ設定（AutoSave）、表示テーマ（Light/Dark）を素早く切り替えられるようにし、またプロジェクトの共有・ダウンロード・リロードといったアクション操作を一箇所にまとめることで、効率的な開発体験を実現する。

**画面へのアクセス方法**：App.vue のテンプレート内で直接使用される子コンポーネントであり、SFC Playground のメイン画面にアクセスすると自動的に画面上部に表示される。個別のルーティングは存在しない。

**主要な操作・処理内容**：
1. Vue バージョンの選択・切替（VersionSelect コンポーネント経由）
2. TypeScript バージョンの選択・切替（VersionSelect コンポーネント経由）
3. DEV/PROD モードの切替トグルボタン
4. SSR ON/OFF の切替トグルボタン
5. AutoSave ON/OFF の切替トグルボタン
6. Light/Dark テーマの切替ボタン
7. Share ボタンによるURL共有（クリップボードコピー）
8. Reload ボタンによるプレビューリロード
9. Download ボタンによるプロジェクトZIPダウンロード
10. GitHub リポジトリへのリンク

**画面遷移**：本コンポーネントは画面遷移を伴わない。GitHub リンクは外部サイト（github.com）を新規タブで開く。Netlify の Commits History リンクも外部サイトを新規タブで開く。Share ボタンで meta キー押下時はローカルホスト（localhost:5173）にリダイレクトする。

**権限による表示制御**：権限による表示制御は存在しない。全機能が全ユーザーに開放されている。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | computed() | 補助機能 | store.vueVersion からバージョン表示文字列を算出 |
| 14 | defineProps() / defineEmits() | 主機能 | store/prod/ssr/autoSave/theme の Props 定義、toggle-theme 等5種のカスタムイベント定義 |

## 画面種別

ナビゲーションバー（コンポーネント）

## URL/ルーティング

本コンポーネントは個別のURL/ルーティングを持たない。App.vue 内に組み込まれ、SFC Playground のルート URL（`/`）で表示される。

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 | 初期値 |
|--------|----------|---------|------|--------|
| store | Props（入力） | ReplStore | Repl の状態管理ストア | 親コンポーネントから注入 |
| prod | Props（入力） | boolean | DEV/PROD モード状態 | 親コンポーネントから注入 |
| ssr | Props（入力） | boolean | SSR モード状態 | 親コンポーネントから注入 |
| autoSave | Props（入力） | boolean | AutoSave 状態 | 親コンポーネントから注入 |
| theme | Props（入力） | 'dark' \| 'light' | 現在のテーマ | 親コンポーネントから注入 |
| toggle-theme | Emit（出力） | (isDark: boolean) => void | テーマ切替イベント | - |
| toggle-ssr | Emit（出力） | () => void | SSR切替イベント | - |
| toggle-prod | Emit（出力） | () => void | DEV/PROD切替イベント | - |
| toggle-autosave | Emit（出力） | () => void | AutoSave切替イベント | - |
| reload-page | Emit（出力） | () => void | リロードイベント | - |
| vueVersion | 内部（computed） | string | 表示用Vueバージョン文字列 | store.loading時 'loading...'、それ以外は store.vueVersion または `@{commit}` |

## 表示項目

| 項目名 | 表示領域 | データソース | 説明 |
|--------|---------|-------------|------|
| ロゴ | 左端 | `/logo.svg` 静的ファイル | Vue.js ロゴ画像 |
| タイトル | ロゴ右 | 固定文字列 | "Vue SFC Playground"。幅520px以下で非表示 |
| TypeScript Version | リンク領域左 | store.typescriptVersion | VersionSelect コンポーネントで表示 |
| Vue Version | リンク領域 | vueVersion computed | VersionSelect コンポーネントで表示。スロットに "This Commit" と "Commits History" リンクを含む |
| DEV/PROD ボタン | リンク領域 | prod プロパティ | DEV（緑）/ PROD（紫）テキストトグル |
| SSR ON/OFF ボタン | リンク領域 | ssr プロパティ | SSR ON（緑）/ SSR OFF（グレー）テキストトグル |
| AutoSave ON/OFF ボタン | リンク領域 | autoSave プロパティ | AutoSave ON（緑）/ AutoSave OFF（グレー）テキストトグル |
| テーマ切替ボタン | リンク領域 | theme プロパティ | Sun アイコン（light時）/ Moon アイコン（dark時） |
| Share ボタン | リンク領域 | - | Share アイコン |
| Reload ボタン | リンク領域 | - | Reload アイコン |
| Download ボタン | リンク領域 | - | Download アイコン |
| GitHub リンク | 右端 | 固定URL | GitHub アイコン |

## イベント仕様

### 1-DEV/PROD モード切替ボタンクリック

ボタンクリック時に `$emit('toggle-prod')` を発火（102行目）。親コンポーネント（App.vue）の `toggleProdMode()` が呼ばれ、`productionMode` が反転する。ボタンのテキストは `prod ? 'PROD' : 'DEV'` で動的に切り替わり（104行目）、CSS クラス `.prod` の有無でボタンカラーが緑（DEV）または紫（PROD）に変化する。

### 2-SSR ON/OFF 切替ボタンクリック

ボタンクリック時に `$emit('toggle-ssr')` を発火（111行目）。ボタンテキストは `ssr ? 'SSR ON' : 'SSR OFF'` で切り替わり（112行目）、`.enabled` クラスの有無で背景色が緑（ON）またはグレー（OFF）に変化する。

### 3-AutoSave 切替ボタンクリック

ボタンクリック時に `$emit('toggle-autosave')` を発火（118行目）。ボタンテキストは `autoSave ? 'AutoSave ON' : 'AutoSave OFF'` で切り替わり（120行目）、`.enabled` クラスの有無で背景色が変化する。

### 4-テーマ切替ボタンクリック

ボタンクリック時に `toggleDark()` メソッドが実行される（125行目）。処理内容:
1. `document.documentElement.classList.toggle('dark')` でHTMLルート要素の dark クラスをトグル（59行目）
2. localStorage の `vue-sfc-playground-prefer-dark` にダークモード状態を保存（61-64行目）
3. `emit('toggle-theme', cls.contains('dark'))` で親コンポーネントに通知（65行目）

### 5-Share ボタンクリック

`copyLink(e)` メソッドが実行される（47-56行目）。処理内容:
1. `e.metaKey` が true の場合: Vueバージョンをリセットし `localhost:5173` にリダイレクト（48-52行目）
2. `e.metaKey` が false の場合: `navigator.clipboard.writeText(location.href)` で現在のURLをクリップボードにコピーし、alert でメッセージ表示（54-55行目）

### 6-Reload ボタンクリック

ボタンクリック時に `$emit('reload-page')` を発火（133行目）。親コンポーネントの `reloadPage()` が呼ばれ、Repl コンポーネントのプレビューがリロードされる。

### 7-Download ボタンクリック

ボタンクリック時に `downloadProject(store)` が直接呼び出される（139行目）。download.ts の `downloadProject` 関数が実行され、confirm ダイアログ確認後にプロジェクトファイルを ZIP 形式でダウンロードする。

### 8-Vue バージョン選択

VersionSelect コンポーネントの `@update:model-value` で `setVueVersion(v)` が呼ばれる（83行目）。`store.vueVersion = v` でストアのバージョンを更新する（40行目）。"This Commit" 選択時は `resetVueVersion()` で `store.vueVersion = null` にリセットされる（43-45行目）。

### 9-TypeScript バージョン選択

VersionSelect コンポーネントの `v-model="store.typescriptVersion"` で直接ストアのバージョンを更新する（77行目）。

### 10-GitHub リンククリック

固定URLリンク `https://github.com/vuejs/core/tree/main/packages-private/sfc-playground` を新規タブで開く（143-150行目）。

## データベース更新仕様

### 操作別データベース影響一覧

本コンポーネントはクライアントサイドのみで動作するため、データベースへのアクセスは発生しない。

| 操作（イベント） | 対象ストレージ | 操作種別 | 概要 |
|----------------|--------------|---------|------|
| テーマ切替 | localStorage | SET | `vue-sfc-playground-prefer-dark` キーに true/false を保存 |
| Share（通常） | クリップボード | WRITE | 現在のページURLをクリップボードに書き込み |

### テーブル別更新項目詳細

#### localStorage

| 操作 | キー名 | 更新値 | 備考 |
|-----|--------|-------|------|
| SET | `vue-sfc-playground-prefer-dark` | `"true"` / `"false"` | toggleDark() 実行時（61-64行目） |

## メッセージ仕様

| メッセージ種別 | メッセージ内容 | 発生条件 | 表示方法 |
|--------------|--------------|---------|---------|
| 情報 | "Sharable URL has been copied to clipboard." | Share ボタンクリック時（metaKey なし） | alert() |
| 確認 | "Download project files?" | Download ボタンクリック時 | confirm()（download.ts 内） |

## 例外処理

| 例外条件 | 処理内容 | 発生箇所 |
|---------|---------|---------|
| store.loading が true | vueVersion computed が 'loading...' を返す | Header.vue 33-34行目 |
| クリップボード API 非対応 | 例外がスローされる（ハンドリングなし） | Header.vue 54行目 |

## 備考

- `__COMMIT__` はビルド時に注入されるグローバル変数であり、現在のGitコミットハッシュを表す
- Share ボタンの meta キー（Mac: Cmd、Windows: Win）併用によるローカルリダイレクト機能は開発者向けの隠し機能である
- レスポンシブ対応: 画面幅560px以下でタイトルフォントサイズが0.9emに縮小、520px以下でタイトル文字列が非表示
- ナビゲーションバーの高さは CSS 変数 `--nav-height: 50px` で定義されている

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、Header コンポーネントが受け取るプロパティと発行するイベントの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 13-19行目: defineProps の型定義（store, prod, ssr, autoSave, theme） |
| 1-2 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 20-26行目: defineEmits の5種のイベント定義 |
| 1-3 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 32-37行目: vueVersion computed の算出ロジック |

**読解のコツ**: `ReplStore` は `@vue/repl` パッケージの型であり、`vueVersion`, `typescriptVersion`, `loading`, `compiler` 等のプロパティを持つ。`__COMMIT__` はビルド時に vite の define で注入されるグローバル変数である。

#### Step 2: エントリーポイントを理解する

Header は App.vue から呼び出される子コンポーネントである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | App.vue | `packages-private/sfc-playground/src/App.vue` | 149-160行目: Header コンポーネントの使用箇所。プロパティバインディングとイベントハンドリング |

**主要処理フロー**:
1. **App.vue 149行目**: `<Header>` コンポーネントの開始
2. **App.vue 150-154行目**: `:store`, `:prod`, `:ssr`, `:autoSave`, `:theme` プロパティの渡し
3. **App.vue 155-159行目**: 5種のイベントハンドラの登録

#### Step 3: イベントハンドラを理解する

Header 内部のイベント処理ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 39-45行目: setVueVersion / resetVueVersion 関数 |
| 3-2 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 47-56行目: copyLink 関数（Share機能） |
| 3-3 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 58-66行目: toggleDark 関数（テーマ切替） |

**主要処理フロー**:
- **39-41行目**: `setVueVersion(v)` - store.vueVersion を指定バージョンに設定
- **43-45行目**: `resetVueVersion()` - store.vueVersion を null にリセット
- **47-56行目**: `copyLink(e)` - metaKey 判定後、クリップボードコピーまたはローカルリダイレクト
- **58-66行目**: `toggleDark()` - DOM操作でダーククラスをトグル、localStorage保存、イベント発火

#### Step 4: テンプレート構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 69-153行目: nav 要素内の構造（h1、.links 配下の各ボタン・コンポーネント） |
| 4-2 | Header.vue | `packages-private/sfc-playground/src/Header.vue` | 76-97行目: VersionSelect の2つのインスタンス（TypeScript用・Vue用） |

**主要処理フロー**:
- **71-74行目**: ロゴとタイトル表示
- **76-80行目**: TypeScript VersionSelect（v-model直接バインド）
- **81-97行目**: Vue VersionSelect（カスタムイベントとスロット使用）
- **98-121行目**: DEV/PROD、SSR、AutoSave の3つのトグルボタン
- **122-141行目**: テーマ切替、Share、Reload、Download の4つのアクションボタン
- **143-150行目**: GitHub リンク

### プログラム呼び出し階層図

```
App.vue
    |
    +-- Header.vue
    |       |
    |       +-- VersionSelect.vue (TypeScript用)
    |       |       +-- fetchVersions() --> jsdelivr API
    |       |       +-- Copy.vue (アイコン)
    |       |
    |       +-- VersionSelect.vue (Vue用)
    |       |       +-- fetchVersions() --> jsdelivr API
    |       |       +-- Copy.vue (アイコン)
    |       |       +-- <slot> (This Commit / Commits History)
    |       |
    |       +-- toggleDark() --> localStorage / DOM操作 / emit
    |       +-- copyLink() --> clipboard API / alert
    |       +-- downloadProject(store) --> download.ts --> JSZip
    |       +-- setVueVersion() / resetVueVersion() --> store 更新
    |       |
    |       +-- アイコンコンポーネント群
    |               +-- Sun.vue / Moon.vue
    |               +-- Share.vue
    |               +-- Download.vue
    |               +-- GitHub.vue
    |               +-- Reload.vue
```

### データフロー図

```
[入力]                       [処理]                           [出力]

App.vue (props) ──────────> Header.vue ────────────────────> UI表示
  store                      |
  prod                       +-- vueVersion computed ──────> バージョン表示文字列
  ssr                        |
  autoSave                   +-- toggleDark() ─────────────> localStorage 更新
  theme                      |                                DOM classList 操作
                             |                                emit('toggle-theme')
                             |
                             +-- copyLink() ───────────────> clipboard / alert
                             |                                または localhost リダイレクト
                             |
                             +-- $emit('toggle-prod') ─────> App.vue toggleProdMode()
                             +-- $emit('toggle-ssr') ──────> App.vue toggleSSR()
                             +-- $emit('toggle-autosave') ─> App.vue toggleAutoSave()
                             +-- $emit('reload-page') ─────> App.vue reloadPage()
                             |
                             +-- downloadProject(store) ───> ZIP ダウンロード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Header.vue | `packages-private/sfc-playground/src/Header.vue` | ソース | ナビゲーションバー本体コンポーネント |
| App.vue | `packages-private/sfc-playground/src/App.vue` | ソース | 親コンポーネント。Header にプロパティ渡しとイベントハンドリング |
| VersionSelect.vue | `packages-private/sfc-playground/src/VersionSelect.vue` | ソース | バージョン選択ドロップダウン。Header内で2回使用 |
| download.ts | `packages-private/sfc-playground/src/download/download.ts` | ソース | プロジェクトZIPダウンロード機能 |
| Sun.vue | `packages-private/sfc-playground/src/icons/Sun.vue` | ソース | ライトテーマ用太陽アイコン |
| Moon.vue | `packages-private/sfc-playground/src/icons/Moon.vue` | ソース | ダークテーマ用月アイコン |
| Share.vue | `packages-private/sfc-playground/src/icons/Share.vue` | ソース | 共有アイコン |
| Download.vue | `packages-private/sfc-playground/src/icons/Download.vue` | ソース | ダウンロードアイコン |
| GitHub.vue | `packages-private/sfc-playground/src/icons/GitHub.vue` | ソース | GitHubアイコン |
| Reload.vue | `packages-private/sfc-playground/src/icons/Reload.vue` | ソース | リロードアイコン |
