systemprompt_logging/services/cli/
theme.rs1use console::{style, Emoji, StyledObject};
2
3pub use super::types::{
4 ActionType, ColorType, EmphasisType, IconType, ItemStatus, MessageLevel, ModuleType,
5};
6
7#[derive(Debug, Copy, Clone)]
8pub struct BrandColors;
9
10impl BrandColors {
11 pub fn primary<D: std::fmt::Display>(text: D) -> StyledObject<D> {
12 style(text).color256(208)
13 }
14
15 pub fn primary_bold<D: std::fmt::Display>(text: D) -> StyledObject<D> {
16 style(text).color256(208).bold()
17 }
18
19 pub fn white_bold<D: std::fmt::Display>(text: D) -> StyledObject<D> {
20 style(text).white().bold()
21 }
22
23 pub fn white<D: std::fmt::Display>(text: D) -> StyledObject<D> {
24 style(text).white()
25 }
26
27 pub fn dim<D: std::fmt::Display>(text: D) -> StyledObject<D> {
28 style(text).dim()
29 }
30
31 pub fn highlight<D: std::fmt::Display>(text: D) -> StyledObject<D> {
32 style(text).cyan()
33 }
34
35 pub fn running<D: std::fmt::Display>(text: D) -> StyledObject<D> {
36 style(text).green()
37 }
38
39 pub fn stopped<D: std::fmt::Display>(text: D) -> StyledObject<D> {
40 style(text).red()
41 }
42
43 pub fn starting<D: std::fmt::Display>(text: D) -> StyledObject<D> {
44 style(text).yellow()
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum ServiceStatus {
50 Running,
51 Stopped,
52 Starting,
53 Failed,
54 Unknown,
55}
56
57impl ServiceStatus {
58 pub const fn symbol(&self) -> &'static str {
59 match self {
60 Self::Running => "●",
61 Self::Stopped => "○",
62 Self::Starting => "◐",
63 Self::Failed => "✗",
64 Self::Unknown => "?",
65 }
66 }
67
68 pub const fn text(&self) -> &'static str {
69 match self {
70 Self::Running => "Running",
71 Self::Stopped => "Stopped",
72 Self::Starting => "Starting",
73 Self::Failed => "Failed",
74 Self::Unknown => "Unknown",
75 }
76 }
77}
78
79#[derive(Debug, Copy, Clone)]
80pub struct Icons;
81
82impl Icons {
83 pub const CHECKMARK: Emoji<'static, 'static> = Emoji("✓", "✓");
84 pub const WARNING: Emoji<'static, 'static> = Emoji("⚠", "!");
85 pub const ERROR: Emoji<'static, 'static> = Emoji("✗", "X");
86 pub const INFO: Emoji<'static, 'static> = Emoji("ℹ", "i");
87
88 pub const PACKAGE: Emoji<'static, 'static> = Emoji("📦", "[MOD]");
89 pub const SCHEMA: Emoji<'static, 'static> = Emoji("📄", "[SCHEMA]");
90 pub const SEED: Emoji<'static, 'static> = Emoji("🌱", "[SEED]");
91 pub const CONFIG: Emoji<'static, 'static> = Emoji("⚙", "[CONFIG]");
92
93 pub const ARROW: Emoji<'static, 'static> = Emoji("→", "->");
94 pub const UPDATE: Emoji<'static, 'static> = Emoji("🔄", "[UPDATE]");
95 pub const INSTALL: Emoji<'static, 'static> = Emoji("📥", "[INSTALL]");
96 pub const PAUSE: Emoji<'static, 'static> = Emoji("⏸", "[PAUSED]");
97
98 pub const fn for_module_type(module_type: ModuleType) -> Emoji<'static, 'static> {
99 match module_type {
100 ModuleType::Schema => Self::SCHEMA,
101 ModuleType::Seed => Self::SEED,
102 ModuleType::Module => Self::PACKAGE,
103 ModuleType::Configuration => Self::CONFIG,
104 }
105 }
106
107 pub const fn for_status(status: ItemStatus) -> Emoji<'static, 'static> {
108 match status {
109 ItemStatus::Valid | ItemStatus::Applied => Self::CHECKMARK,
110 ItemStatus::Missing | ItemStatus::Pending => Self::WARNING,
111 ItemStatus::Failed => Self::ERROR,
112 ItemStatus::Disabled => Self::PAUSE,
113 }
114 }
115
116 pub const fn for_message_level(level: MessageLevel) -> Emoji<'static, 'static> {
117 match level {
118 MessageLevel::Success => Self::CHECKMARK,
119 MessageLevel::Warning => Self::WARNING,
120 MessageLevel::Error => Self::ERROR,
121 MessageLevel::Info => Self::INFO,
122 }
123 }
124}
125
126#[derive(Debug, Copy, Clone)]
127pub struct Colors;
128
129impl Colors {
130 pub fn success<D: std::fmt::Display>(text: D) -> StyledObject<D> {
131 style(text).green()
132 }
133
134 pub fn warning<D: std::fmt::Display>(text: D) -> StyledObject<D> {
135 style(text).yellow()
136 }
137
138 pub fn error<D: std::fmt::Display>(text: D) -> StyledObject<D> {
139 style(text).red()
140 }
141
142 pub fn info<D: std::fmt::Display>(text: D) -> StyledObject<D> {
143 style(text).cyan()
144 }
145
146 pub fn highlight<D: std::fmt::Display>(text: D) -> StyledObject<D> {
147 style(text).bold().cyan()
148 }
149
150 pub fn dim<D: std::fmt::Display>(text: D) -> StyledObject<D> {
151 style(text).dim()
152 }
153
154 pub fn bold<D: std::fmt::Display>(text: D) -> StyledObject<D> {
155 style(text).bold()
156 }
157
158 pub fn underlined<D: std::fmt::Display>(text: D) -> StyledObject<D> {
159 style(text).bold().underlined()
160 }
161
162 pub fn for_status<D: std::fmt::Display>(text: D, status: ItemStatus) -> StyledObject<D> {
163 match status {
164 ItemStatus::Valid | ItemStatus::Applied => Self::success(text),
165 ItemStatus::Missing | ItemStatus::Pending => Self::warning(text),
166 ItemStatus::Failed => Self::error(text),
167 ItemStatus::Disabled => Self::dim(text),
168 }
169 }
170
171 pub fn for_message_level<D: std::fmt::Display>(
172 text: D,
173 level: MessageLevel,
174 ) -> StyledObject<D> {
175 match level {
176 MessageLevel::Success => Self::success(text),
177 MessageLevel::Warning => Self::warning(text),
178 MessageLevel::Error => Self::error(text),
179 MessageLevel::Info => Self::info(text),
180 }
181 }
182}
183
184#[derive(Debug, Clone, Copy)]
185pub struct Theme;
186
187impl Theme {
188 pub fn icon(icon_type: impl Into<IconType>) -> Emoji<'static, 'static> {
189 match icon_type.into() {
190 IconType::Status(status) => Icons::for_status(status),
191 IconType::Module(module_type) => Icons::for_module_type(module_type),
192 IconType::Message(level) => Icons::for_message_level(level),
193 IconType::Action(action) => match action {
194 ActionType::Install => Icons::INSTALL,
195 ActionType::Update => Icons::UPDATE,
196 ActionType::Arrow => Icons::ARROW,
197 },
198 }
199 }
200
201 pub fn color<D: std::fmt::Display>(
202 text: D,
203 color_type: impl Into<ColorType>,
204 ) -> StyledObject<D> {
205 match color_type.into() {
206 ColorType::Status(status) => Colors::for_status(text, status),
207 ColorType::Message(level) => Colors::for_message_level(text, level),
208 ColorType::Emphasis(emphasis) => match emphasis {
209 EmphasisType::Highlight => Colors::highlight(text),
210 EmphasisType::Dim => Colors::dim(text),
211 EmphasisType::Bold => Colors::bold(text),
212 EmphasisType::Underlined => Colors::underlined(text),
213 },
214 }
215 }
216}