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