1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139//! Color palette matching the OpenFang landing page design system.
//!
//! Core palette from globals.css + code syntax from constants.ts.
#![allow(dead_code)] // Full palette โ some colors reserved for future screens.
use ratatui::style::{Color, Modifier, Style};
// โโ Core Palette (dark mode for terminal) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub const ACCENT: Color = Color::Rgb(255, 92, 0); // #FF5C00 โ OpenFang orange
pub const ACCENT_DIM: Color = Color::Rgb(224, 82, 0); // #E05200
pub const BG_PRIMARY: Color = Color::Rgb(15, 14, 14); // #0F0E0E โ dark background
pub const BG_CARD: Color = Color::Rgb(31, 29, 28); // #1F1D1C โ dark surface
pub const BG_HOVER: Color = Color::Rgb(42, 39, 37); // #2A2725 โ dark hover
pub const BG_CODE: Color = Color::Rgb(24, 22, 21); // #181615 โ dark code block
pub const TEXT_PRIMARY: Color = Color::Rgb(240, 239, 238); // #F0EFEE โ light text on dark bg
pub const TEXT_SECONDARY: Color = Color::Rgb(168, 162, 158); // #A8A29E โ muted text
pub const TEXT_TERTIARY: Color = Color::Rgb(120, 113, 108); // #78716C โ dim text
pub const BORDER: Color = Color::Rgb(63, 59, 56); // #3F3B38 โ dark border
// โโ Semantic Colors (brighter variants for dark background contrast) โโโโโโโโ
pub const GREEN: Color = Color::Rgb(34, 197, 94); // #22C55E โ success
pub const BLUE: Color = Color::Rgb(59, 130, 246); // #3B82F6 โ info
pub const YELLOW: Color = Color::Rgb(234, 179, 8); // #EAB308 โ warning
pub const RED: Color = Color::Rgb(239, 68, 68); // #EF4444 โ error
pub const PURPLE: Color = Color::Rgb(168, 85, 247); // #A855F7 โ decorators
// โโ Backward-compat aliases โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub const CYAN: Color = BLUE;
pub const DIM: Color = TEXT_SECONDARY;
// โโ Reusable styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub fn title_style() -> Style {
Style::default().fg(ACCENT).add_modifier(Modifier::BOLD)
}
pub fn selected_style() -> Style {
Style::default().fg(ACCENT).bg(BG_HOVER)
}
pub fn dim_style() -> Style {
Style::default().fg(TEXT_SECONDARY)
}
pub fn input_style() -> Style {
Style::default().fg(ACCENT).add_modifier(Modifier::BOLD)
}
pub fn hint_style() -> Style {
Style::default().fg(TEXT_TERTIARY)
}
// โโ Tab bar styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub fn tab_active() -> Style {
Style::default()
.fg(Color::White)
.bg(ACCENT)
.add_modifier(Modifier::BOLD)
}
pub fn tab_inactive() -> Style {
Style::default().fg(TEXT_SECONDARY)
}
// โโ State badge styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub fn badge_running() -> Style {
Style::default().fg(GREEN).add_modifier(Modifier::BOLD)
}
pub fn badge_created() -> Style {
Style::default().fg(BLUE).add_modifier(Modifier::BOLD)
}
pub fn badge_suspended() -> Style {
Style::default().fg(YELLOW).add_modifier(Modifier::BOLD)
}
pub fn badge_terminated() -> Style {
Style::default().fg(TEXT_TERTIARY)
}
pub fn badge_crashed() -> Style {
Style::default().fg(RED).add_modifier(Modifier::BOLD)
}
/// Return badge text + style for an agent state string.
pub fn state_badge(state: &str) -> (&'static str, Style) {
let lower = state.to_lowercase();
if lower.contains("run") {
("[RUN]", badge_running())
} else if lower.contains("creat") || lower.contains("new") || lower.contains("idle") {
("[NEW]", badge_created())
} else if lower.contains("sus") || lower.contains("paus") {
("[SUS]", badge_suspended())
} else if lower.contains("term") || lower.contains("stop") || lower.contains("end") {
("[END]", badge_terminated())
} else if lower.contains("err") || lower.contains("crash") || lower.contains("fail") {
("[ERR]", badge_crashed())
} else {
("[---]", dim_style())
}
}
// โโ Table / channel styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub fn table_header() -> Style {
Style::default()
.fg(ACCENT)
.add_modifier(Modifier::BOLD | Modifier::UNDERLINED)
}
pub fn channel_ready() -> Style {
Style::default().fg(GREEN).add_modifier(Modifier::BOLD)
}
pub fn channel_missing() -> Style {
Style::default().fg(YELLOW)
}
pub fn channel_off() -> Style {
dim_style()
}
// โโ Spinner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
pub const SPINNER_FRAMES: &[&str] = &[
"\u{280b}", "\u{2819}", "\u{2839}", "\u{2838}", "\u{283c}", "\u{2834}", "\u{2826}", "\u{2827}",
"\u{2807}", "\u{280f}",
];