# 機能設計書 55-テーマ管理

## 概要

本ドキュメントは、OpenCodeのテーマ管理機能について、その設計仕様を記述するものである。

### 本機能の処理概要

テーマ管理機能は、カスタムカラーテーマの読み込み、適用、切り替えを行う機能である。シードカラー（基本色）からOKLCH色空間を使用してカラースケールを自動生成し、200以上のデザイントークン（背景、テキスト、ボーダー、シンタックスハイライト等）にマッピングする。ライト/ダーク両モードに対応し、システム設定またはユーザー選択に基づいて自動切り替えを行う。

**業務上の目的・背景**：開発者は長時間コードと向き合うため、目に優しく、好みに合ったカラースキームで作業できることが重要である。テーマ管理機能により、ユーザーは16種類のプリセットテーマから選択したり、カスタムテーマを作成したりできる。

**機能の利用シーン**：
- アプリケーション初回起動時のデフォルトテーマ適用
- 設定画面でのテーマ切り替え
- システムのダーク/ライトモード変更に連動した自動切り替え
- カスタムテーマJSONファイルからのテーマ読み込み

**主要な処理内容**：
1. シードカラー（8色）からカラースケール（12段階）を自動生成
2. 生成したカラースケールを200以上のデザイントークンにマッピング
3. CSS変数としてDOMに適用
4. ライト/ダークモードの切り替え
5. ローカルストレージへのテーマ設定永続化
6. プレビュー機能（設定確定前の一時適用）

**関連システム・外部連携**：ローカルストレージ、CSSカスタムプロパティ

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | レイアウト | 補助機能 | テーマ切り替え機能、カラースキーム管理 |

## 機能種別

UI設定 / スタイリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| seeds.neutral | HexColor | Yes | ニュートラルカラー（グレースケール基本色） | #RRGGBB形式 |
| seeds.primary | HexColor | Yes | プライマリカラー | #RRGGBB形式 |
| seeds.success | HexColor | Yes | 成功色（緑系） | #RRGGBB形式 |
| seeds.warning | HexColor | Yes | 警告色（黄/オレンジ系） | #RRGGBB形式 |
| seeds.error | HexColor | Yes | エラー色（赤系） | #RRGGBB形式 |
| seeds.info | HexColor | Yes | 情報色（青系） | #RRGGBB形式 |
| seeds.interactive | HexColor | Yes | インタラクティブ要素色 | #RRGGBB形式 |
| seeds.diffAdd | HexColor | Yes | 差分追加色（緑系） | #RRGGBB形式 |
| seeds.diffDelete | HexColor | Yes | 差分削除色（赤系） | #RRGGBB形式 |
| overrides | Record<string, ColorValue> | No | 個別トークンの上書き | - |

### 入力データソース

- テーマJSON定義ファイル（プリセット）
- ローカルストレージ（保存済み設定）
- システム設定（prefers-color-scheme）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| tokens | ResolvedTheme | 解決済みデザイントークン（200+項目） |
| css | string | CSS変数定義文字列 |

### 出力先

- DOMスタイル要素（#oc-theme / #opencode-theme）
- ローカルストレージ（設定永続化）
- document.documentElement.dataset.theme
- document.documentElement.dataset.colorScheme

## 処理フロー

### 処理シーケンス

```
1. テーマ初期化
   └─ ThemeProvider: デフォルトテーマ読み込み、ストア初期化

2. システム設定検出
   └─ getSystemMode(): prefers-color-schemeをクエリ

3. 保存済み設定復元
   └─ localStorage.getItem(): テーマID、カラースキーム取得

4. カラースケール生成
   └─ resolveThemeVariant(): シードカラーからスケール生成

5. CSS変数適用
   └─ applyThemeCss(): DOM要素にスタイル注入

6. イベントリスナー設定
   └─ mediaQuery.addEventListener(): システム設定変更監視
```

### フローチャート

