# 画面設計書 103-アナウンスバー

## 概要

本ドキュメントは、Ghost CMSの公開サイトに表示されるアナウンスバー（Announcement Bar）の設計を定義するものである。この画面はサイト訪問者に重要なお知らせを表示するためのウィジェットである。

### 本画面の処理概要

アナウンスバーは、Ghostサイトのページ上部に表示される目立つお知らせバーである。サイト運営者が設定したメッセージを訪問者に伝えるために使用され、プロモーション、重要なお知らせ、イベント告知などに活用される。

**業務上の目的・背景**：サイト運営者は訪問者に対して重要なメッセージを目立つ形で伝える必要がある場合がある。アナウンスバーはページのコンテンツを妨げることなく、上部に固定表示されることで視認性を確保しつつ、ユーザーが閉じることもできる柔軟な通知手段を提供する。セール告知、新機能リリース、メンテナンス予告など様々なユースケースに対応する。また、コンテンツが変更された場合は自動的に再表示されるため、新しい重要なお知らせを見逃すことがない。

**画面へのアクセス方法**：アナウンスバーはGhostテーマのテンプレートに埋め込まれたscriptタグにより自動的にロードされる。管理画面の「設定 > サイト > アナウンスバー設定」でコンテンツと背景色を設定すると、公開サイトの全ページ上部に表示される。

**主要な操作・処理内容**：
1. 初期化 - scriptタグからAPIのURLを取得し、設定を読み込む
2. 表示判定 - sessionStorageを確認し、表示/非表示を判定
3. コンテンツ変更検知 - 前回表示時と内容が異なる場合は再表示
4. アナウンス表示 - HTMLコンテンツと背景色を適用して表示
5. 閉じる操作 - ユーザーが閉じるボタンをクリックした場合に非表示化

**画面遷移**：
- 遷移元: 公開サイトの任意のページ（テーマに埋め込み）
- 遷移先: なし（表示/非表示の切り替えのみ）

**権限による表示制御**：この画面は公開ウィジェットであり、認証不要で全ての訪問者に表示される。管理画面でアナウンスバーが有効になっている場合のみ表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 39 | アナウンスメントバー | 主機能 | サイト上部のお知らせ表示 |
| 75 | Announcement Bar | 補助機能 | お知らせバーUIウィジェットの表示 |
| 35 | 一般設定 | API連携 | アナウンスバー設定の取得 |

## 画面種別

表示（公開サイトウィジェット）

## URL/ルーティング

- 埋め込みスクリプト: 公開サイトのテーマテンプレートに設置
- API エンドポイント: `{apiUrl}` (data-api-url属性で指定)

## 入出力項目

### 入力項目（なし）

この画面はユーザー入力を受け付けない。

### 設定項目（data属性）

| 項目名 | data属性 | 型 | 必須 | 説明 |
|--------|----------|-----|------|------|
| APIのURL | data-api-url | string | 必須 | アナウンス設定を取得するAPIエンドポイント |
| プレビューモード | data-preview | boolean | 任意 | プレビュー表示フラグ |
| アナウンス内容 | data-announcement | string | 任意 | プレビュー時のアナウンス内容（HTML） |
| 背景色 | data-announcement-background | string | 任意 | プレビュー時の背景色 |

### API レスポンス

| 項目名 | 型 | 説明 |
|--------|-----|------|
| announcement | string | アナウンスのHTMLコンテンツ |
| announcement_background | string | 背景色のクラス名 |

## 表示項目

| 項目名 | 表示条件 | 説明 |
|--------|----------|------|
| アナウンスバーコンテナ | visible=true かつ settings.announcement が存在 | 背景色クラスが適用されたバー |
| アナウンス内容 | 常時（コンテナ内） | HTMLコンテンツ（dangerouslySetInnerHTML） |
| 閉じるボタン | 常時（コンテナ内） | CloseIcon（×アイコン）のボタン |

### 背景色クラス

| クラス名 | 説明 |
|---------|------|
| gh-announcement-bar | 基本スタイル |
| {announcement_background} | 管理画面で設定された背景色クラス |

