Skip to main content

standout_render/theme/
mod.rs

1//! Adaptive themes with automatic light/dark mode support.
2//!
3//! Themes are named collections of styles that automatically adapt to the user's
4//! OS color scheme. Unlike systems with separate "light theme" and "dark theme"
5//! files, Standout's themes define mode-specific variations at the style level,
6//! eliminating duplication for styles that don't change between modes.
7//!
8//! ## Design Decision: Style-Level Adaptation
9//!
10//! Most styles (bold, italic, semantic colors) look fine in both modes. Only a
11//! handful need adjustment — typically foreground colors for contrast. By making
12//! adaptation per-style rather than per-theme, you define shared styles once and
13//! override only what differs:
14//!
15//! ```yaml
16//! # Shared across all modes
17//! header:
18//!   fg: cyan
19//!   bold: true
20//!
21//! # Mode-specific overrides
22//! panel:
23//!   fg: gray          # Base (fallback)
24//!   light:
25//!     fg: black       # Override for light mode
26//!   dark:
27//!     fg: white       # Override for dark mode
28//! ```
29//!
30//! ## How Merging Works
31//!
32//! When resolving a style in Dark mode:
33//! 1. Start with base attributes (`fg: gray`)
34//! 2. Merge dark overrides — each attribute in `dark:` replaces the base
35//! 3. Result: `fg: white` (from dark), other attributes preserved from base
36//!
37//! This is additive: `Some` values in overrides replace, missing values preserve base.
38//!
39//! ## Color Mode Detection
40//!
41//! [`detect_color_mode`] queries the OS for the user's preferred scheme. Override
42//! it for testing with [`set_theme_detector`]:
43//!
44//! ```rust,ignore
45//! standout::set_theme_detector(|| ColorMode::Dark);
46//! ```
47//!
48//! ## Construction
49//!
50//! Programmatic (for compile-time themes):
51//! ```rust
52//! use standout::Theme;
53//! use console::Style;
54//!
55//! let theme = Theme::new()
56//!     .add("header", Style::new().bold().cyan())
57//!     .add_adaptive("panel", Style::new(),
58//!         Some(Style::new().fg(console::Color::Black)),
59//!         Some(Style::new().fg(console::Color::White)));
60//! ```
61//!
62//! YAML (for user-customizable themes):
63//! ```rust
64//! let theme = standout::Theme::from_yaml(r#"
65//! header: { fg: cyan, bold: true }
66//! panel:
67//!   fg: gray
68//!   light: { fg: black }
69//!   dark: { fg: white }
70//! "#).unwrap();
71//! ```
72//!
73//! ## See Also
74//!
75//! - [`crate::stylesheet`]: YAML parsing details and color format reference
76//! - [`crate::style`]: Low-level style primitives and aliasing
77
78mod adaptive;
79#[allow(clippy::module_inception)]
80mod theme;
81
82pub use adaptive::{detect_color_mode, set_theme_detector, ColorMode};
83pub use theme::Theme;