```mermaid
flowchart TD
    A[ThemeProvider初期化] --> B[DEFAULT_THEMES読み込み]
    B --> C[getSystemMode]
    C --> D[localStorage読み込み]
    D --> E{保存済みテーマあり?}
    E -->|Yes| F[保存済みテーマ設定]
    E -->|No| G[デフォルト(oc-1)設定]
    F --> H[resolveThemeVariant]
    G --> H
    H --> I[generateScale ×9]
    I --> J[トークンマッピング]
    J --> K[themeToCss]
    K --> L[applyThemeCss]
    L --> M[DOM更新]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルトテーマ | oc-1をデフォルトとして使用 | テーマ未設定時 |
| BR-02 | システム連動 | colorScheme="system"時はシステム設定に追従 | システムモード選択時 |
| BR-03 | 12段階スケール | 各シードカラーから12段階のスケールを生成 | カラースケール生成時 |
| BR-04 | OKLCH色空間 | 知覚均一性のためOKLCH色空間で計算 | 色変換時 |
| BR-05 | プレビューキャンセル | プレビュー中のキャンセルで元の設定に復帰 | プレビュー操作時 |

### 計算ロジック

- HEX→OKLCH変換: `hexToOklch(hex)` → sRGB→線形RGB→OKLCH
- OKLCH→HEX変換: `oklchToHex(oklch)` → OKLCH→線形RGB→sRGB→HEX
- 輝度スケール: ダーク`[0.15, 0.18, 0.22, ...]` / ライト`[0.99, 0.97, 0.94, ...]`
- 彩度係数: `[0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.85, 1, 1, 0.9, 0.6]`

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベースは使用しない |

### テーブル別操作詳細

ローカルストレージを使用:
- `opencode-theme-id`: テーマID
- `opencode-color-scheme`: カラースキーム（light/dark/system）
- `opencode-theme-css-light`: キャッシュ済みライトモードCSS
- `opencode-theme-css-dark`: キャッシュ済みダークモードCSS

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | テーマ未発見 | 存在しないテーマID指定 | console.warn、無視 |
| - | URL読み込み失敗 | loadThemeFromUrl失敗 | Error throw |
| - | localStorage失敗 | ストレージアクセス不可 | try-catch、無視 |

### リトライ仕様

リトライは行わない。ローカルストレージ操作失敗時は無視して続行。

## トランザクション仕様

該当なし

## パフォーマンス要件

- テーマ切り替え: 即座に反映（DOM更新は同期的）
- カラースケール生成: 数ミリ秒以内

## セキュリティ考慮事項

- 外部URLからのテーマ読み込み時のXSS対策（JSON解析のみ、スクリプト実行なし）

## 備考

- プリセットテーマ数: 16種類（oc-1, oc-2, tokyonight, dracula, monokai, solarized, nord, catppuccin, ayu, onedarkpro, shadesofpurple, nightowl, vesper, carbonfox, gruvbox, aura）
- OKLCH色空間: CSS Color Level 4で標準化された知覚均一色空間

---

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

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

### 推奨読解順序

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

テーマの型定義を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/ui/src/theme/types.ts` | HexColor, OklchColor, ThemeSeedColors, DesktopTheme, ResolvedTheme |

**読解のコツ**:
- **1-7行目**: `HexColor`（#RRGGBB形式）、`OklchColor`（l, c, h）の基本型
- **9-19行目**: `ThemeSeedColors` - 8つのシードカラー定義
- **21-32行目**: `ThemeVariant`と`DesktopTheme` - ライト/ダーク両バリアント
- **53行目**: `ResolvedTheme` - 最終的なトークンマップ

#### Step 2: カラー計算を理解する

色空間変換とスケール生成を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | color.ts | `packages/ui/src/theme/color.ts` | hexToOklch, oklchToHex, generateScale, generateNeutralScale |

**主要処理フロー**:
1. **3-18行目**: `hexToRgb` - HEXをRGB（0-1）に変換
2. **21-28行目**: `rgbToHex` - RGBをHEXに変換
3. **40-62行目**: `rgbToOklch` - RGBをOKLCH色空間に変換
4. **64-87行目**: `oklchToRgb` - OKLCHをRGBに変換
5. **99-122行目**: `generateScale` - シードカラーから12段階スケール生成
6. **124-144行目**: `generateNeutralScale` - ニュートラルカラー用スケール