## イベント仕様

### 1-初期化・設定読み込み

**トリガー**: ページロード時（scriptタグ実行）

**処理フロー**:
1. scriptタグから`data-announcement-bar`属性を持つ要素を検索
2. `data-api-url`を取得
3. `data-preview`がtrueの場合、プレビューモードで動作
4. プレビューモードの場合:
   - `data-announcement`と`data-announcement-background`から直接設定を取得
   - Previewコンポーネントでレンダリング
5. 通常モードの場合:
   - APIからアナウンス設定を非同期で取得
   - Mainコンポーネントでレンダリング

### 2-表示判定

**トリガー**: 設定取得完了時、またはannouncement変更時

**処理フロー**:
1. `shouldShowBar(announcement)`を呼び出し
2. `isContentChanged(content)`でsessionStorageの前回コンテンツと比較
3. コンテンツが変更されている場合:
   - sessionStorageに新しいコンテンツを保存
   - バー表示状態をtrueに設定
   - visibleをtrueに設定
4. コンテンツが変更されていない場合:
   - sessionStorageから表示状態を取得
   - 前回閉じられていない場合のみvisibleをtrueに設定

### 3-閉じるボタンクリック

**トリガー**: 閉じるボタン（×）クリック

**処理フロー**:
1. `handleButtonClick()`が呼び出される
2. `setVisible(false)`でコンポーネントの表示状態を非表示に
3. `setBarVisibility(false)`でsessionStorageから表示フラグを削除
4. コンポーネントがnullを返し、バーが非表示になる

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | この画面ではデータベース操作は発生しない |

この画面はAPIからの読み取りのみを行い、データベースへの書き込みは行わない。sessionStorageはクライアントサイドストレージであり、データベースではない。

## メッセージ仕様

| メッセージID | 種別 | メッセージ | 表示条件 |
|-------------|------|-----------|----------|
| - | - | - | エラーメッセージは表示されない |

アナウンスの内容は管理画面で設定されたHTMLが表示される。

## 例外処理

| 例外状況 | 処理内容 | 表示メッセージ |
|---------|---------|---------------|
| API取得失敗 | バーを表示しない | なし |
| announcement が空 | バーを表示しない | なし |
| sessionStorage アクセスエラー | 通常表示を試みる | なし（コンソールに警告は出ない） |

## 備考

- アナウンスバーはページ上部（`<body>`の先頭）に挿入される
- コンテンツはHTMLとして挿入されるため、管理者が設定したリンクやスタイルが反映される
- sessionStorageを使用するため、ブラウザを閉じるとバー閉じた状態がリセットされる
- 同一セッション内でコンテンツが変更されると、閉じていたバーが再表示される
- プレビューモードはadmin画面でのリアルタイムプレビュー用
- CSSファイル（announcement-bar.css）でスタイルが定義されている

---

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

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

### 推奨読解順序

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

APIから取得するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api.js | `apps/announcement-bar/src/utils/api.js` | API応答の構造（announcement配列）を確認 |

**読解のコツ**: APIクライアントの実装から、バックエンドが返すデータ形式を推測する。`api.init()`が`announcement[0]`を返すことから、配列の最初の要素がアクティブなアナウンスであることがわかる。

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

アプリケーションの初期化処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `apps/announcement-bar/src/index.js` | 初期化処理、DOMへのマウント、scriptタグからのデータ取得 |
| 2-2 | App.js | `apps/announcement-bar/src/App.js` | ルートコンポーネント、プレビューモードの分岐 |

**主要処理フロー**:
1. **8-16行目 (index.js)**: addRootDiv()でbodyの先頭にマウント先を作成
2. **18-28行目 (index.js)**: getSiteData()でscriptタグからapiUrlとpreviewDataを取得
3. **30-39行目 (index.js)**: getPreviewData()でプレビューモード判定とデータ取得
4. **45-57行目 (index.js)**: init()でReactアプリをレンダリング
5. **5-12行目 (App.js)**: previewDataの有無でPreviewまたはMainを表示

