295 lines
11 KiB
Dart
295 lines
11 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
|||
|
|
|
|||
|
|
/// AppColors ThemeExtension
|
|||
|
|
///
|
|||
|
|
/// セマンティックカラーシステム:色の「意味」に基づいて定義
|
|||
|
|
/// テーマバリアント(和紙×墨×琥珀 / Current)とブライトネス(Light/Dark)に完全対応
|
|||
|
|
///
|
|||
|
|
/// 使用例:
|
|||
|
|
/// ```dart
|
|||
|
|
/// final colors = Theme.of(context).extension<AppColors>()!;
|
|||
|
|
/// Icon(icon, color: colors.brandPrimary);
|
|||
|
|
/// Text('テキスト', style: TextStyle(color: colors.textPrimary));
|
|||
|
|
/// ```
|
|||
|
|
@immutable
|
|||
|
|
class AppColors extends ThemeExtension<AppColors> {
|
|||
|
|
// ===== テキストカラー(構造的) =====
|
|||
|
|
/// メインテキスト(本文、タイトル)
|
|||
|
|
final Color textPrimary;
|
|||
|
|
/// セカンダリテキスト(説明文、補足)
|
|||
|
|
final Color textSecondary;
|
|||
|
|
/// ターシャリテキスト(無効化、プレースホルダー)
|
|||
|
|
final Color textTertiary;
|
|||
|
|
|
|||
|
|
// ===== ブランドカラー(テーマバリアント依存) =====
|
|||
|
|
/// プライマリブランドカラー
|
|||
|
|
/// - Washi Light: 墨色(焦げ茶)
|
|||
|
|
/// - Washi Dark: 琥珀色(ゴールド)
|
|||
|
|
/// - Current Light: Posimai Blue
|
|||
|
|
/// - Current Dark: ライトブルー
|
|||
|
|
final Color brandPrimary;
|
|||
|
|
|
|||
|
|
/// アクセントブランドカラー
|
|||
|
|
/// - Washi Light: 琥珀色
|
|||
|
|
/// - Washi Dark: 深い琥珀
|
|||
|
|
/// - Current Light: オレンジ
|
|||
|
|
/// - Current Dark: ライトオレンジ
|
|||
|
|
final Color brandAccent;
|
|||
|
|
|
|||
|
|
/// サーフェイスブランドカラー(背景のティント)
|
|||
|
|
/// - Washi Light: 和紙ホワイト
|
|||
|
|
/// - Washi Dark: ダークグレー
|
|||
|
|
/// - Current Light: ホワイト
|
|||
|
|
/// - Current Dark: ダークグレー
|
|||
|
|
final Color brandSurface;
|
|||
|
|
|
|||
|
|
// ===== アイコンカラー =====
|
|||
|
|
/// デフォルトアイコンカラー(通常のアイコン)
|
|||
|
|
final Color iconDefault;
|
|||
|
|
/// サブアイコンカラー(セカンダリ、無効化)
|
|||
|
|
final Color iconSubtle;
|
|||
|
|
/// アクセントアイコンカラー(強調、アクション)
|
|||
|
|
final Color iconAccent;
|
|||
|
|
|
|||
|
|
// ===== サーフェイスカラー =====
|
|||
|
|
/// カード背景、エレベーション
|
|||
|
|
final Color surfaceElevated;
|
|||
|
|
/// サブトル背景(微妙な差)
|
|||
|
|
final Color surfaceSubtle;
|
|||
|
|
/// ボーダー、区切り線
|
|||
|
|
final Color divider;
|
|||
|
|
|
|||
|
|
// ===== セマンティックカラー(機能的) =====
|
|||
|
|
/// 成功、安全(緑系)
|
|||
|
|
final Color success;
|
|||
|
|
/// 警告、注意(オレンジ系)
|
|||
|
|
final Color warning;
|
|||
|
|
/// エラー、危険(赤系)
|
|||
|
|
final Color error;
|
|||
|
|
/// 情報、中立(青系)
|
|||
|
|
final Color info;
|
|||
|
|
|
|||
|
|
const AppColors({
|
|||
|
|
required this.textPrimary,
|
|||
|
|
required this.textSecondary,
|
|||
|
|
required this.textTertiary,
|
|||
|
|
required this.brandPrimary,
|
|||
|
|
required this.brandAccent,
|
|||
|
|
required this.brandSurface,
|
|||
|
|
required this.iconDefault,
|
|||
|
|
required this.iconSubtle,
|
|||
|
|
required this.iconAccent,
|
|||
|
|
required this.surfaceElevated,
|
|||
|
|
required this.surfaceSubtle,
|
|||
|
|
required this.divider,
|
|||
|
|
required this.success,
|
|||
|
|
required this.warning,
|
|||
|
|
required this.error,
|
|||
|
|
required this.info,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
AppColors copyWith({
|
|||
|
|
Color? textPrimary,
|
|||
|
|
Color? textSecondary,
|
|||
|
|
Color? textTertiary,
|
|||
|
|
Color? brandPrimary,
|
|||
|
|
Color? brandAccent,
|
|||
|
|
Color? brandSurface,
|
|||
|
|
Color? iconDefault,
|
|||
|
|
Color? iconSubtle,
|
|||
|
|
Color? iconAccent,
|
|||
|
|
Color? surfaceElevated,
|
|||
|
|
Color? surfaceSubtle,
|
|||
|
|
Color? divider,
|
|||
|
|
Color? success,
|
|||
|
|
Color? warning,
|
|||
|
|
Color? error,
|
|||
|
|
Color? info,
|
|||
|
|
}) {
|
|||
|
|
return AppColors(
|
|||
|
|
textPrimary: textPrimary ?? this.textPrimary,
|
|||
|
|
textSecondary: textSecondary ?? this.textSecondary,
|
|||
|
|
textTertiary: textTertiary ?? this.textTertiary,
|
|||
|
|
brandPrimary: brandPrimary ?? this.brandPrimary,
|
|||
|
|
brandAccent: brandAccent ?? this.brandAccent,
|
|||
|
|
brandSurface: brandSurface ?? this.brandSurface,
|
|||
|
|
iconDefault: iconDefault ?? this.iconDefault,
|
|||
|
|
iconSubtle: iconSubtle ?? this.iconSubtle,
|
|||
|
|
iconAccent: iconAccent ?? this.iconAccent,
|
|||
|
|
surfaceElevated: surfaceElevated ?? this.surfaceElevated,
|
|||
|
|
surfaceSubtle: surfaceSubtle ?? this.surfaceSubtle,
|
|||
|
|
divider: divider ?? this.divider,
|
|||
|
|
success: success ?? this.success,
|
|||
|
|
warning: warning ?? this.warning,
|
|||
|
|
error: error ?? this.error,
|
|||
|
|
info: info ?? this.info,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@override
|
|||
|
|
AppColors lerp(ThemeExtension<AppColors>? other, double t) {
|
|||
|
|
if (other is! AppColors) {
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
return AppColors(
|
|||
|
|
textPrimary: Color.lerp(textPrimary, other.textPrimary, t)!,
|
|||
|
|
textSecondary: Color.lerp(textSecondary, other.textSecondary, t)!,
|
|||
|
|
textTertiary: Color.lerp(textTertiary, other.textTertiary, t)!,
|
|||
|
|
brandPrimary: Color.lerp(brandPrimary, other.brandPrimary, t)!,
|
|||
|
|
brandAccent: Color.lerp(brandAccent, other.brandAccent, t)!,
|
|||
|
|
brandSurface: Color.lerp(brandSurface, other.brandSurface, t)!,
|
|||
|
|
iconDefault: Color.lerp(iconDefault, other.iconDefault, t)!,
|
|||
|
|
iconSubtle: Color.lerp(iconSubtle, other.iconSubtle, t)!,
|
|||
|
|
iconAccent: Color.lerp(iconAccent, other.iconAccent, t)!,
|
|||
|
|
surfaceElevated: Color.lerp(surfaceElevated, other.surfaceElevated, t)!,
|
|||
|
|
surfaceSubtle: Color.lerp(surfaceSubtle, other.surfaceSubtle, t)!,
|
|||
|
|
divider: Color.lerp(divider, other.divider, t)!,
|
|||
|
|
success: Color.lerp(success, other.success, t)!,
|
|||
|
|
warning: Color.lerp(warning, other.warning, t)!,
|
|||
|
|
error: Color.lerp(error, other.error, t)!,
|
|||
|
|
info: Color.lerp(info, other.info, t)!,
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== ファクトリーメソッド:和紙×墨×琥珀テーマ =====
|
|||
|
|
|
|||
|
|
/// 和紙×墨×琥珀 ライトモード
|
|||
|
|
/// - プライマリ: 墨色(焦げ茶)
|
|||
|
|
/// - アクセント: 琥珀色(ゴールド)
|
|||
|
|
/// - サーフェイス: 和紙ホワイト
|
|||
|
|
static AppColors washiLight() {
|
|||
|
|
return const AppColors(
|
|||
|
|
// テキスト
|
|||
|
|
textPrimary: Color(0xFF2C2C2C), // ほぼ黒(墨インスパイア)
|
|||
|
|
textSecondary: Color(0xFF757575), // グレー
|
|||
|
|
textTertiary: Color(0xFFBDBDBD), // ライトグレー
|
|||
|
|
|
|||
|
|
// ブランド
|
|||
|
|
brandPrimary: Color(0xFF4A3B32), // 墨色(焦げ茶)
|
|||
|
|
brandAccent: Color(0xFFD4A574), // 琥珀色
|
|||
|
|
brandSurface: Color(0xFFFDFBF7), // 和紙ホワイト
|
|||
|
|
|
|||
|
|
// アイコン
|
|||
|
|
iconDefault: Color(0xFF4A3B32), // 墨色
|
|||
|
|
iconSubtle: Color(0xFF9E9E9E), // グレー
|
|||
|
|
iconAccent: Color(0xFFD4A574), // 琥珀色
|
|||
|
|
|
|||
|
|
// サーフェイス
|
|||
|
|
surfaceElevated: Color(0xFFFFFFFF), // 純白(カード)
|
|||
|
|
surfaceSubtle: Color(0xFFF5F5F5), // オフホワイト
|
|||
|
|
divider: Color(0xFFE0E0E0), // ライトグレー
|
|||
|
|
|
|||
|
|
// セマンティック
|
|||
|
|
success: Color(0xFF388E3C), // 緑
|
|||
|
|
warning: Color(0xFFF57C00), // オレンジ
|
|||
|
|
error: Color(0xFFD32F2F), // 赤
|
|||
|
|
info: Color(0xFF1976D2), // 青
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 和紙×墨×琥珀 ダークモード
|
|||
|
|
/// - プライマリ: 琥珀色(ゴールド)
|
|||
|
|
/// - アクセント: 深い琥珀
|
|||
|
|
/// - サーフェイス: ダークグレー
|
|||
|
|
static AppColors washiDark() {
|
|||
|
|
return const AppColors(
|
|||
|
|
// テキスト
|
|||
|
|
textPrimary: Color(0xFFFFFFFF), // 白
|
|||
|
|
textSecondary: Color(0xFFBDBDBD), // ライトグレー
|
|||
|
|
textTertiary: Color(0xFF757575), // グレー
|
|||
|
|
|
|||
|
|
// ブランド
|
|||
|
|
brandPrimary: Color(0xFFD4A574), // 琥珀色(ゴールド)
|
|||
|
|
brandAccent: Color(0xFFB8860B), // 深い琥珀
|
|||
|
|
brandSurface: Color(0xFF1E1E1E), // ダークグレー
|
|||
|
|
|
|||
|
|
// アイコン
|
|||
|
|
iconDefault: Color(0xFFD4A574), // 琥珀色
|
|||
|
|
iconSubtle: Color(0xFF9E9E9E), // グレー
|
|||
|
|
iconAccent: Color(0xFFFFD54F), // ライトゴールド
|
|||
|
|
|
|||
|
|
// サーフェイス
|
|||
|
|
surfaceElevated: Color(0xFF2C2C2C), // ややライトなダーク
|
|||
|
|
surfaceSubtle: Color(0xFF1A1A1A), // 深いダーク
|
|||
|
|
divider: Color(0xFF424242), // ダークグレー
|
|||
|
|
|
|||
|
|
// セマンティック
|
|||
|
|
success: Color(0xFF66BB6A), // ライトグリーン
|
|||
|
|
warning: Color(0xFFFFB74D), // ライトオレンジ
|
|||
|
|
error: Color(0xFFEF5350), // ライトレッド
|
|||
|
|
info: Color(0xFF42A5F5), // ライトブルー
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== ファクトリーメソッド:Currentテーマ(オリジナル) =====
|
|||
|
|
|
|||
|
|
/// Current(オリジナル)ライトモード
|
|||
|
|
/// - プライマリ: Posimai Blue
|
|||
|
|
/// - アクセント: オレンジ
|
|||
|
|
/// - サーフェイス: ホワイト
|
|||
|
|
static AppColors currentLight() {
|
|||
|
|
return const AppColors(
|
|||
|
|
// テキスト
|
|||
|
|
textPrimary: Color(0xFF212121), // ほぼ黒
|
|||
|
|
textSecondary: Color(0xFF757575), // グレー
|
|||
|
|
textTertiary: Color(0xFFBDBDBD), // ライトグレー
|
|||
|
|
|
|||
|
|
// ブランド
|
|||
|
|
brandPrimary: Color(0xFF376495), // Posimai Blue
|
|||
|
|
brandAccent: Color(0xFFFF6F00), // 深いオレンジ
|
|||
|
|
brandSurface: Color(0xFFFFFFFF), // 純白
|
|||
|
|
|
|||
|
|
// アイコン
|
|||
|
|
iconDefault: Color(0xFF376495), // Posimai Blue
|
|||
|
|
iconSubtle: Color(0xFF9E9E9E), // グレー
|
|||
|
|
iconAccent: Color(0xFFFF6F00), // オレンジ
|
|||
|
|
|
|||
|
|
// サーフェイス
|
|||
|
|
surfaceElevated: Color(0xFFFFFFFF), // 純白
|
|||
|
|
surfaceSubtle: Color(0xFFFAFAFA), // オフホワイト
|
|||
|
|
divider: Color(0xFFE0E0E0), // ライトグレー
|
|||
|
|
|
|||
|
|
// セマンティック
|
|||
|
|
success: Color(0xFF388E3C), // 緑
|
|||
|
|
warning: Color(0xFFF57C00), // オレンジ
|
|||
|
|
error: Color(0xFFD32F2F), // 赤
|
|||
|
|
info: Color(0xFF1976D2), // 青
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Current(オリジナル)ダークモード
|
|||
|
|
/// - プライマリ: ライトブルー
|
|||
|
|
/// - アクセント: ライトオレンジ
|
|||
|
|
/// - サーフェイス: ダークグレー
|
|||
|
|
static AppColors currentDark() {
|
|||
|
|
return const AppColors(
|
|||
|
|
// テキスト
|
|||
|
|
textPrimary: Color(0xFFFFFFFF), // 白
|
|||
|
|
textSecondary: Color(0xFFBDBDBD), // ライトグレー
|
|||
|
|
textTertiary: Color(0xFF757575), // グレー
|
|||
|
|
|
|||
|
|
// ブランド
|
|||
|
|
brandPrimary: Color(0xFF8AB4F8), // ライトブルー
|
|||
|
|
brandAccent: Color(0xFFFFB74D), // ライトオレンジ
|
|||
|
|
brandSurface: Color(0xFF1E1E1E), // ダークグレー
|
|||
|
|
|
|||
|
|
// アイコン
|
|||
|
|
iconDefault: Color(0xFF8AB4F8), // ライトブルー
|
|||
|
|
iconSubtle: Color(0xFF9E9E9E), // グレー
|
|||
|
|
iconAccent: Color(0xFFFFB74D), // ライトオレンジ
|
|||
|
|
|
|||
|
|
// サーフェイス
|
|||
|
|
surfaceElevated: Color(0xFF2C2C2C), // ややライトなダーク
|
|||
|
|
surfaceSubtle: Color(0xFF1A1A1A), // 深いダーク
|
|||
|
|
divider: Color(0xFF424242), // ダークグレー
|
|||
|
|
|
|||
|
|
// セマンティック
|
|||
|
|
success: Color(0xFF66BB6A), // ライトグリーン
|
|||
|
|
warning: Color(0xFFFFB74D), // ライトオレンジ
|
|||
|
|
error: Color(0xFFEF5350), // ライトレッド
|
|||
|
|
info: Color(0xFF42A5F5), // ライトブルー
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|