#### Step 3: トークン解決を理解する

シードカラーからデザイントークンへのマッピングを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | resolve.ts | `packages/ui/src/theme/resolve.ts` | resolveThemeVariant, themeToCss |

**主要処理フロー**:
- **4-298行目**: `resolveThemeVariant` - シードカラーからすべてのトークンを生成
- **7-15行目**: 9種類のカラースケール生成（neutral, primary, success等）
- **19-298行目**: 各カテゴリ（background, surface, text, border等）のトークン定義
- **322-326行目**: `themeToCss` - トークンをCSS変数文字列に変換

#### Step 4: テーマ適用を理解する

DOMへのテーマ適用を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | loader.ts | `packages/ui/src/theme/loader.ts` | applyTheme, loadThemeFromUrl, setColorScheme |

**主要処理フロー**:
- **7-16行目**: `ensureLoaderStyleElement` - スタイル要素の取得/作成
- **18-27行目**: `applyTheme` - テーマ適用のメイン関数
- **69-75行目**: `loadThemeFromUrl` - 外部URLからテーマ読み込み
- **97-103行目**: `setColorScheme` - ライト/ダーク/auto切り替え

#### Step 5: コンテキストを理解する

Reactコンテキストによるテーマ状態管理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | context.tsx | `packages/ui/src/theme/context.tsx` | ThemeProvider, useTheme |

**主要処理フロー**:
- **69-180行目**: `ThemeProvider`初期化ロジック
- **81-106行目**: システム設定監視、保存済み設定復元
- **115-124行目**: `setTheme` - テーマ変更
- **126-130行目**: `setColorScheme` - カラースキーム変更
- **140-159行目**: プレビュー機能（previewTheme, previewColorScheme）

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

```
ThemeProvider (context.tsx)
    │
    ├─ onMount
    │      ├─ localStorage.getItem(theme-id, color-scheme)
    │      └─ mediaQuery.addEventListener
    │
    ├─ createEffect
    │      └─ applyThemeCss()
    │             │
    │             ├─ resolveThemeVariant() (resolve.ts)
    │             │      │
    │             │      ├─ generateScale() ×8 (color.ts)
    │             │      │      └─ hexToOklch → oklchToHex
    │             │      │
    │             │      ├─ generateNeutralScale()
    │             │      │
    │             │      └─ トークンマッピング（200+項目）
    │             │
    │             └─ themeToCss()
    │                    └─ CSS変数文字列生成
    │
    └─ setTheme / setColorScheme / previewTheme
```

### データフロー図

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

テーマJSON
  DesktopTheme ─────────▶ resolveThemeVariant ─────────▶ ResolvedTheme
     │                          │                          │
シードカラー                      │                          │
  ThemeSeedColors               ▼                          │
     │                   generateScale ×9                  │
     │                          │                          │
     │                          ▼                          │
     │                   トークンマッピング                 │
     │                          │                          ▼
     │                          │                    themeToCss
     │                          │                          │
     │                          ▼                          ▼
     └───────────────────▶ applyThemeCss ───────────▶ DOM (style要素)
                                │
                                ▼
                          localStorage
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/ui/src/theme/index.ts` | ソース | 公開API集約 |
| types.ts | `packages/ui/src/theme/types.ts` | ソース | 型定義 |
| color.ts | `packages/ui/src/theme/color.ts` | ソース | 色空間変換、スケール生成 |
| resolve.ts | `packages/ui/src/theme/resolve.ts` | ソース | トークン解決 |
| loader.ts | `packages/ui/src/theme/loader.ts` | ソース | テーマ適用 |
| context.tsx | `packages/ui/src/theme/context.tsx` | ソース | Reactコンテキスト |
| default-themes.ts | `packages/ui/src/theme/default-themes.ts` | ソース | プリセットテーマ |
| themes/*.json | `packages/ui/src/theme/themes/` | 設定 | テーマ定義ファイル |