#### Step 3: メインコンポーネントを理解する

通常モードでの動作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | main.js | `apps/announcement-bar/src/components/main.js` | API呼び出しと状態管理 |
| 3-2 | announcement-bar.js | `apps/announcement-bar/src/components/announcement-bar.js` | 表示ロジックとsessionStorage管理 |

**主要処理フロー**:
- **5-26行目 (main.js)**: useEffectでAPI初期化、設定をstateに保存
- **6-8行目 (announcement-bar.js)**: visible状態の管理、shouldShowBarで初期表示判定
- **19-22行目 (announcement-bar.js)**: handleButtonClickで閉じる処理
- **24-40行目 (announcement-bar.js)**: 条件に応じたレンダリング（null or バー表示）

#### Step 4: 表示判定ロジックを理解する

sessionStorageを使った表示/非表示の判定ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | announcement-bar.js | `apps/announcement-bar/src/components/announcement-bar.js` | shouldShowBar, isContentChanged, setBarVisibility, getBarVisibilityの各関数 |

**主要処理フロー**:
- **43-58行目**: shouldShowBar()でコンテンツ変更チェックと表示判定
- **60-62行目**: setContent()でsessionStorageにコンテンツ保存
- **64-71行目**: isContentChanged()で前回コンテンツとの比較
- **72-78行目**: setBarVisibility()で表示状態の永続化
- **80-82行目**: getBarVisibility()で表示状態の取得

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

```
index.js (init)
    |
    +-- addRootDiv() --> body先頭にdiv追加
    +-- getSiteData() --> scriptタグからapiUrl, previewData取得
    +-- getPreviewData() --> プレビューモードチェック
    |
    +-- ReactDOM.render()
            |
            +-- App.js
                    |
                    +-- [プレビューモード] Preview.js
                    |       |
                    |       +-- AnnouncementBar (settings=previewData)
                    |
                    +-- [通常モード] Main.js
                            |
                            +-- setupGhostApi() --> api.js
                            +-- api.init() --> 設定取得
                            +-- AnnouncementBar (settings=siteSettings)
                                    |
                                    +-- shouldShowBar() --> 表示判定
                                    +-- handleButtonClick() --> 閉じる処理
```

### データフロー図

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

scriptタグ                ┌─▶ プレビューモード
  data-api-url ───────────┤       |
  data-preview            │       +── data-announcement ────▶ AnnouncementBar
  data-announcement       │       +── data-announcement-background
  data-announcement-      │
    background            │
                          └─▶ 通常モード
                                  |
                                  +── api.init() ───────────▶ settings
                                  |                               |
                                  v                               v
sessionStorage            ┌─ shouldShowBar() ◀────────── announcement
  BAR_CONTENT_STORAGE_KEY │       |
  BAR_VISIBILITY_KEY ─────┼───────+── isContentChanged()
                          │       |
                          │       v
                          │   visible state
                          │       |
閉じるボタンクリック ──────────────┼───▶ handleButtonClick()
                          │               |
                          │               v
                          └──────── setBarVisibility(false)
                                          |
                                          v
                                  バー非表示 (null)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `apps/announcement-bar/src/index.js` | エントリーポイント | アプリケーション初期化、DOM操作 |
| App.js | `apps/announcement-bar/src/App.js` | ソース | ルートコンポーネント |
| main.js | `apps/announcement-bar/src/components/main.js` | ソース | 通常モードコンポーネント |
| preview.js | `apps/announcement-bar/src/components/preview.js` | ソース | プレビューモードコンポーネント |
| announcement-bar.js | `apps/announcement-bar/src/components/announcement-bar.js` | ソース | アナウンスバー表示コンポーネント |
| api.js | `apps/announcement-bar/src/utils/api.js` | ソース | Ghost APIクライアント |
| announcement-bar.css | `apps/announcement-bar/src/components/announcement-bar.css` | スタイル | バーのスタイル定義 |
| clear.svg | `apps/announcement-bar/src/icons/clear.svg` | アセット | 閉じるボタンアイコン |
