feat: status color customing

This commit is contained in:
sxyazi 2023-07-15 00:54:58 +08:00
parent 19fcc78a12
commit ca08a8447a
No known key found for this signature in database
9 changed files with 119 additions and 63 deletions

8
Cargo.lock generated
View file

@ -1844,9 +1844,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.19.12" version = "0.19.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" checksum = "5f8751d9c1b03c6500c387e96f81f815a4f8e72d142d2d4a9ffa6fedd51ddee7"
dependencies = [ dependencies = [
"indexmap 2.0.0", "indexmap 2.0.0",
"serde", "serde",
@ -2328,9 +2328,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.4.9" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View file

@ -6,7 +6,7 @@ use serde::Deserialize;
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(try_from = "String")] #[serde(try_from = "String")]
pub struct Color(style::Color); pub struct Color(pub(super) style::Color);
impl Default for Color { impl Default for Color {
fn default() -> Self { Self(style::Color::Reset) } fn default() -> Self { Self(style::Color::Reset) }
@ -33,10 +33,15 @@ impl Deref for Color {
fn deref(&self) -> &Self::Target { &self.0 } fn deref(&self) -> &Self::Target { &self.0 }
} }
#[derive(Deserialize)] impl Color {
pub struct ColorDual { pub fn fg(&self) -> style::Style { style::Style::new().fg(self.0) }
#[serde(default)]
pub fg: Color, pub fn bg(&self) -> style::Style { style::Style::new().bg(self.0) }
#[serde(default)] }
pub bg: Color,
#[derive(Deserialize)]
pub struct ColorGroup {
pub normal: Color,
pub select: Color,
pub unselect: Color,
} }

View file

@ -1,9 +1,11 @@
mod color; mod color;
mod filetype; mod filetype;
mod icon; mod icon;
mod style;
mod theme; mod theme;
pub use color::*; pub use color::*;
pub use filetype::*; pub use filetype::*;
pub use icon::*; pub use icon::*;
pub use style::*;
pub use theme::*; pub use theme::*;

40
src/config/theme/style.rs Normal file
View file

@ -0,0 +1,40 @@
use ratatui::style::{self, Modifier};
use serde::Deserialize;
use super::Color;
#[derive(Deserialize)]
pub struct Style {
pub fg: Option<Color>,
pub bg: Option<Color>,
pub bold: Option<bool>,
pub underline: Option<bool>,
}
impl Style {
pub fn get(&self) -> style::Style {
let mut style = style::Style::new();
if let Some(fg) = &self.fg {
style = style.fg(fg.0);
}
if let Some(bg) = &self.bg {
style = style.bg(bg.0);
}
if let Some(bold) = self.bold {
if bold {
style = style.add_modifier(Modifier::BOLD);
} else {
style = style.remove_modifier(Modifier::BOLD);
}
}
if let Some(underline) = self.underline {
if underline {
style = style.add_modifier(Modifier::UNDERLINED);
} else {
style = style.remove_modifier(Modifier::UNDERLINED);
}
}
style
}
}

View file

@ -3,27 +3,36 @@ use std::{fs, path::PathBuf};
use serde::Deserialize; use serde::Deserialize;
use xdg::BaseDirectories; use xdg::BaseDirectories;
use super::{ColorDual, Filetype, Icon}; use super::{ColorGroup, Filetype, Icon, Style};
use crate::misc::absolute_path; use crate::misc::absolute_path;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Mode { pub struct Tab {
pub normal: ColorDual, pub active: Style,
pub select: ColorDual, pub inactive: Style,
pub unselect: ColorDual,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Tab { pub struct Status {
pub active: ColorDual, pub primary: ColorGroup,
pub inactive: ColorDual, pub secondary: ColorGroup,
pub emphasis: ColorGroup,
pub body: ColorGroup,
pub info: ColorGroup,
pub success: ColorGroup,
pub warning: ColorGroup,
pub danger: ColorGroup,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Selection { pub struct Selection {
pub normal: ColorDual, pub hovered: Style,
pub hovered: ColorDual, }
pub selected: ColorDual,
#[derive(Deserialize)]
pub struct Marker {
pub selecting: Style,
pub selected: Style,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -33,9 +42,10 @@ pub struct Syntect {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Theme { pub struct Theme {
pub mode: Mode,
pub tab: Tab, pub tab: Tab,
pub status: Status,
pub selection: Selection, pub selection: Selection,
pub marker: Marker,
#[serde(deserialize_with = "Filetype::deserialize")] #[serde(deserialize_with = "Filetype::deserialize")]
pub filetypes: Vec<Filetype>, pub filetypes: Vec<Filetype>,
#[serde(deserialize_with = "Icon::deserialize")] #[serde(deserialize_with = "Icon::deserialize")]

View file

@ -1,6 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
use crate::config::{theme, THEME}; use crate::config::theme::{self, ColorGroup};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Mode { pub enum Mode {
@ -12,11 +12,11 @@ pub enum Mode {
impl Mode { impl Mode {
#[inline] #[inline]
pub fn color(&self) -> &theme::ColorDual { pub fn color<'a>(&self, group: &'a ColorGroup) -> &'a theme::Color {
match *self { match *self {
Mode::Normal => &THEME.mode.normal, Mode::Normal => &group.normal,
Mode::Select(_) => &THEME.mode.select, Mode::Select(_) => &group.select,
Mode::Unselect(_) => &THEME.mode.unselect, Mode::Unselect(_) => &group.unselect,
} }
} }

View file

@ -10,7 +10,7 @@ pub struct Folder<'a> {
impl<'a> Folder<'a> { impl<'a> Folder<'a> {
pub fn new(folder: &'a core::manager::Folder) -> Self { pub fn new(folder: &'a core::manager::Folder) -> Self {
Self { folder, is_preview: false, is_selection: false } Self { folder, is_preview: false, is_selection: true }
} }
#[inline] #[inline]
@ -28,11 +28,12 @@ impl<'a> Folder<'a> {
impl<'a> Widget for Folder<'a> { impl<'a> Widget for Folder<'a> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let items = self let page = self.folder.paginate();
.folder
.paginate() let items = page
.iter() .iter()
.map(|(k, v)| { .enumerate()
.map(|(i, (k, v))| {
let icon = THEME let icon = THEME
.icons .icons
.iter() .iter()
@ -40,34 +41,32 @@ impl<'a> Widget for Folder<'a> {
.map(|x| x.display.as_ref()) .map(|x| x.display.as_ref())
.unwrap_or(""); .unwrap_or("");
let name = readable_path(k, &self.folder.cwd); if v.is_selected {
let item = ListItem::new(if v.is_selected { buf.set_style(
format!("> {} {}", icon, name) Rect { x: area.x.saturating_sub(1), y: i as u16 + 1, width: 1, height: 1 },
} else { Style::default().fg(Color::Red).bg(Color::Red),
format!("{} {}", icon, name) );
}); }
let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k);
let name = if self.is_selection && v.is_selected {
format!(" {} {}", icon, readable_path(k, &self.folder.cwd))
} else {
format!(" {} {}", icon, readable_path(k, &self.folder.cwd))
};
let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k);
let mut style = Style::default(); let mut style = Style::default();
if self.is_selection { if self.is_preview {
if hovered {
style = style.fg(Color::Black).bg(Color::Red);
} else if v.is_selected {
style = style.fg(Color::Red);
}
} else if self.is_preview {
if hovered { if hovered {
style = style.add_modifier(Modifier::UNDERLINED) style = style.add_modifier(Modifier::UNDERLINED)
} }
} else { } else {
if hovered { if hovered {
style = style.fg(Color::Black).bg(Color::Yellow); style = style.fg(Color::Black).bg(Color::Yellow);
} else if v.is_selected {
style = style.fg(Color::Red);
} }
} }
item.style(style) ListItem::new(name).style(style)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View file

@ -1,4 +1,4 @@
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Block, Borders, Widget}}; use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Block, Borders, Padding, Widget}};
use super::{Folder, Preview}; use super::{Folder, Preview};
use crate::{core::manager::{Mode, ALL_RATIO, CURRENT_RATIO, PARENT_RATIO, PREVIEW_RATIO}, ui::Ctx}; use crate::{core::manager::{Mode, ALL_RATIO, CURRENT_RATIO, PARENT_RATIO, PREVIEW_RATIO}, ui::Ctx};
@ -28,7 +28,7 @@ impl<'a> Widget for Layout<'a> {
.split(area); .split(area);
// Parent // Parent
let block = Block::default().borders(Borders::RIGHT); let block = Block::default().borders(Borders::RIGHT).padding(Padding::new(1, 0, 0, 0));
if let Some(ref parent) = manager.parent() { if let Some(ref parent) = manager.parent() {
Folder::new(parent).render(block.inner(chunks[0]), buf); Folder::new(parent).render(block.inner(chunks[0]), buf);
} }
@ -40,7 +40,7 @@ impl<'a> Widget for Layout<'a> {
.render(chunks[1], buf); .render(chunks[1], buf);
// Preview // Preview
let block = Block::default().borders(Borders::LEFT); let block = Block::default().borders(Borders::LEFT).padding(Padding::new(0, 1, 0, 0));
Preview::new(self.cx).render(block.inner(chunks[2]), buf); Preview::new(self.cx).render(block.inner(chunks[2]), buf);
block.render(chunks[2], buf); block.render(chunks[2], buf);
} }

View file

@ -1,7 +1,7 @@
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, style::{Color, Modifier, Style}, widgets::{Paragraph, Widget}}; use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, style::Modifier, widgets::{Paragraph, Widget}};
use super::Progress; use super::Progress;
use crate::ui::Ctx; use crate::{config::THEME, ui::Ctx};
pub struct Layout<'a> { pub struct Layout<'a> {
cx: &'a Ctx, cx: &'a Ctx,
@ -29,19 +29,19 @@ impl<'a> Widget for Layout<'a> {
) )
.split(area); .split(area);
Paragraph::new("").style(Style::default().fg(*mode.color().bg)).render(chunks[0], buf); let primary = mode.color(&THEME.status.primary);
let secondary = mode.color(&THEME.status.secondary);
let body = mode.color(&THEME.status.body);
Paragraph::new("").style(primary.fg()).render(chunks[0], buf);
Paragraph::new(format!(" {} ", mode)) Paragraph::new(format!(" {} ", mode))
.style( .style(primary.bg().fg(**secondary).add_modifier(Modifier::BOLD))
Style::default().fg(*mode.color().fg).bg(*mode.color().bg).add_modifier(Modifier::BOLD),
)
.render(chunks[1], buf); .render(chunks[1], buf);
Paragraph::new(" master ") Paragraph::new(" master ").style(body.bg().fg(**primary)).render(chunks[2], buf);
.style(Style::default().fg(*mode.color().bg).bg(Color::Rgb(72, 77, 102)))
.render(chunks[2], buf);
Paragraph::new("").style(Style::default().fg(Color::Rgb(72, 77, 102))).render(chunks[3], buf); Paragraph::new("").style(body.fg()).render(chunks[3], buf);
Progress::new(self.cx).render(chunks[4], buf); Progress::new(self.cx).render(chunks[4], buf);
} }