feat(faces): the TUI draws axis, wizard-field, mode and minibuffer colours through face_style (improvise-nn4s.2)
axis_fg, minibuf_fg, field_kind_fg and mode_style are gone, and AxisColor leaves improvise-core. The category-add prompt turns green, ADR 004 clause 8's one declared exception. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
abff562360
commit
12d976b432
@@ -12,17 +12,6 @@ pub enum Axis {
|
||||
None,
|
||||
}
|
||||
|
||||
/// Accent color for an axis. Semantic palette only; `draw.rs::axis_fg` maps
|
||||
/// each variant to a terminal color, so `Axis` names no ratatui type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AxisColor {
|
||||
Row,
|
||||
Column,
|
||||
Page,
|
||||
Filter,
|
||||
Inactive,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
/// The next axis in the Row → Column → Page → None → Row rotation.
|
||||
/// `Filter` is outside it and cycling one is a no-op (improvise-dz8).
|
||||
@@ -48,17 +37,6 @@ impl Axis {
|
||||
!matches!(self, Axis::Filter)
|
||||
}
|
||||
|
||||
/// Accent color. The single source for axis coloring: the tile bar and the
|
||||
/// category panel each carried a copy before (improvise-rml).
|
||||
pub fn color(self) -> AxisColor {
|
||||
match self {
|
||||
Axis::Row => AxisColor::Row,
|
||||
Axis::Column => AxisColor::Column,
|
||||
Axis::Page => AxisColor::Page,
|
||||
Axis::Filter => AxisColor::Filter,
|
||||
Axis::None => AxisColor::Inactive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Name with no decoration: "Row", "Col", "Page", "None".
|
||||
pub fn plain_label(self) -> &'static str {
|
||||
@@ -176,15 +154,4 @@ mod tests {
|
||||
assert!(!Axis::Column.filters_data());
|
||||
assert!(!Axis::None.filters_data());
|
||||
}
|
||||
|
||||
/// A collision defeats the only reason `AxisColor` exists.
|
||||
#[test]
|
||||
fn every_axis_gets_its_own_color() {
|
||||
let colors = ALL.map(Axis::color);
|
||||
for (i, a) in colors.iter().enumerate() {
|
||||
for b in &colors[i + 1..] {
|
||||
assert_ne!(a, b, "two axes share an accent color");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ pub mod axis;
|
||||
pub mod layout;
|
||||
pub mod types;
|
||||
|
||||
pub use axis::{Axis, AxisColor};
|
||||
pub use axis::Axis;
|
||||
pub use layout::{
|
||||
AxisEntry, GridEval, GridLayout, NEW_CATEGORY_COL, NEW_MEASURE_COL, RecordCol, RecordRow,
|
||||
ViewStep, drill_constraint, drill_snapshot, drill_steps, record_row, records_spine,
|
||||
|
||||
@@ -575,6 +575,18 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// A collision defeats the reason the axis faces exist (improvise-rml).
|
||||
#[test]
|
||||
fn every_axis_gets_its_own_accent_in_the_shipped_theme() {
|
||||
let theme = Theme::shipped();
|
||||
let accents = AXES.map(|axis| theme.resolve(Face::Axis(axis)));
|
||||
for (i, a) in accents.iter().enumerate() {
|
||||
for b in &accents[i + 1..] {
|
||||
assert_ne!(a, b, "two axes share an accent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A child overrides what it states and inherits what it does not, from
|
||||
/// the nearest ancestor that states it — `context/test-evidence/protocol.md`.
|
||||
#[test]
|
||||
|
||||
@@ -396,7 +396,7 @@ impl AppMode {
|
||||
minibuf: MinibufferConfig {
|
||||
buffer_key: "category".into(),
|
||||
prompt: "new category: ".into(),
|
||||
color: MinibufColor::Yellow,
|
||||
color: MinibufColor::Green,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ pub struct RenderModel {
|
||||
pub struct RenderMinibuffer {
|
||||
pub prompt: String,
|
||||
pub value: String,
|
||||
/// Semantic, as `MinibufColor` is: the last translation to a CSS class is
|
||||
/// the page's, exactly as `draw.rs::minibuf_fg` is the TUI's (gotcha 26).
|
||||
/// A colour, not a role: the TUI now draws a face per text-entry mode, and
|
||||
/// improvise-nn4s.4 moves the page onto the same faces (ADR 004).
|
||||
pub color: improvise_protocol::MinibufColor,
|
||||
}
|
||||
|
||||
|
||||
+176
-48
@@ -1,5 +1,6 @@
|
||||
use std::io::{self, Stdout};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
@@ -17,8 +18,9 @@ use ratatui::{
|
||||
};
|
||||
|
||||
use crate::command::key;
|
||||
use crate::protocol::face::{AnsiSlot, Colour, Face, Slant, Theme, Weight};
|
||||
use crate::protocol::EditorSession;
|
||||
use crate::ui::app::{App, AppMode, MinibufColor};
|
||||
use crate::ui::app::{App, AppMode};
|
||||
use crate::ui::category_panel::CategoryContent;
|
||||
use crate::ui::formula_panel::FormulaContent;
|
||||
use crate::ui::grid::GridWidget;
|
||||
@@ -29,7 +31,6 @@ use crate::ui::text::truncate;
|
||||
use crate::ui::tile_bar::TileBar;
|
||||
use crate::ui::view_panel::ViewContent;
|
||||
use crate::ui::which_key::WhichKeyWidget;
|
||||
use crate::view::AxisColor;
|
||||
use improvise_command::ui::project;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
@@ -165,24 +166,54 @@ fn convert_modifiers(mods: event::KeyModifiers) -> key::KeyModifiers {
|
||||
|
||||
// ── Drawing ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/// The one place `AxisColor` becomes a terminal color (improvise-rml); the
|
||||
/// accent itself is decided by `Axis::color`. See `context/code/tui.md`.
|
||||
pub(crate) fn axis_fg(color: AxisColor) -> Color {
|
||||
match color {
|
||||
AxisColor::Row => Color::Green,
|
||||
AxisColor::Column => Color::Blue,
|
||||
AxisColor::Page => Color::Magenta,
|
||||
AxisColor::Filter => Color::Yellow,
|
||||
AxisColor::Inactive => Color::DarkGray,
|
||||
/// The one place a face becomes a terminal style (ADR 004): the theme resolves
|
||||
/// it, and only this last translation is the TUI's. `context/code/tui.md`.
|
||||
pub(crate) fn face_style(face: Face) -> Style {
|
||||
static SHIPPED: OnceLock<Theme> = OnceLock::new();
|
||||
let face = SHIPPED.get_or_init(Theme::shipped).resolve(face);
|
||||
let mut style = Style::default();
|
||||
if let Some(fg) = terminal_colour(face.foreground) {
|
||||
style = style.fg(fg);
|
||||
}
|
||||
if let Some(bg) = terminal_colour(face.background) {
|
||||
style = style.bg(bg);
|
||||
}
|
||||
let modifiers = [
|
||||
(face.weight == Weight::Bold, Modifier::BOLD),
|
||||
(face.slant == Slant::Italic, Modifier::ITALIC),
|
||||
(face.underline, Modifier::UNDERLINED),
|
||||
(face.reverse, Modifier::REVERSED),
|
||||
];
|
||||
modifiers
|
||||
.into_iter()
|
||||
.filter(|(on, _)| *on)
|
||||
.fold(style, |style, (_, m)| style.add_modifier(m))
|
||||
}
|
||||
|
||||
/// Map the semantic minibuffer accent to a concrete terminal color.
|
||||
fn minibuf_fg(color: MinibufColor) -> Color {
|
||||
match color {
|
||||
MinibufColor::Green => Color::Green,
|
||||
MinibufColor::Cyan => Color::Cyan,
|
||||
MinibufColor::Yellow => Color::Yellow,
|
||||
/// `None` is "state nothing", so the terminal's own colour shows through.
|
||||
fn terminal_colour(colour: Colour) -> Option<Color> {
|
||||
match colour {
|
||||
Colour::Default => None,
|
||||
Colour::Named(slot) => Some(match slot {
|
||||
AnsiSlot::Black => Color::Black,
|
||||
AnsiSlot::Red => Color::Red,
|
||||
AnsiSlot::Green => Color::Green,
|
||||
AnsiSlot::Yellow => Color::Yellow,
|
||||
AnsiSlot::Blue => Color::Blue,
|
||||
AnsiSlot::Magenta => Color::Magenta,
|
||||
AnsiSlot::Cyan => Color::Cyan,
|
||||
AnsiSlot::White => Color::Gray,
|
||||
AnsiSlot::BrightBlack => Color::DarkGray,
|
||||
AnsiSlot::BrightRed => Color::LightRed,
|
||||
AnsiSlot::BrightGreen => Color::LightGreen,
|
||||
AnsiSlot::BrightYellow => Color::LightYellow,
|
||||
AnsiSlot::BrightBlue => Color::LightBlue,
|
||||
AnsiSlot::BrightMagenta => Color::LightMagenta,
|
||||
AnsiSlot::BrightCyan => Color::LightCyan,
|
||||
AnsiSlot::BrightWhite => Color::White,
|
||||
}),
|
||||
Colour::Indexed(n) => Some(Color::Indexed(n)),
|
||||
Colour::Rgb(r, g, b) => Some(Color::Rgb(r, g, b)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,30 +262,6 @@ fn draw_popup_frame(f: &mut Frame, popup: Rect, title: &str, border_color: Color
|
||||
inner
|
||||
}
|
||||
|
||||
/// Terminal styling for the mode indicator. Exhaustive on purpose, so a new
|
||||
/// `AppMode` fails the build here (improvise-zx8t) — `context/code/tui.md`.
|
||||
fn mode_style(mode: &AppMode) -> Style {
|
||||
let bg = match mode {
|
||||
AppMode::Editing { .. } | AppMode::RecordsEditing { .. } => Color::Green,
|
||||
AppMode::CommandMode { .. } => Color::Yellow,
|
||||
AppMode::TileSelect => Color::Magenta,
|
||||
AppMode::Normal
|
||||
| AppMode::RecordsNormal
|
||||
| AppMode::FormulaEdit { .. }
|
||||
| AppMode::FormulaPanel
|
||||
| AppMode::CategoryPanel
|
||||
| AppMode::CategoryAdd { .. }
|
||||
| AppMode::ItemAdd { .. }
|
||||
| AppMode::ViewPanel
|
||||
| AppMode::ImportWizard
|
||||
| AppMode::ExportPrompt { .. }
|
||||
| AppMode::SavePrompt { .. }
|
||||
| AppMode::Help
|
||||
| AppMode::Quit => Color::DarkGray,
|
||||
};
|
||||
Style::default().fg(Color::Black).bg(bg)
|
||||
}
|
||||
|
||||
fn draw(f: &mut Frame, app: &App) {
|
||||
let size = f.area();
|
||||
|
||||
@@ -442,12 +449,9 @@ fn draw_bottom_bar(f: &mut Frame, area: Rect, app: &App) {
|
||||
.unwrap_or("");
|
||||
let text = minibuffer_line(&mb.prompt, buf, &app.view_state.status_msg, area.width);
|
||||
f.render_widget(
|
||||
Paragraph::new(text).style(
|
||||
Style::default()
|
||||
.fg(minibuf_fg(mb.color))
|
||||
.bg(Color::Indexed(235))
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Paragraph::new(text).style(face_style(
|
||||
Face::of_minibuffer(&app.view_state.mode).unwrap_or(Face::Minibuffer),
|
||||
)),
|
||||
area,
|
||||
);
|
||||
} else {
|
||||
@@ -484,7 +488,7 @@ fn draw_status(f: &mut Frame, area: Rect, app: &App) {
|
||||
let line = fill_line(left, &view_badge, area.width, Keeps::Left);
|
||||
|
||||
f.render_widget(
|
||||
Paragraph::new(line).style(mode_style(&app.view_state.mode)),
|
||||
Paragraph::new(line).style(face_style(Face::of_mode(&app.view_state.mode))),
|
||||
area,
|
||||
);
|
||||
}
|
||||
@@ -639,6 +643,39 @@ mod bottom_bar_tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// The first cell of the bottom row, where the prompt's first glyph lands.
|
||||
fn prompt_cell(app: &App) -> ratatui::buffer::Cell {
|
||||
let mut terminal = Terminal::new(TestBackend::new(40, 1)).expect("test backend");
|
||||
terminal
|
||||
.draw(|f| draw_bottom_bar(f, Rect::new(0, 0, 40, 1), app))
|
||||
.expect("draw");
|
||||
terminal.backend().buffer().content()[0].clone()
|
||||
}
|
||||
|
||||
/// ADR 004 clause 8's one declared exception (the user, Q1): the
|
||||
/// category-add prompt draws as item-add does. `context/test-evidence/tui.md`.
|
||||
#[test]
|
||||
fn the_category_add_prompt_draws_as_the_item_add_prompt_does() {
|
||||
let mut app = App::new(Workbook::new("T"), None);
|
||||
app.view_state.mode = AppMode::item_add("Region".into());
|
||||
let item = prompt_cell(&app);
|
||||
app.view_state.mode = AppMode::category_add();
|
||||
let category = prompt_cell(&app);
|
||||
assert_eq!(category.symbol(), "n", "the prompt is not where it was looked for");
|
||||
assert_eq!(item.fg, ratatui::style::Color::Green);
|
||||
assert_eq!(category.style(), item.style());
|
||||
}
|
||||
|
||||
/// The status line wears the mode's face, not the minibuffer's.
|
||||
#[test]
|
||||
fn the_status_line_is_drawn_in_the_mode_face() {
|
||||
let mut app = App::new(Workbook::new("T"), None);
|
||||
app.view_state.mode = AppMode::TileSelect;
|
||||
let cell = prompt_cell(&app);
|
||||
assert_eq!(cell.bg, ratatui::style::Color::Magenta);
|
||||
assert_eq!(cell.fg, ratatui::style::Color::Black);
|
||||
}
|
||||
|
||||
/// A refusal that keeps the user in a minibuffer stands while they fix it, and
|
||||
/// goes when they leave (improvise-su4u). `context/test-evidence/tui.md`.
|
||||
#[test]
|
||||
@@ -1187,3 +1224,94 @@ mod content_tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod face_tests {
|
||||
use super::*;
|
||||
use crate::protocol::face::TextEntry;
|
||||
use crate::protocol::render::WizardFieldKind;
|
||||
use crate::view::Axis;
|
||||
|
||||
/// `mode_style`'s table as it stood before faces (improvise-zx8t).
|
||||
fn mode_bg_before_faces(mode: &AppMode) -> Color {
|
||||
match mode {
|
||||
AppMode::Editing { .. } | AppMode::RecordsEditing { .. } => Color::Green,
|
||||
AppMode::CommandMode { .. } => Color::Yellow,
|
||||
AppMode::TileSelect => Color::Magenta,
|
||||
AppMode::Normal
|
||||
| AppMode::RecordsNormal
|
||||
| AppMode::FormulaEdit { .. }
|
||||
| AppMode::FormulaPanel
|
||||
| AppMode::CategoryPanel
|
||||
| AppMode::CategoryAdd { .. }
|
||||
| AppMode::ItemAdd { .. }
|
||||
| AppMode::ViewPanel
|
||||
| AppMode::ImportWizard
|
||||
| AppMode::ExportPrompt { .. }
|
||||
| AppMode::SavePrompt { .. }
|
||||
| AppMode::Help
|
||||
| AppMode::Quit => Color::DarkGray,
|
||||
}
|
||||
}
|
||||
|
||||
/// ADR 004 clause 8: the shipped theme draws every migrated site exactly as
|
||||
/// its literal did. `context/test-evidence/tui.md`.
|
||||
#[test]
|
||||
fn the_shipped_theme_reproduces_every_migrated_literal() {
|
||||
let fg = |c| Style::default().fg(c);
|
||||
let axes = [
|
||||
(Axis::Row, Color::Green),
|
||||
(Axis::Column, Color::Blue),
|
||||
(Axis::Page, Color::Magenta),
|
||||
(Axis::Filter, Color::Yellow),
|
||||
(Axis::None, Color::DarkGray),
|
||||
];
|
||||
for (axis, color) in axes {
|
||||
assert_eq!(face_style(Face::Axis(axis)), fg(color), "{axis:?}");
|
||||
}
|
||||
let kinds = [
|
||||
(WizardFieldKind::Category, Color::Green),
|
||||
(WizardFieldKind::Measure, Color::Cyan),
|
||||
(WizardFieldKind::TimeCategory, Color::Magenta),
|
||||
(WizardFieldKind::Label, Color::DarkGray),
|
||||
];
|
||||
for (kind, color) in kinds {
|
||||
assert_eq!(face_style(Face::WizardField(kind)), fg(color), "{kind:?}");
|
||||
}
|
||||
for mode in AppMode::all() {
|
||||
let before = fg(Color::Black).bg(mode_bg_before_faces(&mode));
|
||||
assert_eq!(face_style(Face::of_mode(&mode)), before, "{mode:?}");
|
||||
}
|
||||
let prompts = [
|
||||
(TextEntry::Edit, Color::Green),
|
||||
(TextEntry::ItemAdd, Color::Green),
|
||||
(TextEntry::Formula, Color::Cyan),
|
||||
(TextEntry::Command, Color::Yellow),
|
||||
(TextEntry::Export, Color::Yellow),
|
||||
(TextEntry::Save, Color::Yellow),
|
||||
];
|
||||
for (entry, color) in prompts {
|
||||
let before = fg(color)
|
||||
.bg(Color::Indexed(235))
|
||||
.add_modifier(Modifier::BOLD);
|
||||
assert_eq!(face_style(Face::MinibufferOf(entry)), before, "{entry:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_face_reaches_the_terminal_with_every_attribute_it_states() {
|
||||
let resolved = |face| Theme::shipped().resolve(face);
|
||||
for face in Face::all() {
|
||||
let r = resolved(face);
|
||||
let style = face_style(face);
|
||||
assert_eq!(style.fg, terminal_colour(r.foreground), "{}", face.name());
|
||||
assert_eq!(style.bg, terminal_colour(r.background), "{}", face.name());
|
||||
assert_eq!(
|
||||
style.add_modifier.contains(Modifier::BOLD),
|
||||
r.weight == Weight::Bold,
|
||||
"{}",
|
||||
face.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ use ratatui::{
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::protocol::face::Face;
|
||||
use crate::protocol::{CatTreeEntry, CategoryTreeCache, flatten_cat_tree};
|
||||
use crate::ui::app::Panel as PanelKind;
|
||||
use crate::ui::panel::PanelContent;
|
||||
use crate::view::Axis;
|
||||
|
||||
fn axis_display(axis: Axis) -> (String, Color) {
|
||||
(axis.to_string(), crate::draw::axis_fg(axis.color()))
|
||||
fn axis_display(axis: Axis) -> (String, Style) {
|
||||
(axis.to_string(), crate::draw::face_style(Face::Axis(axis)))
|
||||
}
|
||||
|
||||
/// The category panel draws one flattened tree and nothing else: the axis
|
||||
@@ -78,7 +79,7 @@ impl PanelContent for CategoryContent {
|
||||
axis,
|
||||
} => {
|
||||
let indicator = if *expanded { "▼" } else { "▶" };
|
||||
let (axis_str, axis_color) = axis_display(*axis);
|
||||
let (axis_str, axis_style) = axis_display(*axis);
|
||||
let name_part = format!("{indicator} {name} ({item_count})");
|
||||
let axis_part = format!(" [{axis_str}]");
|
||||
|
||||
@@ -91,7 +92,7 @@ impl PanelContent for CategoryContent {
|
||||
if is_selected {
|
||||
base_style
|
||||
} else {
|
||||
Style::default().fg(axis_color)
|
||||
axis_style
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ use ratatui::{
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::protocol::{WizardCache, WizardFieldKind, WizardStepKind};
|
||||
use crate::protocol::face::Face;
|
||||
use crate::protocol::{WizardCache, WizardStepKind};
|
||||
use crate::ui::text::wrap;
|
||||
|
||||
/// The import wizard, drawn from a [`WizardCache`] (improvise-764) and from
|
||||
@@ -22,17 +23,6 @@ impl<'a> ImportWizardWidget<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map a proposed field's kind to its accent, as `axis_fg` does for
|
||||
/// `AxisColor` (gotcha 26). The decision is the protocol's; the color is not.
|
||||
fn field_kind_fg(kind: WizardFieldKind) -> Color {
|
||||
match kind {
|
||||
WizardFieldKind::Category => Color::Green,
|
||||
WizardFieldKind::Measure => Color::Cyan,
|
||||
WizardFieldKind::TimeCategory => Color::Magenta,
|
||||
WizardFieldKind::Label => Color::DarkGray,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for ImportWizardWidget<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let popup_w = area.width.min(80);
|
||||
@@ -139,7 +129,7 @@ impl<'a> Widget for ImportWizardWidget<'a> {
|
||||
}
|
||||
let is_sel = i == self.wizard.cursor;
|
||||
|
||||
let kind_color = field_kind_fg(proposal.kind);
|
||||
let kind_style = crate::draw::face_style(Face::WizardField(proposal.kind));
|
||||
|
||||
let accept_str = if proposal.accepted {
|
||||
"[\u{2713}]"
|
||||
@@ -159,7 +149,7 @@ impl<'a> Widget for ImportWizardWidget<'a> {
|
||||
.bg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else if proposal.accepted {
|
||||
Style::default().fg(kind_color)
|
||||
kind_style
|
||||
} else {
|
||||
Style::default().fg(Color::DarkGray)
|
||||
};
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@ use ratatui::{
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use crate::protocol::TileBarCache;
|
||||
use crate::protocol::face::Face;
|
||||
use crate::ui::app::AppMode;
|
||||
use crate::view::Axis;
|
||||
|
||||
@@ -44,8 +45,8 @@ impl<'a> TileBar<'a> {
|
||||
tile_cat_idx,
|
||||
}
|
||||
}
|
||||
fn axis_display(axis: Axis) -> (&'static str, Color) {
|
||||
(axis.short_label(), crate::draw::axis_fg(axis.color()))
|
||||
fn axis_display(axis: Axis) -> (&'static str, Style) {
|
||||
(axis.short_label(), crate::draw::face_style(Face::Axis(axis)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ impl<'a> Widget for TileBar<'a> {
|
||||
break;
|
||||
}
|
||||
|
||||
let (_, axis_color) = TileBar::axis_display(tiles[i].axis);
|
||||
let (_, axis_style) = TileBar::axis_display(tiles[i].axis);
|
||||
let is_selected = selected_cat_idx == Some(i);
|
||||
let style = if is_selected {
|
||||
Style::default()
|
||||
@@ -109,7 +110,7 @@ impl<'a> Widget for TileBar<'a> {
|
||||
.bg(Color::Cyan)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
} else {
|
||||
Style::default().fg(axis_color)
|
||||
axis_style
|
||||
};
|
||||
|
||||
buf.set_string(x, area.y, &labels[i], style);
|
||||
|
||||
Reference in New Issue
Block a user