Skip to content

Commit e47e6df

Browse files
daschwaome510
andauthored
More flexible theme config (#118)
Make theme config more flexible so - it is possible to only set some of the component styles in theme.toml - it is possible to not set the palette in theme.toml (and just modify component styles) - it is possible to set the border style with the new component_style attribute border - it is possible to set the style of the current selection with the new component_style selection Co-authored-by: Thang Pham <[email protected]>
1 parent df71e3c commit e47e6df

File tree

8 files changed

+157
-90
lines changed

8 files changed

+157
-90
lines changed

docs/config.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ The application's theme can be modified by setting the `theme` option in `app.to
8989

9090
A theme has three main components: `name` (the theme's name), `palette` (the theme's color palette), `component_style` (a list of pre-defined styles for application's components).
9191

92-
`name` and `palette` are required when defining a new theme. If `component_style` is not specified, a default value will be used.
92+
`name` is required when defining a new theme. If `palette` is not set, a palette based on the terminal's colorscheme will be used. If `component_style` is not specified, a default value will be used.
9393

9494
An example of user-defined themes can be found in the example [`theme.toml`](../examples/theme.toml) file
9595

@@ -133,30 +133,34 @@ If specified, a field's value must be set to be a hex representation of a RGB co
133133

134134
### Component Styles
135135

136-
To define application's component styles, user needs to specify **all of the below fields**:
136+
To define application's component styles, the user can specify any of the below fields:
137137

138138
- `block_title`
139+
- `border`
139140
- `playback_track`
140141
- `playback_album`
141142
- `playback_metadata`
142143
- `playback_progress_bar`
143144
- `current_playing`
144145
- `page_desc`
145146
- `table_header`
147+
- `selection`
146148

147-
A field in the component styles is a `Style` struct which has three optional fields: `fg`, `bg` and `modifiers`. `fg` and `bg` can be either a palette's color (string in pascal case) or a custom RGB color using the following format: `fg = { Rgb { r = ..., g = ..., b = ... } }`. `modifiers` can only be either `Italic` or `Bold`.
149+
A field in the component styles is a `Style` struct which has three optional fields: `fg`, `bg` and `modifiers`. `fg` and `bg` can be either a palette's color (string in pascal case) or a custom RGB color using the following format: `fg = { Rgb { r = ..., g = ..., b = ... } }`. The default values for `fg` and `bg` are the `palette`'s `fg` and `bg`. `modifiers` can only be `Italic`, `Bold` or `Reversed`.
148150

149151
Default value for application's component styles:
150152

151153
```toml
152154
block_title = { fg = "Magenta" }
155+
border = {}
153156
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
154157
playback_album = { fg = "Yellow" }
155158
playback_metadata = { fg = "BrightBlack" }
156159
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
157160
current_playing = { fg = "Green", modifiers = ["Bold"] }
158161
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
159162
table_header = { fg = "Blue" }
163+
selection = { modifiers = ["Bold", "Reversed"] }
160164
```
161165

162166
## Keymaps

examples/theme.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ bright_cyan = "#8be9fd"
2121
bright_white = "#ffffff"
2222
[themes.component_style]
2323
block_title = { fg = "Magenta" }
24+
border = {}
2425
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
2526
playback_album = { fg = "Yellow" }
2627
playback_metadata = { fg = "BrightBlack" }
2728
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
2829
current_playing = { fg = "Green", modifiers = ["Bold"] }
2930
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
3031
table_header = { fg = "Blue" }
32+
selection = { modifiers = ["Bold", "Reversed"] }
3133

3234
[[themes]]
3335
name = "gruvbox_dark"
@@ -52,13 +54,15 @@ bright_cyan = "#8ec07c"
5254
bright_white = "#ebdbb2"
5355
[themes.component_style]
5456
block_title = { fg = "Magenta" }
57+
border = {}
5558
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
5659
playback_album = { fg = "Yellow" }
5760
playback_metadata = { fg = "BrightBlack" }
5861
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
5962
current_playing = { fg = "Green", modifiers = ["Bold"] }
6063
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
6164
table_header = { fg = "Blue" }
65+
selection = { modifiers = ["Bold", "Reversed"] }
6266

6367
[[themes]]
6468
name = "gruvbox_light"
@@ -83,13 +87,15 @@ bright_cyan = "#689d69"
8387
bright_white = "#7c6f64"
8488
[themes.component_style]
8589
block_title = { fg = "Magenta" }
90+
border = {}
8691
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
8792
playback_album = { fg = "Yellow" }
8893
playback_metadata = { fg = "BrightBlack" }
8994
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
9095
current_playing = { fg = "Green", modifiers = ["Bold"] }
9196
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
9297
table_header = { fg = "Blue" }
98+
selection = { modifiers = ["Bold", "Reversed"] }
9399

94100

95101
[[themes]]
@@ -115,13 +121,15 @@ bright_cyan = "#93a1a1"
115121
bright_white = "#fdf6e3"
116122
[themes.component_style]
117123
block_title = { fg = "Magenta" }
124+
border = {}
118125
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
119126
playback_album = { fg = "Yellow" }
120127
playback_metadata = { fg = "White" }
121128
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
122129
current_playing = { fg = "Green", modifiers = ["Bold"] }
123130
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
124131
table_header = { fg = "Blue" }
132+
selection = { modifiers = ["Bold", "Reversed"] }
125133

126134
[[themes]]
127135
name = "solarized_light"
@@ -146,10 +154,12 @@ bright_cyan = "#93a1a1"
146154
bright_white = "#fdf6e3"
147155
[themes.component_style]
148156
block_title = { fg = "Magenta" }
157+
border = {}
149158
playback_track = { fg = "Cyan", modifiers = ["Bold"] }
150159
playback_album = { fg = "Yellow" }
151160
playback_metadata = { fg = "BrightBlack" }
152161
playback_progress_bar = { bg = "BrightBlack", fg = "Green" }
153162
current_playing = { fg = "Green", modifiers = ["Bold"] }
154163
page_desc = { fg = "Cyan", modifiers = ["Bold"] }
155164
table_header = { fg = "Blue" }
165+
selection = { modifiers = ["Bold", "Reversed"] }

scripts/theme_parse

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ bright_cyan = "{data["colors"]["bright"]["cyan"]}"
5151
bright_white = "{data["colors"]["bright"]["white"]}"
5252
[themes.component_style]
5353
block_title = {{ fg = "Magenta" }}
54+
border = {{}}
5455
playback_track = {{ fg = "Cyan", modifiers = ["Bold"] }}
5556
playback_album = {{ fg = "Yellow" }}
5657
playback_metadata = {{ fg = "BrightBlack" }}
5758
playback_progress_bar = {{ bg = "BrightBlack", fg = "Green" }}
5859
current_playing = {{ fg = "Green", modifiers = ["Bold"] }}
5960
page_desc = {{ fg = "Cyan", modifiers = ["Bold"] }}
6061
table_header = {{ fg = "Blue" }}
62+
selection = {{ modifiers = ["Bold", "Reversed"] }}
6163
"""
6264
)

spotify_player/src/config/theme.rs

Lines changed: 119 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub struct ThemeConfig {
1212
#[derive(Clone, Debug, Deserialize)]
1313
pub struct Theme {
1414
pub name: String,
15+
#[serde(default)]
1516
palette: Palette,
1617
#[serde(default)]
1718
component_style: ComponentStyle,
@@ -57,21 +58,18 @@ pub struct Palette {
5758
pub bright_yellow: Color,
5859
}
5960

60-
// TODO: find a way to parse ComponentStyle config options without
61-
// having to specify all the fields
62-
#[derive(Clone, Debug, Deserialize)]
61+
#[derive(Clone, Debug, Default, Deserialize)]
6362
pub struct ComponentStyle {
64-
pub block_title: Style,
65-
66-
pub playback_track: Style,
67-
pub playback_album: Style,
68-
pub playback_metadata: Style,
69-
pub playback_progress_bar: Style,
70-
71-
pub current_playing: Style,
72-
73-
pub page_desc: Style,
74-
pub table_header: Style,
63+
pub block_title: Option<Style>,
64+
pub border: Option<Style>,
65+
pub playback_track: Option<Style>,
66+
pub playback_album: Option<Style>,
67+
pub playback_metadata: Option<Style>,
68+
pub playback_progress_bar: Option<Style>,
69+
pub current_playing: Option<Style>,
70+
pub page_desc: Option<Style>,
71+
pub table_header: Option<Style>,
72+
pub selection: Option<Style>,
7573
}
7674

7775
#[derive(Default, Clone, Debug, Deserialize)]
@@ -107,23 +105,14 @@ pub enum StyleColor {
107105
pub enum StyleModifier {
108106
Bold,
109107
Italic,
108+
Reversed,
110109
}
111110

112111
#[derive(Clone, Debug)]
113112
pub struct Color {
114113
pub color: style::Color,
115114
}
116115

117-
macro_rules! impl_component_style_getters {
118-
($($f:ident),+) => {
119-
$(
120-
pub fn $f(&self) -> tui::style::Style {
121-
self.component_style.$f.style(&self.palette)
122-
}
123-
)*
124-
};
125-
}
126-
127116
impl ThemeConfig {
128117
/// finds a theme whose name matches a given `name`
129118
pub fn find_theme(&self, name: &str) -> Option<Theme> {
@@ -170,9 +159,12 @@ impl Theme {
170159

171160
pub fn selection_style(&self, is_active: bool) -> style::Style {
172161
if is_active {
173-
style::Style::default()
174-
.add_modifier(style::Modifier::REVERSED)
175-
.add_modifier(style::Modifier::BOLD)
162+
match &self.component_style.selection {
163+
None => style::Style::default()
164+
.add_modifier(style::Modifier::REVERSED)
165+
.add_modifier(style::Modifier::BOLD),
166+
Some(s) => s.style(&self.palette),
167+
}
176168
} else {
177169
style::Style::default()
178170
}
@@ -196,16 +188,84 @@ impl Theme {
196188
tui::text::Span::styled(content.into(), self.block_title())
197189
}
198190

199-
impl_component_style_getters!(
200-
block_title,
201-
playback_track,
202-
playback_album,
203-
playback_metadata,
204-
playback_progress_bar,
205-
current_playing,
206-
page_desc,
207-
table_header
208-
);
191+
pub fn block_title(&self) -> tui::style::Style {
192+
match &self.component_style.block_title {
193+
None => Style::default()
194+
.fg(StyleColor::Magenta)
195+
.style(&self.palette),
196+
Some(s) => s.style(&self.palette),
197+
}
198+
}
199+
200+
pub fn border(&self) -> tui::style::Style {
201+
match &self.component_style.border {
202+
None => Style::default().style(&self.palette),
203+
Some(s) => s.style(&self.palette),
204+
}
205+
}
206+
207+
pub fn playback_track(&self) -> tui::style::Style {
208+
match &self.component_style.playback_track {
209+
None => Style::default()
210+
.fg(StyleColor::Cyan)
211+
.modifiers(vec![StyleModifier::Bold])
212+
.style(&self.palette),
213+
Some(s) => s.style(&self.palette),
214+
}
215+
}
216+
217+
pub fn playback_album(&self) -> tui::style::Style {
218+
match &self.component_style.playback_album {
219+
None => Style::default().fg(StyleColor::Yellow).style(&self.palette),
220+
Some(s) => s.style(&self.palette),
221+
}
222+
}
223+
224+
pub fn playback_metadata(&self) -> tui::style::Style {
225+
match &self.component_style.playback_metadata {
226+
None => Style::default()
227+
.fg(StyleColor::BrightBlack)
228+
.style(&self.palette),
229+
Some(s) => s.style(&self.palette),
230+
}
231+
}
232+
233+
pub fn playback_progress_bar(&self) -> tui::style::Style {
234+
match &self.component_style.playback_metadata {
235+
None => Style::default()
236+
.bg(StyleColor::BrightBlack)
237+
.fg(StyleColor::Green)
238+
.style(&self.palette),
239+
Some(s) => s.style(&self.palette),
240+
}
241+
}
242+
243+
pub fn current_playing(&self) -> tui::style::Style {
244+
match &self.component_style.current_playing {
245+
None => Style::default()
246+
.fg(StyleColor::Green)
247+
.modifiers(vec![StyleModifier::Bold])
248+
.style(&self.palette),
249+
Some(s) => s.style(&self.palette),
250+
}
251+
}
252+
253+
pub fn page_desc(&self) -> tui::style::Style {
254+
match &self.component_style.page_desc {
255+
None => Style::default()
256+
.fg(StyleColor::Cyan)
257+
.modifiers(vec![StyleModifier::Bold])
258+
.style(&self.palette),
259+
Some(s) => s.style(&self.palette),
260+
}
261+
}
262+
263+
pub fn table_header(&self) -> tui::style::Style {
264+
match &self.component_style.table_header {
265+
None => Style::default().fg(StyleColor::Blue).style(&self.palette),
266+
Some(s) => s.style(&self.palette),
267+
}
268+
}
209269
}
210270

211271
impl Style {
@@ -268,6 +328,7 @@ impl From<StyleModifier> for style::Modifier {
268328
match m {
269329
StyleModifier::Bold => style::Modifier::BOLD,
270330
StyleModifier::Italic => style::Modifier::ITALIC,
331+
StyleModifier::Reversed => style::Modifier::REVERSED,
271332
}
272333
}
273334
}
@@ -391,54 +452,34 @@ impl Default for Theme {
391452
fn default() -> Self {
392453
Self {
393454
name: "default".to_owned(),
394-
palette: Palette {
395-
background: None,
396-
foreground: None,
397-
// the default theme uses the terminal's ANSI colors
398-
black: Color::black(),
399-
red: Color::red(),
400-
green: Color::green(),
401-
yellow: Color::yellow(),
402-
blue: Color::blue(),
403-
magenta: Color::magenta(),
404-
cyan: Color::cyan(),
405-
white: Color::white(),
406-
bright_black: Color::bright_black(),
407-
bright_red: Color::bright_red(),
408-
bright_green: Color::bright_green(),
409-
bright_yellow: Color::bright_yellow(),
410-
bright_blue: Color::bright_blue(),
411-
bright_magenta: Color::bright_magenta(),
412-
bright_cyan: Color::bright_cyan(),
413-
bright_white: Color::bright_white(),
414-
},
455+
palette: Palette::default(),
415456
component_style: ComponentStyle::default(),
416457
}
417458
}
418459
}
419460

420-
impl Default for ComponentStyle {
461+
impl Default for Palette {
421462
fn default() -> Self {
422463
Self {
423-
block_title: Style::default().fg(StyleColor::Magenta),
424-
425-
playback_track: Style::default()
426-
.fg(StyleColor::Cyan)
427-
.modifiers(vec![StyleModifier::Bold]),
428-
playback_album: Style::default().fg(StyleColor::Yellow),
429-
playback_metadata: Style::default().fg(StyleColor::BrightBlack),
430-
playback_progress_bar: Style::default()
431-
.bg(StyleColor::BrightBlack)
432-
.fg(StyleColor::Green),
433-
434-
current_playing: Style::default()
435-
.fg(StyleColor::Green)
436-
.modifiers(vec![StyleModifier::Bold]),
437-
438-
page_desc: Style::default()
439-
.fg(StyleColor::Cyan)
440-
.modifiers(vec![StyleModifier::Bold]),
441-
table_header: Style::default().fg(StyleColor::Blue),
464+
background: None,
465+
foreground: None,
466+
// the default theme uses the terminal's ANSI colors
467+
black: Color::black(),
468+
red: Color::red(),
469+
green: Color::green(),
470+
yellow: Color::yellow(),
471+
blue: Color::blue(),
472+
magenta: Color::magenta(),
473+
cyan: Color::cyan(),
474+
white: Color::white(),
475+
bright_black: Color::bright_black(),
476+
bright_red: Color::bright_red(),
477+
bright_green: Color::bright_green(),
478+
bright_yellow: Color::bright_yellow(),
479+
bright_blue: Color::bright_blue(),
480+
bright_magenta: Color::bright_magenta(),
481+
bright_cyan: Color::bright_cyan(),
482+
bright_white: Color::bright_white(),
442483
}
443484
}
444485
}

0 commit comments

Comments
 (0)