style update
This commit is contained in:
+37
-5
@@ -20,6 +20,12 @@
|
||||
//! - `ui` - Contains all user interface components, enabling rich CLI experiences.
|
||||
//! - `utils` - Utility functions for common TUI tasks such as clearing the screen.
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use crossterm::event::Event;
|
||||
|
||||
pub mod app;
|
||||
@@ -31,8 +37,19 @@ pub mod utils;
|
||||
/// of UI elements. It re-exports commonly used traits, structs, and utility functions to make
|
||||
/// the UI framework easier to use.
|
||||
pub mod prelude {
|
||||
pub use crate::{app::run, rsx, rsx_elem, ui::*, StateChanger};
|
||||
pub use crate::{Children, Component, Element, ElementCore, State, Value};
|
||||
pub use crate::ui::Color::*;
|
||||
pub use crate::{app::run, css, rsx, rsx_elem, ui::*, Handler};
|
||||
pub use crate::{Children, Element, ElementCore, State, Value};
|
||||
pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
|
||||
pub fn sleep(ms: u64) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(ms));
|
||||
}
|
||||
}
|
||||
|
||||
pub mod prelude_extra{
|
||||
pub use crate::ui::Color::*;
|
||||
pub use crate::{app::run, css, rsx, rsx_elem, ui::*, Handler, StateChanger};
|
||||
pub use crate::{Children, Component, Element, ElementCore, State, Value, run_handler};
|
||||
pub use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
|
||||
pub fn sleep(ms: u64) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(ms));
|
||||
@@ -79,6 +96,7 @@ pub trait ElementCore: Send + Sync {
|
||||
fn update_data(&mut self, width: usize, height: usize);
|
||||
fn get_element_by_id(&mut self, id: &str) -> Option<&mut Element>;
|
||||
fn get_child(&mut self) -> Option<&mut Element>;
|
||||
fn set_styling(&mut self, styling: &HashMap<crate::ui::StyleName, crate::ui::Style>);
|
||||
}
|
||||
|
||||
pub trait Component: ElementCore + std::fmt::Debug {
|
||||
@@ -98,14 +116,28 @@ pub type Element = Box<dyn Component>;
|
||||
/// Handler Struct
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub struct Handler<T>(pub Box<dyn FnMut(&T, Event, &StateChanger) + Send>);
|
||||
pub struct Handler<T>(pub Arc<Mutex<dyn FnMut(&mut T, Event, &StateChanger) + Send + Sync>>);
|
||||
|
||||
impl<T> Handler<T> {
|
||||
pub fn new<F>(handler_fn: F) -> Handler<T>
|
||||
where
|
||||
F: FnMut(&T, Event, &StateChanger) + 'static + Send,
|
||||
F: FnMut(&mut T, Event, &StateChanger) + 'static + Send + Sync,
|
||||
{
|
||||
Handler(Box::new(handler_fn))
|
||||
Handler(Arc::new(Mutex::new(handler_fn)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Handler<T> {
|
||||
fn default() -> Self {
|
||||
Handler(Arc::new(Mutex::new(
|
||||
|_: &mut T, _: Event, _: &StateChanger| {},
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for Handler<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("Handler()")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+173
-47
@@ -1,14 +1,14 @@
|
||||
/// **parse_rsx_param!** - A macro for parsing and setting parameters on elements, allowing for dynamic handling of element properties and children.
|
||||
///
|
||||
///
|
||||
/// This macro enables flexible configuration of UI elements. It handles setting fields, adding children, invoking paths, and processing complex structures.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```rust
|
||||
/// parse_rsx_param!(elem, title: "Hello", for (i in 0..5) { <child> }, text: "World");
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ## Syntax
|
||||
///
|
||||
///
|
||||
/// **Set property or field of an element:**
|
||||
/// ```rust
|
||||
/// parse_rsx_param!($elem, $($k:ident).+: $v:expr);
|
||||
@@ -33,7 +33,7 @@
|
||||
/// ```rust
|
||||
/// parse_rsx_param!($elem, {$ielem:expr} $($rest:tt)*);
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// **Set element text:**
|
||||
/// ```rust
|
||||
/// parse_rsx_param!($elem, $text:expr);
|
||||
@@ -112,14 +112,14 @@ macro_rules! parse_rsx_param {
|
||||
}
|
||||
|
||||
/// **rsx_elem!** - A macro to instantiate a UI element and apply parameters to it.
|
||||
///
|
||||
///
|
||||
/// This macro simplifies creating an element and applying a set of properties or children to it, enabling a declarative style of UI building.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```rust
|
||||
/// let element = rsx_elem!(ui::Button { text: "Click me" });
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ## Syntax
|
||||
/// ```rust
|
||||
/// rsx_elem!($elem:path { $($inner:tt)* })
|
||||
@@ -143,9 +143,9 @@ macro_rules! rsx_elem {
|
||||
/// rsx! {
|
||||
/// text { "Hello, World" }
|
||||
/// div { button {"Click me!"} }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// ## Syntax
|
||||
/// ```rust
|
||||
/// rsx!($($inner:tt)*)
|
||||
@@ -165,48 +165,174 @@ macro_rules! val {
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! write {
|
||||
(($self:ident, $state:expr), $expr:expr) => {{
|
||||
if $state == 0 {
|
||||
return format!(
|
||||
"{}{}{}{}\x1b[0m",
|
||||
$self.style.color.ansi(),
|
||||
$self.style.background.ansi_bg(),
|
||||
$self.style.font.ansi(),
|
||||
$expr
|
||||
);
|
||||
}
|
||||
format!(
|
||||
"{}{}{}{}\x1b[0m",
|
||||
$self.style.hover_color.ansi(),
|
||||
$self.style.hover_background.ansi_bg(),
|
||||
$self.style.hover_font.ansi(),
|
||||
$expr
|
||||
)
|
||||
macro_rules! run_handler {
|
||||
($self:ident.$handler:ident ($($inner:tt)*)) => {{
|
||||
let a = std::sync::Arc::clone(&$self.$handler.0);
|
||||
let mut o = a.lock().unwrap();
|
||||
o($self, $($inner)*);
|
||||
}};
|
||||
|
||||
($self:ident, $kind:ident, $expr:expr) => {{
|
||||
use paste::paste;
|
||||
format!(
|
||||
"{}{}{}{}\x1b[0m",
|
||||
paste! {
|
||||
$self.style.[<$kind _color>].ansi()
|
||||
},
|
||||
paste! {
|
||||
$self.style.[<$kind _background>].ansi_bg()
|
||||
},
|
||||
paste! {
|
||||
$self.style.[<$kind _font>].ansi()
|
||||
},
|
||||
$expr
|
||||
)
|
||||
($self:ident.$handler:ident) => {{
|
||||
&$self.$handler;
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! run_handler {
|
||||
($self:ident.$handler:ident ($renderer:expr, $event:expr)) => {
|
||||
let mut o = $self.$handler.0.lock().unwrap();
|
||||
o($self, $renderer, $event);
|
||||
};
|
||||
macro_rules! __css {
|
||||
($style:expr,)=>{};
|
||||
(
|
||||
$style:expr, ($name:ident): $value:expr
|
||||
) => {{
|
||||
$style.other.insert(stringify!($name).to_string(), Box::new($value));
|
||||
}};
|
||||
(
|
||||
$style:expr, ($name:ident): $value:expr, $($other:tt)*
|
||||
) => {{
|
||||
$style.other.insert(stringify!($name).to_string(), Box::new($value));
|
||||
$crate::__css!($($other)*);
|
||||
}};
|
||||
(
|
||||
$style:expr, $name:ident: $value:expr
|
||||
) => {{
|
||||
$style.$name = $value;
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! _css {
|
||||
($style:expr,) => {};
|
||||
(
|
||||
$hm:expr, .$name:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Class(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
(
|
||||
$hm:expr, .$name:ident::$kind:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Class(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
|
||||
|
||||
(
|
||||
$hm:expr, #$name:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Id(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
(
|
||||
$hm:expr, #$name:ident::$kind:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Id(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
|
||||
|
||||
(
|
||||
$hm:expr, $name:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Component(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
$crate::__css!(style.0, $($inner)*);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
(
|
||||
$hm:expr, $name:ident::$kind:ident { $($inner:tt)* } $($rest:tt)*
|
||||
) => {{
|
||||
let name = $crate::ui::StyleName::Component(stringify!($name).to_string());
|
||||
if let Some(style) = $hm.get_mut(&name) {
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
} else {
|
||||
let mut style = $crate::ui::Style::default();
|
||||
|
||||
let mut style_elem = $crate::ui::StyleElement::default();
|
||||
$crate::__css!(style_elem, $($inner)*);
|
||||
style.1.insert(stringify!($kind).to_string(), style_elem);
|
||||
|
||||
$hm.insert(
|
||||
name,
|
||||
style,
|
||||
);
|
||||
}
|
||||
$crate::_css!($hm, $($rest)*);
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! css {
|
||||
(
|
||||
$($inner:tt)*
|
||||
) => {{
|
||||
let mut hm: $crate::ui::Css = std::collections::HashMap::new();
|
||||
$crate::_css!(hm, $($inner)*);
|
||||
hm
|
||||
}};
|
||||
}
|
||||
|
||||
+10
-2
@@ -5,7 +5,15 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app() -> Element {
|
||||
rsx! {
|
||||
button { "This is a button!" }
|
||||
rsx! { styling: Some(styles()),
|
||||
button { class: "btn", "This is a button!" }
|
||||
}
|
||||
}
|
||||
|
||||
fn styles() -> Css {
|
||||
css! {
|
||||
.btn::click {
|
||||
color: Blue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-13
@@ -1,18 +1,11 @@
|
||||
/// The `ui` module defines the basic building blocks for creating a terminal-based UI framework.
|
||||
/// This includes elements like `Text` and `Div`, which can be combined to create complex layouts
|
||||
/// and interactive UIs in the terminal. It also provides utility functions for rendering, event
|
||||
/// handling, and managing child components.
|
||||
///
|
||||
/// Key Components:
|
||||
/// - `Text`: A simple text element that renders a string to the terminal.
|
||||
/// - `Div`: A container element that holds and renders child components, allowing navigation
|
||||
/// through them with keyboard events (Up, Down, Left, Right).
|
||||
/// # Modules
|
||||
/// - `styles`: A module for defining UI styles.
|
||||
/// - `utils`: Utility functions for rendering and managing state.
|
||||
pub mod styles;
|
||||
pub use styles::*;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::prelude_extra::*;
|
||||
use osui_element::{elem_fn, element};
|
||||
|
||||
/// The `Text` element represents a piece of static text in the terminal UI.
|
||||
@@ -68,7 +61,9 @@ impl Component for Text<'_> {
|
||||
#[element]
|
||||
#[elem_fn]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Div {}
|
||||
pub struct Div {
|
||||
pub styling: Option<std::collections::HashMap<StyleName, Style>>,
|
||||
}
|
||||
|
||||
impl Component for Div<'_> {
|
||||
fn render(&self, state: State) -> String {
|
||||
@@ -93,6 +88,9 @@ impl Component for Div<'_> {
|
||||
}
|
||||
|
||||
fn event(&mut self, event: Event, state: &crate::StateChanger) {
|
||||
if let Some(styling) = self.styling.clone() {
|
||||
self.set_styling(&styling);
|
||||
}
|
||||
match event {
|
||||
Event::Key(key) => {
|
||||
if let Children::Children(children, child) = &mut self.children {
|
||||
@@ -142,13 +140,16 @@ impl Component for Div<'_> {
|
||||
#[element]
|
||||
#[elem_fn]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Button {}
|
||||
pub struct Button {
|
||||
pub on_click: Handler<Button<'a>>,
|
||||
}
|
||||
|
||||
impl Component for Button<'_> {
|
||||
fn render(&self, state: State) -> String {
|
||||
match state {
|
||||
State::Custom(_) => format!("\x1b[32m{}\x1b[0m", self.children.get_text()),
|
||||
_ => self.children.get_text(),
|
||||
State::Custom(_) => self.style.write("click", &self.children.get_text()),
|
||||
State::Hover => self.style.write("hover", &self.children.get_text()),
|
||||
_ => self.style.write("", &self.children.get_text()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +158,7 @@ impl Component for Button<'_> {
|
||||
Event::Key(key) => {
|
||||
if key.code == KeyCode::Enter {
|
||||
let prev_state = state.get_state();
|
||||
run_handler!(self.on_click(event, state));
|
||||
state.set_state(State::Custom(0));
|
||||
sleep(100);
|
||||
state.set_state(prev_state);
|
||||
|
||||
+86
-53
@@ -1,18 +1,19 @@
|
||||
//! The `styles` module defines various styling options for UI elements. This includes colors,
|
||||
//! fonts, padding, margins, and other visual properties that can be applied to UI components
|
||||
//! to change their appearance.
|
||||
//!
|
||||
//! # Example
|
||||
//! ```rust
|
||||
//! use crate::ui::styles::{Style, Color};
|
||||
//!
|
||||
//! let style = Style {
|
||||
//! color: Color::Blue,
|
||||
//! padding: 5,
|
||||
//! };
|
||||
//! ```
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use dyn_clone::{clone_trait_object, DynClone};
|
||||
|
||||
pub trait StyleCore: Debug + Send + Sync + DynClone {
|
||||
fn ansi(&self) -> String;
|
||||
fn ansi_bg(&self) -> String;
|
||||
}
|
||||
|
||||
clone_trait_object!(StyleCore);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Font {
|
||||
None,
|
||||
Bold,
|
||||
@@ -20,11 +21,11 @@ pub enum Font {
|
||||
Italic,
|
||||
Reverse,
|
||||
Strike,
|
||||
Mul(Vec<Font>),
|
||||
Mul(Vec<Font>),
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub fn ansi(&self) -> String {
|
||||
impl StyleCore for Font {
|
||||
fn ansi(&self) -> String {
|
||||
String::from(match self {
|
||||
Font::None => "",
|
||||
Font::Bold => "\x1b[1m",
|
||||
@@ -41,24 +42,15 @@ impl Font {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn prioritize<'a>(&'a self, secondary: &'a Font) -> &Font {
|
||||
if secondary == &Font::None {
|
||||
self
|
||||
} else {
|
||||
secondary
|
||||
}
|
||||
fn ansi_bg(&self) -> String {
|
||||
self.ansi()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Color {
|
||||
None,
|
||||
|
||||
Rgb(u8, u8, u8),
|
||||
NoColor,
|
||||
Rgb(u8, u8, u8),
|
||||
Hex(String),
|
||||
Black,
|
||||
Red,
|
||||
@@ -70,11 +62,10 @@ pub enum Color {
|
||||
White,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
|
||||
pub fn ansi(&self) -> String {
|
||||
impl StyleCore for Color {
|
||||
fn ansi(&self) -> String {
|
||||
String::from(match self {
|
||||
Color::None => "",
|
||||
Color::NoColor => "",
|
||||
Color::Rgb(r, g, b) => {
|
||||
return format!("\x1b[38;2;{r};{g};{b}m");
|
||||
}
|
||||
@@ -93,10 +84,9 @@ impl Color {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
pub fn ansi_bg(&self) -> String {
|
||||
fn ansi_bg(&self) -> String {
|
||||
String::from(match self {
|
||||
Color::None => "",
|
||||
Color::NoColor => "",
|
||||
Color::Rgb(r, g, b) => {
|
||||
return format!("\x1b[48;2;{r};{g};{b}m");
|
||||
}
|
||||
@@ -114,21 +104,11 @@ impl Color {
|
||||
Color::White => "\x1b[47m",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn prioritize<'a>(&'a self, secondary: &'a Color) -> &Color {
|
||||
if secondary == &Color::None {
|
||||
self
|
||||
} else {
|
||||
secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Color::None
|
||||
Color::NoColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,24 +121,77 @@ impl Default for Font {
|
||||
fn hex_to_rgb(hex: &str) -> (u8, u8, u8) {
|
||||
let hex = hex.trim_start_matches('#');
|
||||
|
||||
|
||||
let hex = if hex.len() == 3 {
|
||||
format!(
|
||||
"{}{}{}{}{}{}",
|
||||
&hex[0..1], &hex[0..1],
|
||||
&hex[1..2], &hex[1..2],
|
||||
&hex[2..3], &hex[2..3]
|
||||
&hex[0..1],
|
||||
&hex[0..1],
|
||||
&hex[1..2],
|
||||
&hex[1..2],
|
||||
&hex[2..3],
|
||||
&hex[2..3]
|
||||
)
|
||||
} else if hex.len() == 6 {
|
||||
hex.to_string()
|
||||
} else {
|
||||
return (255, 255, 255);
|
||||
return (255, 255, 255);
|
||||
};
|
||||
|
||||
|
||||
let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(255);
|
||||
let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(255);
|
||||
let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(255);
|
||||
|
||||
(r, g, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
||||
pub enum StyleName {
|
||||
Class(String),
|
||||
Id(String),
|
||||
Component(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StyleElement {
|
||||
pub color: Color,
|
||||
pub other: HashMap<String, Box<dyn StyleCore>>,
|
||||
}
|
||||
|
||||
impl Default for StyleElement {
|
||||
fn default() -> Self {
|
||||
StyleElement {
|
||||
color: Color::NoColor,
|
||||
other: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Style(pub StyleElement, pub HashMap<String, StyleElement>);
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Style(StyleElement::default(), HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn write(&self, state: &str, s: &str) -> String {
|
||||
if state == "" {
|
||||
return self.0.write(s);
|
||||
}
|
||||
if let Some(style_element) = self.1.get(state) {
|
||||
style_element.write(s)
|
||||
} else {
|
||||
s.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleElement {
|
||||
pub fn write(&self, s: &str) -> String {
|
||||
format!("{}{s}\x1b[0m", self.color.ansi())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Css = HashMap<StyleName, Style>;
|
||||
|
||||
Reference in New Issue
Block a user