mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Add Catppuccin Latte, Dracula, Alucard, Nord and Tokyo Night themes
Add five new selectable themes alongside the existing Catppuccin Mocha and Gruvbox Dark, each built through the shared buildAppTheme so they stay visually consistent. Palettes are taken from each project's official source; a few intermediate surface shades are interpolated where the canonical palette omits them (noted in the theme files). Register the new themes in main.dart and add their dropdown entries in settings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3d1f27b02e
commit
dce683e396
@@ -0,0 +1,89 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'theme_builder.dart';
|
||||
|
||||
/// Alucard — the official light counterpart to Dracula.
|
||||
abstract final class AlucardColors {
|
||||
// Neutral ramp (lightest → darkest). Background, the warm/cream tints and the
|
||||
// darker gray are from the base24 Alucard palette; the two mid surfaces are
|
||||
// interpolated to give cards consistent elevation steps.
|
||||
static const Color background = Color(0xFFfffbeb);
|
||||
static const Color warm = Color(0xFFfdf8e2);
|
||||
static const Color cream = Color(0xFFf5f0da);
|
||||
static const Color surface = Color(0xFFf0ebd5);
|
||||
static const Color surfaceHigh = Color(0xFFded8c2);
|
||||
static const Color gray = Color(0xFFceccc0);
|
||||
static const Color comment = Color(0xFF6c664b);
|
||||
static const Color subtleForeground = Color(0xFF4c4a3d);
|
||||
static const Color foreground = Color(0xFF1f1f1f);
|
||||
|
||||
static const Color cyan = Color(0xFF036a96);
|
||||
static const Color green = Color(0xFF14710a);
|
||||
static const Color orange = Color(0xFFa34d14);
|
||||
static const Color pink = Color(0xFFa3144d);
|
||||
static const Color purple = Color(0xFF644ac9);
|
||||
static const Color brightPurple = Color(0xFF7862d0);
|
||||
static const Color red = Color(0xFFcb3a2a);
|
||||
static const Color darkRed = Color(0xFF792219);
|
||||
static const Color redContainer = Color(0xFFf5d6d1);
|
||||
static const Color yellow = Color(0xFF846e15);
|
||||
}
|
||||
|
||||
const ColorScheme _alucardColorScheme = ColorScheme(
|
||||
brightness: Brightness.light,
|
||||
|
||||
// Surfaces — AppBar (darkest) → NavRail → body (lightest)
|
||||
surface: AlucardColors.background,
|
||||
surfaceContainerLowest: AlucardColors.cream,
|
||||
surfaceContainerLow: AlucardColors.warm,
|
||||
surfaceContainer: AlucardColors.surface,
|
||||
surfaceContainerHigh: AlucardColors.surfaceHigh,
|
||||
surfaceContainerHighest: AlucardColors.gray,
|
||||
onSurface: AlucardColors.foreground,
|
||||
onSurfaceVariant: AlucardColors.subtleForeground,
|
||||
outline: AlucardColors.comment,
|
||||
outlineVariant: AlucardColors.gray,
|
||||
|
||||
// Primary — Save button, selected nav indicators
|
||||
primary: AlucardColors.purple,
|
||||
onPrimary: AlucardColors.background,
|
||||
primaryContainer: AlucardColors.surfaceHigh,
|
||||
onPrimaryContainer: AlucardColors.foreground,
|
||||
|
||||
// Secondary — Test button (not-passing state)
|
||||
secondary: AlucardColors.cyan,
|
||||
onSecondary: AlucardColors.background,
|
||||
secondaryContainer: AlucardColors.gray,
|
||||
onSecondaryContainer: AlucardColors.foreground,
|
||||
|
||||
// Tertiary — swipe-to-unread background
|
||||
tertiary: AlucardColors.green,
|
||||
onTertiary: AlucardColors.background,
|
||||
tertiaryContainer: AlucardColors.surface,
|
||||
onTertiaryContainer: AlucardColors.foreground,
|
||||
|
||||
// Error
|
||||
error: AlucardColors.red,
|
||||
onError: AlucardColors.background,
|
||||
errorContainer: AlucardColors.redContainer,
|
||||
onErrorContainer: AlucardColors.darkRed,
|
||||
|
||||
// Inverse / scrim
|
||||
inverseSurface: AlucardColors.foreground,
|
||||
onInverseSurface: AlucardColors.background,
|
||||
inversePrimary: AlucardColors.brightPurple,
|
||||
scrim: AlucardColors.foreground,
|
||||
shadow: AlucardColors.comment,
|
||||
);
|
||||
|
||||
final ThemeData alucardLightTheme = buildAppTheme(
|
||||
colorScheme: _alucardColorScheme,
|
||||
appColors: const AppColorExtension(
|
||||
success: AlucardColors.green,
|
||||
onSuccess: AlucardColors.background,
|
||||
warning: AlucardColors.orange,
|
||||
onWarning: AlucardColors.background,
|
||||
info: AlucardColors.cyan,
|
||||
onInfo: AlucardColors.background,
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,92 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'theme_builder.dart';
|
||||
|
||||
abstract final class CatppuccinLatteColors {
|
||||
static const Color crust = Color(0xFFdce0e8);
|
||||
static const Color mantle = Color(0xFFe6e9ef);
|
||||
static const Color base = Color(0xFFeff1f5);
|
||||
static const Color surface0 = Color(0xFFccd0da);
|
||||
static const Color surface1 = Color(0xFFbcc0cc);
|
||||
static const Color surface2 = Color(0xFFacb0be);
|
||||
static const Color overlay0 = Color(0xFF9ca0b0);
|
||||
static const Color overlay1 = Color(0xFF8c8fa1);
|
||||
static const Color overlay2 = Color(0xFF7c7f93);
|
||||
static const Color subtext0 = Color(0xFF6c6f85);
|
||||
static const Color subtext1 = Color(0xFF5c5f77);
|
||||
static const Color text = Color(0xFF4c4f69);
|
||||
|
||||
static const Color rosewater = Color(0xFFdc8a78);
|
||||
static const Color flamingo = Color(0xFFdd7878);
|
||||
static const Color pink = Color(0xFFea76cb);
|
||||
static const Color mauve = Color(0xFF8839ef);
|
||||
static const Color red = Color(0xFFd20f39);
|
||||
static const Color maroon = Color(0xFFe64553);
|
||||
static const Color peach = Color(0xFFfe640b);
|
||||
static const Color yellow = Color(0xFFdf8e1d);
|
||||
static const Color green = Color(0xFF40a02b);
|
||||
static const Color teal = Color(0xFF179299);
|
||||
static const Color sky = Color(0xFF04a5e5);
|
||||
static const Color sapphire = Color(0xFF209fb5);
|
||||
static const Color blue = Color(0xFF1e66f5);
|
||||
static const Color lavender = Color(0xFF7287fd);
|
||||
}
|
||||
|
||||
const ColorScheme _catppuccinLatteColorScheme = ColorScheme(
|
||||
brightness: Brightness.light,
|
||||
|
||||
// Surfaces — AppBar (darkest) → NavRail → body (lightest)
|
||||
surface: CatppuccinLatteColors.base,
|
||||
surfaceContainerLowest: CatppuccinLatteColors.crust,
|
||||
surfaceContainerLow: CatppuccinLatteColors.mantle,
|
||||
surfaceContainer: CatppuccinLatteColors.surface0,
|
||||
surfaceContainerHigh: CatppuccinLatteColors.surface1,
|
||||
surfaceContainerHighest: CatppuccinLatteColors.surface2,
|
||||
onSurface: CatppuccinLatteColors.text,
|
||||
onSurfaceVariant: CatppuccinLatteColors.subtext1,
|
||||
outline: CatppuccinLatteColors.overlay1,
|
||||
outlineVariant: CatppuccinLatteColors.overlay0,
|
||||
|
||||
// Primary — Save button, selected nav indicators
|
||||
primary: CatppuccinLatteColors.mauve,
|
||||
onPrimary: CatppuccinLatteColors.base,
|
||||
primaryContainer: CatppuccinLatteColors.surface0,
|
||||
onPrimaryContainer: CatppuccinLatteColors.text,
|
||||
|
||||
// Secondary — Test button (not-passing state)
|
||||
secondary: CatppuccinLatteColors.blue,
|
||||
onSecondary: CatppuccinLatteColors.base,
|
||||
secondaryContainer: CatppuccinLatteColors.surface1,
|
||||
onSecondaryContainer: CatppuccinLatteColors.text,
|
||||
|
||||
// Tertiary — swipe-to-unread background
|
||||
tertiary: CatppuccinLatteColors.teal,
|
||||
onTertiary: CatppuccinLatteColors.base,
|
||||
tertiaryContainer: CatppuccinLatteColors.surface0,
|
||||
onTertiaryContainer: CatppuccinLatteColors.text,
|
||||
|
||||
// Error
|
||||
error: CatppuccinLatteColors.red,
|
||||
onError: CatppuccinLatteColors.base,
|
||||
errorContainer: CatppuccinLatteColors.maroon,
|
||||
onErrorContainer: CatppuccinLatteColors.base,
|
||||
|
||||
// Inverse / scrim
|
||||
inverseSurface: CatppuccinLatteColors.text,
|
||||
onInverseSurface: CatppuccinLatteColors.base,
|
||||
inversePrimary: CatppuccinLatteColors.mauve,
|
||||
scrim: CatppuccinLatteColors.crust,
|
||||
shadow: CatppuccinLatteColors.text,
|
||||
);
|
||||
|
||||
final ThemeData catppuccinLatteLightTheme = buildAppTheme(
|
||||
colorScheme: _catppuccinLatteColorScheme,
|
||||
appColors: const AppColorExtension(
|
||||
success: CatppuccinLatteColors.green,
|
||||
onSuccess: CatppuccinLatteColors.base,
|
||||
warning: CatppuccinLatteColors.peach,
|
||||
onWarning: CatppuccinLatteColors.base,
|
||||
info: CatppuccinLatteColors.blue,
|
||||
onInfo: CatppuccinLatteColors.base,
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'theme_builder.dart';
|
||||
|
||||
abstract final class DraculaColors {
|
||||
// Neutral ramp (darkest → lightest). "black" and "currentLine" come from the
|
||||
// official palette; the intermediate elevated surfaces are interpolated.
|
||||
static const Color blacker = Color(0xFF1b1c24);
|
||||
static const Color black = Color(0xFF21222c);
|
||||
static const Color background = Color(0xFF282a36);
|
||||
static const Color elevated = Color(0xFF343746);
|
||||
static const Color currentLine = Color(0xFF44475a);
|
||||
static const Color overlay = Color(0xFF565872);
|
||||
static const Color comment = Color(0xFF6272a4);
|
||||
static const Color subtleForeground = Color(0xFFb8bbd0);
|
||||
static const Color foreground = Color(0xFFf8f8f2);
|
||||
|
||||
static const Color cyan = Color(0xFF8be9fd);
|
||||
static const Color green = Color(0xFF50fa7b);
|
||||
static const Color orange = Color(0xFFffb86c);
|
||||
static const Color pink = Color(0xFFff79c6);
|
||||
static const Color purple = Color(0xFFbd93f9);
|
||||
static const Color red = Color(0xFFff5555);
|
||||
static const Color brightRed = Color(0xFFff6e6e);
|
||||
static const Color yellow = Color(0xFFf1fa8c);
|
||||
}
|
||||
|
||||
const ColorScheme _draculaColorScheme = ColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
|
||||
// Surfaces — AppBar (darkest) → NavRail → body (lightest)
|
||||
surface: DraculaColors.background,
|
||||
surfaceContainerLowest: DraculaColors.blacker,
|
||||
surfaceContainerLow: DraculaColors.black,
|
||||
surfaceContainer: DraculaColors.elevated,
|
||||
surfaceContainerHigh: DraculaColors.currentLine,
|
||||
surfaceContainerHighest: DraculaColors.overlay,
|
||||
onSurface: DraculaColors.foreground,
|
||||
onSurfaceVariant: DraculaColors.subtleForeground,
|
||||
outline: DraculaColors.comment,
|
||||
outlineVariant: DraculaColors.currentLine,
|
||||
|
||||
// Primary — Save button, selected nav indicators
|
||||
primary: DraculaColors.purple,
|
||||
onPrimary: DraculaColors.background,
|
||||
primaryContainer: DraculaColors.currentLine,
|
||||
onPrimaryContainer: DraculaColors.foreground,
|
||||
|
||||
// Secondary — Test button (not-passing state)
|
||||
secondary: DraculaColors.cyan,
|
||||
onSecondary: DraculaColors.background,
|
||||
secondaryContainer: DraculaColors.elevated,
|
||||
onSecondaryContainer: DraculaColors.foreground,
|
||||
|
||||
// Tertiary — swipe-to-unread background
|
||||
tertiary: DraculaColors.pink,
|
||||
onTertiary: DraculaColors.background,
|
||||
tertiaryContainer: DraculaColors.currentLine,
|
||||
onTertiaryContainer: DraculaColors.foreground,
|
||||
|
||||
// Error
|
||||
error: DraculaColors.red,
|
||||
onError: DraculaColors.background,
|
||||
errorContainer: DraculaColors.brightRed,
|
||||
onErrorContainer: DraculaColors.background,
|
||||
|
||||
// Inverse / scrim
|
||||
inverseSurface: DraculaColors.foreground,
|
||||
onInverseSurface: DraculaColors.background,
|
||||
inversePrimary: DraculaColors.purple,
|
||||
scrim: DraculaColors.black,
|
||||
shadow: DraculaColors.black,
|
||||
);
|
||||
|
||||
final ThemeData draculaDarkTheme = buildAppTheme(
|
||||
colorScheme: _draculaColorScheme,
|
||||
appColors: const AppColorExtension(
|
||||
success: DraculaColors.green,
|
||||
onSuccess: DraculaColors.background,
|
||||
warning: DraculaColors.orange,
|
||||
onWarning: DraculaColors.background,
|
||||
info: DraculaColors.cyan,
|
||||
onInfo: DraculaColors.background,
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,91 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'theme_builder.dart';
|
||||
|
||||
abstract final class NordColors {
|
||||
// Polar Night (nord0–nord3). nord0Dark is interpolated below nord0 to give
|
||||
// the AppBar a slightly deeper shade than the body.
|
||||
static const Color nord0Dark = Color(0xFF2b303b);
|
||||
static const Color nord0 = Color(0xFF2e3440);
|
||||
static const Color nord0Soft = Color(0xFF353c4a);
|
||||
static const Color nord1 = Color(0xFF3b4252);
|
||||
static const Color nord2 = Color(0xFF434c5e);
|
||||
static const Color nord3 = Color(0xFF4c566a);
|
||||
|
||||
// Snow Storm (nord4–nord6)
|
||||
static const Color nord4 = Color(0xFFd8dee9);
|
||||
static const Color nord5 = Color(0xFFe5e9f0);
|
||||
static const Color nord6 = Color(0xFFeceff4);
|
||||
|
||||
// Frost (nord7–nord10)
|
||||
static const Color nord7 = Color(0xFF8fbcbb);
|
||||
static const Color nord8 = Color(0xFF88c0d0);
|
||||
static const Color nord9 = Color(0xFF81a1c1);
|
||||
static const Color nord10 = Color(0xFF5e81ac);
|
||||
|
||||
// Aurora (nord11–nord15)
|
||||
static const Color nord11 = Color(0xFFbf616a);
|
||||
static const Color nord12 = Color(0xFFd08770);
|
||||
static const Color nord13 = Color(0xFFebcb8b);
|
||||
static const Color nord14 = Color(0xFFa3be8c);
|
||||
static const Color nord15 = Color(0xFFb48ead);
|
||||
}
|
||||
|
||||
const ColorScheme _nordColorScheme = ColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
|
||||
// Surfaces — AppBar (darkest) → NavRail → body (lightest)
|
||||
surface: NordColors.nord0,
|
||||
surfaceContainerLowest: NordColors.nord0Dark,
|
||||
surfaceContainerLow: NordColors.nord0Soft,
|
||||
surfaceContainer: NordColors.nord1,
|
||||
surfaceContainerHigh: NordColors.nord2,
|
||||
surfaceContainerHighest: NordColors.nord3,
|
||||
onSurface: NordColors.nord6,
|
||||
onSurfaceVariant: NordColors.nord4,
|
||||
outline: NordColors.nord3,
|
||||
outlineVariant: NordColors.nord2,
|
||||
|
||||
// Primary — Save button, selected nav indicators
|
||||
primary: NordColors.nord8,
|
||||
onPrimary: NordColors.nord0,
|
||||
primaryContainer: NordColors.nord1,
|
||||
onPrimaryContainer: NordColors.nord6,
|
||||
|
||||
// Secondary — Test button (not-passing state)
|
||||
secondary: NordColors.nord9,
|
||||
onSecondary: NordColors.nord0,
|
||||
secondaryContainer: NordColors.nord2,
|
||||
onSecondaryContainer: NordColors.nord6,
|
||||
|
||||
// Tertiary — swipe-to-unread background
|
||||
tertiary: NordColors.nord7,
|
||||
onTertiary: NordColors.nord0,
|
||||
tertiaryContainer: NordColors.nord1,
|
||||
onTertiaryContainer: NordColors.nord6,
|
||||
|
||||
// Error
|
||||
error: NordColors.nord11,
|
||||
onError: NordColors.nord6,
|
||||
errorContainer: NordColors.nord11,
|
||||
onErrorContainer: NordColors.nord0,
|
||||
|
||||
// Inverse / scrim
|
||||
inverseSurface: NordColors.nord6,
|
||||
onInverseSurface: NordColors.nord0,
|
||||
inversePrimary: NordColors.nord10,
|
||||
scrim: NordColors.nord0Dark,
|
||||
shadow: NordColors.nord0Dark,
|
||||
);
|
||||
|
||||
final ThemeData nordDarkTheme = buildAppTheme(
|
||||
colorScheme: _nordColorScheme,
|
||||
appColors: const AppColorExtension(
|
||||
success: NordColors.nord14,
|
||||
onSuccess: NordColors.nord0,
|
||||
warning: NordColors.nord13,
|
||||
onWarning: NordColors.nord0,
|
||||
info: NordColors.nord8,
|
||||
onInfo: NordColors.nord0,
|
||||
),
|
||||
);
|
||||
@@ -6,8 +6,9 @@ import 'app_colors.dart';
|
||||
/// Builds a Material 3 [ThemeData] from a [ColorScheme] and the app's custom
|
||||
/// [AppColorExtension], applying the shared OOTT typography.
|
||||
///
|
||||
/// Both bundled themes (Catppuccin Mocha, Gruvbox Dark) go through here so they
|
||||
/// stay visually consistent — only their colors differ.
|
||||
/// Every bundled theme (Catppuccin Mocha/Latte, Gruvbox Dark, Dracula, Alucard,
|
||||
/// Nord, Tokyo Night) goes through here so they stay visually consistent — only
|
||||
/// their colors differ.
|
||||
ThemeData buildAppTheme({
|
||||
required ColorScheme colorScheme,
|
||||
required AppColorExtension appColors,
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'app_colors.dart';
|
||||
import 'theme_builder.dart';
|
||||
|
||||
/// Tokyo Night (the "Night" variant).
|
||||
abstract final class TokyoNightColors {
|
||||
static const Color bgDarker = Color(0xFF0c0e14);
|
||||
static const Color bgDark = Color(0xFF16161e);
|
||||
static const Color bg = Color(0xFF1a1b26);
|
||||
static const Color bgSoft = Color(0xFF1b1e2d);
|
||||
static const Color bgElevated = Color(0xFF24283b);
|
||||
static const Color bgHighlight = Color(0xFF292e42);
|
||||
static const Color fgGutter = Color(0xFF3b4261);
|
||||
static const Color terminalBlack = Color(0xFF414868);
|
||||
static const Color comment = Color(0xFF565f89);
|
||||
static const Color fgDark = Color(0xFFa9b1d6);
|
||||
static const Color fg = Color(0xFFc0caf5);
|
||||
|
||||
static const Color blue = Color(0xFF7aa2f7);
|
||||
static const Color cyan = Color(0xFF7dcfff);
|
||||
static const Color teal = Color(0xFF73daca);
|
||||
static const Color green = Color(0xFF9ece6a);
|
||||
static const Color magenta = Color(0xFFbb9af7);
|
||||
static const Color purple = Color(0xFF9d7cd8);
|
||||
static const Color orange = Color(0xFFff9e64);
|
||||
static const Color yellow = Color(0xFFe0af68);
|
||||
static const Color red = Color(0xFFf7768e);
|
||||
static const Color brightRed = Color(0xFFdb4b4b);
|
||||
}
|
||||
|
||||
const ColorScheme _tokyoNightColorScheme = ColorScheme(
|
||||
brightness: Brightness.dark,
|
||||
|
||||
// Surfaces — AppBar (darkest) → NavRail → body (lightest)
|
||||
surface: TokyoNightColors.bg,
|
||||
surfaceContainerLowest: TokyoNightColors.bgDark,
|
||||
surfaceContainerLow: TokyoNightColors.bgSoft,
|
||||
surfaceContainer: TokyoNightColors.bgElevated,
|
||||
surfaceContainerHigh: TokyoNightColors.bgHighlight,
|
||||
surfaceContainerHighest: TokyoNightColors.fgGutter,
|
||||
onSurface: TokyoNightColors.fg,
|
||||
onSurfaceVariant: TokyoNightColors.fgDark,
|
||||
outline: TokyoNightColors.comment,
|
||||
outlineVariant: TokyoNightColors.terminalBlack,
|
||||
|
||||
// Primary — Save button, selected nav indicators
|
||||
primary: TokyoNightColors.blue,
|
||||
onPrimary: TokyoNightColors.bgDark,
|
||||
primaryContainer: TokyoNightColors.bgHighlight,
|
||||
onPrimaryContainer: TokyoNightColors.fg,
|
||||
|
||||
// Secondary — Test button (not-passing state)
|
||||
secondary: TokyoNightColors.magenta,
|
||||
onSecondary: TokyoNightColors.bgDark,
|
||||
secondaryContainer: TokyoNightColors.fgGutter,
|
||||
onSecondaryContainer: TokyoNightColors.fg,
|
||||
|
||||
// Tertiary — swipe-to-unread background
|
||||
tertiary: TokyoNightColors.teal,
|
||||
onTertiary: TokyoNightColors.bgDark,
|
||||
tertiaryContainer: TokyoNightColors.bgElevated,
|
||||
onTertiaryContainer: TokyoNightColors.fg,
|
||||
|
||||
// Error
|
||||
error: TokyoNightColors.red,
|
||||
onError: TokyoNightColors.bgDark,
|
||||
errorContainer: TokyoNightColors.brightRed,
|
||||
onErrorContainer: TokyoNightColors.fg,
|
||||
|
||||
// Inverse / scrim
|
||||
inverseSurface: TokyoNightColors.fg,
|
||||
onInverseSurface: TokyoNightColors.bgDark,
|
||||
inversePrimary: TokyoNightColors.blue,
|
||||
scrim: TokyoNightColors.bgDarker,
|
||||
shadow: TokyoNightColors.bgDarker,
|
||||
);
|
||||
|
||||
final ThemeData tokyoNightDarkTheme = buildAppTheme(
|
||||
colorScheme: _tokyoNightColorScheme,
|
||||
appColors: const AppColorExtension(
|
||||
success: TokyoNightColors.green,
|
||||
onSuccess: TokyoNightColors.bgDark,
|
||||
warning: TokyoNightColors.yellow,
|
||||
onWarning: TokyoNightColors.bgDark,
|
||||
info: TokyoNightColors.blue,
|
||||
onInfo: TokyoNightColors.bgDark,
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user