From 3f811ebef76e0b9ad937be34f70515fe626c21a3 Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 24 Mar 2025 11:12:00 +0100 Subject: feat: add custom theme struct with dark and light variants --- Cargo.lock | 1 + Cargo.toml | 1 + assets/themes/dark.toml | 46 +++++++ assets/themes/light.toml | 46 +++++++ src/main.rs | 10 +- src/theme.rs | 335 +++++++++++++++++++++++++++++------------------ src/types/project.rs | 46 ++----- 7 files changed, 318 insertions(+), 167 deletions(-) create mode 100644 assets/themes/dark.toml create mode 100644 assets/themes/light.toml diff --git a/Cargo.lock b/Cargo.lock index 1aee68c..e92c3fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1971,6 +1971,7 @@ dependencies = [ name = "iced_builder" version = "0.1.0" dependencies = [ + "dark-light", "dirs-next", "embed-resource 3.0.2", "fxhash", diff --git a/Cargo.toml b/Cargo.toml index d646fd7..39e69af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ rust-format = "0.3.4" fxhash = "0.2.1" thiserror = "2.0.11" dirs-next = "2.0.0" +dark-light = "2.0.0" [workspace.dependencies.iced] git = "https://github.com/pml68/iced" diff --git a/assets/themes/dark.toml b/assets/themes/dark.toml new file mode 100644 index 0000000..a3bde68 --- /dev/null +++ b/assets/themes/dark.toml @@ -0,0 +1,46 @@ +name = "Dark" + +[primary] +primary = "#6200ee" +on_primary = "#ffffff" +primary_container = "#3700b3" +on_primary_container = "#ffffff" + +[secondary] +secondary = "#03dac6" +on_secondary = "#ffffff" +secondary_container = "#018786" +on_secondary_container = "#ffffff" + +[tertiary] +tertiary = "#bb86fc" +on_tertiary = "#000000" +tertiary_container = "#6200ee" +on_tertiary_container = "#000000" + +[error] +error = "#b00020" +on_error = "#ffffff" +error_container = "#cf6679" +on_error_container = "#000000" + +[surface] +surface = "#121212" +on_surface = "#ffffff" +on_surface_variant = "#b0b0b0" + +[surface.surface_container] +lowest = "#1e1e2e" +low = "#333333" +base = "#444444" +high = "#555555" +highest = "#666666" + +[inverse] +inverse_surface = "#212121" +inverse_on_surface = "#ffffff" +inverse_primary = "#bb86fc" + +[outline] +outline = "#737373" +outline_variant = "#aaaaaa" diff --git a/assets/themes/light.toml b/assets/themes/light.toml new file mode 100644 index 0000000..4852b8b --- /dev/null +++ b/assets/themes/light.toml @@ -0,0 +1,46 @@ +name = "Dark" + +[primary] +primary = "#6200ee" +on_primary = "#ffffff" +primary_container = "#e1bee7" +on_primary_container = "#000000" + +[secondary] +secondary = "#03dac6" +on_secondary = "#ffffff" +secondary_container = "#018786" +on_secondary_container = "#ffffff" + +[tertiary] +tertiary = "#bb86fc" +on_tertiary = "#000000" +tertiary_container = "#6200ee" +on_tertiary_container = "#000000" + +[error] +error = "#b00020" +on_error = "#ffffff" +error_container = "#cf6679" +on_error_container = "#000000" + +[surface] +surface = "#ffffff" +on_surface = "#000000" +on_surface_variant = "#757575" + +[surface.surface_container] +lowest = "#fafafa" +low = "#eeeeee" +base = "#dddddd" +high = "#cccccc" +highest = "#bbbbbb" + +[inverse] +inverse_surface = "#121212" +inverse_on_surface = "#ffffff" +inverse_primary = "#bb86fc" + +[outline] +outline = "#757575" +outline_variant = "#b0b0b0" diff --git a/src/main.rs b/src/main.rs index d5715ef..c8a60c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -104,10 +104,7 @@ impl App { let task = if let Some(path) = config.last_project.clone() { if path.exists() && path.is_file() { - Task::perform( - Project::from_path(path, config.clone()), - Message::FileOpened, - ) + Task::perform(Project::from_path(path), Message::FileOpened) } else { warning_dialog(format!( "The file {} does not exist, or isn't a file.", @@ -181,7 +178,8 @@ impl App { } Err(error) => return error_dialog(error), } - } + Err(error) => Task::future(error_dialog(error)).discard(), + }, Message::DropNewElement(name, point, _) => { return iced_drop::zones_on_point( move |zones| Message::HandleNew(name.clone(), zones), @@ -405,7 +403,7 @@ impl App { Panes::Designer => match &self.designer_page { DesignerPane::DesignerView => designer_view::view( self.project.element_tree.as_ref(), - self.project.get_theme(&self.config), + self.project.get_theme(), is_focused, ), DesignerPane::CodeView => { diff --git a/src/theme.rs b/src/theme.rs index a072714..3e6092b 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,12 +1,14 @@ -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; use iced::Color; +use iced::theme::Base; use iced::theme::palette::Extended; +use serde::Deserialize; use crate::config::Config; -const DEFAULT_THEME_CONTENT: &str = - include_str!("../assets/themes/rose_pine.toml"); +const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); +const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); pub fn theme_index(theme_name: &str, slice: &[iced::Theme]) -> Option { slice @@ -59,115 +61,6 @@ pub fn theme_from_str( } } -fn palette_to_string(palette: &iced::theme::Palette) -> String { - format!( - r"Palette {{ - background: color!(0x{}), - text: color!(0x{}), - primary: color!(0x{}), - success: color!(0x{}), - danger: color!(0x{}), - warning: color!(0x{}), - }}", - color_to_hex(palette.background), - color_to_hex(palette.text), - color_to_hex(palette.primary), - color_to_hex(palette.success), - color_to_hex(palette.danger), - color_to_hex(palette.warning), - ) -} - -fn extended_to_string(extended: &Extended) -> String { - format!( - r" -Extended{{background:Background{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},primary:Primary{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},secondary:Secondary{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},success:Success{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},danger:Danger{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},warning:Warning{{base:Pair{{color:color!(0x{}),text:color!(0x{}),}},weak:Pair{{color:color!(0x{}),text:color!(0x{}),}},strong:Pair{{color:color!(0x{}),text:color!(0x{}),}},}},is_dark:true,}}", - color_to_hex(extended.background.base.color), - color_to_hex(extended.background.base.text), - color_to_hex(extended.background.weak.color), - color_to_hex(extended.background.weak.text), - color_to_hex(extended.background.strong.color), - color_to_hex(extended.background.strong.text), - color_to_hex(extended.primary.base.color), - color_to_hex(extended.primary.base.text), - color_to_hex(extended.primary.weak.color), - color_to_hex(extended.primary.weak.text), - color_to_hex(extended.primary.strong.color), - color_to_hex(extended.primary.strong.text), - color_to_hex(extended.secondary.base.color), - color_to_hex(extended.secondary.base.text), - color_to_hex(extended.secondary.weak.color), - color_to_hex(extended.secondary.weak.text), - color_to_hex(extended.secondary.strong.color), - color_to_hex(extended.secondary.strong.text), - color_to_hex(extended.success.base.color), - color_to_hex(extended.success.base.text), - color_to_hex(extended.success.weak.color), - color_to_hex(extended.success.weak.text), - color_to_hex(extended.success.strong.color), - color_to_hex(extended.success.strong.text), - color_to_hex(extended.danger.base.color), - color_to_hex(extended.danger.base.text), - color_to_hex(extended.danger.weak.color), - color_to_hex(extended.danger.weak.text), - color_to_hex(extended.danger.strong.color), - color_to_hex(extended.danger.strong.text), - color_to_hex(extended.warning.base.color), - color_to_hex(extended.warning.base.text), - color_to_hex(extended.warning.weak.color), - color_to_hex(extended.warning.weak.text), - color_to_hex(extended.warning.strong.color), - color_to_hex(extended.warning.strong.text), - ) -} - -pub fn theme_to_string(theme: &iced::Theme) -> String { - let palette = theme.palette(); - let extended = theme.extended_palette(); - - let generated_extended = Extended::generate(palette); - - if &generated_extended == extended { - format!( - r#"custom( - "{}".to_string(), - {} - )"#, - theme, - palette_to_string(&palette) - ) - } else { - format!( - r#"custom_with_fn( - "{}".to_string(), - {}, - |_| {} - )"#, - theme, - palette_to_string(&palette), - extended_to_string(extended) - ) - } -} - -fn color_to_hex(color: Color) -> String { - use std::fmt::Write; - - let mut hex = String::with_capacity(12); - - let [r, g, b, a] = color.into_rgba8(); - - let _ = write!(&mut hex, "{:02X}", r); - let _ = write!(&mut hex, "{:02X}", g); - let _ = write!(&mut hex, "{:02X}", b); - - if a < u8::MAX { - let _ = write!(&mut hex, ", {:.2}", a as f32 / 255.0); - } - - hex -} - #[derive(Debug, Clone)] pub struct Appearance { pub selected: iced::Theme, @@ -187,7 +80,158 @@ impl Default for Appearance { } } -#[derive(Debug, serde::Deserialize)] +#[derive(Debug, PartialEq, Deserialize)] +pub struct OtherTheme { + name: String, + #[serde(flatten)] + colorscheme: ColorScheme, +} + +impl Clone for OtherTheme { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + colorscheme: self.colorscheme, + } + } + + fn clone_from(&mut self, source: &Self) { + self.name = source.name.clone(); + self.colorscheme = source.colorscheme; + } +} + +impl Default for OtherTheme { + fn default() -> Self { + match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { + dark_light::Mode::Dark | dark_light::Mode::Unspecified => { + DARK.clone() + } + dark_light::Mode::Light => LIGHT.clone(), + } + } +} + +impl Base for OtherTheme { + fn base(&self) -> iced::theme::Style { + iced::theme::Style { + background_color: self.colorscheme.surface.surface, + text_color: self.colorscheme.surface.on_surface, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct ColorScheme { + pub primary: Primary, + pub secondary: Secondary, + pub tertiary: Tertiary, + pub error: Error, + pub surface: Surface, + pub inverse: Inverse, + pub outline: Outline, +} + +pub static DARK: LazyLock = LazyLock::new(|| { + toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") +}); + +pub static LIGHT: LazyLock = LazyLock::new(|| { + toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") +}); + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Primary { + #[serde(with = "color_serde")] + pub primary: Color, + #[serde(with = "color_serde")] + pub on_primary: Color, + #[serde(with = "color_serde")] + pub primary_container: Color, + #[serde(with = "color_serde")] + pub on_primary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Secondary { + #[serde(with = "color_serde")] + pub secondary: Color, + #[serde(with = "color_serde")] + pub on_secondary: Color, + #[serde(with = "color_serde")] + pub secondary_container: Color, + #[serde(with = "color_serde")] + pub on_secondary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Tertiary { + #[serde(with = "color_serde")] + pub tertiary: Color, + #[serde(with = "color_serde")] + pub on_tertiary: Color, + #[serde(with = "color_serde")] + pub tertiary_container: Color, + #[serde(with = "color_serde")] + pub on_tertiary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Error { + #[serde(with = "color_serde")] + pub error: Color, + #[serde(with = "color_serde")] + pub on_error: Color, + #[serde(with = "color_serde")] + pub error_container: Color, + #[serde(with = "color_serde")] + pub on_error_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Surface { + #[serde(with = "color_serde")] + pub surface: Color, + #[serde(with = "color_serde")] + pub on_surface: Color, + #[serde(with = "color_serde")] + pub on_surface_variant: Color, + pub surface_container: SurfaceContainer, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct SurfaceContainer { + #[serde(with = "color_serde")] + pub lowest: Color, + #[serde(with = "color_serde")] + pub low: Color, + #[serde(with = "color_serde")] + pub base: Color, + #[serde(with = "color_serde")] + pub high: Color, + #[serde(with = "color_serde")] + pub highest: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Inverse { + #[serde(with = "color_serde")] + pub inverse_surface: Color, + #[serde(with = "color_serde")] + pub inverse_on_surface: Color, + #[serde(with = "color_serde")] + pub inverse_primary: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Outline { + #[serde(with = "color_serde")] + pub outline: Color, + #[serde(with = "color_serde")] + pub outline_variant: Color, +} + +#[derive(Debug, Deserialize)] pub struct Theme { name: String, palette: ThemePalette, @@ -200,7 +244,7 @@ impl From for iced::Theme { fn from(value: Theme) -> Self { iced::Theme::custom_with_fn( value.name.clone(), - value.palette.clone().into(), + value.palette.into(), |_| value.into(), ) } @@ -208,11 +252,12 @@ impl From for iced::Theme { impl Default for Theme { fn default() -> Self { - toml::from_str(DEFAULT_THEME_CONTENT).expect("parse default theme") + toml::from_str(include_str!("../assets/themes/rose_pine.toml")) + .expect("parse default theme") } } -#[derive(Debug, Clone, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Deserialize)] pub struct ThemePalette { #[serde(with = "color_serde")] background: Color, @@ -341,7 +386,7 @@ impl From for Extended { } } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ExtendedThemePalette { background: Option, primary: Option, @@ -351,49 +396,49 @@ struct ExtendedThemePalette { warning: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemeBackground { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemePrimary { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemeSecondary { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemeSuccess { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemeDanger { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemeWarning { base: Option, weak: Option, strong: Option, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, Clone, Copy, Default, Deserialize)] struct ThemePair { #[serde(with = "color_serde")] color: Color, @@ -410,16 +455,56 @@ impl From for iced::theme::palette::Pair { } } +pub fn parse_argb(s: &str) -> Option { + let hex = s.strip_prefix('#').unwrap_or(s); + + let parse_channel = |from: usize, to: usize| { + let num = + usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; + + // If we only got half a byte (one letter), expand it into a full byte (two letters) + Some(if from == to { num + num * 16.0 } else { num }) + }; + + Some(match hex.len() { + 3 => Color::from_rgb( + parse_channel(0, 0)?, + parse_channel(1, 1)?, + parse_channel(2, 2)?, + ), + 4 => Color::from_rgba( + parse_channel(1, 1)?, + parse_channel(2, 2)?, + parse_channel(3, 3)?, + parse_channel(0, 0)?, + ), + 6 => Color::from_rgb( + parse_channel(0, 1)?, + parse_channel(2, 3)?, + parse_channel(4, 5)?, + ), + 8 => Color::from_rgba( + parse_channel(2, 3)?, + parse_channel(4, 5)?, + parse_channel(6, 7)?, + parse_channel(0, 1)?, + ), + _ => None?, + }) +} + mod color_serde { use iced::Color; use serde::{Deserialize, Deserializer}; + use super::parse_argb; + pub fn deserialize<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { Ok(String::deserialize(deserializer) - .map(|hex| Color::parse(&hex))? + .map(|hex| parse_argb(&hex))? .unwrap_or(Color::TRANSPARENT)) } } diff --git a/src/types/project.rs b/src/types/project.rs index 721783e..50cbb69 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -1,24 +1,19 @@ use std::path::{Path, PathBuf}; -use std::sync::Arc; extern crate fxhash; -use fxhash::FxHashMap; use iced::Theme; use rust_format::{Edition, Formatter, RustFmt}; use serde::{Deserialize, Serialize}; use super::rendered_element::RenderedElement; use crate::Error; -use crate::config::Config; -use crate::theme::{theme_from_str, theme_index, theme_to_string}; +use crate::theme::{theme_from_str, theme_index}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Project { pub title: Option, pub theme: Option, pub element_tree: Option, - #[serde(skip)] - theme_cache: FxHashMap, } impl Default for Project { @@ -33,45 +28,24 @@ impl Project { title: None, theme: None, element_tree: None, - theme_cache: FxHashMap::default(), } } - pub fn get_theme(&self, config: &Config) -> Theme { + pub fn get_theme(&self) -> Theme { match &self.theme { - Some(theme) => theme_from_str(Some(config), theme), + Some(theme) => theme_from_str(None, theme), None => Theme::default(), } } - fn theme_code(&mut self, theme: &Theme) -> String { - let theme_name = theme.to_string(); - if theme_index(&theme_name, Theme::ALL).is_none() { - (*self - .theme_cache - .entry(theme_name) - .or_insert(theme_to_string(theme))) - .to_string() - } else { - theme_name.replace(" ", "") - } - } - - pub async fn from_path( - path: PathBuf, - config: Arc, - ) -> Result<(PathBuf, Self), Error> { + pub async fn from_path(path: PathBuf) -> Result<(PathBuf, Self), Error> { let contents = tokio::fs::read_to_string(&path).await?; - let mut project: Self = serde_json::from_str(&contents)?; - - let _ = project.theme_code(&project.get_theme(&config)); + let project: Self = serde_json::from_str(&contents)?; Ok((path, project)) } - pub async fn from_file( - config: Arc, - ) -> Result<(PathBuf, Self), Error> { + pub async fn from_file() -> Result<(PathBuf, Self), Error> { let picked_file = rfd::AsyncFileDialog::new() .set_title("Open a JSON file...") .add_filter("*.json, *.JSON", &["json", "JSON"]) @@ -81,7 +55,7 @@ impl Project { let path = picked_file.path().to_owned(); - Self::from_path(path, config).await + Self::from_path(path).await } pub async fn write_to_file( @@ -108,12 +82,12 @@ impl Project { Ok(path) } - pub fn app_code(&mut self, config: &Config) -> Result { + pub fn app_code(&mut self) -> Result { match self.element_tree { Some(ref element_tree) => { let (imports, view) = element_tree.codegen(); - let theme = self.get_theme(config); - let theme_code = self.theme_code(&theme); + let theme = self.get_theme(); + let theme_code = theme.to_string().replace(" ", ""); let mut theme_imports = ""; if theme_index(&theme.to_string(), Theme::ALL).is_none() { if theme_code.contains("Extended") { -- cgit v1.2.3 From bbc151e82b86bf2d7114f0ea05cde7e8858ba610 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 30 Mar 2025 20:16:48 +0200 Subject: feat: add shadow color, impl `button::Catalog` and `text::Catalog` --- assets/themes/dark.toml | 16 ++-- assets/themes/light.toml | 16 ++-- src/main.rs | 20 +++++ src/theme.rs | 21 ++++-- src/theme/button.rs | 189 +++++++++++++++++++++++++++++++++++++++++++++++ src/theme/text.rs | 50 +++++++++++++ 6 files changed, 290 insertions(+), 22 deletions(-) create mode 100644 src/theme/button.rs create mode 100644 src/theme/text.rs diff --git a/assets/themes/dark.toml b/assets/themes/dark.toml index a3bde68..3c02ce8 100644 --- a/assets/themes/dark.toml +++ b/assets/themes/dark.toml @@ -1,31 +1,33 @@ name = "Dark" +shadow = "#000000" + [primary] -primary = "#6200ee" +color = "#6200ee" on_primary = "#ffffff" primary_container = "#3700b3" on_primary_container = "#ffffff" [secondary] -secondary = "#03dac6" +color = "#03dac6" on_secondary = "#ffffff" secondary_container = "#018786" on_secondary_container = "#ffffff" [tertiary] -tertiary = "#bb86fc" +color = "#bb86fc" on_tertiary = "#000000" tertiary_container = "#6200ee" on_tertiary_container = "#000000" [error] -error = "#b00020" +color = "#b00020" on_error = "#ffffff" error_container = "#cf6679" on_error_container = "#000000" [surface] -surface = "#121212" +color = "#121212" on_surface = "#ffffff" on_surface_variant = "#b0b0b0" @@ -42,5 +44,5 @@ inverse_on_surface = "#ffffff" inverse_primary = "#bb86fc" [outline] -outline = "#737373" -outline_variant = "#aaaaaa" +color = "#737373" +variant = "#aaaaaa" diff --git a/assets/themes/light.toml b/assets/themes/light.toml index 4852b8b..2842c82 100644 --- a/assets/themes/light.toml +++ b/assets/themes/light.toml @@ -1,31 +1,33 @@ name = "Dark" +shadow = "#000000" + [primary] -primary = "#6200ee" +color = "#6200ee" on_primary = "#ffffff" primary_container = "#e1bee7" on_primary_container = "#000000" [secondary] -secondary = "#03dac6" +color = "#03dac6" on_secondary = "#ffffff" secondary_container = "#018786" on_secondary_container = "#ffffff" [tertiary] -tertiary = "#bb86fc" +color = "#bb86fc" on_tertiary = "#000000" tertiary_container = "#6200ee" on_tertiary_container = "#000000" [error] -error = "#b00020" +color = "#b00020" on_error = "#ffffff" error_container = "#cf6679" on_error_container = "#000000" [surface] -surface = "#ffffff" +color = "#ffffff" on_surface = "#000000" on_surface_variant = "#757575" @@ -42,5 +44,5 @@ inverse_on_surface = "#ffffff" inverse_primary = "#bb86fc" [outline] -outline = "#757575" -outline_variant = "#b0b0b0" +color = "#757575" +variant = "#b0b0b0" diff --git a/src/main.rs b/src/main.rs index c8a60c6..7728e63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,8 @@ use types::{ Project, }; +//pub type Element<'a, Message> = iced::Element<'a, Message, OtherTheme>; + fn main() -> Result<(), Box> { let version = std::env::args() .nth(1) @@ -58,7 +60,9 @@ fn main() -> Result<(), Box> { iced::application(App::title, App::update, App::view) .font(icon::FONT) .theme(|state| state.theme.value().clone()) + //.theme(|_| theme::LIGHT.clone()) .subscription(App::subscription) + .antialiasing(true) .run_with(move || App::new(config_load))?; Ok(()) } @@ -445,5 +449,21 @@ impl App { Animation::new(&self.theme, content) .on_update(Message::SwitchTheme) .into() + //row![ + // button("filled") + // .style(theme::button::filled) + // .on_press(Message::RefreshEditorContent), + // button("elevated") + // .style(theme::button::elevated) + // .on_press(Message::RefreshEditorContent), + // button("filled tonal") + // .style(theme::button::filled_tonal) + // .on_press(Message::RefreshEditorContent), + // button("outlined") + // .style(theme::button::outlined) + // .on_press(Message::RefreshEditorContent), + //] + //.spacing(10) + //.into() } } diff --git a/src/theme.rs b/src/theme.rs index 3e6092b..6fe844c 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,3 +1,6 @@ +pub mod button; +pub mod text; + use std::sync::{Arc, LazyLock}; use iced::Color; @@ -115,7 +118,7 @@ impl Default for OtherTheme { impl Base for OtherTheme { fn base(&self) -> iced::theme::Style { iced::theme::Style { - background_color: self.colorscheme.surface.surface, + background_color: self.colorscheme.surface.color, text_color: self.colorscheme.surface.on_surface, } } @@ -130,6 +133,8 @@ pub struct ColorScheme { pub surface: Surface, pub inverse: Inverse, pub outline: Outline, + #[serde(with = "color_serde")] + pub shadow: Color, } pub static DARK: LazyLock = LazyLock::new(|| { @@ -143,7 +148,7 @@ pub static LIGHT: LazyLock = LazyLock::new(|| { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Primary { #[serde(with = "color_serde")] - pub primary: Color, + pub color: Color, #[serde(with = "color_serde")] pub on_primary: Color, #[serde(with = "color_serde")] @@ -155,7 +160,7 @@ pub struct Primary { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Secondary { #[serde(with = "color_serde")] - pub secondary: Color, + pub color: Color, #[serde(with = "color_serde")] pub on_secondary: Color, #[serde(with = "color_serde")] @@ -167,7 +172,7 @@ pub struct Secondary { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Tertiary { #[serde(with = "color_serde")] - pub tertiary: Color, + pub color: Color, #[serde(with = "color_serde")] pub on_tertiary: Color, #[serde(with = "color_serde")] @@ -179,7 +184,7 @@ pub struct Tertiary { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Error { #[serde(with = "color_serde")] - pub error: Color, + pub color: Color, #[serde(with = "color_serde")] pub on_error: Color, #[serde(with = "color_serde")] @@ -191,7 +196,7 @@ pub struct Error { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Surface { #[serde(with = "color_serde")] - pub surface: Color, + pub color: Color, #[serde(with = "color_serde")] pub on_surface: Color, #[serde(with = "color_serde")] @@ -226,9 +231,9 @@ pub struct Inverse { #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Outline { #[serde(with = "color_serde")] - pub outline: Color, + pub color: Color, #[serde(with = "color_serde")] - pub outline_variant: Color, + pub variant: Color, } #[derive(Debug, Deserialize)] diff --git a/src/theme/button.rs b/src/theme/button.rs new file mode 100644 index 0000000..ddd2c71 --- /dev/null +++ b/src/theme/button.rs @@ -0,0 +1,189 @@ +#![allow(dead_code)] +use iced::widget::button::{Catalog, Status, Style, StyleFn}; +use iced::{Background, Border, Color, Shadow, Vector}; + +use super::OtherTheme; + +impl Catalog for OtherTheme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +fn default(theme: &OtherTheme, status: Status) -> Style { + filled(theme, status) +} + +fn button( + foreground: Color, + background: Color, + background_hover: Color, + disabled: Color, + shadow_color: Color, + shadow_elevation: u8, + status: Status, +) -> Style { + let border = Border { + radius: 400.0.into(), + ..Default::default() + }; + + let elevation_to_offset = |elevation: u8| { + (match elevation { + 0 => 0.0, + 1 => 1.0, + 2 => 3.0, + 3 => 6.0, + 4 => 8.0, + _ => 12.0, + } as f32) + }; + + match status { + Status::Active | Status::Pressed => Style { + background: Some(Background::Color(background)), + text_color: foreground, + border, + shadow: Shadow { + color: shadow_color, + offset: Vector { + x: 0.0, + y: elevation_to_offset(shadow_elevation), + }, + blur_radius: elevation_to_offset(shadow_elevation) + * (1.0 + + 0.4_f32.powf(elevation_to_offset(shadow_elevation))), + }, + }, + Status::Hovered => Style { + background: Some(Background::Color(background_hover)), + text_color: foreground, + border, + shadow: Shadow { + color: shadow_color, + offset: Vector { + x: 0.0, + y: elevation_to_offset(shadow_elevation + 1), + }, + blur_radius: (elevation_to_offset(shadow_elevation + 1)) + * (1.0 + + 0.4_f32 + .powf(elevation_to_offset(shadow_elevation + 1))), + }, + }, + Status::Disabled => Style { + background: Some(Background::Color(Color { + a: 0.12, + ..disabled + })), + text_color: Color { + a: 0.38, + ..disabled + }, + border, + ..Default::default() + }, + } +} + +pub fn elevated(theme: &OtherTheme, status: Status) -> Style { + let surface_colors = theme.colorscheme.surface; + + let foreground = theme.colorscheme.primary.color; + let background = surface_colors.surface_container.low; + let disabled = surface_colors.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + background, + disabled, + shadow_color, + 1, + status, + ) +} + +pub fn filled(theme: &OtherTheme, status: Status) -> Style { + let primary_colors = theme.colorscheme.primary; + + let foreground = primary_colors.on_primary; + let background = primary_colors.color; + let disabled = theme.colorscheme.surface.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + background, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn filled_tonal(theme: &OtherTheme, status: Status) -> Style { + let secondary_colors = theme.colorscheme.secondary; + + let foreground = secondary_colors.on_secondary_container; + let background = secondary_colors.secondary_container; + let disabled = theme.colorscheme.surface.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + background, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn outlined(theme: &OtherTheme, status: Status) -> Style { + let foreground = theme.colorscheme.primary.color; + let background = Color::TRANSPARENT; + let disabled = theme.colorscheme.surface.on_surface; + + let outline = theme.colorscheme.outline.color; + + let border = match status { + Status::Active | Status::Pressed | Status::Hovered => Border { + color: outline, + width: 1.0, + radius: 400.0.into(), + }, + Status::Disabled => Border { + color: Color { + a: 0.12, + ..disabled + }, + width: 1.0, + radius: 400.0.into(), + }, + }; + + let style = button( + foreground, + background, + background, + disabled, + Color::TRANSPARENT, + 0, + status, + ); + + Style { border, ..style } +} diff --git a/src/theme/text.rs b/src/theme/text.rs new file mode 100644 index 0000000..9cbd056 --- /dev/null +++ b/src/theme/text.rs @@ -0,0 +1,50 @@ +#![allow(dead_code)] +use iced::widget::text::{Catalog, Style, StyleFn}; + +use super::OtherTheme; + +impl Catalog for OtherTheme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(none) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn none(_: &OtherTheme) -> Style { + Style { color: None } +} + +pub fn primary(theme: &OtherTheme) -> Style { + Style { + color: Some(theme.colorscheme.primary.on_primary), + } +} + +pub fn secondary(theme: &OtherTheme) -> Style { + Style { + color: Some(theme.colorscheme.secondary.on_secondary), + } +} + +pub fn tertiary(theme: &OtherTheme) -> Style { + Style { + color: Some(theme.colorscheme.tertiary.on_tertiary), + } +} + +pub fn error(theme: &OtherTheme) -> Style { + Style { + color: Some(theme.colorscheme.error.on_error), + } +} + +pub fn surface(theme: &OtherTheme) -> Style { + Style { + color: Some(theme.colorscheme.surface.on_surface), + } +} -- cgit v1.2.3 From 1aeba3cbd0ae7b53ffd2c47f325864e3ec3b0210 Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 31 Mar 2025 01:05:24 +0200 Subject: fix: merge conflict blobs [skip ci] --- src/main.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7728e63..63e9deb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -174,15 +174,12 @@ impl App { self.editor_content.perform(action); } } - Message::RefreshEditorContent => { - match self.project.app_code(&self.config) { - Ok(code) => { - self.editor_content = - text_editor::Content::with_text(&code); - } - Err(error) => return error_dialog(error), + Message::RefreshEditorContent => match self.project.app_code() { + Ok(code) => { + self.editor_content = + text_editor::Content::with_text(&code); } - Err(error) => Task::future(error_dialog(error)).discard(), + Err(error) => return error_dialog(error), }, Message::DropNewElement(name, point, _) => { return iced_drop::zones_on_point( @@ -279,7 +276,7 @@ impl App { self.is_dirty = false; self.is_loading = true; return Task::perform( - Project::from_file(self.config.clone()), + Project::from_file(), Message::FileOpened, ) .chain(close_dialog_task); @@ -309,7 +306,7 @@ impl App { self.is_loading = true; return Task::perform( - Project::from_file(self.config.clone()), + Project::from_file(), Message::FileOpened, ); } else { -- cgit v1.2.3 From e9af14434454e8512e99612271b557789f28deeb Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 7 Apr 2025 02:05:39 +0200 Subject: refactor: move custom theme into its separate crate --- Cargo.lock | 20 ++- Cargo.toml | 27 ++-- assets/themes/dark.toml | 48 ------- assets/themes/light.toml | 48 ------- material_theme/Cargo.toml | 40 ++++++ material_theme/assets/themes/dark.toml | 48 +++++++ material_theme/assets/themes/light.toml | 48 +++++++ material_theme/src/button.rs | 209 +++++++++++++++++++++++++++++ material_theme/src/container.rs | 173 ++++++++++++++++++++++++ material_theme/src/lib.rs | 229 ++++++++++++++++++++++++++++++++ material_theme/src/text.rs | 86 ++++++++++++ material_theme/src/utils.rs | 61 +++++++++ src/main.rs | 19 --- src/theme.rs | 162 +--------------------- src/theme/button.rs | 189 -------------------------- src/theme/text.rs | 50 ------- theme_test/Cargo.toml | 8 ++ theme_test/src/main.rs | 89 +++++++++++++ 18 files changed, 1029 insertions(+), 525 deletions(-) delete mode 100644 assets/themes/dark.toml delete mode 100644 assets/themes/light.toml create mode 100644 material_theme/Cargo.toml create mode 100644 material_theme/assets/themes/dark.toml create mode 100644 material_theme/assets/themes/light.toml create mode 100644 material_theme/src/button.rs create mode 100644 material_theme/src/container.rs create mode 100644 material_theme/src/lib.rs create mode 100644 material_theme/src/text.rs create mode 100644 material_theme/src/utils.rs delete mode 100644 src/theme/button.rs delete mode 100644 src/theme/text.rs create mode 100644 theme_test/Cargo.toml create mode 100644 theme_test/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index e92c3fc..2dc8556 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1971,7 +1971,6 @@ dependencies = [ name = "iced_builder" version = "0.1.0" dependencies = [ - "dark-light", "dirs-next", "embed-resource 3.0.2", "fxhash", @@ -1981,6 +1980,7 @@ dependencies = [ "iced_dialog", "iced_drop", "iced_fontello", + "material_theme", "rfd", "rust-format", "serde", @@ -2673,6 +2673,16 @@ dependencies = [ "libc", ] +[[package]] +name = "material_theme" +version = "0.14.0-dev" +dependencies = [ + "dark-light", + "iced_widget", + "serde", + "toml", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -4634,6 +4644,14 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "theme_test" +version = "0.0.1" +dependencies = [ + "iced", + "material_theme", +] + [[package]] name = "thiserror" version = "1.0.69" diff --git a/Cargo.toml b/Cargo.toml index 39e69af..33d3b8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,23 +16,28 @@ debug = ["iced/debug"] [dependencies] iced.workspace = true -iced_anim = { git = "https://github.com/pml68/iced_anim", features = ["derive"] } +iced_anim.workspace = true iced_custom_highlighter = { git = "https://github.com/pml68/iced_custom_highlighter", branch = "master" } iced_drop = { path = "iced_drop" } iced_dialog = { git = "https://github.com/pml68/iced_dialog", branch = "iced/personal" } -serde = { version = "1.0.217", features = ["derive"] } -serde_json = "1.0.138" -toml = "0.8.20" -tokio = { version = "1.43", features = ["fs"] } +material_theme = { path = "material_theme" } +serde.workspace = true +serde_json = "1.0.140" +toml.workspace = true +tokio = { version = "1.42.1", features = ["fs"] } tokio-stream = { version = "0.1", features = ["fs"] } # TODO: enable tokio when it actually compiles # rfd = { version = "0.15.2", default-features = false, features = ["tokio", "xdg-portal"] } rfd = "0.15.3" rust-format = "0.3.4" fxhash = "0.2.1" -thiserror = "2.0.11" +thiserror = "2.0.12" dirs-next = "2.0.0" -dark-light = "2.0.0" + +[workspace.dependencies] +iced_anim = { version = "0.2.1", features = ["derive"] } +serde = { version = "1.0.219", features = ["derive"] } +toml = "0.8.20" [workspace.dependencies.iced] git = "https://github.com/pml68/iced" @@ -46,7 +51,7 @@ iced_fontello = "0.13.2" xdg = "2.5.2" [target.'cfg(windows)'.build-dependencies] -embed-resource = "3.0.1" +embed-resource = "3.0.2" windows_exe_info = "0.5" [profile.dev] @@ -68,7 +73,7 @@ name = "iced-builder" path = "src/main.rs" [workspace] -members = ["iced_drop"] +members = ["iced_drop", "material_theme", "theme_test"] [lints.rust] missing_debug_implementations = "deny" @@ -89,3 +94,7 @@ from_over_into = "deny" needless_borrow = "deny" new_without_default = "deny" useless_conversion = "deny" + +[patch.crates-io] +iced_anim = { git = "https://github.com/pml68/iced_anim" } +iced_widget = { git = "https://github.com/pml68/iced", branch = "feat/rehighlight-on-redraw" } diff --git a/assets/themes/dark.toml b/assets/themes/dark.toml deleted file mode 100644 index 3c02ce8..0000000 --- a/assets/themes/dark.toml +++ /dev/null @@ -1,48 +0,0 @@ -name = "Dark" - -shadow = "#000000" - -[primary] -color = "#6200ee" -on_primary = "#ffffff" -primary_container = "#3700b3" -on_primary_container = "#ffffff" - -[secondary] -color = "#03dac6" -on_secondary = "#ffffff" -secondary_container = "#018786" -on_secondary_container = "#ffffff" - -[tertiary] -color = "#bb86fc" -on_tertiary = "#000000" -tertiary_container = "#6200ee" -on_tertiary_container = "#000000" - -[error] -color = "#b00020" -on_error = "#ffffff" -error_container = "#cf6679" -on_error_container = "#000000" - -[surface] -color = "#121212" -on_surface = "#ffffff" -on_surface_variant = "#b0b0b0" - -[surface.surface_container] -lowest = "#1e1e2e" -low = "#333333" -base = "#444444" -high = "#555555" -highest = "#666666" - -[inverse] -inverse_surface = "#212121" -inverse_on_surface = "#ffffff" -inverse_primary = "#bb86fc" - -[outline] -color = "#737373" -variant = "#aaaaaa" diff --git a/assets/themes/light.toml b/assets/themes/light.toml deleted file mode 100644 index 2842c82..0000000 --- a/assets/themes/light.toml +++ /dev/null @@ -1,48 +0,0 @@ -name = "Dark" - -shadow = "#000000" - -[primary] -color = "#6200ee" -on_primary = "#ffffff" -primary_container = "#e1bee7" -on_primary_container = "#000000" - -[secondary] -color = "#03dac6" -on_secondary = "#ffffff" -secondary_container = "#018786" -on_secondary_container = "#ffffff" - -[tertiary] -color = "#bb86fc" -on_tertiary = "#000000" -tertiary_container = "#6200ee" -on_tertiary_container = "#000000" - -[error] -color = "#b00020" -on_error = "#ffffff" -error_container = "#cf6679" -on_error_container = "#000000" - -[surface] -color = "#ffffff" -on_surface = "#000000" -on_surface_variant = "#757575" - -[surface.surface_container] -lowest = "#fafafa" -low = "#eeeeee" -base = "#dddddd" -high = "#cccccc" -highest = "#bbbbbb" - -[inverse] -inverse_surface = "#121212" -inverse_on_surface = "#ffffff" -inverse_primary = "#bb86fc" - -[outline] -color = "#757575" -variant = "#b0b0b0" diff --git a/material_theme/Cargo.toml b/material_theme/Cargo.toml new file mode 100644 index 0000000..0597d78 --- /dev/null +++ b/material_theme/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "material_theme" +description = "An M3 inspired theme for `iced`" +authors = ["pml68 "] +version = "0.14.0-dev" +edition = "2024" +license = "MIT" +# readme = "README.md" +repository = "https://github.com/pml68/iced_builder" +categories = ["gui"] +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +rust-version = "1.85" + +[dependencies] +iced_widget = "0.14.0-dev" +serde.workspace = true +toml.workspace = true +dark-light = "2.0.0" + +[lints.rust] +unsafe_code = "deny" +unused_results = "deny" + +[lints.clippy] +type-complexity = "allow" +semicolon_if_nothing_returned = "deny" +trivially-copy-pass-by-ref = "deny" +default_trait_access = "deny" +match-wildcard-for-single-variants = "deny" +redundant-closure-for-method-calls = "deny" +filter_map_next = "deny" +manual_let_else = "deny" +unused_async = "deny" +from_over_into = "deny" +needless_borrow = "deny" +new_without_default = "deny" +useless_conversion = "deny" + +[lints.rustdoc] +broken_intra_doc_links = "forbid" diff --git a/material_theme/assets/themes/dark.toml b/material_theme/assets/themes/dark.toml new file mode 100644 index 0000000..4d23fc8 --- /dev/null +++ b/material_theme/assets/themes/dark.toml @@ -0,0 +1,48 @@ +name = "Dark" + +shadow = "#000000" + +[primary] +color = "#9bd4a1" +on_primary = "#003916" +primary_container = "#1b5129" +on_primary_container = "#b6f1bb" + +[secondary] +color = "#b8ccb6" +on_secondary = "#233425" +secondary_container = "#394b3a" +on_secondary_container = "#d3e8d1" + +[tertiary] +color = "#a1ced7" +on_tertiary = "#00363e" +tertiary_container = "#1f4d55" +on_tertiary_container = "#bdeaf4" + +[error] +color = "#ffb4ab" +on_error = "#690005" +error_container = "#93000a" +on_error_container = "#ffdad6" + +[surface] +color = "#101510" +on_surface = "#e0e4dc" +on_surface_variant = "#c1c9be" + +[surface.surface_container] +lowest = "#0b0f0b" +low = "#181d18" +base = "#1c211c" +high = "#262b26" +highest = "#313631" + +[inverse] +inverse_surface = "#e0e4dc" +inverse_on_surface = "#2d322c" +inverse_primary = "#34693f" + +[outline] +color = "#8b9389" +variant = "#414941" diff --git a/material_theme/assets/themes/light.toml b/material_theme/assets/themes/light.toml new file mode 100644 index 0000000..5288c84 --- /dev/null +++ b/material_theme/assets/themes/light.toml @@ -0,0 +1,48 @@ +name = "Light" + +shadow = "#000000" + +[primary] +color = "#34693f" +on_primary = "#ffffff" +primary_container = "#b6f1bb" +on_primary_container = "#1b5129" + +[secondary] +color = "#516351" +on_secondary = "#ffffff" +secondary_container = "#d3e8d1" +on_secondary_container = "#394b3a" + +[tertiary] +color = "#39656d" +on_tertiary = "#ffffff" +tertiary_container = "#bdeaf4" +on_tertiary_container = "#1f4d55" + +[error] +color = "#ba1a1a" +on_error = "#ffffff" +error_container = "#ffdad6" +on_error_container = "#93000a" + +[surface] +color = "#f7fbf2" +on_surface = "#181d18" +on_surface_variant = "#414941" + +[surface.surface_container] +lowest = "#ffffff" +low = "#f1f5ed" +base = "#ebefe7" +high = "#e5e9e1" +highest = "#e0e4dc" + +[inverse] +inverse_surface = "#2d322c" +inverse_on_surface = "#eef2ea" +inverse_primary = "#9bd4a1" + +[outline] +color = "#727970" +variant = "#c1c9be" diff --git a/material_theme/src/button.rs b/material_theme/src/button.rs new file mode 100644 index 0000000..051d6c9 --- /dev/null +++ b/material_theme/src/button.rs @@ -0,0 +1,209 @@ +#![allow(dead_code)] +use iced_widget::button::{Catalog, Status, Style, StyleFn}; +use iced_widget::core::{Background, Border, Color, Shadow, Vector}; + +use crate::Theme; +use crate::utils::{elevation, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(filled) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +fn button( + foreground: Color, + background: Color, + tone_overlay: Color, + disabled: Color, + shadow_color: Color, + shadow_elevation: u8, + status: Status, +) -> Style { + let border = Border { + radius: 400.into(), + ..Default::default() + }; + + let active = Style { + background: Some(Background::Color(background)), + text_color: foreground, + border, + shadow: Shadow { + color: shadow_color, + offset: Vector { + x: 0.0, + y: elevation(shadow_elevation), + }, + blur_radius: elevation(shadow_elevation) + * (1.0 + 0.4_f32.powf(elevation(shadow_elevation))), + }, + }; + + match status { + Status::Active => active, + Status::Pressed => Style { + background: Some(Background::Color(mix( + background, + tone_overlay, + 0.08, + ))), + ..active + }, + Status::Hovered => Style { + background: Some(Background::Color(mix( + background, + tone_overlay, + 0.1, + ))), + text_color: foreground, + border, + shadow: Shadow { + color: shadow_color, + offset: Vector { + x: 0.0, + y: elevation(shadow_elevation + 1), + }, + blur_radius: (elevation(shadow_elevation + 1)) + * (1.0 + 0.4_f32.powf(elevation(shadow_elevation + 1))), + }, + }, + Status::Disabled => Style { + background: Some(Background::Color(Color { + a: 0.12, + ..disabled + })), + text_color: Color { + a: 0.38, + ..disabled + }, + border, + ..Default::default() + }, + } +} + +pub fn elevated(theme: &Theme, status: Status) -> Style { + let surface_colors = theme.colorscheme.surface; + + let foreground = theme.colorscheme.primary.color; + let background = surface_colors.surface_container.low; + let disabled = surface_colors.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 1, + status, + ) +} + +pub fn filled(theme: &Theme, status: Status) -> Style { + let primary_colors = theme.colorscheme.primary; + + let foreground = primary_colors.on_primary; + let background = primary_colors.color; + let disabled = theme.colorscheme.surface.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn filled_tonal(theme: &Theme, status: Status) -> Style { + let secondary_colors = theme.colorscheme.secondary; + + let foreground = secondary_colors.on_secondary_container; + let background = secondary_colors.secondary_container; + let disabled = theme.colorscheme.surface.on_surface; + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn outlined(theme: &Theme, status: Status) -> Style { + let foreground = theme.colorscheme.primary.color; + let background = Color::TRANSPARENT; + let disabled = theme.colorscheme.surface.on_surface; + + let outline = theme.colorscheme.outline.color; + + let border = match status { + Status::Active | Status::Pressed | Status::Hovered => Border { + color: outline, + width: 1.0, + radius: 400.0.into(), + }, + Status::Disabled => Border { + color: Color { + a: 0.12, + ..disabled + }, + width: 1.0, + radius: 400.0.into(), + }, + }; + + let style = button( + foreground, + background, + foreground, + disabled, + Color::TRANSPARENT, + 0, + status, + ); + + Style { border, ..style } +} + +pub fn text(theme: &Theme, status: Status) -> Style { + let foreground = theme.colorscheme.primary.color; + let background = Color::TRANSPARENT; + let disabled = theme.colorscheme.surface.on_surface; + + let style = button( + foreground, + background, + foreground, + disabled, + Color::TRANSPARENT, + 0, + status, + ); + + match status { + Status::Hovered | Status::Pressed => style, + _ => Style { + background: None, + ..style + }, + } +} diff --git a/material_theme/src/container.rs b/material_theme/src/container.rs new file mode 100644 index 0000000..a14cfd5 --- /dev/null +++ b/material_theme/src/container.rs @@ -0,0 +1,173 @@ +use iced_widget::container::{Catalog, Style, StyleFn}; +use iced_widget::core::{Background, border}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(transparent) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn transparent(_theme: &Theme) -> Style { + Style { + border: border::rounded(4), + ..Style::default() + } +} + +pub fn primary(theme: &Theme) -> Style { + let colors = theme.colorscheme.primary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_primary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn primary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.primary; + Style { + background: Some(Background::Color(colors.primary_container)), + text_color: Some(colors.on_primary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn secondary(theme: &Theme) -> Style { + let colors = theme.colorscheme.secondary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_secondary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn secondary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.secondary; + Style { + background: Some(Background::Color(colors.secondary_container)), + text_color: Some(colors.on_secondary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn tertiary(theme: &Theme) -> Style { + let colors = theme.colorscheme.tertiary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_tertiary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn tertiary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.tertiary; + Style { + background: Some(Background::Color(colors.tertiary_container)), + text_color: Some(colors.on_tertiary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn error(theme: &Theme) -> Style { + let colors = theme.colorscheme.error; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_error), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn error_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.error; + Style { + background: Some(Background::Color(colors.error_container)), + text_color: Some(colors.on_error_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_surface), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn surface_container_lowest(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.lowest)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_low(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.low)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.base)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_high(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.high)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_highest(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.highest)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn inverse_surface(theme: &Theme) -> Style { + let colors = theme.colorscheme.inverse; + Style { + background: Some(Background::Color(colors.inverse_surface)), + text_color: Some(colors.inverse_on_surface), + border: border::rounded(4), + ..Style::default() + } +} diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs new file mode 100644 index 0000000..6641b74 --- /dev/null +++ b/material_theme/src/lib.rs @@ -0,0 +1,229 @@ +use std::sync::LazyLock; + +use iced_widget::core::Color; +use iced_widget::core::theme::{Base, Style}; +use serde::Deserialize; + +pub mod button; +pub mod container; +pub mod text; +pub mod utils; + +const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); +const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); + +#[derive(Debug, PartialEq, Deserialize)] +pub struct Theme { + pub name: String, + #[serde(flatten)] + pub colorscheme: ColorScheme, +} + +impl Theme { + pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { + Self { + name: name.into(), + colorscheme, + } + } +} + +impl Clone for Theme { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + colorscheme: self.colorscheme, + } + } + + fn clone_from(&mut self, source: &Self) { + self.name = source.name.clone(); + self.colorscheme = source.colorscheme; + } +} + +impl Default for Theme { + fn default() -> Self { + match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { + dark_light::Mode::Dark | dark_light::Mode::Unspecified => { + DARK.clone() + } + dark_light::Mode::Light => LIGHT.clone(), + } + } +} + +impl Base for Theme { + fn base(&self) -> Style { + Style { + background_color: self.colorscheme.surface.color, + text_color: self.colorscheme.surface.on_surface, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct ColorScheme { + pub primary: Primary, + pub secondary: Secondary, + pub tertiary: Tertiary, + pub error: Error, + pub surface: Surface, + pub inverse: Inverse, + pub outline: Outline, + #[serde(with = "color_serde")] + pub shadow: Color, +} + +pub static DARK: LazyLock = LazyLock::new(|| { + toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") +}); + +pub static LIGHT: LazyLock = LazyLock::new(|| { + toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") +}); + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Primary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_primary: Color, + #[serde(with = "color_serde")] + pub primary_container: Color, + #[serde(with = "color_serde")] + pub on_primary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Secondary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_secondary: Color, + #[serde(with = "color_serde")] + pub secondary_container: Color, + #[serde(with = "color_serde")] + pub on_secondary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Tertiary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_tertiary: Color, + #[serde(with = "color_serde")] + pub tertiary_container: Color, + #[serde(with = "color_serde")] + pub on_tertiary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Error { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_error: Color, + #[serde(with = "color_serde")] + pub error_container: Color, + #[serde(with = "color_serde")] + pub on_error_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Surface { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_surface: Color, + #[serde(with = "color_serde")] + pub on_surface_variant: Color, + pub surface_container: SurfaceContainer, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct SurfaceContainer { + #[serde(with = "color_serde")] + pub lowest: Color, + #[serde(with = "color_serde")] + pub low: Color, + #[serde(with = "color_serde")] + pub base: Color, + #[serde(with = "color_serde")] + pub high: Color, + #[serde(with = "color_serde")] + pub highest: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Inverse { + #[serde(with = "color_serde")] + pub inverse_surface: Color, + #[serde(with = "color_serde")] + pub inverse_on_surface: Color, + #[serde(with = "color_serde")] + pub inverse_primary: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +pub struct Outline { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub variant: Color, +} + +pub fn parse_argb(s: &str) -> Option { + let hex = s.strip_prefix('#').unwrap_or(s); + + let parse_channel = |from: usize, to: usize| { + let num = + usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; + + // If we only got half a byte (one letter), expand it into a full byte (two letters) + Some(if from == to { num + num * 16.0 } else { num }) + }; + + Some(match hex.len() { + 3 => Color::from_rgb( + parse_channel(0, 0)?, + parse_channel(1, 1)?, + parse_channel(2, 2)?, + ), + 4 => Color::from_rgba( + parse_channel(1, 1)?, + parse_channel(2, 2)?, + parse_channel(3, 3)?, + parse_channel(0, 0)?, + ), + 6 => Color::from_rgb( + parse_channel(0, 1)?, + parse_channel(2, 3)?, + parse_channel(4, 5)?, + ), + 8 => Color::from_rgba( + parse_channel(2, 3)?, + parse_channel(4, 5)?, + parse_channel(6, 7)?, + parse_channel(0, 1)?, + ), + _ => None?, + }) +} + +mod color_serde { + use iced_widget::core::Color; + use serde::{Deserialize, Deserializer}; + + use super::parse_argb; + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(String::deserialize(deserializer) + .map(|hex| parse_argb(&hex))? + .unwrap_or(Color::TRANSPARENT)) + } +} diff --git a/material_theme/src/text.rs b/material_theme/src/text.rs new file mode 100644 index 0000000..10b2e65 --- /dev/null +++ b/material_theme/src/text.rs @@ -0,0 +1,86 @@ +#![allow(dead_code)] +use iced_widget::text::{Catalog, Style, StyleFn}; + +use crate::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(none) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn none(_: &Theme) -> Style { + Style { color: None } +} + +pub fn primary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.primary.on_primary), + } +} + +pub fn primary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.primary.on_primary_container), + } +} + +pub fn secondary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.secondary.on_secondary), + } +} + +pub fn secondary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.secondary.on_secondary_container), + } +} + +pub fn tertiary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.tertiary.on_tertiary), + } +} + +pub fn tertiary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.tertiary.on_tertiary_container), + } +} + +pub fn error(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.error.on_error), + } +} + +pub fn error_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.error.on_error_container), + } +} + +pub fn surface(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.surface.on_surface), + } +} + +pub fn surface_variant(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.surface.on_surface_variant), + } +} + +pub fn inverse_surface(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.inverse.inverse_on_surface), + } +} diff --git a/material_theme/src/utils.rs b/material_theme/src/utils.rs new file mode 100644 index 0000000..c9eb78e --- /dev/null +++ b/material_theme/src/utils.rs @@ -0,0 +1,61 @@ +use iced_widget::core::Color; + +pub fn elevation(elevation_level: u8) -> f32 { + (match elevation_level { + 0 => 0.0, + 1 => 1.0, + 2 => 3.0, + 3 => 6.0, + 4 => 8.0, + _ => 12.0, + } as f32) +} + +pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { + if p2 <= 0.0 { + return color1; + } else if p2 >= 1.0 { + return color2; + } + + let p1 = 1.0 - p2; + + if color1.a != 1.0 || color2.a != 1.0 { + let a = color1.a * p1 + color2.a * p2; + if a > 0.0 { + let c1 = color1.into_linear().map(|c| c * color1.a * p1); + let c2 = color2.into_linear().map(|c| c * color2.a * p2); + + let [r, g, b] = + [c1[0] + c2[0], c1[1] + c2[1], c1[2] + c2[2]].map(|u| u / a); + + return Color::from_linear_rgba(r, g, b, a); + } + } + + let c1 = color1.into_linear().map(|c| c * p1); + let c2 = color2.into_linear().map(|c| c * p2); + + Color::from_linear_rgba( + c1[0] + c2[0], + c1[1] + c2[1], + c1[2] + c2[2], + c1[3] + c2[3], + ) +} + +#[cfg(test)] +mod tests { + use super::{Color, mix}; + + #[test] + fn mixing_works() { + let base = Color::from_rgba(1.0, 0.0, 0.0, 0.7); + let overlay = Color::from_rgba(0.0, 1.0, 0.0, 0.2); + + assert_eq!( + mix(base, overlay, 0.75).into_rgba8(), + Color::from_linear_rgba(0.53846, 0.46154, 0.0, 0.325).into_rgba8() + ); + } +} diff --git a/src/main.rs b/src/main.rs index 63e9deb..6ab4da9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,8 +35,6 @@ use types::{ Project, }; -//pub type Element<'a, Message> = iced::Element<'a, Message, OtherTheme>; - fn main() -> Result<(), Box> { let version = std::env::args() .nth(1) @@ -60,7 +58,6 @@ fn main() -> Result<(), Box> { iced::application(App::title, App::update, App::view) .font(icon::FONT) .theme(|state| state.theme.value().clone()) - //.theme(|_| theme::LIGHT.clone()) .subscription(App::subscription) .antialiasing(true) .run_with(move || App::new(config_load))?; @@ -446,21 +443,5 @@ impl App { Animation::new(&self.theme, content) .on_update(Message::SwitchTheme) .into() - //row![ - // button("filled") - // .style(theme::button::filled) - // .on_press(Message::RefreshEditorContent), - // button("elevated") - // .style(theme::button::elevated) - // .on_press(Message::RefreshEditorContent), - // button("filled tonal") - // .style(theme::button::filled_tonal) - // .on_press(Message::RefreshEditorContent), - // button("outlined") - // .style(theme::button::outlined) - // .on_press(Message::RefreshEditorContent), - //] - //.spacing(10) - //.into() } } diff --git a/src/theme.rs b/src/theme.rs index 6fe844c..232f309 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -1,18 +1,11 @@ -pub mod button; -pub mod text; - -use std::sync::{Arc, LazyLock}; +use std::sync::Arc; use iced::Color; -use iced::theme::Base; use iced::theme::palette::Extended; use serde::Deserialize; use crate::config::Config; -const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); -const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); - pub fn theme_index(theme_name: &str, slice: &[iced::Theme]) -> Option { slice .iter() @@ -83,159 +76,6 @@ impl Default for Appearance { } } -#[derive(Debug, PartialEq, Deserialize)] -pub struct OtherTheme { - name: String, - #[serde(flatten)] - colorscheme: ColorScheme, -} - -impl Clone for OtherTheme { - fn clone(&self) -> Self { - Self { - name: self.name.clone(), - colorscheme: self.colorscheme, - } - } - - fn clone_from(&mut self, source: &Self) { - self.name = source.name.clone(); - self.colorscheme = source.colorscheme; - } -} - -impl Default for OtherTheme { - fn default() -> Self { - match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { - dark_light::Mode::Dark | dark_light::Mode::Unspecified => { - DARK.clone() - } - dark_light::Mode::Light => LIGHT.clone(), - } - } -} - -impl Base for OtherTheme { - fn base(&self) -> iced::theme::Style { - iced::theme::Style { - background_color: self.colorscheme.surface.color, - text_color: self.colorscheme.surface.on_surface, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct ColorScheme { - pub primary: Primary, - pub secondary: Secondary, - pub tertiary: Tertiary, - pub error: Error, - pub surface: Surface, - pub inverse: Inverse, - pub outline: Outline, - #[serde(with = "color_serde")] - pub shadow: Color, -} - -pub static DARK: LazyLock = LazyLock::new(|| { - toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") -}); - -pub static LIGHT: LazyLock = LazyLock::new(|| { - toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") -}); - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Primary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_primary: Color, - #[serde(with = "color_serde")] - pub primary_container: Color, - #[serde(with = "color_serde")] - pub on_primary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Secondary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_secondary: Color, - #[serde(with = "color_serde")] - pub secondary_container: Color, - #[serde(with = "color_serde")] - pub on_secondary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Tertiary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_tertiary: Color, - #[serde(with = "color_serde")] - pub tertiary_container: Color, - #[serde(with = "color_serde")] - pub on_tertiary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Error { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_error: Color, - #[serde(with = "color_serde")] - pub error_container: Color, - #[serde(with = "color_serde")] - pub on_error_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Surface { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_surface: Color, - #[serde(with = "color_serde")] - pub on_surface_variant: Color, - pub surface_container: SurfaceContainer, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct SurfaceContainer { - #[serde(with = "color_serde")] - pub lowest: Color, - #[serde(with = "color_serde")] - pub low: Color, - #[serde(with = "color_serde")] - pub base: Color, - #[serde(with = "color_serde")] - pub high: Color, - #[serde(with = "color_serde")] - pub highest: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Inverse { - #[serde(with = "color_serde")] - pub inverse_surface: Color, - #[serde(with = "color_serde")] - pub inverse_on_surface: Color, - #[serde(with = "color_serde")] - pub inverse_primary: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -pub struct Outline { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub variant: Color, -} - #[derive(Debug, Deserialize)] pub struct Theme { name: String, diff --git a/src/theme/button.rs b/src/theme/button.rs deleted file mode 100644 index ddd2c71..0000000 --- a/src/theme/button.rs +++ /dev/null @@ -1,189 +0,0 @@ -#![allow(dead_code)] -use iced::widget::button::{Catalog, Status, Style, StyleFn}; -use iced::{Background, Border, Color, Shadow, Vector}; - -use super::OtherTheme; - -impl Catalog for OtherTheme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -fn default(theme: &OtherTheme, status: Status) -> Style { - filled(theme, status) -} - -fn button( - foreground: Color, - background: Color, - background_hover: Color, - disabled: Color, - shadow_color: Color, - shadow_elevation: u8, - status: Status, -) -> Style { - let border = Border { - radius: 400.0.into(), - ..Default::default() - }; - - let elevation_to_offset = |elevation: u8| { - (match elevation { - 0 => 0.0, - 1 => 1.0, - 2 => 3.0, - 3 => 6.0, - 4 => 8.0, - _ => 12.0, - } as f32) - }; - - match status { - Status::Active | Status::Pressed => Style { - background: Some(Background::Color(background)), - text_color: foreground, - border, - shadow: Shadow { - color: shadow_color, - offset: Vector { - x: 0.0, - y: elevation_to_offset(shadow_elevation), - }, - blur_radius: elevation_to_offset(shadow_elevation) - * (1.0 - + 0.4_f32.powf(elevation_to_offset(shadow_elevation))), - }, - }, - Status::Hovered => Style { - background: Some(Background::Color(background_hover)), - text_color: foreground, - border, - shadow: Shadow { - color: shadow_color, - offset: Vector { - x: 0.0, - y: elevation_to_offset(shadow_elevation + 1), - }, - blur_radius: (elevation_to_offset(shadow_elevation + 1)) - * (1.0 - + 0.4_f32 - .powf(elevation_to_offset(shadow_elevation + 1))), - }, - }, - Status::Disabled => Style { - background: Some(Background::Color(Color { - a: 0.12, - ..disabled - })), - text_color: Color { - a: 0.38, - ..disabled - }, - border, - ..Default::default() - }, - } -} - -pub fn elevated(theme: &OtherTheme, status: Status) -> Style { - let surface_colors = theme.colorscheme.surface; - - let foreground = theme.colorscheme.primary.color; - let background = surface_colors.surface_container.low; - let disabled = surface_colors.on_surface; - - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - background, - disabled, - shadow_color, - 1, - status, - ) -} - -pub fn filled(theme: &OtherTheme, status: Status) -> Style { - let primary_colors = theme.colorscheme.primary; - - let foreground = primary_colors.on_primary; - let background = primary_colors.color; - let disabled = theme.colorscheme.surface.on_surface; - - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - background, - disabled, - shadow_color, - 0, - status, - ) -} - -pub fn filled_tonal(theme: &OtherTheme, status: Status) -> Style { - let secondary_colors = theme.colorscheme.secondary; - - let foreground = secondary_colors.on_secondary_container; - let background = secondary_colors.secondary_container; - let disabled = theme.colorscheme.surface.on_surface; - - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - background, - disabled, - shadow_color, - 0, - status, - ) -} - -pub fn outlined(theme: &OtherTheme, status: Status) -> Style { - let foreground = theme.colorscheme.primary.color; - let background = Color::TRANSPARENT; - let disabled = theme.colorscheme.surface.on_surface; - - let outline = theme.colorscheme.outline.color; - - let border = match status { - Status::Active | Status::Pressed | Status::Hovered => Border { - color: outline, - width: 1.0, - radius: 400.0.into(), - }, - Status::Disabled => Border { - color: Color { - a: 0.12, - ..disabled - }, - width: 1.0, - radius: 400.0.into(), - }, - }; - - let style = button( - foreground, - background, - background, - disabled, - Color::TRANSPARENT, - 0, - status, - ); - - Style { border, ..style } -} diff --git a/src/theme/text.rs b/src/theme/text.rs deleted file mode 100644 index 9cbd056..0000000 --- a/src/theme/text.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![allow(dead_code)] -use iced::widget::text::{Catalog, Style, StyleFn}; - -use super::OtherTheme; - -impl Catalog for OtherTheme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(none) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn none(_: &OtherTheme) -> Style { - Style { color: None } -} - -pub fn primary(theme: &OtherTheme) -> Style { - Style { - color: Some(theme.colorscheme.primary.on_primary), - } -} - -pub fn secondary(theme: &OtherTheme) -> Style { - Style { - color: Some(theme.colorscheme.secondary.on_secondary), - } -} - -pub fn tertiary(theme: &OtherTheme) -> Style { - Style { - color: Some(theme.colorscheme.tertiary.on_tertiary), - } -} - -pub fn error(theme: &OtherTheme) -> Style { - Style { - color: Some(theme.colorscheme.error.on_error), - } -} - -pub fn surface(theme: &OtherTheme) -> Style { - Style { - color: Some(theme.colorscheme.surface.on_surface), - } -} diff --git a/theme_test/Cargo.toml b/theme_test/Cargo.toml new file mode 100644 index 0000000..34008eb --- /dev/null +++ b/theme_test/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "theme_test" +version = "0.0.1" +edition = "2024" + +[dependencies] +iced.workspace = true +material_theme = { path = "../material_theme" } diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs new file mode 100644 index 0000000..c4735be --- /dev/null +++ b/theme_test/src/main.rs @@ -0,0 +1,89 @@ +use iced::Element; +use iced::widget::{button, column, container, row, text}; +use material_theme::Theme; +use material_theme::button::{ + elevated, filled_tonal, outlined, text as text_style, +}; +use material_theme::container::{ + error, error_container, inverse_surface, primary, primary_container, + secondary, secondary_container, surface, surface_container, + surface_container_high, surface_container_highest, surface_container_low, + surface_container_lowest, tertiary, tertiary_container, +}; +use material_theme::text::surface_variant; + +fn main() { + iced::application("Theme Test", (), view) + .theme(|_| material_theme::DARK.clone()) + .run() + .unwrap(); +} + +#[derive(Debug, Clone)] +enum Message { + Noop, +} + +fn view(_: &()) -> Element<'_, Message, Theme> { + container( + row![ + column![ + button("Disabled"), + button("Filled").on_press(Message::Noop), + button("Filled Tonal") + .on_press(Message::Noop) + .style(filled_tonal), + button("Elevated").on_press(Message::Noop).style(elevated), + button("Outlined").on_press(Message::Noop).style(outlined), + button("Text").on_press(Message::Noop).style(text_style), + button("Text Disabled").style(text_style), + ] + .spacing(10), + column![ + text("None"), + container("Primary").padding(8).style(primary), + container("Primary Container") + .padding(8) + .style(primary_container), + container("Secondary").padding(8).style(secondary), + container("Secondary Container") + .padding(8) + .style(secondary_container), + container("Tertiary").padding(8).style(tertiary), + container("Tertiary Container") + .padding(8) + .style(tertiary_container), + container("Error").padding(8).style(error), + container("Error Container") + .padding(8) + .style(error_container), + container("Surface").padding(8).style(surface), + container(text("Surface Variant").style(surface_variant)) + .padding(8) + .style(surface), + container("Inverse Surface") + .padding(8) + .style(inverse_surface), + container("Surface Container Lowest") + .padding(8) + .style(surface_container_lowest), + container("Surface Container Low") + .padding(8) + .style(surface_container_low), + container("Surface Container") + .padding(8) + .style(surface_container), + container("Surface Container High") + .padding(8) + .style(surface_container_high), + container("Surface Container Highest") + .padding(8) + .style(surface_container_highest), + ] + .spacing(10) + ] + .spacing(20), + ) + .padding(12) + .into() +} -- cgit v1.2.3 From 88a22a5a7c281d66c174885aeb01476c061911d3 Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 7 Apr 2025 02:06:41 +0200 Subject: feat(material_theme): add feature flag based iced_anim support --- material_theme/Cargo.toml | 9 +++++++++ material_theme/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/material_theme/Cargo.toml b/material_theme/Cargo.toml index 0597d78..5a48dc0 100644 --- a/material_theme/Cargo.toml +++ b/material_theme/Cargo.toml @@ -11,12 +11,21 @@ categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] rust-version = "1.85" +[features] +default = [] +animate = ["dep:iced_anim"] + [dependencies] iced_widget = "0.14.0-dev" serde.workspace = true toml.workspace = true dark-light = "2.0.0" +[dependencies.iced_anim] +workspace = true +features = ["derive"] +optional = true + [lints.rust] unsafe_code = "deny" unused_results = "deny" diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index 6641b74..38a94b0 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -28,6 +28,31 @@ impl Theme { } } +#[cfg(feature = "animate")] +impl iced_anim::Animate for Theme { + fn components() -> usize { + ColorScheme::components() + } + + fn update(&mut self, components: &mut impl Iterator) { + let mut colors = self.colorscheme; + colors.update(components); + + *self = Theme::new("Animating Theme", colors); + } + + fn distance_to(&self, end: &Self) -> Vec { + self.colorscheme.distance_to(&end.colorscheme) + } + + fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { + let mut colors = self.colorscheme; + colors.lerp(&start.colorscheme, &end.colorscheme, progress); + + *self = Theme::new("Animating Theme", colors); + } +} + impl Clone for Theme { fn clone(&self) -> Self { Self { @@ -63,6 +88,7 @@ impl Base for Theme { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct ColorScheme { pub primary: Primary, pub secondary: Secondary, @@ -84,6 +110,7 @@ pub static LIGHT: LazyLock = LazyLock::new(|| { }); #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Primary { #[serde(with = "color_serde")] pub color: Color, @@ -96,6 +123,7 @@ pub struct Primary { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Secondary { #[serde(with = "color_serde")] pub color: Color, @@ -108,6 +136,7 @@ pub struct Secondary { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Tertiary { #[serde(with = "color_serde")] pub color: Color, @@ -120,6 +149,7 @@ pub struct Tertiary { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Error { #[serde(with = "color_serde")] pub color: Color, @@ -132,6 +162,7 @@ pub struct Error { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Surface { #[serde(with = "color_serde")] pub color: Color, @@ -143,6 +174,7 @@ pub struct Surface { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct SurfaceContainer { #[serde(with = "color_serde")] pub lowest: Color, @@ -157,6 +189,7 @@ pub struct SurfaceContainer { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Inverse { #[serde(with = "color_serde")] pub inverse_surface: Color, @@ -167,6 +200,7 @@ pub struct Inverse { } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Outline { #[serde(with = "color_serde")] pub color: Color, -- cgit v1.2.3 From de7647108e831b9201483b665c99d6527964d2ce Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 7 Apr 2025 23:42:37 +0200 Subject: fix: custom theme Default changing between calls, missing `apply_options`s --- material_theme/src/lib.rs | 15 ++++++++++----- src/theme.rs | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index 38a94b0..930e511 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -69,12 +69,17 @@ impl Clone for Theme { impl Default for Theme { fn default() -> Self { - match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { - dark_light::Mode::Dark | dark_light::Mode::Unspecified => { - DARK.clone() + static DEFAULT: LazyLock = LazyLock::new(|| { + match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) + { + dark_light::Mode::Dark | dark_light::Mode::Unspecified => { + DARK.clone() + } + dark_light::Mode::Light => LIGHT.clone(), } - dark_light::Mode::Light => LIGHT.clone(), - } + }); + + DEFAULT.clone() } } diff --git a/src/theme.rs b/src/theme.rs index 232f309..b721ddc 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -6,6 +6,9 @@ use serde::Deserialize; use crate::config::Config; +const DEFAULT_THEME_CONTENT: &str = + include_str!("../assets/themes/rose_pine.toml"); + pub fn theme_index(theme_name: &str, slice: &[iced::Theme]) -> Option { slice .iter() @@ -97,8 +100,7 @@ impl From for iced::Theme { impl Default for Theme { fn default() -> Self { - toml::from_str(include_str!("../assets/themes/rose_pine.toml")) - .expect("parse default theme") + toml::from_str(DEFAULT_THEME_CONTENT).expect("parse default theme") } } -- cgit v1.2.3 From c6a76e63604b16b9a14d5de6bd0ea91eea7f9bf2 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 8 Apr 2025 01:13:38 +0200 Subject: feat(material_theme): implement Catalog for iced_dialog (`dialog` feature) --- Cargo.lock | 2 ++ Cargo.toml | 3 +- material_theme/Cargo.toml | 3 ++ material_theme/src/lib.rs | 74 ++++++++++++++++++++++++++--------------------- src/main.rs | 17 ++++++----- src/panes/element_list.rs | 11 +++---- 6 files changed, 61 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2dc8556..b2ab721 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2678,6 +2678,8 @@ name = "material_theme" version = "0.14.0-dev" dependencies = [ "dark-light", + "iced_anim", + "iced_dialog", "iced_widget", "serde", "toml", diff --git a/Cargo.toml b/Cargo.toml index 33d3b8e..63e5f89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ iced.workspace = true iced_anim.workspace = true iced_custom_highlighter = { git = "https://github.com/pml68/iced_custom_highlighter", branch = "master" } iced_drop = { path = "iced_drop" } -iced_dialog = { git = "https://github.com/pml68/iced_dialog", branch = "iced/personal" } +iced_dialog.workspace = true material_theme = { path = "material_theme" } serde.workspace = true serde_json = "1.0.140" @@ -36,6 +36,7 @@ dirs-next = "2.0.0" [workspace.dependencies] iced_anim = { version = "0.2.1", features = ["derive"] } +iced_dialog = { git = "https://github.com/pml68/iced_dialog", branch = "iced/personal" } serde = { version = "1.0.219", features = ["derive"] } toml = "0.8.20" diff --git a/material_theme/Cargo.toml b/material_theme/Cargo.toml index 5a48dc0..e88ce92 100644 --- a/material_theme/Cargo.toml +++ b/material_theme/Cargo.toml @@ -14,12 +14,15 @@ rust-version = "1.85" [features] default = [] animate = ["dep:iced_anim"] +dialog = ["dep:iced_dialog"] [dependencies] iced_widget = "0.14.0-dev" serde.workspace = true toml.workspace = true dark-light = "2.0.0" +iced_dialog.workspace = true +iced_dialog.optional = true [dependencies.iced_anim] workspace = true diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index 930e511..87cf353 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -28,31 +28,6 @@ impl Theme { } } -#[cfg(feature = "animate")] -impl iced_anim::Animate for Theme { - fn components() -> usize { - ColorScheme::components() - } - - fn update(&mut self, components: &mut impl Iterator) { - let mut colors = self.colorscheme; - colors.update(components); - - *self = Theme::new("Animating Theme", colors); - } - - fn distance_to(&self, end: &Self) -> Vec { - self.colorscheme.distance_to(&end.colorscheme) - } - - fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { - let mut colors = self.colorscheme; - colors.lerp(&start.colorscheme, &end.colorscheme, progress); - - *self = Theme::new("Animating Theme", colors); - } -} - impl Clone for Theme { fn clone(&self) -> Self { Self { @@ -92,6 +67,47 @@ impl Base for Theme { } } +#[cfg(feature = "animate")] +impl iced_anim::Animate for Theme { + fn components() -> usize { + ColorScheme::components() + } + + fn update(&mut self, components: &mut impl Iterator) { + let mut colors = self.colorscheme; + colors.update(components); + + *self = Theme::new("Animating Theme", colors); + } + + fn distance_to(&self, end: &Self) -> Vec { + self.colorscheme.distance_to(&end.colorscheme) + } + + fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { + let mut colors = self.colorscheme; + colors.lerp(&start.colorscheme, &end.colorscheme, progress); + + *self = Theme::new("Animating Theme", colors); + } +} + +#[cfg(feature = "dialog")] +impl iced_dialog::dialog::Catalog for Theme { + fn default_container<'a>() + -> ::Class<'a> { + Box::new(container::surface) + } +} + +pub static DARK: LazyLock = LazyLock::new(|| { + toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") +}); + +pub static LIGHT: LazyLock = LazyLock::new(|| { + toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") +}); + #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct ColorScheme { @@ -106,14 +122,6 @@ pub struct ColorScheme { pub shadow: Color, } -pub static DARK: LazyLock = LazyLock::new(|| { - toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") -}); - -pub static LIGHT: LazyLock = LazyLock::new(|| { - toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") -}); - #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] pub struct Primary { diff --git a/src/main.rs b/src/main.rs index 6ab4da9..3895dbc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,8 +31,7 @@ use iced_dialog::dialog::Dialog; use panes::{code_view, designer_view, element_list}; use tokio::runtime; use types::{ - Action, DesignerPane, DialogAction, DialogButtons, ElementName, Message, - Project, + Action, DesignerPane, DialogAction, DialogButtons, Message, Project, }; fn main() -> Result<(), Box> { @@ -79,7 +78,6 @@ struct App { dialog_content: String, dialog_buttons: DialogButtons, dialog_action: DialogAction, - element_list: &'static [ElementName], editor_content: text_editor::Content, } @@ -132,7 +130,6 @@ impl App { dialog_content: String::new(), dialog_buttons: DialogButtons::None, dialog_action: DialogAction::None, - element_list: ElementName::ALL, editor_content: text_editor::Content::new(), }, task, @@ -408,9 +405,7 @@ impl App { code_view::view(&self.editor_content, is_focused) } }, - Panes::ElementList => { - element_list::view(self.element_list, is_focused) - } + Panes::ElementList => element_list::view(is_focused), } }, ) @@ -438,7 +433,13 @@ impl App { DialogButtons::OkCancel => vec![ok_button(), cancel_button()], }, ) - .title(self.dialog_title); + .title(self.dialog_title) + .container_style(|theme| container::Style { + background: Some( + theme.extended_palette().background.strong.color.into(), + ), + ..Default::default() + }); Animation::new(&self.theme, content) .on_update(Message::SwitchTheme) diff --git a/src/panes/element_list.rs b/src/panes/element_list.rs index 10eea66..594c203 100644 --- a/src/panes/element_list.rs +++ b/src/panes/element_list.rs @@ -5,13 +5,13 @@ use iced_drop::droppable; use super::style; use crate::types::{ElementName, Message}; -fn items_list_view(items: &[ElementName]) -> Element<'_, Message> { +fn items_list_view<'a>() -> Element<'a, Message> { let mut column = Column::new() .spacing(20) .align_x(Alignment::Center) .width(Length::Fill); - for item in items { + for item in ElementName::ALL { column = column.push( droppable(text(item.clone().to_string())).on_drop(|point, rect| { Message::DropNewElement(item.clone(), point, rect) @@ -25,11 +25,8 @@ fn items_list_view(items: &[ElementName]) -> Element<'_, Message> { .into() } -pub fn view( - element_list: &[ElementName], - is_focused: bool, -) -> pane_grid::Content<'_, Message> { - let items_list = items_list_view(element_list); +pub fn view<'a>(is_focused: bool) -> pane_grid::Content<'a, Message> { + let items_list = items_list_view(); let content = column![items_list] .align_x(Alignment::Center) .height(Length::Fill) -- cgit v1.2.3 From 00d296b230e41dbfaf33d1ba374beadf9d113948 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 8 Apr 2025 18:12:10 +0200 Subject: feat(material_theme): impl `scrollable::Catalog` --- material_theme/src/button.rs | 54 +++++++------------- material_theme/src/lib.rs | 1 + material_theme/src/scrollable.rs | 107 +++++++++++++++++++++++++++++++++++++++ material_theme/src/utils.rs | 19 ++++++- 4 files changed, 145 insertions(+), 36 deletions(-) create mode 100644 material_theme/src/scrollable.rs diff --git a/material_theme/src/button.rs b/material_theme/src/button.rs index 051d6c9..21d77b7 100644 --- a/material_theme/src/button.rs +++ b/material_theme/src/button.rs @@ -1,9 +1,11 @@ -#![allow(dead_code)] use iced_widget::button::{Catalog, Status, Style, StyleFn}; -use iced_widget::core::{Background, Border, Color, Shadow, Vector}; +use iced_widget::core::{Background, Border, Color, border}; use crate::Theme; -use crate::utils::{elevation, mix}; +use crate::utils::{ + DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, + PRESSED_LAYER_OPACITY, elevation, mix, shadow_from_elevation, +}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -23,27 +25,14 @@ fn button( tone_overlay: Color, disabled: Color, shadow_color: Color, - shadow_elevation: u8, + elevation_level: u8, status: Status, ) -> Style { - let border = Border { - radius: 400.into(), - ..Default::default() - }; - let active = Style { background: Some(Background::Color(background)), text_color: foreground, - border, - shadow: Shadow { - color: shadow_color, - offset: Vector { - x: 0.0, - y: elevation(shadow_elevation), - }, - blur_radius: elevation(shadow_elevation) - * (1.0 + 0.4_f32.powf(elevation(shadow_elevation))), - }, + border: border::rounded(400), + shadow: shadow_from_elevation(elevation(elevation_level), shadow_color), }; match status { @@ -52,7 +41,7 @@ fn button( background: Some(Background::Color(mix( background, tone_overlay, - 0.08, + HOVERED_LAYER_OPACITY, ))), ..active }, @@ -60,30 +49,25 @@ fn button( background: Some(Background::Color(mix( background, tone_overlay, - 0.1, + PRESSED_LAYER_OPACITY, ))), text_color: foreground, - border, - shadow: Shadow { - color: shadow_color, - offset: Vector { - x: 0.0, - y: elevation(shadow_elevation + 1), - }, - blur_radius: (elevation(shadow_elevation + 1)) - * (1.0 + 0.4_f32.powf(elevation(shadow_elevation + 1))), - }, + border: border::rounded(400), + shadow: shadow_from_elevation( + elevation(elevation_level + 1), + shadow_color, + ), }, Status::Disabled => Style { background: Some(Background::Color(Color { - a: 0.12, + a: DISABLED_CONTAINER_OPACITY, ..disabled })), text_color: Color { - a: 0.38, + a: DISABLED_TEXT_OPACITY, ..disabled }, - border, + border: border::rounded(400), ..Default::default() }, } @@ -163,7 +147,7 @@ pub fn outlined(theme: &Theme, status: Status) -> Style { }, Status::Disabled => Border { color: Color { - a: 0.12, + a: DISABLED_CONTAINER_OPACITY, ..disabled }, width: 1.0, diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index 87cf353..273ef9a 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -6,6 +6,7 @@ use serde::Deserialize; pub mod button; pub mod container; +pub mod scrollable; pub mod text; pub mod utils; diff --git a/material_theme/src/scrollable.rs b/material_theme/src/scrollable.rs new file mode 100644 index 0000000..c2dde67 --- /dev/null +++ b/material_theme/src/scrollable.rs @@ -0,0 +1,107 @@ +use iced_widget::core::{Border, border}; +use iced_widget::scrollable::{ + Catalog, Rail, Scroller, Status, Style, StyleFn, +}; + +use super::Theme; +use super::container::surface_container; +use super::utils::mix; +use crate::utils::{HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let colors = theme.colorscheme.surface; + + let rail = Rail { + background: None, + scroller: Scroller { + color: colors.on_surface, + border: border::rounded(400), + }, + border: Border::default(), + }; + + let style = Style { + container: surface_container(theme), + vertical_rail: rail, + horizontal_rail: rail, + gap: None, + }; + + match status { + Status::Active { .. } => style, + Status::Hovered { + is_horizontal_scrollbar_hovered, + is_vertical_scrollbar_hovered, + .. + } => { + let hovered_rail = Rail { + scroller: Scroller { + color: mix( + colors.on_surface, + colors.color, + HOVERED_LAYER_OPACITY, + ), + border: border::rounded(400), + }, + ..rail + }; + + Style { + horizontal_rail: if is_horizontal_scrollbar_hovered { + hovered_rail + } else { + rail + }, + vertical_rail: if is_vertical_scrollbar_hovered { + hovered_rail + } else { + rail + }, + ..style + } + } + Status::Dragged { + is_horizontal_scrollbar_dragged, + is_vertical_scrollbar_dragged, + .. + } => { + let dragged_rail = Rail { + scroller: Scroller { + color: mix( + colors.on_surface, + colors.color, + PRESSED_LAYER_OPACITY, + ), + border: border::rounded(400), + }, + ..rail + }; + + Style { + horizontal_rail: if is_horizontal_scrollbar_dragged { + dragged_rail + } else { + rail + }, + vertical_rail: if is_vertical_scrollbar_dragged { + dragged_rail + } else { + rail + }, + ..style + } + } + } +} diff --git a/material_theme/src/utils.rs b/material_theme/src/utils.rs index c9eb78e..7efec9b 100644 --- a/material_theme/src/utils.rs +++ b/material_theme/src/utils.rs @@ -1,4 +1,10 @@ -use iced_widget::core::Color; +use iced_widget::core::{Color, Shadow, Vector}; + +pub const HOVERED_LAYER_OPACITY: f32 = 0.08; +pub const PRESSED_LAYER_OPACITY: f32 = 0.1; + +pub const DISABLED_TEXT_OPACITY: f32 = 0.38; +pub const DISABLED_CONTAINER_OPACITY: f32 = 0.12; pub fn elevation(elevation_level: u8) -> f32 { (match elevation_level { @@ -11,6 +17,17 @@ pub fn elevation(elevation_level: u8) -> f32 { } as f32) } +pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { + Shadow { + color, + offset: Vector { + x: 0.0, + y: elevation, + }, + blur_radius: (elevation) * (1.0 + 0.4_f32.powf(elevation)), + } +} + pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { if p2 <= 0.0 { return color1; -- cgit v1.2.3 From 53dc5464c2f595d1a32174598e280428d3265f15 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 8 Apr 2025 19:40:45 +0200 Subject: feat(material_theme): impl `menu::Catalog`, change `dialog::Catalog` impl --- material_theme/src/dialog.rs | 25 ++++++++++ material_theme/src/lib.rs | 11 ++--- material_theme/src/menu.rs | 29 ++++++++++++ src/types/rendered_element.rs | 105 +++++++++++++++++++++++++++--------------- 4 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 material_theme/src/dialog.rs create mode 100644 material_theme/src/menu.rs diff --git a/material_theme/src/dialog.rs b/material_theme/src/dialog.rs new file mode 100644 index 0000000..68c61b5 --- /dev/null +++ b/material_theme/src/dialog.rs @@ -0,0 +1,25 @@ +use iced_widget::container::Style; +use iced_widget::core::{Background, border}; + +use super::{Theme, text}; + +impl iced_dialog::dialog::Catalog for Theme { + fn default_container<'a>() + -> ::Class<'a> { + Box::new(default_container) + } + + fn default_title<'a>() -> ::Class<'a> { + Box::new(text::surface) + } +} + +pub fn default_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.high)), + text_color: Some(colors.on_surface_variant), + border: border::rounded(28), + ..Style::default() + } +} diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index 273ef9a..a4eea24 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -6,6 +6,9 @@ use serde::Deserialize; pub mod button; pub mod container; +#[cfg(feature = "dialog")] +pub mod dialog; +pub mod menu; pub mod scrollable; pub mod text; pub mod utils; @@ -93,14 +96,6 @@ impl iced_anim::Animate for Theme { } } -#[cfg(feature = "dialog")] -impl iced_dialog::dialog::Catalog for Theme { - fn default_container<'a>() - -> ::Class<'a> { - Box::new(container::surface) - } -} - pub static DARK: LazyLock = LazyLock::new(|| { toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") }); diff --git a/material_theme/src/menu.rs b/material_theme/src/menu.rs new file mode 100644 index 0000000..d1bebec --- /dev/null +++ b/material_theme/src/menu.rs @@ -0,0 +1,29 @@ +use iced_widget::core::{Background, border}; +use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(theme: &Theme) -> Style { + let surface = theme.colorscheme.surface; + let secondary = theme.colorscheme.secondary; + + Style { + border: border::rounded(4), + background: Background::Color(surface.surface_container.base), + text_color: surface.on_surface, + selected_background: Background::Color(secondary.secondary_container), + selected_text_color: secondary.on_secondary_container, + } +} diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs index 0a78dcd..77b76e4 100755 --- a/src/types/rendered_element.rs +++ b/src/types/rendered_element.rs @@ -317,53 +317,86 @@ impl<'a> From for Element<'a, Message> { let child_elements = copy.child_elements.unwrap_or_default(); let content: Element<'a, Message> = match copy.name { - ElementName::Text(s) => { - if s.is_empty() { - widget::text("New Text").apply_options(copy.options).into() - } else { - widget::text(s).apply_options(copy.options).into() - } - } - ElementName::Button(s) => { - if s.is_empty() { - widget::button(widget::text("New Button")) - .apply_options(copy.options) - .into() - } else { - widget::button(widget::text(s)) - .apply_options(copy.options) - .into() - } + ElementName::Text(s) => if s.is_empty() { + widget::text("New Text") + } else { + widget::text(s) } + .apply_options(copy.options) + .into(), + ElementName::Button(s) => widget::button(if s.is_empty() { + widget::text("New Button") + } else { + widget::text(s) + }) + .apply_options(copy.options) + .into(), ElementName::Svg(p) => { widget::svg(p).apply_options(copy.options).into() } ElementName::Image(p) => { widget::image(p).apply_options(copy.options).into() } - ElementName::Container => { - widget::container(if child_elements.len() == 1 { - child_elements[0].clone().into() - } else { - Element::from("") - }) - .apply_options(copy.options) - .padding(20) - .into() + ElementName::Container => if child_elements.len() == 1 { + widget::container(child_elements[0].clone()) + } else { + widget::container("New Container") + .padding(20) + .style(|theme| widget::container::Style { + border: iced::border::rounded(4).color( + theme.extended_palette().background.strongest.text, + ), + ..Default::default() + }) } - ElementName::Row => widget::Row::from_vec( - child_elements.into_iter().map(Into::into).collect(), - ) - .padding(20) - .apply_options(copy.options) - .into(), - ElementName::Column => widget::Column::from_vec( - child_elements.into_iter().map(Into::into).collect(), - ) - .padding(20) .apply_options(copy.options) .into(), + ElementName::Row => { + if !child_elements.is_empty() { + widget::Row::with_children( + child_elements.into_iter().map(Into::into), + ) + .apply_options(copy.options) + .into() + } else { + widget::container( + widget::row!["New Row"] + .padding(20) + .apply_options(copy.options), + ) + .style(|theme| widget::container::Style { + border: iced::border::rounded(4).color( + theme.extended_palette().background.strongest.text, + ), + ..Default::default() + }) + .into() + } + } + ElementName::Column => { + if !child_elements.is_empty() { + widget::Column::with_children( + child_elements.into_iter().map(Into::into), + ) + .apply_options(copy.options) + .into() + } else { + widget::container( + widget::column!["New Column"] + .padding(20) + .apply_options(copy.options), + ) + .style(|theme| widget::container::Style { + border: iced::border::rounded(4).color( + theme.extended_palette().background.strongest.text, + ), + ..Default::default() + }) + .into() + } + } }; + iced_drop::droppable(content) .id(value.id().clone()) .drag_hide(true) -- cgit v1.2.3 From 941eb51e043b6b847089130625c2df10b0674154 Mon Sep 17 00:00:00 2001 From: pml68 Date: Wed, 9 Apr 2025 00:29:34 +0200 Subject: feat: update `iced`, make designer view more usable --- Cargo.lock | 252 +++++++++++++++++++++++------------------- Cargo.toml | 4 +- src/main.rs | 18 ++- src/panes/designer_view.rs | 19 +++- src/types/rendered_element.rs | 42 ++++--- 5 files changed, 193 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2ab721..a324ccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ dependencies = [ "zerocopy 0.7.35", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "aligned-vec" version = "0.5.0" @@ -105,15 +111,6 @@ version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - [[package]] name = "arbitrary" version = "1.4.1" @@ -569,12 +566,6 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "by_address" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" - [[package]] name = "bytemuck" version = "1.22.0" @@ -1316,12 +1307,6 @@ dependencies = [ "zune-inflate", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" version = "2.3.0" @@ -1767,9 +1752,9 @@ dependencies = [ [[package]] name = "half" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -1784,6 +1769,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "heck" version = "0.5.0" @@ -1938,11 +1929,14 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "iced_core", + "iced_debug", + "iced_devtools", "iced_futures", "iced_renderer", + "iced_runtime", "iced_widget", "iced_winit", "image", @@ -1967,6 +1961,21 @@ dependencies = [ "syn", ] +[[package]] +name = "iced_beacon" +version = "0.14.0-dev" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +dependencies = [ + "bincode", + "futures", + "iced_core", + "log", + "semver", + "serde", + "thiserror 1.0.69", + "tokio", +] + [[package]] name = "iced_builder" version = "0.1.0" @@ -1996,7 +2005,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2005,8 +2014,8 @@ dependencies = [ "lilt", "log", "num-traits", - "palette", "rustc-hash 2.1.1", + "serde", "smol_str", "thiserror 1.0.69", "web-time", @@ -2022,6 +2031,26 @@ dependencies = [ "two-face", ] +[[package]] +name = "iced_debug" +version = "0.14.0-dev" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +dependencies = [ + "iced_beacon", + "iced_core", + "log", +] + +[[package]] +name = "iced_devtools" +version = "0.14.0-dev" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +dependencies = [ + "iced_debug", + "iced_program", + "iced_widget", +] + [[package]] name = "iced_dialog" version = "0.14.0-dev" @@ -2055,7 +2084,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "futures", "iced_core", @@ -2069,7 +2098,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2086,10 +2115,19 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "iced_program" +version = "0.14.0-dev" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +dependencies = [ + "iced_graphics", + "iced_runtime", +] + [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2101,20 +2139,20 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "bytes", "iced_core", + "iced_debug", "iced_futures", "raw-window-handle", - "sipper", "thiserror 1.0.69", ] [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "bytemuck", "cosmic-text", @@ -2130,7 +2168,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2149,12 +2187,13 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ "iced_renderer", "iced_runtime", "log", "num-traits", + "ouroboros", "rustc-hash 2.1.1", "thiserror 1.0.69", "unicode-segmentation", @@ -2163,11 +2202,10 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#1a84a8019cbd95ae1b1c88f75aeb0a15f0f3caf2" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" dependencies = [ - "iced_futures", - "iced_graphics", - "iced_runtime", + "iced_debug", + "iced_program", "log", "rustc-hash 2.1.1", "thiserror 1.0.69", @@ -2758,9 +2796,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", "simd-adler32", @@ -3347,36 +3385,36 @@ dependencies = [ ] [[package]] -name = "owned_ttf_parser" -version = "0.25.0" +name = "ouroboros" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" dependencies = [ - "ttf-parser 0.25.1", + "aliasable", + "ouroboros_macro", + "static_assertions", ] [[package]] -name = "palette" -version = "0.7.6" +name = "ouroboros_macro" +version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" dependencies = [ - "approx", - "fast-srgb8", - "palette_derive", - "phf", + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", ] [[package]] -name = "palette_derive" -version = "0.7.6" +name = "owned_ttf_parser" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ - "by_address", - "proc-macro2", - "quote", - "syn", + "ttf-parser 0.25.1", ] [[package]] @@ -3430,48 +3468,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - [[package]] name = "pico-args" version = "0.5.0" @@ -3600,6 +3596,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + [[package]] name = "profiling" version = "1.0.16" @@ -4176,6 +4185,9 @@ name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -4308,16 +4320,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" -[[package]] -name = "sipper" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bccb4192828b3d9a08e0b5a73f17795080dfb278b50190216e3ae2132cf4f95" -dependencies = [ - "futures", - "pin-project-lite", -] - [[package]] name = "skrifa" version = "0.26.6" @@ -4484,7 +4486,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", @@ -4612,7 +4614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" dependencies = [ "cfg-expr", - "heck", + "heck 0.5.0", "pkg-config", "toml", "version-compare", @@ -4790,9 +4792,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.44.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -4800,9 +4802,21 @@ dependencies = [ "mio", "pin-project-lite", "socket2", + "tokio-macros", "windows-sys 0.52.0", ] +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -6029,9 +6043,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" dependencies = [ "memchr", ] @@ -6161,6 +6175,12 @@ dependencies = [ "lzma-sys", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yazi" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index 63e5f89..e48a39c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ material_theme = { path = "material_theme" } serde.workspace = true serde_json = "1.0.140" toml.workspace = true -tokio = { version = "1.42.1", features = ["fs"] } +tokio = { version = "1.44.2", features = ["fs"] } tokio-stream = { version = "0.1", features = ["fs"] } # TODO: enable tokio when it actually compiles # rfd = { version = "0.15.2", default-features = false, features = ["tokio", "xdg-portal"] } @@ -43,7 +43,7 @@ toml = "0.8.20" [workspace.dependencies.iced] git = "https://github.com/pml68/iced" branch = "feat/rehighlight-on-redraw" -features = ["image", "svg", "advanced", "tokio"] +features = ["image", "svg", "advanced", "tokio", "lazy"] [build-dependencies] iced_fontello = "0.13.2" diff --git a/src/main.rs b/src/main.rs index 3895dbc..d58329a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,12 +54,18 @@ fn main() -> Result<(), Box> { rt.block_on(Config::load()) }; - iced::application(App::title, App::update, App::view) - .font(icon::FONT) - .theme(|state| state.theme.value().clone()) - .subscription(App::subscription) - .antialiasing(true) - .run_with(move || App::new(config_load))?; + iced::application( + move || App::new(config_load.clone()), + App::update, + App::view, + ) + .title(App::title) + .font(icon::FONT) + .theme(|state| state.theme.value().clone()) + .subscription(App::subscription) + .antialiasing(true) + .run()?; + Ok(()) } diff --git a/src/panes/designer_view.rs b/src/panes/designer_view.rs index 6340f73..69ff750 100644 --- a/src/panes/designer_view.rs +++ b/src/panes/designer_view.rs @@ -1,16 +1,29 @@ -use iced::widget::{Space, button, container, pane_grid, row, text, themer}; +use iced::widget::{ + Space, button, center, container, pane_grid, responsive, row, text, themer, +}; use iced::{Alignment, Element, Length}; use super::style; use crate::types::{DesignerPane, Message, RenderedElement}; pub fn view<'a>( - element_tree: Option<&RenderedElement>, + element_tree: Option<&'a RenderedElement>, designer_theme: iced::Theme, is_focused: bool, ) -> pane_grid::Content<'a, Message> { let el_tree: Element<'a, Message> = match element_tree { - Some(tree) => tree.clone().into(), + Some(tree) => responsive(|size| { + center( + container(tree.clone()) + .style(|theme| { + container::background(theme.palette().background) + }) + .height(size.height * 0.5) + .width(size.height * 0.8), + ) + .into() + }) + .into(), None => text("Open a project or begin creating one").into(), }; let content = container(themer(designer_theme, el_tree)) diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs index 77b76e4..bd8187e 100755 --- a/src/types/rendered_element.rs +++ b/src/types/rendered_element.rs @@ -340,15 +340,19 @@ impl<'a> From for Element<'a, Message> { ElementName::Container => if child_elements.len() == 1 { widget::container(child_elements[0].clone()) } else { - widget::container("New Container") - .padding(20) - .style(|theme| widget::container::Style { - border: iced::border::rounded(4).color( - theme.extended_palette().background.strongest.text, - ), + widget::container("New Container").style( + |theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, ..Default::default() - }) + }, + ) } + .padding(20) .apply_options(copy.options) .into(), ElementName::Row => { @@ -356,6 +360,7 @@ impl<'a> From for Element<'a, Message> { widget::Row::with_children( child_elements.into_iter().map(Into::into), ) + .padding(20) .apply_options(copy.options) .into() } else { @@ -364,10 +369,13 @@ impl<'a> From for Element<'a, Message> { .padding(20) .apply_options(copy.options), ) - .style(|theme| widget::container::Style { - border: iced::border::rounded(4).color( - theme.extended_palette().background.strongest.text, - ), + .style(|theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, ..Default::default() }) .into() @@ -378,6 +386,7 @@ impl<'a> From for Element<'a, Message> { widget::Column::with_children( child_elements.into_iter().map(Into::into), ) + .padding(20) .apply_options(copy.options) .into() } else { @@ -386,10 +395,13 @@ impl<'a> From for Element<'a, Message> { .padding(20) .apply_options(copy.options), ) - .style(|theme| widget::container::Style { - border: iced::border::rounded(4).color( - theme.extended_palette().background.strongest.text, - ), + .style(|theme: &iced::Theme| widget::container::Style { + border: iced::Border { + color: theme.palette().text, + + width: 2.0, + radius: 4.into(), + }, ..Default::default() }) .into() -- cgit v1.2.3 From 16feecdd82a27dbf0ccae6c32f4e6844f5b45c5f Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 10 Apr 2025 06:32:06 +0200 Subject: feat(material_theme): implement `theme::Base` for theme (`None` for now) --- material_theme/src/lib.rs | 5 +++++ theme_test/src/main.rs | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index a4eea24..ba9d478 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -69,6 +69,11 @@ impl Base for Theme { text_color: self.colorscheme.surface.on_surface, } } + + fn palette(&self) -> Option { + // TODO: create a Palette + None + } } #[cfg(feature = "animate")] diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index c4735be..26358c8 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -12,11 +12,10 @@ use material_theme::container::{ }; use material_theme::text::surface_variant; -fn main() { - iced::application("Theme Test", (), view) - .theme(|_| material_theme::DARK.clone()) +fn main() -> iced::Result { + iced::application(|| {}, (), view) + .theme(|_| material_theme::LIGHT.clone()) .run() - .unwrap(); } #[derive(Debug, Clone)] -- cgit v1.2.3 From b6c5f3e25d4590e347236f481e6a00bdf98ac030 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 00:27:57 +0200 Subject: feat(material_theme): add disabled scrollable `Style`s --- material_theme/src/scrollable.rs | 98 +++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/material_theme/src/scrollable.rs b/material_theme/src/scrollable.rs index c2dde67..8a22e56 100644 --- a/material_theme/src/scrollable.rs +++ b/material_theme/src/scrollable.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Border, border}; +use iced_widget::core::{Border, Color, border}; use iced_widget::scrollable::{ Catalog, Rail, Scroller, Status, Style, StyleFn, }; @@ -6,7 +6,10 @@ use iced_widget::scrollable::{ use super::Theme; use super::container::surface_container; use super::utils::mix; -use crate::utils::{HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY}; +use crate::utils::{ + DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, + PRESSED_LAYER_OPACITY, +}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -23,7 +26,7 @@ impl Catalog for Theme { pub fn default(theme: &Theme, status: Status) -> Style { let colors = theme.colorscheme.surface; - let rail = Rail { + let active = Rail { background: None, scroller: Scroller { color: colors.on_surface, @@ -32,19 +35,53 @@ pub fn default(theme: &Theme, status: Status) -> Style { border: Border::default(), }; + let disabled = Rail { + background: Some( + Color { + a: DISABLED_CONTAINER_OPACITY, + ..colors.on_surface + } + .into(), + ), + scroller: Scroller { + color: Color { + a: DISABLED_TEXT_OPACITY, + ..colors.on_surface + }, + border: border::rounded(400), + }, + ..active + }; + let style = Style { container: surface_container(theme), - vertical_rail: rail, - horizontal_rail: rail, + vertical_rail: active, + horizontal_rail: active, gap: None, }; match status { - Status::Active { .. } => style, + Status::Active { + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, + } => Style { + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled + } else { + active + }, + vertical_rail: if is_vertical_scrollbar_disabled { + disabled + } else { + active + }, + ..style + }, Status::Hovered { is_horizontal_scrollbar_hovered, is_vertical_scrollbar_hovered, - .. + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, } => { let hovered_rail = Rail { scroller: Scroller { @@ -55,19 +92,27 @@ pub fn default(theme: &Theme, status: Status) -> Style { ), border: border::rounded(400), }, - ..rail + ..active }; Style { - horizontal_rail: if is_horizontal_scrollbar_hovered { - hovered_rail + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled } else { - rail + if is_horizontal_scrollbar_hovered { + hovered_rail + } else { + active + } }, - vertical_rail: if is_vertical_scrollbar_hovered { - hovered_rail + vertical_rail: if is_vertical_scrollbar_disabled { + disabled } else { - rail + if is_vertical_scrollbar_hovered { + hovered_rail + } else { + active + } }, ..style } @@ -75,7 +120,8 @@ pub fn default(theme: &Theme, status: Status) -> Style { Status::Dragged { is_horizontal_scrollbar_dragged, is_vertical_scrollbar_dragged, - .. + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, } => { let dragged_rail = Rail { scroller: Scroller { @@ -86,19 +132,27 @@ pub fn default(theme: &Theme, status: Status) -> Style { ), border: border::rounded(400), }, - ..rail + ..active }; Style { - horizontal_rail: if is_horizontal_scrollbar_dragged { - dragged_rail + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled } else { - rail + if is_horizontal_scrollbar_dragged { + dragged_rail + } else { + active + } }, - vertical_rail: if is_vertical_scrollbar_dragged { - dragged_rail + vertical_rail: if is_vertical_scrollbar_disabled { + disabled } else { - rail + if is_vertical_scrollbar_dragged { + dragged_rail + } else { + active + } }, ..style } -- cgit v1.2.3 From 68f4ed46b1846e27c03f23d0b98e3ce89dc497b8 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 03:31:36 +0200 Subject: feat(material_theme): implement `pick_list::Catalog` --- Cargo.lock | 68 ++++++------ material_theme/Cargo.toml | 1 + material_theme/README.md | 3 + material_theme/assets/themes/dark.toml | 1 + material_theme/assets/themes/light.toml | 1 + material_theme/src/lib.rs | 49 ++------- material_theme/src/menu.rs | 16 +-- material_theme/src/pick_list.rs | 40 +++++++ material_theme/src/utils.rs | 38 +++++++ theme_test/Cargo.toml | 4 +- theme_test/src/main.rs | 184 ++++++++++++++++++++------------ 11 files changed, 258 insertions(+), 147 deletions(-) create mode 100644 material_theme/README.md create mode 100644 material_theme/src/pick_list.rs diff --git a/Cargo.lock b/Cargo.lock index a324ccd..0143fbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -649,17 +649,11 @@ dependencies = [ "wayland-client", ] -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" - [[package]] name = "cc" -version = "1.2.17" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "jobserver", "libc", @@ -860,9 +854,9 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.13.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e418dd4f5128c3e93eab12246391c54a20c496811131f85754dc8152ee207892" +checksum = "1db686e755000c93f73a3acc78be56a71e3efb83ed92886f45faea2b9485bad7" dependencies = [ "bitflags 2.9.0", "fontdb 0.16.2", @@ -948,7 +942,7 @@ checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "cryoglyph" version = "0.1.0" -source = "git+https://github.com/iced-rs/cryoglyph.git?rev=be2defe4a13fd7c97c6f4c81e8e085463eb578dc#be2defe4a13fd7c97c6f4c81e8e085463eb578dc" +source = "git+https://github.com/iced-rs/cryoglyph.git?rev=a456d1c17bbcf33afcca41d9e5e299f9f1193819#a456d1c17bbcf33afcca41d9e5e299f9f1193819" dependencies = [ "cosmic-text", "etagere", @@ -1929,7 +1923,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_core", "iced_debug", @@ -1964,7 +1958,7 @@ dependencies = [ [[package]] name = "iced_beacon" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bincode", "futures", @@ -2005,7 +1999,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2034,7 +2028,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_beacon", "iced_core", @@ -2044,7 +2038,7 @@ dependencies = [ [[package]] name = "iced_devtools" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_debug", "iced_program", @@ -2054,7 +2048,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#6bd6c48b55201116791c59e73779613d617615c7" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#c0f931f38ac83e77cfb937d4166fa8d2a23988cf" dependencies = [ "iced_core", "iced_widget", @@ -2084,7 +2078,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "futures", "iced_core", @@ -2098,7 +2092,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2118,7 +2112,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_graphics", "iced_runtime", @@ -2127,7 +2121,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2139,7 +2133,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bytes", "iced_core", @@ -2152,10 +2146,11 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bytemuck", "cosmic-text", + "iced_debug", "iced_graphics", "kurbo 0.10.4", "log", @@ -2168,7 +2163,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2176,6 +2171,7 @@ dependencies = [ "futures", "glam", "guillotiere", + "iced_debug", "iced_graphics", "log", "resvg", @@ -2187,7 +2183,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_renderer", "iced_runtime", @@ -2202,7 +2198,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#add48e518b3423bed980983ddc373cfb8f5e8980" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" dependencies = [ "iced_debug", "iced_program", @@ -2625,9 +2621,9 @@ checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -4036,15 +4032,15 @@ dependencies = [ "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.9.3", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.25" +version = "0.23.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" +checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" dependencies = [ "once_cell", "rustls-pki-types", @@ -4176,9 +4172,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" @@ -4653,6 +4649,8 @@ name = "theme_test" version = "0.0.1" dependencies = [ "iced", + "iced_anim", + "iced_dialog", "material_theme", ] @@ -6156,9 +6154,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" [[package]] name = "xmlwriter" diff --git a/material_theme/Cargo.toml b/material_theme/Cargo.toml index e88ce92..eef9605 100644 --- a/material_theme/Cargo.toml +++ b/material_theme/Cargo.toml @@ -30,6 +30,7 @@ features = ["derive"] optional = true [lints.rust] +missing_debug_implementations = "deny" unsafe_code = "deny" unused_results = "deny" diff --git a/material_theme/README.md b/material_theme/README.md new file mode 100644 index 0000000..da5a1ec --- /dev/null +++ b/material_theme/README.md @@ -0,0 +1,3 @@ +# material_theme + +## A [Material3](https://m3.material.io) inspired custom theme for [`iced`](https://iced.rs) diff --git a/material_theme/assets/themes/dark.toml b/material_theme/assets/themes/dark.toml index 4d23fc8..18a369f 100644 --- a/material_theme/assets/themes/dark.toml +++ b/material_theme/assets/themes/dark.toml @@ -1,6 +1,7 @@ name = "Dark" shadow = "#000000" +scrim = "#4d000000" [primary] color = "#9bd4a1" diff --git a/material_theme/assets/themes/light.toml b/material_theme/assets/themes/light.toml index 5288c84..a7115c4 100644 --- a/material_theme/assets/themes/light.toml +++ b/material_theme/assets/themes/light.toml @@ -1,6 +1,7 @@ name = "Light" shadow = "#000000" +scrim = "#4d000000" [primary] color = "#34693f" diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs index ba9d478..521af2c 100644 --- a/material_theme/src/lib.rs +++ b/material_theme/src/lib.rs @@ -9,6 +9,7 @@ pub mod container; #[cfg(feature = "dialog")] pub mod dialog; pub mod menu; +pub mod pick_list; pub mod scrollable; pub mod text; pub mod utils; @@ -62,6 +63,12 @@ impl Default for Theme { } } +impl std::fmt::Display for Theme { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} + impl Base for Theme { fn base(&self) -> Style { Style { @@ -121,6 +128,8 @@ pub struct ColorScheme { pub outline: Outline, #[serde(with = "color_serde")] pub shadow: Color, + #[serde(with = "color_serde")] + pub scrim: Color, } #[derive(Debug, Clone, Copy, PartialEq, Deserialize)] @@ -222,49 +231,11 @@ pub struct Outline { pub variant: Color, } -pub fn parse_argb(s: &str) -> Option { - let hex = s.strip_prefix('#').unwrap_or(s); - - let parse_channel = |from: usize, to: usize| { - let num = - usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; - - // If we only got half a byte (one letter), expand it into a full byte (two letters) - Some(if from == to { num + num * 16.0 } else { num }) - }; - - Some(match hex.len() { - 3 => Color::from_rgb( - parse_channel(0, 0)?, - parse_channel(1, 1)?, - parse_channel(2, 2)?, - ), - 4 => Color::from_rgba( - parse_channel(1, 1)?, - parse_channel(2, 2)?, - parse_channel(3, 3)?, - parse_channel(0, 0)?, - ), - 6 => Color::from_rgb( - parse_channel(0, 1)?, - parse_channel(2, 3)?, - parse_channel(4, 5)?, - ), - 8 => Color::from_rgba( - parse_channel(2, 3)?, - parse_channel(4, 5)?, - parse_channel(6, 7)?, - parse_channel(0, 1)?, - ), - _ => None?, - }) -} - mod color_serde { use iced_widget::core::Color; use serde::{Deserialize, Deserializer}; - use super::parse_argb; + use super::utils::parse_argb; pub fn deserialize<'de, D>(deserializer: D) -> Result where diff --git a/material_theme/src/menu.rs b/material_theme/src/menu.rs index d1bebec..9f43c72 100644 --- a/material_theme/src/menu.rs +++ b/material_theme/src/menu.rs @@ -2,6 +2,7 @@ use iced_widget::core::{Background, border}; use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; use super::Theme; +use crate::utils::{HOVERED_LAYER_OPACITY, mix}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -16,14 +17,17 @@ impl Catalog for Theme { } pub fn default(theme: &Theme) -> Style { - let surface = theme.colorscheme.surface; - let secondary = theme.colorscheme.secondary; + let colors = theme.colorscheme.surface; Style { border: border::rounded(4), - background: Background::Color(surface.surface_container.base), - text_color: surface.on_surface, - selected_background: Background::Color(secondary.secondary_container), - selected_text_color: secondary.on_secondary_container, + background: Background::Color(colors.surface_container.base), + text_color: colors.on_surface, + selected_background: Background::Color(mix( + colors.surface_container.base, + colors.on_surface, + HOVERED_LAYER_OPACITY, + )), + selected_text_color: colors.on_surface, } } diff --git a/material_theme/src/pick_list.rs b/material_theme/src/pick_list.rs new file mode 100644 index 0000000..c589100 --- /dev/null +++ b/material_theme/src/pick_list.rs @@ -0,0 +1,40 @@ +use iced_widget::core::{Background, border}; +use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style( + &self, + class: &::Class<'_>, + status: Status, + ) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + + let active = Style { + text_color: surface.on_surface, + placeholder_color: surface.on_surface_variant, + handle_color: surface.on_surface_variant, + background: Background::Color(surface.surface_container.highest), + border: border::rounded(4), + }; + + match status { + Status::Active => active, + Status::Hovered | Status::Opened { .. } => Style { + background: Background::Color(surface.surface_container.highest), + ..active + }, + } +} diff --git a/material_theme/src/utils.rs b/material_theme/src/utils.rs index 7efec9b..a05bc62 100644 --- a/material_theme/src/utils.rs +++ b/material_theme/src/utils.rs @@ -28,6 +28,44 @@ pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { } } +pub fn parse_argb(s: &str) -> Option { + let hex = s.strip_prefix('#').unwrap_or(s); + + let parse_channel = |from: usize, to: usize| { + let num = + usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; + + // If we only got half a byte (one letter), expand it into a full byte (two letters) + Some(if from == to { num + num * 16.0 } else { num }) + }; + + Some(match hex.len() { + 3 => Color::from_rgb( + parse_channel(0, 0)?, + parse_channel(1, 1)?, + parse_channel(2, 2)?, + ), + 4 => Color::from_rgba( + parse_channel(1, 1)?, + parse_channel(2, 2)?, + parse_channel(3, 3)?, + parse_channel(0, 0)?, + ), + 6 => Color::from_rgb( + parse_channel(0, 1)?, + parse_channel(2, 3)?, + parse_channel(4, 5)?, + ), + 8 => Color::from_rgba( + parse_channel(2, 3)?, + parse_channel(4, 5)?, + parse_channel(6, 7)?, + parse_channel(0, 1)?, + ), + _ => None?, + }) +} + pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { if p2 <= 0.0 { return color1; diff --git a/theme_test/Cargo.toml b/theme_test/Cargo.toml index 34008eb..5ccbefa 100644 --- a/theme_test/Cargo.toml +++ b/theme_test/Cargo.toml @@ -5,4 +5,6 @@ edition = "2024" [dependencies] iced.workspace = true -material_theme = { path = "../material_theme" } +iced_anim.workspace = true +iced_dialog.workspace = true +material_theme = { path = "../material_theme", features = ["dialog", "animate"] } diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 26358c8..9826fe9 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,9 +1,9 @@ use iced::Element; -use iced::widget::{button, column, container, row, text}; -use material_theme::Theme; -use material_theme::button::{ - elevated, filled_tonal, outlined, text as text_style, -}; +use iced::Length::Fill; +use iced::widget::{button, column, container, pick_list, row}; +use iced_anim::{Animated, Animation, Event}; +use iced_dialog::dialog; +use material_theme::button::{elevated, filled_tonal, outlined, text}; use material_theme::container::{ error, error_container, inverse_surface, primary, primary_container, secondary, secondary_container, surface, surface_container, @@ -11,78 +11,130 @@ use material_theme::container::{ surface_container_lowest, tertiary, tertiary_container, }; use material_theme::text::surface_variant; +use material_theme::{DARK, LIGHT, Theme}; fn main() -> iced::Result { - iced::application(|| {}, (), view) - .theme(|_| material_theme::LIGHT.clone()) + iced::application(State::default, State::update, State::view) + .theme(|state| state.theme.value().clone()) .run() } +#[allow(dead_code)] #[derive(Debug, Clone)] enum Message { Noop, + OpenDialog, + CloseDialog, + SwitchTheme(Event), } -fn view(_: &()) -> Element<'_, Message, Theme> { - container( - row![ - column![ - button("Disabled"), - button("Filled").on_press(Message::Noop), - button("Filled Tonal") - .on_press(Message::Noop) - .style(filled_tonal), - button("Elevated").on_press(Message::Noop).style(elevated), - button("Outlined").on_press(Message::Noop).style(outlined), - button("Text").on_press(Message::Noop).style(text_style), - button("Text Disabled").style(text_style), - ] - .spacing(10), - column![ - text("None"), - container("Primary").padding(8).style(primary), - container("Primary Container") - .padding(8) - .style(primary_container), - container("Secondary").padding(8).style(secondary), - container("Secondary Container") - .padding(8) - .style(secondary_container), - container("Tertiary").padding(8).style(tertiary), - container("Tertiary Container") - .padding(8) - .style(tertiary_container), - container("Error").padding(8).style(error), - container("Error Container") - .padding(8) - .style(error_container), - container("Surface").padding(8).style(surface), - container(text("Surface Variant").style(surface_variant)) +#[derive(Debug, Default)] +pub struct State { + show_dialog: bool, + theme: Animated, +} + +impl State { + fn update(&mut self, message: Message) { + match message { + Message::Noop => {} + Message::OpenDialog => { + self.show_dialog = true; + } + Message::CloseDialog => { + self.show_dialog = false; + } + Message::SwitchTheme(event) => { + self.theme.update(event); + } + } + } + fn view(&self) -> Element<'_, Message, Theme> { + let base = container( + row![ + column![ + button("Disabled"), + button("Filled").on_press(Message::Noop), + button("Filled Tonal") + .on_press(Message::Noop) + .style(filled_tonal), + button("Elevated").on_press(Message::Noop).style(elevated), + button("Outlined").on_press(Message::Noop).style(outlined), + button("Text").on_press(Message::Noop).style(text), + button("Text Disabled").style(text), + ] + .spacing(10), + column![ + container("None").padding(8), + container("Primary").padding(8).style(primary), + container("Primary Container") + .padding(8) + .style(primary_container), + container("Secondary").padding(8).style(secondary), + container("Secondary Container") + .padding(8) + .style(secondary_container), + container("Tertiary").padding(8).style(tertiary), + container("Tertiary Container") + .padding(8) + .style(tertiary_container), + container("Error").padding(8).style(error), + container("Error Container") + .padding(8) + .style(error_container), + container("Surface").padding(8).style(surface), + container( + iced::widget::text("Surface Variant") + .style(surface_variant) + ) .padding(8) .style(surface), - container("Inverse Surface") - .padding(8) - .style(inverse_surface), - container("Surface Container Lowest") - .padding(8) - .style(surface_container_lowest), - container("Surface Container Low") - .padding(8) - .style(surface_container_low), - container("Surface Container") - .padding(8) - .style(surface_container), - container("Surface Container High") - .padding(8) - .style(surface_container_high), - container("Surface Container Highest") - .padding(8) - .style(surface_container_highest), + container("Inverse Surface") + .padding(8) + .style(inverse_surface), + container("Surface Container Lowest") + .padding(8) + .style(surface_container_lowest), + container("Surface Container Low") + .padding(8) + .style(surface_container_low), + container("Surface Container") + .padding(8) + .style(surface_container), + container("Surface Container High") + .padding(8) + .style(surface_container_high), + container("Surface Container Highest") + .padding(8) + .style(surface_container_highest), + ] + .spacing(10), + pick_list( + [LIGHT.clone(), DARK.clone()], + Some(self.theme.target()), + |theme| Message::SwitchTheme(theme.into()) + ) + .placeholder("Select a theme..."), + button("Open Dialog").on_press(Message::OpenDialog) ] - .spacing(10) - ] - .spacing(20), - ) - .padding(12) - .into() + .spacing(20), + ) + .width(Fill) + .height(Fill) + .padding(12); + + let dialog = + dialog(self.show_dialog, base, iced::widget::text("Say Hi!")) + .title("This is a Dialog.") + .push_button( + iced_dialog::button("Hi!").on_press(Message::CloseDialog), + ) + .backdrop(|theme| theme.colorscheme.scrim) + .width(280) + .height(187); + + Animation::new(&self.theme, dialog) + .on_update(Message::SwitchTheme) + .into() + } } -- cgit v1.2.3 From 495985f449e46b24e6b734d3aa9e135a779a8b77 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 03:40:38 +0200 Subject: refactor: move `material_theme` and `iced_drop` into separate crates dir --- Cargo.toml | 7 +- crates/iced_drop/Cargo.toml | 7 + crates/iced_drop/LICENSE | 21 + crates/iced_drop/README.md | 73 ++++ crates/iced_drop/src/lib.rs | 55 +++ crates/iced_drop/src/widget.rs | 2 + crates/iced_drop/src/widget/droppable.rs | 574 +++++++++++++++++++++++++ crates/iced_drop/src/widget/operation.rs | 1 + crates/iced_drop/src/widget/operation/drop.rs | 88 ++++ crates/material_theme/Cargo.toml | 53 +++ crates/material_theme/README.md | 3 + crates/material_theme/assets/themes/dark.toml | 49 +++ crates/material_theme/assets/themes/light.toml | 49 +++ crates/material_theme/src/button.rs | 193 +++++++++ crates/material_theme/src/container.rs | 173 ++++++++ crates/material_theme/src/dialog.rs | 25 ++ crates/material_theme/src/lib.rs | 248 +++++++++++ crates/material_theme/src/menu.rs | 33 ++ crates/material_theme/src/pick_list.rs | 40 ++ crates/material_theme/src/scrollable.rs | 153 +++++++ crates/material_theme/src/text.rs | 86 ++++ crates/material_theme/src/utils.rs | 116 +++++ iced_drop/Cargo.toml | 7 - iced_drop/LICENSE | 21 - iced_drop/README.md | 73 ---- iced_drop/src/lib.rs | 55 --- iced_drop/src/widget.rs | 2 - iced_drop/src/widget/droppable.rs | 574 ------------------------- iced_drop/src/widget/operation.rs | 1 - iced_drop/src/widget/operation/drop.rs | 88 ---- material_theme/Cargo.toml | 53 --- material_theme/README.md | 3 - material_theme/assets/themes/dark.toml | 49 --- material_theme/assets/themes/light.toml | 49 --- material_theme/src/button.rs | 193 --------- material_theme/src/container.rs | 173 -------- material_theme/src/dialog.rs | 25 -- material_theme/src/lib.rs | 248 ----------- material_theme/src/menu.rs | 33 -- material_theme/src/pick_list.rs | 40 -- material_theme/src/scrollable.rs | 161 ------- material_theme/src/text.rs | 86 ---- material_theme/src/utils.rs | 116 ----- theme_test/Cargo.toml | 2 +- 44 files changed, 2047 insertions(+), 2054 deletions(-) create mode 100644 crates/iced_drop/Cargo.toml create mode 100644 crates/iced_drop/LICENSE create mode 100644 crates/iced_drop/README.md create mode 100644 crates/iced_drop/src/lib.rs create mode 100644 crates/iced_drop/src/widget.rs create mode 100644 crates/iced_drop/src/widget/droppable.rs create mode 100644 crates/iced_drop/src/widget/operation.rs create mode 100644 crates/iced_drop/src/widget/operation/drop.rs create mode 100644 crates/material_theme/Cargo.toml create mode 100644 crates/material_theme/README.md create mode 100644 crates/material_theme/assets/themes/dark.toml create mode 100644 crates/material_theme/assets/themes/light.toml create mode 100644 crates/material_theme/src/button.rs create mode 100644 crates/material_theme/src/container.rs create mode 100644 crates/material_theme/src/dialog.rs create mode 100644 crates/material_theme/src/lib.rs create mode 100644 crates/material_theme/src/menu.rs create mode 100644 crates/material_theme/src/pick_list.rs create mode 100644 crates/material_theme/src/scrollable.rs create mode 100644 crates/material_theme/src/text.rs create mode 100644 crates/material_theme/src/utils.rs delete mode 100644 iced_drop/Cargo.toml delete mode 100644 iced_drop/LICENSE delete mode 100644 iced_drop/README.md delete mode 100644 iced_drop/src/lib.rs delete mode 100644 iced_drop/src/widget.rs delete mode 100644 iced_drop/src/widget/droppable.rs delete mode 100644 iced_drop/src/widget/operation.rs delete mode 100644 iced_drop/src/widget/operation/drop.rs delete mode 100644 material_theme/Cargo.toml delete mode 100644 material_theme/README.md delete mode 100644 material_theme/assets/themes/dark.toml delete mode 100644 material_theme/assets/themes/light.toml delete mode 100644 material_theme/src/button.rs delete mode 100644 material_theme/src/container.rs delete mode 100644 material_theme/src/dialog.rs delete mode 100644 material_theme/src/lib.rs delete mode 100644 material_theme/src/menu.rs delete mode 100644 material_theme/src/pick_list.rs delete mode 100644 material_theme/src/scrollable.rs delete mode 100644 material_theme/src/text.rs delete mode 100644 material_theme/src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index e48a39c..1c0984b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,9 @@ debug = ["iced/debug"] iced.workspace = true iced_anim.workspace = true iced_custom_highlighter = { git = "https://github.com/pml68/iced_custom_highlighter", branch = "master" } -iced_drop = { path = "iced_drop" } +iced_drop = { path = "crates/iced_drop" } iced_dialog.workspace = true -material_theme = { path = "material_theme" } +material_theme = { path = "crates/material_theme" } serde.workspace = true serde_json = "1.0.140" toml.workspace = true @@ -74,7 +74,8 @@ name = "iced-builder" path = "src/main.rs" [workspace] -members = ["iced_drop", "material_theme", "theme_test"] +members = ["crates/*", "theme_test"] +default-members = ["crates/material_theme", "."] [lints.rust] missing_debug_implementations = "deny" diff --git a/crates/iced_drop/Cargo.toml b/crates/iced_drop/Cargo.toml new file mode 100644 index 0000000..0692084 --- /dev/null +++ b/crates/iced_drop/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "iced_drop" +version = "0.1.0" +edition = "2021" + +[dependencies] +iced.workspace = true diff --git a/crates/iced_drop/LICENSE b/crates/iced_drop/LICENSE new file mode 100644 index 0000000..89d9fee --- /dev/null +++ b/crates/iced_drop/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 jhannyj + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/iced_drop/README.md b/crates/iced_drop/README.md new file mode 100644 index 0000000..be854f2 --- /dev/null +++ b/crates/iced_drop/README.md @@ -0,0 +1,73 @@ +# iced_drop - updated to `iced` 0.14-dev + +A small library which provides a custom widget and operation to make drag and drop easier to implement in [iced](https://github.com/iced-rs/iced/tree/master) + +## Usage + +To add drag and drog functionality, first define two messages with the following format + +```rust +enum Message { + Drop(iced::Point, iced::Rectangle) + HandleZones(Vec<(iced::advanced::widget::Id, iced::Rectangle)>) +} +``` + +The `Drop` message will be sent when the droppable is being dragged, and the left mouse button is released. This message provides the mouse position and layout boundaries of the droppable at the release point. + +The `HandleZones` message will be sent after an operation that finds the drop zones under the mouse position. It provides the Id and bounds for each drop zone. + +Next, create create a droppable in the view method and assign the on_drop message. The dropopable function takes an `impl Into` object, so it's easy to make a droppable from any iced widget. + +```rust +iced_drop::droppable("Drop me!").on_drop(Message::Drop); +``` + +Next, create a "drop zone." A drop zone is any widget that operates like a container andhas some assigned Id. It's important that the widget is assigned some Id or it won't be recognized as a drop zone. + +```rust +iced::widget::container("Drop zone") + .id(iced::widget::container::Id::new("drop_zone")); +``` + +Finally, handle the updates of the drop messages + +```rust +match message { + Message::Drop(cursor_pos, _) => { + return iced_drop::zones_on_point( + Message::HandleZonesFound, + point, + None, + None, + ); + } + Message::HandleZones(zones) => { + println!("{:?}", zones) + } +} +``` + +On Drop, we return a widget operation that looks for drop zones under the cursor_pos. When this operation finishes, it returns the zones found and sends the `HandleZones` message. In this example, we only defined one zone, so the zones vector will either be empty if the droppable was not dropped on the zone, or it will contain the `drop_zone` + +## Examples + +There are two examples: color, todo. + +The color example is a very basic drag/drop showcase where the user can drag colors into zones and change the zone's color. I would start here. + +[Link to video](https://drive.google.com/file/d/1K1CCi2Lc90IUyDufsvoUBZmUCbeg6_Fi/view?usp=sharing) + +To run this examples: `cargo run -p color` + +The todo example is a basic todo board application similar to Trello. This is a much much more complex example as it handles custom highlighting and nested droppables, but it just shows you can make some pretty cool things with iced. + +[Link to video](https://drive.google.com/file/d/1MLOCk4Imd_oUnrTj_psbpYbwua976HmR/view?usp=sharing) + +To run this example try: `cargo run -p todo` + +Note: the todo example might also be a good example on how one can use operations. Check examples/todo/src/operation.rs. I didn't find any other examples of this in the iced repo except for the built in focus operations. + +## Future Development + +Right now it's a little annoying having to work with iced's Id type. At some point, I will work on a drop_zone widget that can take some generic clonable type as an id, and I will create a seperate find_zones operation that will return a list of this custom Id. This should make it easier to determine which drop zones were found. diff --git a/crates/iced_drop/src/lib.rs b/crates/iced_drop/src/lib.rs new file mode 100644 index 0000000..c1e1b03 --- /dev/null +++ b/crates/iced_drop/src/lib.rs @@ -0,0 +1,55 @@ +pub mod widget; + +use iced::advanced::graphics::futures::MaybeSend; +use iced::advanced::renderer; +use iced::advanced::widget::{operate, Id}; +use iced::task::Task; +use iced::{Element, Point, Rectangle}; +use widget::droppable::*; +use widget::operation::drop; + +pub fn droppable<'a, Message, Theme, Renderer>( + content: impl Into>, +) -> Droppable<'a, Message, Theme, Renderer> +where + Message: Clone, + Renderer: renderer::Renderer, +{ + Droppable::new(content) +} + +pub fn zones_on_point( + msg: MF, + point: Point, + options: Option>, + depth: Option, +) -> Task +where + T: Send + 'static, + MF: Fn(Vec<(Id, Rectangle)>) -> T + MaybeSend + Sync + Clone + 'static, +{ + operate(drop::find_zones( + move |bounds| bounds.contains(point), + options, + depth, + )) + .map(move |id| msg(id)) +} + +pub fn find_zones( + msg: MF, + filter: F, + options: Option>, + depth: Option, +) -> Task +where + Message: Send + 'static, + MF: Fn(Vec<(Id, Rectangle)>) -> Message + + MaybeSend + + Sync + + Clone + + 'static, + F: Fn(&Rectangle) -> bool + Send + 'static, +{ + operate(drop::find_zones(filter, options, depth)).map(move |id| msg(id)) +} diff --git a/crates/iced_drop/src/widget.rs b/crates/iced_drop/src/widget.rs new file mode 100644 index 0000000..6b3fed2 --- /dev/null +++ b/crates/iced_drop/src/widget.rs @@ -0,0 +1,2 @@ +pub mod droppable; +pub mod operation; diff --git a/crates/iced_drop/src/widget/droppable.rs b/crates/iced_drop/src/widget/droppable.rs new file mode 100644 index 0000000..947cf5b --- /dev/null +++ b/crates/iced_drop/src/widget/droppable.rs @@ -0,0 +1,574 @@ +//! Encapsulates a widget that can be dragged and dropped. +use std::fmt::Debug; +use std::vec; + +use iced::advanced::widget::{Operation, Tree, Widget}; +use iced::advanced::{self, Layout, layout, mouse, overlay, renderer}; +use iced::{Element, Point, Rectangle, Size, Vector}; + +/// An element that can be dragged and dropped on a [`DropZone`] +pub struct Droppable< + 'a, + Message, + Theme = iced::Theme, + Renderer = iced::Renderer, +> where + Message: Clone, + Renderer: renderer::Renderer, +{ + content: Element<'a, Message, Theme, Renderer>, + id: Option, + on_click: Option, + on_drop: Option Message + 'a>>, + on_drag: Option Message + 'a>>, + on_cancel: Option, + drag_mode: Option<(bool, bool)>, + drag_overlay: bool, + drag_hide: bool, + drag_center: bool, + drag_size: Option, + reset_delay: usize, + status: Option, +} + +impl<'a, Message, Theme, Renderer> Droppable<'a, Message, Theme, Renderer> +where + Message: Clone, + Renderer: renderer::Renderer, +{ + /// Creates a new [`Droppable`]. + pub fn new( + content: impl Into>, + ) -> Self { + Self { + content: content.into(), + id: None, + on_click: None, + on_drop: None, + on_drag: None, + on_cancel: None, + drag_mode: Some((true, true)), + drag_overlay: true, + drag_hide: false, + drag_center: false, + drag_size: None, + reset_delay: 0, + status: None, + } + } + + /// Sets the unique identifier of the [`Droppable`]. + pub fn id(mut self, id: iced::advanced::widget::Id) -> Self { + self.id = Some(id); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is clicked. + pub fn on_click(mut self, message: Message) -> Self { + self.on_click = Some(message); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is dropped on a [`DropZone`]. + /// + /// Unless this is set, the [`Droppable`] will be disabled. + pub fn on_drop(mut self, message: F) -> Self + where + F: Fn(Point, Rectangle) -> Message + 'a, + { + self.on_drop = Some(Box::new(message)); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is dragged. + pub fn on_drag(mut self, message: F) -> Self + where + F: Fn(Point, Rectangle) -> Message + 'a, + { + self.on_drag = Some(Box::new(message)); + self + } + + /// Sets the message that will be produced when the user right clicks while dragging the [`Droppable`]. + pub fn on_cancel(mut self, message: Message) -> Self { + self.on_cancel = Some(message); + self + } + + /// Sets whether the [`Droppable`] should be drawn under the cursor while dragging. + pub fn drag_overlay(mut self, drag_overlay: bool) -> Self { + self.drag_overlay = drag_overlay; + self + } + + /// Sets whether the [`Droppable`] should be hidden while dragging. + pub fn drag_hide(mut self, drag_hide: bool) -> Self { + self.drag_hide = drag_hide; + self + } + + /// Sets whether the [`Droppable`] should be centered on the cursor while dragging. + pub fn drag_center(mut self, drag_center: bool) -> Self { + self.drag_center = drag_center; + self + } + + // Sets whether the [`Droppable`] can be dragged along individual axes. + pub fn drag_mode(mut self, drag_x: bool, drag_y: bool) -> Self { + self.drag_mode = Some((drag_x, drag_y)); + self + } + + /// Sets whether the [`Droppable`] should be be resized to a given size while dragging. + pub fn drag_size(mut self, hide_size: Size) -> Self { + self.drag_size = Some(hide_size); + self + } + + /// Sets the number of frames/layout calls to wait before resetting the size of the [`Droppable`] after dropping. + /// + /// This is useful for cases where the [`Droppable`] is being moved to a new location after some widget operation. + /// In this case, the [`Droppable`] will mainting the 'drag_size' for the given number of frames before resetting to its original size. + /// This prevents the [`Droppable`] from 'jumping' back to its original size before the new location is rendered which + /// prevents flickering. + /// + /// Warning: this should only be set if there's is some noticeble flickering when the [`Droppable`] is dropped. That is, if the + /// [`Droppable`] returns to its original size before it's moved to it's new location. + pub fn reset_delay(mut self, reset_delay: usize) -> Self { + self.reset_delay = reset_delay; + self + } +} + +impl<'a, Message, Theme, Renderer> Widget + for Droppable<'a, Message, Theme, Renderer> +where + Message: Clone, + Renderer: renderer::Renderer, +{ + fn state(&self) -> iced::advanced::widget::tree::State { + advanced::widget::tree::State::new(State::default()) + } + + fn tag(&self) -> iced::advanced::widget::tree::Tag { + advanced::widget::tree::Tag::of::() + } + + fn children(&self) -> Vec { + vec![advanced::widget::Tree::new(&self.content)] + } + + fn diff(&self, tree: &mut iced::advanced::widget::Tree) { + tree.diff_children(std::slice::from_ref(&self.content)) + } + + fn size(&self) -> iced::Size { + self.content.as_widget().size() + } + + fn update( + &mut self, + tree: &mut iced::advanced::widget::Tree, + event: &iced::Event, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + _renderer: &Renderer, + _clipboard: &mut dyn iced::advanced::Clipboard, + shell: &mut iced::advanced::Shell<'_, Message>, + _viewport: &iced::Rectangle, + ) { + // handle the on event of the content first, in case that the droppable is nested + self.content.as_widget_mut().update( + &mut tree.children[0], + event, + layout, + cursor, + _renderer, + _clipboard, + shell, + _viewport, + ); + // this should really only be captured if the droppable is nested or it contains some other + // widget that captures the event + if shell.is_event_captured() { + return; + } + + if let Some(on_drop) = self.on_drop.as_deref() { + let state = tree.state.downcast_mut::(); + if let iced::Event::Mouse(mouse) = event { + match mouse { + mouse::Event::ButtonPressed(btn) => { + if *btn == mouse::Button::Left + && cursor.is_over(layout.bounds()) + { + // select the droppable and store the position of the widget before dragging + state.action = + Action::Select(cursor.position().unwrap()); + let bounds = layout.bounds(); + state.widget_pos = bounds.position(); + state.overlay_bounds.width = bounds.width; + state.overlay_bounds.height = bounds.height; + + if let Some(on_click) = self.on_click.clone() { + shell.publish(on_click); + } + shell.capture_event(); + } else if *btn == mouse::Button::Right { + if let Action::Drag(_, _) = state.action { + shell.invalidate_layout(); + state.action = Action::None; + if let Some(on_cancel) = self.on_cancel.clone() + { + shell.publish(on_cancel); + } + } + } + } + mouse::Event::CursorMoved { mut position } => match state + .action + { + Action::Select(start) | Action::Drag(start, _) => { + // calculate the new position of the widget after dragging + + if let Some((drag_x, drag_y)) = self.drag_mode { + position = Point { + x: if drag_x { + position.x + } else { + start.x + }, + y: if drag_y { + position.y + } else { + start.y + }, + }; + } + + state.action = Action::Drag(start, position); + // update the position of the overlay since the cursor was moved + if self.drag_center { + state.overlay_bounds.x = position.x + - state.overlay_bounds.width / 2.0; + state.overlay_bounds.y = position.y + - state.overlay_bounds.height / 2.0; + } else { + state.overlay_bounds.x = + state.widget_pos.x + position.x - start.x; + state.overlay_bounds.y = + state.widget_pos.y + position.y - start.y; + } + // send on drag msg + if let Some(on_drag) = self.on_drag.as_deref() { + let message = + (on_drag)(position, state.overlay_bounds); + shell.publish(message); + } + + shell.request_redraw(); + } + _ => (), + }, + mouse::Event::ButtonReleased(mouse::Button::Left) => { + match state.action { + Action::Select(_) => { + state.action = Action::None; + } + Action::Drag(_, current) => { + // send on drop msg + let message = + (on_drop)(current, state.overlay_bounds); + shell.publish(message); + + if self.reset_delay == 0 { + state.action = Action::None; + } else { + state.action = + Action::Wait(self.reset_delay); + } + } + _ => (), + } + } + _ => {} + } + } + } + + let current_status = if cursor.is_over(layout.bounds()) { + if self.on_drop.is_none() { + Status::Disabled + } else { + let state = tree.state.downcast_ref::(); + + if let Action::Drag(_, _) = state.action { + Status::Dragged + } else { + Status::Hovered + } + } + } else { + Status::Active + }; + + if let iced::Event::Window(iced::window::Event::RedrawRequested(_now)) = + event + { + self.status = Some(current_status); + } else if self.status.is_some_and(|status| status != current_status) { + shell.request_redraw(); + } + } + + fn layout( + &self, + tree: &mut iced::advanced::widget::Tree, + renderer: &Renderer, + limits: &iced::advanced::layout::Limits, + ) -> iced::advanced::layout::Node { + let state: &mut State = tree.state.downcast_mut::(); + let content_node = self.content.as_widget().layout( + &mut tree.children[0], + renderer, + limits, + ); + + // Adjust the size of the original widget if it's being dragged or we're wating to reset the size + if let Some(new_size) = self.drag_size { + match state.action { + Action::Drag(_, _) => { + return iced::advanced::layout::Node::with_children( + new_size, + content_node.children().to_vec(), + ); + } + Action::Wait(reveal_index) => { + if reveal_index <= 1 { + state.action = Action::None; + } else { + state.action = Action::Wait(reveal_index - 1); + } + + return iced::advanced::layout::Node::with_children( + new_size, + content_node.children().to_vec(), + ); + } + _ => (), + } + } + + content_node + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + let state = tree.state.downcast_mut::(); + operation.custom(self.id.as_ref(), layout.bounds(), state); + operation.container( + self.id.as_ref(), + layout.bounds(), + &mut |operation| { + self.content.as_widget().operate( + &mut tree.children[0], + layout, + renderer, + operation, + ); + }, + ); + } + + fn draw( + &self, + tree: &iced::advanced::widget::Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + viewport: &iced::Rectangle, + ) { + let state: &State = tree.state.downcast_ref::(); + if let Action::Drag(_, _) = state.action { + if self.drag_hide { + return; + } + } + + self.content.as_widget().draw( + &tree.children[0], + renderer, + theme, + style, + layout, + cursor, + &viewport, + ); + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + _translation: Vector, + ) -> Option> { + let state: &mut State = tree.state.downcast_mut::(); + if self.drag_overlay { + if let Action::Drag(_, _) = state.action { + return Some(overlay::Element::new(Box::new(Overlay { + content: &self.content, + tree: &mut tree.children[0], + overlay_bounds: state.overlay_bounds, + }))); + } + } + self.content.as_widget_mut().overlay( + &mut tree.children[0], + layout, + renderer, + _translation, + ) + } + + fn mouse_interaction( + &self, + tree: &iced::advanced::widget::Tree, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + _viewport: &iced::Rectangle, + _renderer: &Renderer, + ) -> iced::advanced::mouse::Interaction { + let child_interact = self.content.as_widget().mouse_interaction( + &tree.children[0], + layout, + cursor, + _viewport, + _renderer, + ); + + if child_interact != mouse::Interaction::default() { + return child_interact; + } + + let state = tree.state.downcast_ref::(); + + if self.on_drop.is_none() && cursor.is_over(layout.bounds()) { + return mouse::Interaction::NotAllowed; + } + + if let Action::Drag(_, _) = state.action { + return mouse::Interaction::Grabbing; + } + + if cursor.is_over(layout.bounds()) { + return mouse::Interaction::Pointer; + } + + mouse::Interaction::default() + } +} + +impl<'a, Message, Theme, Renderer> From> + for Element<'a, Message, Theme, Renderer> +where + Message: 'a + Clone, + Theme: 'a, + Renderer: 'a + renderer::Renderer, +{ + fn from( + droppable: Droppable<'a, Message, Theme, Renderer>, + ) -> Element<'a, Message, Theme, Renderer> { + Element::new(droppable) + } +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub struct State { + widget_pos: Point, + overlay_bounds: Rectangle, + action: Action, +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub enum Status { + #[default] + Active, + Hovered, + Dragged, + Disabled, +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub enum Action { + #[default] + None, + /// (point clicked) + Select(Point), + /// (start pos, current pos) + Drag(Point, Point), + /// (frames to wait) + Wait(usize), +} + +struct Overlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + content: &'b Element<'a, Message, Theme, Renderer>, + tree: &'b mut advanced::widget::Tree, + overlay_bounds: Rectangle, +} + +impl<'a, 'b, Message, Theme, Renderer> + overlay::Overlay + for Overlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + fn layout(&mut self, renderer: &Renderer, _bounds: Size) -> layout::Node { + Widget::::layout( + self.content.as_widget(), + self.tree, + renderer, + &layout::Limits::new(Size::ZERO, self.overlay_bounds.size()), + ) + .move_to(self.overlay_bounds.position()) + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Theme, + inherited_style: &renderer::Style, + layout: Layout<'_>, + cursor_position: mouse::Cursor, + ) { + Widget::::draw( + self.content.as_widget(), + self.tree, + renderer, + theme, + inherited_style, + layout, + cursor_position, + &Rectangle::with_size(Size::INFINITY), + ); + } + + fn is_over( + &self, + _layout: Layout<'_>, + _renderer: &Renderer, + _cursor_position: Point, + ) -> bool { + false + } +} diff --git a/crates/iced_drop/src/widget/operation.rs b/crates/iced_drop/src/widget/operation.rs new file mode 100644 index 0000000..3d7dcff --- /dev/null +++ b/crates/iced_drop/src/widget/operation.rs @@ -0,0 +1 @@ +pub mod drop; diff --git a/crates/iced_drop/src/widget/operation/drop.rs b/crates/iced_drop/src/widget/operation/drop.rs new file mode 100644 index 0000000..ead412c --- /dev/null +++ b/crates/iced_drop/src/widget/operation/drop.rs @@ -0,0 +1,88 @@ +use iced::advanced::widget::operation::{Outcome, Scrollable}; +use iced::advanced::widget::{Id, Operation}; +use iced::{Rectangle, Vector}; + +/// Produces an [`Operation`] that will find the drop zones that pass a filter on the zone's bounds. +/// For any drop zone to be considered, the Element must have some Id. +/// If `options` is `None`, all drop zones will be considered. +/// Depth determines how how deep into nested drop zones to go. +/// If 'depth' is `None`, nested dropzones will be fully explored +pub fn find_zones( + filter: F, + options: Option>, + depth: Option, +) -> impl Operation> +where + F: Fn(&Rectangle) -> bool + Send + 'static, +{ + struct FindDropZone { + filter: F, + options: Option>, + zones: Vec<(Id, Rectangle)>, + max_depth: Option, + c_depth: usize, + offset: Vector, + } + + impl Operation> for FindDropZone + where + F: Fn(&Rectangle) -> bool + Send + 'static, + { + fn container( + &mut self, + id: Option<&Id>, + bounds: iced::Rectangle, + operate_on_children: &mut dyn FnMut( + &mut dyn Operation>, + ), + ) { + match id { + Some(id) => { + let is_option = match &self.options { + Some(options) => options.contains(id), + None => true, + }; + let bounds = bounds - self.offset; + if is_option && (self.filter)(&bounds) { + self.c_depth += 1; + self.zones.push((id.clone(), bounds)); + } + } + None => (), + } + let goto_next = match &self.max_depth { + Some(m_depth) => self.c_depth < *m_depth, + None => true, + }; + if goto_next { + operate_on_children(self); + } + } + + fn finish(&self) -> Outcome> { + Outcome::Some(self.zones.clone()) + } + + fn scrollable( + &mut self, + _id: Option<&Id>, + bounds: Rectangle, + _content_bounds: Rectangle, + translation: Vector, + _state: &mut dyn Scrollable, + ) { + if (self.filter)(&bounds) { + self.offset = self.offset + translation; + } + } + } + + FindDropZone { + filter, + options, + zones: vec![], + max_depth: depth, + c_depth: 0, + offset: Vector { x: 0.0, y: 0.0 }, + } +} diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml new file mode 100644 index 0000000..eef9605 --- /dev/null +++ b/crates/material_theme/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "material_theme" +description = "An M3 inspired theme for `iced`" +authors = ["pml68 "] +version = "0.14.0-dev" +edition = "2024" +license = "MIT" +# readme = "README.md" +repository = "https://github.com/pml68/iced_builder" +categories = ["gui"] +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +rust-version = "1.85" + +[features] +default = [] +animate = ["dep:iced_anim"] +dialog = ["dep:iced_dialog"] + +[dependencies] +iced_widget = "0.14.0-dev" +serde.workspace = true +toml.workspace = true +dark-light = "2.0.0" +iced_dialog.workspace = true +iced_dialog.optional = true + +[dependencies.iced_anim] +workspace = true +features = ["derive"] +optional = true + +[lints.rust] +missing_debug_implementations = "deny" +unsafe_code = "deny" +unused_results = "deny" + +[lints.clippy] +type-complexity = "allow" +semicolon_if_nothing_returned = "deny" +trivially-copy-pass-by-ref = "deny" +default_trait_access = "deny" +match-wildcard-for-single-variants = "deny" +redundant-closure-for-method-calls = "deny" +filter_map_next = "deny" +manual_let_else = "deny" +unused_async = "deny" +from_over_into = "deny" +needless_borrow = "deny" +new_without_default = "deny" +useless_conversion = "deny" + +[lints.rustdoc] +broken_intra_doc_links = "forbid" diff --git a/crates/material_theme/README.md b/crates/material_theme/README.md new file mode 100644 index 0000000..da5a1ec --- /dev/null +++ b/crates/material_theme/README.md @@ -0,0 +1,3 @@ +# material_theme + +## A [Material3](https://m3.material.io) inspired custom theme for [`iced`](https://iced.rs) diff --git a/crates/material_theme/assets/themes/dark.toml b/crates/material_theme/assets/themes/dark.toml new file mode 100644 index 0000000..18a369f --- /dev/null +++ b/crates/material_theme/assets/themes/dark.toml @@ -0,0 +1,49 @@ +name = "Dark" + +shadow = "#000000" +scrim = "#4d000000" + +[primary] +color = "#9bd4a1" +on_primary = "#003916" +primary_container = "#1b5129" +on_primary_container = "#b6f1bb" + +[secondary] +color = "#b8ccb6" +on_secondary = "#233425" +secondary_container = "#394b3a" +on_secondary_container = "#d3e8d1" + +[tertiary] +color = "#a1ced7" +on_tertiary = "#00363e" +tertiary_container = "#1f4d55" +on_tertiary_container = "#bdeaf4" + +[error] +color = "#ffb4ab" +on_error = "#690005" +error_container = "#93000a" +on_error_container = "#ffdad6" + +[surface] +color = "#101510" +on_surface = "#e0e4dc" +on_surface_variant = "#c1c9be" + +[surface.surface_container] +lowest = "#0b0f0b" +low = "#181d18" +base = "#1c211c" +high = "#262b26" +highest = "#313631" + +[inverse] +inverse_surface = "#e0e4dc" +inverse_on_surface = "#2d322c" +inverse_primary = "#34693f" + +[outline] +color = "#8b9389" +variant = "#414941" diff --git a/crates/material_theme/assets/themes/light.toml b/crates/material_theme/assets/themes/light.toml new file mode 100644 index 0000000..a7115c4 --- /dev/null +++ b/crates/material_theme/assets/themes/light.toml @@ -0,0 +1,49 @@ +name = "Light" + +shadow = "#000000" +scrim = "#4d000000" + +[primary] +color = "#34693f" +on_primary = "#ffffff" +primary_container = "#b6f1bb" +on_primary_container = "#1b5129" + +[secondary] +color = "#516351" +on_secondary = "#ffffff" +secondary_container = "#d3e8d1" +on_secondary_container = "#394b3a" + +[tertiary] +color = "#39656d" +on_tertiary = "#ffffff" +tertiary_container = "#bdeaf4" +on_tertiary_container = "#1f4d55" + +[error] +color = "#ba1a1a" +on_error = "#ffffff" +error_container = "#ffdad6" +on_error_container = "#93000a" + +[surface] +color = "#f7fbf2" +on_surface = "#181d18" +on_surface_variant = "#414941" + +[surface.surface_container] +lowest = "#ffffff" +low = "#f1f5ed" +base = "#ebefe7" +high = "#e5e9e1" +highest = "#e0e4dc" + +[inverse] +inverse_surface = "#2d322c" +inverse_on_surface = "#eef2ea" +inverse_primary = "#9bd4a1" + +[outline] +color = "#727970" +variant = "#c1c9be" diff --git a/crates/material_theme/src/button.rs b/crates/material_theme/src/button.rs new file mode 100644 index 0000000..21d77b7 --- /dev/null +++ b/crates/material_theme/src/button.rs @@ -0,0 +1,193 @@ +use iced_widget::button::{Catalog, Status, Style, StyleFn}; +use iced_widget::core::{Background, Border, Color, border}; + +use crate::Theme; +use crate::utils::{ + DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, + PRESSED_LAYER_OPACITY, elevation, mix, shadow_from_elevation, +}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(filled) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +fn button( + foreground: Color, + background: Color, + tone_overlay: Color, + disabled: Color, + shadow_color: Color, + elevation_level: u8, + status: Status, +) -> Style { + let active = Style { + background: Some(Background::Color(background)), + text_color: foreground, + border: border::rounded(400), + shadow: shadow_from_elevation(elevation(elevation_level), shadow_color), + }; + + match status { + Status::Active => active, + Status::Pressed => Style { + background: Some(Background::Color(mix( + background, + tone_overlay, + HOVERED_LAYER_OPACITY, + ))), + ..active + }, + Status::Hovered => Style { + background: Some(Background::Color(mix( + background, + tone_overlay, + PRESSED_LAYER_OPACITY, + ))), + text_color: foreground, + border: border::rounded(400), + shadow: shadow_from_elevation( + elevation(elevation_level + 1), + shadow_color, + ), + }, + Status::Disabled => Style { + background: Some(Background::Color(Color { + a: DISABLED_CONTAINER_OPACITY, + ..disabled + })), + text_color: Color { + a: DISABLED_TEXT_OPACITY, + ..disabled + }, + border: border::rounded(400), + ..Default::default() + }, + } +} + +pub fn elevated(theme: &Theme, status: Status) -> Style { + let surface_colors = theme.colorscheme.surface; + + let foreground = theme.colorscheme.primary.color; + let background = surface_colors.surface_container.low; + let disabled = surface_colors.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 1, + status, + ) +} + +pub fn filled(theme: &Theme, status: Status) -> Style { + let primary_colors = theme.colorscheme.primary; + + let foreground = primary_colors.on_primary; + let background = primary_colors.color; + let disabled = theme.colorscheme.surface.on_surface; + + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn filled_tonal(theme: &Theme, status: Status) -> Style { + let secondary_colors = theme.colorscheme.secondary; + + let foreground = secondary_colors.on_secondary_container; + let background = secondary_colors.secondary_container; + let disabled = theme.colorscheme.surface.on_surface; + let shadow_color = theme.colorscheme.shadow; + + button( + foreground, + background, + foreground, + disabled, + shadow_color, + 0, + status, + ) +} + +pub fn outlined(theme: &Theme, status: Status) -> Style { + let foreground = theme.colorscheme.primary.color; + let background = Color::TRANSPARENT; + let disabled = theme.colorscheme.surface.on_surface; + + let outline = theme.colorscheme.outline.color; + + let border = match status { + Status::Active | Status::Pressed | Status::Hovered => Border { + color: outline, + width: 1.0, + radius: 400.0.into(), + }, + Status::Disabled => Border { + color: Color { + a: DISABLED_CONTAINER_OPACITY, + ..disabled + }, + width: 1.0, + radius: 400.0.into(), + }, + }; + + let style = button( + foreground, + background, + foreground, + disabled, + Color::TRANSPARENT, + 0, + status, + ); + + Style { border, ..style } +} + +pub fn text(theme: &Theme, status: Status) -> Style { + let foreground = theme.colorscheme.primary.color; + let background = Color::TRANSPARENT; + let disabled = theme.colorscheme.surface.on_surface; + + let style = button( + foreground, + background, + foreground, + disabled, + Color::TRANSPARENT, + 0, + status, + ); + + match status { + Status::Hovered | Status::Pressed => style, + _ => Style { + background: None, + ..style + }, + } +} diff --git a/crates/material_theme/src/container.rs b/crates/material_theme/src/container.rs new file mode 100644 index 0000000..a14cfd5 --- /dev/null +++ b/crates/material_theme/src/container.rs @@ -0,0 +1,173 @@ +use iced_widget::container::{Catalog, Style, StyleFn}; +use iced_widget::core::{Background, border}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(transparent) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn transparent(_theme: &Theme) -> Style { + Style { + border: border::rounded(4), + ..Style::default() + } +} + +pub fn primary(theme: &Theme) -> Style { + let colors = theme.colorscheme.primary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_primary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn primary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.primary; + Style { + background: Some(Background::Color(colors.primary_container)), + text_color: Some(colors.on_primary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn secondary(theme: &Theme) -> Style { + let colors = theme.colorscheme.secondary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_secondary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn secondary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.secondary; + Style { + background: Some(Background::Color(colors.secondary_container)), + text_color: Some(colors.on_secondary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn tertiary(theme: &Theme) -> Style { + let colors = theme.colorscheme.tertiary; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_tertiary), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn tertiary_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.tertiary; + Style { + background: Some(Background::Color(colors.tertiary_container)), + text_color: Some(colors.on_tertiary_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn error(theme: &Theme) -> Style { + let colors = theme.colorscheme.error; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_error), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn error_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.error; + Style { + background: Some(Background::Color(colors.error_container)), + text_color: Some(colors.on_error_container), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.color)), + text_color: Some(colors.on_surface), + border: border::rounded(4), + ..Style::default() + } +} + +pub fn surface_container_lowest(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.lowest)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_low(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.low)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.base)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_high(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.high)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn surface_container_highest(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.highest)), + text_color: Some(colors.on_surface), + border: border::rounded(8), + ..Style::default() + } +} + +pub fn inverse_surface(theme: &Theme) -> Style { + let colors = theme.colorscheme.inverse; + Style { + background: Some(Background::Color(colors.inverse_surface)), + text_color: Some(colors.inverse_on_surface), + border: border::rounded(4), + ..Style::default() + } +} diff --git a/crates/material_theme/src/dialog.rs b/crates/material_theme/src/dialog.rs new file mode 100644 index 0000000..68c61b5 --- /dev/null +++ b/crates/material_theme/src/dialog.rs @@ -0,0 +1,25 @@ +use iced_widget::container::Style; +use iced_widget::core::{Background, border}; + +use super::{Theme, text}; + +impl iced_dialog::dialog::Catalog for Theme { + fn default_container<'a>() + -> ::Class<'a> { + Box::new(default_container) + } + + fn default_title<'a>() -> ::Class<'a> { + Box::new(text::surface) + } +} + +pub fn default_container(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + Style { + background: Some(Background::Color(colors.surface_container.high)), + text_color: Some(colors.on_surface_variant), + border: border::rounded(28), + ..Style::default() + } +} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs new file mode 100644 index 0000000..521af2c --- /dev/null +++ b/crates/material_theme/src/lib.rs @@ -0,0 +1,248 @@ +use std::sync::LazyLock; + +use iced_widget::core::Color; +use iced_widget::core::theme::{Base, Style}; +use serde::Deserialize; + +pub mod button; +pub mod container; +#[cfg(feature = "dialog")] +pub mod dialog; +pub mod menu; +pub mod pick_list; +pub mod scrollable; +pub mod text; +pub mod utils; + +const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); +const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); + +#[derive(Debug, PartialEq, Deserialize)] +pub struct Theme { + pub name: String, + #[serde(flatten)] + pub colorscheme: ColorScheme, +} + +impl Theme { + pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { + Self { + name: name.into(), + colorscheme, + } + } +} + +impl Clone for Theme { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + colorscheme: self.colorscheme, + } + } + + fn clone_from(&mut self, source: &Self) { + self.name = source.name.clone(); + self.colorscheme = source.colorscheme; + } +} + +impl Default for Theme { + fn default() -> Self { + static DEFAULT: LazyLock = LazyLock::new(|| { + match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) + { + dark_light::Mode::Dark | dark_light::Mode::Unspecified => { + DARK.clone() + } + dark_light::Mode::Light => LIGHT.clone(), + } + }); + + DEFAULT.clone() + } +} + +impl std::fmt::Display for Theme { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name) + } +} + +impl Base for Theme { + fn base(&self) -> Style { + Style { + background_color: self.colorscheme.surface.color, + text_color: self.colorscheme.surface.on_surface, + } + } + + fn palette(&self) -> Option { + // TODO: create a Palette + None + } +} + +#[cfg(feature = "animate")] +impl iced_anim::Animate for Theme { + fn components() -> usize { + ColorScheme::components() + } + + fn update(&mut self, components: &mut impl Iterator) { + let mut colors = self.colorscheme; + colors.update(components); + + *self = Theme::new("Animating Theme", colors); + } + + fn distance_to(&self, end: &Self) -> Vec { + self.colorscheme.distance_to(&end.colorscheme) + } + + fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { + let mut colors = self.colorscheme; + colors.lerp(&start.colorscheme, &end.colorscheme, progress); + + *self = Theme::new("Animating Theme", colors); + } +} + +pub static DARK: LazyLock = LazyLock::new(|| { + toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") +}); + +pub static LIGHT: LazyLock = LazyLock::new(|| { + toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") +}); + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct ColorScheme { + pub primary: Primary, + pub secondary: Secondary, + pub tertiary: Tertiary, + pub error: Error, + pub surface: Surface, + pub inverse: Inverse, + pub outline: Outline, + #[serde(with = "color_serde")] + pub shadow: Color, + #[serde(with = "color_serde")] + pub scrim: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Primary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_primary: Color, + #[serde(with = "color_serde")] + pub primary_container: Color, + #[serde(with = "color_serde")] + pub on_primary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Secondary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_secondary: Color, + #[serde(with = "color_serde")] + pub secondary_container: Color, + #[serde(with = "color_serde")] + pub on_secondary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Tertiary { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_tertiary: Color, + #[serde(with = "color_serde")] + pub tertiary_container: Color, + #[serde(with = "color_serde")] + pub on_tertiary_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Error { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_error: Color, + #[serde(with = "color_serde")] + pub error_container: Color, + #[serde(with = "color_serde")] + pub on_error_container: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Surface { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub on_surface: Color, + #[serde(with = "color_serde")] + pub on_surface_variant: Color, + pub surface_container: SurfaceContainer, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct SurfaceContainer { + #[serde(with = "color_serde")] + pub lowest: Color, + #[serde(with = "color_serde")] + pub low: Color, + #[serde(with = "color_serde")] + pub base: Color, + #[serde(with = "color_serde")] + pub high: Color, + #[serde(with = "color_serde")] + pub highest: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Inverse { + #[serde(with = "color_serde")] + pub inverse_surface: Color, + #[serde(with = "color_serde")] + pub inverse_on_surface: Color, + #[serde(with = "color_serde")] + pub inverse_primary: Color, +} + +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +pub struct Outline { + #[serde(with = "color_serde")] + pub color: Color, + #[serde(with = "color_serde")] + pub variant: Color, +} + +mod color_serde { + use iced_widget::core::Color; + use serde::{Deserialize, Deserializer}; + + use super::utils::parse_argb; + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(String::deserialize(deserializer) + .map(|hex| parse_argb(&hex))? + .unwrap_or(Color::TRANSPARENT)) + } +} diff --git a/crates/material_theme/src/menu.rs b/crates/material_theme/src/menu.rs new file mode 100644 index 0000000..9f43c72 --- /dev/null +++ b/crates/material_theme/src/menu.rs @@ -0,0 +1,33 @@ +use iced_widget::core::{Background, border}; +use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; + +use super::Theme; +use crate::utils::{HOVERED_LAYER_OPACITY, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(theme: &Theme) -> Style { + let colors = theme.colorscheme.surface; + + Style { + border: border::rounded(4), + background: Background::Color(colors.surface_container.base), + text_color: colors.on_surface, + selected_background: Background::Color(mix( + colors.surface_container.base, + colors.on_surface, + HOVERED_LAYER_OPACITY, + )), + selected_text_color: colors.on_surface, + } +} diff --git a/crates/material_theme/src/pick_list.rs b/crates/material_theme/src/pick_list.rs new file mode 100644 index 0000000..c589100 --- /dev/null +++ b/crates/material_theme/src/pick_list.rs @@ -0,0 +1,40 @@ +use iced_widget::core::{Background, border}; +use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style( + &self, + class: &::Class<'_>, + status: Status, + ) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + + let active = Style { + text_color: surface.on_surface, + placeholder_color: surface.on_surface_variant, + handle_color: surface.on_surface_variant, + background: Background::Color(surface.surface_container.highest), + border: border::rounded(4), + }; + + match status { + Status::Active => active, + Status::Hovered | Status::Opened { .. } => Style { + background: Background::Color(surface.surface_container.highest), + ..active + }, + } +} diff --git a/crates/material_theme/src/scrollable.rs b/crates/material_theme/src/scrollable.rs new file mode 100644 index 0000000..ee739ba --- /dev/null +++ b/crates/material_theme/src/scrollable.rs @@ -0,0 +1,153 @@ +use iced_widget::core::{Border, Color, border}; +use iced_widget::scrollable::{ + Catalog, Rail, Scroller, Status, Style, StyleFn, +}; + +use super::Theme; +use super::container::surface_container; +use super::utils::mix; +use crate::utils::{ + DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, + PRESSED_LAYER_OPACITY, +}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let colors = theme.colorscheme.surface; + + let active = Rail { + background: None, + scroller: Scroller { + color: colors.on_surface, + border: border::rounded(400), + }, + border: Border::default(), + }; + + let disabled = Rail { + background: Some( + Color { + a: DISABLED_CONTAINER_OPACITY, + ..colors.on_surface + } + .into(), + ), + scroller: Scroller { + color: Color { + a: DISABLED_TEXT_OPACITY, + ..colors.on_surface + }, + border: border::rounded(400), + }, + ..active + }; + + let style = Style { + container: surface_container(theme), + vertical_rail: active, + horizontal_rail: active, + gap: None, + }; + + match status { + Status::Active { + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, + } => Style { + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled + } else { + active + }, + vertical_rail: if is_vertical_scrollbar_disabled { + disabled + } else { + active + }, + ..style + }, + Status::Hovered { + is_horizontal_scrollbar_hovered, + is_vertical_scrollbar_hovered, + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, + } => { + let hovered_rail = Rail { + scroller: Scroller { + color: mix( + colors.on_surface, + colors.color, + HOVERED_LAYER_OPACITY, + ), + border: border::rounded(400), + }, + ..active + }; + + Style { + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled + } else if is_horizontal_scrollbar_hovered { + hovered_rail + } else { + active + }, + vertical_rail: if is_vertical_scrollbar_disabled { + disabled + } else if is_vertical_scrollbar_hovered { + hovered_rail + } else { + active + }, + ..style + } + } + Status::Dragged { + is_horizontal_scrollbar_dragged, + is_vertical_scrollbar_dragged, + is_horizontal_scrollbar_disabled, + is_vertical_scrollbar_disabled, + } => { + let dragged_rail = Rail { + scroller: Scroller { + color: mix( + colors.on_surface, + colors.color, + PRESSED_LAYER_OPACITY, + ), + border: border::rounded(400), + }, + ..active + }; + + Style { + horizontal_rail: if is_horizontal_scrollbar_disabled { + disabled + } else if is_horizontal_scrollbar_dragged { + dragged_rail + } else { + active + }, + vertical_rail: if is_vertical_scrollbar_disabled { + disabled + } else if is_vertical_scrollbar_dragged { + dragged_rail + } else { + active + }, + ..style + } + } + } +} diff --git a/crates/material_theme/src/text.rs b/crates/material_theme/src/text.rs new file mode 100644 index 0000000..10b2e65 --- /dev/null +++ b/crates/material_theme/src/text.rs @@ -0,0 +1,86 @@ +#![allow(dead_code)] +use iced_widget::text::{Catalog, Style, StyleFn}; + +use crate::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(none) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn none(_: &Theme) -> Style { + Style { color: None } +} + +pub fn primary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.primary.on_primary), + } +} + +pub fn primary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.primary.on_primary_container), + } +} + +pub fn secondary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.secondary.on_secondary), + } +} + +pub fn secondary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.secondary.on_secondary_container), + } +} + +pub fn tertiary(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.tertiary.on_tertiary), + } +} + +pub fn tertiary_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.tertiary.on_tertiary_container), + } +} + +pub fn error(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.error.on_error), + } +} + +pub fn error_container(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.error.on_error_container), + } +} + +pub fn surface(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.surface.on_surface), + } +} + +pub fn surface_variant(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.surface.on_surface_variant), + } +} + +pub fn inverse_surface(theme: &Theme) -> Style { + Style { + color: Some(theme.colorscheme.inverse.inverse_on_surface), + } +} diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs new file mode 100644 index 0000000..a05bc62 --- /dev/null +++ b/crates/material_theme/src/utils.rs @@ -0,0 +1,116 @@ +use iced_widget::core::{Color, Shadow, Vector}; + +pub const HOVERED_LAYER_OPACITY: f32 = 0.08; +pub const PRESSED_LAYER_OPACITY: f32 = 0.1; + +pub const DISABLED_TEXT_OPACITY: f32 = 0.38; +pub const DISABLED_CONTAINER_OPACITY: f32 = 0.12; + +pub fn elevation(elevation_level: u8) -> f32 { + (match elevation_level { + 0 => 0.0, + 1 => 1.0, + 2 => 3.0, + 3 => 6.0, + 4 => 8.0, + _ => 12.0, + } as f32) +} + +pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { + Shadow { + color, + offset: Vector { + x: 0.0, + y: elevation, + }, + blur_radius: (elevation) * (1.0 + 0.4_f32.powf(elevation)), + } +} + +pub fn parse_argb(s: &str) -> Option { + let hex = s.strip_prefix('#').unwrap_or(s); + + let parse_channel = |from: usize, to: usize| { + let num = + usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; + + // If we only got half a byte (one letter), expand it into a full byte (two letters) + Some(if from == to { num + num * 16.0 } else { num }) + }; + + Some(match hex.len() { + 3 => Color::from_rgb( + parse_channel(0, 0)?, + parse_channel(1, 1)?, + parse_channel(2, 2)?, + ), + 4 => Color::from_rgba( + parse_channel(1, 1)?, + parse_channel(2, 2)?, + parse_channel(3, 3)?, + parse_channel(0, 0)?, + ), + 6 => Color::from_rgb( + parse_channel(0, 1)?, + parse_channel(2, 3)?, + parse_channel(4, 5)?, + ), + 8 => Color::from_rgba( + parse_channel(2, 3)?, + parse_channel(4, 5)?, + parse_channel(6, 7)?, + parse_channel(0, 1)?, + ), + _ => None?, + }) +} + +pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { + if p2 <= 0.0 { + return color1; + } else if p2 >= 1.0 { + return color2; + } + + let p1 = 1.0 - p2; + + if color1.a != 1.0 || color2.a != 1.0 { + let a = color1.a * p1 + color2.a * p2; + if a > 0.0 { + let c1 = color1.into_linear().map(|c| c * color1.a * p1); + let c2 = color2.into_linear().map(|c| c * color2.a * p2); + + let [r, g, b] = + [c1[0] + c2[0], c1[1] + c2[1], c1[2] + c2[2]].map(|u| u / a); + + return Color::from_linear_rgba(r, g, b, a); + } + } + + let c1 = color1.into_linear().map(|c| c * p1); + let c2 = color2.into_linear().map(|c| c * p2); + + Color::from_linear_rgba( + c1[0] + c2[0], + c1[1] + c2[1], + c1[2] + c2[2], + c1[3] + c2[3], + ) +} + +#[cfg(test)] +mod tests { + use super::{Color, mix}; + + #[test] + fn mixing_works() { + let base = Color::from_rgba(1.0, 0.0, 0.0, 0.7); + let overlay = Color::from_rgba(0.0, 1.0, 0.0, 0.2); + + assert_eq!( + mix(base, overlay, 0.75).into_rgba8(), + Color::from_linear_rgba(0.53846, 0.46154, 0.0, 0.325).into_rgba8() + ); + } +} diff --git a/iced_drop/Cargo.toml b/iced_drop/Cargo.toml deleted file mode 100644 index 0692084..0000000 --- a/iced_drop/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "iced_drop" -version = "0.1.0" -edition = "2021" - -[dependencies] -iced.workspace = true diff --git a/iced_drop/LICENSE b/iced_drop/LICENSE deleted file mode 100644 index 89d9fee..0000000 --- a/iced_drop/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 jhannyj - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/iced_drop/README.md b/iced_drop/README.md deleted file mode 100644 index be854f2..0000000 --- a/iced_drop/README.md +++ /dev/null @@ -1,73 +0,0 @@ -# iced_drop - updated to `iced` 0.14-dev - -A small library which provides a custom widget and operation to make drag and drop easier to implement in [iced](https://github.com/iced-rs/iced/tree/master) - -## Usage - -To add drag and drog functionality, first define two messages with the following format - -```rust -enum Message { - Drop(iced::Point, iced::Rectangle) - HandleZones(Vec<(iced::advanced::widget::Id, iced::Rectangle)>) -} -``` - -The `Drop` message will be sent when the droppable is being dragged, and the left mouse button is released. This message provides the mouse position and layout boundaries of the droppable at the release point. - -The `HandleZones` message will be sent after an operation that finds the drop zones under the mouse position. It provides the Id and bounds for each drop zone. - -Next, create create a droppable in the view method and assign the on_drop message. The dropopable function takes an `impl Into` object, so it's easy to make a droppable from any iced widget. - -```rust -iced_drop::droppable("Drop me!").on_drop(Message::Drop); -``` - -Next, create a "drop zone." A drop zone is any widget that operates like a container andhas some assigned Id. It's important that the widget is assigned some Id or it won't be recognized as a drop zone. - -```rust -iced::widget::container("Drop zone") - .id(iced::widget::container::Id::new("drop_zone")); -``` - -Finally, handle the updates of the drop messages - -```rust -match message { - Message::Drop(cursor_pos, _) => { - return iced_drop::zones_on_point( - Message::HandleZonesFound, - point, - None, - None, - ); - } - Message::HandleZones(zones) => { - println!("{:?}", zones) - } -} -``` - -On Drop, we return a widget operation that looks for drop zones under the cursor_pos. When this operation finishes, it returns the zones found and sends the `HandleZones` message. In this example, we only defined one zone, so the zones vector will either be empty if the droppable was not dropped on the zone, or it will contain the `drop_zone` - -## Examples - -There are two examples: color, todo. - -The color example is a very basic drag/drop showcase where the user can drag colors into zones and change the zone's color. I would start here. - -[Link to video](https://drive.google.com/file/d/1K1CCi2Lc90IUyDufsvoUBZmUCbeg6_Fi/view?usp=sharing) - -To run this examples: `cargo run -p color` - -The todo example is a basic todo board application similar to Trello. This is a much much more complex example as it handles custom highlighting and nested droppables, but it just shows you can make some pretty cool things with iced. - -[Link to video](https://drive.google.com/file/d/1MLOCk4Imd_oUnrTj_psbpYbwua976HmR/view?usp=sharing) - -To run this example try: `cargo run -p todo` - -Note: the todo example might also be a good example on how one can use operations. Check examples/todo/src/operation.rs. I didn't find any other examples of this in the iced repo except for the built in focus operations. - -## Future Development - -Right now it's a little annoying having to work with iced's Id type. At some point, I will work on a drop_zone widget that can take some generic clonable type as an id, and I will create a seperate find_zones operation that will return a list of this custom Id. This should make it easier to determine which drop zones were found. diff --git a/iced_drop/src/lib.rs b/iced_drop/src/lib.rs deleted file mode 100644 index c1e1b03..0000000 --- a/iced_drop/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -pub mod widget; - -use iced::advanced::graphics::futures::MaybeSend; -use iced::advanced::renderer; -use iced::advanced::widget::{operate, Id}; -use iced::task::Task; -use iced::{Element, Point, Rectangle}; -use widget::droppable::*; -use widget::operation::drop; - -pub fn droppable<'a, Message, Theme, Renderer>( - content: impl Into>, -) -> Droppable<'a, Message, Theme, Renderer> -where - Message: Clone, - Renderer: renderer::Renderer, -{ - Droppable::new(content) -} - -pub fn zones_on_point( - msg: MF, - point: Point, - options: Option>, - depth: Option, -) -> Task -where - T: Send + 'static, - MF: Fn(Vec<(Id, Rectangle)>) -> T + MaybeSend + Sync + Clone + 'static, -{ - operate(drop::find_zones( - move |bounds| bounds.contains(point), - options, - depth, - )) - .map(move |id| msg(id)) -} - -pub fn find_zones( - msg: MF, - filter: F, - options: Option>, - depth: Option, -) -> Task -where - Message: Send + 'static, - MF: Fn(Vec<(Id, Rectangle)>) -> Message - + MaybeSend - + Sync - + Clone - + 'static, - F: Fn(&Rectangle) -> bool + Send + 'static, -{ - operate(drop::find_zones(filter, options, depth)).map(move |id| msg(id)) -} diff --git a/iced_drop/src/widget.rs b/iced_drop/src/widget.rs deleted file mode 100644 index 6b3fed2..0000000 --- a/iced_drop/src/widget.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod droppable; -pub mod operation; diff --git a/iced_drop/src/widget/droppable.rs b/iced_drop/src/widget/droppable.rs deleted file mode 100644 index 947cf5b..0000000 --- a/iced_drop/src/widget/droppable.rs +++ /dev/null @@ -1,574 +0,0 @@ -//! Encapsulates a widget that can be dragged and dropped. -use std::fmt::Debug; -use std::vec; - -use iced::advanced::widget::{Operation, Tree, Widget}; -use iced::advanced::{self, Layout, layout, mouse, overlay, renderer}; -use iced::{Element, Point, Rectangle, Size, Vector}; - -/// An element that can be dragged and dropped on a [`DropZone`] -pub struct Droppable< - 'a, - Message, - Theme = iced::Theme, - Renderer = iced::Renderer, -> where - Message: Clone, - Renderer: renderer::Renderer, -{ - content: Element<'a, Message, Theme, Renderer>, - id: Option, - on_click: Option, - on_drop: Option Message + 'a>>, - on_drag: Option Message + 'a>>, - on_cancel: Option, - drag_mode: Option<(bool, bool)>, - drag_overlay: bool, - drag_hide: bool, - drag_center: bool, - drag_size: Option, - reset_delay: usize, - status: Option, -} - -impl<'a, Message, Theme, Renderer> Droppable<'a, Message, Theme, Renderer> -where - Message: Clone, - Renderer: renderer::Renderer, -{ - /// Creates a new [`Droppable`]. - pub fn new( - content: impl Into>, - ) -> Self { - Self { - content: content.into(), - id: None, - on_click: None, - on_drop: None, - on_drag: None, - on_cancel: None, - drag_mode: Some((true, true)), - drag_overlay: true, - drag_hide: false, - drag_center: false, - drag_size: None, - reset_delay: 0, - status: None, - } - } - - /// Sets the unique identifier of the [`Droppable`]. - pub fn id(mut self, id: iced::advanced::widget::Id) -> Self { - self.id = Some(id); - self - } - - /// Sets the message that will be produced when the [`Droppable`] is clicked. - pub fn on_click(mut self, message: Message) -> Self { - self.on_click = Some(message); - self - } - - /// Sets the message that will be produced when the [`Droppable`] is dropped on a [`DropZone`]. - /// - /// Unless this is set, the [`Droppable`] will be disabled. - pub fn on_drop(mut self, message: F) -> Self - where - F: Fn(Point, Rectangle) -> Message + 'a, - { - self.on_drop = Some(Box::new(message)); - self - } - - /// Sets the message that will be produced when the [`Droppable`] is dragged. - pub fn on_drag(mut self, message: F) -> Self - where - F: Fn(Point, Rectangle) -> Message + 'a, - { - self.on_drag = Some(Box::new(message)); - self - } - - /// Sets the message that will be produced when the user right clicks while dragging the [`Droppable`]. - pub fn on_cancel(mut self, message: Message) -> Self { - self.on_cancel = Some(message); - self - } - - /// Sets whether the [`Droppable`] should be drawn under the cursor while dragging. - pub fn drag_overlay(mut self, drag_overlay: bool) -> Self { - self.drag_overlay = drag_overlay; - self - } - - /// Sets whether the [`Droppable`] should be hidden while dragging. - pub fn drag_hide(mut self, drag_hide: bool) -> Self { - self.drag_hide = drag_hide; - self - } - - /// Sets whether the [`Droppable`] should be centered on the cursor while dragging. - pub fn drag_center(mut self, drag_center: bool) -> Self { - self.drag_center = drag_center; - self - } - - // Sets whether the [`Droppable`] can be dragged along individual axes. - pub fn drag_mode(mut self, drag_x: bool, drag_y: bool) -> Self { - self.drag_mode = Some((drag_x, drag_y)); - self - } - - /// Sets whether the [`Droppable`] should be be resized to a given size while dragging. - pub fn drag_size(mut self, hide_size: Size) -> Self { - self.drag_size = Some(hide_size); - self - } - - /// Sets the number of frames/layout calls to wait before resetting the size of the [`Droppable`] after dropping. - /// - /// This is useful for cases where the [`Droppable`] is being moved to a new location after some widget operation. - /// In this case, the [`Droppable`] will mainting the 'drag_size' for the given number of frames before resetting to its original size. - /// This prevents the [`Droppable`] from 'jumping' back to its original size before the new location is rendered which - /// prevents flickering. - /// - /// Warning: this should only be set if there's is some noticeble flickering when the [`Droppable`] is dropped. That is, if the - /// [`Droppable`] returns to its original size before it's moved to it's new location. - pub fn reset_delay(mut self, reset_delay: usize) -> Self { - self.reset_delay = reset_delay; - self - } -} - -impl<'a, Message, Theme, Renderer> Widget - for Droppable<'a, Message, Theme, Renderer> -where - Message: Clone, - Renderer: renderer::Renderer, -{ - fn state(&self) -> iced::advanced::widget::tree::State { - advanced::widget::tree::State::new(State::default()) - } - - fn tag(&self) -> iced::advanced::widget::tree::Tag { - advanced::widget::tree::Tag::of::() - } - - fn children(&self) -> Vec { - vec![advanced::widget::Tree::new(&self.content)] - } - - fn diff(&self, tree: &mut iced::advanced::widget::Tree) { - tree.diff_children(std::slice::from_ref(&self.content)) - } - - fn size(&self) -> iced::Size { - self.content.as_widget().size() - } - - fn update( - &mut self, - tree: &mut iced::advanced::widget::Tree, - event: &iced::Event, - layout: iced::advanced::Layout<'_>, - cursor: iced::advanced::mouse::Cursor, - _renderer: &Renderer, - _clipboard: &mut dyn iced::advanced::Clipboard, - shell: &mut iced::advanced::Shell<'_, Message>, - _viewport: &iced::Rectangle, - ) { - // handle the on event of the content first, in case that the droppable is nested - self.content.as_widget_mut().update( - &mut tree.children[0], - event, - layout, - cursor, - _renderer, - _clipboard, - shell, - _viewport, - ); - // this should really only be captured if the droppable is nested or it contains some other - // widget that captures the event - if shell.is_event_captured() { - return; - } - - if let Some(on_drop) = self.on_drop.as_deref() { - let state = tree.state.downcast_mut::(); - if let iced::Event::Mouse(mouse) = event { - match mouse { - mouse::Event::ButtonPressed(btn) => { - if *btn == mouse::Button::Left - && cursor.is_over(layout.bounds()) - { - // select the droppable and store the position of the widget before dragging - state.action = - Action::Select(cursor.position().unwrap()); - let bounds = layout.bounds(); - state.widget_pos = bounds.position(); - state.overlay_bounds.width = bounds.width; - state.overlay_bounds.height = bounds.height; - - if let Some(on_click) = self.on_click.clone() { - shell.publish(on_click); - } - shell.capture_event(); - } else if *btn == mouse::Button::Right { - if let Action::Drag(_, _) = state.action { - shell.invalidate_layout(); - state.action = Action::None; - if let Some(on_cancel) = self.on_cancel.clone() - { - shell.publish(on_cancel); - } - } - } - } - mouse::Event::CursorMoved { mut position } => match state - .action - { - Action::Select(start) | Action::Drag(start, _) => { - // calculate the new position of the widget after dragging - - if let Some((drag_x, drag_y)) = self.drag_mode { - position = Point { - x: if drag_x { - position.x - } else { - start.x - }, - y: if drag_y { - position.y - } else { - start.y - }, - }; - } - - state.action = Action::Drag(start, position); - // update the position of the overlay since the cursor was moved - if self.drag_center { - state.overlay_bounds.x = position.x - - state.overlay_bounds.width / 2.0; - state.overlay_bounds.y = position.y - - state.overlay_bounds.height / 2.0; - } else { - state.overlay_bounds.x = - state.widget_pos.x + position.x - start.x; - state.overlay_bounds.y = - state.widget_pos.y + position.y - start.y; - } - // send on drag msg - if let Some(on_drag) = self.on_drag.as_deref() { - let message = - (on_drag)(position, state.overlay_bounds); - shell.publish(message); - } - - shell.request_redraw(); - } - _ => (), - }, - mouse::Event::ButtonReleased(mouse::Button::Left) => { - match state.action { - Action::Select(_) => { - state.action = Action::None; - } - Action::Drag(_, current) => { - // send on drop msg - let message = - (on_drop)(current, state.overlay_bounds); - shell.publish(message); - - if self.reset_delay == 0 { - state.action = Action::None; - } else { - state.action = - Action::Wait(self.reset_delay); - } - } - _ => (), - } - } - _ => {} - } - } - } - - let current_status = if cursor.is_over(layout.bounds()) { - if self.on_drop.is_none() { - Status::Disabled - } else { - let state = tree.state.downcast_ref::(); - - if let Action::Drag(_, _) = state.action { - Status::Dragged - } else { - Status::Hovered - } - } - } else { - Status::Active - }; - - if let iced::Event::Window(iced::window::Event::RedrawRequested(_now)) = - event - { - self.status = Some(current_status); - } else if self.status.is_some_and(|status| status != current_status) { - shell.request_redraw(); - } - } - - fn layout( - &self, - tree: &mut iced::advanced::widget::Tree, - renderer: &Renderer, - limits: &iced::advanced::layout::Limits, - ) -> iced::advanced::layout::Node { - let state: &mut State = tree.state.downcast_mut::(); - let content_node = self.content.as_widget().layout( - &mut tree.children[0], - renderer, - limits, - ); - - // Adjust the size of the original widget if it's being dragged or we're wating to reset the size - if let Some(new_size) = self.drag_size { - match state.action { - Action::Drag(_, _) => { - return iced::advanced::layout::Node::with_children( - new_size, - content_node.children().to_vec(), - ); - } - Action::Wait(reveal_index) => { - if reveal_index <= 1 { - state.action = Action::None; - } else { - state.action = Action::Wait(reveal_index - 1); - } - - return iced::advanced::layout::Node::with_children( - new_size, - content_node.children().to_vec(), - ); - } - _ => (), - } - } - - content_node - } - - fn operate( - &self, - tree: &mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn Operation, - ) { - let state = tree.state.downcast_mut::(); - operation.custom(self.id.as_ref(), layout.bounds(), state); - operation.container( - self.id.as_ref(), - layout.bounds(), - &mut |operation| { - self.content.as_widget().operate( - &mut tree.children[0], - layout, - renderer, - operation, - ); - }, - ); - } - - fn draw( - &self, - tree: &iced::advanced::widget::Tree, - renderer: &mut Renderer, - theme: &Theme, - style: &renderer::Style, - layout: iced::advanced::Layout<'_>, - cursor: iced::advanced::mouse::Cursor, - viewport: &iced::Rectangle, - ) { - let state: &State = tree.state.downcast_ref::(); - if let Action::Drag(_, _) = state.action { - if self.drag_hide { - return; - } - } - - self.content.as_widget().draw( - &tree.children[0], - renderer, - theme, - style, - layout, - cursor, - &viewport, - ); - } - - fn overlay<'b>( - &'b mut self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - _translation: Vector, - ) -> Option> { - let state: &mut State = tree.state.downcast_mut::(); - if self.drag_overlay { - if let Action::Drag(_, _) = state.action { - return Some(overlay::Element::new(Box::new(Overlay { - content: &self.content, - tree: &mut tree.children[0], - overlay_bounds: state.overlay_bounds, - }))); - } - } - self.content.as_widget_mut().overlay( - &mut tree.children[0], - layout, - renderer, - _translation, - ) - } - - fn mouse_interaction( - &self, - tree: &iced::advanced::widget::Tree, - layout: iced::advanced::Layout<'_>, - cursor: iced::advanced::mouse::Cursor, - _viewport: &iced::Rectangle, - _renderer: &Renderer, - ) -> iced::advanced::mouse::Interaction { - let child_interact = self.content.as_widget().mouse_interaction( - &tree.children[0], - layout, - cursor, - _viewport, - _renderer, - ); - - if child_interact != mouse::Interaction::default() { - return child_interact; - } - - let state = tree.state.downcast_ref::(); - - if self.on_drop.is_none() && cursor.is_over(layout.bounds()) { - return mouse::Interaction::NotAllowed; - } - - if let Action::Drag(_, _) = state.action { - return mouse::Interaction::Grabbing; - } - - if cursor.is_over(layout.bounds()) { - return mouse::Interaction::Pointer; - } - - mouse::Interaction::default() - } -} - -impl<'a, Message, Theme, Renderer> From> - for Element<'a, Message, Theme, Renderer> -where - Message: 'a + Clone, - Theme: 'a, - Renderer: 'a + renderer::Renderer, -{ - fn from( - droppable: Droppable<'a, Message, Theme, Renderer>, - ) -> Element<'a, Message, Theme, Renderer> { - Element::new(droppable) - } -} - -#[derive(Default, Clone, Copy, PartialEq, Debug)] -pub struct State { - widget_pos: Point, - overlay_bounds: Rectangle, - action: Action, -} - -#[derive(Default, Clone, Copy, PartialEq, Debug)] -pub enum Status { - #[default] - Active, - Hovered, - Dragged, - Disabled, -} - -#[derive(Default, Clone, Copy, PartialEq, Debug)] -pub enum Action { - #[default] - None, - /// (point clicked) - Select(Point), - /// (start pos, current pos) - Drag(Point, Point), - /// (frames to wait) - Wait(usize), -} - -struct Overlay<'a, 'b, Message, Theme, Renderer> -where - Renderer: renderer::Renderer, -{ - content: &'b Element<'a, Message, Theme, Renderer>, - tree: &'b mut advanced::widget::Tree, - overlay_bounds: Rectangle, -} - -impl<'a, 'b, Message, Theme, Renderer> - overlay::Overlay - for Overlay<'a, 'b, Message, Theme, Renderer> -where - Renderer: renderer::Renderer, -{ - fn layout(&mut self, renderer: &Renderer, _bounds: Size) -> layout::Node { - Widget::::layout( - self.content.as_widget(), - self.tree, - renderer, - &layout::Limits::new(Size::ZERO, self.overlay_bounds.size()), - ) - .move_to(self.overlay_bounds.position()) - } - - fn draw( - &self, - renderer: &mut Renderer, - theme: &Theme, - inherited_style: &renderer::Style, - layout: Layout<'_>, - cursor_position: mouse::Cursor, - ) { - Widget::::draw( - self.content.as_widget(), - self.tree, - renderer, - theme, - inherited_style, - layout, - cursor_position, - &Rectangle::with_size(Size::INFINITY), - ); - } - - fn is_over( - &self, - _layout: Layout<'_>, - _renderer: &Renderer, - _cursor_position: Point, - ) -> bool { - false - } -} diff --git a/iced_drop/src/widget/operation.rs b/iced_drop/src/widget/operation.rs deleted file mode 100644 index 3d7dcff..0000000 --- a/iced_drop/src/widget/operation.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod drop; diff --git a/iced_drop/src/widget/operation/drop.rs b/iced_drop/src/widget/operation/drop.rs deleted file mode 100644 index ead412c..0000000 --- a/iced_drop/src/widget/operation/drop.rs +++ /dev/null @@ -1,88 +0,0 @@ -use iced::advanced::widget::operation::{Outcome, Scrollable}; -use iced::advanced::widget::{Id, Operation}; -use iced::{Rectangle, Vector}; - -/// Produces an [`Operation`] that will find the drop zones that pass a filter on the zone's bounds. -/// For any drop zone to be considered, the Element must have some Id. -/// If `options` is `None`, all drop zones will be considered. -/// Depth determines how how deep into nested drop zones to go. -/// If 'depth' is `None`, nested dropzones will be fully explored -pub fn find_zones( - filter: F, - options: Option>, - depth: Option, -) -> impl Operation> -where - F: Fn(&Rectangle) -> bool + Send + 'static, -{ - struct FindDropZone { - filter: F, - options: Option>, - zones: Vec<(Id, Rectangle)>, - max_depth: Option, - c_depth: usize, - offset: Vector, - } - - impl Operation> for FindDropZone - where - F: Fn(&Rectangle) -> bool + Send + 'static, - { - fn container( - &mut self, - id: Option<&Id>, - bounds: iced::Rectangle, - operate_on_children: &mut dyn FnMut( - &mut dyn Operation>, - ), - ) { - match id { - Some(id) => { - let is_option = match &self.options { - Some(options) => options.contains(id), - None => true, - }; - let bounds = bounds - self.offset; - if is_option && (self.filter)(&bounds) { - self.c_depth += 1; - self.zones.push((id.clone(), bounds)); - } - } - None => (), - } - let goto_next = match &self.max_depth { - Some(m_depth) => self.c_depth < *m_depth, - None => true, - }; - if goto_next { - operate_on_children(self); - } - } - - fn finish(&self) -> Outcome> { - Outcome::Some(self.zones.clone()) - } - - fn scrollable( - &mut self, - _id: Option<&Id>, - bounds: Rectangle, - _content_bounds: Rectangle, - translation: Vector, - _state: &mut dyn Scrollable, - ) { - if (self.filter)(&bounds) { - self.offset = self.offset + translation; - } - } - } - - FindDropZone { - filter, - options, - zones: vec![], - max_depth: depth, - c_depth: 0, - offset: Vector { x: 0.0, y: 0.0 }, - } -} diff --git a/material_theme/Cargo.toml b/material_theme/Cargo.toml deleted file mode 100644 index eef9605..0000000 --- a/material_theme/Cargo.toml +++ /dev/null @@ -1,53 +0,0 @@ -[package] -name = "material_theme" -description = "An M3 inspired theme for `iced`" -authors = ["pml68 "] -version = "0.14.0-dev" -edition = "2024" -license = "MIT" -# readme = "README.md" -repository = "https://github.com/pml68/iced_builder" -categories = ["gui"] -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -rust-version = "1.85" - -[features] -default = [] -animate = ["dep:iced_anim"] -dialog = ["dep:iced_dialog"] - -[dependencies] -iced_widget = "0.14.0-dev" -serde.workspace = true -toml.workspace = true -dark-light = "2.0.0" -iced_dialog.workspace = true -iced_dialog.optional = true - -[dependencies.iced_anim] -workspace = true -features = ["derive"] -optional = true - -[lints.rust] -missing_debug_implementations = "deny" -unsafe_code = "deny" -unused_results = "deny" - -[lints.clippy] -type-complexity = "allow" -semicolon_if_nothing_returned = "deny" -trivially-copy-pass-by-ref = "deny" -default_trait_access = "deny" -match-wildcard-for-single-variants = "deny" -redundant-closure-for-method-calls = "deny" -filter_map_next = "deny" -manual_let_else = "deny" -unused_async = "deny" -from_over_into = "deny" -needless_borrow = "deny" -new_without_default = "deny" -useless_conversion = "deny" - -[lints.rustdoc] -broken_intra_doc_links = "forbid" diff --git a/material_theme/README.md b/material_theme/README.md deleted file mode 100644 index da5a1ec..0000000 --- a/material_theme/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# material_theme - -## A [Material3](https://m3.material.io) inspired custom theme for [`iced`](https://iced.rs) diff --git a/material_theme/assets/themes/dark.toml b/material_theme/assets/themes/dark.toml deleted file mode 100644 index 18a369f..0000000 --- a/material_theme/assets/themes/dark.toml +++ /dev/null @@ -1,49 +0,0 @@ -name = "Dark" - -shadow = "#000000" -scrim = "#4d000000" - -[primary] -color = "#9bd4a1" -on_primary = "#003916" -primary_container = "#1b5129" -on_primary_container = "#b6f1bb" - -[secondary] -color = "#b8ccb6" -on_secondary = "#233425" -secondary_container = "#394b3a" -on_secondary_container = "#d3e8d1" - -[tertiary] -color = "#a1ced7" -on_tertiary = "#00363e" -tertiary_container = "#1f4d55" -on_tertiary_container = "#bdeaf4" - -[error] -color = "#ffb4ab" -on_error = "#690005" -error_container = "#93000a" -on_error_container = "#ffdad6" - -[surface] -color = "#101510" -on_surface = "#e0e4dc" -on_surface_variant = "#c1c9be" - -[surface.surface_container] -lowest = "#0b0f0b" -low = "#181d18" -base = "#1c211c" -high = "#262b26" -highest = "#313631" - -[inverse] -inverse_surface = "#e0e4dc" -inverse_on_surface = "#2d322c" -inverse_primary = "#34693f" - -[outline] -color = "#8b9389" -variant = "#414941" diff --git a/material_theme/assets/themes/light.toml b/material_theme/assets/themes/light.toml deleted file mode 100644 index a7115c4..0000000 --- a/material_theme/assets/themes/light.toml +++ /dev/null @@ -1,49 +0,0 @@ -name = "Light" - -shadow = "#000000" -scrim = "#4d000000" - -[primary] -color = "#34693f" -on_primary = "#ffffff" -primary_container = "#b6f1bb" -on_primary_container = "#1b5129" - -[secondary] -color = "#516351" -on_secondary = "#ffffff" -secondary_container = "#d3e8d1" -on_secondary_container = "#394b3a" - -[tertiary] -color = "#39656d" -on_tertiary = "#ffffff" -tertiary_container = "#bdeaf4" -on_tertiary_container = "#1f4d55" - -[error] -color = "#ba1a1a" -on_error = "#ffffff" -error_container = "#ffdad6" -on_error_container = "#93000a" - -[surface] -color = "#f7fbf2" -on_surface = "#181d18" -on_surface_variant = "#414941" - -[surface.surface_container] -lowest = "#ffffff" -low = "#f1f5ed" -base = "#ebefe7" -high = "#e5e9e1" -highest = "#e0e4dc" - -[inverse] -inverse_surface = "#2d322c" -inverse_on_surface = "#eef2ea" -inverse_primary = "#9bd4a1" - -[outline] -color = "#727970" -variant = "#c1c9be" diff --git a/material_theme/src/button.rs b/material_theme/src/button.rs deleted file mode 100644 index 21d77b7..0000000 --- a/material_theme/src/button.rs +++ /dev/null @@ -1,193 +0,0 @@ -use iced_widget::button::{Catalog, Status, Style, StyleFn}; -use iced_widget::core::{Background, Border, Color, border}; - -use crate::Theme; -use crate::utils::{ - DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, - PRESSED_LAYER_OPACITY, elevation, mix, shadow_from_elevation, -}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(filled) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -fn button( - foreground: Color, - background: Color, - tone_overlay: Color, - disabled: Color, - shadow_color: Color, - elevation_level: u8, - status: Status, -) -> Style { - let active = Style { - background: Some(Background::Color(background)), - text_color: foreground, - border: border::rounded(400), - shadow: shadow_from_elevation(elevation(elevation_level), shadow_color), - }; - - match status { - Status::Active => active, - Status::Pressed => Style { - background: Some(Background::Color(mix( - background, - tone_overlay, - HOVERED_LAYER_OPACITY, - ))), - ..active - }, - Status::Hovered => Style { - background: Some(Background::Color(mix( - background, - tone_overlay, - PRESSED_LAYER_OPACITY, - ))), - text_color: foreground, - border: border::rounded(400), - shadow: shadow_from_elevation( - elevation(elevation_level + 1), - shadow_color, - ), - }, - Status::Disabled => Style { - background: Some(Background::Color(Color { - a: DISABLED_CONTAINER_OPACITY, - ..disabled - })), - text_color: Color { - a: DISABLED_TEXT_OPACITY, - ..disabled - }, - border: border::rounded(400), - ..Default::default() - }, - } -} - -pub fn elevated(theme: &Theme, status: Status) -> Style { - let surface_colors = theme.colorscheme.surface; - - let foreground = theme.colorscheme.primary.color; - let background = surface_colors.surface_container.low; - let disabled = surface_colors.on_surface; - - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 1, - status, - ) -} - -pub fn filled(theme: &Theme, status: Status) -> Style { - let primary_colors = theme.colorscheme.primary; - - let foreground = primary_colors.on_primary; - let background = primary_colors.color; - let disabled = theme.colorscheme.surface.on_surface; - - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 0, - status, - ) -} - -pub fn filled_tonal(theme: &Theme, status: Status) -> Style { - let secondary_colors = theme.colorscheme.secondary; - - let foreground = secondary_colors.on_secondary_container; - let background = secondary_colors.secondary_container; - let disabled = theme.colorscheme.surface.on_surface; - let shadow_color = theme.colorscheme.shadow; - - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 0, - status, - ) -} - -pub fn outlined(theme: &Theme, status: Status) -> Style { - let foreground = theme.colorscheme.primary.color; - let background = Color::TRANSPARENT; - let disabled = theme.colorscheme.surface.on_surface; - - let outline = theme.colorscheme.outline.color; - - let border = match status { - Status::Active | Status::Pressed | Status::Hovered => Border { - color: outline, - width: 1.0, - radius: 400.0.into(), - }, - Status::Disabled => Border { - color: Color { - a: DISABLED_CONTAINER_OPACITY, - ..disabled - }, - width: 1.0, - radius: 400.0.into(), - }, - }; - - let style = button( - foreground, - background, - foreground, - disabled, - Color::TRANSPARENT, - 0, - status, - ); - - Style { border, ..style } -} - -pub fn text(theme: &Theme, status: Status) -> Style { - let foreground = theme.colorscheme.primary.color; - let background = Color::TRANSPARENT; - let disabled = theme.colorscheme.surface.on_surface; - - let style = button( - foreground, - background, - foreground, - disabled, - Color::TRANSPARENT, - 0, - status, - ); - - match status { - Status::Hovered | Status::Pressed => style, - _ => Style { - background: None, - ..style - }, - } -} diff --git a/material_theme/src/container.rs b/material_theme/src/container.rs deleted file mode 100644 index a14cfd5..0000000 --- a/material_theme/src/container.rs +++ /dev/null @@ -1,173 +0,0 @@ -use iced_widget::container::{Catalog, Style, StyleFn}; -use iced_widget::core::{Background, border}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(transparent) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn transparent(_theme: &Theme) -> Style { - Style { - border: border::rounded(4), - ..Style::default() - } -} - -pub fn primary(theme: &Theme) -> Style { - let colors = theme.colorscheme.primary; - Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_primary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn primary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.primary; - Style { - background: Some(Background::Color(colors.primary_container)), - text_color: Some(colors.on_primary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn secondary(theme: &Theme) -> Style { - let colors = theme.colorscheme.secondary; - Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_secondary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn secondary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.secondary; - Style { - background: Some(Background::Color(colors.secondary_container)), - text_color: Some(colors.on_secondary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn tertiary(theme: &Theme) -> Style { - let colors = theme.colorscheme.tertiary; - Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_tertiary), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn tertiary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.tertiary; - Style { - background: Some(Background::Color(colors.tertiary_container)), - text_color: Some(colors.on_tertiary_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn error(theme: &Theme) -> Style { - let colors = theme.colorscheme.error; - Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_error), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn error_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.error; - Style { - background: Some(Background::Color(colors.error_container)), - text_color: Some(colors.on_error_container), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_surface), - border: border::rounded(4), - ..Style::default() - } -} - -pub fn surface_container_lowest(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.lowest)), - text_color: Some(colors.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_low(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.low)), - text_color: Some(colors.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.base)), - text_color: Some(colors.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_high(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.high)), - text_color: Some(colors.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn surface_container_highest(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.highest)), - text_color: Some(colors.on_surface), - border: border::rounded(8), - ..Style::default() - } -} - -pub fn inverse_surface(theme: &Theme) -> Style { - let colors = theme.colorscheme.inverse; - Style { - background: Some(Background::Color(colors.inverse_surface)), - text_color: Some(colors.inverse_on_surface), - border: border::rounded(4), - ..Style::default() - } -} diff --git a/material_theme/src/dialog.rs b/material_theme/src/dialog.rs deleted file mode 100644 index 68c61b5..0000000 --- a/material_theme/src/dialog.rs +++ /dev/null @@ -1,25 +0,0 @@ -use iced_widget::container::Style; -use iced_widget::core::{Background, border}; - -use super::{Theme, text}; - -impl iced_dialog::dialog::Catalog for Theme { - fn default_container<'a>() - -> ::Class<'a> { - Box::new(default_container) - } - - fn default_title<'a>() -> ::Class<'a> { - Box::new(text::surface) - } -} - -pub fn default_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - Style { - background: Some(Background::Color(colors.surface_container.high)), - text_color: Some(colors.on_surface_variant), - border: border::rounded(28), - ..Style::default() - } -} diff --git a/material_theme/src/lib.rs b/material_theme/src/lib.rs deleted file mode 100644 index 521af2c..0000000 --- a/material_theme/src/lib.rs +++ /dev/null @@ -1,248 +0,0 @@ -use std::sync::LazyLock; - -use iced_widget::core::Color; -use iced_widget::core::theme::{Base, Style}; -use serde::Deserialize; - -pub mod button; -pub mod container; -#[cfg(feature = "dialog")] -pub mod dialog; -pub mod menu; -pub mod pick_list; -pub mod scrollable; -pub mod text; -pub mod utils; - -const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); -const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); - -#[derive(Debug, PartialEq, Deserialize)] -pub struct Theme { - pub name: String, - #[serde(flatten)] - pub colorscheme: ColorScheme, -} - -impl Theme { - pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { - Self { - name: name.into(), - colorscheme, - } - } -} - -impl Clone for Theme { - fn clone(&self) -> Self { - Self { - name: self.name.clone(), - colorscheme: self.colorscheme, - } - } - - fn clone_from(&mut self, source: &Self) { - self.name = source.name.clone(); - self.colorscheme = source.colorscheme; - } -} - -impl Default for Theme { - fn default() -> Self { - static DEFAULT: LazyLock = LazyLock::new(|| { - match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) - { - dark_light::Mode::Dark | dark_light::Mode::Unspecified => { - DARK.clone() - } - dark_light::Mode::Light => LIGHT.clone(), - } - }); - - DEFAULT.clone() - } -} - -impl std::fmt::Display for Theme { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name) - } -} - -impl Base for Theme { - fn base(&self) -> Style { - Style { - background_color: self.colorscheme.surface.color, - text_color: self.colorscheme.surface.on_surface, - } - } - - fn palette(&self) -> Option { - // TODO: create a Palette - None - } -} - -#[cfg(feature = "animate")] -impl iced_anim::Animate for Theme { - fn components() -> usize { - ColorScheme::components() - } - - fn update(&mut self, components: &mut impl Iterator) { - let mut colors = self.colorscheme; - colors.update(components); - - *self = Theme::new("Animating Theme", colors); - } - - fn distance_to(&self, end: &Self) -> Vec { - self.colorscheme.distance_to(&end.colorscheme) - } - - fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { - let mut colors = self.colorscheme; - colors.lerp(&start.colorscheme, &end.colorscheme, progress); - - *self = Theme::new("Animating Theme", colors); - } -} - -pub static DARK: LazyLock = LazyLock::new(|| { - toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") -}); - -pub static LIGHT: LazyLock = LazyLock::new(|| { - toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") -}); - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct ColorScheme { - pub primary: Primary, - pub secondary: Secondary, - pub tertiary: Tertiary, - pub error: Error, - pub surface: Surface, - pub inverse: Inverse, - pub outline: Outline, - #[serde(with = "color_serde")] - pub shadow: Color, - #[serde(with = "color_serde")] - pub scrim: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Primary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_primary: Color, - #[serde(with = "color_serde")] - pub primary_container: Color, - #[serde(with = "color_serde")] - pub on_primary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Secondary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_secondary: Color, - #[serde(with = "color_serde")] - pub secondary_container: Color, - #[serde(with = "color_serde")] - pub on_secondary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Tertiary { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_tertiary: Color, - #[serde(with = "color_serde")] - pub tertiary_container: Color, - #[serde(with = "color_serde")] - pub on_tertiary_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Error { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_error: Color, - #[serde(with = "color_serde")] - pub error_container: Color, - #[serde(with = "color_serde")] - pub on_error_container: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Surface { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub on_surface: Color, - #[serde(with = "color_serde")] - pub on_surface_variant: Color, - pub surface_container: SurfaceContainer, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct SurfaceContainer { - #[serde(with = "color_serde")] - pub lowest: Color, - #[serde(with = "color_serde")] - pub low: Color, - #[serde(with = "color_serde")] - pub base: Color, - #[serde(with = "color_serde")] - pub high: Color, - #[serde(with = "color_serde")] - pub highest: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Inverse { - #[serde(with = "color_serde")] - pub inverse_surface: Color, - #[serde(with = "color_serde")] - pub inverse_on_surface: Color, - #[serde(with = "color_serde")] - pub inverse_primary: Color, -} - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[cfg_attr(feature = "animate", derive(iced_anim::Animate))] -pub struct Outline { - #[serde(with = "color_serde")] - pub color: Color, - #[serde(with = "color_serde")] - pub variant: Color, -} - -mod color_serde { - use iced_widget::core::Color; - use serde::{Deserialize, Deserializer}; - - use super::utils::parse_argb; - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(String::deserialize(deserializer) - .map(|hex| parse_argb(&hex))? - .unwrap_or(Color::TRANSPARENT)) - } -} diff --git a/material_theme/src/menu.rs b/material_theme/src/menu.rs deleted file mode 100644 index 9f43c72..0000000 --- a/material_theme/src/menu.rs +++ /dev/null @@ -1,33 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; - -use super::Theme; -use crate::utils::{HOVERED_LAYER_OPACITY, mix}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> ::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &::Class<'_>) -> Style { - class(self) - } -} - -pub fn default(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; - - Style { - border: border::rounded(4), - background: Background::Color(colors.surface_container.base), - text_color: colors.on_surface, - selected_background: Background::Color(mix( - colors.surface_container.base, - colors.on_surface, - HOVERED_LAYER_OPACITY, - )), - selected_text_color: colors.on_surface, - } -} diff --git a/material_theme/src/pick_list.rs b/material_theme/src/pick_list.rs deleted file mode 100644 index c589100..0000000 --- a/material_theme/src/pick_list.rs +++ /dev/null @@ -1,40 +0,0 @@ -use iced_widget::core::{Background, border}; -use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; - -use super::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> ::Class<'a> { - Box::new(default) - } - - fn style( - &self, - class: &::Class<'_>, - status: Status, - ) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - - let active = Style { - text_color: surface.on_surface, - placeholder_color: surface.on_surface_variant, - handle_color: surface.on_surface_variant, - background: Background::Color(surface.surface_container.highest), - border: border::rounded(4), - }; - - match status { - Status::Active => active, - Status::Hovered | Status::Opened { .. } => Style { - background: Background::Color(surface.surface_container.highest), - ..active - }, - } -} diff --git a/material_theme/src/scrollable.rs b/material_theme/src/scrollable.rs deleted file mode 100644 index 8a22e56..0000000 --- a/material_theme/src/scrollable.rs +++ /dev/null @@ -1,161 +0,0 @@ -use iced_widget::core::{Border, Color, border}; -use iced_widget::scrollable::{ - Catalog, Rail, Scroller, Status, Style, StyleFn, -}; - -use super::Theme; -use super::container::surface_container; -use super::utils::mix; -use crate::utils::{ - DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, - PRESSED_LAYER_OPACITY, -}; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(default) - } - - fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { - class(self, status) - } -} - -pub fn default(theme: &Theme, status: Status) -> Style { - let colors = theme.colorscheme.surface; - - let active = Rail { - background: None, - scroller: Scroller { - color: colors.on_surface, - border: border::rounded(400), - }, - border: Border::default(), - }; - - let disabled = Rail { - background: Some( - Color { - a: DISABLED_CONTAINER_OPACITY, - ..colors.on_surface - } - .into(), - ), - scroller: Scroller { - color: Color { - a: DISABLED_TEXT_OPACITY, - ..colors.on_surface - }, - border: border::rounded(400), - }, - ..active - }; - - let style = Style { - container: surface_container(theme), - vertical_rail: active, - horizontal_rail: active, - gap: None, - }; - - match status { - Status::Active { - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else { - active - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else { - active - }, - ..style - }, - Status::Hovered { - is_horizontal_scrollbar_hovered, - is_vertical_scrollbar_hovered, - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => { - let hovered_rail = Rail { - scroller: Scroller { - color: mix( - colors.on_surface, - colors.color, - HOVERED_LAYER_OPACITY, - ), - border: border::rounded(400), - }, - ..active - }; - - Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else { - if is_horizontal_scrollbar_hovered { - hovered_rail - } else { - active - } - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else { - if is_vertical_scrollbar_hovered { - hovered_rail - } else { - active - } - }, - ..style - } - } - Status::Dragged { - is_horizontal_scrollbar_dragged, - is_vertical_scrollbar_dragged, - is_horizontal_scrollbar_disabled, - is_vertical_scrollbar_disabled, - } => { - let dragged_rail = Rail { - scroller: Scroller { - color: mix( - colors.on_surface, - colors.color, - PRESSED_LAYER_OPACITY, - ), - border: border::rounded(400), - }, - ..active - }; - - Style { - horizontal_rail: if is_horizontal_scrollbar_disabled { - disabled - } else { - if is_horizontal_scrollbar_dragged { - dragged_rail - } else { - active - } - }, - vertical_rail: if is_vertical_scrollbar_disabled { - disabled - } else { - if is_vertical_scrollbar_dragged { - dragged_rail - } else { - active - } - }, - ..style - } - } - } -} diff --git a/material_theme/src/text.rs b/material_theme/src/text.rs deleted file mode 100644 index 10b2e65..0000000 --- a/material_theme/src/text.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![allow(dead_code)] -use iced_widget::text::{Catalog, Style, StyleFn}; - -use crate::Theme; - -impl Catalog for Theme { - type Class<'a> = StyleFn<'a, Self>; - - fn default<'a>() -> Self::Class<'a> { - Box::new(none) - } - - fn style(&self, class: &Self::Class<'_>) -> Style { - class(self) - } -} - -pub fn none(_: &Theme) -> Style { - Style { color: None } -} - -pub fn primary(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.primary.on_primary), - } -} - -pub fn primary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.primary.on_primary_container), - } -} - -pub fn secondary(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.secondary.on_secondary), - } -} - -pub fn secondary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.secondary.on_secondary_container), - } -} - -pub fn tertiary(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.tertiary.on_tertiary), - } -} - -pub fn tertiary_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.tertiary.on_tertiary_container), - } -} - -pub fn error(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.error.on_error), - } -} - -pub fn error_container(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.error.on_error_container), - } -} - -pub fn surface(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.surface.on_surface), - } -} - -pub fn surface_variant(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.surface.on_surface_variant), - } -} - -pub fn inverse_surface(theme: &Theme) -> Style { - Style { - color: Some(theme.colorscheme.inverse.inverse_on_surface), - } -} diff --git a/material_theme/src/utils.rs b/material_theme/src/utils.rs deleted file mode 100644 index a05bc62..0000000 --- a/material_theme/src/utils.rs +++ /dev/null @@ -1,116 +0,0 @@ -use iced_widget::core::{Color, Shadow, Vector}; - -pub const HOVERED_LAYER_OPACITY: f32 = 0.08; -pub const PRESSED_LAYER_OPACITY: f32 = 0.1; - -pub const DISABLED_TEXT_OPACITY: f32 = 0.38; -pub const DISABLED_CONTAINER_OPACITY: f32 = 0.12; - -pub fn elevation(elevation_level: u8) -> f32 { - (match elevation_level { - 0 => 0.0, - 1 => 1.0, - 2 => 3.0, - 3 => 6.0, - 4 => 8.0, - _ => 12.0, - } as f32) -} - -pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { - Shadow { - color, - offset: Vector { - x: 0.0, - y: elevation, - }, - blur_radius: (elevation) * (1.0 + 0.4_f32.powf(elevation)), - } -} - -pub fn parse_argb(s: &str) -> Option { - let hex = s.strip_prefix('#').unwrap_or(s); - - let parse_channel = |from: usize, to: usize| { - let num = - usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; - - // If we only got half a byte (one letter), expand it into a full byte (two letters) - Some(if from == to { num + num * 16.0 } else { num }) - }; - - Some(match hex.len() { - 3 => Color::from_rgb( - parse_channel(0, 0)?, - parse_channel(1, 1)?, - parse_channel(2, 2)?, - ), - 4 => Color::from_rgba( - parse_channel(1, 1)?, - parse_channel(2, 2)?, - parse_channel(3, 3)?, - parse_channel(0, 0)?, - ), - 6 => Color::from_rgb( - parse_channel(0, 1)?, - parse_channel(2, 3)?, - parse_channel(4, 5)?, - ), - 8 => Color::from_rgba( - parse_channel(2, 3)?, - parse_channel(4, 5)?, - parse_channel(6, 7)?, - parse_channel(0, 1)?, - ), - _ => None?, - }) -} - -pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { - if p2 <= 0.0 { - return color1; - } else if p2 >= 1.0 { - return color2; - } - - let p1 = 1.0 - p2; - - if color1.a != 1.0 || color2.a != 1.0 { - let a = color1.a * p1 + color2.a * p2; - if a > 0.0 { - let c1 = color1.into_linear().map(|c| c * color1.a * p1); - let c2 = color2.into_linear().map(|c| c * color2.a * p2); - - let [r, g, b] = - [c1[0] + c2[0], c1[1] + c2[1], c1[2] + c2[2]].map(|u| u / a); - - return Color::from_linear_rgba(r, g, b, a); - } - } - - let c1 = color1.into_linear().map(|c| c * p1); - let c2 = color2.into_linear().map(|c| c * p2); - - Color::from_linear_rgba( - c1[0] + c2[0], - c1[1] + c2[1], - c1[2] + c2[2], - c1[3] + c2[3], - ) -} - -#[cfg(test)] -mod tests { - use super::{Color, mix}; - - #[test] - fn mixing_works() { - let base = Color::from_rgba(1.0, 0.0, 0.0, 0.7); - let overlay = Color::from_rgba(0.0, 1.0, 0.0, 0.2); - - assert_eq!( - mix(base, overlay, 0.75).into_rgba8(), - Color::from_linear_rgba(0.53846, 0.46154, 0.0, 0.325).into_rgba8() - ); - } -} diff --git a/theme_test/Cargo.toml b/theme_test/Cargo.toml index 5ccbefa..29fcdc8 100644 --- a/theme_test/Cargo.toml +++ b/theme_test/Cargo.toml @@ -7,4 +7,4 @@ edition = "2024" iced.workspace = true iced_anim.workspace = true iced_dialog.workspace = true -material_theme = { path = "../material_theme", features = ["dialog", "animate"] } +material_theme = { path = "../crates/material_theme", features = ["dialog", "animate"] } -- cgit v1.2.3 From 18df0db658698014bb5d0851cabfd9f5dc49c2c9 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 11:48:09 +0200 Subject: feat(material_theme): tweak `pick_list` and `menu` borders --- crates/material_theme/src/menu.rs | 7 +++++-- crates/material_theme/src/pick_list.rs | 12 ++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/material_theme/src/menu.rs b/crates/material_theme/src/menu.rs index 9f43c72..5990c00 100644 --- a/crates/material_theme/src/menu.rs +++ b/crates/material_theme/src/menu.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Background, border}; +use iced_widget::core::{Background, Border, border}; use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; use super::Theme; @@ -20,7 +20,10 @@ pub fn default(theme: &Theme) -> Style { let colors = theme.colorscheme.surface; Style { - border: border::rounded(4), + border: Border { + radius: border::bottom(4), + ..Default::default() + }, background: Background::Color(colors.surface_container.base), text_color: colors.on_surface, selected_background: Background::Color(mix( diff --git a/crates/material_theme/src/pick_list.rs b/crates/material_theme/src/pick_list.rs index c589100..25b09f8 100644 --- a/crates/material_theme/src/pick_list.rs +++ b/crates/material_theme/src/pick_list.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Background, border}; +use iced_widget::core::{Background, Border, border}; use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; use super::Theme; @@ -32,9 +32,17 @@ pub fn default(theme: &Theme, status: Status) -> Style { match status { Status::Active => active, - Status::Hovered | Status::Opened { .. } => Style { + Status::Hovered => Style { background: Background::Color(surface.surface_container.highest), ..active }, + Status::Opened { .. } => Style { + background: Background::Color(surface.surface_container.highest), + border: Border { + radius: border::top(4), + ..Default::default() + }, + ..active + }, } } -- cgit v1.2.3 From 676d6334cd3bb095b4a7abee577b99bbe059c2f4 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 11:53:16 +0200 Subject: ci: set dependabot interval to monthly --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5cad797..b7e295a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ updates: - package-ecosystem: cargo directory: "/" schedule: - interval: daily + interval: monthly time: "20:00" open-pull-requests-limit: 10 reviewers: -- cgit v1.2.3 From 606e22290e4542171ac18309d3cff27468c909fb Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 12:03:54 +0200 Subject: feat(PKGBUILD): update pkgver fn, dependencies --- Cargo.lock | 6 ++++++ PKGBUILD | 2 +- TODO.md | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0143fbd..7a48765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -649,6 +649,12 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" + [[package]] name = "cc" version = "1.2.19" diff --git a/PKGBUILD b/PKGBUILD index c17d10d..0297bc9 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: pml68 pkgname=iced-builder -pkgver=0.1.0.r99.gd0e05b9 +pkgver=0.1.0.r115.g77b2e89 pkgrel=1 pkgdesc='UI builder for iced, built with iced.' arch=(x86_64) diff --git a/TODO.md b/TODO.md index d85bf5e..b8e9d30 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,3 @@ -- [ ] Make Designer view more usable +- [X] Make Designer view more usable - [ ] Rework options backend to work on-project-load - [x] Remove GTK3 dependency -- cgit v1.2.3 From de43465ddb50dd6b0c44d8de7a05aa16ba38d312 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 15 Apr 2025 01:44:00 +0200 Subject: chore(deps): update `iced_dialog` --- Cargo.lock | 18 +++++++++--------- crates/material_theme/src/dialog.rs | 30 +++++++++++++++++++++++------- src/dialogs.rs | 4 ++-- theme_test/src/main.rs | 7 ++----- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a48765..c8379a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arbitrary" @@ -860,9 +860,9 @@ dependencies = [ [[package]] name = "cosmic-text" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db686e755000c93f73a3acc78be56a71e3efb83ed92886f45faea2b9485bad7" +checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8" dependencies = [ "bitflags 2.9.0", "fontdb 0.16.2", @@ -1733,9 +1733,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" +checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" dependencies = [ "atomic-waker", "bytes", @@ -2054,7 +2054,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#c0f931f38ac83e77cfb937d4166fa8d2a23988cf" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#a41468011f8e4f566e9301565f3276fb10cc9551" dependencies = [ "iced_core", "iced_widget", @@ -3778,9 +3778,9 @@ dependencies = [ [[package]] name = "ravif" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6" +checksum = "d6a5f31fcf7500f9401fea858ea4ab5525c99f2322cfcee732c0e6c74208c0c6" dependencies = [ "avif-serialize", "imgref", diff --git a/crates/material_theme/src/dialog.rs b/crates/material_theme/src/dialog.rs index 68c61b5..a022548 100644 --- a/crates/material_theme/src/dialog.rs +++ b/crates/material_theme/src/dialog.rs @@ -1,25 +1,41 @@ -use iced_widget::container::Style; +use iced_dialog::dialog::{Catalog, Style, StyleFn}; +use iced_widget::container; use iced_widget::core::{Background, border}; use super::{Theme, text}; -impl iced_dialog::dialog::Catalog for Theme { - fn default_container<'a>() - -> ::Class<'a> { +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn default_container<'a>() -> ::Class<'a> { Box::new(default_container) } fn default_title<'a>() -> ::Class<'a> { Box::new(text::surface) } + + fn style(&self, class: &::Class<'_>) -> Style { + class(self) + } } -pub fn default_container(theme: &Theme) -> Style { +pub fn default_container(theme: &Theme) -> container::Style { let colors = theme.colorscheme.surface; - Style { + container::Style { background: Some(Background::Color(colors.surface_container.high)), text_color: Some(colors.on_surface_variant), border: border::rounded(28), - ..Style::default() + ..container::Style::default() + } +} + +pub fn default(theme: &Theme) -> Style { + Style { + backdrop_color: theme.colorscheme.scrim, } } diff --git a/src/dialogs.rs b/src/dialogs.rs index 08513fd..a623f35 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -9,11 +9,11 @@ pub const WARNING_TITLE: &str = "Heads up!"; pub const ERROR_TITLE: &str = "Oops! Something went wrong."; pub fn ok_button<'a>() -> Element<'a, Message> { - button("Ok").on_press(Message::DialogOk).into() + button("Ok", Message::DialogOk).into() } pub fn cancel_button<'a>() -> Element<'a, Message> { - button("Cancel").on_press(Message::DialogCancel).into() + button("Cancel", Message::DialogCancel).into() } pub fn error_dialog(description: impl Into) -> Task { diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 9826fe9..bcf16de 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -126,12 +126,9 @@ impl State { let dialog = dialog(self.show_dialog, base, iced::widget::text("Say Hi!")) .title("This is a Dialog.") - .push_button( - iced_dialog::button("Hi!").on_press(Message::CloseDialog), - ) - .backdrop(|theme| theme.colorscheme.scrim) + .push_button(iced_dialog::button("Hi!", Message::CloseDialog)) .width(280) - .height(187); + .height(186); Animation::new(&self.theme, dialog) .on_update(Message::SwitchTheme) -- cgit v1.2.3 From 911cd4ffc291d2d9b92f90ede1d03d41edc97920 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 15 Apr 2025 23:45:14 +0200 Subject: feat(material_theme): implement `text_input::Catalog` --- Cargo.lock | 6 +-- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/text_input.rs | 81 +++++++++++++++++++++++++++++++++ theme_test/src/main.rs | 26 +++++++---- 4 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 crates/material_theme/src/text_input.rs diff --git a/Cargo.lock b/Cargo.lock index c8379a9..4d8371f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2054,7 +2054,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#a41468011f8e4f566e9301565f3276fb10cc9551" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#6e901c21dbb259d337ed1ad2054da3862172b8b3" dependencies = [ "iced_core", "iced_widget", @@ -2563,9 +2563,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libfuzzer-sys" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 521af2c..adffe09 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -12,6 +12,7 @@ pub mod menu; pub mod pick_list; pub mod scrollable; pub mod text; +pub mod text_input; pub mod utils; const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); diff --git a/crates/material_theme/src/text_input.rs b/crates/material_theme/src/text_input.rs new file mode 100644 index 0000000..5fa65ef --- /dev/null +++ b/crates/material_theme/src/text_input.rs @@ -0,0 +1,81 @@ +use iced_widget::core::{Background, Border, Color}; +use iced_widget::text_input::{Catalog, Status, Style, StyleFn}; + +use super::Theme; +use crate::utils::{DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + + let active = Style { + background: Background::Color(surface.surface_container.highest), + border: Border { + color: theme.colorscheme.outline.color, + width: 1.0, + radius: 4.into(), + }, + icon: surface.on_surface_variant, + placeholder: surface.on_surface_variant, + value: surface.on_surface, + selection: surface.on_surface, + }; + + match status { + Status::Active => active, + Status::Hovered => Style { + border: Border { + color: surface.on_surface, + ..active.border + }, + ..active + }, + Status::Disabled => Style { + background: Color::TRANSPARENT.into(), + border: Border { + color: Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.on_surface + }, + ..active.border + }, + icon: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + placeholder: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + value: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + selection: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + }, + Status::Focused { .. } => Style { + border: Border { + color: primary.color, + width: 2.0, + ..active.border + }, + placeholder: primary.color, + ..active + }, + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index bcf16de..799d68d 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,6 +1,6 @@ use iced::Element; use iced::Length::Fill; -use iced::widget::{button, column, container, pick_list, row}; +use iced::widget::{button, column, container, pick_list, row, text_input}; use iced_anim::{Animated, Animation, Event}; use iced_dialog::dialog; use material_theme::button::{elevated, filled_tonal, outlined, text}; @@ -25,13 +25,15 @@ enum Message { Noop, OpenDialog, CloseDialog, + Input(String), SwitchTheme(Event), } #[derive(Debug, Default)] pub struct State { - show_dialog: bool, theme: Animated, + show_dialog: bool, + content: String, } impl State { @@ -44,6 +46,7 @@ impl State { Message::CloseDialog => { self.show_dialog = false; } + Message::Input(content) => self.content = content, Message::SwitchTheme(event) => { self.theme.update(event); } @@ -109,13 +112,18 @@ impl State { .style(surface_container_highest), ] .spacing(10), - pick_list( - [LIGHT.clone(), DARK.clone()], - Some(self.theme.target()), - |theme| Message::SwitchTheme(theme.into()) - ) - .placeholder("Select a theme..."), - button("Open Dialog").on_press(Message::OpenDialog) + column![ + pick_list( + [LIGHT.clone(), DARK.clone()], + Some(self.theme.target()), + |theme| Message::SwitchTheme(theme.into()) + ) + .placeholder("Select a theme..."), + button("Open Dialog").on_press(Message::OpenDialog), + text_input("Type something here...", &self.content) + .on_input(Message::Input) + ] + .spacing(10) ] .spacing(20), ) -- cgit v1.2.3 From 73711596ee7295b6f0d78bb443d5f39956f8892c Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 15 Apr 2025 23:58:34 +0200 Subject: chore(deps): regenerate lockfile, update dependencies --- Cargo.lock | 120 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d8371f..3bd023a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff22c2722516255d1823ce3cc4bc0b154dbc9364be5c905d6baa6eccbbc8774" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", @@ -1232,9 +1232,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1284,9 +1284,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener 5.4.0", "pin-project-lite", @@ -1324,9 +1324,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -1352,9 +1352,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "font-types" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd" +checksum = "1fa6a5e5a77b5f3f7f9e32879f484aa5b3632ddfbe568a16266c904a6f32cdaf" dependencies = [ "bytemuck", ] @@ -1909,9 +1909,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ "bytes", "futures-channel", @@ -1919,6 +1919,7 @@ dependencies = [ "http", "http-body", "hyper", + "libc", "pin-project-lite", "socket2", "tokio", @@ -2259,9 +2260,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -2283,9 +2284,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -2304,9 +2305,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -2359,9 +2360,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.5" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", @@ -2404,9 +2405,9 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -2477,10 +2478,11 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -2601,7 +2603,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.9.0", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.11", ] [[package]] @@ -2661,9 +2663,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" dependencies = [ "value-bag", ] @@ -3288,9 +3290,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "onig" @@ -3316,9 +3318,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags 2.9.0", "cfg-if", @@ -3348,9 +3350,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", @@ -3443,7 +3445,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.11", "smallvec", "windows-targets 0.52.6", ] @@ -3647,9 +3649,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.37.2" +version = "0.37.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" dependencies = [ "memchr", ] @@ -3838,9 +3840,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags 2.9.0", ] @@ -4031,9 +4033,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags 2.9.0", "errno", @@ -4072,9 +4074,9 @@ checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" -version = "0.103.0" +version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa4eeac2588ffff23e9d7a7e9b3f971c5fb5b7ebc9452745e0c232c64f83b2f" +checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ "ring", "rustls-pki-types", @@ -4352,9 +4354,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "smithay-client-toolkit" @@ -4403,9 +4405,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4431,7 +4433,7 @@ dependencies = [ "objc2-foundation 0.2.2", "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.10", + "redox_syscall 0.5.11", "rustix 0.38.44", "tiny-xlib", "wasm-bindgen", @@ -4519,9 +4521,9 @@ dependencies = [ [[package]] name = "swash" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13d5bbc2aa266907ed8ee977c9c9e16363cc2b001266104e13397b57f1d15f71" +checksum = "fae9a562c7b46107d9c78cd78b75bbe1e991c16734c0aee8ff0ee711fb8b620a" dependencies = [ "skrifa", "yazi", @@ -4637,7 +4639,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -4713,9 +4715,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.40" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "num-conv", @@ -5157,9 +5159,9 @@ dependencies = [ [[package]] name = "value-bag" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" +checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" [[package]] name = "vcpkg" @@ -5506,9 +5508,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "24.0.2" +version = "24.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4317a17171dc20e6577bf606796794580accae0716a69edbc7388c86a3ec9f23" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" dependencies = [ "android_system_properties", "arrayvec", @@ -6389,9 +6391,9 @@ dependencies = [ [[package]] name = "zip" -version = "2.4.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744" dependencies = [ "aes", "arbitrary", @@ -6400,7 +6402,6 @@ dependencies = [ "crc32fast", "crossbeam-utils", "deflate64", - "displaydoc", "flate2", "getrandom 0.3.2", "hmac", @@ -6409,7 +6410,6 @@ dependencies = [ "memchr", "pbkdf2", "sha1", - "thiserror 2.0.12", "time", "xz2", "zeroize", -- cgit v1.2.3 From 427be61dc78a38586ee4829c0b706d07d3d9cbf0 Mon Sep 17 00:00:00 2001 From: pml68 Date: Wed, 16 Apr 2025 20:08:04 +0200 Subject: feat: center the window by default --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index d58329a..c7e6314 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,6 +64,7 @@ fn main() -> Result<(), Box> { .theme(|state| state.theme.value().clone()) .subscription(App::subscription) .antialiasing(true) + .centered() .run()?; Ok(()) -- cgit v1.2.3 From 4bfe227274b7861048eba5ff0f4b93f7afdbe8b2 Mon Sep 17 00:00:00 2001 From: pml68 Date: Wed, 16 Apr 2025 20:08:35 +0200 Subject: refactor(PKGBUILD): use `printf` over `echo` in `pkgver` --- PKGBUILD | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PKGBUILD b/PKGBUILD index 0297bc9..ecddb41 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -10,6 +10,7 @@ license=('GPL-3.0-or-later') depends=( gcc-libs glibc + rustfmt ) makedepends=( git @@ -30,7 +31,10 @@ prepare() { pkgver() { cd "${pkgname}" - echo "$(cargo pkgid | cut -d@ -f2).r$(git rev-list --count HEAD).g$(git rev-parse --short HEAD)" + printf "%s.r%s.g%s" \ + $(cargo pkgid | cut -d@ -f2) \ + $(git rev-list --count HEAD) \ + $(git rev-parse --short HEAD) } build() { @@ -42,10 +46,6 @@ build() { } package() { - depends=( - rustfmt - ) - cd "${pkgname}" install -Dm755 "target/release/${pkgname}" "${pkgdir}/usr/bin/${pkgname}" -- cgit v1.2.3 From 385187e2db4681b99a5dcef30a0c170f8c60546a Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:01:09 +0200 Subject: feat(material_theme): implement `checkbox::Catalog` --- crates/material_theme/Cargo.toml | 2 + crates/material_theme/src/checkbox.rs | 127 ++++++++++++++++++++++++++++++++++ crates/material_theme/src/lib.rs | 1 + theme_test/src/main.rs | 15 +++- 4 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 crates/material_theme/src/checkbox.rs diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index eef9605..58c5e0c 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -13,7 +13,9 @@ rust-version = "1.85" [features] default = [] +# Provides support for animating with `iced_anim` animate = ["dep:iced_anim"] +# Provides support for `iced_dialog` dialog = ["dep:iced_dialog"] [dependencies] diff --git a/crates/material_theme/src/checkbox.rs b/crates/material_theme/src/checkbox.rs new file mode 100644 index 0000000..ac1f974 --- /dev/null +++ b/crates/material_theme/src/checkbox.rs @@ -0,0 +1,127 @@ +use iced_widget::checkbox::{Catalog, Status, Style, StyleFn}; +use iced_widget::core::{Background, Border, Color, border}; + +use super::Theme; +use crate::utils::{DISABLED_CONTAINER_OPACITY, HOVERED_LAYER_OPACITY, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn styled( + background_color: Color, + background_hover: Option, + icon_color: Color, + border_color: Color, + text_color: Option, + is_checked: bool, +) -> Style { + Style { + background: Background::Color(if is_checked { + background_color + } else { + background_hover.unwrap_or(Color::TRANSPARENT) + }), + icon_color, + border: if is_checked { + border::rounded(2) + } else { + Border { + color: border_color, + width: 2.0, + radius: border::radius(2), + } + }, + text_color, + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + + match status { + Status::Active { is_checked } => styled( + primary.color, + None, + primary.on_primary, + surface.on_surface_variant, + Some(surface.on_surface), + is_checked, + ), + Status::Hovered { is_checked } => styled( + mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY), + Some(Color { + a: HOVERED_LAYER_OPACITY, + ..surface.on_surface + }), + primary.on_primary, + surface.on_surface_variant, + Some(surface.on_surface), + is_checked, + ), + Status::Disabled { is_checked } => styled( + Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.on_surface + }, + None, + surface.color, + Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.on_surface + }, + Some(surface.on_surface), + is_checked, + ), + } +} + +pub fn error(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let error = theme.colorscheme.error; + + match status { + Status::Active { is_checked } => styled( + error.color, + None, + error.on_error, + error.color, + Some(error.color), + is_checked, + ), + Status::Hovered { is_checked } => styled( + mix(error.color, surface.on_surface, HOVERED_LAYER_OPACITY), + Some(Color { + a: HOVERED_LAYER_OPACITY, + ..error.color + }), + error.on_error, + error.color, + Some(error.color), + is_checked, + ), + Status::Disabled { is_checked } => styled( + Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.on_surface + }, + None, + surface.color, + Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.on_surface + }, + Some(surface.on_surface), + is_checked, + ), + } +} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index adffe09..2440538 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -5,6 +5,7 @@ use iced_widget::core::theme::{Base, Style}; use serde::Deserialize; pub mod button; +pub mod checkbox; pub mod container; #[cfg(feature = "dialog")] pub mod dialog; diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 799d68d..953d4e0 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,6 +1,8 @@ use iced::Element; use iced::Length::Fill; -use iced::widget::{button, column, container, pick_list, row, text_input}; +use iced::widget::{ + button, checkbox, column, container, pick_list, row, text_input, +}; use iced_anim::{Animated, Animation, Event}; use iced_dialog::dialog; use material_theme::button::{elevated, filled_tonal, outlined, text}; @@ -26,6 +28,7 @@ enum Message { OpenDialog, CloseDialog, Input(String), + CheckBox(bool), SwitchTheme(Event), } @@ -34,6 +37,7 @@ pub struct State { theme: Animated, show_dialog: bool, content: String, + is_checked: bool, } impl State { @@ -47,6 +51,7 @@ impl State { self.show_dialog = false; } Message::Input(content) => self.content = content, + Message::CheckBox(is_checked) => self.is_checked = is_checked, Message::SwitchTheme(event) => { self.theme.update(event); } @@ -121,7 +126,13 @@ impl State { .placeholder("Select a theme..."), button("Open Dialog").on_press(Message::OpenDialog), text_input("Type something here...", &self.content) - .on_input(Message::Input) + .on_input(Message::Input), + checkbox("Normal", self.is_checked) + .on_toggle(Message::CheckBox), + checkbox("Error", self.is_checked) + .on_toggle(Message::CheckBox) + .style(material_theme::checkbox::error), + checkbox("Disabled", self.is_checked), ] .spacing(10) ] -- cgit v1.2.3 From b17edaf591c173495d1097f20684feb20d7db065 Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:28:53 +0200 Subject: feat(material_theme): implement `markdown::Catalog` (under feature flag) --- crates/material_theme/Cargo.toml | 6 ++++-- crates/material_theme/src/lib.rs | 2 ++ crates/material_theme/src/markdown.rs | 10 ++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 crates/material_theme/src/markdown.rs diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index 58c5e0c..0cfa571 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -13,10 +13,12 @@ rust-version = "1.85" [features] default = [] -# Provides support for animating with `iced_anim` +# Provides support for animating with `iced_anim`. animate = ["dep:iced_anim"] -# Provides support for `iced_dialog` +# Provides support for `iced_dialog`. dialog = ["dep:iced_dialog"] +# Provides support for the markdown widget. +markdown = ["iced_widget/markdown"] [dependencies] iced_widget = "0.14.0-dev" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 2440538..e7ff343 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -9,6 +9,8 @@ pub mod checkbox; pub mod container; #[cfg(feature = "dialog")] pub mod dialog; +#[cfg(feature = "markdown")] +pub mod markdown; pub mod menu; pub mod pick_list; pub mod scrollable; diff --git a/crates/material_theme/src/markdown.rs b/crates/material_theme/src/markdown.rs new file mode 100644 index 0000000..bc14ffe --- /dev/null +++ b/crates/material_theme/src/markdown.rs @@ -0,0 +1,10 @@ +use iced_widget::markdown::Catalog; + +use super::{Theme, container}; + +impl Catalog for Theme { + fn code_block<'a>() -> ::Class<'a> + { + Box::new(container::surface_container_highest) + } +} -- cgit v1.2.3 From 70f7cd31eb5055f80664c574e46003b202b2206f Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:29:42 +0200 Subject: feat(material_theme): implement `svg::Catalog` (under feature flag) --- crates/material_theme/Cargo.toml | 2 ++ crates/material_theme/src/lib.rs | 2 ++ crates/material_theme/src/svg.rs | 15 +++++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 crates/material_theme/src/svg.rs diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index 0cfa571..ad825fd 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -19,6 +19,8 @@ animate = ["dep:iced_anim"] dialog = ["dep:iced_dialog"] # Provides support for the markdown widget. markdown = ["iced_widget/markdown"] +# Provides support for the SVG widget. +svg = ["iced_widget/svg"] [dependencies] iced_widget = "0.14.0-dev" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index e7ff343..a41dfd5 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -14,6 +14,8 @@ pub mod markdown; pub mod menu; pub mod pick_list; pub mod scrollable; +#[cfg(feature = "svg")] +pub mod svg; pub mod text; pub mod text_input; pub mod utils; diff --git a/crates/material_theme/src/svg.rs b/crates/material_theme/src/svg.rs new file mode 100644 index 0000000..885d743 --- /dev/null +++ b/crates/material_theme/src/svg.rs @@ -0,0 +1,15 @@ +use iced_widget::svg::{Catalog, Status, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(|_theme, _status| Style::default()) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} -- cgit v1.2.3 From b2b7dddb28732fbf8b070dd96922eb7df50318cb Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:30:03 +0200 Subject: feat(material_theme): implement `qr_code::Catalog` (under feature flag) --- Cargo.lock | 98 ++++++++++++++++++++++++++++++++++++ crates/material_theme/Cargo.toml | 2 + crates/material_theme/src/lib.rs | 2 + crates/material_theme/src/qr_code.rs | 24 +++++++++ 4 files changed, 126 insertions(+) create mode 100644 crates/material_theme/src/qr_code.rs diff --git a/Cargo.lock b/Cargo.lock index 3bd023a..6f5e4cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1338,6 +1338,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + [[package]] name = "fnv" version = "1.0.7" @@ -1579,6 +1585,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -2110,6 +2125,7 @@ dependencies = [ "image", "kamadak-exif", "log", + "lyon_path", "raw-window-handle", "rustc-hash 2.1.1", "thiserror 1.0.69", @@ -2181,6 +2197,7 @@ dependencies = [ "iced_debug", "iced_graphics", "log", + "lyon", "resvg", "rustc-hash 2.1.1", "thiserror 1.0.69", @@ -2197,9 +2214,12 @@ dependencies = [ "log", "num-traits", "ouroboros", + "pulldown-cmark", + "qrcode", "rustc-hash 2.1.1", "thiserror 1.0.69", "unicode-segmentation", + "url", ] [[package]] @@ -2685,6 +2705,58 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +[[package]] +name = "lyon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + +[[package]] +name = "lyon_algorithms" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13c9be19d257c7d37e70608ed858e8eab4b2afcea2e3c9a622e892acbf43c08" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_geom" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8af69edc087272df438b3ee436c4bb6d7c04aa8af665cfd398feae627dbd8570" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0047f508cd7a85ad6bad9518f68cce7b1bf6b943fb71f6da0ee3bc1e8cb75f25" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579d42360a4b09846eff2feef28f538696c7d6c7439bfa65874ff3cbe0951b2c" +dependencies = [ + "float_next_after", + "lyon_path", + "num-traits", +] + [[package]] name = "lzma-rs" version = "0.3.0" @@ -2992,6 +3064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3632,6 +3705,25 @@ dependencies = [ "syn", ] +[[package]] +name = "pulldown-cmark" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" +dependencies = [ + "bitflags 2.9.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "qoi" version = "0.4.1" @@ -3641,6 +3733,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "qrcode" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "166f136dfdb199f98186f3649cf7a0536534a61417a1a30221b492b4fb60ce3f" + [[package]] name = "quick-error" version = "2.0.1" diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index ad825fd..e1da2fb 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -21,6 +21,8 @@ dialog = ["dep:iced_dialog"] markdown = ["iced_widget/markdown"] # Provides support for the SVG widget. svg = ["iced_widget/svg"] +# Provides support for the QR code widget. +qr_code = ["iced_widget/qr_code"] [dependencies] iced_widget = "0.14.0-dev" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index a41dfd5..06ad838 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -13,6 +13,8 @@ pub mod dialog; pub mod markdown; pub mod menu; pub mod pick_list; +#[cfg(feature = "qr_code")] +pub mod qr_code; pub mod scrollable; #[cfg(feature = "svg")] pub mod svg; diff --git a/crates/material_theme/src/qr_code.rs b/crates/material_theme/src/qr_code.rs new file mode 100644 index 0000000..f93fb77 --- /dev/null +++ b/crates/material_theme/src/qr_code.rs @@ -0,0 +1,24 @@ +use iced_widget::qr_code::{Catalog, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(theme: &Theme) -> Style { + let surface = theme.colorscheme.surface; + + Style { + cell: surface.on_surface, + background: surface.color, + } +} -- cgit v1.2.3 From e5c682934668c029ac01700465787e49d772425b Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:30:18 +0200 Subject: feat(material_theme): implement `combo_box::Catalog` --- crates/material_theme/src/combo_box.rs | 5 +++++ crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/menu.rs | 7 ++----- crates/material_theme/src/pick_list.rs | 7 ++----- 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 crates/material_theme/src/combo_box.rs diff --git a/crates/material_theme/src/combo_box.rs b/crates/material_theme/src/combo_box.rs new file mode 100644 index 0000000..3024176 --- /dev/null +++ b/crates/material_theme/src/combo_box.rs @@ -0,0 +1,5 @@ +use iced_widget::combo_box::Catalog; + +use super::Theme; + +impl Catalog for Theme {} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 06ad838..64e71d3 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -6,6 +6,7 @@ use serde::Deserialize; pub mod button; pub mod checkbox; +pub mod combo_box; pub mod container; #[cfg(feature = "dialog")] pub mod dialog; diff --git a/crates/material_theme/src/menu.rs b/crates/material_theme/src/menu.rs index 5990c00..9f43c72 100644 --- a/crates/material_theme/src/menu.rs +++ b/crates/material_theme/src/menu.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Background, Border, border}; +use iced_widget::core::{Background, border}; use iced_widget::overlay::menu::{Catalog, Style, StyleFn}; use super::Theme; @@ -20,10 +20,7 @@ pub fn default(theme: &Theme) -> Style { let colors = theme.colorscheme.surface; Style { - border: Border { - radius: border::bottom(4), - ..Default::default() - }, + border: border::rounded(4), background: Background::Color(colors.surface_container.base), text_color: colors.on_surface, selected_background: Background::Color(mix( diff --git a/crates/material_theme/src/pick_list.rs b/crates/material_theme/src/pick_list.rs index 25b09f8..4b34871 100644 --- a/crates/material_theme/src/pick_list.rs +++ b/crates/material_theme/src/pick_list.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Background, Border, border}; +use iced_widget::core::{Background, border}; use iced_widget::pick_list::{Catalog, Status, Style, StyleFn}; use super::Theme; @@ -38,10 +38,7 @@ pub fn default(theme: &Theme, status: Status) -> Style { }, Status::Opened { .. } => Style { background: Background::Color(surface.surface_container.highest), - border: Border { - radius: border::top(4), - ..Default::default() - }, + border: border::rounded(4), ..active }, } -- cgit v1.2.3 From a1d4112532a41c32ad3ef4d301f1603ae73c50ab Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 00:39:06 +0200 Subject: feat(material_theme): implement `progress_bar::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/progress_bar.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 crates/material_theme/src/progress_bar.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 64e71d3..a68f0ae 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -14,6 +14,7 @@ pub mod dialog; pub mod markdown; pub mod menu; pub mod pick_list; +pub mod progress_bar; #[cfg(feature = "qr_code")] pub mod qr_code; pub mod scrollable; diff --git a/crates/material_theme/src/progress_bar.rs b/crates/material_theme/src/progress_bar.rs new file mode 100644 index 0000000..f686fff --- /dev/null +++ b/crates/material_theme/src/progress_bar.rs @@ -0,0 +1,26 @@ +use iced_widget::core::{Background, border}; +use iced_widget::progress_bar::{Catalog, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(theme: &Theme) -> Style { + Style { + background: Background::Color( + theme.colorscheme.secondary.secondary_container, + ), + bar: Background::Color(theme.colorscheme.primary.color), + border: border::rounded(400), + } +} -- cgit v1.2.3 From 7a1df9e05c73c3d735792110a863f4cad8e7b96b Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 02:59:58 +0200 Subject: feat(material_theme): implement `radio::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/radio.rs | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 crates/material_theme/src/radio.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index a68f0ae..cbebdc9 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -17,6 +17,7 @@ pub mod pick_list; pub mod progress_bar; #[cfg(feature = "qr_code")] pub mod qr_code; +pub mod radio; pub mod scrollable; #[cfg(feature = "svg")] pub mod svg; diff --git a/crates/material_theme/src/radio.rs b/crates/material_theme/src/radio.rs new file mode 100644 index 0000000..d249413 --- /dev/null +++ b/crates/material_theme/src/radio.rs @@ -0,0 +1,65 @@ +use iced_widget::core::{Background, Color}; +use iced_widget::radio::{Catalog, Status, Style, StyleFn}; + +use super::Theme; +use crate::utils::{DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + + let active = Style { + background: Color::TRANSPARENT.into(), + dot_color: primary.color, + border_width: 1.0, + border_color: primary.color, + text_color: None, + }; + + match status { + Status::Active { is_selected } => Style { + border_color: if is_selected { + active.border_color + } else { + surface.on_surface + }, + ..active + }, + Status::Hovered { is_selected } => Style { + dot_color: mix( + primary.color, + surface.on_surface, + HOVERED_LAYER_OPACITY, + ), + border_color: if is_selected { + mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY) + } else { + Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + } + }, + background: Background::Color(if is_selected { + Color { + a: HOVERED_LAYER_OPACITY, + ..surface.on_surface + } + } else { + Color::TRANSPARENT + }), + ..active + }, + } +} -- cgit v1.2.3 From ce62ff16fbd8e839b5f707f8d9637db083945803 Mon Sep 17 00:00:00 2001 From: pml68 Date: Thu, 17 Apr 2025 03:00:52 +0200 Subject: refactor: inline Dark and Light theme definitions, remove toml files --- Cargo.lock | 1 - crates/material_theme/Cargo.toml | 8 +- crates/material_theme/assets/themes/dark.toml | 49 ----- crates/material_theme/assets/themes/light.toml | 49 ----- crates/material_theme/src/lib.rs | 238 +++++++++++++++++++------ crates/material_theme/src/utils.rs | 20 +++ theme_test/src/main.rs | 15 +- 7 files changed, 222 insertions(+), 158 deletions(-) delete mode 100644 crates/material_theme/assets/themes/dark.toml delete mode 100644 crates/material_theme/assets/themes/light.toml diff --git a/Cargo.lock b/Cargo.lock index 6f5e4cb..e8a5b71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2796,7 +2796,6 @@ dependencies = [ "iced_dialog", "iced_widget", "serde", - "toml", ] [[package]] diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index e1da2fb..941bc3e 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -13,6 +13,8 @@ rust-version = "1.85" [features] default = [] +# Provides `serde` support +serde = ["dep:serde"] # Provides support for animating with `iced_anim`. animate = ["dep:iced_anim"] # Provides support for `iced_dialog`. @@ -26,9 +28,11 @@ qr_code = ["iced_widget/qr_code"] [dependencies] iced_widget = "0.14.0-dev" -serde.workspace = true -toml.workspace = true dark-light = "2.0.0" + +serde.workspace = true +serde.optional = true + iced_dialog.workspace = true iced_dialog.optional = true diff --git a/crates/material_theme/assets/themes/dark.toml b/crates/material_theme/assets/themes/dark.toml deleted file mode 100644 index 18a369f..0000000 --- a/crates/material_theme/assets/themes/dark.toml +++ /dev/null @@ -1,49 +0,0 @@ -name = "Dark" - -shadow = "#000000" -scrim = "#4d000000" - -[primary] -color = "#9bd4a1" -on_primary = "#003916" -primary_container = "#1b5129" -on_primary_container = "#b6f1bb" - -[secondary] -color = "#b8ccb6" -on_secondary = "#233425" -secondary_container = "#394b3a" -on_secondary_container = "#d3e8d1" - -[tertiary] -color = "#a1ced7" -on_tertiary = "#00363e" -tertiary_container = "#1f4d55" -on_tertiary_container = "#bdeaf4" - -[error] -color = "#ffb4ab" -on_error = "#690005" -error_container = "#93000a" -on_error_container = "#ffdad6" - -[surface] -color = "#101510" -on_surface = "#e0e4dc" -on_surface_variant = "#c1c9be" - -[surface.surface_container] -lowest = "#0b0f0b" -low = "#181d18" -base = "#1c211c" -high = "#262b26" -highest = "#313631" - -[inverse] -inverse_surface = "#e0e4dc" -inverse_on_surface = "#2d322c" -inverse_primary = "#34693f" - -[outline] -color = "#8b9389" -variant = "#414941" diff --git a/crates/material_theme/assets/themes/light.toml b/crates/material_theme/assets/themes/light.toml deleted file mode 100644 index a7115c4..0000000 --- a/crates/material_theme/assets/themes/light.toml +++ /dev/null @@ -1,49 +0,0 @@ -name = "Light" - -shadow = "#000000" -scrim = "#4d000000" - -[primary] -color = "#34693f" -on_primary = "#ffffff" -primary_container = "#b6f1bb" -on_primary_container = "#1b5129" - -[secondary] -color = "#516351" -on_secondary = "#ffffff" -secondary_container = "#d3e8d1" -on_secondary_container = "#394b3a" - -[tertiary] -color = "#39656d" -on_tertiary = "#ffffff" -tertiary_container = "#bdeaf4" -on_tertiary_container = "#1f4d55" - -[error] -color = "#ba1a1a" -on_error = "#ffffff" -error_container = "#ffdad6" -on_error_container = "#93000a" - -[surface] -color = "#f7fbf2" -on_surface = "#181d18" -on_surface_variant = "#414941" - -[surface.surface_container] -lowest = "#ffffff" -low = "#f1f5ed" -base = "#ebefe7" -high = "#e5e9e1" -highest = "#e0e4dc" - -[inverse] -inverse_surface = "#2d322c" -inverse_on_surface = "#eef2ea" -inverse_primary = "#9bd4a1" - -[outline] -color = "#727970" -variant = "#c1c9be" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index cbebdc9..a9beb2a 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -1,8 +1,7 @@ use std::sync::LazyLock; -use iced_widget::core::Color; use iced_widget::core::theme::{Base, Style}; -use serde::Deserialize; +use iced_widget::core::{Color, color}; pub mod button; pub mod checkbox; @@ -25,13 +24,16 @@ pub mod text; pub mod text_input; pub mod utils; -const DARK_THEME_CONTENT: &str = include_str!("../assets/themes/dark.toml"); -const LIGHT_THEME_CONTENT: &str = include_str!("../assets/themes/light.toml"); +pub static DARK: LazyLock = + LazyLock::new(|| Theme::new("Dark", ColorScheme::DARK)); +pub static LIGHT: LazyLock = + LazyLock::new(|| Theme::new("Light", ColorScheme::LIGHT)); -#[derive(Debug, PartialEq, Deserialize)] +#[derive(Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Theme { pub name: String, - #[serde(flatten)] + #[cfg_attr(feature = "serde", serde(flatten))] pub colorscheme: ColorScheme, } @@ -119,16 +121,9 @@ impl iced_anim::Animate for Theme { } } -pub static DARK: LazyLock = LazyLock::new(|| { - toml::from_str(DARK_THEME_CONTENT).expect("parse dark theme") -}); - -pub static LIGHT: LazyLock = LazyLock::new(|| { - toml::from_str(LIGHT_THEME_CONTENT).expect("parse light theme") -}); - -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ColorScheme { pub primary: Primary, pub secondary: Secondary, @@ -137,116 +132,240 @@ pub struct ColorScheme { pub surface: Surface, pub inverse: Inverse, pub outline: Outline, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub shadow: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub scrim: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +macro_rules! from_argb { + ($hex:expr) => {{ + let hex = $hex as u32; + + let a = ((hex & 0xff000000) >> 24) as f32 / 255.0; + let r = (hex & 0x00ff0000) >> 16; + let g = (hex & 0x0000ff00) >> 8; + let b = (hex & 0x000000ff); + + color!(r as u8, g as u8, b as u8, a) + }}; +} + +impl ColorScheme { + const DARK: Self = Self { + primary: Primary { + color: from_argb!(0xff9bd4a1), + on_primary: from_argb!(0xff003916), + primary_container: from_argb!(0xff1b5129), + on_primary_container: from_argb!(0xffb6f1bb), + }, + secondary: Secondary { + color: from_argb!(0xffb8ccb6), + on_secondary: from_argb!(0xff233425), + secondary_container: from_argb!(0xff394b3a), + on_secondary_container: from_argb!(0xffd3e8d1), + }, + tertiary: Tertiary { + color: from_argb!(0xffa1ced7), + on_tertiary: from_argb!(0xff00363e), + tertiary_container: from_argb!(0xff1f4d55), + on_tertiary_container: from_argb!(0xffbdeaf4), + }, + error: Error { + color: from_argb!(0xffffb4ab), + on_error: from_argb!(0xff690005), + error_container: from_argb!(0xff93000a), + on_error_container: from_argb!(0xffffdad6), + }, + surface: Surface { + color: from_argb!(0xff101510), + on_surface: from_argb!(0xffe0e4dc), + on_surface_variant: from_argb!(0xffc1c9be), + surface_container: SurfaceContainer { + lowest: from_argb!(0xff0b0f0b), + low: from_argb!(0xff181d18), + base: from_argb!(0xff1c211c), + high: from_argb!(0xff262b26), + highest: from_argb!(0xff313631), + }, + }, + inverse: Inverse { + inverse_surface: from_argb!(0xffe0e4dc), + inverse_on_surface: from_argb!(0xff2d322c), + inverse_primary: from_argb!(0xff34693f), + }, + outline: Outline { + color: from_argb!(0xff8b9389), + variant: from_argb!(0xff414941), + }, + shadow: from_argb!(0xff000000), + scrim: from_argb!(0x4d000000), + }; + + const LIGHT: Self = Self { + primary: Primary { + color: from_argb!(0xff34693f), + on_primary: from_argb!(0xffffffff), + primary_container: from_argb!(0xffb6f1bb), + on_primary_container: from_argb!(0xff1b5129), + }, + secondary: Secondary { + color: from_argb!(0xff516351), + on_secondary: from_argb!(0xffffffff), + secondary_container: from_argb!(0xffd3e8d1), + on_secondary_container: from_argb!(0xff394b3a), + }, + tertiary: Tertiary { + color: from_argb!(0xff39656d), + on_tertiary: from_argb!(0xffffffff), + tertiary_container: from_argb!(0xffbdeaf4), + on_tertiary_container: from_argb!(0xff1f4d55), + }, + error: Error { + color: from_argb!(0xffba1a1a), + on_error: from_argb!(0xffffffff), + error_container: from_argb!(0xffffdad6), + on_error_container: from_argb!(0xff93000a), + }, + surface: Surface { + color: from_argb!(0xfff7fbf2), + on_surface: from_argb!(0xff181d18), + on_surface_variant: from_argb!(0xff414941), + surface_container: SurfaceContainer { + lowest: from_argb!(0xffffffff), + low: from_argb!(0xfff1f5ed), + base: from_argb!(0xffebefe7), + high: from_argb!(0xffe5e9e1), + highest: from_argb!(0xffe0e4dc), + }, + }, + inverse: Inverse { + inverse_surface: from_argb!(0xff2d322c), + inverse_on_surface: from_argb!(0xffeef2ea), + inverse_primary: from_argb!(0xff9bd4a1), + }, + outline: Outline { + color: from_argb!(0xff727970), + variant: from_argb!(0xffc1c9be), + }, + shadow: from_argb!(0xff000000), + scrim: from_argb!(0x4d000000), + }; +} + +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Primary { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_primary: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub primary_container: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_primary_container: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Secondary { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_secondary: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub secondary_container: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_secondary_container: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Tertiary { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_tertiary: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub tertiary_container: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_tertiary_container: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Error { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_error: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub error_container: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_error_container: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Surface { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_surface: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub on_surface_variant: Color, pub surface_container: SurfaceContainer, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SurfaceContainer { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub lowest: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub low: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub base: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub high: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub highest: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Inverse { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub inverse_surface: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub inverse_on_surface: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub inverse_primary: Color, } -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "animate", derive(iced_anim::Animate))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Outline { - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub color: Color, - #[serde(with = "color_serde")] + #[cfg_attr(feature = "serde", serde(with = "color_serde"))] pub variant: Color, } +#[cfg(feature = "serde")] mod color_serde { use iced_widget::core::Color; - use serde::{Deserialize, Deserializer}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use super::utils::parse_argb; + use super::utils::{color_to_argb, parse_argb}; pub fn deserialize<'de, D>(deserializer: D) -> Result where @@ -256,4 +375,11 @@ mod color_serde { .map(|hex| parse_argb(&hex))? .unwrap_or(Color::TRANSPARENT)) } + + pub fn serialize(color: &Color, serializer: S) -> Result + where + S: Serializer, + { + color_to_argb(*color).serialize(serializer) + } } diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs index a05bc62..f35396f 100644 --- a/crates/material_theme/src/utils.rs +++ b/crates/material_theme/src/utils.rs @@ -66,6 +66,26 @@ pub fn parse_argb(s: &str) -> Option { }) } +pub fn color_to_argb(color: Color) -> String { + use std::fmt::Write; + + let mut hex = String::with_capacity(9); + + let [r, g, b, a] = color.into_rgba8(); + + let _ = write!(&mut hex, "#"); + + if a < u8::MAX { + let _ = write!(&mut hex, "{a:02X}"); + } + + let _ = write!(&mut hex, "{r:02X}"); + let _ = write!(&mut hex, "{g:02X}"); + let _ = write!(&mut hex, "{b:02X}"); + + hex +} + pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { if p2 <= 0.0 { return color1; diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 953d4e0..9aab2fe 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,7 +1,7 @@ use iced::Element; use iced::Length::Fill; use iced::widget::{ - button, checkbox, column, container, pick_list, row, text_input, + button, checkbox, column, container, pick_list, radio, row, text_input, }; use iced_anim::{Animated, Animation, Event}; use iced_dialog::dialog; @@ -29,6 +29,7 @@ enum Message { CloseDialog, Input(String), CheckBox(bool), + Radio(Choice), SwitchTheme(Event), } @@ -38,6 +39,14 @@ pub struct State { show_dialog: bool, content: String, is_checked: bool, + selection: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Choice { + A, + B, + C, } impl State { @@ -52,6 +61,7 @@ impl State { } Message::Input(content) => self.content = content, Message::CheckBox(is_checked) => self.is_checked = is_checked, + Message::Radio(choice) => self.selection = Some(choice), Message::SwitchTheme(event) => { self.theme.update(event); } @@ -133,6 +143,9 @@ impl State { .on_toggle(Message::CheckBox) .style(material_theme::checkbox::error), checkbox("Disabled", self.is_checked), + radio("A", Choice::A, self.selection, Message::Radio,), + radio("B", Choice::B, self.selection, Message::Radio,), + radio("C", Choice::C, self.selection, Message::Radio,), ] .spacing(10) ] -- cgit v1.2.3 From 1683717e93899d4c90641e605bfc96cbc2bf5ef1 Mon Sep 17 00:00:00 2001 From: pml68 Date: Fri, 18 Apr 2025 00:52:13 +0200 Subject: fix: `iced` 0.14 codegen --- Cargo.lock | 43 +++++++++++++++++++++---------------------- src/types/project.rs | 2 +- src/types/rendered_element.rs | 13 ++++++++++--- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8a5b71..4f0a992 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,7 +187,7 @@ dependencies = [ "enumflags2", "futures-channel", "futures-util", - "rand 0.9.0", + "rand 0.9.1", "raw-window-handle", "serde", "serde_repr", @@ -1945,7 +1945,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_core", "iced_debug", @@ -1980,7 +1980,7 @@ dependencies = [ [[package]] name = "iced_beacon" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bincode", "futures", @@ -2021,7 +2021,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2050,7 +2050,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_beacon", "iced_core", @@ -2060,7 +2060,7 @@ dependencies = [ [[package]] name = "iced_devtools" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_debug", "iced_program", @@ -2100,7 +2100,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "futures", "iced_core", @@ -2114,7 +2114,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2135,7 +2135,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_graphics", "iced_runtime", @@ -2144,7 +2144,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2156,7 +2156,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bytes", "iced_core", @@ -2169,7 +2169,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bytemuck", "cosmic-text", @@ -2186,7 +2186,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2207,7 +2207,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_renderer", "iced_runtime", @@ -2225,7 +2225,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#4f933c3b8919a115fa82d9aee94ec5b1c81c4dfe" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" dependencies = [ "iced_debug", "iced_program", @@ -3665,9 +3665,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -3781,13 +3781,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy 0.8.24", ] [[package]] @@ -4602,9 +4601,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "svg_fmt" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" [[package]] name = "svgtypes" diff --git a/src/types/project.rs b/src/types/project.rs index 50cbb69..145ab18 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -103,7 +103,7 @@ use iced::{{widget::{{{imports}}},Element}}; {theme_imports} fn main() -> iced::Result {{ - iced::application("{}", State::update, State::view).theme(State::theme).run() + iced::application(State::default, State::update, State::view).title("{}").theme(State::theme).run() }} #[derive(Default)] diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs index bd8187e..9639299 100755 --- a/src/types/rendered_element.rs +++ b/src/types/rendered_element.rs @@ -223,7 +223,14 @@ impl RenderedElement { match &self.name { ElementName::Container => { imports = format!("{imports}container,"); - view = format!("{view}\ncontainer({elements}){options}"); + view = format!( + "{view}\ncontainer({}){options}", + if elements.is_empty() { + String::from("\"\"") + } else { + elements.to_string() + } + ); } ElementName::Row => { imports = format!("{imports}row,"); @@ -237,7 +244,7 @@ impl RenderedElement { imports = format!("{imports}text,"); view = format!( "{view}\ntext(\"{}\"){options}", - if *string == String::new() { + if string.is_empty() { "New Text" } else { string @@ -248,7 +255,7 @@ impl RenderedElement { imports = format!("{imports}button,"); view = format!( "{view}\nbutton(\"{}\"){options}", - if *string == String::new() { + if string.is_empty() { "New Button" } else { string -- cgit v1.2.3 From f7274ea5efea2055f8f71d7cde7fc7e2704648cd Mon Sep 17 00:00:00 2001 From: pml68 Date: Fri, 18 Apr 2025 00:54:08 +0200 Subject: refactor: load config in `IcedBuilder::init` instead of `main` --- src/main.rs | 66 +++++++++++++++++++++++++++++++----------------------------- src/types.rs | 2 ++ 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/main.rs b/src/main.rs index c7e6314..0f1a1bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,6 @@ use iced_anim::transition::Easing; use iced_anim::{Animated, Animation}; use iced_dialog::dialog::Dialog; use panes::{code_view, designer_view, element_list}; -use tokio::runtime; use types::{ Action, DesignerPane, DialogAction, DialogButtons, Message, Project, }; @@ -46,23 +45,15 @@ fn main() -> Result<(), Box> { return Ok(()); } - let config_load = { - let rt = runtime::Builder::new_current_thread() - .enable_all() - .build()?; - - rt.block_on(Config::load()) - }; - iced::application( - move || App::new(config_load.clone()), - App::update, - App::view, + IcedBuilder::init, + IcedBuilder::update, + IcedBuilder::view, ) - .title(App::title) + .title(IcedBuilder::title) .font(icon::FONT) .theme(|state| state.theme.value().clone()) - .subscription(App::subscription) + .subscription(IcedBuilder::subscription) .antialiasing(true) .centered() .run()?; @@ -70,7 +61,7 @@ fn main() -> Result<(), Box> { Ok(()) } -struct App { +struct IcedBuilder { is_dirty: bool, is_loading: bool, project_path: Option, @@ -94,8 +85,8 @@ enum Panes { ElementList, } -impl App { - fn new(config_load: Result) -> (Self, Task) { +impl IcedBuilder { + fn init() -> (Self, Task) { let state = pane_grid::State::with_configuration( pane_grid::Configuration::Split { axis: pane_grid::Axis::Vertical, @@ -105,22 +96,9 @@ impl App { }, ); - let config = Arc::new(config_load.unwrap_or_default()); + let config = Arc::new(Config::default()); let theme = config.selected_theme(); - let task = if let Some(path) = config.last_project.clone() { - if path.exists() && path.is_file() { - Task::perform(Project::from_path(path), Message::FileOpened) - } else { - warning_dialog(format!( - "The file {} does not exist, or isn't a file.", - path.to_string_lossy() - )) - } - } else { - Task::none() - }; - ( Self { is_dirty: false, @@ -139,7 +117,7 @@ impl App { dialog_action: DialogAction::None, editor_content: text_editor::Content::new(), }, - task, + Task::perform(Config::load(), Message::ConfigLoad), ) } @@ -165,6 +143,30 @@ impl App { fn update(&mut self, message: Message) -> Task { match message { + Message::ConfigLoad(result) => match result { + Ok(config) => { + self.config = Arc::new(config); + + self.theme.update(self.config.selected_theme().into()); + return if let Some(path) = self.config.last_project.clone() + { + if path.exists() && path.is_file() { + Task::perform( + Project::from_path(path), + Message::FileOpened, + ) + } else { + warning_dialog(format!( + "The file {} does not exist, or isn't a file.", + path.to_string_lossy() + )) + } + } else { + Task::none() + }; + } + Err(error) => return error_dialog(error), + }, Message::SwitchTheme(event) => self.theme.update(event), Message::CopyCode => { return clipboard::write(self.editor_content.text()); diff --git a/src/types.rs b/src/types.rs index a7fae1c..adb788e 100644 --- a/src/types.rs +++ b/src/types.rs @@ -12,9 +12,11 @@ pub use project::Project; pub use rendered_element::*; use crate::Error; +use crate::config::Config; #[derive(Debug, Clone)] pub enum Message { + ConfigLoad(Result), SwitchTheme(Event), CopyCode, SwitchPage(DesignerPane), -- cgit v1.2.3 From ec063de6a3cccd6d51bd494573fb0b2c40cfc7a6 Mon Sep 17 00:00:00 2001 From: pml68 Date: Fri, 18 Apr 2025 00:54:37 +0200 Subject: feat(debug): add custom "Code Generation" Comet debug metric --- src/types/project.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/types/project.rs b/src/types/project.rs index 145ab18..91b2bb1 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -83,7 +83,10 @@ impl Project { } pub fn app_code(&mut self) -> Result { - match self.element_tree { + use iced::debug; + let codegen = debug::time("Code Generation"); + + let result = match self.element_tree { Some(ref element_tree) => { let (imports, view) = element_tree.codegen(); let theme = self.get_theme(); @@ -137,6 +140,9 @@ impl State {{ Ok(rustfmt.format_str(app_code)?) } None => Err("No element tree present".into()), - } + }; + + codegen.finish(); + result } } -- cgit v1.2.3 From 21214574718a02002e632f6192a611a758595811 Mon Sep 17 00:00:00 2001 From: pml68 Date: Fri, 18 Apr 2025 12:34:49 +0200 Subject: feat(material_theme): implement `slider::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/slider.rs | 63 +++++++++++++++++++++++++++++++++++++ theme_test/src/main.rs | 12 +++++-- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 crates/material_theme/src/slider.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index a9beb2a..03f1ca5 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -18,6 +18,7 @@ pub mod progress_bar; pub mod qr_code; pub mod radio; pub mod scrollable; +pub mod slider; #[cfg(feature = "svg")] pub mod svg; pub mod text; diff --git a/crates/material_theme/src/slider.rs b/crates/material_theme/src/slider.rs new file mode 100644 index 0000000..cc3bf98 --- /dev/null +++ b/crates/material_theme/src/slider.rs @@ -0,0 +1,63 @@ +use iced_widget::core::{Background, Color, border}; +use iced_widget::slider::{ + Catalog, Handle, HandleShape, Rail, Status, Style, StyleFn, +}; + +use super::Theme; +use crate::utils::{HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style( + &self, + class: &::Class<'_>, + status: Status, + ) -> Style { + class(self, status) + } +} + +pub fn styled(left: Color, right: Color, handle_radius: f32) -> Style { + Style { + rail: Rail { + backgrounds: (left.into(), right.into()), + width: 8.0, + border: border::rounded(400), + }, + handle: Handle { + shape: HandleShape::Circle { + radius: handle_radius, + }, + background: Background::Color(left), + border_width: 0.0, + border_color: Color::TRANSPARENT, + }, + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + let secondary = theme.colorscheme.secondary; + + match status { + Status::Active => { + styled(primary.color, secondary.secondary_container, 16.0) + } + Status::Hovered => styled( + mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY), + secondary.secondary_container, + 16.0, + ), + Status::Dragged => styled( + mix(primary.color, surface.on_surface, PRESSED_LAYER_OPACITY), + secondary.secondary_container, + 15.0, + ), + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 9aab2fe..c13bde7 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,8 +1,9 @@ -use iced::Element; use iced::Length::Fill; use iced::widget::{ - button, checkbox, column, container, pick_list, radio, row, text_input, + button, center, checkbox, column, container, pick_list, radio, row, slider, + text_input, }; +use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; use iced_dialog::dialog; use material_theme::button::{elevated, filled_tonal, outlined, text}; @@ -30,6 +31,7 @@ enum Message { Input(String), CheckBox(bool), Radio(Choice), + Slider(f32), SwitchTheme(Event), } @@ -40,6 +42,7 @@ pub struct State { content: String, is_checked: bool, selection: Option, + value: f32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -62,6 +65,7 @@ impl State { Message::Input(content) => self.content = content, Message::CheckBox(is_checked) => self.is_checked = is_checked, Message::Radio(choice) => self.selection = Some(choice), + Message::Slider(value) => self.value = value, Message::SwitchTheme(event) => { self.theme.update(event); } @@ -146,6 +150,10 @@ impl State { radio("A", Choice::A, self.selection, Message::Radio,), radio("B", Choice::B, self.selection, Message::Radio,), radio("C", Choice::C, self.selection, Message::Radio,), + center(iced::widget::text!("{:.1}", self.value)) + .width(Length::Fill) + .height(Length::Shrink), + slider(0.0..=100.0, self.value, Message::Slider).step(0.1) ] .spacing(10) ] -- cgit v1.2.3 From 6300486b8ea51b75850708acb271fcce02666dd6 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 19 Apr 2025 01:10:11 +0200 Subject: feat(material_theme): implement `rule::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/rule.rs | 33 +++++++++++++++++++++++++++++++++ theme_test/src/main.rs | 15 +++++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 crates/material_theme/src/rule.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 03f1ca5..2452d88 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -17,6 +17,7 @@ pub mod progress_bar; #[cfg(feature = "qr_code")] pub mod qr_code; pub mod radio; +pub mod rule; pub mod scrollable; pub mod slider; #[cfg(feature = "svg")] diff --git a/crates/material_theme/src/rule.rs b/crates/material_theme/src/rule.rs new file mode 100644 index 0000000..e433005 --- /dev/null +++ b/crates/material_theme/src/rule.rs @@ -0,0 +1,33 @@ +use iced_widget::core::border::Radius; +use iced_widget::rule::{Catalog, FillMode, Style, StyleFn}; + +use super::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(inset) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn inset(theme: &Theme) -> Style { + Style { + color: theme.colorscheme.outline.variant, + fill_mode: FillMode::Padded(8), + width: 1, + radius: Radius::default(), + } +} +pub fn full_width(theme: &Theme) -> Style { + Style { + color: theme.colorscheme.outline.variant, + fill_mode: FillMode::Full, + width: 1, + radius: Radius::default(), + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index c13bde7..7192785 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,7 +1,7 @@ use iced::Length::Fill; use iced::widget::{ - button, center, checkbox, column, container, pick_list, radio, row, slider, - text_input, + button, center, checkbox, column, container, horizontal_rule, pick_list, + radio, row, slider, text_input, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -132,24 +132,35 @@ impl State { ] .spacing(10), column![ + // Pick List pick_list( [LIGHT.clone(), DARK.clone()], Some(self.theme.target()), |theme| Message::SwitchTheme(theme.into()) ) .placeholder("Select a theme..."), + horizontal_rule(1), + // Button button("Open Dialog").on_press(Message::OpenDialog), + horizontal_rule(1), + // Text Input text_input("Type something here...", &self.content) .on_input(Message::Input), + horizontal_rule(1), + // Checkbox checkbox("Normal", self.is_checked) .on_toggle(Message::CheckBox), checkbox("Error", self.is_checked) .on_toggle(Message::CheckBox) .style(material_theme::checkbox::error), checkbox("Disabled", self.is_checked), + horizontal_rule(1), + // Radio radio("A", Choice::A, self.selection, Message::Radio,), radio("B", Choice::B, self.selection, Message::Radio,), radio("C", Choice::C, self.selection, Message::Radio,), + horizontal_rule(1), + // Slider center(iced::widget::text!("{:.1}", self.value)) .width(Length::Fill) .height(Length::Shrink), -- cgit v1.2.3 From 4a17d1fa468caf89e33088b3be69a67a52b29a99 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 19 Apr 2025 11:12:59 +0200 Subject: feat(material_theme): implement `slider::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/toggler.rs | 80 ++++++++++++++++++++++++++++++++++++ theme_test/src/main.rs | 17 +++++--- 3 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 crates/material_theme/src/toggler.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 2452d88..0df5b1c 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -24,6 +24,7 @@ pub mod slider; pub mod svg; pub mod text; pub mod text_input; +pub mod toggler; pub mod utils; pub static DARK: LazyLock = diff --git a/crates/material_theme/src/toggler.rs b/crates/material_theme/src/toggler.rs new file mode 100644 index 0000000..1cc5082 --- /dev/null +++ b/crates/material_theme/src/toggler.rs @@ -0,0 +1,80 @@ +use iced_widget::core::Color; +use iced_widget::toggler::{Catalog, Status, Style, StyleFn}; + +use super::Theme; +use crate::utils::{ + DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, + mix, +}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn styled( + background: Color, + foreground: Color, + border: Option, +) -> Style { + Style { + background, + background_border_width: if border.is_some() { 2.0 } else { 0.0 }, + background_border_color: border.unwrap_or(Color::TRANSPARENT), + foreground, + foreground_border_width: 0.0, + foreground_border_color: Color::TRANSPARENT, + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + + match status { + Status::Active { is_toggled } => { + if is_toggled { + styled(primary.color, primary.on_primary, None) + } else { + styled( + surface.surface_container.highest, + theme.colorscheme.outline.color, + Some(theme.colorscheme.outline.color), + ) + } + } + Status::Hovered { is_toggled } => { + if is_toggled { + styled(primary.color, primary.primary_container, None) + } else { + styled( + mix( + surface.surface_container.highest, + surface.on_surface, + HOVERED_LAYER_OPACITY, + ), + surface.on_surface_variant, + Some(theme.colorscheme.outline.color), + ) + } + } + Status::Disabled => styled( + Color { + a: DISABLED_CONTAINER_OPACITY, + ..surface.surface_container.highest + }, + Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + Some(surface.on_surface), + ), + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 7192785..d564ee5 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,7 +1,7 @@ use iced::Length::Fill; use iced::widget::{ button, center, checkbox, column, container, horizontal_rule, pick_list, - radio, row, slider, text_input, + radio, row, slider, text_input, toggler, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -29,7 +29,7 @@ enum Message { OpenDialog, CloseDialog, Input(String), - CheckBox(bool), + Bool(bool), Radio(Choice), Slider(f32), SwitchTheme(Event), @@ -63,7 +63,7 @@ impl State { self.show_dialog = false; } Message::Input(content) => self.content = content, - Message::CheckBox(is_checked) => self.is_checked = is_checked, + Message::Bool(is_checked) => self.is_checked = is_checked, Message::Radio(choice) => self.selection = Some(choice), Message::Slider(value) => self.value = value, Message::SwitchTheme(event) => { @@ -149,9 +149,9 @@ impl State { horizontal_rule(1), // Checkbox checkbox("Normal", self.is_checked) - .on_toggle(Message::CheckBox), + .on_toggle(Message::Bool), checkbox("Error", self.is_checked) - .on_toggle(Message::CheckBox) + .on_toggle(Message::Bool) .style(material_theme::checkbox::error), checkbox("Disabled", self.is_checked), horizontal_rule(1), @@ -164,7 +164,12 @@ impl State { center(iced::widget::text!("{:.1}", self.value)) .width(Length::Fill) .height(Length::Shrink), - slider(0.0..=100.0, self.value, Message::Slider).step(0.1) + slider(0.0..=100.0, self.value, Message::Slider).step(0.1), + horizontal_rule(1), + // Toggler + toggler(self.is_checked) + .on_toggle(Message::Bool) + .size(24.0) ] .spacing(10) ] -- cgit v1.2.3 From 68d3fc231968f8bf955082655b3d49faa3f3f547 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 19 Apr 2025 11:13:12 +0200 Subject: feat: tweak default slider size --- crates/material_theme/src/slider.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/material_theme/src/slider.rs b/crates/material_theme/src/slider.rs index cc3bf98..8665459 100644 --- a/crates/material_theme/src/slider.rs +++ b/crates/material_theme/src/slider.rs @@ -47,17 +47,17 @@ pub fn default(theme: &Theme, status: Status) -> Style { match status { Status::Active => { - styled(primary.color, secondary.secondary_container, 16.0) + styled(primary.color, secondary.secondary_container, 12.0) } Status::Hovered => styled( mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY), secondary.secondary_container, - 16.0, + 12.0, ), Status::Dragged => styled( mix(primary.color, surface.on_surface, PRESSED_LAYER_OPACITY), secondary.secondary_container, - 15.0, + 11.0, ), } } -- cgit v1.2.3 From 78c7ac2f3ea0a6e4e88ea9857f37cbc43db12736 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 20 Apr 2025 01:04:42 +0200 Subject: feat(material_theme): implement `pane_grid::Catalog` --- crates/material_theme/src/lib.rs | 1 + crates/material_theme/src/pane_grid.rs | 38 +++++ theme_test/src/main.rs | 284 ++++++++++++++++++++------------- 3 files changed, 216 insertions(+), 107 deletions(-) create mode 100644 crates/material_theme/src/pane_grid.rs diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 0df5b1c..416c958 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -12,6 +12,7 @@ pub mod dialog; #[cfg(feature = "markdown")] pub mod markdown; pub mod menu; +pub mod pane_grid; pub mod pick_list; pub mod progress_bar; #[cfg(feature = "qr_code")] diff --git a/crates/material_theme/src/pane_grid.rs b/crates/material_theme/src/pane_grid.rs new file mode 100644 index 0000000..d66e475 --- /dev/null +++ b/crates/material_theme/src/pane_grid.rs @@ -0,0 +1,38 @@ +use iced_widget::core::{Background, border}; +use iced_widget::pane_grid::{Catalog, Highlight, Line, Style, StyleFn}; + +use super::Theme; +use crate::utils::{HOVERED_LAYER_OPACITY, mix}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> ::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(theme: &Theme) -> Style { + Style { + hovered_region: Highlight { + background: Background::Color(mix( + theme.colorscheme.tertiary.tertiary_container, + theme.colorscheme.surface.on_surface, + HOVERED_LAYER_OPACITY, + )), + border: border::rounded(12), + }, + picked_split: Line { + color: theme.colorscheme.outline.variant, + width: 2.0, + }, + hovered_split: Line { + color: theme.colorscheme.surface.on_surface, + width: 6.0, + }, + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index d564ee5..b8653b5 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,7 +1,7 @@ use iced::Length::Fill; use iced::widget::{ - button, center, checkbox, column, container, horizontal_rule, pick_list, - radio, row, slider, text_input, toggler, + button, center, checkbox, column, container, horizontal_rule, pane_grid, + pick_list, radio, row, slider, text_input, toggler, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -32,10 +32,11 @@ enum Message { Bool(bool), Radio(Choice), Slider(f32), + Resize(pane_grid::ResizeEvent), SwitchTheme(Event), } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct State { theme: Animated, show_dialog: bool, @@ -43,6 +44,28 @@ pub struct State { is_checked: bool, selection: Option, value: f32, + panes: pane_grid::State, +} + +impl Default for State { + fn default() -> Self { + Self { + theme: Default::default(), + show_dialog: Default::default(), + content: Default::default(), + is_checked: Default::default(), + selection: Default::default(), + value: Default::default(), + panes: pane_grid::State::with_configuration( + pane_grid::Configuration::Split { + axis: pane_grid::Axis::Vertical, + ratio: 0.5, + a: Box::new(pane_grid::Configuration::Pane(Pane::Left)), + b: Box::new(pane_grid::Configuration::Pane(Pane::Right)), + }, + ), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -52,6 +75,12 @@ pub enum Choice { C, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Pane { + Left, + Right, +} + impl State { fn update(&mut self, message: Message) { match message { @@ -66,118 +95,159 @@ impl State { Message::Bool(is_checked) => self.is_checked = is_checked, Message::Radio(choice) => self.selection = Some(choice), Message::Slider(value) => self.value = value, + Message::Resize(pane_grid::ResizeEvent { split, ratio }) => { + self.panes.resize(split, ratio); + } Message::SwitchTheme(event) => { self.theme.update(event); } } } fn view(&self) -> Element<'_, Message, Theme> { - let base = container( - row![ - column![ - button("Disabled"), - button("Filled").on_press(Message::Noop), - button("Filled Tonal") - .on_press(Message::Noop) - .style(filled_tonal), - button("Elevated").on_press(Message::Noop).style(elevated), - button("Outlined").on_press(Message::Noop).style(outlined), - button("Text").on_press(Message::Noop).style(text), - button("Text Disabled").style(text), - ] - .spacing(10), - column![ - container("None").padding(8), - container("Primary").padding(8).style(primary), - container("Primary Container") - .padding(8) - .style(primary_container), - container("Secondary").padding(8).style(secondary), - container("Secondary Container") - .padding(8) - .style(secondary_container), - container("Tertiary").padding(8).style(tertiary), - container("Tertiary Container") - .padding(8) - .style(tertiary_container), - container("Error").padding(8).style(error), - container("Error Container") - .padding(8) - .style(error_container), - container("Surface").padding(8).style(surface), - container( - iced::widget::text("Surface Variant") - .style(surface_variant) + let base: pane_grid::PaneGrid<'_, Message, Theme> = + pane_grid(&self.panes, |_pane, state, _is_maximized| { + pane_grid::Content::new(match state { + Pane::Left => container( + row![ + column![ + button("Disabled"), + button("Filled").on_press(Message::Noop), + button("Filled Tonal") + .on_press(Message::Noop) + .style(filled_tonal), + button("Elevated") + .on_press(Message::Noop) + .style(elevated), + button("Outlined") + .on_press(Message::Noop) + .style(outlined), + button("Text") + .on_press(Message::Noop) + .style(text), + button("Text Disabled").style(text), + ] + .spacing(10), + column![ + container("None").padding(8), + container("Primary").padding(8).style(primary), + container("Primary Container") + .padding(8) + .style(primary_container), + container("Secondary") + .padding(8) + .style(secondary), + container("Secondary Container") + .padding(8) + .style(secondary_container), + container("Tertiary") + .padding(8) + .style(tertiary), + container("Tertiary Container") + .padding(8) + .style(tertiary_container), + container("Error").padding(8).style(error), + container("Error Container") + .padding(8) + .style(error_container), + container("Surface").padding(8).style(surface), + container( + iced::widget::text("Surface Variant") + .style(surface_variant) + ) + .padding(8) + .style(surface), + container("Inverse Surface") + .padding(8) + .style(inverse_surface), + container("Surface Container Lowest") + .padding(8) + .style(surface_container_lowest), + container("Surface Container Low") + .padding(8) + .style(surface_container_low), + container("Surface Container") + .padding(8) + .style(surface_container), + container("Surface Container High") + .padding(8) + .style(surface_container_high), + container("Surface Container Highest") + .padding(8) + .style(surface_container_highest), + ] + .spacing(10), + ] + .spacing(10), ) - .padding(8) - .style(surface), - container("Inverse Surface") - .padding(8) - .style(inverse_surface), - container("Surface Container Lowest") - .padding(8) - .style(surface_container_lowest), - container("Surface Container Low") - .padding(8) - .style(surface_container_low), - container("Surface Container") - .padding(8) - .style(surface_container), - container("Surface Container High") - .padding(8) - .style(surface_container_high), - container("Surface Container Highest") - .padding(8) - .style(surface_container_highest), - ] - .spacing(10), - column![ - // Pick List - pick_list( - [LIGHT.clone(), DARK.clone()], - Some(self.theme.target()), - |theme| Message::SwitchTheme(theme.into()) + .width(Length::Fill) + .height(Length::Fill) + .padding(12), + + Pane::Right => container( + column![ + // Pick List + pick_list( + [LIGHT.clone(), DARK.clone()], + Some(self.theme.target()), + |theme| Message::SwitchTheme(theme.into()) + ) + .placeholder("Select a theme..."), + horizontal_rule(1), + // Button + button("Open Dialog").on_press(Message::OpenDialog), + horizontal_rule(1), + // Text Input + text_input("Type something here...", &self.content) + .on_input(Message::Input), + horizontal_rule(1), + // Checkbox + checkbox("Normal", self.is_checked) + .on_toggle(Message::Bool), + checkbox("Error", self.is_checked) + .on_toggle(Message::Bool) + .style(material_theme::checkbox::error), + checkbox("Disabled", self.is_checked), + horizontal_rule(1), + // Radio + radio( + "A", + Choice::A, + self.selection, + Message::Radio, + ), + radio( + "B", + Choice::B, + self.selection, + Message::Radio, + ), + radio( + "C", + Choice::C, + self.selection, + Message::Radio, + ), + horizontal_rule(1), + // Slider + center(iced::widget::text!("{:.1}", self.value)) + .width(Length::Fill) + .height(Length::Shrink), + slider(0.0..=100.0, self.value, Message::Slider) + .step(0.1), + horizontal_rule(1), + // Toggler + toggler(self.is_checked) + .on_toggle(Message::Bool) + .size(24.0) + ] + .spacing(10), ) - .placeholder("Select a theme..."), - horizontal_rule(1), - // Button - button("Open Dialog").on_press(Message::OpenDialog), - horizontal_rule(1), - // Text Input - text_input("Type something here...", &self.content) - .on_input(Message::Input), - horizontal_rule(1), - // Checkbox - checkbox("Normal", self.is_checked) - .on_toggle(Message::Bool), - checkbox("Error", self.is_checked) - .on_toggle(Message::Bool) - .style(material_theme::checkbox::error), - checkbox("Disabled", self.is_checked), - horizontal_rule(1), - // Radio - radio("A", Choice::A, self.selection, Message::Radio,), - radio("B", Choice::B, self.selection, Message::Radio,), - radio("C", Choice::C, self.selection, Message::Radio,), - horizontal_rule(1), - // Slider - center(iced::widget::text!("{:.1}", self.value)) - .width(Length::Fill) - .height(Length::Shrink), - slider(0.0..=100.0, self.value, Message::Slider).step(0.1), - horizontal_rule(1), - // Toggler - toggler(self.is_checked) - .on_toggle(Message::Bool) - .size(24.0) - ] - .spacing(10) - ] - .spacing(20), - ) - .width(Fill) - .height(Fill) - .padding(12); + .width(Length::Fill) + .height(Length::Fill) + .padding(12), + }) + }) + .on_resize(10, Message::Resize); let dialog = dialog(self.show_dialog, base, iced::widget::text("Say Hi!")) -- cgit v1.2.3 From cf446c5310f08350e1d7cc68390cb89598dbcf5a Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 20 Apr 2025 01:05:14 +0200 Subject: fix: ordering in `build.rs` --- build.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/build.rs b/build.rs index d1a02af..de1f754 100644 --- a/build.rs +++ b/build.rs @@ -5,6 +5,17 @@ use std::path::Path; use std::process::Command; fn main() { + println!("cargo::rerun-if-changed=fonts/icons.toml"); + iced_fontello::build("fonts/icons.toml").expect("Build icons font"); + #[cfg(windows)] + { + embed_resource::compile( + "assets/windows/iced_builder.rc", + embed_resource::NONE, + ); + windows_exe_info::versioninfo::link_cargo_env(); + } + let git_hash = Command::new("git") .args(["describe", "--always", "--dirty", "--exclude='*'"]) .output() @@ -48,15 +59,4 @@ fn main() { if head_ref.exists() { println!("cargo:rerun-if-changed={}", head_ref.display()); } - - println!("cargo::rerun-if-changed=fonts/icons.toml"); - iced_fontello::build("fonts/icons.toml").expect("Build icons font"); - #[cfg(windows)] - { - embed_resource::compile( - "assets/windows/iced_builder.rc", - embed_resource::NONE, - ); - windows_exe_info::versioninfo::link_cargo_env(); - } } -- cgit v1.2.3 From bbecf293208ba61bb3d57d57afd7373797007bfe Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 20 Apr 2025 01:05:54 +0200 Subject: feat: use `pane_grid::Controls` for PaneGrid titlebar controls --- fonts/icons.toml | 1 + fonts/icons.ttf | Bin 6348 -> 6504 bytes src/icon.rs | 6 +++++- src/panes/code_view.rs | 49 +++++++++++++++++++++++++++++---------------- src/panes/designer_view.rs | 29 ++++++++++++++++++--------- 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/fonts/icons.toml b/fonts/icons.toml index a70c0e7..3092001 100644 --- a/fonts/icons.toml +++ b/fonts/icons.toml @@ -4,3 +4,4 @@ module = "icon" save = "entypo-floppy" open = "fontawesome-folder-open-empty" copy = "fontawesome-file-code" +switch = "entypo-switch" diff --git a/fonts/icons.ttf b/fonts/icons.ttf index 7af6b0e..e1aba57 100644 Binary files a/fonts/icons.ttf and b/fonts/icons.ttf differ diff --git a/src/icon.rs b/src/icon.rs index 9dc0a89..3fbeb83 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -1,6 +1,6 @@ // Generated automatically by iced_fontello at build time. // Do not edit manually. Source: ../fonts/icons.toml -// 02c7558d187cdc056fdd0e6a638ef805fa10f5955f834575e51d75acd35bc70e +// 915ea6b0646871c0f04350f201f27f28881b61f3bd6ef292a415d67a211739c1 use iced::widget::{text, Text}; use iced::Font; @@ -18,6 +18,10 @@ pub fn save<'a>() -> Text<'a> { icon("\u{1F4BE}") } +pub fn switch<'a>() -> Text<'a> { + icon("\u{21C6}") +} + fn icon(codepoint: &str) -> Text<'_> { text(codepoint).font(Font::with_name("icons")) } diff --git a/src/panes/code_view.rs b/src/panes/code_view.rs index 551347c..85b0bbe 100644 --- a/src/panes/code_view.rs +++ b/src/panes/code_view.rs @@ -22,25 +22,40 @@ pub fn view( editor_content: &text_editor::Content, is_focused: bool, ) -> pane_grid::Content<'_, Message> { - let title = row![ - text("Generated Code"), - Space::with_width(Length::Fill), - tip( - button(icon::copy()) - .on_press(Message::CopyCode) - .padding([2, 7]) - .style(button::text), - "Copy", - tip::Position::FollowCursor - ), - Space::with_width(20), - button("Switch to Designer view") - .on_press(Message::SwitchPage(DesignerPane::DesignerView)) - ] - .align_y(Alignment::Center); - let title_bar = pane_grid::TitleBar::new(title) + let title_bar = pane_grid::TitleBar::new(text("Generated Code").center()) + .controls(pane_grid::Controls::dynamic( + row![ + tip( + button(icon::copy()) + .on_press(Message::CopyCode) + .padding([2, 7]) + .style(button::text), + "Copy", + tip::Position::FollowCursor + ), + Space::with_width(20), + button("Switch to Designer view") + .on_press(Message::SwitchPage(DesignerPane::DesignerView)) + ] + .align_y(Alignment::Center), + row![ + tip( + button(icon::copy()) + .on_press(Message::CopyCode) + .padding([2, 7]) + .style(button::text), + "Copy", + tip::Position::FollowCursor + ), + Space::with_width(20), + button(icon::switch()) + .on_press(Message::SwitchPage(DesignerPane::DesignerView)) + ] + .align_y(Alignment::Center), + )) .padding(10) .style(style::title_bar); + pane_grid::Content::new( text_editor(editor_content) .on_action(Message::EditorAction) diff --git a/src/panes/designer_view.rs b/src/panes/designer_view.rs index 69ff750..af72022 100644 --- a/src/panes/designer_view.rs +++ b/src/panes/designer_view.rs @@ -1,9 +1,10 @@ use iced::widget::{ - Space, button, center, container, pane_grid, responsive, row, text, themer, + button, center, container, pane_grid, responsive, row, text, themer, }; use iced::{Alignment, Element, Length}; use super::style; +use crate::icon; use crate::types::{DesignerPane, Message, RenderedElement}; pub fn view<'a>( @@ -24,22 +25,30 @@ pub fn view<'a>( .into() }) .into(), - None => text("Open a project or begin creating one").into(), + None => center("Open a project or begin creating one").into(), }; + let content = container(themer(designer_theme, el_tree)) .id(iced::widget::container::Id::new("drop_zone")) .height(Length::Fill) .width(Length::Fill); - let title = row![ - text("Designer"), - Space::with_width(Length::Fill), - button("Switch to Code view") - .on_press(Message::SwitchPage(DesignerPane::CodeView)), - ] - .align_y(Alignment::Center); - let title_bar = pane_grid::TitleBar::new(title) + + let title_bar = pane_grid::TitleBar::new(text("Designer").center()) + .controls(pane_grid::Controls::dynamic( + row![ + button("Switch to Code view") + .on_press(Message::SwitchPage(DesignerPane::CodeView),) + ] + .align_y(Alignment::Center), + row![ + button(icon::switch()) + .on_press(Message::SwitchPage(DesignerPane::CodeView),) + ] + .align_y(Alignment::Center), + )) .padding(10) .style(style::title_bar); + pane_grid::Content::new(content) .title_bar(title_bar) .style(if is_focused { -- cgit v1.2.3 From c3c05cef555de305729e53cef8b8e660e31eaf27 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 22 Apr 2025 14:33:36 +0200 Subject: refactor: apply some clippy suggestions --- Cargo.lock | 99 ++++++++++++++++------------------- crates/material_theme/src/button.rs | 4 +- crates/material_theme/src/checkbox.rs | 6 +-- crates/material_theme/src/lib.rs | 5 +- crates/material_theme/src/utils.rs | 6 ++- src/panes/code_view.rs | 2 +- 6 files changed, 59 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f0a992..fd31403 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,11 +534,11 @@ dependencies = [ [[package]] name = "block2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" +checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" dependencies = [ - "objc2 0.6.0", + "objc2 0.6.1", ] [[package]] @@ -1070,9 +1070,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0" dependencies = [ "bitflags 2.9.0", - "block2 0.6.0", + "block2 0.6.1", "libc", - "objc2 0.6.0", + "objc2 0.6.1", +] + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.1", ] [[package]] @@ -1160,20 +1170,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "embed-resource" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml", - "vswhom", - "winreg", -] - [[package]] name = "embed-resource" version = "3.0.2" @@ -1997,7 +1993,7 @@ name = "iced_builder" version = "0.1.0" dependencies = [ "dirs-next", - "embed-resource 3.0.2", + "embed-resource", "fxhash", "iced", "iced_anim", @@ -2611,9 +2607,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -2675,12 +2671,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - [[package]] name = "log" version = "0.4.27" @@ -3124,9 +3114,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" dependencies = [ "objc2-encode", ] @@ -3149,14 +3139,14 @@ dependencies = [ [[package]] name = "objc2-app-kit" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ "bitflags 2.9.0", - "block2 0.6.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", + "block2 0.6.1", + "objc2 0.6.1", + "objc2-foundation 0.3.1", ] [[package]] @@ -3197,12 +3187,13 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "dispatch2 0.3.0", + "objc2 0.6.1", ] [[package]] @@ -3250,12 +3241,12 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "bitflags 2.9.0", - "objc2 0.6.0", + "objc2 0.6.1", "objc2-core-foundation", ] @@ -4035,14 +4026,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d" dependencies = [ "ashpd 0.11.0", - "block2 0.6.0", - "dispatch2", + "block2 0.6.1", + "dispatch2 0.2.0", "js-sys", "log", - "objc2 0.6.0", - "objc2-app-kit 0.3.0", + "objc2 0.6.1", + "objc2-app-kit 0.3.1", "objc2-core-foundation", - "objc2-foundation 0.3.0", + "objc2-foundation 0.3.1", "pollster", "raw-window-handle", "urlencoding", @@ -4383,9 +4374,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] @@ -5952,12 +5943,12 @@ checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_exe_info" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0960cd3c8e7c1a55327ac8206395748c8145dc56c524057d1d50ab80300f49f" +checksum = "3a7c2cd292e8e58e012eaf18f18f6b64ef74e0b90677b4f9e1f15bfca24056c7" dependencies = [ "camino", - "embed-resource 2.5.1", + "embed-resource", ] [[package]] @@ -6515,15 +6506,13 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", - "lockfree-object-pool", "log", - "once_cell", "simd-adler32", ] diff --git a/crates/material_theme/src/button.rs b/crates/material_theme/src/button.rs index 21d77b7..e1369eb 100644 --- a/crates/material_theme/src/button.rs +++ b/crates/material_theme/src/button.rs @@ -143,7 +143,7 @@ pub fn outlined(theme: &Theme, status: Status) -> Style { Status::Active | Status::Pressed | Status::Hovered => Border { color: outline, width: 1.0, - radius: 400.0.into(), + radius: 400.into(), }, Status::Disabled => Border { color: Color { @@ -151,7 +151,7 @@ pub fn outlined(theme: &Theme, status: Status) -> Style { ..disabled }, width: 1.0, - radius: 400.0.into(), + radius: 400.into(), }, }; diff --git a/crates/material_theme/src/checkbox.rs b/crates/material_theme/src/checkbox.rs index ac1f974..ff038b0 100644 --- a/crates/material_theme/src/checkbox.rs +++ b/crates/material_theme/src/checkbox.rs @@ -18,7 +18,7 @@ impl Catalog for Theme { pub fn styled( background_color: Color, - background_hover: Option, + background_unchecked: Option, icon_color: Color, border_color: Color, text_color: Option, @@ -28,7 +28,7 @@ pub fn styled( background: Background::Color(if is_checked { background_color } else { - background_hover.unwrap_or(Color::TRANSPARENT) + background_unchecked.unwrap_or(Color::TRANSPARENT) }), icon_color, border: if is_checked { @@ -37,7 +37,7 @@ pub fn styled( Border { color: border_color, width: 2.0, - radius: border::radius(2), + radius: 2.into(), } }, text_color, diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 416c958..13f13b1 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -24,6 +24,7 @@ pub mod slider; #[cfg(feature = "svg")] pub mod svg; pub mod text; +pub mod text_editor; pub mod text_input; pub mod toggler; pub mod utils; @@ -59,7 +60,7 @@ impl Clone for Theme { } fn clone_from(&mut self, source: &Self) { - self.name = source.name.clone(); + self.name.clone_from(&source.name); self.colorscheme = source.colorscheme; } } @@ -142,6 +143,7 @@ pub struct ColorScheme { pub scrim: Color, } +#[allow(clippy::cast_precision_loss)] macro_rules! from_argb { ($hex:expr) => {{ let hex = $hex as u32; @@ -155,6 +157,7 @@ macro_rules! from_argb { }}; } +#[allow(clippy::cast_precision_loss)] impl ColorScheme { const DARK: Self = Self { primary: Primary { diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs index f35396f..5ad137e 100644 --- a/crates/material_theme/src/utils.rs +++ b/crates/material_theme/src/utils.rs @@ -1,5 +1,7 @@ use iced_widget::core::{Color, Shadow, Vector}; +const COLOR_ERROR_MARGIN: f32 = 0.0001; + pub const HOVERED_LAYER_OPACITY: f32 = 0.08; pub const PRESSED_LAYER_OPACITY: f32 = 0.1; @@ -95,7 +97,9 @@ pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { let p1 = 1.0 - p2; - if color1.a != 1.0 || color2.a != 1.0 { + if (color1.a - 1.0).abs() > COLOR_ERROR_MARGIN + || (color2.a - 1.0) > COLOR_ERROR_MARGIN + { let a = color1.a * p1 + color2.a * p2; if a > 0.0 { let c1 = color1.into_linear().map(|c| c * color1.a * p1); diff --git a/src/panes/code_view.rs b/src/panes/code_view.rs index 85b0bbe..890af8a 100644 --- a/src/panes/code_view.rs +++ b/src/panes/code_view.rs @@ -71,7 +71,7 @@ pub fn view( palette.background.base.color, ), border: Border { - radius: 2.0.into(), + radius: 2.into(), width: 1.0, color: palette.background.strong.color, }, -- cgit v1.2.3 From 674d1bb1f50707c3473a675820f7c2dc5cbb2e15 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 22 Apr 2025 14:35:39 +0200 Subject: fix(material_theme): disabled checkbox border being fully opaque --- crates/material_theme/src/toggler.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/material_theme/src/toggler.rs b/crates/material_theme/src/toggler.rs index 1cc5082..8949d07 100644 --- a/crates/material_theme/src/toggler.rs +++ b/crates/material_theme/src/toggler.rs @@ -74,7 +74,10 @@ pub fn default(theme: &Theme, status: Status) -> Style { a: DISABLED_TEXT_OPACITY, ..surface.on_surface }, - Some(surface.on_surface), + Some(Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }), ), } } -- cgit v1.2.3 From 44bd09e90a18a14eb53def25702225481760fb78 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 22 Apr 2025 14:36:44 +0200 Subject: fix(material_theme): highlighted text not being visible in `TextInput` --- crates/material_theme/src/text_input.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/material_theme/src/text_input.rs b/crates/material_theme/src/text_input.rs index 5fa65ef..5de5993 100644 --- a/crates/material_theme/src/text_input.rs +++ b/crates/material_theme/src/text_input.rs @@ -30,7 +30,10 @@ pub fn default(theme: &Theme, status: Status) -> Style { icon: surface.on_surface_variant, placeholder: surface.on_surface_variant, value: surface.on_surface, - selection: surface.on_surface, + selection: Color { + a: DISABLED_TEXT_OPACITY, + ..primary.color + }, }; match status { -- cgit v1.2.3 From 21648601fa642e560772506967ce0fd589aebfaa Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 22 Apr 2025 14:37:00 +0200 Subject: feat(material_theme): implement `text_editor::Catalog` --- crates/material_theme/src/text_editor.rs | 85 ++++++++++++++++++++++++++++++++ theme_test/src/main.rs | 19 +++++-- 2 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 crates/material_theme/src/text_editor.rs diff --git a/crates/material_theme/src/text_editor.rs b/crates/material_theme/src/text_editor.rs new file mode 100644 index 0000000..daad7d2 --- /dev/null +++ b/crates/material_theme/src/text_editor.rs @@ -0,0 +1,85 @@ +use iced_widget::core::{Background, Border, Color, border}; +use iced_widget::text_editor::{Catalog, Status, Style, StyleFn}; + +use super::Theme; +use crate::utils::DISABLED_TEXT_OPACITY; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn default(theme: &Theme, status: Status) -> Style { + let surface = theme.colorscheme.surface; + let primary = theme.colorscheme.primary; + + let active = Style { + background: Background::Color(surface.surface_container.highest), + border: Border { + color: theme.colorscheme.outline.color, + width: 1.0, + radius: 4.into(), + }, + icon: surface.on_surface_variant, + placeholder: surface.on_surface_variant, + value: surface.on_surface, + selection: Color { + a: DISABLED_TEXT_OPACITY, + ..primary.color + }, + }; + + match status { + Status::Active => active, + Status::Hovered => Style { + border: Border { + color: surface.on_surface, + ..active.border + }, + ..active + }, + Status::Focused { .. } => Style { + border: Border { + color: primary.color, + width: 2.0, + ..active.border + }, + placeholder: primary.color, + ..active + }, + Status::Disabled => Style { + background: Color::TRANSPARENT.into(), + border: Border { + color: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + width: 1.0, + radius: border::radius(4), + }, + icon: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + placeholder: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + selection: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + value: Color { + a: DISABLED_TEXT_OPACITY, + ..surface.on_surface + }, + }, + } +} diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index b8653b5..3331196 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,7 +1,6 @@ -use iced::Length::Fill; use iced::widget::{ button, center, checkbox, column, container, horizontal_rule, pane_grid, - pick_list, radio, row, slider, text_input, toggler, + pick_list, radio, row, slider, text_editor, text_input, toggler, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -32,6 +31,7 @@ enum Message { Bool(bool), Radio(Choice), Slider(f32), + Edit(text_editor::Action), Resize(pane_grid::ResizeEvent), SwitchTheme(Event), } @@ -44,6 +44,7 @@ pub struct State { is_checked: bool, selection: Option, value: f32, + editor_content: text_editor::Content, panes: pane_grid::State, } @@ -56,6 +57,7 @@ impl Default for State { is_checked: Default::default(), selection: Default::default(), value: Default::default(), + editor_content: text_editor::Content::new(), panes: pane_grid::State::with_configuration( pane_grid::Configuration::Split { axis: pane_grid::Axis::Vertical, @@ -95,6 +97,7 @@ impl State { Message::Bool(is_checked) => self.is_checked = is_checked, Message::Radio(choice) => self.selection = Some(choice), Message::Slider(value) => self.value = value, + Message::Edit(action) => self.editor_content.perform(action), Message::Resize(pane_grid::ResizeEvent { split, ratio }) => { self.panes.resize(split, ratio); } @@ -193,12 +196,13 @@ impl State { ) .placeholder("Select a theme..."), horizontal_rule(1), - // Button + // Dialog button("Open Dialog").on_press(Message::OpenDialog), horizontal_rule(1), // Text Input text_input("Type something here...", &self.content) .on_input(Message::Input), + text_input("Disabled", "Disabled"), horizontal_rule(1), // Checkbox checkbox("Normal", self.is_checked) @@ -238,7 +242,14 @@ impl State { // Toggler toggler(self.is_checked) .on_toggle(Message::Bool) - .size(24.0) + .size(24.0), + toggler(self.is_checked).size(24.0), + horizontal_rule(1), + // Text Editor + text_editor(&self.editor_content) + .on_action(Message::Edit), + text_editor(&self.editor_content) + .placeholder("Disabled") ] .spacing(10), ) -- cgit v1.2.3 From 4dc531f63712e8072a785bd1ec22f35aab3b9140 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 22 Apr 2025 20:27:20 +0200 Subject: refactor(material_theme): make `Theme` `Copy`, add `Theme::ALL` constant --- Cargo.toml | 1 + crates/material_theme/src/lib.rs | 60 +++++++++++++++++----------------------- theme_test/src/main.rs | 6 ++-- 3 files changed, 29 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c0984b..a4abf56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ from_over_into = "deny" needless_borrow = "deny" new_without_default = "deny" useless_conversion = "deny" +clone_on_copy = "deny" [patch.crates-io] iced_anim = { git = "https://github.com/pml68/iced_anim" } diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 13f13b1..25b6a9c 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -1,7 +1,7 @@ use std::sync::LazyLock; +use iced_widget::core::Color; use iced_widget::core::theme::{Base, Style}; -use iced_widget::core::{Color, color}; pub mod button; pub mod checkbox; @@ -29,55 +29,48 @@ pub mod text_input; pub mod toggler; pub mod utils; -pub static DARK: LazyLock = - LazyLock::new(|| Theme::new("Dark", ColorScheme::DARK)); -pub static LIGHT: LazyLock = - LazyLock::new(|| Theme::new("Light", ColorScheme::LIGHT)); - -#[derive(Debug, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Theme { - pub name: String, + pub name: &'static str, #[cfg_attr(feature = "serde", serde(flatten))] pub colorscheme: ColorScheme, } impl Theme { + pub const ALL: &'static [Self] = &[Self::DARK, Self::LIGHT]; + + pub const DARK: Self = Self { + name: "Dark", + colorscheme: ColorScheme::DARK, + }; + + pub const LIGHT: Self = Self { + name: "Light", + colorscheme: ColorScheme::LIGHT, + }; + pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { Self { - name: name.into(), + name: Box::leak(name.into().into_boxed_str()), colorscheme, } } } -impl Clone for Theme { - fn clone(&self) -> Self { - Self { - name: self.name.clone(), - colorscheme: self.colorscheme, - } - } - - fn clone_from(&mut self, source: &Self) { - self.name.clone_from(&source.name); - self.colorscheme = source.colorscheme; - } -} - impl Default for Theme { fn default() -> Self { static DEFAULT: LazyLock = LazyLock::new(|| { match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { dark_light::Mode::Dark | dark_light::Mode::Unspecified => { - DARK.clone() + Theme::DARK } - dark_light::Mode::Light => LIGHT.clone(), + dark_light::Mode::Light => Theme::LIGHT, } }); - DEFAULT.clone() + *DEFAULT } } @@ -108,10 +101,8 @@ impl iced_anim::Animate for Theme { } fn update(&mut self, components: &mut impl Iterator) { - let mut colors = self.colorscheme; - colors.update(components); - - *self = Theme::new("Animating Theme", colors); + self.colorscheme.update(components); + self.name = "Animating Theme"; } fn distance_to(&self, end: &Self) -> Vec { @@ -119,10 +110,9 @@ impl iced_anim::Animate for Theme { } fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { - let mut colors = self.colorscheme; - colors.lerp(&start.colorscheme, &end.colorscheme, progress); - - *self = Theme::new("Animating Theme", colors); + self.colorscheme + .lerp(&start.colorscheme, &end.colorscheme, progress); + self.name = "Animating Theme"; } } @@ -153,7 +143,7 @@ macro_rules! from_argb { let g = (hex & 0x0000ff00) >> 8; let b = (hex & 0x000000ff); - color!(r as u8, g as u8, b as u8, a) + ::iced_widget::core::color!(r as u8, g as u8, b as u8, a) }}; } diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 3331196..7ec7f15 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -5,6 +5,7 @@ use iced::widget::{ use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; use iced_dialog::dialog; +use material_theme::Theme; use material_theme::button::{elevated, filled_tonal, outlined, text}; use material_theme::container::{ error, error_container, inverse_surface, primary, primary_container, @@ -13,11 +14,10 @@ use material_theme::container::{ surface_container_lowest, tertiary, tertiary_container, }; use material_theme::text::surface_variant; -use material_theme::{DARK, LIGHT, Theme}; fn main() -> iced::Result { iced::application(State::default, State::update, State::view) - .theme(|state| state.theme.value().clone()) + .theme(|state| *state.theme.value()) .run() } @@ -190,7 +190,7 @@ impl State { column![ // Pick List pick_list( - [LIGHT.clone(), DARK.clone()], + Theme::ALL, Some(self.theme.target()), |theme| Message::SwitchTheme(theme.into()) ) -- cgit v1.2.3 From f9f854f124d4676e8c79adeda6bfaceba586805f Mon Sep 17 00:00:00 2001 From: pml68 Date: Fri, 25 Apr 2025 11:30:46 +0200 Subject: feat(material_theme): create an iced `Palette` for `iced::theme::Base` impl --- Cargo.toml | 3 ++- crates/material_theme/src/lib.rs | 44 +++++++++++++++++++++++++--------------- src/main.rs | 2 +- theme_test/Cargo.toml | 1 + 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a4abf56..0a7d769 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,8 @@ toml = "0.8.20" [workspace.dependencies.iced] git = "https://github.com/pml68/iced" branch = "feat/rehighlight-on-redraw" -features = ["image", "svg", "advanced", "tokio", "lazy"] +default-features = false +features = ["wgpu", "tiny-skia", "web-colors", "auto-detect-theme", "image", "svg", "advanced", "tokio", "lazy"] [build-dependencies] iced_fontello = "0.13.2" diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 25b6a9c..569b06c 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -29,6 +29,20 @@ pub mod text_input; pub mod toggler; pub mod utils; +#[allow(clippy::cast_precision_loss)] +macro_rules! from_argb { + ($hex:expr) => {{ + let hex = $hex as u32; + + let a = ((hex & 0xff000000) >> 24) as f32 / 255.0; + let r = (hex & 0x00ff0000) >> 16; + let g = (hex & 0x0000ff00) >> 8; + let b = (hex & 0x000000ff); + + ::iced_widget::core::color!(r as u8, g as u8, b as u8, a) + }}; +} + #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Theme { @@ -89,8 +103,20 @@ impl Base for Theme { } fn palette(&self) -> Option { - // TODO: create a Palette - None + let colors = self.colorscheme; + + Some(iced_widget::theme::Palette { + background: colors.surface.color, + text: colors.surface.on_surface, + primary: colors.primary.color, + success: colors.primary.primary_container, + warning: utils::mix( + from_argb!(0xffffff00), + colors.primary.color, + 0.25, + ), + danger: colors.error.color, + }) } } @@ -133,20 +159,6 @@ pub struct ColorScheme { pub scrim: Color, } -#[allow(clippy::cast_precision_loss)] -macro_rules! from_argb { - ($hex:expr) => {{ - let hex = $hex as u32; - - let a = ((hex & 0xff000000) >> 24) as f32 / 255.0; - let r = (hex & 0x00ff0000) >> 16; - let g = (hex & 0x0000ff00) >> 8; - let b = (hex & 0x000000ff); - - ::iced_widget::core::color!(r as u8, g as u8, b as u8, a) - }}; -} - #[allow(clippy::cast_precision_loss)] impl ColorScheme { const DARK: Self = Self { diff --git a/src/main.rs b/src/main.rs index 0f1a1bf..5014077 100644 --- a/src/main.rs +++ b/src/main.rs @@ -146,8 +146,8 @@ impl IcedBuilder { Message::ConfigLoad(result) => match result { Ok(config) => { self.config = Arc::new(config); - self.theme.update(self.config.selected_theme().into()); + return if let Some(path) = self.config.last_project.clone() { if path.exists() && path.is_file() { diff --git a/theme_test/Cargo.toml b/theme_test/Cargo.toml index 29fcdc8..300a7af 100644 --- a/theme_test/Cargo.toml +++ b/theme_test/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] iced.workspace = true +iced.features = ["debug"] iced_anim.workspace = true iced_dialog.workspace = true material_theme = { path = "../crates/material_theme", features = ["dialog", "animate"] } -- cgit v1.2.3 From 3bdd724119eb2dbcb2480e441cd13f82575c6536 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 26 Apr 2025 13:17:58 +0200 Subject: feat(material_theme): implement `image::Catalog` (under feature flag) --- Cargo.lock | 89 +++++++++++++++++--------------- crates/iced_drop/src/widget/droppable.rs | 2 + crates/material_theme/Cargo.toml | 2 + crates/material_theme/src/image.rs | 21 ++++++++ crates/material_theme/src/lib.rs | 2 + theme_test/src/main.rs | 4 +- 6 files changed, 78 insertions(+), 42 deletions(-) create mode 100644 crates/material_theme/src/image.rs diff --git a/Cargo.lock b/Cargo.lock index fd31403..9154eb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", "zerocopy 0.7.35", @@ -657,9 +657,9 @@ checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -1592,9 +1592,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1941,7 +1941,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_core", "iced_debug", @@ -1958,7 +1958,7 @@ dependencies = [ [[package]] name = "iced_anim" version = "0.2.1" -source = "git+https://github.com/pml68/iced_anim#0c833c0943493c8fc22a60e138785e4c688ef8d8" +source = "git+https://github.com/pml68/iced_anim#c881a8a9c49b0536f4ee3c236ec24285eabc0d76" dependencies = [ "iced", "iced_anim_derive", @@ -1967,7 +1967,7 @@ dependencies = [ [[package]] name = "iced_anim_derive" version = "0.2.0" -source = "git+https://github.com/pml68/iced_anim#0c833c0943493c8fc22a60e138785e4c688ef8d8" +source = "git+https://github.com/pml68/iced_anim#c881a8a9c49b0536f4ee3c236ec24285eabc0d76" dependencies = [ "quote", "syn", @@ -1976,7 +1976,7 @@ dependencies = [ [[package]] name = "iced_beacon" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bincode", "futures", @@ -2017,7 +2017,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2046,7 +2046,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_beacon", "iced_core", @@ -2056,7 +2056,7 @@ dependencies = [ [[package]] name = "iced_devtools" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_debug", "iced_program", @@ -2066,7 +2066,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#6e901c21dbb259d337ed1ad2054da3862172b8b3" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#57388a202159052ccc771bfb537bd46e8f3b9e70" dependencies = [ "iced_core", "iced_widget", @@ -2096,7 +2096,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "futures", "iced_core", @@ -2110,7 +2110,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2131,7 +2131,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_graphics", "iced_runtime", @@ -2140,7 +2140,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bytes", "iced_core", @@ -2165,7 +2165,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bytemuck", "cosmic-text", @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2203,7 +2203,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_renderer", "iced_runtime", @@ -2221,7 +2221,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_debug", "iced_program", @@ -3636,7 +3636,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.25", ] [[package]] @@ -3806,7 +3806,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -3940,7 +3940,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -4060,7 +4060,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -4943,9 +4943,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -4956,9 +4956,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" dependencies = [ "serde", "serde_spanned", @@ -4968,26 +4968,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976" + [[package]] name = "tower" version = "0.5.2" @@ -6136,9 +6143,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -6384,11 +6391,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.25", ] [[package]] @@ -6404,9 +6411,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", diff --git a/crates/iced_drop/src/widget/droppable.rs b/crates/iced_drop/src/widget/droppable.rs index 947cf5b..196464a 100644 --- a/crates/iced_drop/src/widget/droppable.rs +++ b/crates/iced_drop/src/widget/droppable.rs @@ -418,6 +418,7 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, + _viewport: &iced::Rectangle, _translation: Vector, ) -> Option> { let state: &mut State = tree.state.downcast_mut::(); @@ -434,6 +435,7 @@ where &mut tree.children[0], layout, renderer, + _viewport, _translation, ) } diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index 941bc3e..30de38b 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -21,6 +21,8 @@ animate = ["dep:iced_anim"] dialog = ["dep:iced_dialog"] # Provides support for the markdown widget. markdown = ["iced_widget/markdown"] +# Provides support for the image widget. +image = ["iced_widget/image"] # Provides support for the SVG widget. svg = ["iced_widget/svg"] # Provides support for the QR code widget. diff --git a/crates/material_theme/src/image.rs b/crates/material_theme/src/image.rs new file mode 100644 index 0000000..de5942a --- /dev/null +++ b/crates/material_theme/src/image.rs @@ -0,0 +1,21 @@ +use iced_widget::core::{Background, Border, Color, border}; +use iced_widget::image::{Catalog, Style, StyleFn}; + +use super::Theme; +use crate::utils::{elevation, shadow_from_elevation}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(_theme: &Theme) -> Style { + Style::default() +} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 569b06c..1b4f90e 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -9,6 +9,8 @@ pub mod combo_box; pub mod container; #[cfg(feature = "dialog")] pub mod dialog; +#[cfg(feature = "image")] +pub mod image; #[cfg(feature = "markdown")] pub mod markdown; pub mod menu; diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 7ec7f15..b4a7731 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,6 +1,7 @@ use iced::widget::{ button, center, checkbox, column, container, horizontal_rule, pane_grid, - pick_list, radio, row, slider, text_editor, text_input, toggler, + pick_list, progress_bar, radio, row, slider, text_editor, text_input, + toggler, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -238,6 +239,7 @@ impl State { .height(Length::Shrink), slider(0.0..=100.0, self.value, Message::Slider) .step(0.1), + progress_bar(0.0..=100.0, self.value), horizontal_rule(1), // Toggler toggler(self.is_checked) -- cgit v1.2.3 From dac7e82e0bff128097653fe05829b2d576fcdb2f Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 28 Apr 2025 10:56:49 +0200 Subject: refactor(material_theme)!: make `Theme` an enum with `Custom` variant --- crates/material_theme/src/button.rs | 103 +++++++++----------------- crates/material_theme/src/checkbox.rs | 30 +++----- crates/material_theme/src/container.rs | 119 ++++++++++++++++++------------ crates/material_theme/src/dialog.rs | 4 +- crates/material_theme/src/image.rs | 8 +- crates/material_theme/src/lib.rs | 111 +++++++++++++++++++--------- crates/material_theme/src/menu.rs | 2 +- crates/material_theme/src/pane_grid.rs | 8 +- crates/material_theme/src/pick_list.rs | 2 +- crates/material_theme/src/progress_bar.rs | 4 +- crates/material_theme/src/qr_code.rs | 2 +- crates/material_theme/src/radio.rs | 11 +-- crates/material_theme/src/rule.rs | 4 +- crates/material_theme/src/scrollable.rs | 33 ++++----- crates/material_theme/src/slider.rs | 6 +- crates/material_theme/src/text.rs | 22 +++--- crates/material_theme/src/text_editor.rs | 38 +++------- crates/material_theme/src/text_input.rs | 38 +++------- crates/material_theme/src/toggler.rs | 28 +++---- crates/material_theme/src/utils.rs | 18 +++++ 20 files changed, 282 insertions(+), 309 deletions(-) diff --git a/crates/material_theme/src/button.rs b/crates/material_theme/src/button.rs index e1369eb..3f16bc7 100644 --- a/crates/material_theme/src/button.rs +++ b/crates/material_theme/src/button.rs @@ -3,8 +3,8 @@ use iced_widget::core::{Background, Border, Color, border}; use crate::Theme; use crate::utils::{ - DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, - PRESSED_LAYER_OPACITY, elevation, mix, shadow_from_elevation, + HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, disabled_container, + disabled_text, elevation, mix, shadow_from_elevation, }; impl Catalog for Theme { @@ -20,9 +20,8 @@ impl Catalog for Theme { } fn button( - foreground: Color, background: Color, - tone_overlay: Color, + foreground: Color, disabled: Color, shadow_color: Color, elevation_level: u8, @@ -40,7 +39,7 @@ fn button( Status::Pressed => Style { background: Some(Background::Color(mix( background, - tone_overlay, + foreground, HOVERED_LAYER_OPACITY, ))), ..active @@ -48,25 +47,18 @@ fn button( Status::Hovered => Style { background: Some(Background::Color(mix( background, - tone_overlay, + foreground, PRESSED_LAYER_OPACITY, ))), - text_color: foreground, - border: border::rounded(400), shadow: shadow_from_elevation( elevation(elevation_level + 1), shadow_color, ), + ..active }, Status::Disabled => Style { - background: Some(Background::Color(Color { - a: DISABLED_CONTAINER_OPACITY, - ..disabled - })), - text_color: Color { - a: DISABLED_TEXT_OPACITY, - ..disabled - }, + background: Some(Background::Color(disabled_container(disabled))), + text_color: disabled_text(disabled), border: border::rounded(400), ..Default::default() }, @@ -74,70 +66,46 @@ fn button( } pub fn elevated(theme: &Theme, status: Status) -> Style { - let surface_colors = theme.colorscheme.surface; + let surface = theme.colors().surface; - let foreground = theme.colorscheme.primary.color; - let background = surface_colors.surface_container.low; - let disabled = surface_colors.on_surface; + let foreground = theme.colors().primary.color; + let background = surface.surface_container.low; + let disabled = surface.on_surface; - let shadow_color = theme.colorscheme.shadow; + let shadow_color = theme.colors().shadow; - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 1, - status, - ) + button(background, foreground, disabled, shadow_color, 1, status) } pub fn filled(theme: &Theme, status: Status) -> Style { - let primary_colors = theme.colorscheme.primary; + let primary = theme.colors().primary; - let foreground = primary_colors.on_primary; - let background = primary_colors.color; - let disabled = theme.colorscheme.surface.on_surface; + let foreground = primary.on_primary; + let background = primary.color; + let disabled = theme.colors().surface.on_surface; - let shadow_color = theme.colorscheme.shadow; + let shadow_color = theme.colors().shadow; - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 0, - status, - ) + button(background, foreground, disabled, shadow_color, 0, status) } pub fn filled_tonal(theme: &Theme, status: Status) -> Style { - let secondary_colors = theme.colorscheme.secondary; + let secondary = theme.colors().secondary; - let foreground = secondary_colors.on_secondary_container; - let background = secondary_colors.secondary_container; - let disabled = theme.colorscheme.surface.on_surface; - let shadow_color = theme.colorscheme.shadow; + let foreground = secondary.on_secondary_container; + let background = secondary.secondary_container; + let disabled = theme.colors().surface.on_surface; + let shadow_color = theme.colors().shadow; - button( - foreground, - background, - foreground, - disabled, - shadow_color, - 0, - status, - ) + button(background, foreground, disabled, shadow_color, 0, status) } pub fn outlined(theme: &Theme, status: Status) -> Style { - let foreground = theme.colorscheme.primary.color; + let foreground = theme.colors().primary.color; let background = Color::TRANSPARENT; - let disabled = theme.colorscheme.surface.on_surface; + let disabled = theme.colors().surface.on_surface; - let outline = theme.colorscheme.outline.color; + let outline = theme.colors().outline.color; let border = match status { Status::Active | Status::Pressed | Status::Hovered => Border { @@ -146,17 +114,13 @@ pub fn outlined(theme: &Theme, status: Status) -> Style { radius: 400.into(), }, Status::Disabled => Border { - color: Color { - a: DISABLED_CONTAINER_OPACITY, - ..disabled - }, + color: disabled_container(disabled), width: 1.0, radius: 400.into(), }, }; let style = button( - foreground, background, foreground, disabled, @@ -169,12 +133,11 @@ pub fn outlined(theme: &Theme, status: Status) -> Style { } pub fn text(theme: &Theme, status: Status) -> Style { - let foreground = theme.colorscheme.primary.color; + let foreground = theme.colors().primary.color; let background = Color::TRANSPARENT; - let disabled = theme.colorscheme.surface.on_surface; + let disabled = theme.colors().surface.on_surface; let style = button( - foreground, background, foreground, disabled, @@ -185,7 +148,7 @@ pub fn text(theme: &Theme, status: Status) -> Style { match status { Status::Hovered | Status::Pressed => style, - _ => Style { + Status::Active | Status::Disabled => Style { background: None, ..style }, diff --git a/crates/material_theme/src/checkbox.rs b/crates/material_theme/src/checkbox.rs index ff038b0..7a3729c 100644 --- a/crates/material_theme/src/checkbox.rs +++ b/crates/material_theme/src/checkbox.rs @@ -2,7 +2,7 @@ use iced_widget::checkbox::{Catalog, Status, Style, StyleFn}; use iced_widget::core::{Background, Border, Color, border}; use super::Theme; -use crate::utils::{DISABLED_CONTAINER_OPACITY, HOVERED_LAYER_OPACITY, mix}; +use crate::utils::{HOVERED_LAYER_OPACITY, disabled_text, mix}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -45,8 +45,8 @@ pub fn styled( } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; match status { Status::Active { is_checked } => styled( @@ -69,16 +69,10 @@ pub fn default(theme: &Theme, status: Status) -> Style { is_checked, ), Status::Disabled { is_checked } => styled( - Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.on_surface - }, + disabled_text(surface.on_surface), None, surface.color, - Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.on_surface - }, + disabled_text(surface.on_surface), Some(surface.on_surface), is_checked, ), @@ -86,8 +80,8 @@ pub fn default(theme: &Theme, status: Status) -> Style { } pub fn error(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let error = theme.colorscheme.error; + let surface = theme.colors().surface; + let error = theme.colors().error; match status { Status::Active { is_checked } => styled( @@ -110,16 +104,10 @@ pub fn error(theme: &Theme, status: Status) -> Style { is_checked, ), Status::Disabled { is_checked } => styled( - Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.on_surface - }, + disabled_text(surface.on_surface), None, surface.color, - Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.on_surface - }, + disabled_text(surface.on_surface), Some(surface.on_surface), is_checked, ), diff --git a/crates/material_theme/src/container.rs b/crates/material_theme/src/container.rs index a14cfd5..5c253ad 100644 --- a/crates/material_theme/src/container.rs +++ b/crates/material_theme/src/container.rs @@ -1,5 +1,5 @@ use iced_widget::container::{Catalog, Style, StyleFn}; -use iced_widget::core::{Background, border}; +use iced_widget::core::{Background, Border, border}; use super::Theme; @@ -23,151 +23,178 @@ pub fn transparent(_theme: &Theme) -> Style { } pub fn primary(theme: &Theme) -> Style { - let colors = theme.colorscheme.primary; + let primary = theme.colors().primary; + Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_primary), + background: Some(Background::Color(primary.color)), + text_color: Some(primary.on_primary), border: border::rounded(4), ..Style::default() } } pub fn primary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.primary; + let primary = theme.colors().primary; + Style { - background: Some(Background::Color(colors.primary_container)), - text_color: Some(colors.on_primary_container), + background: Some(Background::Color(primary.primary_container)), + text_color: Some(primary.on_primary_container), border: border::rounded(8), ..Style::default() } } pub fn secondary(theme: &Theme) -> Style { - let colors = theme.colorscheme.secondary; + let secondary = theme.colors().secondary; + Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_secondary), + background: Some(Background::Color(secondary.color)), + text_color: Some(secondary.on_secondary), border: border::rounded(4), ..Style::default() } } pub fn secondary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.secondary; + let secondary = theme.colors().secondary; + Style { - background: Some(Background::Color(colors.secondary_container)), - text_color: Some(colors.on_secondary_container), + background: Some(Background::Color(secondary.secondary_container)), + text_color: Some(secondary.on_secondary_container), border: border::rounded(8), ..Style::default() } } pub fn tertiary(theme: &Theme) -> Style { - let colors = theme.colorscheme.tertiary; + let tertiary = theme.colors().tertiary; + Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_tertiary), + background: Some(Background::Color(tertiary.color)), + text_color: Some(tertiary.on_tertiary), border: border::rounded(4), ..Style::default() } } pub fn tertiary_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.tertiary; + let tertiary = theme.colors().tertiary; + Style { - background: Some(Background::Color(colors.tertiary_container)), - text_color: Some(colors.on_tertiary_container), + background: Some(Background::Color(tertiary.tertiary_container)), + text_color: Some(tertiary.on_tertiary_container), border: border::rounded(8), ..Style::default() } } pub fn error(theme: &Theme) -> Style { - let colors = theme.colorscheme.error; + let error = theme.colors().error; + Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_error), + background: Some(Background::Color(error.color)), + text_color: Some(error.on_error), border: border::rounded(4), ..Style::default() } } pub fn error_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.error; + let error = theme.colors().error; + Style { - background: Some(Background::Color(colors.error_container)), - text_color: Some(colors.on_error_container), + background: Some(Background::Color(error.error_container)), + text_color: Some(error.on_error_container), border: border::rounded(8), ..Style::default() } } pub fn surface(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.color)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.color)), + text_color: Some(surface.on_surface), border: border::rounded(4), ..Style::default() } } pub fn surface_container_lowest(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.surface_container.lowest)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.surface_container.lowest)), + text_color: Some(surface.on_surface), border: border::rounded(8), ..Style::default() } } pub fn surface_container_low(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.surface_container.low)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.surface_container.low)), + text_color: Some(surface.on_surface), border: border::rounded(8), ..Style::default() } } pub fn surface_container(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.surface_container.base)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.surface_container.base)), + text_color: Some(surface.on_surface), border: border::rounded(8), ..Style::default() } } pub fn surface_container_high(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.surface_container.high)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.surface_container.high)), + text_color: Some(surface.on_surface), border: border::rounded(8), ..Style::default() } } pub fn surface_container_highest(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; + Style { - background: Some(Background::Color(colors.surface_container.highest)), - text_color: Some(colors.on_surface), + background: Some(Background::Color(surface.surface_container.highest)), + text_color: Some(surface.on_surface), border: border::rounded(8), ..Style::default() } } pub fn inverse_surface(theme: &Theme) -> Style { - let colors = theme.colorscheme.inverse; + let inverse = theme.colors().inverse; + Style { - background: Some(Background::Color(colors.inverse_surface)), - text_color: Some(colors.inverse_on_surface), + background: Some(Background::Color(inverse.inverse_surface)), + text_color: Some(inverse.inverse_on_surface), border: border::rounded(4), ..Style::default() } } + +pub fn outlined(theme: &Theme) -> Style { + let base = transparent(theme); + + Style { + border: Border { + color: theme.colors().outline.color, + ..base.border + }, + ..base + } +} diff --git a/crates/material_theme/src/dialog.rs b/crates/material_theme/src/dialog.rs index a022548..c839948 100644 --- a/crates/material_theme/src/dialog.rs +++ b/crates/material_theme/src/dialog.rs @@ -25,7 +25,7 @@ impl Catalog for Theme { } pub fn default_container(theme: &Theme) -> container::Style { - let colors = theme.colorscheme.surface; + let colors = theme.colors().surface; container::Style { background: Some(Background::Color(colors.surface_container.high)), text_color: Some(colors.on_surface_variant), @@ -36,6 +36,6 @@ pub fn default_container(theme: &Theme) -> container::Style { pub fn default(theme: &Theme) -> Style { Style { - backdrop_color: theme.colorscheme.scrim, + backdrop_color: theme.colors().scrim, } } diff --git a/crates/material_theme/src/image.rs b/crates/material_theme/src/image.rs index de5942a..4251b39 100644 --- a/crates/material_theme/src/image.rs +++ b/crates/material_theme/src/image.rs @@ -1,21 +1,15 @@ -use iced_widget::core::{Background, Border, Color, border}; use iced_widget::image::{Catalog, Style, StyleFn}; use super::Theme; -use crate::utils::{elevation, shadow_from_elevation}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; fn default<'a>() -> Self::Class<'a> { - Box::new(default) + Box::new(|_theme| Style::default()) } fn style(&self, class: &Self::Class<'_>) -> Style { class(self) } } - -pub fn default(_theme: &Theme) -> Style { - Style::default() -} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 1b4f90e..7b6ac58 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -2,6 +2,7 @@ use std::sync::LazyLock; use iced_widget::core::Color; use iced_widget::core::theme::{Base, Style}; +use utils::{lightness, mix}; pub mod button; pub mod checkbox; @@ -45,31 +46,47 @@ macro_rules! from_argb { }}; } -#[derive(Debug, Clone, Copy, PartialEq)] +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct Theme { - pub name: &'static str, - #[cfg_attr(feature = "serde", serde(flatten))] - pub colorscheme: ColorScheme, +pub enum Theme { + Dark, + Light, + Custom(Custom), } impl Theme { - pub const ALL: &'static [Self] = &[Self::DARK, Self::LIGHT]; - - pub const DARK: Self = Self { - name: "Dark", - colorscheme: ColorScheme::DARK, - }; - - pub const LIGHT: Self = Self { - name: "Light", - colorscheme: ColorScheme::LIGHT, - }; + pub const ALL: &'static [Self] = &[Self::Dark, Self::Light]; pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { - Self { - name: Box::leak(name.into().into_boxed_str()), + Self::Custom(Custom { + name: name.into(), colorscheme, + is_dark: lightness(colorscheme.surface.color) <= 0.5, + }) + } + + pub fn name(&self) -> &str { + match self { + Self::Dark => "Dark", + Self::Light => "Light", + Self::Custom(custom) => &custom.name, + } + } + + pub fn colors(&self) -> ColorScheme { + match self { + Self::Dark => ColorScheme::DARK, + Self::Light => ColorScheme::LIGHT, + Self::Custom(custom) => custom.colorscheme, + } + } + + pub fn is_dark(&self) -> bool { + match self { + Self::Dark => true, + Self::Light => false, + Self::Custom(custom) => custom.is_dark, } } } @@ -80,43 +97,39 @@ impl Default for Theme { match dark_light::detect().unwrap_or(dark_light::Mode::Unspecified) { dark_light::Mode::Dark | dark_light::Mode::Unspecified => { - Theme::DARK + Theme::Dark } - dark_light::Mode::Light => Theme::LIGHT, + dark_light::Mode::Light => Theme::Light, } }); - *DEFAULT + DEFAULT.clone() } } impl std::fmt::Display for Theme { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name) + write!(f, "{}", self.name()) } } impl Base for Theme { fn base(&self) -> Style { Style { - background_color: self.colorscheme.surface.color, - text_color: self.colorscheme.surface.on_surface, + background_color: self.colors().surface.color, + text_color: self.colors().surface.on_surface, } } fn palette(&self) -> Option { - let colors = self.colorscheme; + let colors = self.colors(); Some(iced_widget::theme::Palette { background: colors.surface.color, text: colors.surface.on_surface, primary: colors.primary.color, success: colors.primary.primary_container, - warning: utils::mix( - from_argb!(0xffffff00), - colors.primary.color, - 0.25, - ), + warning: mix(from_argb!(0xffffff00), colors.primary.color, 0.25), danger: colors.error.color, }) } @@ -129,18 +142,44 @@ impl iced_anim::Animate for Theme { } fn update(&mut self, components: &mut impl Iterator) { - self.colorscheme.update(components); - self.name = "Animating Theme"; + let mut colorscheme = self.colors(); + colorscheme.update(components); + *self = Self::new("Animating Theme", colorscheme); } fn distance_to(&self, end: &Self) -> Vec { - self.colorscheme.distance_to(&end.colorscheme) + self.colors().distance_to(&end.colors()) } fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { - self.colorscheme - .lerp(&start.colorscheme, &end.colorscheme, progress); - self.name = "Animating Theme"; + let mut colorscheme = self.colors(); + colorscheme.lerp(&start.colors(), &end.colors(), progress); + *self = Self::new("Animating Theme", colorscheme); + } +} + +#[derive(Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Custom { + pub name: String, + #[cfg_attr(feature = "serde", serde(flatten))] + pub colorscheme: ColorScheme, + pub is_dark: bool, +} + +impl Clone for Custom { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + colorscheme: self.colorscheme, + is_dark: self.is_dark, + } + } + + fn clone_from(&mut self, source: &Self) { + self.name.clone_from(&source.name); + self.colorscheme = source.colorscheme; + self.is_dark = source.is_dark; } } diff --git a/crates/material_theme/src/menu.rs b/crates/material_theme/src/menu.rs index 9f43c72..d595c2f 100644 --- a/crates/material_theme/src/menu.rs +++ b/crates/material_theme/src/menu.rs @@ -17,7 +17,7 @@ impl Catalog for Theme { } pub fn default(theme: &Theme) -> Style { - let colors = theme.colorscheme.surface; + let colors = theme.colors().surface; Style { border: border::rounded(4), diff --git a/crates/material_theme/src/pane_grid.rs b/crates/material_theme/src/pane_grid.rs index d66e475..fb69a32 100644 --- a/crates/material_theme/src/pane_grid.rs +++ b/crates/material_theme/src/pane_grid.rs @@ -20,18 +20,18 @@ pub fn default(theme: &Theme) -> Style { Style { hovered_region: Highlight { background: Background::Color(mix( - theme.colorscheme.tertiary.tertiary_container, - theme.colorscheme.surface.on_surface, + theme.colors().tertiary.tertiary_container, + theme.colors().surface.on_surface, HOVERED_LAYER_OPACITY, )), border: border::rounded(12), }, picked_split: Line { - color: theme.colorscheme.outline.variant, + color: theme.colors().outline.variant, width: 2.0, }, hovered_split: Line { - color: theme.colorscheme.surface.on_surface, + color: theme.colors().surface.on_surface, width: 6.0, }, } diff --git a/crates/material_theme/src/pick_list.rs b/crates/material_theme/src/pick_list.rs index 4b34871..1fe015e 100644 --- a/crates/material_theme/src/pick_list.rs +++ b/crates/material_theme/src/pick_list.rs @@ -20,7 +20,7 @@ impl Catalog for Theme { } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; + let surface = theme.colors().surface; let active = Style { text_color: surface.on_surface, diff --git a/crates/material_theme/src/progress_bar.rs b/crates/material_theme/src/progress_bar.rs index f686fff..9b4e844 100644 --- a/crates/material_theme/src/progress_bar.rs +++ b/crates/material_theme/src/progress_bar.rs @@ -18,9 +18,9 @@ impl Catalog for Theme { pub fn default(theme: &Theme) -> Style { Style { background: Background::Color( - theme.colorscheme.secondary.secondary_container, + theme.colors().secondary.secondary_container, ), - bar: Background::Color(theme.colorscheme.primary.color), + bar: Background::Color(theme.colors().primary.color), border: border::rounded(400), } } diff --git a/crates/material_theme/src/qr_code.rs b/crates/material_theme/src/qr_code.rs index f93fb77..f603440 100644 --- a/crates/material_theme/src/qr_code.rs +++ b/crates/material_theme/src/qr_code.rs @@ -15,7 +15,7 @@ impl Catalog for Theme { } pub fn default(theme: &Theme) -> Style { - let surface = theme.colorscheme.surface; + let surface = theme.colors().surface; Style { cell: surface.on_surface, diff --git a/crates/material_theme/src/radio.rs b/crates/material_theme/src/radio.rs index d249413..7fb7a3f 100644 --- a/crates/material_theme/src/radio.rs +++ b/crates/material_theme/src/radio.rs @@ -2,7 +2,7 @@ use iced_widget::core::{Background, Color}; use iced_widget::radio::{Catalog, Status, Style, StyleFn}; use super::Theme; -use crate::utils::{DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, mix}; +use crate::utils::{HOVERED_LAYER_OPACITY, disabled_text, mix}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -17,8 +17,8 @@ impl Catalog for Theme { } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; let active = Style { background: Color::TRANSPARENT.into(), @@ -46,10 +46,7 @@ pub fn default(theme: &Theme, status: Status) -> Style { border_color: if is_selected { mix(primary.color, surface.on_surface, HOVERED_LAYER_OPACITY) } else { - Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - } + disabled_text(surface.on_surface) }, background: Background::Color(if is_selected { Color { diff --git a/crates/material_theme/src/rule.rs b/crates/material_theme/src/rule.rs index e433005..36e4dd4 100644 --- a/crates/material_theme/src/rule.rs +++ b/crates/material_theme/src/rule.rs @@ -17,7 +17,7 @@ impl Catalog for Theme { pub fn inset(theme: &Theme) -> Style { Style { - color: theme.colorscheme.outline.variant, + color: theme.colors().outline.variant, fill_mode: FillMode::Padded(8), width: 1, radius: Radius::default(), @@ -25,7 +25,7 @@ pub fn inset(theme: &Theme) -> Style { } pub fn full_width(theme: &Theme) -> Style { Style { - color: theme.colorscheme.outline.variant, + color: theme.colors().outline.variant, fill_mode: FillMode::Full, width: 1, radius: Radius::default(), diff --git a/crates/material_theme/src/scrollable.rs b/crates/material_theme/src/scrollable.rs index ee739ba..341f047 100644 --- a/crates/material_theme/src/scrollable.rs +++ b/crates/material_theme/src/scrollable.rs @@ -1,4 +1,4 @@ -use iced_widget::core::{Border, Color, border}; +use iced_widget::core::{Background, Border, border}; use iced_widget::scrollable::{ Catalog, Rail, Scroller, Status, Style, StyleFn, }; @@ -7,8 +7,8 @@ use super::Theme; use super::container::surface_container; use super::utils::mix; use crate::utils::{ - DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, - PRESSED_LAYER_OPACITY, + HOVERED_LAYER_OPACITY, PRESSED_LAYER_OPACITY, disabled_container, + disabled_text, }; impl Catalog for Theme { @@ -24,30 +24,23 @@ impl Catalog for Theme { } pub fn default(theme: &Theme, status: Status) -> Style { - let colors = theme.colorscheme.surface; + let surface = theme.colors().surface; let active = Rail { background: None, scroller: Scroller { - color: colors.on_surface, + color: surface.on_surface, border: border::rounded(400), }, border: Border::default(), }; let disabled = Rail { - background: Some( - Color { - a: DISABLED_CONTAINER_OPACITY, - ..colors.on_surface - } - .into(), - ), + background: Some(Background::Color(disabled_container( + surface.on_surface, + ))), scroller: Scroller { - color: Color { - a: DISABLED_TEXT_OPACITY, - ..colors.on_surface - }, + color: disabled_text(surface.on_surface), border: border::rounded(400), }, ..active @@ -86,8 +79,8 @@ pub fn default(theme: &Theme, status: Status) -> Style { let hovered_rail = Rail { scroller: Scroller { color: mix( - colors.on_surface, - colors.color, + surface.on_surface, + surface.color, HOVERED_LAYER_OPACITY, ), border: border::rounded(400), @@ -122,8 +115,8 @@ pub fn default(theme: &Theme, status: Status) -> Style { let dragged_rail = Rail { scroller: Scroller { color: mix( - colors.on_surface, - colors.color, + surface.on_surface, + surface.color, PRESSED_LAYER_OPACITY, ), border: border::rounded(400), diff --git a/crates/material_theme/src/slider.rs b/crates/material_theme/src/slider.rs index 8665459..ae9ee4b 100644 --- a/crates/material_theme/src/slider.rs +++ b/crates/material_theme/src/slider.rs @@ -41,9 +41,9 @@ pub fn styled(left: Color, right: Color, handle_radius: f32) -> Style { } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; - let secondary = theme.colorscheme.secondary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; + let secondary = theme.colors().secondary; match status { Status::Active => { diff --git a/crates/material_theme/src/text.rs b/crates/material_theme/src/text.rs index 10b2e65..8da3cdf 100644 --- a/crates/material_theme/src/text.rs +++ b/crates/material_theme/src/text.rs @@ -21,66 +21,66 @@ pub fn none(_: &Theme) -> Style { pub fn primary(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.primary.on_primary), + color: Some(theme.colors().primary.on_primary), } } pub fn primary_container(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.primary.on_primary_container), + color: Some(theme.colors().primary.on_primary_container), } } pub fn secondary(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.secondary.on_secondary), + color: Some(theme.colors().secondary.on_secondary), } } pub fn secondary_container(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.secondary.on_secondary_container), + color: Some(theme.colors().secondary.on_secondary_container), } } pub fn tertiary(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.tertiary.on_tertiary), + color: Some(theme.colors().tertiary.on_tertiary), } } pub fn tertiary_container(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.tertiary.on_tertiary_container), + color: Some(theme.colors().tertiary.on_tertiary_container), } } pub fn error(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.error.on_error), + color: Some(theme.colors().error.on_error), } } pub fn error_container(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.error.on_error_container), + color: Some(theme.colors().error.on_error_container), } } pub fn surface(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.surface.on_surface), + color: Some(theme.colors().surface.on_surface), } } pub fn surface_variant(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.surface.on_surface_variant), + color: Some(theme.colors().surface.on_surface_variant), } } pub fn inverse_surface(theme: &Theme) -> Style { Style { - color: Some(theme.colorscheme.inverse.inverse_on_surface), + color: Some(theme.colors().inverse.inverse_on_surface), } } diff --git a/crates/material_theme/src/text_editor.rs b/crates/material_theme/src/text_editor.rs index daad7d2..14d7104 100644 --- a/crates/material_theme/src/text_editor.rs +++ b/crates/material_theme/src/text_editor.rs @@ -2,7 +2,7 @@ use iced_widget::core::{Background, Border, Color, border}; use iced_widget::text_editor::{Catalog, Status, Style, StyleFn}; use super::Theme; -use crate::utils::DISABLED_TEXT_OPACITY; +use crate::utils::{disabled_container, disabled_text}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -17,23 +17,20 @@ impl Catalog for Theme { } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; let active = Style { background: Background::Color(surface.surface_container.highest), border: Border { - color: theme.colorscheme.outline.color, + color: theme.colors().outline.color, width: 1.0, radius: 4.into(), }, icon: surface.on_surface_variant, placeholder: surface.on_surface_variant, value: surface.on_surface, - selection: Color { - a: DISABLED_TEXT_OPACITY, - ..primary.color - }, + selection: disabled_text(primary.color), }; match status { @@ -57,29 +54,14 @@ pub fn default(theme: &Theme, status: Status) -> Style { Status::Disabled => Style { background: Color::TRANSPARENT.into(), border: Border { - color: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, + color: disabled_container(surface.on_surface), width: 1.0, radius: border::radius(4), }, - icon: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - placeholder: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - selection: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - value: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, + icon: disabled_text(surface.on_surface), + placeholder: disabled_text(surface.on_surface), + value: disabled_text(surface.on_surface), + selection: disabled_text(surface.on_surface), }, } } diff --git a/crates/material_theme/src/text_input.rs b/crates/material_theme/src/text_input.rs index 5de5993..ed5e02a 100644 --- a/crates/material_theme/src/text_input.rs +++ b/crates/material_theme/src/text_input.rs @@ -2,7 +2,7 @@ use iced_widget::core::{Background, Border, Color}; use iced_widget::text_input::{Catalog, Status, Style, StyleFn}; use super::Theme; -use crate::utils::{DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY}; +use crate::utils::{disabled_container, disabled_text}; impl Catalog for Theme { type Class<'a> = StyleFn<'a, Self>; @@ -17,23 +17,20 @@ impl Catalog for Theme { } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; let active = Style { background: Background::Color(surface.surface_container.highest), border: Border { - color: theme.colorscheme.outline.color, + color: theme.colors().outline.color, width: 1.0, radius: 4.into(), }, icon: surface.on_surface_variant, placeholder: surface.on_surface_variant, value: surface.on_surface, - selection: Color { - a: DISABLED_TEXT_OPACITY, - ..primary.color - }, + selection: disabled_text(primary.color), }; match status { @@ -48,28 +45,13 @@ pub fn default(theme: &Theme, status: Status) -> Style { Status::Disabled => Style { background: Color::TRANSPARENT.into(), border: Border { - color: Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.on_surface - }, + color: disabled_container(surface.on_surface), ..active.border }, - icon: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - placeholder: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - value: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - selection: Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, + icon: disabled_text(surface.on_surface), + placeholder: disabled_text(surface.on_surface), + value: disabled_text(surface.on_surface), + selection: disabled_text(surface.on_surface), }, Status::Focused { .. } => Style { border: Border { diff --git a/crates/material_theme/src/toggler.rs b/crates/material_theme/src/toggler.rs index 8949d07..5cebc88 100644 --- a/crates/material_theme/src/toggler.rs +++ b/crates/material_theme/src/toggler.rs @@ -3,8 +3,7 @@ use iced_widget::toggler::{Catalog, Status, Style, StyleFn}; use super::Theme; use crate::utils::{ - DISABLED_CONTAINER_OPACITY, DISABLED_TEXT_OPACITY, HOVERED_LAYER_OPACITY, - mix, + HOVERED_LAYER_OPACITY, disabled_container, disabled_text, mix, }; impl Catalog for Theme { @@ -35,8 +34,8 @@ pub fn styled( } pub fn default(theme: &Theme, status: Status) -> Style { - let surface = theme.colorscheme.surface; - let primary = theme.colorscheme.primary; + let surface = theme.colors().surface; + let primary = theme.colors().primary; match status { Status::Active { is_toggled } => { @@ -45,8 +44,8 @@ pub fn default(theme: &Theme, status: Status) -> Style { } else { styled( surface.surface_container.highest, - theme.colorscheme.outline.color, - Some(theme.colorscheme.outline.color), + theme.colors().outline.color, + Some(theme.colors().outline.color), ) } } @@ -61,23 +60,14 @@ pub fn default(theme: &Theme, status: Status) -> Style { HOVERED_LAYER_OPACITY, ), surface.on_surface_variant, - Some(theme.colorscheme.outline.color), + Some(theme.colors().outline.color), ) } } Status::Disabled => styled( - Color { - a: DISABLED_CONTAINER_OPACITY, - ..surface.surface_container.highest - }, - Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }, - Some(Color { - a: DISABLED_TEXT_OPACITY, - ..surface.on_surface - }), + disabled_container(surface.surface_container.highest), + disabled_text(surface.on_surface), + Some(disabled_text(surface.on_surface)), ), } } diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs index 5ad137e..963c9fc 100644 --- a/crates/material_theme/src/utils.rs +++ b/crates/material_theme/src/utils.rs @@ -30,6 +30,20 @@ pub fn shadow_from_elevation(elevation: f32, color: Color) -> Shadow { } } +pub fn disabled_text(color: Color) -> Color { + Color { + a: DISABLED_TEXT_OPACITY, + ..color + } +} + +pub fn disabled_container(color: Color) -> Color { + Color { + a: DISABLED_CONTAINER_OPACITY, + ..color + } +} + pub fn parse_argb(s: &str) -> Option { let hex = s.strip_prefix('#').unwrap_or(s); @@ -88,6 +102,10 @@ pub fn color_to_argb(color: Color) -> String { hex } +pub const fn lightness(color: Color) -> f32 { + color.r * 0.299 + color.g * 0.587 + color.b * 0.114 +} + pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { if p2 <= 0.0 { return color1; -- cgit v1.2.3 From 9dfb469d1ba975e59f39f3bb799b019204315784 Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 28 Apr 2025 10:57:42 +0200 Subject: feat: switch to modified `iced_fontello` for custom Theme support --- Cargo.lock | 10 +- Cargo.toml | 8 +- crates/iced_fontello/.gitignore | 2 + crates/iced_fontello/Cargo.toml | 18 ++ crates/iced_fontello/README.md | 109 +++++++++++ crates/iced_fontello/src/lib.rs | 394 ++++++++++++++++++++++++++++++++++++++++ src/icon.rs | 4 +- 7 files changed, 534 insertions(+), 11 deletions(-) create mode 100644 crates/iced_fontello/.gitignore create mode 100644 crates/iced_fontello/Cargo.toml create mode 100644 crates/iced_fontello/README.md create mode 100644 crates/iced_fontello/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9154eb4..02b475d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2082,8 +2082,6 @@ dependencies = [ [[package]] name = "iced_fontello" version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1088f296a44a5c7e51ae5e533954429bfa479d44b304cb7c370480994abab7ef" dependencies = [ "reqwest", "serde", @@ -3737,9 +3735,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.37.4" +version = "0.37.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" dependencies = [ "memchr", ] @@ -4619,9 +4617,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0a7d769..9ffaa5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ iced_anim.workspace = true iced_custom_highlighter = { git = "https://github.com/pml68/iced_custom_highlighter", branch = "master" } iced_drop = { path = "crates/iced_drop" } iced_dialog.workspace = true -material_theme = { path = "crates/material_theme" } +material_theme = { path = "crates/material_theme", features = ["animate", "serde", "dialog", "image", "svg"] } serde.workspace = true serde_json = "1.0.140" toml.workspace = true @@ -38,16 +38,16 @@ dirs-next = "2.0.0" iced_anim = { version = "0.2.1", features = ["derive"] } iced_dialog = { git = "https://github.com/pml68/iced_dialog", branch = "iced/personal" } serde = { version = "1.0.219", features = ["derive"] } -toml = "0.8.20" +toml = "0.8.21" [workspace.dependencies.iced] git = "https://github.com/pml68/iced" branch = "feat/rehighlight-on-redraw" default-features = false -features = ["wgpu", "tiny-skia", "web-colors", "auto-detect-theme", "image", "svg", "advanced", "tokio", "lazy"] +features = ["wgpu", "tiny-skia", "web-colors", "auto-detect-theme", "advanced", "tokio", "image", "svg", "lazy"] [build-dependencies] -iced_fontello = "0.13.2" +iced_fontello = { path = "crates/iced_fontello" } [target.'cfg(target_os = "macos")'.dependencies] xdg = "2.5.2" diff --git a/crates/iced_fontello/.gitignore b/crates/iced_fontello/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/crates/iced_fontello/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/crates/iced_fontello/Cargo.toml b/crates/iced_fontello/Cargo.toml new file mode 100644 index 0000000..8c170a1 --- /dev/null +++ b/crates/iced_fontello/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "iced_fontello" +version = "0.13.2" +edition = "2021" +description = "Generate type-safe icon fonts for `iced` at compile time" +repository = "https://github.com/hecrj/iced_fontello" +license = "MIT" +categories = ["gui"] +keywords = ["gui", "ui", "graphics", "interface", "widgets"] +rust-version = "1.85" + +[dependencies] +reqwest = { version = "0.12", features = ["blocking", "json", "multipart"] } +sha2 = "0.10" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +toml = "0.8" +zip = "2" diff --git a/crates/iced_fontello/README.md b/crates/iced_fontello/README.md new file mode 100644 index 0000000..52a59c1 --- /dev/null +++ b/crates/iced_fontello/README.md @@ -0,0 +1,109 @@ +
+ +# iced_fontello + +[![Documentation](https://docs.rs/iced_fontello/badge.svg)](https://docs.rs/iced_fontello) +[![Crates.io](https://img.shields.io/crates/v/iced_fontello.svg)](https://crates.io/crates/iced_fontello) +[![License](https://img.shields.io/crates/l/iced_fontello.svg)](https://github.com/hecrj/iced_fontello/blob/master/LICENSE) +[![Downloads](https://img.shields.io/crates/d/iced_fontello.svg)](https://crates.io/crates/iced_fontello) +[![Test Status](https://img.shields.io/github/actions/workflow/status/hecrj/iced_fontello/test.yml?branch=master&event=push&label=test)](https://github.com/hecrj/iced_fontello/actions) +[![Discourse](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscourse.iced.rs%2Fsite%2Fstatistics.json&query=%24.users_count&suffix=%20users&label=discourse&color=5e7ce2)](https://discourse.iced.rs/) +[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd) + +A compile-time, type-safe icon font generator for [`iced`]. +Powered by [Fontello]. + +[`iced`]: https://github.com/iced-rs/iced +[Fontello]: https://github.com/fontello/fontello + +
+ +## Usage +Create a `.toml` file somewhere in your crate with the font definition: + +```toml +# fonts/example-icons.toml +module = "icon" + +[glyphs] +edit = "fontawesome-pencil" +save = "entypo-floppy" +trash = "typicons-trash" +``` + +The `module` value defines the Rust module that will be generated in your `src` +directory containing a type-safe API to use the font. + +Each entry in the `[glyphs]` section corresponds to an icon. The keys will be +used as names for the functions of the module of the font; while the values +specify the glyph for that key using the format: `-`. You can browse +the available glyphs in [Fontello] or [the `fonts.json` file](fonts.json). + +Next, add `iced_fontello` to your `build-dependencies`: + +```rust +[build-dependencies] +iced_fontello = "0.13" +``` + +Then, call `iced_fontello::build` in your [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html), +passing the path of your font definition: + +```rust +pub fn main() { + println!("cargo::rerun-if-changed=fonts/example-icons.toml"); + iced_fontello::build("fonts/example-icons.toml").expect("Build example-icons font"); +} +``` + +The library will generate the font and save its `.ttf` file right next to its definition. +In this example, the library would generate `fonts/example-icons.ttf`. + +Finally, it will generate a type-safe `iced` API that lets you use the font. In our example: + +```rust +// Generated automatically by iced_fontello at build time. +// Do not edit manually. +// d24460a00249b2acd0ccc64c3176452c546ad12d1038974e974d7bdb4cdb4a8f +use iced::widget::{text, Text}; +use iced::Font; + +pub const FONT: &[u8] = include_bytes!("../fonts/example-icons.ttf"); + +pub fn edit<'a>() -> Text<'a> { + icon("\u{270E}") +} + +pub fn save<'a>() -> Text<'a> { + icon("\u{1F4BE}") +} + +pub fn trash<'a>() -> Text<'a> { + icon("\u{E10A}") +} + +fn icon<'a>(codepoint: &'a str) -> Text<'a> { + text(codepoint).font(Font::with_name("example-icons")) +} +``` + +Now you can simply add `mod icon;` to your `lib.rs` or `main.rs` file and enjoy your new font: + +```rust +mod icon; + +use iced::widget::row; + +// ... + +row![icon::edit(), icon::save(), icon::trash()].spacing(10) + +// ... +``` + +Check out [the full example](example) to see it all in action. + +## Packaging +If you plan to package your crate, you must make sure you include the generated module +and font file in the final package. `build` is effectively a no-op when the module and +the font already exist and are up-to-date. diff --git a/crates/iced_fontello/src/lib.rs b/crates/iced_fontello/src/lib.rs new file mode 100644 index 0000000..2b39647 --- /dev/null +++ b/crates/iced_fontello/src/lib.rs @@ -0,0 +1,394 @@ +#![allow(clippy::needless_doctest_main)] +//! A compile-time, type-safe icon font generator for [`iced`]. +//! Powered by [Fontello]. +//! +//! [`iced`]: https://github.com/iced-rs/iced +//! [Fontello]: https://github.com/fontello/fontello +//! +//! # Usage +//! Create a `.toml` file somewhere in your crate with the font definition: +//! +//! ```toml +//! # fonts/example-icons.toml +//! module = "icon" +//! +//! [glyphs] +//! edit = "fontawesome-pencil" +//! save = "entypo-floppy" +//! trash = "typicons-trash" +//! ``` +//! +//! The `module` value defines the Rust module that will be generated in your `src` +//! directory containing a type-safe API to use the font. +//! +//! Each entry in the `[glyphs]` section corresponds to an icon. The keys will be +//! used as names for the functions of the module of the font; while the values +//! specify the glyph for that key using the format: `-`. You can browse +//! the available glyphs in [Fontello] or [the `fonts.json` file](fonts.json). +//! +//! Next, add `iced_fontello` to your `build-dependencies`: +//! +//! ```toml +//! [build-dependencies] +//! iced_fontello = "0.13" +//! ``` +//! +//! Then, call `iced_fontello::build` in your [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html), +//! passing the path of your font definition: +//! +//! ```rust,no_run +//! pub fn main() { +//! println!("cargo::rerun-if-changed=fonts/example-icons.toml"); +//! iced_fontello::build("fonts/example-icons.toml").expect("Build example-icons font"); +//! } +//! ``` +//! +//! The library will generate the font and save its `.ttf` file right next to its definition. +//! In this example, the library would generate `fonts/example-icons.ttf`. +//! +//! Finally, it will generate a type-safe `iced` API that lets you use the font. In our example: +//! +//! ```rust,ignore +//! // Generated automatically by iced_fontello at build time. +//! // Do not edit manually. +//! // d24460a00249b2acd0ccc64c3176452c546ad12d1038974e974d7bdb4cdb4a8f +//! use iced::widget::{text, Text}; +//! use iced::Font; +//! +//! pub const FONT: &[u8] = include_bytes!("../fonts/example-icons.ttf"); +//! +//! pub fn edit<'a>() -> Text<'a> { +//! icon("\u{270E}") +//! } +//! +//! pub fn save<'a>() -> Text<'a> { +//! icon("\u{1F4BE}") +//! } +//! +//! pub fn trash<'a>() -> Text<'a> { +//! icon("\u{E10A}") +//! } +//! +//! fn icon<'a>(codepoint: &'a str) -> Text<'a> { +//! text(codepoint).font(Font::with_name("example-icons")) +//! } +//! ``` +//! +//! Now you can simply add `mod icon;` to your `lib.rs` or `main.rs` file and enjoy your new font: +//! +//! ```rust,ignore +//! mod icon; +//! +//! use iced::widget::row; +//! +//! // ... +//! +//! row![icon::edit(), icon::save(), icon::trash()].spacing(10) +//! +//! // ... +//! ``` +//! +//! Check out [the full example](example) to see it all in action. +//! +//! # Packaging +//! If you plan to package your crate, you must make sure you include the generated module +//! and font file in the final package. `build` is effectively a no-op when the module and +//! the font already exist and are up-to-date. +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::{fs, io}; + +use reqwest::blocking as reqwest; +use serde::{Deserialize, Serialize}; + +pub fn build(path: impl AsRef) -> Result<(), Error> { + let path = path.as_ref(); + + let definition: Definition = { + let contents = fs::read_to_string(path).unwrap_or_else(|error| { + panic!( + "Font definition {path} could not be read: {error}", + path = path.display() + ) + }); + + toml::from_str(&contents).unwrap_or_else(|error| { + panic!( + "Font definition {path} is invalid: {error}", + path = path.display() + ) + }) + }; + + let fonts = parse_fonts(); + + let glyphs: BTreeMap = definition + .glyphs + .into_iter() + .map(|(name, id)| { + let Some((font_name, glyph)) = id.split_once('-') else { + panic!( + "Invalid glyph identifier: \"{id}\"\n\ + Glyph identifier must have \"-\" format" + ) + }; + + let Some(font) = fonts.get(font_name) else { + panic!( + "Font \"{font_name}\" was not found. Available fonts are:\n{}", + fonts + .keys() + .map(|name| format!("- {name}")) + .collect::>() + .join("\n") + ); + }; + + let Some(glyph) = font.glyphs.get(glyph) else { + // TODO: Display similarly named candidates + panic!( + "Glyph \"{glyph}\" was not found. Available glyphs are:\n{}", + font.glyphs + .keys() + .map(|name| format!("- {name}")) + .collect::>() + .join("\n") + ); + }; + + ( + name, + ChosenGlyph { + uid: glyph.uid.clone(), + css: glyph.name.clone(), + code: glyph.code, + src: font.name.clone(), + }, + ) + }) + .collect(); + + #[derive(Serialize)] + struct Config { + name: String, + css_prefix_text: &'static str, + css_use_suffix: bool, + hinting: bool, + units_per_em: u32, + ascent: u32, + glyphs: Vec, + } + + #[derive(Clone, Serialize)] + struct ChosenGlyph { + uid: Id, + css: String, + code: u64, + src: String, + } + + let file_name = path + .file_stem() + .expect("Get file stem from definition path") + .to_string_lossy() + .into_owned(); + + let config = Config { + name: file_name.clone(), + css_prefix_text: "icon-", + css_use_suffix: false, + hinting: true, + units_per_em: 1000, + ascent: 850, + glyphs: glyphs.values().cloned().collect(), + }; + + let hash = { + use sha2::Digest as _; + + let mut hasher = sha2::Sha256::new(); + hasher.update( + serde_json::to_string(&config).expect("Serialize config as JSON"), + ); + + format!("{:x}", hasher.finalize()) + }; + + let module_target = PathBuf::new() + .join("src") + .join(definition.module.replace("::", "/")) + .with_extension("rs"); + + let module_contents = + fs::read_to_string(&module_target).unwrap_or_default(); + let module_hash = module_contents + .lines() + .nth(2) + .unwrap_or_default() + .trim_start_matches("// "); + + if hash != module_hash || !path.with_extension("ttf").exists() { + let client = reqwest::Client::new(); + let session = client + .post("https://fontello.com/") + .multipart( + reqwest::multipart::Form::new().part( + "config", + reqwest::multipart::Part::text( + serde_json::to_string(&config) + .expect("Serialize Fontello config"), + ) + .file_name("config.json"), + ), + ) + .send() + .and_then(reqwest::Response::error_for_status) + .and_then(reqwest::Response::text) + .expect("Create Fontello session"); + + let font = client + .get(format!("https://fontello.com/{session}/get")) + .send() + .and_then(reqwest::Response::error_for_status) + .and_then(reqwest::Response::bytes) + .expect("Download Fontello font"); + + let mut archive = zip::ZipArchive::new(io::Cursor::new(font)) + .expect("Parse compressed font"); + + let mut font_file = (0..archive.len()) + .find(|i| { + let file = + archive.by_index(*i).expect("Access zip archive by index"); + + file.name().ends_with(&format!("{file_name}.ttf")) + }) + .and_then(|i| archive.by_index(i).ok()) + .expect("Find font file in zipped archive"); + + io::copy( + &mut font_file, + &mut fs::File::create(path.with_extension("ttf")) + .expect("Create font file"), + ) + .expect("Extract font file"); + } + + let relative_path = PathBuf::from( + std::iter::repeat("../") + .take(definition.module.split("::").count()) + .collect::(), + ); + + let mut module = String::new(); + + module.push_str(&format!( + "// Generated automatically by iced_fontello at build time.\n\ + // Do not edit manually. Source: {source}\n\ + // {hash}\n\ + use iced::Font;\n\ + use iced::widget::text;\n\n\ + use crate::widget::Text;\n\n\ + pub const FONT: &[u8] = include_bytes!(\"{path}\");\n\n", + source = relative_path.join(path.with_extension("toml")).display(), + path = relative_path.join(path.with_extension("ttf")).display() + )); + + for (name, glyph) in glyphs { + module.push_str(&format!( + "\ +pub fn {name}<'a>() -> Text<'a> {{ + icon(\"\\u{{{code:X}}}\") +}}\n\n", + code = glyph.code + )); + } + + module.push_str(&format!( + "\ +fn icon(codepoint: &str) -> Text<'_> {{ + text(codepoint).font(Font::with_name(\"{file_name}\")) +}}\n" + )); + + if module != module_contents { + if let Some(directory) = module_target.parent() { + fs::create_dir_all(directory) + .expect("Create parent directory of font module"); + } + + fs::write(module_target, module).expect("Write font module"); + } + + Ok(()) +} + +#[derive(Debug, Clone)] +pub enum Error {} + +#[derive(Debug, Clone, Deserialize)] +struct Definition { + module: String, + glyphs: BTreeMap, +} + +#[derive(Debug, Clone)] +struct Font { + name: String, + glyphs: BTreeMap, +} + +#[derive(Debug, Clone, Deserialize)] +struct Glyph { + uid: Id, + code: u64, + #[serde(rename = "css")] + name: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +struct Id(String); + +fn parse_fonts() -> BTreeMap { + #[derive(Deserialize)] + struct ItemSchema { + font: FontSchema, + glyphs: Vec, + } + + #[derive(Deserialize)] + struct FontSchema { + fontname: String, + } + + let items: Vec = + serde_json::from_str(include_str!("../fonts.json")) + .expect("Deserialize fonts"); + + items + .into_iter() + .map(|item| { + ( + item.font.fontname.clone(), + Font { + name: item.font.fontname, + glyphs: item + .glyphs + .into_iter() + .map(|glyph| (glyph.name.clone(), glyph)) + .collect(), + }, + ) + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_parses_fonts() { + assert!(!parse_fonts().is_empty()); + } +} diff --git a/src/icon.rs b/src/icon.rs index 3fbeb83..d218943 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -1,8 +1,10 @@ // Generated automatically by iced_fontello at build time. // Do not edit manually. Source: ../fonts/icons.toml // 915ea6b0646871c0f04350f201f27f28881b61f3bd6ef292a415d67a211739c1 -use iced::widget::{text, Text}; use iced::Font; +use iced::widget::text; + +use crate::widget::Text; pub const FONT: &[u8] = include_bytes!("../fonts/icons.ttf"); -- cgit v1.2.3 From e17ce59fa4c907511f38795c342b2232a7bba26d Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 28 Apr 2025 10:59:52 +0200 Subject: feat: switch to fully custom, Material3-based theme --- assets/themes/rose_pine.toml | 41 ----- src/appearance.rs | 46 ++++++ src/config.rs | 41 +++-- src/dialogs.rs | 4 +- src/main.rs | 23 ++- src/options.rs | 2 +- src/panes/code_view.rs | 46 +++--- src/panes/designer_view.rs | 7 +- src/panes/element_list.rs | 7 +- src/panes/style.rs | 23 +-- src/theme.rs | 357 ------------------------------------------ src/types.rs | 6 +- src/types/project.rs | 18 +-- src/types/rendered_element.rs | 30 +--- src/widget.rs | 18 ++- theme_test/src/main.rs | 2 +- 16 files changed, 155 insertions(+), 516 deletions(-) delete mode 100644 assets/themes/rose_pine.toml create mode 100644 src/appearance.rs delete mode 100644 src/theme.rs diff --git a/assets/themes/rose_pine.toml b/assets/themes/rose_pine.toml deleted file mode 100644 index e4540fb..0000000 --- a/assets/themes/rose_pine.toml +++ /dev/null @@ -1,41 +0,0 @@ -name = "Rosé Pine" - -dark = true - -[palette] -background = "#26233a" -text = "#e0def4" -primary = "#9ccfd8" -success = "#f6c177" -danger = "#eb6f92" -warning = "#e4b363" - -[background] -base = { color = "#191724", text = "#e0def4" } -weak = { color = "#1f1d2e", text = "#e0def4" } -strong = { color = "#26233a", text = "#f4ebd3" } - -[primary] -base = { color = "#eb6f92", text = "#000000" } -weak = { color = "#f6c177", text = "#000000" } -strong = { color = "#ebbcba", text = "#000000" } - -[secondary] -base = { color = "#31748f", text = "#ffffff" } -weak = { color = "#9ccfd8", text = "#000000" } -strong = { color = "#c4a7e7", text = "#000000" } - -[success] -base = { color = "#9ccfd8", text = "#000000" } -weak = { color = "#6e6a86", text = "#ffffff" } -strong = { color = "#908caa", text = "#000000" } - -[danger] -base = { color = "#eb6f92", text = "#ffffff" } -weak = { color = "#f6c177", text = "#ffffff" } -strong = { color = "#524f67", text = "#ffffff" } - -[warning] -base = { color = "#e4b363", text = "#ffffff" } -weak = { color = "#f4e1a1", text = "#000000" } -strong = { color = "#d8a343", text = "#ffffff" } diff --git a/src/appearance.rs b/src/appearance.rs new file mode 100644 index 0000000..78e782d --- /dev/null +++ b/src/appearance.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; + +use material_theme::Theme; + +pub fn iced_theme_from_str(theme_name: &str) -> iced::Theme { + match theme_name { + "Light" => iced::Theme::Light, + "Dark" => iced::Theme::Dark, + "Dracula" => iced::Theme::Dracula, + "Nord" => iced::Theme::Nord, + "Solarized Light" => iced::Theme::SolarizedLight, + "Solarized Dark" => iced::Theme::SolarizedDark, + "Gruvbox Light" => iced::Theme::GruvboxLight, + "Gruvbox Dark" => iced::Theme::GruvboxDark, + "Catppuccin Latte" => iced::Theme::CatppuccinLatte, + "Catppuccin Frappé" => iced::Theme::CatppuccinFrappe, + "Catppuccin Macchiato" => iced::Theme::CatppuccinMacchiato, + "Catppuccin Mocha" => iced::Theme::CatppuccinMocha, + "Tokyo Night" => iced::Theme::TokyoNight, + "Tokyo Night Storm" => iced::Theme::TokyoNightStorm, + "Tokyo Night Light" => iced::Theme::TokyoNightLight, + "Kanagawa Wave" => iced::Theme::KanagawaWave, + "Kanagawa Dragon" => iced::Theme::KanagawaDragon, + "Kanagawa Lotus" => iced::Theme::KanagawaLotus, + "Moonfly" => iced::Theme::Moonfly, + "Nightfly" => iced::Theme::Nightfly, + "Oxocarbon" => iced::Theme::Oxocarbon, + "Ferra" => iced::Theme::Ferra, + _ => iced::Theme::default(), + } +} + +#[derive(Debug, Clone)] +pub struct Appearance { + pub selected: Theme, + pub all: Arc<[Theme]>, +} + +impl Default for Appearance { + fn default() -> Self { + Self { + selected: Theme::default(), + all: Theme::ALL.into(), + } + } +} diff --git a/src/config.rs b/src/config.rs index 1da1239..7f6f8ce 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,26 +1,36 @@ // (c) 2022-2024 Cory Forsstrom, Casper Rogild Storm, Calvin Lee, Andrew Baldwin, Reza Alizadeh Majd // (c) 2024-2025 Polesznyák Márk László -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use material_theme::Theme; use serde::Deserialize; use tokio_stream::StreamExt; use tokio_stream::wrappers::ReadDirStream; -use crate::theme::{Appearance, Theme, theme_from_str, theme_index}; +use crate::appearance::Appearance; use crate::{Error, environment}; #[derive(Debug, Clone, Default)] pub struct Config { - pub theme: Appearance, - pub last_project: Option, + theme: Appearance, + last_project: Option, } impl Config { - pub fn selected_theme(&self) -> iced::Theme { + pub fn selected_theme(&self) -> Theme { self.theme.selected.clone() } + pub fn themes(&self) -> Arc<[Theme]> { + self.theme.all.clone() + } + + pub fn last_project(&self) -> Option<&Path> { + self.last_project.as_deref() + } + pub fn config_dir() -> PathBuf { let dir = environment::config_dir(); @@ -67,7 +77,7 @@ impl Config { last_project, } = toml::from_str(content.as_ref())?; - let theme = Self::load_theme(theme).await.unwrap_or_default(); + let theme = Self::load_appearance(&theme).await.unwrap_or_default(); Ok(Self { theme, @@ -75,7 +85,9 @@ impl Config { }) } - pub async fn load_theme(theme_name: String) -> Result { + pub async fn load_appearance( + theme_name: &str, + ) -> Result { use tokio::fs; let read_entry = async move |entry: fs::DirEntry| { @@ -83,15 +95,16 @@ impl Config { let theme: Theme = toml::from_str(content.as_ref()).ok()?; - Some(iced::Theme::from(theme)) + Some(theme) }; - let mut selected = Theme::default().into(); - let mut all = iced::Theme::ALL.to_owned(); - all.push(Theme::default().into()); + let mut selected = Theme::default(); + let mut all = Theme::ALL.to_owned(); - if theme_index(&theme_name, iced::Theme::ALL).is_some() { - selected = theme_from_str(None, &theme_name); + if let Some(index) = + Theme::ALL.iter().position(|t| t.name() == theme_name) + { + selected = Theme::ALL[index].clone(); } let mut stream = @@ -102,7 +115,7 @@ impl Config { }; if let Some(theme) = read_entry(entry).await { - if theme.to_string() == theme_name { + if theme.name() == theme_name { selected = theme.clone(); } all.push(theme); diff --git a/src/dialogs.rs b/src/dialogs.rs index a623f35..c1933ec 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -1,8 +1,8 @@ -use iced::{Element, Task}; +use iced::Task; use iced_dialog::button; use crate::Message; -use crate::types::{DialogAction, DialogButtons}; +use crate::types::{DialogAction, DialogButtons, Element}; pub const UNSAVED_CHANGES_TITLE: &str = "Unsaved changes"; pub const WARNING_TITLE: &str = "Heads up!"; diff --git a/src/main.rs b/src/main.rs index 5014077..1ac1d67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod appearance; mod config; mod dialogs; mod environment; @@ -6,7 +7,6 @@ mod error; mod icon; mod options; mod panes; -mod theme; mod types; mod values; mod widget; @@ -24,13 +24,15 @@ use iced::advanced::widget::Id; use iced::widget::{ Column, container, pane_grid, pick_list, row, text, text_editor, }; -use iced::{Alignment, Element, Length, Task, Theme, clipboard, keyboard}; +use iced::{Alignment, Length, Task, clipboard, keyboard}; use iced_anim::transition::Easing; use iced_anim::{Animated, Animation}; use iced_dialog::dialog::Dialog; +use material_theme::Theme; use panes::{code_view, designer_view, element_list}; use types::{ - Action, DesignerPane, DialogAction, DialogButtons, Message, Project, + Action, DesignerPane, DialogAction, DialogButtons, Element, Message, + Project, }; fn main() -> Result<(), Box> { @@ -148,11 +150,10 @@ impl IcedBuilder { self.config = Arc::new(config); self.theme.update(self.config.selected_theme().into()); - return if let Some(path) = self.config.last_project.clone() - { + return if let Some(path) = self.config.last_project() { if path.exists() && path.is_file() { Task::perform( - Project::from_path(path), + Project::from_path(path.to_owned()), Message::FileOpened, ) } else { @@ -394,7 +395,7 @@ impl IcedBuilder { fn view(&self) -> Element<'_, Message> { let header = row![pick_list( - self.config.theme.all.clone(), + self.config.themes(), Some(self.theme.target()), |theme| Message::SwitchTheme(theme.into()) )] @@ -442,13 +443,7 @@ impl IcedBuilder { DialogButtons::OkCancel => vec![ok_button(), cancel_button()], }, ) - .title(self.dialog_title) - .container_style(|theme| container::Style { - background: Some( - theme.extended_palette().background.strong.color.into(), - ), - ..Default::default() - }); + .title(self.dialog_title); Animation::new(&self.theme, content) .on_update(Message::SwitchTheme) diff --git a/src/options.rs b/src/options.rs index 2dc25d7..931182a 100644 --- a/src/options.rs +++ b/src/options.rs @@ -258,7 +258,7 @@ impl ApplyOptions for Row<'_, Message> { } } -impl ApplyOptions for Image { +impl ApplyOptions for Image<'_, Handle> { fn apply_options(self, options: BTreeMap>) -> Self { let mut image = self; diff --git a/src/panes/code_view.rs b/src/panes/code_view.rs index 890af8a..5999b8f 100644 --- a/src/panes/code_view.rs +++ b/src/panes/code_view.rs @@ -1,27 +1,36 @@ use iced::advanced::text::highlighter::Format; -use iced::widget::{Space, button, pane_grid, row, text, text_editor}; -use iced::{Alignment, Background, Border, Font, Length, Theme}; +use iced::border::Radius; +use iced::widget::{button, pane_grid, row, text, text_editor}; +use iced::{Alignment, Border, Font, Length}; use iced_custom_highlighter::{Highlight, Highlighter, Scope, Settings}; +use material_theme::Theme; use super::style; use crate::icon; use crate::types::{DesignerPane, Message}; use crate::widget::tip; +// TODO: implement a highlight style for the material theme fn highlight_style(theme: &Theme, scope: &Scope) -> Format { + let theme = if theme.is_dark() { + iced::Theme::SolarizedDark + } else { + iced::Theme::SolarizedLight + }; + match scope { Scope::Custom { .. } | Scope::Other => Format { color: Some(theme.extended_palette().primary.strong.color), font: None, }, - _ => Highlight::default_style(theme, scope), + _ => Highlight::default_style(&theme, scope), } } pub fn view( editor_content: &text_editor::Content, is_focused: bool, -) -> pane_grid::Content<'_, Message> { +) -> pane_grid::Content<'_, Message, Theme> { let title_bar = pane_grid::TitleBar::new(text("Generated Code").center()) .controls(pane_grid::Controls::dynamic( row![ @@ -29,28 +38,28 @@ pub fn view( button(icon::copy()) .on_press(Message::CopyCode) .padding([2, 7]) - .style(button::text), + .style(material_theme::button::text), "Copy", tip::Position::FollowCursor ), - Space::with_width(20), button("Switch to Designer view") .on_press(Message::SwitchPage(DesignerPane::DesignerView)) ] + .spacing(20) .align_y(Alignment::Center), row![ tip( button(icon::copy()) .on_press(Message::CopyCode) .padding([2, 7]) - .style(button::text), + .style(material_theme::button::text), "Copy", tip::Position::FollowCursor ), - Space::with_width(20), button(icon::switch()) .on_press(Message::SwitchPage(DesignerPane::DesignerView)) ] + .spacing(20) .align_y(Alignment::Center), )) .padding(10) @@ -60,25 +69,22 @@ pub fn view( text_editor(editor_content) .on_action(Message::EditorAction) .font(Font::MONOSPACE) - .highlight_with::( + .highlight_with::>( Settings::new(vec![], highlight_style, "rs"), Highlight::to_format, ) .style(|theme, _| { - let palette = theme.extended_palette(); + let style = material_theme::text_editor::default( + theme, + text_editor::Status::Active, + ); + text_editor::Style { - background: Background::Color( - palette.background.base.color, - ), border: Border { - radius: 2.into(), - width: 1.0, - color: palette.background.strong.color, + radius: Radius::default(), + ..style.border }, - icon: palette.background.weak.text, - placeholder: palette.background.strong.color, - value: palette.background.base.text, - selection: palette.primary.weak.color, + ..style } }) .height(Length::Fill) diff --git a/src/panes/designer_view.rs b/src/panes/designer_view.rs index af72022..0255b40 100644 --- a/src/panes/designer_view.rs +++ b/src/panes/designer_view.rs @@ -1,7 +1,8 @@ use iced::widget::{ button, center, container, pane_grid, responsive, row, text, themer, }; -use iced::{Alignment, Element, Length}; +use iced::{Alignment, Length}; +use material_theme::Theme; use super::style; use crate::icon; @@ -11,8 +12,8 @@ pub fn view<'a>( element_tree: Option<&'a RenderedElement>, designer_theme: iced::Theme, is_focused: bool, -) -> pane_grid::Content<'a, Message> { - let el_tree: Element<'a, Message> = match element_tree { +) -> pane_grid::Content<'a, Message, Theme> { + let el_tree: iced::Element<'a, Message> = match element_tree { Some(tree) => responsive(|size| { center( container(tree.clone()) diff --git a/src/panes/element_list.rs b/src/panes/element_list.rs index 594c203..0e5dbfe 100644 --- a/src/panes/element_list.rs +++ b/src/panes/element_list.rs @@ -1,9 +1,10 @@ use iced::widget::{Column, column, container, pane_grid, text}; -use iced::{Alignment, Element, Length}; +use iced::{Alignment, Length}; use iced_drop::droppable; +use material_theme::Theme; use super::style; -use crate::types::{ElementName, Message}; +use crate::types::{Element, ElementName, Message}; fn items_list_view<'a>() -> Element<'a, Message> { let mut column = Column::new() @@ -25,7 +26,7 @@ fn items_list_view<'a>() -> Element<'a, Message> { .into() } -pub fn view<'a>(is_focused: bool) -> pane_grid::Content<'a, Message> { +pub fn view<'a>(is_focused: bool) -> pane_grid::Content<'a, Message, Theme> { let items_list = items_list_view(); let content = column![items_list] .align_x(Alignment::Center) diff --git a/src/panes/style.rs b/src/panes/style.rs index 1eefb2d..acca6f9 100644 --- a/src/panes/style.rs +++ b/src/panes/style.rs @@ -1,24 +1,25 @@ use iced::widget::container::Style; -use iced::{Border, Theme}; +use iced::{Background, Border}; +use material_theme::Theme; pub fn title_bar(theme: &Theme) -> Style { - let palette = theme.extended_palette(); + let surface = theme.colors().surface; Style { - text_color: Some(palette.background.strong.text), - background: Some(palette.background.strong.color.into()), + text_color: Some(surface.on_surface), + background: Some(Background::Color(surface.surface_container.high)), ..Default::default() } } pub fn pane_active(theme: &Theme) -> Style { - let palette = theme.extended_palette(); + let surface = theme.colors().surface; Style { - background: Some(palette.background.weak.color.into()), + background: Some(Background::Color(surface.surface_container.low)), border: Border { width: 1.0, - color: palette.background.strong.color, + color: surface.surface_container.high, ..Border::default() }, ..Default::default() @@ -26,13 +27,13 @@ pub fn pane_active(theme: &Theme) -> Style { } pub fn pane_focused(theme: &Theme) -> Style { - let palette = theme.extended_palette(); + let surface = theme.colors().surface; Style { - background: Some(palette.background.weak.color.into()), + background: Some(Background::Color(surface.surface_container.low)), border: Border { - width: 4.0, - color: palette.background.strong.color, + width: 2.0, + color: surface.surface_container.high, ..Border::default() }, ..Default::default() diff --git a/src/theme.rs b/src/theme.rs deleted file mode 100644 index b721ddc..0000000 --- a/src/theme.rs +++ /dev/null @@ -1,357 +0,0 @@ -use std::sync::Arc; - -use iced::Color; -use iced::theme::palette::Extended; -use serde::Deserialize; - -use crate::config::Config; - -const DEFAULT_THEME_CONTENT: &str = - include_str!("../assets/themes/rose_pine.toml"); - -pub fn theme_index(theme_name: &str, slice: &[iced::Theme]) -> Option { - slice - .iter() - .position(|theme| theme.to_string() == theme_name) -} - -pub fn theme_from_str( - config: Option<&Config>, - theme_name: &str, -) -> iced::Theme { - match theme_name { - "Light" => iced::Theme::Light, - "Dark" => iced::Theme::Dark, - "Dracula" => iced::Theme::Dracula, - "Nord" => iced::Theme::Nord, - "Solarized Light" => iced::Theme::SolarizedLight, - "Solarized Dark" => iced::Theme::SolarizedDark, - "Gruvbox Light" => iced::Theme::GruvboxLight, - "Gruvbox Dark" => iced::Theme::GruvboxDark, - "Catppuccin Latte" => iced::Theme::CatppuccinLatte, - "Catppuccin Frappé" => iced::Theme::CatppuccinFrappe, - "Catppuccin Macchiato" => iced::Theme::CatppuccinMacchiato, - "Catppuccin Mocha" => iced::Theme::CatppuccinMocha, - "Tokyo Night" => iced::Theme::TokyoNight, - "Tokyo Night Storm" => iced::Theme::TokyoNightStorm, - "Tokyo Night Light" => iced::Theme::TokyoNightLight, - "Kanagawa Wave" => iced::Theme::KanagawaWave, - "Kanagawa Dragon" => iced::Theme::KanagawaDragon, - "Kanagawa Lotus" => iced::Theme::KanagawaLotus, - "Moonfly" => iced::Theme::Moonfly, - "Nightfly" => iced::Theme::Nightfly, - "Oxocarbon" => iced::Theme::Oxocarbon, - "Ferra" => iced::Theme::Ferra, - _ => { - if let Some(config) = config { - if theme_name == config.theme.selected.to_string() { - config.theme.selected.clone() - } else if let Some(index) = - theme_index(theme_name, &config.theme.all) - { - config.theme.all[index].clone() - } else { - iced::Theme::default() - } - } else { - iced::Theme::default() - } - } - } -} - -#[derive(Debug, Clone)] -pub struct Appearance { - pub selected: iced::Theme, - pub all: Arc<[iced::Theme]>, -} - -impl Default for Appearance { - fn default() -> Self { - Self { - selected: Theme::default().into(), - all: { - let mut themes = iced::Theme::ALL.to_owned(); - themes.push(Theme::default().into()); - themes.into() - }, - } - } -} - -#[derive(Debug, Deserialize)] -pub struct Theme { - name: String, - palette: ThemePalette, - dark: Option, - #[serde(flatten)] - extended: Option, -} - -impl From for iced::Theme { - fn from(value: Theme) -> Self { - iced::Theme::custom_with_fn( - value.name.clone(), - value.palette.into(), - |_| value.into(), - ) - } -} - -impl Default for Theme { - fn default() -> Self { - toml::from_str(DEFAULT_THEME_CONTENT).expect("parse default theme") - } -} - -#[derive(Debug, Clone, Copy, Deserialize)] -pub struct ThemePalette { - #[serde(with = "color_serde")] - background: Color, - #[serde(with = "color_serde")] - text: Color, - #[serde(with = "color_serde")] - primary: Color, - #[serde(with = "color_serde")] - success: Color, - #[serde(with = "color_serde")] - danger: Color, - #[serde(with = "color_serde")] - warning: Color, -} - -impl Default for ThemePalette { - fn default() -> Self { - let palette = iced::Theme::default().palette(); - Self { - background: palette.background, - text: palette.text, - primary: palette.primary, - success: palette.success, - danger: palette.danger, - warning: palette.warning, - } - } -} - -impl From for iced::theme::Palette { - fn from(palette: ThemePalette) -> Self { - iced::theme::Palette { - background: palette.background, - text: palette.text, - primary: palette.primary, - success: palette.success, - danger: palette.danger, - warning: palette.warning, - } - } -} - -impl From for Extended { - fn from(theme: Theme) -> Self { - let mut extended = Extended::generate(theme.palette.into()); - - if let Some(is_dark) = theme.dark { - extended.is_dark = is_dark; - } - - if let Some(extended_palette) = theme.extended { - if let Some(background) = extended_palette.background { - if let Some(base) = background.base { - extended.background.base = base.into(); - } - if let Some(weak) = background.weak { - extended.background.weak = weak.into(); - } - if let Some(strong) = background.strong { - extended.background.strong = strong.into(); - } - } - - if let Some(primary) = extended_palette.primary { - if let Some(base) = primary.base { - extended.primary.base = base.into(); - } - if let Some(weak) = primary.weak { - extended.primary.weak = weak.into(); - } - if let Some(strong) = primary.strong { - extended.primary.strong = strong.into(); - } - } - - if let Some(secondary) = extended_palette.secondary { - if let Some(base) = secondary.base { - extended.secondary.base = base.into(); - } - if let Some(weak) = secondary.weak { - extended.secondary.weak = weak.into(); - } - if let Some(strong) = secondary.strong { - extended.secondary.strong = strong.into(); - } - } - - if let Some(success) = extended_palette.success { - if let Some(base) = success.base { - extended.success.base = base.into(); - } - if let Some(weak) = success.weak { - extended.success.weak = weak.into(); - } - if let Some(strong) = success.strong { - extended.success.strong = strong.into(); - } - } - - if let Some(danger) = extended_palette.danger { - if let Some(base) = danger.base { - extended.danger.base = base.into(); - } - if let Some(weak) = danger.weak { - extended.danger.weak = weak.into(); - } - if let Some(strong) = danger.strong { - extended.danger.strong = strong.into(); - } - } - - if let Some(warning) = extended_palette.warning { - if let Some(base) = warning.base { - extended.warning.base = base.into(); - } - if let Some(weak) = warning.weak { - extended.warning.weak = weak.into(); - } - if let Some(strong) = warning.strong { - extended.warning.strong = strong.into(); - } - } - } - - extended - } -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ExtendedThemePalette { - background: Option, - primary: Option, - secondary: Option, - success: Option, - danger: Option, - warning: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemeBackground { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemePrimary { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemeSecondary { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemeSuccess { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemeDanger { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemeWarning { - base: Option, - weak: Option, - strong: Option, -} - -#[derive(Debug, Clone, Copy, Default, Deserialize)] -struct ThemePair { - #[serde(with = "color_serde")] - color: Color, - #[serde(with = "color_serde")] - text: Color, -} - -impl From for iced::theme::palette::Pair { - fn from(pair: ThemePair) -> Self { - Self { - color: pair.color, - text: pair.text, - } - } -} - -pub fn parse_argb(s: &str) -> Option { - let hex = s.strip_prefix('#').unwrap_or(s); - - let parse_channel = |from: usize, to: usize| { - let num = - usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0; - - // If we only got half a byte (one letter), expand it into a full byte (two letters) - Some(if from == to { num + num * 16.0 } else { num }) - }; - - Some(match hex.len() { - 3 => Color::from_rgb( - parse_channel(0, 0)?, - parse_channel(1, 1)?, - parse_channel(2, 2)?, - ), - 4 => Color::from_rgba( - parse_channel(1, 1)?, - parse_channel(2, 2)?, - parse_channel(3, 3)?, - parse_channel(0, 0)?, - ), - 6 => Color::from_rgb( - parse_channel(0, 1)?, - parse_channel(2, 3)?, - parse_channel(4, 5)?, - ), - 8 => Color::from_rgba( - parse_channel(2, 3)?, - parse_channel(4, 5)?, - parse_channel(6, 7)?, - parse_channel(0, 1)?, - ), - _ => None?, - }) -} - -mod color_serde { - use iced::Color; - use serde::{Deserialize, Deserializer}; - - use super::parse_argb; - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(String::deserialize(deserializer) - .map(|hex| parse_argb(&hex))? - .unwrap_or(Color::TRANSPARENT)) - } -} diff --git a/src/types.rs b/src/types.rs index adb788e..608f285 100644 --- a/src/types.rs +++ b/src/types.rs @@ -8,16 +8,20 @@ pub use element_name::ElementName; use iced::advanced::widget::Id; use iced::widget::{pane_grid, text_editor}; use iced_anim::Event; +use material_theme::Theme; pub use project::Project; pub use rendered_element::*; use crate::Error; use crate::config::Config; +pub type Element<'a, Message> = iced::Element<'a, Message, Theme>; + +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone)] pub enum Message { ConfigLoad(Result), - SwitchTheme(Event), + SwitchTheme(Event), CopyCode, SwitchPage(DesignerPane), EditorAction(text_editor::Action), diff --git a/src/types/project.rs b/src/types/project.rs index 91b2bb1..11789ac 100644 --- a/src/types/project.rs +++ b/src/types/project.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use super::rendered_element::RenderedElement; use crate::Error; -use crate::theme::{theme_from_str, theme_index}; +use crate::appearance::iced_theme_from_str; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Project { @@ -33,8 +33,8 @@ impl Project { pub fn get_theme(&self) -> Theme { match &self.theme { - Some(theme) => theme_from_str(None, theme), - None => Theme::default(), + Some(theme) => iced_theme_from_str(theme), + None => iced::Theme::default(), } } @@ -90,20 +90,10 @@ impl Project { Some(ref element_tree) => { let (imports, view) = element_tree.codegen(); let theme = self.get_theme(); - let theme_code = theme.to_string().replace(" ", ""); - let mut theme_imports = ""; - if theme_index(&theme.to_string(), Theme::ALL).is_none() { - if theme_code.contains("Extended") { - theme_imports = "use iced::{{color,theme::{{Palette,palette::{{Extended,Background,Primary,Secondary,Success,Danger,Warning,Pair}}}}}};\n"; - } else { - theme_imports = "use iced::{{color,theme::Palette}};\n"; - } - } let app_code = format!( r#"// Automatically generated by iced Builder use iced::{{widget::{{{imports}}},Element}}; -{theme_imports} fn main() -> iced::Result {{ iced::application(State::default, State::update, State::view).title("{}").theme(State::theme).run() @@ -130,7 +120,7 @@ impl State {{ Some(ref t) => t, None => "New app", }, - theme_code + theme.to_string().replace(" ", "") ); let config = rust_format::Config::new_str() .edition(Edition::Rust2021) diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs index 9639299..020aa46 100755 --- a/src/types/rendered_element.rs +++ b/src/types/rendered_element.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use iced::advanced::widget::Id; -use iced::{Element, Length, widget}; +use iced::{Element, widget}; use serde::{Deserialize, Serialize}; use crate::Error; @@ -171,34 +171,6 @@ impl RenderedElement { self } - pub fn text_view<'a>(self) -> Element<'a, Message> { - let mut children = widget::column![]; - - if let Some(els) = self.child_elements.clone() { - for el in els { - children = children.push(el.clone().text_view()); - } - } - iced_drop::droppable( - widget::container( - widget::column![ - widget::text(self.name.clone().to_string()), - children - ] - .width(Length::Fill) - .spacing(10), - ) - .padding(10) - .style(widget::container::bordered_box), - ) - .id(self.id().clone()) - .drag_hide(true) - .on_drop(move |point, rect| { - Message::MoveElement(self.clone(), point, rect) - }) - .into() - } - pub fn codegen(&self) -> (String, String) { let mut imports = String::new(); let mut view = String::new(); diff --git a/src/widget.rs b/src/widget.rs index f1eb0f3..859d25e 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -1,5 +1,7 @@ -use iced::Element; -use iced::widget::{container, text, tooltip}; +use iced::widget::{self, container, text, tooltip}; +use material_theme::Theme; + +use crate::types::Element; pub mod tip { pub use super::tooltip::Position; @@ -12,10 +14,16 @@ pub fn tip<'a, Message: 'a>( ) -> Element<'a, Message> { tooltip( target, - container(text(tip).size(14)) - .padding(5) - .style(container::rounded_box), + container(text(tip).size(14)).padding(5).style(|theme| { + let base = material_theme::container::surface_container_low(theme); + container::Style { + border: iced::border::rounded(4), + ..base + } + }), position, ) .into() } + +pub type Text<'a> = widget::Text<'a, Theme>; diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index b4a7731..cba4377 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -18,7 +18,7 @@ use material_theme::text::surface_variant; fn main() -> iced::Result { iced::application(State::default, State::update, State::view) - .theme(|state| *state.theme.value()) + .theme(|state| state.theme.value().clone()) .run() } -- cgit v1.2.3 From 06c5d14e4781bef4a60ca353da99e24c2f25b138 Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 28 Apr 2025 23:46:18 +0200 Subject: fix: iced_fontello/fonts.json being ignored by git --- crates/iced_fontello/.gitignore | 1 + crates/iced_fontello/fonts.json | 23494 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 23495 insertions(+) create mode 100644 crates/iced_fontello/fonts.json diff --git a/crates/iced_fontello/.gitignore b/crates/iced_fontello/.gitignore index 96ef6c0..089e9cd 100644 --- a/crates/iced_fontello/.gitignore +++ b/crates/iced_fontello/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +!fonts.json diff --git a/crates/iced_fontello/fonts.json b/crates/iced_fontello/fonts.json new file mode 100644 index 0000000..cd7d963 --- /dev/null +++ b/crates/iced_fontello/fonts.json @@ -0,0 +1,23494 @@ +[ + { + "glyphs": [ + { + "css": "emo-happy", + "code": 59392, + "uid": "c64623255a4a7c72436b199b05296c4f", + "search": [ + "emoticon", + "smiley", + "happy" + ], + "charRef": 61440 + }, + { + "css": "emo-wink", + "code": 59393, + "uid": "1ba44825e5f10920b4e3f1d0c73f79a2", + "search": [ + "emoticon", + "smiley", + "wink" + ], + "charRef": 61441 + }, + { + "css": "emo-wink2", + "code": 59411, + "uid": "4bb2045a2aca451705fe8a23c4a576ab", + "search": [ + "emoticon", + "smiley", + "wink" + ], + "charRef": 61442 + }, + { + "css": "emo-unhappy", + "code": 59394, + "uid": "53ed8570225581269cd7eff5795e8bea", + "search": [ + "emoticon", + "smiley", + "unhappy" + ], + "charRef": 61443 + }, + { + "css": "emo-sleep", + "code": 59395, + "uid": "fd59eac4d575b48eb156590b63a355fd", + "search": [ + "emoticon", + "smiley", + "sleep" + ], + "charRef": 61444 + }, + { + "css": "emo-thumbsup", + "code": 59396, + "uid": "142263941b9f4cd4b2b84f1f4cd13b1d", + "search": [ + "emoticon", + "smiley", + "thumbsup" + ], + "charRef": 61445 + }, + { + "css": "emo-devil", + "code": 59397, + "uid": "4dd56d61fd0dab19277824da301424b3", + "search": [ + "emoticon", + "smiley", + "devil" + ], + "charRef": 61446 + }, + { + "css": "emo-surprised", + "code": 59398, + "uid": "68e298ff2d8b25dd7f647ed64f5ae690", + "search": [ + "emoticon", + "smiley", + "surprised" + ], + "charRef": 61447 + }, + { + "css": "emo-tongue", + "code": 59399, + "uid": "bb68a13a3574b087d4350eff0b8d48e3", + "search": [ + "emoticon", + "smiley", + "tongue" + ], + "charRef": 61448 + }, + { + "css": "emo-coffee", + "code": 59400, + "uid": "48cc210e59ff4bc56b6c8fba6eb384b8", + "search": [ + "emoticon", + "smiley", + "coffee" + ], + "charRef": 61449 + }, + { + "css": "emo-sunglasses", + "code": 59401, + "uid": "078fec38562c3f83a1201a908040c141", + "search": [ + "emoticon", + "smiley", + "sunglasses" + ], + "charRef": 61450 + }, + { + "css": "emo-displeased", + "code": 59402, + "uid": "043b585886018be7408f4c77c1a3759c", + "search": [ + "emoticon", + "smiley", + "displeased" + ], + "charRef": 61451 + }, + { + "css": "emo-beer", + "code": 59403, + "uid": "3a900d0e9f43f5409211f62bec557379", + "search": [ + "emoticon", + "smiley", + "beer" + ], + "charRef": 61452 + }, + { + "css": "emo-grin", + "code": 59404, + "uid": "cbc328d1c779a2b9e3b1199d904199a5", + "search": [ + "emoticon", + "smiley", + "grin" + ], + "charRef": 61453 + }, + { + "css": "emo-angry", + "code": 59405, + "uid": "f0d3ad15d020cf187d42dd3b2295b65c", + "search": [ + "emoticon", + "smiley", + "angry" + ], + "charRef": 61454 + }, + { + "css": "emo-saint", + "code": 59406, + "uid": "5195e2dcb4a63fbb8c09896a8058f6ab", + "search": [ + "emoticon", + "smiley", + "saint" + ], + "charRef": 61455 + }, + { + "css": "emo-cry", + "code": 59407, + "uid": "04688d76a33ce7a7950e40fae79c08ac", + "search": [ + "emoticon", + "smiley", + "cry" + ], + "charRef": 61456 + }, + { + "css": "emo-shoot", + "code": 59408, + "uid": "4843d0d6050dd508d4c101a334f46db2", + "search": [ + "emoticon", + "smiley", + "shoot" + ], + "charRef": 61457 + }, + { + "css": "emo-squint", + "code": 59409, + "uid": "fc92480dedc439d274d4e3e4b425edf4", + "search": [ + "emoticon", + "smiley", + "squint" + ], + "charRef": 61458 + }, + { + "css": "emo-laugh", + "code": 59410, + "uid": "2bd5f98482d86649958312ea2ab5bb40", + "search": [ + "emoticon", + "smiley", + "laugh" + ], + "charRef": 61459 + }, + { + "css": "spin1", + "code": 59440, + "uid": "72109d2fb3088d0e66ea6a9204297651", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61460 + }, + { + "css": "spin2", + "code": 59441, + "uid": "f0c301ac841dafc38d8eb1b933fc73e5", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61461 + }, + { + "css": "spin3", + "code": 59442, + "uid": "2a6740fc2f9d0edea54205963f662594", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61462 + }, + { + "css": "spin4", + "code": 59444, + "uid": "9bd60140934a1eb9236fd7a8ab1ff6ba", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61463 + }, + { + "css": "spin5", + "code": 59448, + "uid": "5d2d07f112b8de19f2c0dbfec3e42c05", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61464 + }, + { + "css": "spin6", + "code": 59449, + "uid": "9bc2902722abb366a213a052ade360bc", + "search": [ + "load", + "progress", + "wait" + ], + "css-ext": "animate-spin", + "charRef": 61465 + }, + { + "css": "firefox", + "code": 59456, + "uid": "62c089cb34e74b3a1200bc7f5314eb4e", + "search": [ + "browser", + "firefox" + ], + "charRef": 61466 + }, + { + "css": "chrome", + "code": 59457, + "uid": "9c2b737b16ae2c8d66b7bfd29ba5ecd8", + "search": [ + "browser", + "chrome" + ], + "charRef": 61467 + }, + { + "css": "opera", + "code": 59458, + "uid": "45861dd1e5ce4fde338bcccf01eeb808", + "search": [ + "browser", + "opera" + ], + "charRef": 61468 + }, + { + "css": "ie", + "code": 59459, + "uid": "2a46f1d1c9bd036e17a74e46613c1636", + "search": [ + "browser", + "ie", + "bullshit", + "crap" + ], + "charRef": 61469 + }, + { + "css": "crown", + "code": 59460, + "uid": "186dec7a13156bbe2550790c158fb85d", + "search": [ + "crown", + "leader" + ], + "charRef": 61470 + }, + { + "css": "crown-plus", + "code": 59461, + "uid": "36ef9feb0754335302784521267a9ad4", + "search": [ + "crown", + "plus", + "leader", + "add" + ], + "charRef": 61471 + }, + { + "css": "crown-minus", + "code": 59462, + "uid": "ec8496ef645f3be7b28147ec60cd9ab1", + "search": [ + "crown", + "minus", + "leader", + "remove" + ], + "charRef": 61472 + }, + { + "css": "marquee", + "code": 59463, + "uid": "8ce732688587909ad0a9d8323eaca8ad", + "search": [ + "marquee" + ], + "charRef": 61473 + } + ], + "font": { + "fontname": "fontelico", + "fullname": "Fontelico", + "familyname": "Fontelico", + "copyright": "Copyright (C) 2012 by Fontello project", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "Crowdsourced, for Fontello project", + "homepage": "http://fontello.com", + "email": "vitaly@rcdesign.ru", + "twitter": "http://twitter.com/puzrin", + "github": "https://github.com/fontello/fontelico.font", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "glass", + "code": 127864, + "uid": "cfaa8fbbdcc7bb8d636cb974aad1f9b9", + "search": [ + "glass" + ], + "charRef": 61474 + }, + { + "css": "music", + "code": 9835, + "uid": "9ea0a737ccc45d6c510dcbae56058849", + "search": [ + "music", + "note", + "song", + "sound" + ], + "charRef": 61475 + }, + { + "css": "search", + "code": 128269, + "uid": "9dd9e835aebe1060ba7190ad2b2ed951", + "search": [ + "search", + "find" + ], + "charRef": 61476 + }, + { + "css": "mail", + "code": 9993, + "uid": "bf882b30900da12fca090d9796bc3030", + "search": [ + "mail", + "email", + "envelope-o" + ], + "charRef": 61477 + }, + { + "css": "mail-alt", + "code": 61664, + "uid": "ccc2329632396dc096bb638d4b46fb98", + "search": [ + "mail", + "email" + ], + "charRef": 61478 + }, + { + "css": "mail-squared", + "code": 61849, + "uid": "17c21cd98db80e521e573eba247bd69b", + "search": [ + "mail", + "email" + ], + "charRef": 61479 + }, + { + "css": "heart", + "code": 9829, + "uid": "d73eceadda1f594cec0536087539afbf", + "search": [ + "heart" + ], + "charRef": 61480 + }, + { + "css": "heart-empty", + "code": 9825, + "uid": "f3dc2d6d8fe9cf9ebff84dc260888cdf", + "search": [ + "heart" + ], + "charRef": 61481 + }, + { + "css": "star", + "code": 9733, + "uid": "474656633f79ea2f1dad59ff63f6bf07", + "search": [ + "star" + ], + "charRef": 61482 + }, + { + "css": "star-empty", + "code": 9734, + "uid": "d17030afaecc1e1c22349b99f3c4992a", + "search": [ + "star", + "star-o" + ], + "charRef": 61483 + }, + { + "css": "star-half", + "code": 59137, + "uid": "8f8278fbe5a2a0ea836be3c408b005d2", + "search": [ + "star" + ], + "charRef": 61484 + }, + { + "css": "star-half-alt", + "code": 61731, + "uid": "84cf1fcc3fec556e7eaeb19679ca2dc9", + "search": [ + "star" + ], + "charRef": 61485 + }, + { + "css": "user", + "code": 128100, + "uid": "8b80d36d4ef43889db10bc1f0dc9a862", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 61486 + }, + { + "css": "user-plus", + "code": 62004, + "uid": "1bafeeb1808a5fe24484c7890096901a", + "search": [ + "user", + "plus", + "add" + ], + "charRef": 61487 + }, + { + "css": "user-times", + "code": 62005, + "uid": "fb1c59faa93eb6e2248c2456625b08a2", + "search": [ + "user", + "remove", + "delete" + ], + "charRef": 61488 + }, + { + "css": "users", + "code": 128101, + "uid": "31972e4e9d080eaa796290349ae6c1fd", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 61489 + }, + { + "css": "male", + "code": 61827, + "uid": "ca2d64f8a3ea7cbf6af45898b2dcf35e", + "search": [ + "male" + ], + "charRef": 61490 + }, + { + "css": "female", + "code": 61826, + "uid": "9bf7e14698cccdca37a6f1a02cf7d79e", + "search": [ + "female" + ], + "charRef": 61491 + }, + { + "css": "child", + "code": 61870, + "uid": "c2314ed1d2314b89f9285c53bcbf2548", + "search": [ + "child", + "people" + ], + "charRef": 61492 + }, + { + "css": "user-secret", + "code": 61979, + "uid": "f9c8ea86275ca16128235c6452b67b8e", + "search": [ + "secret", + "private", + "user" + ], + "charRef": 61493 + }, + { + "css": "video", + "code": 127916, + "uid": "872d9516df93eb6b776cc4d94bd97dac", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 61494 + }, + { + "css": "videocam", + "code": 127909, + "uid": "0f99ab40ab0b4d64a74f2d0deeb03e42", + "search": [ + "facetime", + "movie", + "video", + "film", + "video-camera" + ], + "charRef": 61495 + }, + { + "css": "picture", + "code": 127748, + "uid": "381da2c2f7fd51f8de877c044d7f439d", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 61496 + }, + { + "css": "camera", + "code": 128247, + "uid": "dc3f1d5b1d006f7f7b3b6295eccab9da", + "search": [ + "camera", + "photo" + ], + "charRef": 61497 + }, + { + "css": "camera-alt", + "code": 59151, + "uid": "9d3d9d6ce1ec63eaa26281e6162853c9", + "search": [ + "camera", + "photo" + ], + "charRef": 61498 + }, + { + "css": "th-large", + "code": 59144, + "uid": "dd492243d64e21dfe16a92452f7861cb", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 61499 + }, + { + "css": "th", + "code": 9871, + "uid": "b1887b423d2fd15c345e090320c91ca0", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 61500 + }, + { + "css": "th-list", + "code": 9776, + "uid": "f805bb95d40c7ef2bc51b3d50d4f2e5c", + "search": [ + "list" + ], + "charRef": 61501 + }, + { + "css": "ok", + "code": 10003, + "uid": "12f4ece88e46abd864e40b35e05b11cd", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 61502 + }, + { + "css": "ok-circled", + "code": 10004, + "uid": "43ab845088317bd348dee1d975700c48", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 61503 + }, + { + "css": "ok-circled2", + "code": 59138, + "uid": "ad33e708f4d2e25c5056c931da1528d6", + "search": [ + "ok", + "yes", + "check", + "mark", + "check-circle-o" + ], + "charRef": 61504 + }, + { + "css": "ok-squared", + "code": 61770, + "uid": "1400d5103edd2fa6d2d61688fee79a5a", + "search": [ + "ok", + "check" + ], + "charRef": 61505 + }, + { + "css": "cancel", + "code": 10005, + "uid": "5211af474d3a9848f67f945e2ccaf143", + "search": [ + "close", + "cancel", + "reject", + "times" + ], + "charRef": 61506 + }, + { + "css": "cancel-circled", + "code": 10006, + "uid": "0f4cae16f34ae243a6144c18a003f2d8", + "search": [ + "close", + "cancel", + "reject", + "times-circle" + ], + "charRef": 61507 + }, + { + "css": "cancel-circled2", + "code": 59139, + "uid": "2e2dba0307a502a8507c1729084c7ab5", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 61508 + }, + { + "css": "plus", + "code": 43, + "uid": "44e04715aecbca7f266a17d5a7863c68", + "search": [ + "plus" + ], + "charRef": 61509 + }, + { + "css": "plus-circled", + "code": 10133, + "uid": "4ba33d2607902cf690dd45df09774cb0", + "search": [ + "plus" + ], + "charRef": 61510 + }, + { + "css": "plus-squared", + "code": 61694, + "uid": "1a5cfa186647e8c929c2b17b9fc4dac1", + "search": [ + "plus", + "plus-square" + ], + "charRef": 61511 + }, + { + "css": "plus-squared-alt", + "code": 61846, + "uid": "2d3be3e856fc1e4ac067590d2ded1b07", + "search": [ + "plus" + ], + "charRef": 61512 + }, + { + "css": "minus", + "code": 45, + "uid": "861ab06e455e2de3232ebef67d60d708", + "search": [ + "minus" + ], + "charRef": 61513 + }, + { + "css": "minus-circled", + "code": 10134, + "uid": "eeadb020bb75d089b25d8424aabe19e0", + "search": [ + "minus" + ], + "charRef": 61514 + }, + { + "css": "minus-squared", + "code": 61766, + "uid": "f755a58fb985eeb70bd47d9b31892a34", + "search": [ + "minus" + ], + "charRef": 61515 + }, + { + "css": "minus-squared-alt", + "code": 61767, + "uid": "18ef25350258541e8e54148ed79845c0", + "search": [ + "minus" + ], + "charRef": 61516 + }, + { + "css": "help", + "code": 61736, + "uid": "ce3cf091d6ebd004dd0b52d24074e6e3", + "search": [ + "help" + ], + "charRef": 61517 + }, + { + "css": "help-circled", + "code": 59140, + "uid": "17ebadd1e3f274ff0205601eef7b9cc4", + "search": [ + "help", + "question", + "question-circle" + ], + "charRef": 61518 + }, + { + "css": "info-circled", + "code": 59141, + "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2", + "search": [ + "info", + "info-circle" + ], + "charRef": 61519 + }, + { + "css": "info", + "code": 61737, + "uid": "3d4ea8a78dc34efe891f3a0f3d961274", + "search": [ + "info" + ], + "charRef": 61520 + }, + { + "css": "home", + "code": 8962, + "uid": "d7271d490b71df4311e32cdacae8b331", + "search": [ + "home" + ], + "charRef": 61521 + }, + { + "css": "link", + "code": 128279, + "uid": "0ddd3e8201ccc7d41f7b7c9d27eca6c1", + "search": [ + "link", + "chain" + ], + "charRef": 61522 + }, + { + "css": "unlink", + "code": 61735, + "uid": "1dcd2b2148b7f086a4eb47f6a746bdee", + "search": [ + "unlink", + "chain-broken" + ], + "charRef": 61523 + }, + { + "css": "link-ext", + "code": 61582, + "uid": "e15f0d620a7897e2035c18c80142f6d9", + "search": [ + "link", + "url", + "external", + "external-link" + ], + "charRef": 61524 + }, + { + "css": "link-ext-alt", + "code": 61772, + "uid": "e35de5ea31cd56970498e33efbcb8e36", + "search": [ + "link", + "url", + "external" + ], + "charRef": 61525 + }, + { + "css": "attach", + "code": 128206, + "uid": "0d6ab6194c0eddda2b8c9cedf2ab248e", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 61526 + }, + { + "css": "lock", + "code": 128274, + "uid": "c1f1975c885aa9f3dad7810c53b82074", + "search": [ + "lock" + ], + "charRef": 61527 + }, + { + "css": "lock-open", + "code": 128275, + "uid": "657ab647f6248a6b57a5b893beaf35a9", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 61528 + }, + { + "css": "lock-open-alt", + "code": 61758, + "uid": "05376be04a27d5a46e855a233d6e8508", + "search": [ + "lock", + "unlock", + "open" + ], + "charRef": 61529 + }, + { + "css": "pin", + "code": 128204, + "uid": "5b0772e9484a1a11646793a82edd622a", + "search": [ + "pin", + "pushpin" + ], + "charRef": 61530 + }, + { + "css": "eye", + "code": 59146, + "uid": "c5fd349cbd3d23e4ade333789c29c729", + "search": [ + "eye", + "subscribe" + ], + "charRef": 61531 + }, + { + "css": "eye-off", + "code": 59147, + "uid": "7fd683b2c518ceb9e5fa6757f2276faa", + "search": [ + "eye", + "unsubscribe" + ], + "charRef": 61532 + }, + { + "css": "tag", + "code": 59148, + "uid": "3db5347bd219f3bce6025780f5d9ef45", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 61533 + }, + { + "css": "tags", + "code": 59149, + "uid": "a3f89e106175a5c5c4e9738870b12e55", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 61534 + }, + { + "css": "bookmark", + "code": 128278, + "uid": "f04a5d24e9e659145b966739c4fde82a", + "search": [ + "bookmark" + ], + "charRef": 61535 + }, + { + "css": "bookmark-empty", + "code": 61591, + "uid": "2f5ef6f6b7aaebc56458ab4e865beff5", + "search": [ + "bookmark" + ], + "charRef": 61536 + }, + { + "css": "flag", + "code": 9873, + "uid": "57a0ac800df728aad61a7cf9e12f5fef", + "search": [ + "flag" + ], + "charRef": 61537 + }, + { + "css": "flag-empty", + "code": 61725, + "uid": "6c83092421441296f5c4e8074b0cf32c", + "search": [ + "flag" + ], + "charRef": 61538 + }, + { + "css": "flag-checkered", + "code": 61726, + "uid": "d7a614bd701f6712e8e3b2be124899e1", + "search": [ + "flag" + ], + "charRef": 61539 + }, + { + "css": "thumbs-up", + "code": 128077, + "uid": "acf41aa4018e58d49525665469e35665", + "search": [ + "thumbs", + "vote", + "up", + "like", + "love", + "thumbs-o-up" + ], + "charRef": 61540 + }, + { + "css": "thumbs-down", + "code": 128078, + "uid": "7533e68038fc6d520ede7a7ffa0a2f64", + "search": [ + "thumbs", + "vote", + "down", + "unlike", + "dislike", + "thumbs-o-down" + ], + "charRef": 61541 + }, + { + "css": "thumbs-up-alt", + "code": 61796, + "uid": "5e2ab018e3044337bcef5f7e94098ea1", + "search": [ + "thumbs", + "vote", + "up", + "like", + "love" + ], + "charRef": 61542 + }, + { + "css": "thumbs-down-alt", + "code": 61797, + "uid": "ddcd918b502642705838815d40aea9e3", + "search": [ + "thumbs", + "vote", + "down", + "dislike", + "unlike" + ], + "charRef": 61543 + }, + { + "css": "download", + "code": 128229, + "uid": "9a76bc135eac17d2c8b8ad4a5774fc87", + "search": [ + "download" + ], + "charRef": 61544 + }, + { + "css": "upload", + "code": 128228, + "uid": "eeec3208c90b7b48e804919d0d2d4a41", + "search": [ + "upload" + ], + "charRef": 61545 + }, + { + "css": "download-cloud", + "code": 61677, + "uid": "f5999a012fc3752386635ec02a858447", + "search": [ + "download", + "cloud" + ], + "charRef": 61546 + }, + { + "css": "upload-cloud", + "code": 61678, + "uid": "de2fc7a5c986ab8c622f63455d7cf814", + "search": [ + "upload", + "cloud" + ], + "charRef": 61547 + }, + { + "css": "reply", + "code": 61714, + "uid": "c6be5a58ee4e63a5ec399c2b0d15cf2c", + "search": [ + "reply" + ], + "charRef": 61548 + }, + { + "css": "reply-all", + "code": 61730, + "uid": "1b5597a3bacaeca6600e88ae36d02e0a", + "search": [ + "reply" + ], + "charRef": 61549 + }, + { + "css": "forward", + "code": 10150, + "uid": "3d39c828009c04ddb6764c0b04cd2439", + "search": [ + "forward" + ], + "charRef": 61550 + }, + { + "css": "quote-left", + "code": 61709, + "uid": "ab95e1351ebaec5850101097cbf7097f", + "search": [ + "quote" + ], + "charRef": 61551 + }, + { + "css": "quote-right", + "code": 61710, + "uid": "d745d7c05b94e609decabade2cae12cb", + "search": [ + "quote" + ], + "charRef": 61552 + }, + { + "css": "code", + "code": 61729, + "uid": "7034e4d22866af82bef811f52fb1ba46", + "search": [ + "code" + ], + "charRef": 61553 + }, + { + "css": "export", + "code": 59157, + "uid": "895405dfac8a3b7b2f23b183c6608ee6", + "search": [ + "export", + "share", + "share-permalink" + ], + "charRef": 61554 + }, + { + "css": "export-alt", + "code": 61773, + "uid": "13b9eebfea581ad8e756ee7a18a7cba8", + "search": [ + "export", + "share" + ], + "charRef": 61555 + }, + { + "css": "share", + "code": 61920, + "uid": "4aad6bb50b02c18508aae9cbe14e784e", + "search": [ + "share" + ], + "charRef": 61556 + }, + { + "css": "share-squared", + "code": 61921, + "uid": "4c1f3c0b331d5f72c6a38d7bb7632675", + "search": [ + "share" + ], + "charRef": 61557 + }, + { + "css": "pencil", + "code": 9998, + "uid": "d35a1d35efeb784d1dc9ac18b9b6c2b6", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 61558 + }, + { + "css": "pencil-squared", + "code": 61771, + "uid": "44fae3bfdd54754dc68ec50d37efea37", + "search": [ + "pencil", + "edit" + ], + "charRef": 61559 + }, + { + "css": "edit", + "code": 9997, + "uid": "41087bc74d4b20b55059c60a33bf4008", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 61560 + }, + { + "css": "print", + "code": 59158, + "uid": "7277ded7695b2a307a5f9d50097bb64c", + "search": [ + "print" + ], + "charRef": 61561 + }, + { + "css": "retweet", + "code": 59159, + "uid": "09feb4465d9bd1364f4e301c9ddbaa92", + "search": [ + "retweet", + "twitter" + ], + "charRef": 61562 + }, + { + "css": "keyboard", + "code": 61724, + "uid": "ecb97add13804c190456025e43ec003b", + "search": [ + "keyboard", + "keyboard-o" + ], + "charRef": 61563 + }, + { + "css": "gamepad", + "code": 61723, + "uid": "0133387f2069a1b3168942b84d81dd3a", + "search": [ + "gamepad" + ], + "charRef": 61564 + }, + { + "css": "comment", + "code": 59160, + "uid": "85528017f1e6053b2253785c31047f44", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 61565 + }, + { + "css": "chat", + "code": 59168, + "uid": "dcedf50ab1ede3283d7a6c70e2fe32f3", + "search": [ + "chat", + "talk" + ], + "charRef": 61566 + }, + { + "css": "comment-empty", + "code": 61669, + "uid": "9c1376672bb4f1ed616fdd78a23667e9", + "search": [ + "comment", + "reply", + "write", + "comment-o" + ], + "charRef": 61567 + }, + { + "css": "chat-empty", + "code": 61670, + "uid": "31951fbb9820ed0690f675b3d495c8da", + "search": [ + "chat", + "talk" + ], + "charRef": 61568 + }, + { + "css": "bell", + "code": 128276, + "uid": "cd21cbfb28ad4d903cede582157f65dc", + "search": [ + "alert", + "bell", + "jingle", + "bell-o" + ], + "charRef": 61569 + }, + { + "css": "bell-alt", + "code": 61683, + "uid": "671f29fa10dda08074a4c6a341bb4f39", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 61570 + }, + { + "css": "bell-off", + "code": 61942, + "uid": "563683020e0bf9f22f3f055a69b5c57a", + "search": [ + "bell" + ], + "charRef": 61571 + }, + { + "css": "bell-off-empty", + "code": 61943, + "uid": "8a074400a056c59d389f2d0517281bd5", + "search": [ + "bell" + ], + "charRef": 61572 + }, + { + "css": "attention-alt", + "code": 61738, + "uid": "00391fac5d419345ffcccd95b6f76263", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 61573 + }, + { + "css": "attention", + "code": 9888, + "uid": "c76b7947c957c9b78b11741173c8349b", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 61574 + }, + { + "css": "attention-circled", + "code": 10071, + "uid": "b035c28eba2b35c6ffe92aee8b0df507", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 61575 + }, + { + "css": "location", + "code": 59172, + "uid": "0d08dbb1dd648a43bdea81b7e6c9e036", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 61576 + }, + { + "css": "direction", + "code": 61732, + "uid": "921e3974e54ff9e8b7cd906a3dc74636", + "search": [ + "direction", + "location", + "location-arrow" + ], + "charRef": 61577 + }, + { + "css": "compass", + "code": 61774, + "uid": "e5d624264734620fa9f98d59e6dc941f", + "search": [ + "compass" + ], + "charRef": 61578 + }, + { + "css": "trash", + "code": 61944, + "uid": "bbfb51903f40597f0b70fd75bc7b5cac", + "search": [ + "trash", + "trash-o" + ], + "charRef": 61579 + }, + { + "css": "trash-empty", + "code": 59177, + "uid": "f48ae54adfb27d8ada53d0fd9e34ee10", + "search": [ + "trash", + "delete" + ], + "charRef": 61580 + }, + { + "css": "doc", + "code": 128196, + "uid": "1b5a5d7b7e3c71437f5a26befdd045ed", + "search": [ + "doc", + "file", + "article" + ], + "charRef": 61581 + }, + { + "css": "docs", + "code": 61637, + "uid": "c8585e1e5b0467f28b70bce765d5840c", + "search": [ + "doc", + "file", + "article", + "copy" + ], + "charRef": 61582 + }, + { + "css": "doc-text", + "code": 61686, + "uid": "5408be43f7c42bccee419c6be53fdef5", + "search": [ + "doc", + "file", + "article", + "file-text-o" + ], + "charRef": 61583 + }, + { + "css": "doc-inv", + "code": 61787, + "uid": "178053298e3e5b03551d754d4b9acd8b", + "search": [ + "doc", + "file", + "article" + ], + "charRef": 61584 + }, + { + "css": "doc-text-inv", + "code": 61788, + "uid": "c08a1cde48d96cba21d8c05fa7d7feb1", + "search": [ + "doc", + "file", + "article" + ], + "charRef": 61585 + }, + { + "css": "file-pdf", + "code": 61889, + "uid": "9daa1fdf0838118518a7e22715e83abc", + "search": [ + "file", + "pdf", + "file-pdf-o" + ], + "charRef": 61586 + }, + { + "css": "file-word", + "code": 61890, + "uid": "310ffd629da85142bc8669f010556f2d", + "search": [ + "file", + "word" + ], + "charRef": 61587 + }, + { + "css": "file-excel", + "code": 61891, + "uid": "f761c3bbe16ba2d332914ecb28e7a042", + "search": [ + "file", + "excel" + ], + "charRef": 61588 + }, + { + "css": "file-powerpoint", + "code": 61892, + "uid": "edcd4022de8d8df266ef7c42d2658ca5", + "search": [ + "file", + "powerpoint" + ], + "charRef": 61589 + }, + { + "css": "file-image", + "code": 61893, + "uid": "3c961c1a8d874815856fc6637dc5a13c", + "search": [ + "file", + "image", + "picture" + ], + "charRef": 61590 + }, + { + "css": "file-archive", + "code": 61894, + "uid": "e80ae555c1413a4ec18b33fb348b4049", + "search": [ + "file", + "archive", + "file-zip-o" + ], + "charRef": 61591 + }, + { + "css": "file-audio", + "code": 61895, + "uid": "81db033e704eb7c586a365559d7c0f36", + "search": [ + "file", + "audio", + "sound" + ], + "charRef": 61592 + }, + { + "css": "file-video", + "code": 61896, + "uid": "dd69d9aa589ea7bc0a82a3fe67039f4b", + "search": [ + "file", + "video", + "movie" + ], + "charRef": 61593 + }, + { + "css": "file-code", + "code": 61897, + "uid": "26613a2e6bc41593c54bead46f8c8ee3", + "search": [ + "file", + "code" + ], + "charRef": 61594 + }, + { + "css": "folder", + "code": 128193, + "uid": "f8aa663c489bcbd6e68ec8147dca841e", + "search": [ + "folder" + ], + "charRef": 61595 + }, + { + "css": "folder-open", + "code": 128194, + "uid": "c95735c17a10af81448c7fed98a04546", + "search": [ + "folder" + ], + "charRef": 61596 + }, + { + "css": "folder-empty", + "code": 61716, + "uid": "b091a8bd0fdade174951f17d936f51e4", + "search": [ + "folder" + ], + "charRef": 61597 + }, + { + "css": "folder-open-empty", + "code": 61717, + "uid": "6533bdc16ab201eb3f3b27ce989cab33", + "search": [ + "folder" + ], + "charRef": 61598 + }, + { + "css": "box", + "code": 61831, + "uid": "04ff8d6592fe548b332b27ed87ce397a", + "search": [ + "box" + ], + "charRef": 61599 + }, + { + "css": "rss", + "code": 61598, + "uid": "72b1277834cba5b7944b0a6cac7ddb0d", + "search": [ + "rss" + ], + "charRef": 61600 + }, + { + "css": "rss-squared", + "code": 61763, + "uid": "de5f0a564ccf8816325330e292e11533", + "search": [ + "rss" + ], + "charRef": 61601 + }, + { + "css": "phone", + "code": 128222, + "uid": "9f7e588c66cfd6891f6f507cf6f6596b", + "search": [ + "phone", + "telephone", + "call" + ], + "charRef": 61602 + }, + { + "css": "phone-squared", + "code": 61592, + "uid": "ec488dfd1f548948c09671ca5a60ec92", + "search": [ + "phone" + ], + "charRef": 61603 + }, + { + "css": "fax", + "code": 61868, + "uid": "5cbe092278ff71fc27c920298b0f3ca3", + "search": [ + "fax" + ], + "charRef": 61604 + }, + { + "css": "menu", + "code": 61641, + "uid": "559647a6f430b3aeadbecd67194451dd", + "search": [ + "menu" + ], + "charRef": 61605 + }, + { + "css": "cog", + "code": 9881, + "uid": "e99461abfef3923546da8d745372c995", + "search": [ + "settings", + "cog", + "gear", + "params" + ], + "charRef": 61606 + }, + { + "css": "cog-alt", + "code": 9967, + "uid": "98687378abd1faf8f6af97c254eb6cd6", + "search": [ + "settings", + "cog", + "gear", + "params" + ], + "charRef": 61607 + }, + { + "css": "wrench", + "code": 128295, + "uid": "5bb103cd29de77e0e06a52638527b575", + "search": [ + "wrench", + "tools", + "settings", + "params" + ], + "charRef": 61608 + }, + { + "css": "sliders", + "code": 61918, + "uid": "21b42d3c3e6be44c3cc3d73042faa216", + "search": [ + "sliders", + "equalizer", + "settings" + ], + "charRef": 61609 + }, + { + "css": "basket", + "code": 59197, + "uid": "9affc98d652b86628d650ee58dbf0357", + "search": [ + "basket", + "shopping", + "cart", + "shopping-cart" + ], + "charRef": 61610 + }, + { + "css": "cart-plus", + "code": 61975, + "uid": "cddbeffea9d90c5db93d5d3e77b8893e", + "search": [ + "cart", + "basket" + ], + "charRef": 61611 + }, + { + "css": "cart-arrow-down", + "code": 61976, + "uid": "93c35534e6b079466c4676cdedcdb7c1", + "search": [ + "cart", + "basket" + ], + "charRef": 61612 + }, + { + "css": "calendar", + "code": 128197, + "uid": "531bc468eecbb8867d822f1c11f1e039", + "search": [ + "calendar", + "date" + ], + "charRef": 61613 + }, + { + "css": "calendar-empty", + "code": 61747, + "uid": "ead4c82d04d7758db0f076584893a8c1", + "search": [ + "calendar" + ], + "charRef": 61614 + }, + { + "css": "login", + "code": 59200, + "uid": "3a00327e61b997b58518bd43ed83c3df", + "search": [ + "login", + "signin", + "enter", + "sign-in" + ], + "charRef": 61615 + }, + { + "css": "logout", + "code": 59201, + "uid": "0d20938846444af8deb1920dc85a29fb", + "search": [ + "logout", + "signout", + "exit", + "sign-out" + ], + "charRef": 61616 + }, + { + "css": "mic", + "code": 61744, + "uid": "19c50c52858a81de58f9db488aba77bc", + "search": [ + "mic" + ], + "charRef": 61617 + }, + { + "css": "mute", + "code": 61745, + "uid": "43c629249e2cca7e73cd4ef410c9551f", + "search": [ + "mic", + "mute" + ], + "charRef": 61618 + }, + { + "css": "volume-off", + "code": 128263, + "uid": "e44601720c64e6bb6a2d5cba6b0c588c", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 61619 + }, + { + "css": "volume-down", + "code": 128265, + "uid": "fee6e00f36e8ca8ef3e4a62caa213bf6", + "search": [ + "volume", + "sound" + ], + "charRef": 61620 + }, + { + "css": "volume-up", + "code": 128266, + "uid": "76857a03fbaa6857fe063b6c25aa98ed", + "search": [ + "volume", + "sound" + ], + "charRef": 61621 + }, + { + "css": "headphones", + "code": 127911, + "uid": "f27bba41a700af51a4dd23cf4edea61d", + "search": [ + "sound", + "music", + "headphones" + ], + "charRef": 61622 + }, + { + "css": "clock", + "code": 128340, + "uid": "598a5f2bcf3521d1615de8e1881ccd17", + "search": [ + "clock", + "time", + "clock-o" + ], + "charRef": 61623 + }, + { + "css": "lightbulb", + "code": 61675, + "uid": "5278ef7773e948d56c4d442c8c8c98cf", + "search": [ + "idea", + "lamp", + "light", + "lightbulb-o" + ], + "charRef": 61624 + }, + { + "css": "block", + "code": 128683, + "uid": "98d9c83c1ee7c2c25af784b518c522c5", + "search": [ + "block", + "deny" + ], + "charRef": 61625 + }, + { + "css": "resize-full", + "code": 59204, + "uid": "e594fc6e5870b4ab7e49f52571d52577", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 61626 + }, + { + "css": "resize-full-alt", + "code": 61618, + "uid": "b013f6403e5ab0326614e68d1850fd6b", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 61627 + }, + { + "css": "resize-small", + "code": 59206, + "uid": "3c24ee33c9487bbf18796ca6dffa1905", + "search": [ + "resize" + ], + "charRef": 61628 + }, + { + "css": "resize-vertical", + "code": 11020, + "uid": "d3b3f17bc3eb7cd809a07bbd4d178bee", + "search": [ + "resize" + ], + "charRef": 61629 + }, + { + "css": "resize-horizontal", + "code": 11021, + "uid": "3c73d058e4589b65a8d959c0fc8f153d", + "search": [ + "resize" + ], + "charRef": 61630 + }, + { + "css": "move", + "code": 61511, + "uid": "6605ee6441bf499ffa3c63d3c7409471", + "search": [ + "move" + ], + "charRef": 61631 + }, + { + "css": "zoom-in", + "code": 59216, + "uid": "0b2b66e526028a6972d51a6f10281b4b", + "search": [ + "zoom", + "scale", + "in" + ], + "charRef": 61632 + }, + { + "css": "zoom-out", + "code": 59217, + "uid": "d25d10efa900f529ad1d275657cfd30e", + "search": [ + "zoom", + "scale", + "out" + ], + "charRef": 61633 + }, + { + "css": "down-circled2", + "code": 59224, + "uid": "c53068fe21c8410b0a098b4c52c3d37e", + "search": [ + "arrow", + "down", + "download" + ], + "charRef": 61634 + }, + { + "css": "up-circled2", + "code": 59227, + "uid": "128d63150a41800e0beff55235269542", + "search": [ + "arrow", + "up", + "upload" + ], + "charRef": 61635 + }, + { + "css": "left-circled2", + "code": 61840, + "uid": "a65ca48f3fe7d6e5c60edbd943f4fdb6", + "search": [ + "arrow", + "left" + ], + "charRef": 61636 + }, + { + "css": "right-circled2", + "code": 61838, + "uid": "d0673ef38e1c458a6de52aad2a2f800d", + "search": [ + "arrow", + "right", + "arrow-circle-o-right" + ], + "charRef": 61637 + }, + { + "css": "down-dir", + "code": 9662, + "uid": "2d6150442079cbda7df64522dc24f482", + "search": [ + "down", + "arrow" + ], + "charRef": 61638 + }, + { + "css": "up-dir", + "code": 9652, + "uid": "80cd1022bd9ea151d554bec1fa05f2de", + "search": [ + "up", + "arrow" + ], + "charRef": 61639 + }, + { + "css": "left-dir", + "code": 9666, + "uid": "9dc654095085167524602c9acc0c5570", + "search": [ + "left", + "arrow" + ], + "charRef": 61640 + }, + { + "css": "right-dir", + "code": 9656, + "uid": "fb1c799ffe5bf8fb7f8bcb647c8fe9e6", + "search": [ + "right", + "arrow" + ], + "charRef": 61641 + }, + { + "css": "down-open", + "code": 59228, + "uid": "ccddff8e8670dcd130e3cb55fdfc2fd0", + "search": [ + "arrow", + "down" + ], + "charRef": 61642 + }, + { + "css": "left-open", + "code": 59229, + "uid": "d870630ff8f81e6de3958ecaeac532f2", + "search": [ + "arrow", + "left" + ], + "charRef": 61643 + }, + { + "css": "right-open", + "code": 59230, + "uid": "399ef63b1e23ab1b761dfbb5591fa4da", + "search": [ + "arrow", + "right" + ], + "charRef": 61644 + }, + { + "css": "up-open", + "code": 59231, + "uid": "fe6697b391355dec12f3d86d6d490397", + "search": [ + "arrow", + "up" + ], + "charRef": 61645 + }, + { + "css": "angle-left", + "code": 61700, + "uid": "f3f90c8c89795da30f7444634476ea4f", + "search": [], + "charRef": 61646 + }, + { + "css": "angle-right", + "code": 61701, + "uid": "7bf14281af5633a597f85b061ef1cfb9", + "search": [ + "angle", + "right" + ], + "charRef": 61647 + }, + { + "css": "angle-up", + "code": 61702, + "uid": "5de9370846a26947e03f63142a3f1c07", + "search": [ + "angle", + "up" + ], + "charRef": 61648 + }, + { + "css": "angle-down", + "code": 61703, + "uid": "e4dde1992f787163e2e2b534b8c8067d", + "search": [ + "angle", + "down" + ], + "charRef": 61649 + }, + { + "css": "angle-circled-left", + "code": 61751, + "uid": "8933c2579166c2ee56ae40dc6a0b4dc6", + "search": [ + "angle", + "left", + "chevron-circle-left" + ], + "charRef": 61650 + }, + { + "css": "angle-circled-right", + "code": 61752, + "uid": "94089b37297572e936b0943bcfa041d3", + "search": [ + "angle", + "right", + "chevron-circle-right" + ], + "charRef": 61651 + }, + { + "css": "angle-circled-up", + "code": 61753, + "uid": "8cbd5bcfb00043b8094fd7ac21ae5e06", + "search": [ + "angle", + "up", + "chevron-circle-up" + ], + "charRef": 61652 + }, + { + "css": "angle-circled-down", + "code": 61754, + "uid": "c35e0796f6f806945a44b1655ce7bbe7", + "search": [ + "angle", + "down", + "chevron-circle-down" + ], + "charRef": 61653 + }, + { + "css": "angle-double-left", + "code": 61696, + "uid": "745f12abe1472d14f8f658de7e5aba66", + "search": [ + "angle", + "left" + ], + "charRef": 61654 + }, + { + "css": "angle-double-right", + "code": 61697, + "uid": "fdfbd1fcbd4cb229716a810801a5f207", + "search": [ + "angle", + "right" + ], + "charRef": 61655 + }, + { + "css": "angle-double-up", + "code": 61698, + "uid": "63b3012c8cbe3654ba5bea598235aa3a", + "search": [ + "angle", + "up" + ], + "charRef": 61656 + }, + { + "css": "angle-double-down", + "code": 61699, + "uid": "dfec4ffa849d8594c2e4b86f6320b8a6", + "search": [ + "angle", + "down" + ], + "charRef": 61657 + }, + { + "css": "down", + "code": 61813, + "uid": "f06941dfcb90dc24b987d810898c4310", + "search": [ + "arrow", + "down" + ], + "charRef": 61658 + }, + { + "css": "left", + "code": 61815, + "uid": "f6d72aa5ef8e8f0e553012af9a29a87e", + "search": [ + "arrow", + "left" + ], + "charRef": 61659 + }, + { + "css": "right", + "code": 61816, + "uid": "fb94e23ae1e7660aa63cc5f351ec7560", + "search": [ + "arrow", + "right" + ], + "charRef": 61660 + }, + { + "css": "up", + "code": 61814, + "uid": "720f98e7580b7987c8dc542513d1d440", + "search": [ + "arrow", + "up" + ], + "charRef": 61661 + }, + { + "css": "down-big", + "code": 8595, + "uid": "1c4068ed75209e21af36017df8871802", + "search": [ + "arrow", + "down", + "arrow-down" + ], + "charRef": 61662 + }, + { + "css": "left-big", + "code": 8592, + "uid": "555ef8c86832e686fef85f7af2eb7cde", + "search": [ + "arrow", + "left", + "arrow-left" + ], + "charRef": 61663 + }, + { + "css": "right-big", + "code": 8594, + "uid": "ad6b3fbb5324abe71a9c0b6609cbb9f1", + "search": [ + "arrow", + "right", + "arrow-right" + ], + "charRef": 61664 + }, + { + "css": "up-big", + "code": 8593, + "uid": "95376bf082bfec6ce06ea1cda7bd7ead", + "search": [ + "arrow", + "up", + "arrow-up" + ], + "charRef": 61665 + }, + { + "css": "right-hand", + "code": 9758, + "uid": "aa0d9175a3919a260a4012d560e9f01e", + "search": [ + "hand", + "right", + "arrow" + ], + "charRef": 61666 + }, + { + "css": "left-hand", + "code": 9756, + "uid": "3d99d345645f43e31e9e0fd48be37e9c", + "search": [ + "hand", + "left", + "arrow" + ], + "charRef": 61667 + }, + { + "css": "up-hand", + "code": 9757, + "uid": "034e645aa3bad56ce68389a816547c87", + "search": [ + "hand", + "up", + "arrow" + ], + "charRef": 61668 + }, + { + "css": "down-hand", + "code": 9759, + "uid": "beb43b8df442eac4b8d35f528d5ed5af", + "search": [ + "hand", + "down", + "arrow" + ], + "charRef": 61669 + }, + { + "css": "left-circled", + "code": 61608, + "uid": "6855131631509e8795730ce062045ea1", + "search": [ + "left", + "arrow" + ], + "charRef": 61670 + }, + { + "css": "right-circled", + "code": 61609, + "uid": "19b04848ae7332d2c0ea2a9e19064037", + "search": [ + "right", + "arrow" + ], + "charRef": 61671 + }, + { + "css": "up-circled", + "code": 61610, + "uid": "2b8e9b027181aafd210bf29c5486d4a0", + "search": [ + "up", + "arrow" + ], + "charRef": 61672 + }, + { + "css": "down-circled", + "code": 61611, + "uid": "55ae6ea25cd707fe34af5b52b2001cdc", + "search": [ + "down", + "arrow" + ], + "charRef": 61673 + }, + { + "css": "cw", + "code": 10227, + "uid": "bc71f4c6e53394d5ba46b063040014f1", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 61674 + }, + { + "css": "ccw", + "code": 10226, + "uid": "f9c3205df26e7778abac86183aefdc99", + "search": [ + "reload", + "undo", + "arrow" + ], + "charRef": 61675 + }, + { + "css": "arrows-cw", + "code": 59232, + "uid": "a73c5deb486c8d66249811642e5d719a", + "search": [ + "reload", + "refresh", + "update", + "sync" + ], + "charRef": 61676 + }, + { + "css": "level-up", + "code": 61768, + "uid": "dea706a9bd3144316ce37406ec10f469", + "search": [ + "arrow", + "level", + "up" + ], + "charRef": 61677 + }, + { + "css": "level-down", + "code": 61769, + "uid": "4684e690bad65fb618329dfe52017475", + "search": [ + "arrow", + "level", + "down" + ], + "charRef": 61678 + }, + { + "css": "shuffle", + "code": 128256, + "uid": "37c5ab63f10d7ad0b84d0978dcd0c7a8", + "search": [ + "shuffle" + ], + "charRef": 61679 + }, + { + "css": "exchange", + "code": 61676, + "uid": "6020aff067fc3c119cdd75daa5249220", + "search": [ + "exchange", + "swap", + "switch", + "arrows" + ], + "charRef": 61680 + }, + { + "css": "history", + "code": 61914, + "uid": "d4816c0845aa43767213d45574b3b145", + "search": [ + "history" + ], + "charRef": 61681 + }, + { + "css": "expand", + "code": 61776, + "uid": "84bb9695b8662fa4783242f84c9e4682", + "search": [ + "expand" + ], + "charRef": 61682 + }, + { + "css": "collapse", + "code": 61777, + "uid": "7960517a504e42aea0641f15bc55fbed", + "search": [ + "collapse" + ], + "charRef": 61683 + }, + { + "css": "expand-right", + "code": 61778, + "uid": "ed5a38704f0329e610ee1c92bec3ad3d", + "search": [ + "expand" + ], + "charRef": 61684 + }, + { + "css": "collapse-left", + "code": 61841, + "uid": "ea2ec99fbce03864e593bbf4f302a79d", + "search": [ + "collapse" + ], + "charRef": 61685 + }, + { + "css": "play", + "code": 9654, + "uid": "ce06b5805120d0c2f8d60cd3f1a4fdb5", + "search": [ + "play", + "player" + ], + "charRef": 61686 + }, + { + "css": "play-circled", + "code": 61764, + "uid": "5717236f6134afe2d2a278a5c9b3927a", + "search": [ + "player", + "play" + ], + "charRef": 61687 + }, + { + "css": "play-circled2", + "code": 59233, + "uid": "e835d9d0f2ee39ae01b01cc6a6fa24ab", + "search": [ + "play", + "player" + ], + "charRef": 61688 + }, + { + "css": "stop", + "code": 9642, + "uid": "b624a1e512819d410ddbee84e6918b9d", + "search": [ + "stop", + "player" + ], + "charRef": 61689 + }, + { + "css": "pause", + "code": 9097, + "uid": "0b28050bac9d3facf2f0226db643ece0", + "search": [ + "pause", + "player" + ], + "charRef": 61690 + }, + { + "css": "to-end", + "code": 9197, + "uid": "c47efa0e3e74f6ba4c2562c1258fff1f", + "search": [ + "right", + "player" + ], + "charRef": 61691 + }, + { + "css": "to-end-alt", + "code": 59234, + "uid": "7ea35a8fc7e676c78e99cab2d4bc8653", + "search": [ + "right", + "player" + ], + "charRef": 61692 + }, + { + "css": "to-start", + "code": 9198, + "uid": "12052b30d23a1a70d6b32962d5464cae", + "search": [ + "left", + "player" + ], + "charRef": 61693 + }, + { + "css": "to-start-alt", + "code": 59235, + "uid": "6b5450145d620234f07ffcbfbb671074", + "search": [ + "left", + "player" + ], + "charRef": 61694 + }, + { + "css": "fast-fw", + "code": 9193, + "uid": "4e511190b60f329d08301eb6869c5130", + "search": [ + "right", + "player" + ], + "charRef": 61695 + }, + { + "css": "fast-bw", + "code": 9194, + "uid": "b3d902fcead809e3a64c7ddcda497a6c", + "search": [ + "left", + "player" + ], + "charRef": 61696 + }, + { + "css": "eject", + "code": 11983, + "uid": "91b141af48402743aa3503d0a7007132", + "search": [ + "eject", + "player" + ], + "charRef": 61697 + }, + { + "css": "target", + "code": 127919, + "uid": "e75c54c282c0bf22186c5c7ec4b03eac", + "search": [ + "target" + ], + "charRef": 61698 + }, + { + "css": "signal", + "code": 128246, + "uid": "d407a4707f719b042ed2ad28d2619d7e", + "search": [ + "broadcast", + "wifi", + "signal" + ], + "charRef": 61699 + }, + { + "css": "wifi", + "code": 61931, + "uid": "cd4bfdae4dc89b175ff49330ce29611a", + "search": [ + "wifi", + "signal" + ], + "charRef": 61700 + }, + { + "css": "award", + "code": 127945, + "uid": "ab656e280958018a7859eba9a1eabbc7", + "search": [ + "top", + "trophy", + "prize", + "award" + ], + "charRef": 61701 + }, + { + "css": "desktop", + "code": 61704, + "uid": "757afacc32d82967975cbb3b45cfb41b", + "search": [ + "desktop", + "screen", + "monitor" + ], + "charRef": 61702 + }, + { + "css": "laptop", + "code": 61705, + "uid": "500fc1f109021e4b1de4deda2f7ed399", + "search": [ + "laptop", + "notebook" + ], + "charRef": 61703 + }, + { + "css": "tablet", + "code": 61706, + "uid": "f001fc3d4daa7da078e8c971e4f36977", + "search": [ + "tablet" + ], + "charRef": 61704 + }, + { + "css": "mobile", + "code": 61707, + "uid": "0357f7abbc0babf43509669f332e41e6", + "search": [ + "mobile", + "phone" + ], + "charRef": 61705 + }, + { + "css": "inbox", + "code": 59255, + "uid": "c7a75a25880928fe76981a53eca4f926", + "search": [ + "inbox", + "stack" + ], + "charRef": 61706 + }, + { + "css": "globe", + "code": 127758, + "uid": "197375a3cea8cb90b02d06e4ddf1433d", + "search": [ + "globe", + "world" + ], + "charRef": 61707 + }, + { + "css": "sun", + "code": 61829, + "uid": "aa035df0908c4665c269b7b09a5596f3", + "search": [ + "sun", + "sun-o" + ], + "charRef": 61708 + }, + { + "css": "cloud", + "code": 9729, + "uid": "2c413e78faf1d6631fd7b094d14c2253", + "search": [ + "cloud" + ], + "charRef": 61709 + }, + { + "css": "flash", + "code": 9889, + "uid": "3212f42c65d41ed91cb435d0490e29ed", + "search": [ + "flash", + "bolt" + ], + "charRef": 61710 + }, + { + "css": "moon", + "code": 61830, + "uid": "567e3e257f2cc8fba2c12bf691c9f2d8", + "search": [ + "moon" + ], + "charRef": 61711 + }, + { + "css": "umbrella", + "code": 9730, + "uid": "24ca41ab002c09de6e89b28f9d599508", + "search": [ + "umbrella" + ], + "charRef": 61712 + }, + { + "css": "flight", + "code": 9992, + "uid": "297fe6c2ef08198b03d706ba52f51b7f", + "search": [ + "flight", + "plane", + "airplane" + ], + "charRef": 61713 + }, + { + "css": "fighter-jet", + "code": 61691, + "uid": "cb36cbe4e2dac9545e32c3d80a7c6e03", + "search": [ + "flight", + "plane", + "airplane", + "fly", + "jet" + ], + "charRef": 61714 + }, + { + "css": "paper-plane", + "code": 61912, + "uid": "38575a803c4da31ce20d77e1e1236bcb", + "search": [ + "flight", + "plane", + "airplane", + "fly" + ], + "charRef": 61715 + }, + { + "css": "paper-plane-empty", + "code": 61913, + "uid": "4b2321afcbe0505a70b80abd5c25e09b", + "search": [ + "flight", + "plane", + "airplane", + "fly" + ], + "charRef": 61716 + }, + { + "css": "space-shuttle", + "code": 61847, + "uid": "d650df2fd7c4e27d9185d90a1c12a881", + "search": [ + "space", + "shuttle" + ], + "charRef": 61717 + }, + { + "css": "leaf", + "code": 127810, + "uid": "19e7b342a5e6bd0cd86de6d6208486a4", + "search": [ + "leaf" + ], + "charRef": 61718 + }, + { + "css": "font", + "code": 59257, + "uid": "f9cbf7508cd04145ade2800169959eef", + "search": [ + "editor", + "font" + ], + "charRef": 61719 + }, + { + "css": "bold", + "code": 59258, + "uid": "02cca871bb69da75e8ee286b7055832c", + "search": [ + "editor", + "bold" + ], + "charRef": 61720 + }, + { + "css": "medium", + "code": 62010, + "uid": "bf09b1c6561dc0ced707476e2cd83d29", + "search": [ + "medium" + ], + "charRef": 61721 + }, + { + "css": "italic", + "code": 59259, + "uid": "a8cb1c217f02b073db3670c061cc54d2", + "search": [ + "editor", + "italic" + ], + "charRef": 61722 + }, + { + "css": "header", + "code": 61916, + "uid": "0c708edd8fae2376b3370aa56d40cf9e", + "search": [ + "header" + ], + "charRef": 61723 + }, + { + "css": "paragraph", + "code": 61917, + "uid": "c5845105a87df2ee1999826d90622f6a", + "search": [ + "paragraph" + ], + "charRef": 61724 + }, + { + "css": "text-height", + "code": 59260, + "uid": "c009d417f87d6a27bb5a1cefd30b6cbd", + "search": [ + "editor", + "text", + "height" + ], + "charRef": 61725 + }, + { + "css": "text-width", + "code": 59261, + "uid": "13a971bcccd2dda26d4d4eccd8593f8a", + "search": [ + "editor", + "text", + "width" + ], + "charRef": 61726 + }, + { + "css": "align-left", + "code": 59262, + "uid": "f4f0e849b805be1f6d76b65581cb3b8b", + "search": [ + "editor", + "align", + "left" + ], + "charRef": 61727 + }, + { + "css": "align-center", + "code": 59263, + "uid": "ae6336c46d73af999fe7460c089abb4d", + "search": [ + "editor", + "align", + "center" + ], + "charRef": 61728 + }, + { + "css": "align-right", + "code": 59264, + "uid": "e1e7306b47c3c5e6faecce9d32571381", + "search": [ + "editor", + "align", + "right" + ], + "charRef": 61729 + }, + { + "css": "align-justify", + "code": 59265, + "uid": "25a81737628d1e654a30ad412d7d6dd7", + "search": [ + "editor", + "align", + "justify" + ], + "charRef": 61730 + }, + { + "css": "list", + "code": 59266, + "uid": "48b87105bd38c20315f1b705b8c7b38c", + "search": [ + "editor", + "list" + ], + "charRef": 61731 + }, + { + "css": "indent-left", + "code": 59267, + "uid": "594e9271c08ff732c04b3bf3117b9040", + "search": [ + "editor", + "indent" + ], + "charRef": 61732 + }, + { + "css": "indent-right", + "code": 59268, + "uid": "4d2dfc45d8176b1f26aed973fa84a91e", + "search": [ + "editor", + "indent" + ], + "charRef": 61733 + }, + { + "css": "list-bullet", + "code": 61642, + "uid": "a2a74f5e7b7d9ba054897d8c795a326a", + "search": [ + "list", + "list-ul" + ], + "charRef": 61734 + }, + { + "css": "list-numbered", + "code": 61643, + "uid": "f6766a8b042c2453a4e153af03294383", + "search": [ + "list" + ], + "charRef": 61735 + }, + { + "css": "strike", + "code": 61644, + "uid": "61c242c9e2134d5864d7fdd57b3c9289", + "search": [ + "strike" + ], + "charRef": 61736 + }, + { + "css": "underline", + "code": 61645, + "uid": "d4a4a38a40b728f46dad1de4ac950231", + "search": [ + "underline" + ], + "charRef": 61737 + }, + { + "css": "superscript", + "code": 61739, + "uid": "4e88371fb8857dacc1f66afe6314e426", + "search": [ + "editor", + "superscript" + ], + "charRef": 61738 + }, + { + "css": "subscript", + "code": 61740, + "uid": "3d1c929dbc966992185ce749548c1b2c", + "search": [ + "editor", + "subscript" + ], + "charRef": 61739 + }, + { + "css": "table", + "code": 61646, + "uid": "8fb55fd696d9a0f58f3b27c1d8633750", + "search": [ + "table" + ], + "charRef": 61740 + }, + { + "css": "columns", + "code": 61659, + "uid": "53dd31a6cc6438192b2d7b09b1c1dd45", + "search": [ + "columns" + ], + "charRef": 61741 + }, + { + "css": "crop", + "code": 61733, + "uid": "09bdae120f85e79f2db16145a9e1f6d8", + "search": [ + "crop" + ], + "charRef": 61742 + }, + { + "css": "scissors", + "code": 9986, + "uid": "8772331a9fec983cdb5d72902a6f9e0e", + "search": [ + "scissors", + "cut" + ], + "charRef": 61743 + }, + { + "css": "paste", + "code": 61674, + "uid": "b429436ec5a518c78479d44ef18dbd60", + "search": [ + "paste" + ], + "charRef": 61744 + }, + { + "css": "briefcase", + "code": 128188, + "uid": "053b757d97042e1c94276200c7b64b91", + "search": [ + "briefcase" + ], + "charRef": 61745 + }, + { + "css": "suitcase", + "code": 61682, + "uid": "5ccf1ed249fd9d723ec1ce8629a9f507", + "search": [ + "suitcase" + ], + "charRef": 61746 + }, + { + "css": "ellipsis", + "code": 61761, + "uid": "107ce08c7231097c7447d8f4d059b55f", + "search": [ + "ellipsis" + ], + "charRef": 61747 + }, + { + "css": "ellipsis-vert", + "code": 61762, + "uid": "750058837a91edae64b03d60fc7e81a7", + "search": [ + "ellipsis" + ], + "charRef": 61748 + }, + { + "css": "off", + "code": 59278, + "uid": "8b9e6a8dd8f67f7c003ed8e7e5ee0857", + "search": [ + "off" + ], + "charRef": 61749 + }, + { + "css": "road", + "code": 59279, + "uid": "ecede48deb16179e5ef9a3f8ffae62f4", + "search": [ + "road" + ], + "charRef": 61750 + }, + { + "css": "list-alt", + "code": 59280, + "uid": "c819c6225685bae2eed1b8da13e629fa", + "search": [ + "list" + ], + "charRef": 61751 + }, + { + "css": "qrcode", + "code": 59281, + "uid": "fd45bb961d08f9f2092f0df3fba29fe9", + "search": [ + "qrcode" + ], + "charRef": 61752 + }, + { + "css": "barcode", + "code": 59282, + "uid": "aa991e8e66ac54b33f0a4b0555597b08", + "search": [ + "barcode" + ], + "charRef": 61753 + }, + { + "css": "book", + "code": 128213, + "uid": "9755f76110ae4d12ac5f9466c9152031", + "search": [ + "book" + ], + "charRef": 61754 + }, + { + "css": "adjust", + "code": 59283, + "uid": "ca90da02d2c6a3183f2458e4dc416285", + "search": [ + "adjust", + "contrast" + ], + "charRef": 61755 + }, + { + "css": "tint", + "code": 59284, + "uid": "83458acd9f38d03ec0226ce82a83c0f4", + "search": [ + "tint" + ], + "charRef": 61756 + }, + { + "css": "toggle-off", + "code": 61956, + "uid": "2a4e6c99b732a57da40e32fa2a7800a4", + "search": [ + "toggle", + "switch", + "off", + "disable" + ], + "charRef": 61757 + }, + { + "css": "toggle-on", + "code": 61957, + "uid": "3256ef03b16e7ab51235bc7378b53bb5", + "search": [ + "toggle", + "switch", + "on", + "enable" + ], + "charRef": 61758 + }, + { + "css": "check", + "code": 9745, + "uid": "dd6c6b221a1088ff8a9b9cd32d0b3dd5", + "search": [ + "check", + "check-square-o" + ], + "charRef": 61759 + }, + { + "css": "check-empty", + "code": 61590, + "uid": "4b900d04e8ab8c82f080c1cfbac5772c", + "search": [ + "check", + "empty", + "square", + "square-o" + ], + "charRef": 61760 + }, + { + "css": "circle", + "code": 61713, + "uid": "130380e481a7defc690dfb24123a1f0c", + "search": [ + "circle" + ], + "charRef": 61761 + }, + { + "css": "circle-empty", + "code": 61708, + "uid": "422e07e5afb80258a9c4ed1706498f8a", + "search": [ + "circle", + "radio" + ], + "charRef": 61762 + }, + { + "css": "circle-thin", + "code": 61915, + "uid": "5774d0a0e50f6eefc8be01bd761e5dd3", + "search": [ + "circle" + ], + "charRef": 61763 + }, + { + "css": "circle-notch", + "code": 61902, + "uid": "4ffd8122933b9ee0183b925e1554969f", + "search": [ + "circle", + "notch", + "circle-o-notch" + ], + "charRef": 61764 + }, + { + "css": "dot-circled", + "code": 61842, + "uid": "81bb68665e8e595505272a746db07c7a", + "search": [ + "dot", + "radio" + ], + "charRef": 61765 + }, + { + "css": "asterisk", + "code": 10033, + "uid": "823a9e02e643318116fea40a00190e4e", + "search": [ + "asterisk" + ], + "charRef": 61766 + }, + { + "css": "gift", + "code": 127873, + "uid": "28f308aa0a07a67433f54c089c400d82", + "search": [ + "gift", + "present", + "package", + "box" + ], + "charRef": 61767 + }, + { + "css": "fire", + "code": 128293, + "uid": "254077e7c0a9e6d303b32f9c35b96a40", + "search": [ + "fire" + ], + "charRef": 61768 + }, + { + "css": "magnet", + "code": 59297, + "uid": "d20912c814d0ff9a7fd27ed1f54813cc", + "search": [ + "magnet" + ], + "charRef": 61769 + }, + { + "css": "chart-bar", + "code": 128202, + "uid": "266d5d9adf15a61800477a5acf9a4462", + "search": [ + "chart", + "bar", + "diagram", + "bar-chart" + ], + "charRef": 61770 + }, + { + "css": "chart-area", + "code": 61950, + "uid": "7d1ca956f4181a023de4b9efbed92524", + "search": [ + "chart", + "area-chart" + ], + "charRef": 61771 + }, + { + "css": "chart-pie", + "code": 61952, + "uid": "554ee96588a6c9ee632624cd051fe6fc", + "search": [ + "chart", + "pie", + "pie-chart" + ], + "charRef": 61772 + }, + { + "css": "chart-line", + "code": 61953, + "uid": "ea2d9a8c51ca42b38ef0d2a07f16d9a7", + "search": [ + "chart", + "line-chart" + ], + "charRef": 61773 + }, + { + "css": "ticket", + "code": 61765, + "uid": "d6fcb9886485b0bdb41b94521e7a3311", + "search": [ + "ticket" + ], + "charRef": 61774 + }, + { + "css": "credit-card", + "code": 128179, + "uid": "3d8cc269fdad8a4cda55a20542a84e5c", + "search": [ + "card", + "plastic", + "credit" + ], + "charRef": 61775 + }, + { + "css": "floppy", + "code": 128190, + "uid": "f4445feb55521283572ee88bc304f928", + "search": [ + "floppy", + "save" + ], + "charRef": 61776 + }, + { + "css": "megaphone", + "code": 128227, + "uid": "3e674995cacc2b09692c096ea7eb6165", + "search": [ + "megaphone", + "bullhorn" + ], + "charRef": 61777 + }, + { + "css": "hdd", + "code": 61600, + "uid": "795efd07cd5205b589c883916a76cff0", + "search": [ + "hdd", + "drive", + "disk" + ], + "charRef": 61778 + }, + { + "css": "key", + "code": 128273, + "uid": "f2aa28a2548ed3d2be718d087b65ee21", + "search": [ + "key" + ], + "charRef": 61779 + }, + { + "css": "fork", + "code": 61734, + "uid": "bc4b94dd7a9a1dd2e02f9e4648062596", + "search": [ + "fork", + "junction", + "flow" + ], + "charRef": 61780 + }, + { + "css": "rocket", + "code": 61749, + "uid": "8aa99bc60f3553bb3e31b73dd6e744c8", + "search": [ + "rocket" + ], + "charRef": 61781 + }, + { + "css": "bug", + "code": 61832, + "uid": "7432077e6a2d6aa19984ca821bb6bbda", + "search": [ + "bug" + ], + "charRef": 61782 + }, + { + "css": "certificate", + "code": 61603, + "uid": "d61be837c725a299b432dcbee2ecdae6", + "search": [ + "certificate" + ], + "charRef": 61783 + }, + { + "css": "tasks", + "code": 61614, + "uid": "9396b2d8849e0213a0f11c5fd7fcc522", + "search": [ + "tasks" + ], + "charRef": 61784 + }, + { + "css": "filter", + "code": 61616, + "uid": "4109c474ff99cad28fd5a2c38af2ec6f", + "search": [ + "filter" + ], + "charRef": 61785 + }, + { + "css": "beaker", + "code": 61635, + "uid": "0f444c61b0d2c9966016d7ddb12f5837", + "search": [ + "beaker", + "flask" + ], + "charRef": 61786 + }, + { + "css": "magic", + "code": 61648, + "uid": "ff70f7b3228702e0d590e60ed3b90bea", + "search": [ + "magic" + ], + "charRef": 61787 + }, + { + "css": "cab", + "code": 61881, + "uid": "9937d762aee170b7350b15dd02dd34a3", + "search": [ + "cab", + "auto", + "car" + ], + "charRef": 61788 + }, + { + "css": "taxi", + "code": 61882, + "uid": "5eacf9f8805e2c0bc306dcd1e709db16", + "search": [ + "taxi", + "auto", + "car" + ], + "charRef": 61789 + }, + { + "css": "truck", + "code": 128666, + "uid": "7f3d8ff1d5f6ee019f0c00ed7a86caec", + "search": [ + "truck", + "auto", + "car" + ], + "charRef": 61790 + }, + { + "css": "bus", + "code": 61959, + "uid": "5b17c7263caa553039655f2fef81ecaf", + "search": [ + "bus", + "auto" + ], + "charRef": 61791 + }, + { + "css": "bicycle", + "code": 61958, + "uid": "891d861cffd152a6474f01e77716d44e", + "search": [ + "bicycle" + ], + "charRef": 61792 + }, + { + "css": "motorcycle", + "code": 61980, + "uid": "326dd5dc5899787161184614d04a50b9", + "search": [ + "motorcycle" + ], + "charRef": 61793 + }, + { + "css": "train", + "code": 62008, + "uid": "4df54de7f9081aefcc1476068d4464e9", + "search": [ + "train" + ], + "charRef": 61794 + }, + { + "css": "subway", + "code": 62009, + "uid": "26667777684de4808cedd3783834356f", + "search": [ + "subway" + ], + "charRef": 61795 + }, + { + "css": "ship", + "code": 61978, + "uid": "3bf0956ae356f79d805fb17f4a523f24", + "search": [ + "ship", + "boat", + "swim" + ], + "charRef": 61796 + }, + { + "css": "money", + "code": 61654, + "uid": "f279f25007794fa6837ff78fe94b216e", + "search": [ + "money", + "banknote" + ], + "charRef": 61797 + }, + { + "css": "euro", + "code": 61779, + "uid": "486b835e9eebf54eee78ed12b4291b86", + "search": [ + "euro", + "money" + ], + "charRef": 61798 + }, + { + "css": "pound", + "code": 61780, + "uid": "9854f7f091bd4fdf9b8735ed66667b9d", + "search": [ + "pound", + "gpb", + "money" + ], + "charRef": 61799 + }, + { + "css": "dollar", + "code": 61781, + "uid": "026007bd17bfc67f3fe013199676f620", + "search": [ + "dollar", + "usd", + "money" + ], + "charRef": 61800 + }, + { + "css": "rupee", + "code": 61782, + "uid": "62e4fa2c664818d20ce4740cadbf9aeb", + "search": [ + "rupee", + "inr", + "money" + ], + "charRef": 61801 + }, + { + "css": "yen", + "code": 61783, + "uid": "5f61f8a682b77d2529296a8061bf9597", + "search": [ + "yen", + "jpy", + "renminbi", + "cny", + "money" + ], + "charRef": 61802 + }, + { + "css": "rouble", + "code": 61784, + "uid": "243424d56528e83e4fe9ef6e6347a2ef", + "search": [ + "rouble", + "rub", + "rur", + "ruble", + "money" + ], + "charRef": 61803 + }, + { + "css": "shekel", + "code": 61963, + "uid": "589ae2cbc6d95cc74eb2dbd3fa9c9bcd", + "search": [ + "ils", + "shekel", + "sheqel" + ], + "charRef": 61804 + }, + { + "css": "try", + "code": 61845, + "uid": "7f5801d1e299b445ad0090b0a9e94bcb", + "search": [ + "try", + "lira" + ], + "charRef": 61805 + }, + { + "css": "won", + "code": 61785, + "uid": "82f0dc5149d842219e45000bebd683fb", + "search": [ + "won", + "krw", + "money" + ], + "charRef": 61806 + }, + { + "css": "bitcoin", + "code": 61786, + "uid": "2cb15eb2b295ee3c33fab1530e18a924", + "search": [ + "bitcoin", + "money" + ], + "charRef": 61807 + }, + { + "css": "viacoin", + "code": 62007, + "uid": "77b6b5ad1966970971c43e40e8d10772", + "search": [ + "viacoin" + ], + "charRef": 61808 + }, + { + "css": "sort", + "code": 61660, + "uid": "56a21935a5d4d79b2e91ec00f760b369", + "search": [ + "sort" + ], + "charRef": 61809 + }, + { + "css": "sort-down", + "code": 61661, + "uid": "94103e1b3f1e8cf514178ec5912b4469", + "search": [ + "sort" + ], + "charRef": 61810 + }, + { + "css": "sort-up", + "code": 61662, + "uid": "65b3ce930627cabfb6ac81ac60ec5ae4", + "search": [ + "sort" + ], + "charRef": 61811 + }, + { + "css": "sort-alt-up", + "code": 61792, + "uid": "0cd2582b8c93719d066ee0affd02ac78", + "search": [ + "sort" + ], + "charRef": 61812 + }, + { + "css": "sort-alt-down", + "code": 61793, + "uid": "27b13eff5eb0ca15e01a6e65ffe6eeec", + "search": [ + "sort" + ], + "charRef": 61813 + }, + { + "css": "sort-name-up", + "code": 61789, + "uid": "3ed68ae14e9cde775121954242a412b2", + "search": [ + "sort" + ], + "charRef": 61814 + }, + { + "css": "sort-name-down", + "code": 61790, + "uid": "6586267200a42008a9fc0a1bf7ac06c7", + "search": [ + "sort" + ], + "charRef": 61815 + }, + { + "css": "sort-number-up", + "code": 61794, + "uid": "3a7b6876c1817ce3b801b86c04a9d0af", + "search": [ + "sort" + ], + "charRef": 61816 + }, + { + "css": "sort-number-down", + "code": 61795, + "uid": "b04fc30546f597a7e0a14715e6fc81ff", + "search": [ + "sort" + ], + "charRef": 61817 + }, + { + "css": "hammer", + "code": 128296, + "uid": "dec0ce0476433f7e49e096526cf89465", + "search": [ + "hammer", + "legal", + "gavel" + ], + "charRef": 61818 + }, + { + "css": "gauge", + "code": 61668, + "uid": "0bda4bc779d4c32623dec2e43bd67ee8", + "search": [ + "gauge", + "indicator", + "dashboard", + "tachometer" + ], + "charRef": 61819 + }, + { + "css": "sitemap", + "code": 61672, + "uid": "6fe95ffc3c807e62647d4f814a96e0d7", + "search": [ + "sitemap" + ], + "charRef": 61820 + }, + { + "css": "spinner", + "code": 61712, + "uid": "cda0cdcfd38f5f1d9255e722dad42012", + "search": [ + "spinner" + ], + "charRef": 61821 + }, + { + "css": "coffee", + "code": 61684, + "uid": "3a26448b711645ba1abfc86c1a6e2f30", + "search": [ + "coffee", + "cup" + ], + "charRef": 61822 + }, + { + "css": "food", + "code": 61685, + "uid": "30b79160618d99ce798e4bd11cafe3fe", + "search": [ + "food", + "eat" + ], + "charRef": 61823 + }, + { + "css": "beer", + "code": 61692, + "uid": "890bcc8897cce868f6ee65cadadde036", + "search": [ + "beer" + ], + "charRef": 61824 + }, + { + "css": "user-md", + "code": 61680, + "uid": "9e8430ce95f56720ae8e7afba291df88", + "search": [ + "medic" + ], + "charRef": 61825 + }, + { + "css": "stethoscope", + "code": 61681, + "uid": "5590d2f643b64d2d0757ae660f9c24cb", + "search": [ + "stethoscope" + ], + "charRef": 61826 + }, + { + "css": "heartbeat", + "code": 61982, + "uid": "d84a06c5ce6da9ebdc9b0a5cb94db4c4", + "search": [ + "heartbeat" + ], + "charRef": 61827 + }, + { + "css": "ambulance", + "code": 61689, + "uid": "6dbf07228006788a96eb6244b3591970", + "search": [ + "ambulance" + ], + "charRef": 61828 + }, + { + "css": "medkit", + "code": 61690, + "uid": "46120eb259799eab0dac0691137e5706", + "search": [ + "medkit" + ], + "charRef": 61829 + }, + { + "css": "h-sigh", + "code": 61693, + "uid": "6f41d9b99564a01f1fde503b7f03bf1a", + "search": [ + "hospital" + ], + "charRef": 61830 + }, + { + "css": "bed", + "code": 62006, + "uid": "df9d9b2fb366c10427ffb727943db912", + "search": [ + "bed", + "sleep" + ], + "charRef": 61831 + }, + { + "css": "hospital", + "code": 61688, + "uid": "c4adaacece4c6341a9ae1816f5ea500c", + "search": [ + "hospital" + ], + "charRef": 61832 + }, + { + "css": "building", + "code": 61687, + "uid": "3d1e04316a48ace4e2b81be58343a41c", + "search": [ + "building" + ], + "charRef": 61833 + }, + { + "css": "building-filled", + "code": 61869, + "uid": "ede2ea0a583f662b79fbb181b428c20d", + "search": [ + "building", + "building-o" + ], + "charRef": 61834 + }, + { + "css": "bank", + "code": 61852, + "uid": "8c0ffa714cecbf5144e022d9c3df4a1f", + "search": [ + "bank", + "university", + "institution", + "temple", + "columns" + ], + "charRef": 61835 + }, + { + "css": "smile", + "code": 61720, + "uid": "d862a10e1448589215be19702f98f2c1", + "search": [ + "emoticon", + "sniley", + "smile", + "happy", + "smile-o" + ], + "charRef": 61836 + }, + { + "css": "frown", + "code": 61721, + "uid": "06ddc67d609c477cd5524a7238d7850d", + "search": [ + "emoticon", + "sniley", + "frown", + "frown-o" + ], + "charRef": 61837 + }, + { + "css": "meh", + "code": 61722, + "uid": "2c5055a9c9723725f49f0593a08535af", + "search": [ + "emoticon", + "sniley", + "meh" + ], + "charRef": 61838 + }, + { + "css": "anchor", + "code": 61757, + "uid": "7a9d73c640892d4b917c706ad95d6fec", + "search": [ + "anchor" + ], + "charRef": 61839 + }, + { + "css": "terminal", + "code": 61728, + "uid": "fa10777b2d88cc64cd6e4f26ef0e5264", + "search": [ + "terminal", + "prompt" + ], + "charRef": 61840 + }, + { + "css": "eraser", + "code": 61741, + "uid": "ebc57fa8400e4ede049ac5dc665210e1", + "search": [ + "eraser" + ], + "charRef": 61841 + }, + { + "css": "puzzle", + "code": 61742, + "uid": "5f0f183e241d15cbe486bff88b188dff", + "search": [ + "puzzle" + ], + "charRef": 61842 + }, + { + "css": "shield", + "code": 61746, + "uid": "44a0e2660ac966cdfaa04deb6aac51df", + "search": [ + "shield", + "chest" + ], + "charRef": 61843 + }, + { + "css": "extinguisher", + "code": 61748, + "uid": "1e7648f03fbdc28114a00b33b059b499", + "search": [ + "extinguisher" + ], + "charRef": 61844 + }, + { + "css": "bullseye", + "code": 61760, + "uid": "c92ad3028acce9d51bae0ac82f5de8a2", + "search": [ + "bullseye" + ], + "charRef": 61845 + }, + { + "css": "wheelchair", + "code": 61843, + "uid": "8a67014b864fb93503348593979ddce3", + "search": [ + "wheelchair", + "accessibility" + ], + "charRef": 61846 + }, + { + "css": "language", + "code": 61867, + "uid": "4fc9b8c122d1b5ca3df42a104a655e8b", + "search": [ + "language" + ], + "charRef": 61847 + }, + { + "css": "graduation-cap", + "code": 61853, + "uid": "20fc52f9a88bb7bda023ef209acac095", + "search": [ + "graduation cap" + ], + "charRef": 61848 + }, + { + "css": "paw", + "code": 61872, + "uid": "55605ca79a65def1a9c300037ff1d0d5", + "search": [ + "paw" + ], + "charRef": 61849 + }, + { + "css": "spoon", + "code": 61873, + "uid": "3964e28e6bdf85b3b70df3533db69867", + "search": [ + "spoon" + ], + "charRef": 61850 + }, + { + "css": "cube", + "code": 61874, + "uid": "fbede3c5584282a0e9b131926dff71da", + "search": [ + "cube" + ], + "charRef": 61851 + }, + { + "css": "cubes", + "code": 61875, + "uid": "af95ef0ddda80a78828c62d386506433", + "search": [ + "cubes" + ], + "charRef": 61852 + }, + { + "css": "recycle", + "code": 61880, + "uid": "288f930b765216bc04e475740331bdf5", + "search": [ + "recycle" + ], + "charRef": 61853 + }, + { + "css": "tree", + "code": 61883, + "uid": "88da60b3a17e5744695682833a178e73", + "search": [ + "tree" + ], + "charRef": 61854 + }, + { + "css": "database", + "code": 61888, + "uid": "347c38a8b96a509270fdcabc951e7571", + "search": [ + "database" + ], + "charRef": 61855 + }, + { + "css": "server", + "code": 62003, + "uid": "d59ff824282fc6edaeca991deab522aa", + "search": [ + "server" + ], + "charRef": 61856 + }, + { + "css": "lifebuoy", + "code": 61901, + "uid": "ebffa4e734c8379ffee4fbfe49264d94", + "search": [ + "lifebuoy", + "support" + ], + "charRef": 61857 + }, + { + "css": "rebel", + "code": 61904, + "uid": "c53415fbd2695033bd7180d7a9ed4934", + "search": [ + "rebel" + ], + "charRef": 61858 + }, + { + "css": "empire", + "code": 61905, + "uid": "6632ce1019f9115842335622cb55f4e7", + "search": [ + "empire" + ], + "charRef": 61859 + }, + { + "css": "bomb", + "code": 61922, + "uid": "49ef53dc31aa9442d77f6ba4f559b528", + "search": [ + "bomb" + ], + "charRef": 61860 + }, + { + "css": "soccer-ball", + "code": 61923, + "uid": "cf62866c0cfe3dd14455b381c724f8e1", + "search": [ + "soccer", + "ball" + ], + "charRef": 61861 + }, + { + "css": "tty", + "code": 61924, + "uid": "3e1c9aac91dc062dc1af383d43f58ac5", + "search": [ + "tty", + "teletype" + ], + "charRef": 61862 + }, + { + "css": "binoculars", + "code": 61925, + "uid": "73ffeb70554099177620847206c12457", + "search": [ + "binoculars" + ], + "charRef": 61863 + }, + { + "css": "plug", + "code": 61926, + "uid": "a14be0c7e0689076e2bdde97f8e309f9", + "search": [ + "plug" + ], + "charRef": 61864 + }, + { + "css": "newspaper", + "code": 61930, + "uid": "032bd8bbd70adf90ead98b6813bfe446", + "search": [ + "newspaper" + ], + "charRef": 61865 + }, + { + "css": "calc", + "code": 61932, + "uid": "1ee2aeb352153a403df4b441a8bc9bda", + "search": [ + "calculator" + ], + "charRef": 61866 + }, + { + "css": "copyright", + "code": 61945, + "uid": "4a74a0f87d4089efe7aba1825bff4193", + "search": [ + "copyright" + ], + "charRef": 61867 + }, + { + "css": "at", + "code": 61946, + "uid": "33194d4a025fbf12baca54579afe4c8e", + "search": [ + "at" + ], + "charRef": 61868 + }, + { + "css": "eyedropper", + "code": 61947, + "uid": "88e6faa0f633ee23667f815689e82af3", + "search": [ + "eyedropper", + "pipette" + ], + "charRef": 61869 + }, + { + "css": "brush", + "code": 61948, + "uid": "fa9a0b7e788c2d78e24cef1de6b70e80", + "search": [ + "brush" + ], + "charRef": 61870 + }, + { + "css": "birthday", + "code": 61949, + "uid": "bc61ebcf2f5d8d08b1e9e62167df7617", + "search": [ + "cake", + "birthday" + ], + "charRef": 61871 + }, + { + "css": "diamond", + "code": 61977, + "uid": "f85affb51c357be83d187344c8c6e35c", + "search": [ + "diamond" + ], + "charRef": 61872 + }, + { + "css": "street-view", + "code": 61981, + "uid": "3c7eb0c1678e6fa93cc4264bad3150d6", + "search": [ + "street", + "view" + ], + "charRef": 61873 + }, + { + "css": "venus", + "code": 61985, + "uid": "95501182783a570088194c41bc63543b", + "search": [ + "venus", + "astrology" + ], + "charRef": 61874 + }, + { + "css": "mars", + "code": 61986, + "uid": "5d5d8995aa777cb59c88671e89ab5ced", + "search": [ + "mars", + "astrology" + ], + "charRef": 61875 + }, + { + "css": "mercury", + "code": 61987, + "uid": "c3c269bbbf641affca7e52beb39f7909", + "search": [ + "mercury", + "astrology" + ], + "charRef": 61876 + }, + { + "css": "transgender", + "code": 61988, + "uid": "d589e468da8556b0701206cfdfcfc567", + "search": [ + "transgender", + "astrology" + ], + "charRef": 61877 + }, + { + "css": "transgender-alt", + "code": 61989, + "uid": "5a77a57792f5bfd20fb80827af089d17", + "search": [ + "transgender", + "astrology" + ], + "charRef": 61878 + }, + { + "css": "venus-double", + "code": 61990, + "uid": "6c6165b9b97c471cc4c6366f9cf84537", + "search": [ + "venus", + "astrology" + ], + "charRef": 61879 + }, + { + "css": "mars-double", + "code": 61991, + "uid": "3bc42da674bdbebcb6471ceb42966d33", + "search": [ + "mars", + "astrology" + ], + "charRef": 61880 + }, + { + "css": "venus-mars", + "code": 61992, + "uid": "4ced65e721620e2b3e77b02d54af4100", + "search": [ + "venus", + "mars", + "astrology" + ], + "charRef": 61881 + }, + { + "css": "mars-stroke", + "code": 61993, + "uid": "6d4f6e98584c8b8ec08bd47a96ed86c4", + "search": [ + "mars", + "astrology" + ], + "charRef": 61882 + }, + { + "css": "mars-stroke-v", + "code": 61994, + "uid": "4162b5adba555571ca1be76baa365b9c", + "search": [ + "mars", + "astrology" + ], + "charRef": 61883 + }, + { + "css": "mars-stroke-h", + "code": 61995, + "uid": "10bd8ed7a393f773e81d145ad5523beb", + "search": [ + "mars", + "astrology" + ], + "charRef": 61884 + }, + { + "css": "neuter", + "code": 61996, + "uid": "14896a85fab311b3a5a9b614fe8c6874", + "search": [ + "neuter", + "astrology" + ], + "charRef": 61885 + }, + { + "css": "cc-visa", + "code": 61936, + "uid": "e3ed188ab8569b45cf41e74ce81aa86e", + "search": [ + "visa", + "card" + ], + "charRef": 61886 + }, + { + "css": "cc-mastercard", + "code": 61937, + "uid": "4b1bfce8593a2c1c7d60b9145ada2adf", + "search": [ + "mastercard", + "card" + ], + "charRef": 61887 + }, + { + "css": "cc-discover", + "code": 61938, + "uid": "6413682e05e1c65d13cb76fbca6d67e1", + "search": [ + "discover", + "card" + ], + "charRef": 61888 + }, + { + "css": "cc-amex", + "code": 61939, + "uid": "4e7a8235533632f4df7ba7a2c68cd39d", + "search": [ + "amex", + "card" + ], + "charRef": 61889 + }, + { + "css": "cc-paypal", + "code": 61940, + "uid": "b83f99fd47bff831e25255c9bbbbabe7", + "search": [ + "paypal", + "card" + ], + "charRef": 61890 + }, + { + "css": "cc-stripe", + "code": 61941, + "uid": "9698d35be5c118ec7521a98130fddc67", + "search": [ + "stripe", + "card" + ], + "charRef": 61891 + }, + { + "css": "adn", + "code": 61808, + "uid": "ef98b489bfb943225e6761cfa9999e9b", + "search": [ + "adn" + ], + "charRef": 61892 + }, + { + "css": "android", + "code": 61819, + "uid": "809f2374b759f5b9278ac6307e690ba4", + "search": [ + "android" + ], + "charRef": 61893 + }, + { + "css": "angellist", + "code": 61961, + "uid": "3fb64dab2b2e0a6cefa161387250c620", + "search": [ + "angellist" + ], + "charRef": 61894 + }, + { + "css": "apple", + "code": 61817, + "uid": "e9fa538fd5913046497ac148e27cd8ea", + "search": [ + "apple" + ], + "charRef": 61895 + }, + { + "css": "behance", + "code": 61876, + "uid": "aa58e30c7196b1378a6ca78c025cc3b5", + "search": [ + "behance" + ], + "charRef": 61896 + }, + { + "css": "behance-squared", + "code": 61877, + "uid": "b501bc7737850366e98043c585163eec", + "search": [ + "behance" + ], + "charRef": 61897 + }, + { + "css": "bitbucket", + "code": 61809, + "uid": "169f51b7e405de8c03cf85a6e8c740ab", + "search": [ + "bitbucket" + ], + "charRef": 61898 + }, + { + "css": "bitbucket-squared", + "code": 61810, + "uid": "4ae56c66a1f93e28b8d4f866db2b018a", + "search": [ + "bitbucket" + ], + "charRef": 61899 + }, + { + "css": "buysellads", + "code": 61965, + "uid": "18d3287c351d9799fedb221e4923b2d2", + "search": [ + "buysellads" + ], + "charRef": 61900 + }, + { + "css": "cc", + "code": 61962, + "uid": "66faf6c4e3b0e4e33f06171e30253e26", + "search": [ + "cc" + ], + "charRef": 61901 + }, + { + "css": "codepen", + "code": 61899, + "uid": "76675011e906d50af404186b489fc76f", + "search": [ + "codepen" + ], + "charRef": 61902 + }, + { + "css": "connectdevelop", + "code": 61966, + "uid": "aa4ded7a2d22e21c3cfe775efe267120", + "search": [ + "connectdevelop" + ], + "charRef": 61903 + }, + { + "css": "css3", + "code": 61756, + "uid": "01c946ce2ed5500e0a918f2b3a7d1923", + "search": [ + "css3" + ], + "charRef": 61904 + }, + { + "css": "dashcube", + "code": 61968, + "uid": "71e046578954f177921bcf5b241d0d95", + "search": [ + "dashcube" + ], + "charRef": 61905 + }, + { + "css": "delicious", + "code": 61861, + "uid": "6975c4c656d41a0283d9c52516bf38ed", + "search": [ + "delicious" + ], + "charRef": 61906 + }, + { + "css": "deviantart", + "code": 61885, + "uid": "54fad985c676a007c79c346ebaec29d6", + "search": [ + "deviantart" + ], + "charRef": 61907 + }, + { + "css": "digg", + "code": 61862, + "uid": "ef0e69c3275e8c845aca69a79900092d", + "search": [ + "digg" + ], + "charRef": 61908 + }, + { + "css": "dribbble", + "code": 61821, + "uid": "199c44bca402ec5a6351f75ba5228375", + "search": [ + "dribbble" + ], + "charRef": 61909 + }, + { + "css": "dropbox", + "code": 61803, + "uid": "9e34a047fee949eae9b6e613d790d6cf", + "search": [ + "dropbox" + ], + "charRef": 61910 + }, + { + "css": "drupal", + "code": 61865, + "uid": "d16ba9078d51e79b5ad6af0235adbd54", + "search": [ + "drupal" + ], + "charRef": 61911 + }, + { + "css": "facebook", + "code": 61594, + "uid": "8e04c98c8f5ca0a035776e3001ad2638", + "search": [ + "facebook" + ], + "charRef": 61912 + }, + { + "css": "facebook-squared", + "code": 62216, + "uid": "4743b088aa95d6f3b6b990e770d3b647", + "search": [ + "facebook" + ], + "charRef": 61913 + }, + { + "css": "facebook-official", + "code": 62000, + "uid": "6cc7af3e5b55720bcb6ef68372ce24be", + "search": [ + "facebook" + ], + "charRef": 61914 + }, + { + "css": "flickr", + "code": 61806, + "uid": "649004fb1ed50395a33c3780236ba8aa", + "search": [ + "flickr" + ], + "charRef": 61915 + }, + { + "css": "forumbee", + "code": 61969, + "uid": "7b7116fa67e5e3f4c98e5928ebe3f6ae", + "search": [ + "forumbee" + ], + "charRef": 61916 + }, + { + "css": "foursquare", + "code": 61824, + "uid": "a32d12927584e3c8a3dff23eb816d360", + "search": [ + "foursquare" + ], + "charRef": 61917 + }, + { + "css": "git-squared", + "code": 61906, + "uid": "c75b7d61b0bce6aeb54292e3952a1568", + "search": [ + "git" + ], + "charRef": 61918 + }, + { + "css": "git", + "code": 61907, + "uid": "e7cb72a17f3b21e3576f35c3f0a7639b", + "search": [ + "git" + ], + "charRef": 61919 + }, + { + "css": "github", + "code": 61715, + "uid": "5e0a374728ffa8d0ae1f331a8f648231", + "search": [ + "github" + ], + "charRef": 61920 + }, + { + "css": "github-squared", + "code": 62208, + "uid": "0ece9a12de796b8411f868d582bee678", + "search": [ + "github" + ], + "charRef": 61921 + }, + { + "css": "github-circled", + "code": 61595, + "uid": "0f6a2573a7b6df911ed199bb63717e27", + "search": [ + "github" + ], + "charRef": 61922 + }, + { + "css": "gittip", + "code": 61828, + "uid": "5b4b48418155c35459f12171f97c82ff", + "search": [ + "gittip" + ], + "charRef": 61923 + }, + { + "css": "google", + "code": 61856, + "uid": "f06fe7ff18d1c591bc1183cb3ab105e9", + "search": [ + "google" + ], + "charRef": 61924 + }, + { + "css": "gplus", + "code": 61653, + "uid": "b8d0c7d76e87b94882329a88e8e43d3d", + "search": [ + "google", + "plus" + ], + "charRef": 61925 + }, + { + "css": "gplus-squared", + "code": 61652, + "uid": "f0cf7db1b03cb65adc450aa3bdaf8c4d", + "search": [ + "google", + "plus" + ], + "charRef": 61926 + }, + { + "css": "gwallet", + "code": 61934, + "uid": "50fbbd926b2a64fcaf384788056c0e43", + "search": [ + "google wallet" + ], + "charRef": 61927 + }, + { + "css": "hacker-news", + "code": 61908, + "uid": "237ee28b7e826b75a5b6f51ee3e2bfc1", + "search": [ + "hacker news", + "hn" + ], + "charRef": 61928 + }, + { + "css": "html5", + "code": 61755, + "uid": "ff44f01f60948555026580eedf1e39bb", + "search": [ + "html5" + ], + "charRef": 61929 + }, + { + "css": "instagram", + "code": 61805, + "uid": "4c1ef492f1d2c39a2250ae457cee2a6e", + "search": [ + "instagram" + ], + "charRef": 61930 + }, + { + "css": "ioxhost", + "code": 61960, + "uid": "9b9e5f3ee9e3525808ed2afc83e8bb0b", + "search": [ + "ioxhost" + ], + "charRef": 61931 + }, + { + "css": "joomla", + "code": 61866, + "uid": "8cd1b9899389237def726c08587a649f", + "search": [ + "joomla" + ], + "charRef": 61932 + }, + { + "css": "jsfiddle", + "code": 61900, + "uid": "486f6d0a05aef9e65eeb07be26793bd3", + "search": [ + "jsfiddle" + ], + "charRef": 61933 + }, + { + "css": "lastfm", + "code": 61954, + "uid": "5dcf6620378353c5b0089b12d961fedf", + "search": [ + "lastfm" + ], + "charRef": 61934 + }, + { + "css": "lastfm-squared", + "code": 61955, + "uid": "32e335f0cd5c4fcc692af6fa742f6b7e", + "search": [ + "lastfm" + ], + "charRef": 61935 + }, + { + "css": "leanpub", + "code": 61970, + "uid": "f78244d4753a3aa2be87d56b858d148d", + "search": [ + "leanpub" + ], + "charRef": 61936 + }, + { + "css": "linkedin-squared", + "code": 62220, + "uid": "1145676a91138011729fa2909997af66", + "search": [ + "linkedin" + ], + "charRef": 61937 + }, + { + "css": "linux", + "code": 61820, + "uid": "47a35af762c8e06f3d152750134c8750", + "search": [ + "linux" + ], + "charRef": 61938 + }, + { + "css": "linkedin", + "code": 61665, + "uid": "e9107949dd6c9e8ab2b29ae07156e38c", + "search": [ + "linkedin" + ], + "charRef": 61939 + }, + { + "css": "maxcdn", + "code": 61750, + "uid": "fcdc6d7a89771d2dbd38eb719aafb2ff", + "search": [ + "maxcdn" + ], + "charRef": 61940 + }, + { + "css": "meanpath", + "code": 61964, + "uid": "9b2e17ef8fc33eb2a1c8b5953d51c595", + "search": [ + "meanpath" + ], + "charRef": 61941 + }, + { + "css": "openid", + "code": 61851, + "uid": "da8a58b1deff73d1ba89ba1172ca4bcc", + "search": [ + "openid" + ], + "charRef": 61942 + }, + { + "css": "pagelines", + "code": 61836, + "uid": "bbf50a560f95a4cce5209d47e71cbc30", + "search": [ + "pagelines" + ], + "charRef": 61943 + }, + { + "css": "paypal", + "code": 61933, + "uid": "1d2b426ab6db81a58547ba13d8701ad8", + "search": [ + "paypal" + ], + "charRef": 61944 + }, + { + "css": "pied-piper-squared", + "code": 61863, + "uid": "92a4d74aa4e0549812301299020915a5", + "search": [ + "pied-piper" + ], + "charRef": 61945 + }, + { + "css": "pied-piper-alt", + "code": 61864, + "uid": "604733d6d4f7ae269a2ea97f4dc7c346", + "search": [ + "pied-piper" + ], + "charRef": 61946 + }, + { + "css": "pinterest", + "code": 62001, + "uid": "cc399e4597f157dcbf016be0b7407fea", + "search": [ + "pinterest" + ], + "charRef": 61947 + }, + { + "css": "pinterest-circled", + "code": 61650, + "uid": "da851b7c1f84ee83f93b29ae613558dc", + "search": [ + "pinterest" + ], + "charRef": 61948 + }, + { + "css": "pinterest-squared", + "code": 61651, + "uid": "79689c4c425b7cdaa2746f510e81e27a", + "search": [ + "pinterest" + ], + "charRef": 61949 + }, + { + "css": "qq", + "code": 61910, + "uid": "657ff9fe5df74f1993937aa4b19cf909", + "search": [ + "qq" + ], + "charRef": 61950 + }, + { + "css": "reddit", + "code": 61857, + "uid": "9121e3eb89863f67c8bda378eea01a93", + "search": [ + "reddit" + ], + "charRef": 61951 + }, + { + "css": "reddit-squared", + "code": 61858, + "uid": "4fc515c6a083b42e628273ab06cb2a90", + "search": [ + "reddit" + ], + "charRef": 61952 + }, + { + "css": "renren", + "code": 61835, + "uid": "cfa8a2588cab42a6ff7ba81eb4fec21b", + "search": [ + "renren" + ], + "charRef": 61953 + }, + { + "css": "sellsy", + "code": 61971, + "uid": "281020881dd80ef01d0369bf4b80ebef", + "search": [ + "sellsy" + ], + "charRef": 61954 + }, + { + "css": "shirtsinbulk", + "code": 61972, + "uid": "770fafc9392963133bb03b4ad4ed3a28", + "search": [ + "shirtsinbulk" + ], + "charRef": 61955 + }, + { + "css": "simplybuilt", + "code": 61973, + "uid": "12b38aeedfa5b6672936432bc7d3082c", + "search": [ + "simplybuilt" + ], + "charRef": 61956 + }, + { + "css": "skyatlas", + "code": 61974, + "uid": "a0afa21fe64100c16eac19f4e1615c2a", + "search": [ + "skyatlas" + ], + "charRef": 61957 + }, + { + "css": "skype", + "code": 61822, + "uid": "58a16628dcbd6456c61218f3d27591be", + "search": [ + "skype" + ], + "charRef": 61958 + }, + { + "css": "slack", + "code": 61848, + "uid": "87276033a77d0b9b890125c3639e4f87", + "search": [ + "slack" + ], + "charRef": 61959 + }, + { + "css": "slideshare", + "code": 61927, + "uid": "be13b8c668eb18839d5d53107725f1de", + "search": [ + "slideshare" + ], + "charRef": 61960 + }, + { + "css": "soundcloud", + "code": 61886, + "uid": "dff942d95eb1b3f1be140e622d0a7c74", + "search": [ + "soundcloud" + ], + "charRef": 61961 + }, + { + "css": "spotify", + "code": 61884, + "uid": "fb4794d89b77ab712ad56c0dc4c76c6b", + "search": [ + "spotify" + ], + "charRef": 61962 + }, + { + "css": "stackexchange", + "code": 61837, + "uid": "b6d6b3561d705330c7ad2155e8ee94ba", + "search": [ + "stackexchange" + ], + "charRef": 61963 + }, + { + "css": "stackoverflow", + "code": 61804, + "uid": "e1597911f34fea0a188ae51fe4a2d9a9", + "search": [ + "stackoverflow" + ], + "charRef": 61964 + }, + { + "css": "steam", + "code": 61878, + "uid": "2ec1790207a8ba67a7192c6af1eafec4", + "search": [ + "steam" + ], + "charRef": 61965 + }, + { + "css": "steam-squared", + "code": 61879, + "uid": "727544621cb891115c99b4a4cfed01df", + "search": [ + "steam" + ], + "charRef": 61966 + }, + { + "css": "stumbleupon", + "code": 61860, + "uid": "3958d12510001a1a172f088893506c27", + "search": [ + "stumbleupon" + ], + "charRef": 61967 + }, + { + "css": "stumbleupon-circled", + "code": 61859, + "uid": "7377e22d1e1d2dd079f87b05fb6a11a3", + "search": [ + "stumbleupon" + ], + "charRef": 61968 + }, + { + "css": "tencent-weibo", + "code": 61909, + "uid": "d9b33592f56a02af69a36aa64ed452fc", + "search": [ + "tencent-weibo" + ], + "charRef": 61969 + }, + { + "css": "trello", + "code": 61825, + "uid": "b846892636bd74112998bb159bdddf27", + "search": [ + "trello" + ], + "charRef": 61970 + }, + { + "css": "tumblr", + "code": 61811, + "uid": "43fcf807461234935e65261328e1dff6", + "search": [ + "tumblr" + ], + "charRef": 61971 + }, + { + "css": "tumblr-squared", + "code": 61812, + "uid": "5b79895d979c408282b4e92fa7db8e82", + "search": [ + "tumblr" + ], + "charRef": 61972 + }, + { + "css": "twitch", + "code": 61928, + "uid": "e70df9acbabaebfbbf9c1dbc3e52ab13", + "search": [ + "twitch" + ], + "charRef": 61973 + }, + { + "css": "twitter-squared", + "code": 62212, + "uid": "906348dc798a0d42715cc97c875e3ac6", + "search": [ + "twitter" + ], + "charRef": 61974 + }, + { + "css": "twitter", + "code": 61593, + "uid": "627abcdb627cb1789e009c08e2678ef9", + "search": [ + "twitter" + ], + "charRef": 61975 + }, + { + "css": "vimeo-squared", + "code": 61844, + "uid": "1f66490bf24c99e2c56b866d8fbd0372", + "search": [ + "vimeo" + ], + "charRef": 61976 + }, + { + "css": "vine", + "code": 61898, + "uid": "676cf66256441f09e4934ae6378b3e2d", + "search": [ + "vine" + ], + "charRef": 61977 + }, + { + "css": "vkontakte", + "code": 61833, + "uid": "f3d95e13eb43f3f6b8efe1eb424a1e3b", + "search": [ + "vkontakte" + ], + "charRef": 61978 + }, + { + "css": "whatsapp", + "code": 62002, + "uid": "9d3e9faf68fd4e12def853f0d4e1173b", + "search": [ + "whatsapp" + ], + "charRef": 61979 + }, + { + "css": "wechat", + "code": 61911, + "uid": "34cb6ce62bf3f1efd59e2f5eb0d79f82", + "search": [ + "wechat" + ], + "charRef": 61980 + }, + { + "css": "weibo", + "code": 61834, + "uid": "9854b94688e31450fc76aae4c2a45dff", + "search": [ + "weibo" + ], + "charRef": 61981 + }, + { + "css": "windows", + "code": 61818, + "uid": "8aff323697468c4a63993cde00386ec6", + "search": [ + "windows" + ], + "charRef": 61982 + }, + { + "css": "wordpress", + "code": 61850, + "uid": "39f52f80e1864df5e5022d7f0f5ff86f", + "search": [ + "wordpress" + ], + "charRef": 61983 + }, + { + "css": "xing", + "code": 61800, + "uid": "11ebb30e17efcd988a228ade5d3e8c74", + "search": [ + "xing" + ], + "charRef": 61984 + }, + { + "css": "xing-squared", + "code": 61801, + "uid": "f7dff44258aa565cbe35565be350b58d", + "search": [ + "xing" + ], + "charRef": 61985 + }, + { + "css": "yelp", + "code": 61929, + "uid": "7a48de2ac7ca47c78d6c279996ee6250", + "search": [ + "yelp" + ], + "charRef": 61986 + }, + { + "css": "youtube", + "code": 61799, + "uid": "a9862b9d5197886c1ad693ecd7120b31", + "search": [ + "youtube" + ], + "charRef": 61987 + }, + { + "css": "yahoo", + "code": 61854, + "uid": "ba071f2b01f1fed40d8e2366434b6f42", + "search": [ + "yahoo" + ], + "charRef": 61988 + }, + { + "css": "youtube-squared", + "code": 61798, + "uid": "e331ff486a299c6bdf0056426c8fac53", + "search": [ + "youtube" + ], + "charRef": 61989 + }, + { + "css": "youtube-play", + "code": 61802, + "uid": "47a1f80457068fbeab69fdb83d7d0817", + "search": [ + "youtube", + "video" + ], + "charRef": 61990 + }, + { + "css": "blank", + "code": 61640, + "uid": "2c2ca8a96b31781c9c8056d05c0a8980", + "search": [ + "blank", + "square" + ], + "charRef": 61991 + }, + { + "css": "lemon", + "code": 127819, + "uid": "5e0191587645a9f5d514ed4b0a0e008a", + "charRef": 61992 + }, + { + "css": "genderless", + "code": 61997, + "uid": "6052fa7e25643f06a46dc7eedb5f596b", + "search": [], + "charRef": 61993 + }, + { + "css": "y-combinator", + "code": 62011, + "uid": "cee894776000256eed076cb6bf06599e", + "search": [ + "yc" + ], + "charRef": 61994 + }, + { + "css": "optin-monster", + "code": 62012, + "uid": "41cdd46ab935131f6dfea37a5b9e7add", + "search": [], + "charRef": 61995 + }, + { + "css": "opencart", + "code": 62013, + "uid": "10e444e650c211fbcb6ae5e73671d94b", + "search": [], + "charRef": 61996 + }, + { + "css": "expeditedssl", + "code": 62014, + "uid": "653f72ed4ded6e41c93fd571970efe6f", + "search": [], + "charRef": 61997 + }, + { + "css": "battery-4", + "code": 62016, + "uid": "69bd9dfe950d07d910f39c6988364e49", + "search": [ + "battery-full" + ], + "charRef": 61998 + }, + { + "css": "battery-3", + "code": 62017, + "uid": "7ab4ec24078133effbc4e923b65ef835", + "search": [ + "battery-three-quarters" + ], + "charRef": 61999 + }, + { + "css": "battery-2", + "code": 62018, + "uid": "e430a168b45ba40aa988ca1a5034a553", + "search": [ + "battery-half" + ], + "charRef": 62000 + }, + { + "css": "battery-1", + "code": 62019, + "uid": "99f4ea74adc24022106932d84a49b055", + "search": [ + "battery-quarter" + ], + "charRef": 62001 + }, + { + "css": "battery-0", + "code": 62020, + "uid": "9983d2489e028d659d196915a25ef3ca", + "search": [ + "battery-empty" + ], + "charRef": 62002 + }, + { + "css": "mouse-pointer", + "code": 62021, + "uid": "12a80769cc7ac08e986deeafbe553054", + "search": [], + "charRef": 62003 + }, + { + "css": "i-cursor", + "code": 62022, + "uid": "c4c41817bb8c088a8ec6d08784b33da7", + "search": [], + "charRef": 62004 + }, + { + "css": "object-group", + "code": 62023, + "uid": "7aa8cc552d9d6d19815750fc339cf090", + "search": [], + "charRef": 62005 + }, + { + "css": "object-ungroup", + "code": 62024, + "uid": "d4edf8563d5cb3b5f654808aa4fe438a", + "search": [], + "charRef": 62006 + }, + { + "css": "sticky-note", + "code": 62025, + "uid": "c116c18983825a9b32a23a62fd18e1e6", + "search": [], + "charRef": 62007 + }, + { + "css": "sticky-note-o", + "code": 62026, + "uid": "b9ca73befd583b2197a56a68045c9c0c", + "search": [], + "charRef": 62008 + }, + { + "css": "cc-jcb", + "code": 62027, + "uid": "69529d146afd305c4e34b7e3b9be7012", + "search": [], + "charRef": 62009 + }, + { + "css": "cc-diners-club", + "code": 62028, + "uid": "956f4ffb9483306d20278f271ad9da1e", + "search": [], + "charRef": 62010 + }, + { + "css": "clone", + "code": 62029, + "uid": "6846d155ad5bda456569df81f3057faa", + "search": [], + "charRef": 62011 + }, + { + "css": "balance-scale", + "code": 62030, + "uid": "ff1710a605b3fc98346903db89034558", + "search": [], + "charRef": 62012 + }, + { + "css": "hourglass-o", + "code": 62032, + "uid": "9dfee680431bb2f9cc4485bfa4d982ac", + "search": [], + "charRef": 62013 + }, + { + "css": "hourglass-1", + "code": 62033, + "uid": "8bc4e828380b962c8b5a04ee982f1d71", + "search": [ + "hourglass-start" + ], + "charRef": 62014 + }, + { + "css": "hourglass-2", + "code": 62034, + "uid": "f70af5dd0ecd154b007d980cd011a7f7", + "search": [ + "hourglass-half" + ], + "charRef": 62015 + }, + { + "css": "hourglass-3", + "code": 62035, + "uid": "423dee39096bacea6b9e3b00919b983c", + "search": [ + "hourglass-end" + ], + "charRef": 62016 + }, + { + "css": "hourglass", + "code": 62036, + "uid": "bc9b0a766409e4ddeb2e9745c3e8130c", + "search": [], + "charRef": 62017 + }, + { + "css": "hand-grab-o", + "code": 62037, + "uid": "c82f1ec71a2c9e5af8b00fe5fe27f57e", + "search": [ + "hand-rock-o" + ], + "charRef": 62018 + }, + { + "css": "hand-paper-o", + "code": 62038, + "uid": "abf08be829659c02d1f9a711daefa8ce", + "search": [ + "hand-stop-o" + ], + "charRef": 62019 + }, + { + "css": "hand-scissors-o", + "code": 62039, + "uid": "dd0acda8a6217fd10e94d4feadccd90f", + "search": [], + "charRef": 62020 + }, + { + "css": "hand-lizard-o", + "code": 62040, + "uid": "0eb9a32706e05e4f9f2561aa1bfbb7e9", + "search": [], + "charRef": 62021 + }, + { + "css": "hand-spock-o", + "code": 62041, + "uid": "7a8becfd21312643b7be5463583e7425", + "search": [], + "charRef": 62022 + }, + { + "css": "hand-pointer-o", + "code": 62042, + "uid": "18e30ad120ce4b15d7e5c797e4bf0ee8", + "search": [], + "charRef": 62023 + }, + { + "css": "hand-peace-o", + "code": 62043, + "uid": "31562b831ad0016b89ddf9693214041f", + "search": [], + "charRef": 62024 + }, + { + "css": "trademark", + "code": 62044, + "uid": "c3ec0e8d143190ee85d404bd064bf8f4", + "search": [], + "charRef": 62025 + }, + { + "css": "registered", + "code": 62045, + "uid": "c3371cca5561d470f45ae0a9c485b7ec", + "search": [], + "charRef": 62026 + }, + { + "css": "creative-commons", + "code": 62046, + "uid": "e9b178b4a02c08399ca5ea10ba522528", + "search": [], + "charRef": 62027 + }, + { + "css": "gg", + "code": 62048, + "uid": "b37d0b43098feda6ef73a24dcf4fc58f", + "search": [], + "charRef": 62028 + }, + { + "css": "gg-circle", + "code": 62049, + "uid": "994cebef2d88a25f775b1b2b318f71c7", + "search": [], + "charRef": 62029 + }, + { + "css": "tripadvisor", + "code": 62050, + "uid": "fbc6facd27f744438410cbcad545bf52", + "search": [], + "charRef": 62030 + }, + { + "css": "odnoklassniki", + "code": 62051, + "uid": "2f87e74e6eb8d985044bf7f3c47cb50b", + "search": [], + "charRef": 62031 + }, + { + "css": "odnoklassniki-square", + "code": 62052, + "uid": "b3ccbe22f1b25b3f3ecfd7096a7c9187", + "search": [], + "charRef": 62032 + }, + { + "css": "get-pocket", + "code": 62053, + "uid": "685e1db17ba5c233b6ab38aed4084a24", + "search": [], + "charRef": 62033 + }, + { + "css": "wikipedia-w", + "code": 62054, + "uid": "0b5f5c9abb1b4f21e75ff572955aa1de", + "search": [], + "charRef": 62034 + }, + { + "css": "safari", + "code": 62055, + "uid": "c5af9b4626c0f2fa6dc259f9f035b055", + "search": [], + "charRef": 62035 + }, + { + "css": "chrome", + "code": 62056, + "uid": "bd7fd67bed189448225cad0fe4ef3d7c", + "search": [], + "charRef": 62036 + }, + { + "css": "firefox", + "code": 62057, + "uid": "c97bfbcfb31e74be0653d8551c89a40f", + "search": [], + "charRef": 62037 + }, + { + "css": "opera", + "code": 62058, + "uid": "52f734427edaded2af2fc050ac5d3554", + "search": [], + "charRef": 62038 + }, + { + "css": "internet-explorer", + "code": 62059, + "uid": "c0a33f22eaeba6c843457bc23a7ab2a8", + "search": [], + "charRef": 62039 + }, + { + "css": "television", + "code": 62060, + "uid": "cfb6e143c0650c485536374f2a2f88fb", + "search": [ + "tv" + ], + "charRef": 62040 + }, + { + "css": "contao", + "code": 62061, + "uid": "a5c942b3315f858cd0fc1a34a1b0d1bb", + "search": [], + "charRef": 62041 + }, + { + "css": "500px", + "code": 62062, + "uid": "baec122d16d314a0e0e66d5fb6b55a4b", + "search": [], + "charRef": 62042 + }, + { + "css": "amazon", + "code": 62064, + "uid": "efb5a384af4a5450b7c9acff76a85b8b", + "search": [], + "charRef": 62043 + }, + { + "css": "calendar-plus-o", + "code": 62065, + "uid": "e7eecc3cc44f3f4cad6229b202588308", + "search": [], + "charRef": 62044 + }, + { + "css": "calendar-minus-o", + "code": 62066, + "uid": "e66ec405e2e1f3bec6546b4e776924d3", + "search": [], + "charRef": 62045 + }, + { + "css": "calendar-times-o", + "code": 62067, + "uid": "a027a2ce420dfd6b660212d5ac6a7cc9", + "search": [], + "charRef": 62046 + }, + { + "css": "calendar-check-o", + "code": 62068, + "uid": "9de4ac1aec6b1cca1929e1407eecf3db", + "search": [], + "charRef": 62047 + }, + { + "css": "industry", + "code": 62069, + "uid": "31efa81b26fa5a380119c95d6b831d6d", + "search": [], + "charRef": 62048 + }, + { + "css": "map-pin", + "code": 62070, + "uid": "8b4584b43f9858f2d38b3741ecdfe15c", + "search": [], + "charRef": 62049 + }, + { + "css": "map-signs", + "code": 62071, + "uid": "94aa5db477515f1da4ce43b239badb9e", + "search": [], + "charRef": 62050 + }, + { + "css": "map-o", + "code": 62072, + "uid": "c62cbc7fa604e32cc19731a3bb29be79", + "search": [], + "charRef": 62051 + }, + { + "css": "map", + "code": 62073, + "uid": "79beb8c7fcd56e1985b70e9a120cbcbf", + "search": [], + "charRef": 62052 + }, + { + "css": "commenting", + "code": 62074, + "uid": "53c28626072159c49f33b71d67138ad9", + "search": [], + "charRef": 62053 + }, + { + "css": "commenting-o", + "code": 62075, + "uid": "9cc990bbcac7aa8504078b3f49df79b1", + "search": [], + "charRef": 62054 + }, + { + "css": "houzz", + "code": 62076, + "uid": "52ee4b2769437c85066253217b23c265", + "search": [], + "charRef": 62055 + }, + { + "css": "vimeo", + "code": 62077, + "uid": "6b44ce2430177c5b05a1d1575ccaaf5c", + "search": [], + "charRef": 62056 + }, + { + "css": "black-tie", + "code": 62078, + "uid": "7b610e9b9c75f602f9006ce645986c8c", + "search": [], + "charRef": 62057 + }, + { + "css": "fonticons", + "code": 62080, + "uid": "dab8d5c8dbacfa8b2c310a7aa97a28da", + "search": [], + "charRef": 62058 + }, + { + "css": "reddit-alien", + "code": 62081, + "uid": "f08ba9f0e8f9b426a92efcaa59c1e932", + "search": [], + "charRef": 62059 + }, + { + "css": "edge", + "code": 62082, + "uid": "03957a1f03b5ae5dfac6e5027d893157", + "search": [], + "charRef": 62060 + }, + { + "css": "credit-card-alt", + "code": 62083, + "uid": "7ea4150d9eb2d2ade9491d5ad905718c", + "search": [], + "charRef": 62061 + }, + { + "css": "codiepie", + "code": 62084, + "uid": "b649f3c065f335b126ec3eb3ac78759b", + "search": [], + "charRef": 62062 + }, + { + "css": "modx", + "code": 62085, + "uid": "e3a73480599b09c84f6657ef2e081abd", + "search": [], + "charRef": 62063 + }, + { + "css": "fort-awesome", + "code": 62086, + "uid": "fc649ed0a69a0a1916ac6d5125234183", + "search": [], + "charRef": 62064 + }, + { + "css": "usb", + "code": 62087, + "uid": "21e7025c85a7eeae71fd3539855afe2b", + "search": [], + "charRef": 62065 + }, + { + "css": "product-hunt", + "code": 62088, + "uid": "26eb5e234f87bad251fdd8e285b6fae7", + "search": [], + "charRef": 62066 + }, + { + "css": "mixcloud", + "code": 62089, + "uid": "e6eeb1a403c52c3f981eb19646021691", + "search": [], + "charRef": 62067 + }, + { + "css": "scribd", + "code": 62090, + "uid": "5c6ee0240a4b7b2b8674ec1f0ca8886d", + "search": [], + "charRef": 62068 + }, + { + "css": "pause-circle", + "code": 62091, + "uid": "9c0fabd22e5b65b3ef7ed847eb864bcb", + "search": [], + "charRef": 62069 + }, + { + "css": "pause-circle-o", + "code": 62092, + "uid": "4ae8cbc2c1329cb5dbe6e6995d8c68be", + "search": [], + "charRef": 62070 + }, + { + "css": "stop-circle", + "code": 62093, + "uid": "3363990fa5a224d75ed1740e1ec50bb6", + "search": [], + "charRef": 62071 + }, + { + "css": "stop-circle-o", + "code": 62094, + "uid": "5434b2bf3a3a6c4c260a11a386e3f5d1", + "search": [], + "charRef": 62072 + }, + { + "css": "shopping-bag", + "code": 62096, + "uid": "d531ea7e8c094b73df941ed0bac921f3", + "search": [], + "charRef": 62073 + }, + { + "css": "shopping-basket", + "code": 62097, + "uid": "90e0aff5c929e444038355746a952aaf", + "search": [], + "charRef": 62074 + }, + { + "css": "hashtag", + "code": 62098, + "uid": "090c79ed8971e478a27fae8a3eb3eb11", + "search": [], + "charRef": 62075 + }, + { + "css": "bluetooth", + "code": 62099, + "uid": "fb15371451b9110f93afcaa70d6ea98d", + "search": [], + "charRef": 62076 + }, + { + "css": "bluetooth-b", + "code": 62100, + "uid": "9a0873ae5167deefbf38061b7cddbe34", + "search": [], + "charRef": 62077 + }, + { + "css": "percent", + "code": 62101, + "uid": "2c452255d4fed51ef0a6ef86436a7d08", + "search": [], + "charRef": 62078 + }, + { + "css": "gitlab", + "code": 62102, + "uid": "7cca4643f1e938c673e91c0c78058ddf", + "search": [], + "charRef": 62079 + }, + { + "css": "wpbeginner", + "code": 62103, + "uid": "4be3f9da1280527c2a1f41fbf34ad4c4", + "search": [], + "charRef": 62080 + }, + { + "css": "wpforms", + "code": 62104, + "uid": "a41cabcd11152063a37f2407048c5494", + "search": [], + "charRef": 62081 + }, + { + "css": "envira", + "code": 62105, + "uid": "40177cc6c35597ea3422673689409152", + "search": [], + "charRef": 62082 + }, + { + "css": "universal-access", + "code": 62106, + "uid": "caeb3b38733e4cf2702a50d3c7c4ee6f", + "search": [], + "charRef": 62083 + }, + { + "css": "wheelchair-alt", + "code": 62107, + "uid": "9729f562bc9df27c93250f66c1a1b2f3", + "search": [], + "charRef": 62084 + }, + { + "css": "question-circle-o", + "code": 62108, + "uid": "9c9f0a69d4abbeb5ff9d779df7679356", + "search": [], + "charRef": 62085 + }, + { + "css": "blind", + "code": 62109, + "uid": "cce5e05853d0798a4d10077ef613387c", + "search": [], + "charRef": 62086 + }, + { + "css": "audio-description", + "code": 62110, + "uid": "472c1b83f2e156e20280a4854e1cfa69", + "search": [], + "charRef": 62087 + }, + { + "css": "volume-control-phone", + "code": 62112, + "uid": "ed42a2d393650165b737216b5fe85c40", + "search": [], + "charRef": 62088 + }, + { + "css": "braille", + "code": 62113, + "uid": "a0e6549c693b73d4fe92b1db1824b919", + "search": [], + "charRef": 62089 + }, + { + "css": "assistive-listening-systems", + "code": 62114, + "uid": "2e0a6d93466b3f1b0fc90c15b2aff13f", + "search": [], + "charRef": 62090 + }, + { + "css": "american-sign-language-interpreting", + "code": 62115, + "uid": "ecc56ff0652abe04c23b4f5d736ed506", + "search": [], + "charRef": 62091 + }, + { + "css": "asl-interpreting", + "code": 62116, + "uid": "0e393c5fb8776a60df0d71b5ee46ca44", + "search": [ + "deaf", + "deafness", + "hard-of-hearing" + ], + "charRef": 62092 + }, + { + "css": "glide", + "code": 62117, + "uid": "dc6cb47e30d3ca4fd06c8cbf9248692f", + "search": [], + "charRef": 62093 + }, + { + "css": "glide-g", + "code": 62118, + "uid": "2a3fc031662edd118ba3c2e2f8564aef", + "search": [], + "charRef": 62094 + }, + { + "css": "sign-language", + "code": 62119, + "uid": "67b150662a25d2c6d556d23d721b9569", + "search": [ + "signing" + ], + "charRef": 62095 + }, + { + "css": "low-vision", + "code": 62120, + "uid": "440e5cbb0f604b4be0c0183e63a0cde3", + "search": [], + "charRef": 62096 + }, + { + "css": "viadeo", + "code": 62121, + "uid": "7eed62ae3352efe006c173a890f44d45", + "search": [], + "charRef": 62097 + }, + { + "css": "viadeo-square", + "code": 62122, + "uid": "52328217db1b956669bc214cd7c64dcc", + "search": [], + "charRef": 62098 + }, + { + "css": "snapchat", + "code": 62123, + "uid": "cab8b1ea47d71c77413157c592db2293", + "search": [], + "charRef": 62099 + }, + { + "css": "snapchat-ghost", + "code": 62124, + "uid": "1b1a592d33fa26c37926cbe840eb60b8", + "search": [], + "charRef": 62100 + }, + { + "css": "snapchat-square", + "code": 62125, + "uid": "d20b5fb608f848b0e14aef1325c9e23c", + "search": [], + "charRef": 62101 + }, + { + "css": "pied-piper", + "code": 62126, + "uid": "caa1c8d19cb3f0b7641eb59828bd50bb", + "search": [], + "charRef": 62102 + }, + { + "css": "first-order", + "code": 62128, + "uid": "80b02191b84eb4ea4516adc83330d7b3", + "search": [], + "charRef": 62103 + }, + { + "css": "yoast", + "code": 62129, + "uid": "cc0c348dee522c0f93e3287dccaf2b8f", + "search": [], + "charRef": 62104 + }, + { + "css": "themeisle", + "code": 62130, + "uid": "67c726a4267687f5061ebaa1bbdf1c79", + "search": [], + "charRef": 62105 + }, + { + "css": "google-plus-circle", + "code": 62131, + "uid": "2342c9255e31850fcf5f89799cb8420f", + "search": [ + "google-plus-official" + ], + "charRef": 62106 + }, + { + "css": "font-awesome", + "code": 62132, + "uid": "3c8e3fe48360de90a1ff1267411aae88", + "search": [ + "fa" + ], + "charRef": 62107 + }, + { + "css": "handshake-o", + "code": 62133, + "uid": "9fecfcfe680a469caedeeb40641a479f", + "search": [], + "charRef": 62108 + }, + { + "css": "envelope-open", + "code": 62134, + "uid": "f89739d9df5c9e70ece9be9cdf66abb6", + "search": [], + "charRef": 62109 + }, + { + "css": "envelope-open-o", + "code": 62135, + "uid": "57ae6bdecc7044555daa84354a8dfe49", + "search": [], + "charRef": 62110 + }, + { + "css": "linode", + "code": 62136, + "uid": "0259fec71de1f22e70877ca024b634fd", + "search": [], + "charRef": 62111 + }, + { + "css": "address-book", + "code": 62137, + "uid": "15899c11210bc9f45fc15a507789f6be", + "search": [], + "charRef": 62112 + }, + { + "css": "address-book-o", + "code": 62138, + "uid": "693e13611b84512c92e6115e0c31934d", + "search": [], + "charRef": 62113 + }, + { + "css": "address-card", + "code": 62139, + "uid": "79d27b578931fd441a6dc885c9dd88a6", + "search": [ + "vcard" + ], + "charRef": 62114 + }, + { + "css": "address-card-o", + "code": 62140, + "uid": "68eb56470b836f19335231578515153e", + "search": [ + "vcard-o" + ], + "charRef": 62115 + }, + { + "css": "user-circle", + "code": 62141, + "uid": "818981e2ad316f18ae61cfa805d41309", + "search": [], + "charRef": 62116 + }, + { + "css": "user-circle-o", + "code": 62142, + "uid": "3fce1eca43f917c8f23e532749abae5d", + "search": [], + "charRef": 62117 + }, + { + "css": "user-o", + "code": 62144, + "uid": "b86df50a2d898bfcd371fa86c0b8b2fb", + "search": [], + "charRef": 62118 + }, + { + "css": "id-badge", + "code": 62145, + "uid": "b2cc036e1ba44934896c345436ac44d1", + "search": [], + "charRef": 62119 + }, + { + "css": "id-card", + "code": 62146, + "uid": "37b41cdae5ec9dab40e0c5bfff8a0ec8", + "search": [ + "drivers-license" + ], + "charRef": 62120 + }, + { + "css": "id-card-o", + "code": 62147, + "uid": "2e6301ac94d0d51566727b9199259451", + "search": [ + "drivers-license-o" + ], + "charRef": 62121 + }, + { + "css": "quora", + "code": 62148, + "uid": "2726ee8140faa11aba6a4183a8a8b903", + "search": [], + "charRef": 62122 + }, + { + "css": "free-code-camp", + "code": 62149, + "uid": "8dc7142e4848751b5d2b0200ba77b991", + "search": [], + "charRef": 62123 + }, + { + "css": "telegram", + "code": 62150, + "uid": "531359183f9fedb14b23666f1308591f", + "search": [], + "charRef": 62124 + }, + { + "css": "thermometer", + "code": 62151, + "uid": "07c8bfac1a39b6c62bc83e23a3c4b706", + "search": [ + "thermometer-full", + "thermometer-4" + ], + "charRef": 62125 + }, + { + "css": "thermometer-3", + "code": 62152, + "uid": "d7ef51ac5d8223e1c4e6551b833a6b44", + "search": [ + "thermometer-three-quarters" + ], + "charRef": 62126 + }, + { + "css": "thermometer-2", + "code": 62153, + "uid": "c22930d29b554d41c0ef882aafd3f8c9", + "search": [ + "thermometer-half" + ], + "charRef": 62127 + }, + { + "css": "thermometer-quarter", + "code": 62154, + "uid": "f50506878717cd58f94b689daa79bfae", + "search": [ + "thermometer-1" + ], + "charRef": 62128 + }, + { + "css": "thermometer-0", + "code": 62155, + "uid": "bc89c320cf57f6c88f1ae7248e12a28f", + "search": [ + "thermometer-empty" + ], + "charRef": 62129 + }, + { + "css": "shower", + "code": 62156, + "uid": "71abe0fa648a63c00b5222c37345b38c", + "search": [], + "charRef": 62130 + }, + { + "css": "bath", + "code": 62157, + "uid": "5d24e595104bfd7117db134253fc9ca1", + "search": [ + "bathtub", + "s15" + ], + "charRef": 62131 + }, + { + "css": "podcast", + "code": 62158, + "uid": "af4312b5501867fa089ec3afeece5630", + "search": [], + "charRef": 62132 + }, + { + "css": "window-maximize", + "code": 62160, + "uid": "07f0832c07f3d9713fffb06c8bffa027", + "search": [], + "charRef": 62133 + }, + { + "css": "window-minimize", + "code": 62161, + "uid": "04f022b8bd044d4ccfffd3887ff72088", + "search": [], + "charRef": 62134 + }, + { + "css": "window-restore", + "code": 62162, + "uid": "d0e62145dbf40f30e47b3819b8b43a8f", + "search": [], + "charRef": 62135 + }, + { + "css": "window-close", + "code": 62163, + "uid": "7394501fc0b17cb7bda99538f92e26d6", + "search": [ + "times-rectangle" + ], + "charRef": 62136 + }, + { + "css": "window-close-o", + "code": 62164, + "uid": "316d3c537e21cb6b56c466bb615b32e6", + "search": [ + "times-rectangle-o" + ], + "charRef": 62137 + }, + { + "css": "bandcamp", + "code": 62165, + "uid": "50eb1aca5fe19bd9eaa1257117cb0419", + "search": [], + "charRef": 62138 + }, + { + "css": "grav", + "code": 62166, + "uid": "527f48749d1d339c73a09fd5f12f77c0", + "search": [], + "charRef": 62139 + }, + { + "css": "etsy", + "code": 62167, + "uid": "0abcdfbaa2ece1cbd5a7896e8cfc4668", + "search": [], + "charRef": 62140 + }, + { + "css": "imdb", + "code": 62168, + "uid": "eea8064584ca4397576380d9de87bfc3", + "search": [], + "charRef": 62141 + }, + { + "css": "ravelry", + "code": 62169, + "uid": "aa34496baad01bf631deaf33a2acbf85", + "search": [], + "charRef": 62142 + }, + { + "css": "eercast", + "code": 62170, + "uid": "4f0e633d65949512c49f9a95c959b5a0", + "search": [], + "charRef": 62143 + }, + { + "css": "microchip", + "code": 62171, + "uid": "1cb3652ffb3492344fa3a675c3ff3290", + "search": [], + "charRef": 62144 + }, + { + "css": "snowflake-o", + "code": 62172, + "uid": "56f2eac13d2b397ff4a54dc38f783b95", + "search": [], + "charRef": 62145 + }, + { + "css": "superpowers", + "code": 62173, + "uid": "d38d01d4665f7aaaaddd789800ef7669", + "search": [], + "charRef": 62146 + }, + { + "css": "wpexplorer", + "code": 62174, + "uid": "74195f8d61ee77a2ba6df97c9ace11e8", + "search": [], + "charRef": 62147 + }, + { + "css": "meetup", + "code": 62176, + "uid": "322a3317bf081dd6a78d5d6a620e1dd5", + "search": [], + "charRef": 62148 + } + ], + "font": { + "version": "4.7.0", + "fontname": "fontawesome", + "fullname": "Font Awesome", + "familyname": "Font Awesome", + "copyright": "Copyright (C) 2016 by Dave Gandy", + "ascent": 850, + "descent": 150, + "weight": "Regular" + }, + "meta": { + "author": "Dave Gandy", + "homepage": "http://fortawesome.github.com/Font-Awesome/", + "email": "dave@davegandy.com", + "twitter": "https://twitter.com/fontawesome/", + "github": "https://github.com/FortAwesome/Font-Awesome", + "license": "SIL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "note", + "code": 9834, + "uid": "39e2e6682c28e1e3b5f49825a19717c4", + "search": [ + "music", + "note", + "song" + ], + "charRef": 62149 + }, + { + "css": "note-beamed", + "code": 9835, + "uid": "fda731b5a4026685e1a9c7e64228e2b2", + "search": [ + "music", + "note", + "song" + ], + "charRef": 62150 + }, + { + "css": "music", + "code": 127925, + "uid": "f2a036a85c0a6a46b0c9709a70e1bb70", + "search": [ + "song", + "music", + "sound" + ], + "charRef": 62151 + }, + { + "css": "search", + "code": 128269, + "uid": "7222571caa5c15f83dcfd447c58d68d9", + "search": [ + "search", + "find" + ], + "charRef": 62152 + }, + { + "css": "flashlight", + "code": 128294, + "uid": "c9b928dc82d7d77033644fcf59dca3b3", + "search": [ + "search", + "find", + "flashlight" + ], + "charRef": 62153 + }, + { + "css": "mail", + "code": 9993, + "uid": "e335adbc2d898c7d85d40c507796e7b4", + "search": [ + "mail", + "email" + ], + "charRef": 62154 + }, + { + "css": "heart", + "code": 9829, + "uid": "0eabe5f8d71cc838484ff39436426d2d", + "search": [ + "heart" + ], + "charRef": 62155 + }, + { + "css": "heart-empty", + "code": 9825, + "uid": "d18071bbf8f0a8cec8d1f556c91c6af0", + "search": [ + "heart" + ], + "charRef": 62156 + }, + { + "css": "star", + "code": 9733, + "uid": "25b34dea4784f72c710454f32ff8fa2b", + "search": [ + "star" + ], + "charRef": 62157 + }, + { + "css": "star-empty", + "code": 9734, + "uid": "0e3f1335f83cca67329b2c4bcb3aaec5", + "search": [ + "star" + ], + "charRef": 62158 + }, + { + "css": "user", + "code": 128100, + "uid": "bbd66ef66bb8fa9edde54d9a90b89150", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62159 + }, + { + "css": "users", + "code": 128101, + "uid": "ecf8edb95c3f45eb433b4cce7ba9f740", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 62160 + }, + { + "css": "user-add", + "code": 59136, + "uid": "6274e0601f2feef7eced89146e708de0", + "search": [ + "profile", + "contact", + "user", + "add" + ], + "charRef": 62161 + }, + { + "css": "video", + "code": 127916, + "uid": "6341ebcbe1ed1f6777c1b9527ead368e", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 62162 + }, + { + "css": "picture", + "code": 127748, + "uid": "3def559c3c39b8500882e02892b7daa8", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 62163 + }, + { + "css": "camera", + "code": 128247, + "uid": "85017ab6ca074831a8de771b40e9640c", + "search": [ + "camera", + "photo" + ], + "charRef": 62164 + }, + { + "css": "layout", + "code": 9871, + "uid": "5e9f01871d44e56b45ecbfd00f4dbc3a", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 62165 + }, + { + "css": "menu", + "code": 9776, + "uid": "2cfb3f2b46b34a1790aec0aa846297b6", + "search": [ + "menu", + "list" + ], + "charRef": 62166 + }, + { + "css": "check", + "code": 10003, + "uid": "14017aae737730faeda4a6fd8fb3a5f0", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62167 + }, + { + "css": "cancel", + "code": 10005, + "uid": "c709da589c923ba3c2ad48d9fc563e93", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62168 + }, + { + "css": "cancel-circled", + "code": 10006, + "uid": "c759418c008e9562944080fee617fc76", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62169 + }, + { + "css": "cancel-squared", + "code": 10062, + "uid": "bf45c39702763f1803b550c36a0ceb12", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62170 + }, + { + "css": "plus", + "code": 43, + "uid": "70370693ada58ef0a60fa0984fe8d52a", + "search": [ + "plus" + ], + "charRef": 62171 + }, + { + "css": "plus-circled", + "code": 10133, + "uid": "a66cdc7278e6b33b8bd44a141f5e1a8d", + "search": [ + "plus" + ], + "charRef": 62172 + }, + { + "css": "plus-squared", + "code": 8862, + "uid": "9e1c33b6849ceb08db8acfaf02188b7d", + "search": [ + "plus", + "expand" + ], + "charRef": 62173 + }, + { + "css": "minus", + "code": 45, + "uid": "1256e3054823e304d7e452a589cf8bb8", + "search": [ + "minus" + ], + "charRef": 62174 + }, + { + "css": "minus-circled", + "code": 10134, + "uid": "3eb93689881ad0804f87052a53edc2b6", + "search": [ + "minus" + ], + "charRef": 62175 + }, + { + "css": "minus-squared", + "code": 8863, + "uid": "4ffa544c1a81c905f0a8a5745d8b9faa", + "search": [ + "minus", + "collapse" + ], + "charRef": 62176 + }, + { + "css": "help", + "code": 10067, + "uid": "3a230e539a4f3b904debd04c6c155034", + "search": [ + "help", + "question" + ], + "charRef": 62177 + }, + { + "css": "help-circled", + "code": 59140, + "uid": "de9a631a7d18106aea1c89ba51b1990a", + "search": [ + "help", + "question" + ], + "charRef": 62178 + }, + { + "css": "info", + "code": 8505, + "uid": "63b86fedd4ee9ad2105f54f4888e7088", + "search": [ + "info" + ], + "charRef": 62179 + }, + { + "css": "info-circled", + "code": 59141, + "uid": "7e4164950ffa4990961958b2d6318658", + "search": [ + "info" + ], + "charRef": 62180 + }, + { + "css": "back", + "code": 128281, + "uid": "3ba4275937db277075fc47d6b5a69a2e", + "search": [ + "back", + "return" + ], + "charRef": 62181 + }, + { + "css": "home", + "code": 8962, + "uid": "513ac180ff85bd275f2b736720cbbf5e", + "search": [ + "home" + ], + "charRef": 62182 + }, + { + "css": "link", + "code": 128279, + "uid": "815503841e980c848f55e0271deacead", + "search": [ + "link", + "url" + ], + "charRef": 62183 + }, + { + "css": "attach", + "code": 128206, + "uid": "44b9e75612c5fad5505edd70d071651f", + "search": [ + "attach", + "clip" + ], + "charRef": 62184 + }, + { + "css": "lock", + "code": 128274, + "uid": "1a7104205ea96e6f40ac716d0ca72f21", + "search": [ + "lock" + ], + "charRef": 62185 + }, + { + "css": "lock-open", + "code": 128275, + "uid": "e81fc3a0d39ace6ee735d7b24eedd56d", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 62186 + }, + { + "css": "eye", + "code": 59146, + "uid": "25fc99a30fecc4021fdcae5fff5ba9ac", + "search": [ + "eye", + "subscribe" + ], + "charRef": 62187 + }, + { + "css": "tag", + "code": 59148, + "uid": "875ab0f6d417223f6ec76ff7f0a4baed", + "search": [ + "tag", + "price", + "offer" + ], + "charRef": 62188 + }, + { + "css": "bookmark", + "code": 128278, + "uid": "23912d5623126e14b7b137c3ba557168", + "search": [ + "bookmark" + ], + "charRef": 62189 + }, + { + "css": "bookmarks", + "code": 128209, + "uid": "8538a2249db7f07ae75411886732fb87", + "search": [ + "bookmarks" + ], + "charRef": 62190 + }, + { + "css": "flag", + "code": 9873, + "uid": "1d2a6c3d9236b88b0f185c7c4530fa52", + "search": [ + "flag" + ], + "charRef": 62191 + }, + { + "css": "thumbs-up", + "code": 128077, + "uid": "7ad4d2306ebda8452e5e3eff3cd8241c", + "search": [ + "thumbs", + "up", + "like", + "love", + "vote" + ], + "charRef": 62192 + }, + { + "css": "thumbs-down", + "code": 128078, + "uid": "429fba993b729174468a9493613ad1ba", + "search": [ + "thumbs", + "down", + "dislike", + "unlike", + "vote" + ], + "charRef": 62193 + }, + { + "css": "download", + "code": 128229, + "uid": "b08cfe8039de2ce815686aced2caef06", + "search": [ + "download" + ], + "charRef": 62194 + }, + { + "css": "upload", + "code": 128228, + "uid": "44199a54057e6e264fde61a49b034171", + "search": [ + "upload" + ], + "charRef": 62195 + }, + { + "css": "upload-cloud", + "code": 59153, + "uid": "5d595124cecf472869d1cdc020da0ccc", + "search": [ + "upload", + "cloud" + ], + "charRef": 62196 + }, + { + "css": "reply", + "code": 59154, + "uid": "b6fc2f656ef87275889422e19550680a", + "search": [ + "reply" + ], + "charRef": 62197 + }, + { + "css": "reply-all", + "code": 59155, + "uid": "1a4b54ba5618e5364fc47a3d26c1cf59", + "search": [ + "reply" + ], + "charRef": 62198 + }, + { + "css": "forward", + "code": 10150, + "uid": "ec347024a3640deebeeab53fd0d5ad03", + "search": [ + "forward" + ], + "charRef": 62199 + }, + { + "css": "quote", + "code": 10078, + "uid": "c3e5dafba1739ef33cc574c7484febf7", + "search": [ + "quote" + ], + "charRef": 62200 + }, + { + "css": "code", + "code": 59156, + "uid": "b6f32db98a3de777f5ae3005191b1831", + "search": [ + "code" + ], + "charRef": 62201 + }, + { + "css": "export", + "code": 59157, + "uid": "390d6d13398cbf8c8c3c5493f7d34088", + "search": [ + "export", + "share" + ], + "charRef": 62202 + }, + { + "css": "pencil", + "code": 9998, + "uid": "c77fd2fd065b5fe16d6f2b41e190b266", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62203 + }, + { + "css": "feather", + "code": 10002, + "uid": "bcb868184ff9c35f8aef564f50c0d649", + "search": [ + "pen", + "write", + "reply", + "edit", + "feather" + ], + "charRef": 62204 + }, + { + "css": "print", + "code": 59158, + "uid": "28f124a10127a47b9d9472699193d75a", + "search": [ + "print" + ], + "charRef": 62205 + }, + { + "css": "retweet", + "code": 59159, + "uid": "216891b0093d4dbef19877d5b00d1b16", + "search": [ + "retweet", + "twitter" + ], + "charRef": 62206 + }, + { + "css": "keyboard", + "code": 9000, + "uid": "005a38f6af74b31aeb817fedb09d2175", + "search": [ + "keyboard" + ], + "charRef": 62207 + }, + { + "css": "comment", + "code": 59160, + "uid": "16890362e811b4cb8de36282b071fe30", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62208 + }, + { + "css": "chat", + "code": 59168, + "uid": "2c0b53280f82068f6bab4e2200025d9f", + "search": [ + "chat", + "talk" + ], + "charRef": 62209 + }, + { + "css": "bell", + "code": 128276, + "uid": "2c5335c6e56b876139d7a58ab2f4b2fe", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 62210 + }, + { + "css": "attention", + "code": 9888, + "uid": "97902f87200ce74d181044df02a0458d", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 62211 + }, + { + "css": "alert", + "code": 128165, + "uid": "39a5a0d7ce8342d149373b2ce219503a", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 62212 + }, + { + "css": "vcard", + "code": 59170, + "uid": "457c8e2b305e7af74c1be4f07a01ca92", + "search": [ + "contact", + "card", + "vcard" + ], + "charRef": 62213 + }, + { + "css": "address", + "code": 59171, + "uid": "540b6a4262be769515c79700618b4aea", + "search": [ + "address" + ], + "charRef": 62214 + }, + { + "css": "location", + "code": 59172, + "uid": "a42b598e4298f3319b25a2702a02e7ff", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62215 + }, + { + "css": "map", + "code": 59175, + "uid": "64f5a50cf7ac972a56a9a511acb5d28e", + "search": [ + "down" + ], + "charRef": 62216 + }, + { + "css": "direction", + "code": 10146, + "uid": "f8513213799b244e66b2836aeee88531", + "search": [ + "direction" + ], + "charRef": 62217 + }, + { + "css": "compass", + "code": 59176, + "uid": "c117f17c0316ef71fb2a658c4c273002", + "search": [ + "compass" + ], + "charRef": 62218 + }, + { + "css": "cup", + "code": 9749, + "uid": "9bdc80f58999873c5a8079ad2d7f4143", + "search": [ + "cup" + ], + "charRef": 62219 + }, + { + "css": "trash", + "code": 59177, + "uid": "2626e3a1bbcd90e45849af3b58a1d594", + "search": [ + "trash", + "delete" + ], + "charRef": 62220 + }, + { + "css": "doc", + "code": 59184, + "uid": "49bd3e825b8267f976f6d1ad391e2f4d", + "search": [ + "doc", + "article" + ], + "charRef": 62221 + }, + { + "css": "docs", + "code": 59190, + "uid": "922ab2cb66943a83de969990289ef1dc", + "search": [ + "doc", + "article" + ], + "charRef": 62222 + }, + { + "css": "doc-landscape", + "code": 59191, + "uid": "8782cc70184b33096ae927590d1fadc4", + "search": [ + "doc", + "article" + ], + "charRef": 62223 + }, + { + "css": "doc-text", + "code": 128196, + "uid": "1189604bf305b6b03a74685ce60e6632", + "search": [ + "doc", + "text", + "article" + ], + "charRef": 62224 + }, + { + "css": "doc-text-inv", + "code": 59185, + "uid": "1d7c1d30ad49a988556273a238097c2a", + "search": [ + "doc", + "text", + "article" + ], + "charRef": 62225 + }, + { + "css": "newspaper", + "code": 128240, + "uid": "da0fd38d651815e3a12f6c030ff1fe5b", + "search": [ + "newspaper", + "article" + ], + "charRef": 62226 + }, + { + "css": "book-open", + "code": 128214, + "uid": "51727ca007aa35ceabcaffc28934faee", + "search": [ + "book", + "doc" + ], + "charRef": 62227 + }, + { + "css": "book", + "code": 128213, + "uid": "48b79f27e4798f23bafa07b55dbe5b73", + "search": [ + "book" + ], + "charRef": 62228 + }, + { + "css": "folder", + "code": 128193, + "uid": "0ccb084ddeeae372673793ed0b45bb4a", + "search": [ + "folder" + ], + "charRef": 62229 + }, + { + "css": "archive", + "code": 59192, + "uid": "96ea1be71f597a5bdfc8f791ada4f651", + "search": [ + "archive" + ], + "charRef": 62230 + }, + { + "css": "box", + "code": 128230, + "uid": "cc05df515bebe11df3ada0a5910a8f6d", + "search": [ + "box" + ], + "charRef": 62231 + }, + { + "css": "rss", + "code": 59194, + "uid": "3e617d8049807e128c80d0344ba09e37", + "search": [ + "rss" + ], + "charRef": 62232 + }, + { + "css": "phone", + "code": 128222, + "uid": "5854855e963044f93b15738a5bb27a29", + "search": [ + "phone", + "telephone", + "call" + ], + "charRef": 62233 + }, + { + "css": "cog", + "code": 9881, + "uid": "bc64550dd022ce21604f97309b346cea", + "search": [ + "settings", + "cog", + "gear", + "params" + ], + "charRef": 62234 + }, + { + "css": "tools", + "code": 9874, + "uid": "6a7b9d4863bb7e6c79e9457a72d689b6", + "search": [ + "tools", + "params" + ], + "charRef": 62235 + }, + { + "css": "share", + "code": 59196, + "uid": "91426c82d94428a33353e495418435e3", + "search": [ + "share" + ], + "charRef": 62236 + }, + { + "css": "shareable", + "code": 59198, + "uid": "e4536ab890a215f2fe8952de5c2fe354", + "search": [ + "shareable" + ], + "charRef": 62237 + }, + { + "css": "basket", + "code": 59197, + "uid": "e126987944593dfee041f8e2a68145db", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 62238 + }, + { + "css": "bag", + "code": 128092, + "uid": "2c71ee1c65e1992ba32d5ffc5ee7f337", + "search": [ + "bag", + "shopping", + "cart" + ], + "charRef": 62239 + }, + { + "css": "calendar", + "code": 128197, + "uid": "413717f5ea649e8d8b93938be277264a", + "search": [ + "calendar", + "date" + ], + "charRef": 62240 + }, + { + "css": "login", + "code": 59200, + "uid": "a204f0fa972408eaae5a363c444991b2", + "search": [ + "login" + ], + "charRef": 62241 + }, + { + "css": "logout", + "code": 59201, + "uid": "2d76f2c8d13be40694ecadfea7fb83c3", + "search": [ + "logout" + ], + "charRef": 62242 + }, + { + "css": "mic", + "code": 127908, + "uid": "1e099a876c8a6a83f10c9bafa9886614", + "search": [ + "mic" + ], + "charRef": 62243 + }, + { + "css": "mute", + "code": 128263, + "uid": "2f750a9be253e8e451209574336e7020", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 62244 + }, + { + "css": "sound", + "code": 128266, + "uid": "ef51920c7a9bed4d87f53709db115e34", + "search": [ + "volume", + "sound" + ], + "charRef": 62245 + }, + { + "css": "volume", + "code": 59202, + "uid": "edd88296295d95d6510e66d9a6bbd6c3", + "search": [ + "volume", + "sound" + ], + "charRef": 62246 + }, + { + "css": "clock", + "code": 128340, + "uid": "8663320a860b00f26e94d3d15c9ba99a", + "search": [ + "clock", + "time" + ], + "charRef": 62247 + }, + { + "css": "hourglass", + "code": 9203, + "uid": "7f6916533c0842b6cec699fd773693d3", + "search": [ + "clock", + "hourglass", + "busy", + "wait" + ], + "charRef": 62248 + }, + { + "css": "lamp", + "code": 128161, + "uid": "4b20e1deee87faf4c3fab735fbd4bc1a", + "search": [ + "idea", + "lamp", + "light" + ], + "charRef": 62249 + }, + { + "css": "light-down", + "code": 128261, + "uid": "2d14369ed7f129e779eaa30195368218", + "search": [ + "light", + "dim", + "bright" + ], + "charRef": 62250 + }, + { + "css": "light-up", + "code": 128262, + "uid": "f8e120c48c070f8afd2d072651b4fb9f", + "search": [ + "light", + "dim", + "bright" + ], + "charRef": 62251 + }, + { + "css": "adjust", + "code": 9681, + "uid": "f6fa10cb3ffec7becb60834f50bb0182", + "search": [ + "adjust", + "contrast" + ], + "charRef": 62252 + }, + { + "css": "block", + "code": 128683, + "uid": "29e7f6072d5935d7818204d9b088508b", + "search": [ + "block", + "deny" + ], + "charRef": 62253 + }, + { + "css": "resize-full", + "code": 59204, + "uid": "3a3f65b92c9b2fcbb3a8dcd0d42ee806", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62254 + }, + { + "css": "resize-small", + "code": 59206, + "uid": "108c8ac13badc00ce66da014436e6eb1", + "search": [ + "resize" + ], + "charRef": 62255 + }, + { + "css": "popup", + "code": 59212, + "uid": "9248ce8062fb4707a6919bfe9ac1af8e", + "search": [ + "popup", + "window" + ], + "charRef": 62256 + }, + { + "css": "publish", + "code": 59213, + "uid": "77bcf90f0c68635bab5abfb4ed736696", + "search": [ + "publish" + ], + "charRef": 62257 + }, + { + "css": "window", + "code": 59214, + "uid": "744a71fe4b5ab7c4f4b7cd598e9bf75a", + "search": [ + "window" + ], + "charRef": 62258 + }, + { + "css": "arrow-combo", + "code": 59215, + "uid": "0a3192de65a73ca1501b073ad601f87d", + "search": [ + "arrow", + "dropdown", + "combobox" + ], + "charRef": 62259 + }, + { + "css": "down-circled", + "code": 59224, + "uid": "40ef3542646bed70cb63f1290c9d98c9", + "search": [ + "arrow", + "down", + "download" + ], + "charRef": 62260 + }, + { + "css": "left-circled", + "code": 59225, + "uid": "0db0310883e0bdacfd1bb2d394238e8a", + "search": [ + "arrow", + "left" + ], + "charRef": 62261 + }, + { + "css": "right-circled", + "code": 59226, + "uid": "52725ff4d4042964bd3a60609bf3695b", + "search": [ + "arrow", + "right" + ], + "charRef": 62262 + }, + { + "css": "up-circled", + "code": 59227, + "uid": "64691230b90991883f94c6dfb2afc90a", + "search": [ + "arrow", + "up", + "upload" + ], + "charRef": 62263 + }, + { + "css": "down-open", + "code": 59228, + "uid": "8704cd847a47b64265b8bb110c8b4d62", + "search": [ + "arrow", + "down" + ], + "charRef": 62264 + }, + { + "css": "left-open", + "code": 59229, + "uid": "c311c48d79488965b0fab7f9cd12b6b5", + "search": [ + "arrow", + "left" + ], + "charRef": 62265 + }, + { + "css": "right-open", + "code": 59230, + "uid": "749e7d90a9182938180f1d2d8c33584e", + "search": [ + "arrow", + "right" + ], + "charRef": 62266 + }, + { + "css": "up-open", + "code": 59231, + "uid": "9c7ff134960bb5a82404e4aeaab366d9", + "search": [ + "arrow", + "up" + ], + "charRef": 62267 + }, + { + "css": "down-open-mini", + "code": 59232, + "uid": "f11c9e95ae5eaa84d193e8fa1d38c6f9", + "search": [ + "arrow", + "down" + ], + "charRef": 62268 + }, + { + "css": "left-open-mini", + "code": 59233, + "uid": "592717bd601645d61517d2a584d04127", + "search": [ + "arrow", + "left" + ], + "charRef": 62269 + }, + { + "css": "right-open-mini", + "code": 59234, + "uid": "37f6cfbb4062ed0d01b351ec35c334ff", + "search": [ + "arrow", + "right" + ], + "charRef": 62270 + }, + { + "css": "up-open-mini", + "code": 59235, + "uid": "9e251fb8e9e1c71ab09683468e0479a3", + "search": [ + "arrow", + "up" + ], + "charRef": 62271 + }, + { + "css": "down-open-big", + "code": 59236, + "uid": "289b5f92f23acf1059c93fbf401c1ad5", + "search": [ + "arrow", + "down" + ], + "charRef": 62272 + }, + { + "css": "left-open-big", + "code": 59237, + "uid": "884cfc3e6e2d456dd2a2ca0dbb9e6337", + "search": [ + "arrow", + "left" + ], + "charRef": 62273 + }, + { + "css": "right-open-big", + "code": 59238, + "uid": "004882ab2d5c418c5b2060e80596279b", + "search": [ + "arrow", + "right" + ], + "charRef": 62274 + }, + { + "css": "up-open-big", + "code": 59239, + "uid": "0805cca616b3c12714f35af4d0912c10", + "search": [ + "arrow", + "up" + ], + "charRef": 62275 + }, + { + "css": "down", + "code": 11015, + "uid": "d5098cb09be5827a2911dbab5af49ad2", + "search": [ + "arrow", + "down" + ], + "charRef": 62276 + }, + { + "css": "left", + "code": 11013, + "uid": "6acd5cf005d48f96787350e72bd45688", + "search": [ + "arrow", + "left" + ], + "charRef": 62277 + }, + { + "css": "right", + "code": 10145, + "uid": "9e67bfab0143d9511f8eef6897caeb88", + "search": [ + "arrow", + "right" + ], + "charRef": 62278 + }, + { + "css": "up", + "code": 11014, + "uid": "43c4064ec1260d0e55c37e0467c75cbb", + "search": [ + "arrow", + "up" + ], + "charRef": 62279 + }, + { + "css": "down-dir", + "code": 9662, + "uid": "7e89c12b577c31bc91bfb61bb597f01f", + "search": [ + "arrow", + "down" + ], + "charRef": 62280 + }, + { + "css": "left-dir", + "code": 9666, + "uid": "9aeaf29161eb005a308bbd624d6e066a", + "search": [ + "arrow", + "left" + ], + "charRef": 62281 + }, + { + "css": "right-dir", + "code": 9656, + "uid": "ff9a85aa20950dcc0615a2707a2b3f8e", + "search": [ + "arrow", + "right" + ], + "charRef": 62282 + }, + { + "css": "up-dir", + "code": 9652, + "uid": "401b644723fb2f20b0df30cce7745c18", + "search": [ + "arrow", + "up" + ], + "charRef": 62283 + }, + { + "css": "down-bold", + "code": 58544, + "uid": "78944e4652d6f9b8b506eaef331308cd", + "search": [ + "arrow", + "down" + ], + "charRef": 62284 + }, + { + "css": "left-bold", + "code": 58541, + "uid": "0222089fb4194cc714dcc1ffd2525c11", + "search": [ + "arrow", + "left" + ], + "charRef": 62285 + }, + { + "css": "right-bold", + "code": 58542, + "uid": "1a90b06af8614b12d8c8a5b90cc19ab3", + "search": [ + "arrow", + "right" + ], + "charRef": 62286 + }, + { + "css": "up-bold", + "code": 58543, + "uid": "8c8f768607b8fc4c92c0f85b488e87e8", + "search": [ + "arrow", + "up" + ], + "charRef": 62287 + }, + { + "css": "down-thin", + "code": 8595, + "uid": "a30a32d49f80bb534c062ae1743ef433", + "search": [ + "arrow", + "down" + ], + "charRef": 62288 + }, + { + "css": "left-thin", + "code": 8592, + "uid": "8d8f4722d16e95290858eaf294d9d830", + "search": [ + "arrow", + "left" + ], + "charRef": 62289 + }, + { + "css": "right-thin", + "code": 8594, + "uid": "ef3eda51383ce050517892df3fc05ffc", + "search": [ + "arrow", + "right" + ], + "charRef": 62290 + }, + { + "css": "up-thin", + "code": 8593, + "uid": "dbc97808cba7d0c135c7054e7a85fb86", + "search": [ + "arrow", + "up" + ], + "charRef": 62291 + }, + { + "css": "ccw", + "code": 10226, + "uid": "465bb89b6f204234e5787c326b4ae54c", + "search": [ + "reload", + "undo", + "arrow" + ], + "charRef": 62292 + }, + { + "css": "cw", + "code": 10227, + "uid": "bb46b15cb78cc4cc05d3d715d522ac4d", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 62293 + }, + { + "css": "arrows-ccw", + "code": 128260, + "uid": "3bd18d47a12b8709e9f4fe9ead4f7518", + "search": [ + "circle", + "sync", + "reload", + "refresh" + ], + "charRef": 62294 + }, + { + "css": "level-down", + "code": 8627, + "uid": "fa0118a65fc8dee739469f6901bbd189", + "search": [ + "down" + ], + "charRef": 62295 + }, + { + "css": "level-up", + "code": 8624, + "uid": "5308d824454af8ec7835786e272361a9", + "search": [ + "back", + "return" + ], + "charRef": 62296 + }, + { + "css": "shuffle", + "code": 128256, + "uid": "3d349daaea304032a7669b4f24931b6c", + "search": [ + "shuffle", + "random" + ], + "charRef": 62297 + }, + { + "css": "loop", + "code": 128257, + "uid": "8e0220796066428d6ddea96a4f1b5131", + "search": [ + "loop", + "repeat" + ], + "charRef": 62298 + }, + { + "css": "switch", + "code": 8646, + "uid": "f0eac0958921fe45b85d01b79d76e86b", + "search": [ + "switch", + "exchange" + ], + "charRef": 62299 + }, + { + "css": "play", + "code": 9654, + "uid": "cb13afd4722a849d48056540bb74c47e", + "search": [ + "play", + "player" + ], + "charRef": 62300 + }, + { + "css": "stop", + "code": 9632, + "uid": "48f2e18872fe74d4579a4c8a1527fc1e", + "search": [ + "stop", + "player" + ], + "charRef": 62301 + }, + { + "css": "pause", + "code": 9097, + "uid": "d8d378d0ce413f231dfa37592e39c227", + "search": [ + "pause", + "player" + ], + "charRef": 62302 + }, + { + "css": "record", + "code": 9899, + "uid": "e188c02f740feff7e2d2bce1950b75fa", + "search": [ + "record", + "player" + ], + "charRef": 62303 + }, + { + "css": "to-end", + "code": 9197, + "uid": "0afbb00323696f49e9c47f4d9fe6390b", + "search": [ + "right", + "player" + ], + "charRef": 62304 + }, + { + "css": "to-start", + "code": 9198, + "uid": "ceefe7653a4f6edaacce9e7f196cec5a", + "search": [ + "left", + "player" + ], + "charRef": 62305 + }, + { + "css": "fast-forward", + "code": 9193, + "uid": "18f7c393e3532e40edd45607c9d99988", + "search": [ + "right", + "player" + ], + "charRef": 62306 + }, + { + "css": "fast-backward", + "code": 9194, + "uid": "85806fd8ab907f45d34f976354a0df23", + "search": [ + "left", + "player" + ], + "charRef": 62307 + }, + { + "css": "progress-0", + "code": 59240, + "uid": "be998d5ee625a58912ae630f34cc8419", + "search": [ + "progress", + "charge" + ], + "charRef": 62308 + }, + { + "css": "progress-1", + "code": 59241, + "uid": "054519608bca087aa306252471dda9c4", + "search": [ + "progress", + "charge" + ], + "charRef": 62309 + }, + { + "css": "progress-2", + "code": 59242, + "uid": "3e49435dd1950a0b7543e13256c89e52", + "search": [ + "progress", + "charge" + ], + "charRef": 62310 + }, + { + "css": "progress-3", + "code": 59243, + "uid": "d924bc68683f68ecf5e09e49731fd59a", + "search": [ + "progress", + "charge" + ], + "charRef": 62311 + }, + { + "css": "target", + "code": 127919, + "uid": "3eadc3e443cf1c7e17f1b44d21254c00", + "search": [ + "target" + ], + "charRef": 62312 + }, + { + "css": "palette", + "code": 127912, + "uid": "80451d627470ea7f977a263fdb771d7b", + "search": [ + "palette" + ], + "charRef": 62313 + }, + { + "css": "list", + "code": 57349, + "uid": "3626b3f3a0b284e7f4166b815719aece", + "search": [ + "list" + ], + "charRef": 62314 + }, + { + "css": "list-add", + "code": 57347, + "uid": "97bd5542ed3e143d2ee9b60e14487615", + "search": [ + "add", + "list" + ], + "charRef": 62315 + }, + { + "css": "signal", + "code": 128246, + "uid": "84a7262985600b683bbab0da9298776d", + "search": [ + "broadcast", + "wifi", + "signal" + ], + "charRef": 62316 + }, + { + "css": "trophy", + "code": 127942, + "uid": "978aa8facd816df874039e139cb0cdde", + "search": [ + "top", + "trophy" + ], + "charRef": 62317 + }, + { + "css": "battery", + "code": 128267, + "uid": "a51290161c48d96d7f2e2151a4cbcde1", + "search": [ + "battery" + ], + "charRef": 62318 + }, + { + "css": "back-in-time", + "code": 59249, + "uid": "89eb512cb82a1c3fe83cb16134f9876c", + "search": [ + "back", + "time" + ], + "charRef": 62319 + }, + { + "css": "monitor", + "code": 128187, + "uid": "b7a336095aa4535c3689cb557edf23db", + "search": [ + "tv", + "screen", + "monitor" + ], + "charRef": 62320 + }, + { + "css": "mobile", + "code": 128241, + "uid": "767fede84586366cd7d6c835be745454", + "search": [ + "mobile", + "iphone" + ], + "charRef": 62321 + }, + { + "css": "network", + "code": 59254, + "uid": "414fe97e4af5215a06d29be0f2cecdf5", + "search": [ + "net" + ], + "charRef": 62322 + }, + { + "css": "cd", + "code": 128191, + "uid": "16f88519423df34fc5c48be7ded81b8f", + "search": [ + "cd", + "vinyl" + ], + "charRef": 62323 + }, + { + "css": "inbox", + "code": 59255, + "uid": "b32d88adf7cd6bfa8d0e177dfa642a4d", + "search": [ + "inbox" + ], + "charRef": 62324 + }, + { + "css": "install", + "code": 59256, + "uid": "d83b7429002f7b0b206c8d550034212b", + "search": [ + "install" + ], + "charRef": 62325 + }, + { + "css": "globe", + "code": 127758, + "uid": "6a12c2b74456ea21cc984e11dec227a1", + "search": [ + "globe" + ], + "charRef": 62326 + }, + { + "css": "cloud", + "code": 9729, + "uid": "114fed43140e2b5ce42c48b95c19375b", + "search": [ + "cloud" + ], + "charRef": 62327 + }, + { + "css": "cloud-thunder", + "code": 9928, + "uid": "66a40c7c0ee5ea61f4b6aa0dd0f9ebb9", + "search": [ + "cloud", + "thunder", + "bolt" + ], + "charRef": 62328 + }, + { + "css": "flash", + "code": 9889, + "uid": "98c63f6b98c543b52d4c43bcd486d28f", + "search": [ + "flash", + "bolt" + ], + "charRef": 62329 + }, + { + "css": "moon", + "code": 9789, + "uid": "0d03db7afd4857accf1821efdc8ea72b", + "search": [ + "moon", + "sleep" + ], + "charRef": 62330 + }, + { + "css": "flight", + "code": 9992, + "uid": "6e8aea8fff9525dfc5149f0c03669091", + "search": [ + "flight", + "plane", + "airplane", + "fly" + ], + "charRef": 62331 + }, + { + "css": "paper-plane", + "code": 59291, + "uid": "db112402805d9dadc01ce009fbfdb914", + "search": [ + "paper", + "plane", + "fly" + ], + "charRef": 62332 + }, + { + "css": "leaf", + "code": 127810, + "uid": "41d534223ef447a01af3e2f629ec70eb", + "search": [ + "leaf" + ], + "charRef": 62333 + }, + { + "css": "lifebuoy", + "code": 59272, + "uid": "2f9f67ee4354feef8c1f51e03bac6ef3", + "search": [ + "lifebuoy" + ], + "charRef": 62334 + }, + { + "css": "mouse", + "code": 59273, + "uid": "97c6901d8db077614e77b089d4eedac8", + "search": [ + "mouse", + "website" + ], + "charRef": 62335 + }, + { + "css": "briefcase", + "code": 128188, + "uid": "9ea7cce5e08e5ac2c225fabf2e6dc353", + "search": [ + "briefcase" + ], + "charRef": 62336 + }, + { + "css": "suitcase", + "code": 59278, + "uid": "11dd26ebf6934bf750a9156b353d7f2d", + "search": [ + "suitcase" + ], + "charRef": 62337 + }, + { + "css": "dot", + "code": 59275, + "uid": "d2c6b59d9a239140cb76be0627480855", + "search": [ + "dot" + ], + "charRef": 62338 + }, + { + "css": "dot-2", + "code": 59276, + "uid": "13b11ab72c6ae9c97ee12428e17f3a4e", + "search": [ + "dot", + "flickr" + ], + "charRef": 62339 + }, + { + "css": "dot-3", + "code": 59277, + "uid": "d10920db2e79c997c5e783279291970c", + "search": [ + "dot" + ], + "charRef": 62340 + }, + { + "css": "brush", + "code": 59290, + "uid": "39c4d0e225a1263a398a47523cb5b9bd", + "search": [ + "brush" + ], + "charRef": 62341 + }, + { + "css": "magnet", + "code": 59297, + "uid": "d55e21e6468c04c5ca38a6560b27d1aa", + "search": [ + "magnet" + ], + "charRef": 62342 + }, + { + "css": "infinity", + "code": 8734, + "uid": "34ba50fe8e4f95e7f3d76c6534814a70", + "search": [ + "infinity" + ], + "charRef": 62343 + }, + { + "css": "erase", + "code": 9003, + "uid": "e8239f8188c76c925be4bd1bbcc013ac", + "search": [ + "erase" + ], + "charRef": 62344 + }, + { + "css": "chart-pie", + "code": 59217, + "uid": "fb5082fac1794b69a1381196219a836e", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62345 + }, + { + "css": "chart-line", + "code": 128200, + "uid": "7184d8171b6a9b18eabbace94cca21db", + "search": [ + "chart", + "graph", + "line", + "diagram" + ], + "charRef": 62346 + }, + { + "css": "chart-bar", + "code": 128202, + "uid": "7d90b6cb3f3783170a96b09e5f0de6d5", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 62347 + }, + { + "css": "chart-area", + "code": 128318, + "uid": "32b4054f35918992f723e39f4095f005", + "search": [ + "chart", + "area", + "diagram" + ], + "charRef": 62348 + }, + { + "css": "tape", + "code": 9991, + "uid": "ed62f5f10b256b0a959e6c847ed8f4a6", + "search": [ + "tape", + "voice mail" + ], + "charRef": 62349 + }, + { + "css": "graduation-cap", + "code": 127891, + "uid": "ef74ff62feda486fd414410e782b598a", + "search": [ + "graduation", + "study" + ], + "charRef": 62350 + }, + { + "css": "language", + "code": 59218, + "uid": "ddecf5ad7935e3fb1b70dac6ed00d06a", + "search": [ + "language", + "translate" + ], + "charRef": 62351 + }, + { + "css": "ticket", + "code": 127915, + "uid": "333bae7aaf7395d1004875be5a075661", + "search": [ + "ticket" + ], + "charRef": 62352 + }, + { + "css": "water", + "code": 128166, + "uid": "36a1cee80657a9c66e8384dd57bed66c", + "search": [ + "whater", + "wash" + ], + "charRef": 62353 + }, + { + "css": "droplet", + "code": 128167, + "uid": "4efb719e797c54b3c58e5ae061d29d53", + "search": [ + "droplet", + "tint" + ], + "charRef": 62354 + }, + { + "css": "air", + "code": 59219, + "uid": "5f3a0ebf2d13f60ec7ed76eb41ba9bb2", + "search": [], + "charRef": 62355 + }, + { + "css": "credit-card", + "code": 128179, + "uid": "c5cd6ea1981cecdd85c42d9d209bc3b8", + "search": [ + "card", + "plastic", + "credit" + ], + "charRef": 62356 + }, + { + "css": "floppy", + "code": 128190, + "uid": "191bcf63575a78def53c907c3d3bf7f0", + "search": [ + "floppy", + "save" + ], + "charRef": 62357 + }, + { + "css": "clipboard", + "code": 128203, + "uid": "b95cfc96d48a72dd665e0ab109880b5e", + "search": [ + "clipboard" + ], + "charRef": 62358 + }, + { + "css": "megaphone", + "code": 128227, + "uid": "489090690d8bd1745e365485946e20a8", + "search": [ + "megaphone", + "bullhorn" + ], + "charRef": 62359 + }, + { + "css": "database", + "code": 59220, + "uid": "248db7c0563d8cee80b7041f7736dcad", + "search": [ + "database" + ], + "charRef": 62360 + }, + { + "css": "drive", + "code": 59221, + "uid": "603d5ccab42d916e79d7c0fcdb56a614", + "search": [ + "drive", + "disk", + "hdd" + ], + "charRef": 62361 + }, + { + "css": "bucket", + "code": 59222, + "uid": "8ea66d97faf9816abd34f48f3f26d216", + "search": [ + "bucket" + ], + "charRef": 62362 + }, + { + "css": "thermometer", + "code": 59223, + "uid": "d4939d1f4e5f03f6e58900b2ac8f1c6c", + "search": [ + "thermometer" + ], + "charRef": 62363 + }, + { + "css": "key", + "code": 128273, + "uid": "8beac4a5fd5bed9f82ca7a96cc8ba218", + "search": [ + "key", + "password" + ], + "charRef": 62364 + }, + { + "css": "flow-cascade", + "code": 59280, + "uid": "898ddc67cb7d9ae53dbd4cce78043e9e", + "search": [ + "flow", + "cascade", + "junction" + ], + "charRef": 62365 + }, + { + "css": "flow-branch", + "code": 59281, + "uid": "4bcb3aaa98736be3027bef7c76c55021", + "search": [ + "flow", + "branch", + "junction" + ], + "charRef": 62366 + }, + { + "css": "flow-tree", + "code": 59282, + "uid": "8a1d446e5555e76f82ddb1c8b526f579", + "search": [ + "flow", + "tree", + "junction" + ], + "charRef": 62367 + }, + { + "css": "flow-line", + "code": 59283, + "uid": "6cea40aa6cc50057083e4f0a5b92410c", + "search": [ + "flow", + "line", + "junction" + ], + "charRef": 62368 + }, + { + "css": "flow-parallel", + "code": 59284, + "uid": "5f88095dc5e638863a0c733e99c32568", + "search": [ + "flow", + "parallel", + "junction" + ], + "charRef": 62369 + }, + { + "css": "rocket", + "code": 128640, + "uid": "9c7fd7637a41b59a358cb70893f945a5", + "search": [ + "rocket", + "fly" + ], + "charRef": 62370 + }, + { + "css": "gauge", + "code": 59298, + "uid": "3a6f0140c3a390bdb203f56d1bfdefcb", + "search": [ + "gauge", + "meter", + "speed", + "indicator" + ], + "charRef": 62371 + }, + { + "css": "traffic-cone", + "code": 59299, + "uid": "2bbde1076919db3d1dcc7f6b43d19bd4", + "search": [], + "charRef": 62372 + }, + { + "css": "cc", + "code": 59301, + "uid": "4a413ef43c364dafa42766e74c31bbca", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62373 + }, + { + "css": "cc-by", + "code": 59302, + "uid": "72681d2825fef7fd83711278f845547b", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62374 + }, + { + "css": "cc-nc", + "code": 59303, + "uid": "7540520e12e941839cdb7d76b12e82a8", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62375 + }, + { + "css": "cc-nc-eu", + "code": 59304, + "uid": "2d741e29010c6afbfc3784251fbf4e8b", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62376 + }, + { + "css": "cc-nc-jp", + "code": 59305, + "uid": "3138d5e10d50279c6d97ad1c99fdb584", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62377 + }, + { + "css": "cc-sa", + "code": 59306, + "uid": "900851106d63af1bc6076ae118dc543d", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62378 + }, + { + "css": "cc-nd", + "code": 59307, + "uid": "b92e2a918daa2f9a042df1ce942b686f", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62379 + }, + { + "css": "cc-pd", + "code": 59308, + "uid": "49679f26492c29c7bc277f1de9249229", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62380 + }, + { + "css": "cc-zero", + "code": 59309, + "uid": "94914cbbfba692ebbc13c179d62355f7", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62381 + }, + { + "css": "cc-share", + "code": 59310, + "uid": "915c11e4e2e713cc7d65d32d66f004bf", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62382 + }, + { + "css": "cc-remix", + "code": 59311, + "uid": "0cd7be54280d9ffbe0f48342c011268e", + "search": [ + "creative", + "cc", + "licence" + ], + "charRef": 62383 + }, + { + "css": "github", + "code": 62208, + "uid": "d94334f23acba022bfd68e49d76b31bb", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 62384 + }, + { + "css": "github-circled", + "code": 62209, + "uid": "91daf8fde1042a363514ca7e42d89570", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 62385 + }, + { + "css": "flickr", + "code": 62211, + "uid": "14cfd18cc1dd5fb99ba04311b888bc23", + "search": [ + "flickr", + "social", + "logo" + ], + "charRef": 62386 + }, + { + "css": "flickr-circled", + "code": 62212, + "uid": "5bbd46b2a0b972533f4d3ef243645e1d", + "search": [ + "flickr", + "social", + "logo" + ], + "charRef": 62387 + }, + { + "css": "vimeo", + "code": 62214, + "uid": "538531af0e023b15882c505ee2297cbe", + "search": [ + "vimeo", + "social", + "logo" + ], + "charRef": 62388 + }, + { + "css": "vimeo-circled", + "code": 62215, + "uid": "6569bd1801e232180221ba0f6a4b8b27", + "search": [ + "vimeo", + "social", + "logo" + ], + "charRef": 62389 + }, + { + "css": "twitter", + "code": 62217, + "uid": "d090355c31f497b61d676416c1fd39fb", + "search": [ + "twitter", + "social", + "logo" + ], + "charRef": 62390 + }, + { + "css": "twitter-circled", + "code": 62218, + "uid": "0419da6446cb4f31093e2022793571ca", + "search": [ + "twitter", + "social", + "logo" + ], + "charRef": 62391 + }, + { + "css": "facebook", + "code": 62220, + "uid": "bc50457410acf467b8b5721240768742", + "search": [ + "facebook", + "social", + "logo" + ], + "charRef": 62392 + }, + { + "css": "facebook-circled", + "code": 62221, + "uid": "ce1d525f3f31024c6a6b38f5e9a88953", + "search": [ + "facebook", + "social", + "logo" + ], + "charRef": 62393 + }, + { + "css": "facebook-squared", + "code": 62222, + "uid": "47bd87a650e95b97f947d275ed968efe", + "search": [ + "facebook", + "social", + "logo" + ], + "charRef": 62394 + }, + { + "css": "gplus", + "code": 62223, + "uid": "b945f4ac2439565661e8e4878e35d379", + "search": [ + "google", + "plus", + "social", + "logo" + ], + "charRef": 62395 + }, + { + "css": "gplus-circled", + "code": 62224, + "uid": "818a6c2a76c89800632c0335e9cdafee", + "search": [ + "google", + "plus", + "social", + "logo" + ], + "charRef": 62396 + }, + { + "css": "pinterest", + "code": 62226, + "uid": "689febe699d74bc8862965555503e445", + "search": [ + "pinterest", + "social", + "logo" + ], + "charRef": 62397 + }, + { + "css": "pinterest-circled", + "code": 62227, + "uid": "2e9c0fdd4d59598cb122801ab80222e7", + "search": [ + "pinterest", + "social", + "logo" + ], + "charRef": 62398 + }, + { + "css": "tumblr", + "code": 62229, + "uid": "d491462e64eb5b8c4f064108a2ff1780", + "search": [ + "tumblr", + "social", + "logo" + ], + "charRef": 62399 + }, + { + "css": "tumblr-circled", + "code": 62230, + "uid": "72a6237752f5cd00a107d097adac9ce3", + "search": [ + "tumblr", + "social", + "logo" + ], + "charRef": 62400 + }, + { + "css": "linkedin", + "code": 62232, + "uid": "7132e1233bc16cd1b6efe7e29d3613a5", + "search": [ + "linkedin", + "social", + "logo" + ], + "charRef": 62401 + }, + { + "css": "linkedin-circled", + "code": 62233, + "uid": "21adad41ffebf469b2370d26bcb8a3c4", + "search": [ + "linkedin", + "social", + "logo" + ], + "charRef": 62402 + }, + { + "css": "dribbble", + "code": 62235, + "uid": "e8d13cd05bd63219329b2b61835d776c", + "search": [ + "dribbble", + "social", + "logo" + ], + "charRef": 62403 + }, + { + "css": "dribbble-circled", + "code": 62236, + "uid": "ec3e0b50a56867ac26a6de47953b9831", + "search": [ + "dribbble", + "social", + "logo" + ], + "charRef": 62404 + }, + { + "css": "stumbleupon", + "code": 62238, + "uid": "ef5e2b339a93fff038cc6a28f8c91edd", + "search": [ + "stumbleupon", + "social", + "logo" + ], + "charRef": 62405 + }, + { + "css": "stumbleupon-circled", + "code": 62239, + "uid": "e3606432570e59d4d852727bad063cd1", + "search": [ + "stumbleupon", + "social", + "logo" + ], + "charRef": 62406 + }, + { + "css": "lastfm", + "code": 62241, + "uid": "ae49d5a5d0c2f7253f375bde5f0da2d2", + "search": [ + "lastfm", + "social", + "logo" + ], + "charRef": 62407 + }, + { + "css": "lastfm-circled", + "code": 62242, + "uid": "9eedcbf6e07d6ba820e3e22f5ab6f734", + "search": [ + "lastfm", + "social", + "logo" + ], + "charRef": 62408 + }, + { + "css": "rdio", + "code": 62244, + "uid": "406d96226bd9d021b7d976efa1c4a061", + "search": [ + "rdio", + "social", + "logo" + ], + "charRef": 62409 + }, + { + "css": "rdio-circled", + "code": 62245, + "uid": "4d8e1f1173bab9aac8991e9eee2fa326", + "search": [ + "rdio", + "social", + "logo" + ], + "charRef": 62410 + }, + { + "css": "spotify", + "code": 62247, + "uid": "882d407598d4e60074f5c08b3372811e", + "search": [ + "spotify", + "social", + "logo" + ], + "charRef": 62411 + }, + { + "css": "spotify-circled", + "code": 62248, + "uid": "067edf3e1f6458e782d0254e63eb5eb6", + "search": [ + "spotify", + "social", + "logo" + ], + "charRef": 62412 + }, + { + "css": "qq", + "code": 62250, + "uid": "935e2e437efbb3a69ed9a83e2d2f637e", + "search": [ + "qq", + "social", + "logo" + ], + "charRef": 62413 + }, + { + "css": "instagram", + "code": 62253, + "uid": "0fbfb1cd7a847c88ea4c141d0e1bbdb5", + "search": [ + "instagram", + "social", + "logo" + ], + "charRef": 62414 + }, + { + "css": "dropbox", + "code": 62256, + "uid": "b22fdf6cbaa9c54fbb0bc9abb0ed4098", + "search": [ + "dropbox", + "social", + "logo" + ], + "charRef": 62415 + }, + { + "css": "evernote", + "code": 62259, + "uid": "ce291d00162e998dbf5cb81bc5edff75", + "search": [ + "evernote", + "social", + "logo" + ], + "charRef": 62416 + }, + { + "css": "flattr", + "code": 62262, + "uid": "4274fc9f6190d330fcdf61e7ad564370", + "search": [ + "flattr", + "social", + "logo" + ], + "charRef": 62417 + }, + { + "css": "skype", + "code": 62265, + "uid": "28ccaf022b8363aeaa5b86f66e1f5173", + "search": [ + "skype", + "social", + "logo" + ], + "charRef": 62418 + }, + { + "css": "skype-circled", + "code": 62266, + "uid": "8354734770d837204e6a004885240d2e", + "search": [ + "skype", + "social", + "logo" + ], + "charRef": 62419 + }, + { + "css": "renren", + "code": 62268, + "uid": "7fe35dea791456114c356934333b4171", + "search": [ + "renren", + "social", + "logo" + ], + "charRef": 62420 + }, + { + "css": "sina-weibo", + "code": 62271, + "uid": "d1945696d6bbbf84e388df9961f26a37", + "search": [ + "sina-weibo", + "social", + "logo" + ], + "charRef": 62421 + }, + { + "css": "paypal", + "code": 62274, + "uid": "8d584f31a5d54de313f1f3da28708ec0", + "search": [ + "paypal", + "social", + "logo" + ], + "charRef": 62422 + }, + { + "css": "picasa", + "code": 62277, + "uid": "07269ba9c8905d091e1a01beab1f0958", + "search": [ + "picasa", + "social", + "logo" + ], + "charRef": 62423 + }, + { + "css": "soundcloud", + "code": 62280, + "uid": "b86600decaba538aca184421752cd640", + "search": [ + "soundcloud", + "social", + "logo" + ], + "charRef": 62424 + }, + { + "css": "mixi", + "code": 62283, + "uid": "c510878e39f27f3fb4e6171148829962", + "search": [ + "mixi", + "social", + "logo" + ], + "charRef": 62425 + }, + { + "css": "behance", + "code": 62286, + "uid": "84f3880057574e968053d6d6c8a7b216", + "search": [ + "behance", + "social", + "logo" + ], + "charRef": 62426 + }, + { + "css": "google-circles", + "code": 62289, + "uid": "5a24a9d2bffe3b66cea31ed2f57fb65a", + "search": [ + "google", + "circles", + "social", + "logo" + ], + "charRef": 62427 + }, + { + "css": "vkontakte", + "code": 62292, + "uid": "c9a7eca58474311926922ff8c2c1d256", + "search": [ + "vkontakte", + "social", + "logo" + ], + "charRef": 62428 + }, + { + "css": "smashing", + "code": 62295, + "uid": "2e97984c1130787e123117d4cacc07fa", + "search": [ + "smashing", + "social", + "logo" + ], + "charRef": 62429 + }, + { + "css": "sweden", + "code": 62977, + "uid": "c22c5fa36d200793ad39b984fb5c8610", + "search": [ + "sweden" + ], + "charRef": 62430 + }, + { + "css": "db-shape", + "code": 62976, + "uid": "e9ede58f5f90bbc3e52bf4bf53da71c0", + "search": [ + "entypo", + "daniel", + "bruce" + ], + "charRef": 62431 + }, + { + "css": "logo-db", + "code": 62979, + "uid": "ea16996158db7b9fedf060a4f44b27ee", + "search": [ + "daniel", + "bruce", + "megadesigner" + ], + "charRef": 62432 + } + ], + "font": { + "version": "2.0", + "fontname": "entypo", + "fullname": "Entypo", + "familyname": "Entypo", + "copyright": "Copyright (C) 2012 by Daniel Bruce", + "ascent": 850, + "descent": -150, + "weight": "Medium" + }, + "meta": { + "author": "Daniel Bruce", + "homepage": "http://www.entypo.com", + "email": "daniel@precinct.net", + "twitter": "http://twitter.com/danielbruce_", + "dribbble": "http://dribbble.com/danielbruce", + "github": "https://github.com/danielbruce/entypo", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "music-outline", + "code": 57522, + "uid": "b1c81b3df9f4a9b8c393f405bb5293d8", + "search": [ + "music", + "note", + "song", + "sound" + ], + "charRef": 62433 + }, + { + "css": "music", + "code": 57523, + "uid": "5rarhtgcreeh8evuaqd8zoekgehkt3mm", + "search": [ + "music", + "note", + "song", + "sound" + ], + "charRef": 62434 + }, + { + "css": "search-outline", + "code": 57650, + "uid": "1be0ad37c941fcc88233d38c2e460cf5", + "search": [ + "search", + "find" + ], + "charRef": 62435 + }, + { + "css": "search", + "code": 57651, + "uid": "t6cy82vd3t5piy0j3uknrlrzpg1ld8y3", + "search": [ + "search", + "find" + ], + "charRef": 62436 + }, + { + "css": "mail", + "code": 57498, + "uid": "wg849ixsobykxshs6efpc6fk4m0fq8bh", + "search": [ + "mail", + "email" + ], + "charRef": 62437 + }, + { + "css": "heart", + "code": 57470, + "uid": "3b00728aa97ad1a2581d414bd9d650bc", + "search": [ + "heart" + ], + "charRef": 62438 + }, + { + "css": "heart-filled", + "code": 57471, + "uid": "hi76m8qggwn5lbl286oeqp64q0n8kusy", + "search": [ + "heart" + ], + "charRef": 62439 + }, + { + "css": "star", + "code": 57584, + "uid": "bcdc294bb787b15203b82f2be8096548", + "search": [ + "star" + ], + "charRef": 62440 + }, + { + "css": "star-filled", + "code": 57585, + "uid": "vyuzsm6wijlfwtjo4ifkoblfmsepk6g8", + "search": [ + "star" + ], + "charRef": 62441 + }, + { + "css": "user-outline", + "code": 57618, + "uid": "8ed4884bf9b840729eef8f0bbd2b1dbb", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62442 + }, + { + "css": "user", + "code": 57619, + "uid": "bczb7qup4axmc490xmuuv8qdhcnbgeyf", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62443 + }, + { + "css": "users-outline", + "code": 57467, + "uid": "a1d4b614f12cfe2b5aa66313ad88c90c", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 62444 + }, + { + "css": "users", + "code": 57468, + "uid": "x8m4z7b33cv1h2s784tjlam56uq40wtd", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 62445 + }, + { + "css": "user-add-outline", + "code": 57614, + "uid": "b9cd6e266f74ac97272b2fabbfbd0b85", + "search": [ + "user", + "member", + "add" + ], + "charRef": 62446 + }, + { + "css": "user-add", + "code": 57615, + "uid": "076f940ac56adee91dd43d6fd77dd0cf", + "search": [ + "user", + "member", + "add" + ], + "charRef": 62447 + }, + { + "css": "user-delete-outline", + "code": 57616, + "uid": "344c1c070cd0018ced51d3f051c6f4dd", + "search": [ + "user", + "member", + "delete", + "remove" + ], + "charRef": 62448 + }, + { + "css": "user-delete", + "code": 57617, + "uid": "d139ce97a43aedd333fa40f776328c3c", + "search": [ + "user", + "member", + "delete", + "remove" + ], + "charRef": 62449 + }, + { + "css": "video", + "code": 57452, + "uid": "342dd4f00ec75318e1484d360cc21871", + "search": [ + "video", + "movie", + "film" + ], + "charRef": 62450 + }, + { + "css": "videocam-outline", + "code": 57620, + "uid": "3d8b20949cd6f782067f9e652967f8a8", + "search": [ + "videocam", + "movie", + "video", + "film" + ], + "charRef": 62451 + }, + { + "css": "videocam", + "code": 57621, + "uid": "fa92c2529910e6958311b673ebf307e2", + "search": [ + "videocam", + "movie", + "video", + "film" + ], + "charRef": 62452 + }, + { + "css": "picture-outline", + "code": 57474, + "uid": "96819a35f3d743b4df0ea2e92803eeb5", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 62453 + }, + { + "css": "picture", + "code": 57475, + "uid": "6a7ed3214c9049148cbdb01825e5efc2", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 62454 + }, + { + "css": "camera-outline", + "code": 57399, + "uid": "05de65980bb8a3711da037c2cc25f4f8", + "search": [ + "camera", + "photo" + ], + "charRef": 62455 + }, + { + "css": "camera", + "code": 57400, + "uid": "aklhk54yg779pgovdsjr9r9w22hej00n", + "search": [ + "camera", + "photo" + ], + "charRef": 62456 + }, + { + "css": "th-outline", + "code": 57599, + "uid": "a0af0ba081a37bac0783788042ea1774", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 62457 + }, + { + "css": "th", + "code": 57600, + "uid": "9x8p16w516pn1b19chr85japkedporm7", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 62458 + }, + { + "css": "th-large-outline", + "code": 57593, + "uid": "08db5357646aae59e018ba87f2d466cd", + "search": [ + "thumbnail", + "list", + "image" + ], + "charRef": 62459 + }, + { + "css": "th-large", + "code": 57594, + "uid": "e903698d494785d5e9328f0645da81bb", + "search": [ + "thumbnail", + "list", + "image" + ], + "charRef": 62460 + }, + { + "css": "th-list-outline", + "code": 57595, + "uid": "43855c51ebf847e8d581b794e4126dfe", + "search": [ + "list" + ], + "charRef": 62461 + }, + { + "css": "th-list", + "code": 57596, + "uid": "lu2wqmd7v9zp21knhy4eifo41wjp4cnx", + "search": [ + "list" + ], + "charRef": 62462 + }, + { + "css": "ok-outline", + "code": 57604, + "uid": "40c9502d45c736a0a6ec45e6fbc28656", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62463 + }, + { + "css": "ok", + "code": 57605, + "uid": "43fl9m553j1z5937vfjz0lgolrlspxwl", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62464 + }, + { + "css": "cancel-outline", + "code": 57608, + "uid": "24aba8757d4a7b49568c98a577a85df3", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62465 + }, + { + "css": "cancel", + "code": 57609, + "uid": "1dq4tek4k8ea7zlj4kc3w83itnutaxg5", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62466 + }, + { + "css": "cancel-alt", + "code": 57381, + "uid": "3df1557e2d6e84ec32bd47aee5bfdf59", + "search": [ + "close", + "cancel" + ], + "charRef": 62467 + }, + { + "css": "cancel-alt-filled", + "code": 57382, + "uid": "l11ixzfrief0chds7elurdm2ot98xp4l", + "search": [ + "close", + "cancel" + ], + "charRef": 62468 + }, + { + "css": "cancel-circled-outline", + "code": 57427, + "uid": "517522647a556192fbc78aa391b7b0c2", + "search": [ + "close", + "cancel", + "delete", + "reject" + ], + "charRef": 62469 + }, + { + "css": "cancel-circled", + "code": 57428, + "uid": "3327862df439988139b61814143b7a42", + "search": [ + "close", + "cancel", + "delete", + "reject" + ], + "charRef": 62470 + }, + { + "css": "plus-outline", + "code": 57536, + "uid": "0677f879e75956571d8cbbb478487c47", + "search": [ + "plus" + ], + "charRef": 62471 + }, + { + "css": "plus", + "code": 57537, + "uid": "1gf923f9wvaezxmfon515dglxa3drf0e", + "search": [ + "plus" + ], + "charRef": 62472 + }, + { + "css": "minus-outline", + "code": 57519, + "uid": "7b67ab93e2dd09f8884b574925ab9352", + "search": [ + "minus" + ], + "charRef": 62473 + }, + { + "css": "minus", + "code": 57520, + "uid": "qab5uvjyoc3uu4d2pvt8soshtgkuvpak", + "search": [ + "minus" + ], + "charRef": 62474 + }, + { + "css": "divide-outline", + "code": 57434, + "uid": "c7b7ea4719f6592a6b36f8d041226e37", + "search": [ + "divide" + ], + "charRef": 62475 + }, + { + "css": "divide", + "code": 57435, + "uid": "863fa3cea75a505bbc420a1db8b6b89b", + "search": [ + "divide" + ], + "charRef": 62476 + }, + { + "css": "eq-outline", + "code": 57445, + "uid": "f8d0a7a987fa0384bfd7e08000ec1476", + "search": [ + "equal" + ], + "charRef": 62477 + }, + { + "css": "eq", + "code": 57446, + "uid": "yb3vdwfxck5hmudxna4fq8fcwo9xari9", + "search": [ + "equal" + ], + "charRef": 62478 + }, + { + "css": "info-outline", + "code": 57478, + "uid": "6364d85e960f23b9a843a506387e7970", + "search": [ + "info" + ], + "charRef": 62479 + }, + { + "css": "info", + "code": 57479, + "uid": "85fda3129wk4amvn25wrq843sbj3yzl0", + "search": [ + "info" + ], + "charRef": 62480 + }, + { + "css": "home-outline", + "code": 57472, + "uid": "a42f298da5c64e646a5d532724cd6e15", + "search": [ + "home" + ], + "charRef": 62481 + }, + { + "css": "home", + "code": 57473, + "uid": "w3nzesrlbezu6f30q7ytyq919p6gdlb6", + "search": [ + "home" + ], + "charRef": 62482 + }, + { + "css": "link-outline", + "code": 57488, + "uid": "3562ca2f2f16f6629b5ffabfe3cfa5a7", + "search": [ + "link", + "url" + ], + "charRef": 62483 + }, + { + "css": "link", + "code": 57489, + "uid": "45g23adv6rwe7nokwek4d471h8y09ayz", + "search": [ + "link", + "url" + ], + "charRef": 62484 + }, + { + "css": "attach-outline", + "code": 57379, + "uid": "6310fc4804f3ffaebc4436ee30f3856e", + "search": [ + "attach", + "clip" + ], + "charRef": 62485 + }, + { + "css": "attach", + "code": 57380, + "uid": "0f81c70dd389bf78f46387b794f2573f", + "search": [ + "attach", + "clip" + ], + "charRef": 62486 + }, + { + "css": "lock", + "code": 57494, + "uid": "3e1bb74572a30486bd647304d9fcaff6", + "search": [ + "lock", + "close" + ], + "charRef": 62487 + }, + { + "css": "lock-filled", + "code": 57495, + "uid": "4x5p6fnblkhqsj4ibuc724faotghuiaq", + "search": [ + "lock", + "close" + ], + "charRef": 62488 + }, + { + "css": "lock-open", + "code": 57496, + "uid": "75cff40f03567673e13b0e7d005b7741", + "search": [ + "lock", + "unlock", + "open" + ], + "charRef": 62489 + }, + { + "css": "lock-open-filled", + "code": 57497, + "uid": "a33vyvfsje6eklq8loqtzb1jcgo37onm", + "search": [ + "lock", + "unlock", + "open" + ], + "charRef": 62490 + }, + { + "css": "pin-outline", + "code": 57530, + "uid": "6373242453e92e8ce419b8391463867a", + "search": [ + "pin", + "pushpin" + ], + "charRef": 62491 + }, + { + "css": "pin", + "code": 57531, + "uid": "p57wgnf4glngbchbucdi029iptu8oxb8", + "search": [ + "pin", + "pushpin" + ], + "charRef": 62492 + }, + { + "css": "eye-outline", + "code": 57449, + "uid": "366c3c56b79031deacc953d7f92085e5", + "search": [ + "eye", + "subscribe" + ], + "charRef": 62493 + }, + { + "css": "eye", + "code": 57450, + "uid": "k7sao112253txym1egnte7822irbyphe", + "search": [ + "eye", + "subscribe" + ], + "charRef": 62494 + }, + { + "css": "tag", + "code": 57591, + "uid": "z2kx6nr3u9112p0e1pfhxdhva9v7kd4k", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 62495 + }, + { + "css": "tags", + "code": 57592, + "uid": "e417e4ca7774bb0f4aca5278ae3bfe49", + "search": [ + "tags" + ], + "charRef": 62496 + }, + { + "css": "bookmark", + "code": 128278, + "uid": "gr2i0fsmy50yfjhz6defsqkexnmctv8z", + "search": [ + "bookmark" + ], + "charRef": 62497 + }, + { + "css": "flag", + "code": 57453, + "uid": "d91495faa39f7bc987caa15275d96ae8", + "search": [ + "flag" + ], + "charRef": 62498 + }, + { + "css": "flag-filled", + "code": 57454, + "uid": "4i0s2bklai5fywieqm4dqqngfz9ptfab", + "search": [ + "flag" + ], + "charRef": 62499 + }, + { + "css": "thumbs-up", + "code": 128077, + "uid": "tau7t0t38662eqxrb80ozeiase5em2x9", + "search": [ + "thumbs", + "up", + "like", + "vote" + ], + "charRef": 62500 + }, + { + "css": "thumbs-down", + "code": 128078, + "uid": "ani12ucvy2plqmykysnk4zd9i24cmxqp", + "search": [ + "thumbs", + "down", + "unlike", + "vote" + ], + "charRef": 62501 + }, + { + "css": "download-outline", + "code": 57440, + "uid": "86157b2f942e37940f8702a4a3221a2b", + "search": [ + "download" + ], + "charRef": 62502 + }, + { + "css": "download", + "code": 128229, + "uid": "7yekfd0qlkgp6emwfbo10sjdmf8pewli", + "search": [ + "download" + ], + "charRef": 62503 + }, + { + "css": "upload-outline", + "code": 57612, + "uid": "9367acef93427f6301ee8ab42d45def7", + "search": [ + "upload" + ], + "charRef": 62504 + }, + { + "css": "upload", + "code": 57613, + "uid": "f156d14a32cd7d5bc5a5f70382ab04ec", + "search": [ + "upload" + ], + "charRef": 62505 + }, + { + "css": "upload-cloud-outline", + "code": 57425, + "uid": "e9bce795d01ef5a058c63cab0a03dc66", + "search": [ + "cloud", + "upload" + ], + "charRef": 62506 + }, + { + "css": "upload-cloud", + "code": 57416, + "uid": "4e77fc7fc71e69ba520ffa3b4d898e55", + "search": [ + "cloud", + "upload" + ], + "charRef": 62507 + }, + { + "css": "reply-outline", + "code": 57349, + "uid": "c60f50a1729165e3752fa27a16325208", + "search": [ + "reply" + ], + "charRef": 62508 + }, + { + "css": "reply", + "code": 57350, + "uid": "28r0xthd180mg0wnfh8ek3mtn761hs11", + "search": [ + "reply" + ], + "charRef": 62509 + }, + { + "css": "forward-outline", + "code": 57354, + "uid": "ca92083691d138f832d6a9874d7636dc", + "search": [ + "forward" + ], + "charRef": 62510 + }, + { + "css": "forward", + "code": 57355, + "uid": "7p5gflyid3o4gtesy94a6erq94e4pz7u", + "search": [ + "forward" + ], + "charRef": 62511 + }, + { + "css": "code-outline", + "code": 57417, + "uid": "9e02faeda1ede96a076b72260f44e4b5", + "search": [ + "code" + ], + "charRef": 62512 + }, + { + "css": "code", + "code": 57418, + "uid": "8b202d3dd1fd0541ed0d47d1279ec8f3", + "search": [ + "code" + ], + "charRef": 62513 + }, + { + "css": "export-outline", + "code": 57447, + "uid": "44a6b866f720a1d2b11bf05023a4e089", + "search": [ + "export", + "share" + ], + "charRef": 62514 + }, + { + "css": "export", + "code": 57448, + "uid": "wh8nbtrxjl2f67dpybsww6mri0xcaklm", + "search": [ + "export", + "share" + ], + "charRef": 62515 + }, + { + "css": "pencil", + "code": 9998, + "uid": "1e77a2yvsq3owssduo2lcgsiven57iv5", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62516 + }, + { + "css": "pen", + "code": 57524, + "uid": "8e50efd23ddcb26f05878476c2c1ce8f", + "search": [ + "pen", + "stylo" + ], + "charRef": 62517 + }, + { + "css": "feather", + "code": 57451, + "uid": "d78522fbabf6251440fe30463756192c", + "search": [ + "feather" + ], + "charRef": 62518 + }, + { + "css": "edit", + "code": 57442, + "uid": "jqzwo6i8oicjbn049sh2856d8anrqoli", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62519 + }, + { + "css": "print", + "code": 57542, + "uid": "9d4f81f2d81e14141b68706668498441", + "search": [ + "print" + ], + "charRef": 62520 + }, + { + "css": "comment", + "code": 57515, + "uid": "b90868gfogj970a1g0dnot6hm5r4uj55", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62521 + }, + { + "css": "chat", + "code": 57514, + "uid": "2hqh2lidoqvaujgq29tdkrtiay5s6tyk", + "search": [ + "comment", + "reply", + "chat", + "talk" + ], + "charRef": 62522 + }, + { + "css": "chat-alt", + "code": 57516, + "uid": "ccf71c505b173c61a2e4e8c8cb907dfa", + "search": [ + "talk", + "chat" + ], + "charRef": 62523 + }, + { + "css": "bell", + "code": 57390, + "uid": "c155bb86da2f8da808394d58220b5146", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 62524 + }, + { + "css": "attention", + "code": 57480, + "uid": "2a58da2238c31ffa3ff4dac966c2dc99", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 62525 + }, + { + "css": "attention-filled", + "code": 9888, + "uid": "rp4bhvranczqlvvwzerni2uuanp2gvqb", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 62526 + }, + { + "css": "warning-empty", + "code": 57626, + "uid": "8f28d948aa6379b1a69d2a090e7531d4", + "search": [ + "warning", + "alert", + "attention" + ], + "charRef": 62527 + }, + { + "css": "warning", + "code": 57627, + "uid": "dd4b00255957a608953c409346e7d7fb", + "search": [ + "warning", + "alert", + "attention" + ], + "charRef": 62528 + }, + { + "css": "contacts", + "code": 57423, + "uid": "ba9ae3250633c7b1fe249587358c8383", + "search": [ + "contacts" + ], + "charRef": 62529 + }, + { + "css": "vcard", + "code": 57395, + "uid": "933f454f9d3342a055217fd695475d44", + "search": [ + "vcard", + "contact", + "card" + ], + "charRef": 62530 + }, + { + "css": "address", + "code": 57433, + "uid": "gruasbs60jlu9us53csv9q7nnwy4d990", + "search": [ + "address" + ], + "charRef": 62531 + }, + { + "css": "location-outline", + "code": 57492, + "uid": "13289e807e02b1d46f2fe10d81d6fba6", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62532 + }, + { + "css": "location", + "code": 57493, + "uid": "gjt8ba5q0n3nn8ptw6324sflr8qoaeam", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62533 + }, + { + "css": "map", + "code": 57499, + "uid": "87d337fee4866c2c28f6082994ce0f41", + "search": [ + "map" + ], + "charRef": 62534 + }, + { + "css": "direction-outline", + "code": 57490, + "uid": "0d5c609b66c40a8482943f18235da869", + "search": [ + "direction" + ], + "charRef": 62535 + }, + { + "css": "direction", + "code": 57491, + "uid": "cka09asalx8otiykquyp5d9tymlan1o3", + "search": [ + "direction" + ], + "charRef": 62536 + }, + { + "css": "compass", + "code": 57422, + "uid": "547c96163e3724fa7384f6ddce0c10e7", + "search": [ + "compass" + ], + "charRef": 62537 + }, + { + "css": "trash", + "code": 57610, + "uid": "csuoy0rqoun3unhsgjoy2uumpldzbfmt", + "search": [ + "trash", + "delete" + ], + "charRef": 62538 + }, + { + "css": "doc", + "code": 57439, + "uid": "85ef733b1e280809e8443f5f0167b5c2", + "search": [ + "document" + ], + "charRef": 62539 + }, + { + "css": "doc-text", + "code": 57438, + "uid": "6a06892e76b81e023da6ddfb38a26b37", + "search": [ + "document", + "text" + ], + "charRef": 62540 + }, + { + "css": "doc-add", + "code": 57436, + "uid": "bd517dbd6ccbc464f6d80efca97abb7d", + "search": [ + "document", + "add" + ], + "charRef": 62541 + }, + { + "css": "doc-remove", + "code": 57437, + "uid": "72686f3e46dda4b891938886eca27c59", + "search": [ + "document", + "remove" + ], + "charRef": 62542 + }, + { + "css": "news", + "code": 57521, + "uid": "56da5324fc5a04f131ab65668c36b931", + "search": [ + "news" + ], + "charRef": 62543 + }, + { + "css": "folder", + "code": 57463, + "uid": "83e7b366e9b39bc4006b821f7c5efa4d", + "search": [ + "folder" + ], + "charRef": 62544 + }, + { + "css": "folder-add", + "code": 57461, + "uid": "e536c80e011366046360f5ffe669dbfd", + "search": [ + "folder", + "add" + ], + "charRef": 62545 + }, + { + "css": "folder-delete", + "code": 57462, + "uid": "aa0d87f43ed577ed479df28dc3724c11", + "search": [ + "folder", + "delete" + ], + "charRef": 62546 + }, + { + "css": "archive", + "code": 57348, + "uid": "f7f29824b6c2d0a9645adc48297f41f4", + "search": [ + "archive" + ], + "charRef": 62547 + }, + { + "css": "box", + "code": 57553, + "uid": "a3264f2df401aaeeee9d9eb800e455eb", + "search": [ + "box" + ], + "charRef": 62548 + }, + { + "css": "rss-outline", + "code": 57549, + "uid": "aa7d4f131e866180ed30e6fbb504328c", + "search": [ + "rss" + ], + "charRef": 62549 + }, + { + "css": "rss", + "code": 57550, + "uid": "3o0pu4qbmgvcv8zqb5o3qh8vttzvhpy7", + "search": [ + "rss" + ], + "charRef": 62550 + }, + { + "css": "phone-outline", + "code": 57526, + "uid": "eae068bed86aca956cdd10edcaaf24ee", + "search": [ + "phone", + "call" + ], + "charRef": 62551 + }, + { + "css": "phone", + "code": 128222, + "uid": "24eiet6l58t0myywueih34b0e5a30bw1", + "search": [ + "phone", + "call" + ], + "charRef": 62552 + }, + { + "css": "menu-outline", + "code": 57597, + "uid": "a151e07df1262b33b210de5d956e4cc8", + "search": [ + "editor", + "list", + "menu" + ], + "charRef": 62553 + }, + { + "css": "menu", + "code": 57598, + "uid": "jh3jpcb1t1bcm80gidkadilh080aq79h", + "search": [ + "editor", + "list", + "menu" + ], + "charRef": 62554 + }, + { + "css": "cog-outline", + "code": 57420, + "uid": "3a89ddb1c81111c15d6c4e26cc3c546a", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 62555 + }, + { + "css": "cog", + "code": 9881, + "uid": "dpxunrtmigvk6jm0ieo7axfsgzx4awll", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 62556 + }, + { + "css": "wrench-outline", + "code": 57582, + "uid": "9e717a7080503cfe84c7c7bd336ffe5f", + "search": [ + "settings", + "wrench" + ], + "charRef": 62557 + }, + { + "css": "wrench", + "code": 128295, + "uid": "i7r8vgyqewsy2rlx0xhawybpw5uyss3z", + "search": [ + "settings", + "wrench" + ], + "charRef": 62558 + }, + { + "css": "basket", + "code": 57554, + "uid": "e0d15ef5945000f5f264acc35494002f", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 62559 + }, + { + "css": "calendar-outlilne", + "code": 57397, + "uid": "3d211fe82ca138fce185f8869d38df26", + "search": [ + "calendar", + "date" + ], + "charRef": 62560 + }, + { + "css": "calendar", + "code": 57398, + "uid": "4c2a3128819fef9548d6f0d38a5e291a", + "search": [ + "calendar", + "date" + ], + "charRef": 62561 + }, + { + "css": "mic-outline", + "code": 57517, + "uid": "b7bd78e163801889af145e513d6c5383", + "search": [ + "mic" + ], + "charRef": 62562 + }, + { + "css": "mic", + "code": 127908, + "uid": "b1a40ej6b1xgsxjeh1b1urm8ptglt0hk", + "search": [ + "mic" + ], + "charRef": 62563 + }, + { + "css": "volume-off", + "code": 57623, + "uid": "0a9d5a8bfa0ccfd44a38328b8ca276c2", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 62564 + }, + { + "css": "volume-low", + "code": 57625, + "uid": "43m0a70tvxqc6q7jxgzhz5lmlt3ce2iy", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 62565 + }, + { + "css": "volume-middle", + "code": 57622, + "uid": "3bf8e868324f7efb93c7bde31be9cc5e", + "search": [ + "volume", + "sound" + ], + "charRef": 62566 + }, + { + "css": "volume-high", + "code": 57624, + "uid": "okc52fdxu9uz2wnl0awdtv5373is429s", + "search": [ + "volume", + "sound" + ], + "charRef": 62567 + }, + { + "css": "headphones", + "code": 57469, + "uid": "e5297b06d9300be7e7c347f78a9b8b61", + "search": [ + "headphones", + "sound", + "music" + ], + "charRef": 62568 + }, + { + "css": "clock", + "code": 128340, + "uid": "eh1m4shhgsndy7pmdzx3ynrakadhozgr", + "search": [ + "clock", + "time" + ], + "charRef": 62569 + }, + { + "css": "wristwatch", + "code": 57628, + "uid": "e5e2804a6d7681eb37e80a1fc380fe49", + "search": [ + "clock", + "time", + "wristwatch" + ], + "charRef": 62570 + }, + { + "css": "stopwatch", + "code": 57588, + "uid": "cb8b402e2efdc57d6d37ad7d3da819fe", + "search": [ + "stopwatch", + "timer" + ], + "charRef": 62571 + }, + { + "css": "lightbulb", + "code": 57487, + "uid": "12d16dda691bda304e3b57d7bc0de5a9", + "search": [ + "idea", + "lamp", + "light", + "lightbulb" + ], + "charRef": 62572 + }, + { + "css": "block-outline", + "code": 57401, + "uid": "d8e8d6ef89a7e3992ade2b9e01b6b780", + "search": [ + "block", + "deny" + ], + "charRef": 62573 + }, + { + "css": "block", + "code": 128683, + "uid": "j6xzwioffey3gxe90yx3ie56j5dlt902", + "search": [ + "block", + "deny" + ], + "charRef": 62574 + }, + { + "css": "resize-full-outline", + "code": 57361, + "uid": "debaf3311987af708b9c1646fc192c15", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62575 + }, + { + "css": "resize-full", + "code": 57362, + "uid": "cdfalpadi7huwv9ah4fef2gpfpb4c6qm", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62576 + }, + { + "css": "resize-normal-outline", + "code": 57363, + "uid": "1e4cf19f2a9f546c5f13f09af7c40ba9", + "search": [ + "resize" + ], + "charRef": 62577 + }, + { + "css": "resize-normal", + "code": 57364, + "uid": "8d2bc2d959a55e76466bbef6e84c8373", + "search": [ + "resize" + ], + "charRef": 62578 + }, + { + "css": "move-outline", + "code": 57365, + "uid": "2b9bcf0829f99d9bdaa653b0a8cf41f5", + "search": [ + "move" + ], + "charRef": 62579 + }, + { + "css": "move", + "code": 57366, + "uid": "fhkechw94uv9ydw6tukba3ka2hhoif4n", + "search": [ + "move" + ], + "charRef": 62580 + }, + { + "css": "popup", + "code": 57590, + "uid": "ca1c07c0df52dbf2af6813c9e36c2611", + "search": [ + "popup", + "window" + ], + "charRef": 62581 + }, + { + "css": "zoom-in-outline", + "code": 57646, + "uid": "16bd6f8fd1c32a89b16d61e09a968c24", + "search": [ + "zoom. scale", + "in" + ], + "charRef": 62582 + }, + { + "css": "zoom-in", + "code": 57647, + "uid": "dfhp68fdlvh9dknvxk4tkf8yy0h7vw3r", + "search": [ + "zoom. scale", + "in" + ], + "charRef": 62583 + }, + { + "css": "zoom-out-outline", + "code": 57648, + "uid": "abbfffb71ee797c071d628c374714083", + "search": [ + "zoom. scale", + "out" + ], + "charRef": 62584 + }, + { + "css": "zoom-out", + "code": 57649, + "uid": "1nkxlfe3u6kwarxqy3g4z3c9lrsgdu5h", + "search": [ + "zoom. scale", + "out" + ], + "charRef": 62585 + }, + { + "css": "popup", + "code": 57391, + "uid": "493hui9b6xiqaf04slclmqnwpap3oxjj", + "search": [ + "popup", + "window" + ], + "charRef": 62586 + }, + { + "css": "left-open-outline", + "code": 57411, + "uid": "d4ebe676479ff9cb41c7797f003aa54d", + "search": [ + "arrow", + "left" + ], + "charRef": 62587 + }, + { + "css": "left-open", + "code": 57412, + "uid": "wlri7uftq4zbi82q2xuf08ayd8kpijlk", + "search": [ + "arrow", + "left" + ], + "charRef": 62588 + }, + { + "css": "right-open-outline", + "code": 57413, + "uid": "813cb2527308990d4870591d9d76f8cd", + "search": [ + "arrow", + "right" + ], + "charRef": 62589 + }, + { + "css": "right-open", + "code": 57414, + "uid": "6zhrgcf3co77hnljttd3b2mrc8z5fiq5", + "search": [ + "arrow", + "right" + ], + "charRef": 62590 + }, + { + "css": "down", + "code": 57352, + "uid": "xq9z5jujkqhrf97s70hjek6otohmhr1y", + "search": [ + "arrow", + "down" + ], + "charRef": 62591 + }, + { + "css": "left", + "code": 57357, + "uid": "qqsxko9kqxh5g53lz33yonkpc2rpkvkn", + "search": [ + "arrow", + "left" + ], + "charRef": 62592 + }, + { + "css": "right", + "code": 57370, + "uid": "4oaz56fmzfvx7vry2o540n9l4z79fz8t", + "search": [ + "arrow", + "right" + ], + "charRef": 62593 + }, + { + "css": "up", + "code": 57376, + "uid": "mj2pxhfj0eumtbzirpdokhtzk00480uo", + "search": [ + "arrow", + "up" + ], + "charRef": 62594 + }, + { + "css": "down-outline", + "code": 57351, + "uid": "1d9b2bb0d0621cd616139c6a441ed442", + "search": [ + "arrow", + "down" + ], + "charRef": 62595 + }, + { + "css": "left-outline", + "code": 57356, + "uid": "ec3be32c1330a17ef251b378ebd7d3ac", + "search": [ + "arrow", + "left" + ], + "charRef": 62596 + }, + { + "css": "right-outline", + "code": 57369, + "uid": "86bc84e014767f8f1377723c47d1b153", + "search": [ + "arrow", + "right" + ], + "charRef": 62597 + }, + { + "css": "up-outline", + "code": 57375, + "uid": "abf264d54e3f10187167ebc0e833d12e", + "search": [ + "arrow", + "up" + ], + "charRef": 62598 + }, + { + "css": "down-small", + "code": 57353, + "uid": "c16a63e911bc47b46dc2a7129d2f0c46", + "search": [ + "arrow", + "down" + ], + "charRef": 62599 + }, + { + "css": "left-small", + "code": 57358, + "uid": "58b78b6ca784d5c3db5beefcd9e18061", + "search": [ + "arrow", + "left" + ], + "charRef": 62600 + }, + { + "css": "right-small", + "code": 57371, + "uid": "877a233d7fdca8a1d82615b96ed0d7a2", + "search": [ + "arrow", + "right" + ], + "charRef": 62601 + }, + { + "css": "up-small", + "code": 57377, + "uid": "62bc6fe2a82e4864e2b94d4c0985ee0c", + "search": [ + "arrow", + "up" + ], + "charRef": 62602 + }, + { + "css": "cw-outline", + "code": 57547, + "uid": "1fb50a37bc38da3863187931ac44ae5e", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 62603 + }, + { + "css": "cw", + "code": 10227, + "uid": "5qynhqqaenby227l5kogqj8sdk5s4e7h", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 62604 + }, + { + "css": "arrows-cw-outline", + "code": 57373, + "uid": "d12574a0151c84ddf56f4fd7b4aff678", + "search": [ + "reload", + "refresh", + "update", + "sync" + ], + "charRef": 62605 + }, + { + "css": "arrows-cw", + "code": 57374, + "uid": "mqlxga8x57rhlfv44zsvmz1reex8lbqg", + "search": [ + "reload", + "refresh", + "update", + "sync" + ], + "charRef": 62606 + }, + { + "css": "loop-outline", + "code": 57367, + "uid": "6b69b1a2df6d099ba15f11476075438e", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62607 + }, + { + "css": "loop", + "code": 128257, + "uid": "em9mdmyhjwd003ndercv4r08h0ai31tl", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62608 + }, + { + "css": "loop-alt-outline", + "code": 57359, + "uid": "7c0965b50bb5e83150abcbd752b7c29e", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62609 + }, + { + "css": "loop-alt", + "code": 57360, + "uid": "jskdfgyhjwd003ndercv4r08h0ai3dfg", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62610 + }, + { + "css": "shuffle", + "code": 128256, + "uid": "36m3wq83tio3uymjbu44su7ior03u9cc", + "search": [ + "shuffle" + ], + "charRef": 62611 + }, + { + "css": "play-outline", + "code": 57506, + "uid": "8d2b91edcad12992a96fc5eac674700d", + "search": [ + "player", + "play" + ], + "charRef": 62612 + }, + { + "css": "play", + "code": 57507, + "uid": "3e290a111c0f3ee3acbf7b5f17ccc04a", + "search": [ + "player", + "play" + ], + "charRef": 62613 + }, + { + "css": "stop-outline", + "code": 57512, + "uid": "4a770f766e0c1f06ce850db219684355", + "search": [ + "player", + "stop" + ], + "charRef": 62614 + }, + { + "css": "stop", + "code": 57513, + "uid": "0785c02e57804318c8fe070338f89cd9", + "search": [ + "player", + "stop" + ], + "charRef": 62615 + }, + { + "css": "pause-outline", + "code": 57504, + "uid": "633072ff889a2ac52b162880e104550e", + "search": [ + "player", + "pause" + ], + "charRef": 62616 + }, + { + "css": "pause", + "code": 57505, + "uid": "e44ef09cb81413287d702eefa65dd790", + "search": [ + "player", + "pause" + ], + "charRef": 62617 + }, + { + "css": "fast-fw-outline", + "code": 57502, + "uid": "f7b9bc563b87218a2ed804cc71a6eb9c", + "search": [ + "player", + "right" + ], + "charRef": 62618 + }, + { + "css": "fast-fw", + "code": 57503, + "uid": "94656a720f169a0fc78c5a942e0c7112", + "search": [ + "player", + "right" + ], + "charRef": 62619 + }, + { + "css": "rewind-outline", + "code": 57510, + "uid": "f54874f26664ff241013d7b74b930b3f", + "search": [ + "player", + "right", + "rewind" + ], + "charRef": 62620 + }, + { + "css": "rewind", + "code": 57511, + "uid": "c80828ee2c3fc55b3e58a2b5e6ebba91", + "search": [ + "player", + "right", + "rewind" + ], + "charRef": 62621 + }, + { + "css": "record-outline", + "code": 57508, + "uid": "1e29f134dfa565422897dacc67dee3e8", + "search": [ + "player", + "record" + ], + "charRef": 62622 + }, + { + "css": "record", + "code": 57509, + "uid": "6c985c88b4c460d6c5a3e34d53361286", + "search": [ + "player", + "record" + ], + "charRef": 62623 + }, + { + "css": "eject-outline", + "code": 57443, + "uid": "b345edfec8ce1b62e75f889fbd02bd0e", + "search": [ + "eject" + ], + "charRef": 62624 + }, + { + "css": "eject", + "code": 57444, + "uid": "ef7107c004ac05657c5f41177e0bf4f3", + "search": [ + "eject" + ], + "charRef": 62625 + }, + { + "css": "eject-alt-outline", + "code": 57500, + "uid": "24f39880f1bd96bafcaf46db5881bc0e", + "search": [ + "eject", + "player" + ], + "charRef": 62626 + }, + { + "css": "eject-alt", + "code": 57501, + "uid": "ygvgohzaooew2l8favz2xu2xi59w1hoo", + "search": [ + "eject", + "player" + ], + "charRef": 62627 + }, + { + "css": "bat1", + "code": 57386, + "uid": "f378encthmyxe8mfi1ute1knv09ggkar", + "search": [ + "battery" + ], + "charRef": 62628 + }, + { + "css": "bat2", + "code": 57387, + "uid": "jslb32twsd38zgx4v3sm5upu0t6wirtm", + "search": [ + "battery" + ], + "charRef": 62629 + }, + { + "css": "bat3", + "code": 57385, + "uid": "g43j86b0hso37oir42285zjo3nhd7m08", + "search": [ + "battery" + ], + "charRef": 62630 + }, + { + "css": "bat4", + "code": 57384, + "uid": "7wc8mz5d93cbka5pscqjhsej173tqmbs", + "search": [ + "battery" + ], + "charRef": 62631 + }, + { + "css": "bat-charge", + "code": 57383, + "uid": "bc1u8zgs4wteyj0u35n943k3jzx5olkm", + "search": [ + "battery", + "charge" + ], + "charRef": 62632 + }, + { + "css": "plug", + "code": 57535, + "uid": "5c8a627c2e11bfc2854045872f6bd8f4", + "search": [ + "plug" + ], + "charRef": 62633 + }, + { + "css": "target-outline", + "code": 57545, + "uid": "c3b851a7a3ee5407ff159e9c7f61945f", + "search": [ + "target" + ], + "charRef": 62634 + }, + { + "css": "target", + "code": 127919, + "uid": "xzlln8s96kcutcubtwavdjt80tmhkbkq", + "search": [ + "target" + ], + "charRef": 62635 + }, + { + "css": "wifi-outline", + "code": 57641, + "uid": "c72248ca6a6ca8ee4c267f343e464003", + "search": [ + "wifi", + "signal", + "radio" + ], + "charRef": 62636 + }, + { + "css": "wifi", + "code": 57642, + "uid": "a19527dd18f0e45e597e8a2622604d14", + "search": [ + "wifi", + "signal", + "radio" + ], + "charRef": 62637 + }, + { + "css": "desktop", + "code": 57429, + "uid": "4d3a91e6b0db6e03acaa74a861e2ab95", + "search": [ + "desktop" + ], + "charRef": 62638 + }, + { + "css": "laptop", + "code": 57430, + "uid": "eea1af32a01c5e7a9ce5675bcff64a7b", + "search": [ + "laptop", + "notebook" + ], + "charRef": 62639 + }, + { + "css": "tablet", + "code": 57432, + "uid": "c710cda53f5e1f8705865d453b7f323f", + "search": [ + "tablet" + ], + "charRef": 62640 + }, + { + "css": "mobile", + "code": 128241, + "uid": "gz5flrq210wzbyafnerm4e0aublo7qwb", + "search": [ + "mobile", + "iphone" + ], + "charRef": 62641 + }, + { + "css": "contrast", + "code": 57345, + "uid": "3fzybskyukolbvmshoyord1b254366gh", + "search": [ + "ajust", + "contrast" + ], + "charRef": 62642 + }, + { + "css": "globe-outline", + "code": 57644, + "uid": "1e8ffb4f9e0d313a9f5ffa5788487712", + "search": [ + "globe" + ], + "charRef": 62643 + }, + { + "css": "globe", + "code": 119565, + "uid": "igynut9bozd2s1mxnmkeeut1qou984gc", + "search": [ + "globe" + ], + "charRef": 62644 + }, + { + "css": "globe-alt-outline", + "code": 57465, + "uid": "63ec74ce71635a8fc128c2eef73b96ae", + "search": [ + "globe" + ], + "charRef": 62645 + }, + { + "css": "globe-alt", + "code": 127760, + "uid": "n1ld0w7zazkxq7bsqtksyez86sdufqgd", + "search": [ + "globe" + ], + "charRef": 62646 + }, + { + "css": "sun", + "code": 9788, + "uid": "ivmsk67zo1yb1tthd3ugi4xnb3get418", + "search": [ + "weather", + "sun", + "brightness" + ], + "charRef": 62647 + }, + { + "css": "sun-filled", + "code": 57344, + "uid": "5840fe162df3bcc8e390c58ef4e2acf9", + "search": [ + "weather", + "sun", + "brightness" + ], + "charRef": 62648 + }, + { + "css": "cloud", + "code": 57631, + "uid": "f9efb0f1944c550cf8d38cdf4aba07c4", + "search": [ + "cloud", + "weather" + ], + "charRef": 62649 + }, + { + "css": "flash-outline", + "code": 57455, + "uid": "971842913945f59c7f3cf11e75e1e4f1", + "search": [ + "flash", + "bolt" + ], + "charRef": 62650 + }, + { + "css": "flash", + "code": 9889, + "uid": "pgdm1vsngqxmheo5xkjpbm5o8k81pawd", + "search": [ + "flash", + "bolt" + ], + "charRef": 62651 + }, + { + "css": "moon", + "code": 57633, + "uid": "7d6302991626c252d089d14dc760fc37", + "search": [ + "moon", + "weather" + ], + "charRef": 62652 + }, + { + "css": "waves-outline", + "code": 57629, + "uid": "9bd0a2540c17de10023e5e8ca3e64da5", + "search": [ + "waves" + ], + "charRef": 62653 + }, + { + "css": "waves", + "code": 57630, + "uid": "fd8d9ae4422e55d3ca23f55d9cf4b20a", + "search": [ + "waves" + ], + "charRef": 62654 + }, + { + "css": "rain", + "code": 57632, + "uid": "e7a4824e79002c2d8ce3047b2da8b5a2", + "search": [ + "cloud", + "rain", + "drizzle", + "weather" + ], + "charRef": 62655 + }, + { + "css": "cloud-sun", + "code": 57634, + "uid": "ac10a3a3077eab1b9d66509eb25fb9b4", + "search": [ + "cloud", + "sun", + "weather" + ], + "charRef": 62656 + }, + { + "css": "drizzle", + "code": 57635, + "uid": "6f200a5a449259c51cd0ccf56b4c1e93", + "search": [ + "cloud", + "rain", + "drizzle", + "weather" + ], + "charRef": 62657 + }, + { + "css": "snow", + "code": 57636, + "uid": "d26795657ef6fb008bee4d54c358f7c8", + "search": [ + "snow", + "weather" + ], + "charRef": 62658 + }, + { + "css": "cloud-flash", + "code": 57637, + "uid": "3cac7625657b10cf706e7f332749c912", + "search": [ + "cloud", + "flash", + "weather" + ], + "charRef": 62659 + }, + { + "css": "cloud-wind", + "code": 57639, + "uid": "364cc69fb3edb8fb21caa6a2c0489589", + "search": [ + "cloud", + "wind", + "weather" + ], + "charRef": 62660 + }, + { + "css": "wind", + "code": 57640, + "uid": "b356b6fbb59d7eca7c15fdb055f0401f", + "search": [ + "wind", + "weather" + ], + "charRef": 62661 + }, + { + "css": "plane-outline", + "code": 57533, + "uid": "db7651b88bb33a590710f551bfbbd371", + "search": [ + "flight", + "plane", + "airplane", + "fly" + ], + "charRef": 62662 + }, + { + "css": "plane", + "code": 57534, + "uid": "3dae5d2af2b99240c3c118e872f762f2", + "search": [ + "flight", + "plane", + "airplane", + "fly" + ], + "charRef": 62663 + }, + { + "css": "leaf", + "code": 57486, + "uid": "4ecf5fd3870bb82ba003d7f34845448d", + "search": [ + "leaf" + ], + "charRef": 62664 + }, + { + "css": "lifebuoy", + "code": 57589, + "uid": "a9359f32375e27bf884c4b3388885050", + "search": [ + "support", + "lifebuoy" + ], + "charRef": 62665 + }, + { + "css": "briefcase", + "code": 57393, + "uid": "bb310a229d0d33a1cbe8aa151a7a8fcb", + "search": [ + "briefcase" + ], + "charRef": 62666 + }, + { + "css": "brush", + "code": 57394, + "uid": "5381e124761bc5dbcf32ec5dd86f91d6", + "search": [ + "brush", + "paint" + ], + "charRef": 62667 + }, + { + "css": "pipette", + "code": 57532, + "uid": "287ee2cac4ded1712253c7b03ff4a5db", + "search": [ + "pipette", + "eyedropper" + ], + "charRef": 62668 + }, + { + "css": "power-outline", + "code": 57540, + "uid": "b7cf8dba5f349cb92b536d76db4a4178", + "search": [ + "power", + "off" + ], + "charRef": 62669 + }, + { + "css": "power", + "code": 57541, + "uid": "b387bb08e237859ba573fb32e2117310", + "search": [ + "power", + "off" + ], + "charRef": 62670 + }, + { + "css": "check-outline", + "code": 57482, + "uid": "0c71ab36fb4e0923e3cf8d6beabe1851", + "search": [ + "check" + ], + "charRef": 62671 + }, + { + "css": "check", + "code": 57483, + "uid": "27531040afb54140f4d449321c9cec3a", + "search": [ + "check" + ], + "charRef": 62672 + }, + { + "css": "gift", + "code": 57464, + "uid": "610efad3150b6959e1b3fc863f39c60c", + "search": [ + "gift", + "box" + ], + "charRef": 62673 + }, + { + "css": "temperatire", + "code": 57601, + "uid": "5c49851100aa021825b346d16d7f3abf", + "search": [ + "temperature", + "weather", + "thermometer" + ], + "charRef": 62674 + }, + { + "css": "chart-outline", + "code": 57407, + "uid": "85046e7e5a2fe685961d1423fcda0649", + "search": [ + "chart", + "diagram" + ], + "charRef": 62675 + }, + { + "css": "chart", + "code": 128200, + "uid": "pdnk53e9ff0ck5q3b16vcm1hh1447j7e", + "search": [ + "chart", + "diagram" + ], + "charRef": 62676 + }, + { + "css": "chart-alt-outline", + "code": 57403, + "uid": "a55e4173e388989f16afd373b894a9f4", + "search": [ + "chart", + "diagram" + ], + "charRef": 62677 + }, + { + "css": "chart-alt", + "code": 57404, + "uid": "d5f287ad8e3a2db8f808bc09980ec3dc", + "search": [ + "chart", + "diagram" + ], + "charRef": 62678 + }, + { + "css": "chart-bar-outline", + "code": 57405, + "uid": "890649841b2c37d56ff90065872fecf3", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 62679 + }, + { + "css": "chart-bar", + "code": 128202, + "uid": "5v7h140x5zz1acnzfzo36flbwar5tujm", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 62680 + }, + { + "css": "chart-pie-outline", + "code": 57409, + "uid": "76dfadaf502e065ac7b2689948f49cb0", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62681 + }, + { + "css": "chart-pie", + "code": 57410, + "uid": "um6h7e9nfp79peah8uphjhismoa8owtu", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62682 + }, + { + "css": "ticket", + "code": 57606, + "uid": "17bddf8c9ea5dc5b8e1f33c936d08c1a", + "search": [ + "ticket" + ], + "charRef": 62683 + }, + { + "css": "credit-card", + "code": 57424, + "uid": "9f498adcae624d612adc3123d65abf04", + "search": [ + "credit", + "card", + "plastic" + ], + "charRef": 62684 + }, + { + "css": "clipboard", + "code": 57415, + "uid": "1a27e6346cdf0480c9c22351378bebbb", + "search": [ + "clipboard" + ], + "charRef": 62685 + }, + { + "css": "database", + "code": 57426, + "uid": "9637f035d143cc193e71c9704ebbb513", + "search": [ + "database" + ], + "charRef": 62686 + }, + { + "css": "key-outline", + "code": 57484, + "uid": "8cc0aaefb9860f1ccef03f63f5873361", + "search": [ + "key" + ], + "charRef": 62687 + }, + { + "css": "key", + "code": 128273, + "uid": "upidp9k72x66utj5w89oyq65tp6r2tpe", + "search": [ + "key" + ], + "charRef": 62688 + }, + { + "css": "flow-split", + "code": 57457, + "uid": "da6c4728f6175a4b99b122274b8f921c", + "search": [ + "flow", + "junction", + "split" + ], + "charRef": 62689 + }, + { + "css": "flow-merge", + "code": 57458, + "uid": "c1bea2b4c01d1d4bd1e4e1f79e51cdd2", + "search": [ + "flow", + "junction", + "split", + "merge" + ], + "charRef": 62690 + }, + { + "css": "flow-parallel", + "code": 57459, + "uid": "ccfaa7f5fe179987bd366051345ba985", + "search": [ + "flow", + "junction", + "parallel" + ], + "charRef": 62691 + }, + { + "css": "flow-cross", + "code": 57460, + "uid": "e45a44236f3f1ac013a1287bb60cd965", + "search": [ + "flow", + "junction", + "cross", + "switch" + ], + "charRef": 62692 + }, + { + "css": "certificate-outline", + "code": 57586, + "uid": "d7b214265bfe7138768bb8b9f62b759a", + "search": [ + "certificate" + ], + "charRef": 62693 + }, + { + "css": "certificate", + "code": 57587, + "uid": "1a7ed99931fee554309101d072e5363d", + "search": [ + "certificate" + ], + "charRef": 62694 + }, + { + "css": "scissors-outline", + "code": 57551, + "uid": "819df9964d860125547757a693150aeb", + "search": [ + "scissors" + ], + "charRef": 62695 + }, + { + "css": "scissors", + "code": 9986, + "uid": "2npqajwqwxy3kbchcht7tyupllg270hb", + "search": [ + "scissors" + ], + "charRef": 62696 + }, + { + "css": "flask", + "code": 57388, + "uid": "0fg01d4656jzluy9fz6ee4ohdd3nt2pe", + "search": [ + "flask" + ], + "charRef": 62697 + }, + { + "css": "wine", + "code": 57643, + "uid": "935dd4069330896913745bbdd9699b0e", + "search": [ + "wine", + "glass" + ], + "charRef": 62698 + }, + { + "css": "coffee", + "code": 57419, + "uid": "8f73806c205d38d9412c340f93ed0c7a", + "search": [ + "coffee", + "cup" + ], + "charRef": 62699 + }, + { + "css": "beer", + "code": 57389, + "uid": "c2e02247804b8372740de0b76311f1ad", + "search": [ + "beer", + "drink" + ], + "charRef": 62700 + }, + { + "css": "anchor-outline", + "code": 57346, + "uid": "40b8b7bf3ab4931765b7d32fb625b4cd", + "search": [ + "anchor" + ], + "charRef": 62701 + }, + { + "css": "anchor", + "code": 57347, + "uid": "eb707fc827e812cdcfdf25b13622fb7b", + "search": [ + "anchor" + ], + "charRef": 62702 + }, + { + "css": "puzzle-outline", + "code": 57543, + "uid": "8f47f269b2667fb9b661e950a9599e26", + "search": [ + "puzzle", + "plugin" + ], + "charRef": 62703 + }, + { + "css": "puzzle", + "code": 57544, + "uid": "xoidjr6q3rzi7tpw6hci1k6srz15g11l", + "search": [ + "puzzle", + "plugin" + ], + "charRef": 62704 + }, + { + "css": "tree", + "code": 57611, + "uid": "2b8ea04aa0e500ae056f9c7934af18e6", + "search": [ + "tree" + ], + "charRef": 62705 + }, + { + "css": "calculator", + "code": 57396, + "uid": "2de0dab5fbbc467b51692895fcce11e2", + "search": [ + "calculator" + ], + "charRef": 62706 + }, + { + "css": "infinity-outline", + "code": 57476, + "uid": "d054fe11fb18e0ac8035d0d9ad556e3b", + "search": [ + "infinity", + "math" + ], + "charRef": 62707 + }, + { + "css": "infinity", + "code": 8734, + "uid": "2039c86dq3jtfwqmgow2quvuzq3k34bu", + "search": [ + "infinity", + "math" + ], + "charRef": 62708 + }, + { + "css": "pi-outline", + "code": 57528, + "uid": "ffa340a4e2c3aa6ea354787b999bced7", + "search": [ + "pi", + "math" + ], + "charRef": 62709 + }, + { + "css": "pi", + "code": 57529, + "uid": "d2d6ab0dd4fb9365b1d5756380484bbb", + "search": [ + "pi", + "math" + ], + "charRef": 62710 + }, + { + "css": "at", + "code": 57378, + "uid": "8bf56386082752a2acc88a1ddf6851a8", + "search": [ + "at" + ], + "charRef": 62711 + }, + { + "css": "at-circled", + "code": 57555, + "uid": "aa5bd6860d8921412a6e25946991410b", + "search": [ + "at" + ], + "charRef": 62712 + }, + { + "css": "looped-square-outline", + "code": 57538, + "uid": "36cd8afd434ce27844b51a9a783037e6", + "search": [ + "looped", + "square" + ], + "charRef": 62713 + }, + { + "css": "looped-square-interest", + "code": 57539, + "uid": "6f8cc29884d86ad170e2a6e7544fdced", + "search": [ + "looped", + "square" + ], + "charRef": 62714 + }, + { + "css": "sort-alphabet-outline", + "code": 57578, + "uid": "ef8560a06ed46a192092bf1f08c142a6", + "search": [ + "sort", + "alphabetically" + ], + "charRef": 62715 + }, + { + "css": "sort-alphabet", + "code": 57579, + "uid": "67f793f91864e379458a92ccc61d9ccf", + "search": [ + "sort", + "alphabetically" + ], + "charRef": 62716 + }, + { + "css": "sort-numeric-outline", + "code": 57580, + "uid": "03df30a09d260eb427edcd7a65c1a84c", + "search": [ + "sort", + "numerically" + ], + "charRef": 62717 + }, + { + "css": "sort-numeric", + "code": 57581, + "uid": "2d220a22480861b15878d1632e31ab47", + "search": [ + "sort", + "numerically" + ], + "charRef": 62718 + }, + { + "css": "dribbble-circled", + "code": 57556, + "uid": "11970c0d1bb67f9525844b424f0f8736", + "search": [ + "dribbble", + "social" + ], + "charRef": 62719 + }, + { + "css": "dribbble", + "code": 57557, + "uid": "758801555b61307e51e333e9d62d53ba", + "search": [ + "dribbble", + "social" + ], + "charRef": 62720 + }, + { + "css": "facebook-circled", + "code": 57558, + "uid": "33cea6d7bd699348c0d593e105361a51", + "search": [ + "facebook", + "social" + ], + "charRef": 62721 + }, + { + "css": "facebook", + "code": 57559, + "uid": "77b3693facc3d803417105997b4ffe96", + "search": [ + "facebook", + "social" + ], + "charRef": 62722 + }, + { + "css": "flickr-circled", + "code": 57560, + "uid": "5a010022e299fec5a6f33a6157e8ea25", + "search": [ + "flickr", + "social" + ], + "charRef": 62723 + }, + { + "css": "flickr", + "code": 57561, + "uid": "5006b0f71f1a3cd3c73c04f7664cc20f", + "search": [ + "flickr", + "social" + ], + "charRef": 62724 + }, + { + "css": "github-circled", + "code": 57562, + "uid": "4a98de1ada96673f8b43a600fd50d569", + "search": [ + "github", + "social" + ], + "charRef": 62725 + }, + { + "css": "github", + "code": 57563, + "uid": "b94db9f012742fbdde9cb59413e14e9b", + "search": [ + "github", + "social" + ], + "charRef": 62726 + }, + { + "css": "lastfm-circled", + "code": 57564, + "uid": "ae8492c61cce60c36ed9667680017e7d", + "search": [ + "lastfm", + "social" + ], + "charRef": 62727 + }, + { + "css": "lastfm", + "code": 57565, + "uid": "afe98849cb4fe253a2b30b9716f67526", + "search": [ + "lastfm", + "social" + ], + "charRef": 62728 + }, + { + "css": "linkedin-circled", + "code": 57566, + "uid": "b2178b8fca35bac9e4bfcea4a4c05a92", + "search": [ + "linkedin", + "social" + ], + "charRef": 62729 + }, + { + "css": "linkedin", + "code": 57567, + "uid": "25a30265650b260ef03df4cbbff80272", + "search": [ + "linkedin", + "social" + ], + "charRef": 62730 + }, + { + "css": "pinterest-circled", + "code": 57568, + "uid": "0a3e0e5caddaa9cb266e42b6495975e2", + "search": [ + "pinterest", + "social" + ], + "charRef": 62731 + }, + { + "css": "pinterest", + "code": 57569, + "uid": "178c8af85364e12fe70b959c7c055bc6", + "search": [ + "pinterest", + "social" + ], + "charRef": 62732 + }, + { + "css": "skype-outline", + "code": 57570, + "uid": "2cfac2c1a9eb4552af0eba34def4b010", + "search": [ + "skype", + "social" + ], + "charRef": 62733 + }, + { + "css": "skype", + "code": 57571, + "uid": "f5b8e78b48e3028969a964e002daf745", + "search": [ + "skype", + "social" + ], + "charRef": 62734 + }, + { + "css": "tumbler-circled", + "code": 57572, + "uid": "3e9a99df4e0ede4d8d029d6e71d597ba", + "search": [ + "tumbler", + "social" + ], + "charRef": 62735 + }, + { + "css": "tumbler", + "code": 57573, + "uid": "4a0984f0fb3fd89dd5bdd923f2ff8e45", + "search": [ + "tumbler", + "social" + ], + "charRef": 62736 + }, + { + "css": "twitter-circled", + "code": 57574, + "uid": "b523a5bcf8d08725038873d89bb003fd", + "search": [ + "twitter", + "social" + ], + "charRef": 62737 + }, + { + "css": "twitter", + "code": 57575, + "uid": "4568bba1dba45522fc539c733c9b35e5", + "search": [ + "twitter", + "social" + ], + "charRef": 62738 + }, + { + "css": "vimeo-circled", + "code": 57576, + "uid": "bfaa824e96fa07779bc7b130b1216ce9", + "search": [ + "vimeo", + "social" + ], + "charRef": 62739 + }, + { + "css": "vimeo", + "code": 57577, + "uid": "3315691c918224dc4893f2e368a4e0c8", + "search": [ + "vimeo", + "social" + ], + "charRef": 62740 + } + ], + "font": { + "version": "2.0.2", + "fontname": "typicons", + "fullname": "Typicons", + "familyname": "Typicons", + "copyright": "(c) Stephen Hutchings 2012", + "ascent": 850, + "descent": -150, + "weight": "Book" + }, + "meta": { + "author": "Stephen Hutchings", + "homepage": "http://typicons.com/", + "twitter": "https://twitter.com/Typicons/", + "github": "https://github.com/stephenhutchings/typicons.font", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "search", + "code": 128270, + "uid": "c6344a6ed148da12354cc90705287696", + "search": [ + "search", + "find" + ], + "charRef": 62741 + }, + { + "css": "mail", + "code": 9993, + "uid": "937f4db8b6ff3348a1d9fcd5e12fd2fe", + "search": [ + "mail", + "email" + ], + "charRef": 62742 + }, + { + "css": "heart", + "code": 9829, + "uid": "ff933ecda3a1da53071ee6ec224ef8c9", + "search": [ + "heart" + ], + "charRef": 62743 + }, + { + "css": "heart-empty", + "code": 9825, + "uid": "acae2d2db2ebe97429c6eddc2f7b0cd2", + "search": [ + "heart" + ], + "charRef": 62744 + }, + { + "css": "star", + "code": 9733, + "uid": "5daac230ad1cfdf4782697dfbda679dd", + "search": [ + "star" + ], + "charRef": 62745 + }, + { + "css": "user", + "code": 128100, + "uid": "86ee1fc7ff57e9c9c60d8a5e57183776", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62746 + }, + { + "css": "video", + "code": 127916, + "uid": "2d2f83f97ba029f32db3ca963dd0beea", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 62747 + }, + { + "css": "picture", + "code": 127748, + "uid": "9bf421d05c985b569e86fa7c502bd879", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 62748 + }, + { + "css": "camera", + "code": 128247, + "uid": "69253046b55214b42caada5c226801f2", + "search": [ + "camera", + "photo" + ], + "charRef": 62749 + }, + { + "css": "ok", + "code": 10003, + "uid": "b90d80c250a9bbdd6cd3fe00e6351710", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62750 + }, + { + "css": "ok-circle", + "code": 10004, + "uid": "b4cc17a45ed7d179a2cc815e2da7a383", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62751 + }, + { + "css": "cancel", + "code": 10005, + "uid": "11e664deed5b2587456a4f9c01d720b6", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62752 + }, + { + "css": "cancel-circle", + "code": 10006, + "uid": "188e881b2e2f2b1eb350eb7697aabafd", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62753 + }, + { + "css": "plus", + "code": 43, + "uid": "dbd39eb5a1d67beb54cfcb535e840e0f", + "search": [ + "plus" + ], + "charRef": 62754 + }, + { + "css": "plus-circle", + "code": 10133, + "uid": "59ba4f90d2ca2a843f4f930b03270362", + "search": [ + "plus" + ], + "charRef": 62755 + }, + { + "css": "minus", + "code": 45, + "uid": "9559f17a471856ef50ed266e726cfa25", + "search": [ + "minus" + ], + "charRef": 62756 + }, + { + "css": "minus-circle", + "code": 10134, + "uid": "4062c0e99a3540f6c261bd08ef0fb63f", + "search": [ + "minus" + ], + "charRef": 62757 + }, + { + "css": "help", + "code": 10067, + "uid": "f3eb666ee77d5120ac33c710aa3fd28e", + "search": [ + "help", + "question" + ], + "charRef": 62758 + }, + { + "css": "info", + "code": 8505, + "uid": "ccd52a22af21fbaa98a9c85fb50fca6b", + "search": [ + "info" + ], + "charRef": 62759 + }, + { + "css": "home", + "code": 8962, + "uid": "d6944e1d9af302093d43b299bbecbbbe02", + "search": [ + "home" + ], + "charRef": 62760 + }, + { + "css": "link", + "code": 128279, + "uid": "754557fa790629b8df53349af508af41", + "search": [ + "link", + "url", + "address" + ], + "charRef": 62761 + }, + { + "css": "attach", + "code": 128206, + "uid": "1df601d49c98cef45ef993db54bd966d", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 62762 + }, + { + "css": "lock", + "code": 128274, + "uid": "9682f692dd55ada1d1741a3a56420232", + "search": [ + "lock" + ], + "charRef": 62763 + }, + { + "css": "lock-empty", + "code": 59144, + "uid": "2648c9967bbf1c714670b9f79d7d43d7", + "search": [ + "lock" + ], + "charRef": 62764 + }, + { + "css": "lock-open", + "code": 128275, + "uid": "51fe10dcd3f6669d6a1ea52fc94d5173", + "search": [ + "lock", + "unlock" + ], + "charRef": 62765 + }, + { + "css": "lock-open-empty", + "code": 59145, + "uid": "7f374d3b7333829adfc2dc54a08f25f6", + "search": [ + "lock", + "unlock" + ], + "charRef": 62766 + }, + { + "css": "pin", + "code": 128204, + "uid": "794d73c3a5fcf710265679700e470578", + "search": [ + "pin", + "pushpin" + ], + "charRef": 62767 + }, + { + "css": "eye", + "code": 59146, + "uid": "fbb01025c73ffb726bf28b98619df36d", + "search": [ + "eye", + "subscribe" + ], + "charRef": 62768 + }, + { + "css": "tag", + "code": 59148, + "uid": "d3d5f318c8e9a58245c2e48c7ce0f57d", + "search": [ + "tag", + "price", + "offer" + ], + "charRef": 62769 + }, + { + "css": "tag-empty", + "code": 59150, + "uid": "e713848e7db2b6593236d147dd4e81ad", + "search": [ + "tag", + "price", + "offer" + ], + "charRef": 62770 + }, + { + "css": "download", + "code": 128229, + "uid": "815576dccc008afcfd83a38378a4fdde", + "search": [ + "download" + ], + "charRef": 62771 + }, + { + "css": "upload", + "code": 128228, + "uid": "2dabd0ee753bedbc9c1c52990d204403", + "search": [ + "upload" + ], + "charRef": 62772 + }, + { + "css": "download-cloud", + "code": 59152, + "uid": "acba01b26400b5e898ef20aabb2ff84d", + "search": [ + "download", + "cloud" + ], + "charRef": 62773 + }, + { + "css": "upload-cloud", + "code": 59153, + "uid": "efca324e399b7ce0e33c94090bb8784b", + "search": [ + "upload", + "cloud" + ], + "charRef": 62774 + }, + { + "css": "quote-left", + "code": 10077, + "uid": "661bd5ba1dad15ad9acbfcd8b8af76f3", + "search": [ + "quote" + ], + "charRef": 62775 + }, + { + "css": "quote-right", + "code": 10078, + "uid": "bc0af4824c8eedcad7bc0d35911dac2a", + "search": [ + "quote" + ], + "charRef": 62776 + }, + { + "css": "quote-left-alt", + "code": 10075, + "uid": "96a3aff31cec6cfbe6177151b3a44d20", + "search": [ + "quote" + ], + "charRef": 62777 + }, + { + "css": "quote-right-alt", + "code": 10076, + "uid": "6d0d103e180c68aa77bd26a595b5aa5f", + "search": [ + "quote" + ], + "charRef": 62778 + }, + { + "css": "pencil", + "code": 9998, + "uid": "667b873c8422e4cab006df8422cb51c5", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62779 + }, + { + "css": "pencil-neg", + "code": 9999, + "uid": "e3e12be877eab92e593ca185223e7a5b", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62780 + }, + { + "css": "pencil-alt", + "code": 10000, + "uid": "eedb189bc6326c685d83627f78e1c9de", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62781 + }, + { + "css": "undo", + "code": 8630, + "uid": "ce5e29aa5208417700e7f7012a236c00", + "search": [ + "undo", + "return", + "back" + ], + "charRef": 62782 + }, + { + "css": "comment", + "code": 59160, + "uid": "679d36f8485f05180a2719c91b3f621e", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62783 + }, + { + "css": "comment-inv", + "code": 59161, + "uid": "1bea05ec4430cc1cd93622249d6b92e9", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62784 + }, + { + "css": "comment-alt", + "code": 59162, + "uid": "acb5a542eef1c187078a9af1ede3db01", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62785 + }, + { + "css": "comment-inv-alt", + "code": 59163, + "uid": "7636185c02f509cf3b305508532a5c05", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62786 + }, + { + "css": "comment-alt2", + "code": 59164, + "uid": "2ae040a98998e1497aa0c5ddbacaf3c0", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62787 + }, + { + "css": "comment-inv-alt2", + "code": 59165, + "uid": "e34c1d65ed4ecd53aec3687f0e5b1cf0", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 62788 + }, + { + "css": "chat", + "code": 59168, + "uid": "7e2642b7a42728c7d9ce5558c3f8461b", + "search": [ + "chat", + "talk" + ], + "charRef": 62789 + }, + { + "css": "chat-inv", + "code": 59169, + "uid": "cc8beaf58a46ee4186e7aa51209a9b53", + "search": [ + "chat", + "talk" + ], + "charRef": 62790 + }, + { + "css": "location", + "code": 59172, + "uid": "08a23ea96a596b1b5f12f6abbbc8f5f9", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62791 + }, + { + "css": "location-inv", + "code": 59173, + "uid": "d061c177f823e3ab1eb38085f84efaf2", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62792 + }, + { + "css": "location-alt", + "code": 59174, + "uid": "cfcd1785b56a93cbac7662294861173e", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62793 + }, + { + "css": "compass", + "code": 59176, + "uid": "47ad68217678b39090ac757b873da2e6", + "search": [ + "compass" + ], + "charRef": 62794 + }, + { + "css": "trash", + "code": 59177, + "uid": "d41b15fca9100375790a920f2deda3ff", + "search": [ + "trash", + "delete" + ], + "charRef": 62795 + }, + { + "css": "trash-empty", + "code": 59178, + "uid": "ef0c0495599c1e1d733359546ae3a48a", + "search": [ + "trash", + "delete" + ], + "charRef": 62796 + }, + { + "css": "doc", + "code": 59184, + "uid": "9ebd01466c6cb73106d26dbacef5f84a", + "search": [ + "doc", + "article" + ], + "charRef": 62797 + }, + { + "css": "doc-inv", + "code": 59185, + "uid": "cb35902d643e9e6ba8ba1cf739edef9a", + "search": [ + "doc", + "article" + ], + "charRef": 62798 + }, + { + "css": "doc-alt", + "code": 59186, + "uid": "d52e2eb2073c96a2a33487779090f899", + "search": [ + "doc", + "article" + ], + "charRef": 62799 + }, + { + "css": "doc-inv-alt", + "code": 59187, + "uid": "c93d6731f7cc8c218754e005306bad54", + "search": [ + "doc", + "article" + ], + "charRef": 62800 + }, + { + "css": "article", + "code": 59188, + "uid": "8e22728e15b02b170033259b208e43e1", + "search": [ + "document", + "article" + ], + "charRef": 62801 + }, + { + "css": "article-alt", + "code": 59189, + "uid": "f886d2d6cc8cb1b1117e26819a7bc282", + "search": [ + "document", + "article", + "more" + ], + "charRef": 62802 + }, + { + "css": "book-open", + "code": 128214, + "uid": "8fc56819afcd07e2786e34f18d39b71b", + "search": [ + "book", + "doc" + ], + "charRef": 62803 + }, + { + "css": "folder", + "code": 128193, + "uid": "b13a27d19dd739e29cbc7926085386d9", + "search": [ + "folder" + ], + "charRef": 62804 + }, + { + "css": "folder-empty", + "code": 128194, + "uid": "13ea1e82d38c7ed614d9ee85e9c42053", + "search": [ + "folder" + ], + "charRef": 62805 + }, + { + "css": "box", + "code": 128230, + "uid": "dd6df3b754e8d0dbf09d9b24088f0442", + "search": [ + "box", + "archive", + "package" + ], + "charRef": 62806 + }, + { + "css": "rss", + "code": 59194, + "uid": "cbfc8f7ba004d60f5134b30a27e87829", + "search": [ + "rss" + ], + "charRef": 62807 + }, + { + "css": "rss-alt", + "code": 59195, + "uid": "d6a9fe8ceb1a852d925452694691a41d", + "search": [ + "rss" + ], + "charRef": 62808 + }, + { + "css": "cog", + "code": 9881, + "uid": "fc94b92194752796654c96c7b7dccebb", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 62809 + }, + { + "css": "wrench", + "code": 128295, + "uid": "f185a7454f33a8fbcdd943db8a998cfd", + "search": [ + "settings", + "wrench" + ], + "charRef": 62810 + }, + { + "css": "share", + "code": 59196, + "uid": "afdef1656447e2558662b393d6b4bb75", + "search": [ + "share" + ], + "charRef": 62811 + }, + { + "css": "calendar", + "code": 128197, + "uid": "c833c98d78cfebed5780cfaaa302a12b", + "search": [ + "calendar", + "date" + ], + "charRef": 62812 + }, + { + "css": "calendar-inv", + "code": 59198, + "uid": "e2d4382fb8eb0e89e8990f4c44753342", + "search": [ + "calendar", + "date" + ], + "charRef": 62813 + }, + { + "css": "calendar-alt", + "code": 128198, + "uid": "4dcad05669d06805ebe58675e14408ad", + "search": [ + "calendar", + "date" + ], + "charRef": 62814 + }, + { + "css": "mic", + "code": 127908, + "uid": "659d9389a0f9630c7d6dca5a83544901", + "search": [ + "mic" + ], + "charRef": 62815 + }, + { + "css": "volume-off", + "code": 128263, + "uid": "fcf5b3c96534af57ea0e201d4500ed8b", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 62816 + }, + { + "css": "volume-up", + "code": 128266, + "uid": "03a0e5d43971354eb6af8fdc46e33ab6", + "search": [ + "volume", + "sound" + ], + "charRef": 62817 + }, + { + "css": "headphones", + "code": 127911, + "uid": "52177c3387cdac48d6ed18bebe84c34a", + "search": [ + "sound", + "music", + "headphones" + ], + "charRef": 62818 + }, + { + "css": "clock", + "code": 128340, + "uid": "b99d736cef489a3150ba8aac7c4e8403", + "search": [ + "clock", + "time" + ], + "charRef": 62819 + }, + { + "css": "lamp", + "code": 128161, + "uid": "831e70448a066d4403a0bbd8ff0b8973", + "search": [ + "idea", + "lamp", + "light" + ], + "charRef": 62820 + }, + { + "css": "block", + "code": 128683, + "uid": "7cf0c6fefa5327473dec91427434ae26", + "search": [ + "block", + "deny" + ], + "charRef": 62821 + }, + { + "css": "resize-full", + "code": 59204, + "uid": "4815ddddea76d90e367a9694a93b7e24", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62822 + }, + { + "css": "resize-full-alt", + "code": 59205, + "uid": "776687efbdb973ebc67e049cc4c41b13", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62823 + }, + { + "css": "resize-small", + "code": 59206, + "uid": "b05c5a209b56e7ea6632a31e4bd0b41d", + "search": [ + "resize" + ], + "charRef": 62824 + }, + { + "css": "resize-small-alt", + "code": 59207, + "uid": "8596dc69a5e7e0297e8926b6e2563509", + "search": [ + "resize" + ], + "charRef": 62825 + }, + { + "css": "resize-vertical", + "code": 11020, + "uid": "7dde84b4f180e3c07523faecda81caa6", + "search": [ + "resize" + ], + "charRef": 62826 + }, + { + "css": "resize-horizontal", + "code": 11021, + "uid": "63493102fc6b827e4a7be30b13cbf3b4", + "search": [ + "resize" + ], + "charRef": 62827 + }, + { + "css": "move", + "code": 59210, + "uid": "be25d23b15c3294588947a6b959811ec", + "search": [ + "move" + ], + "charRef": 62828 + }, + { + "css": "popup", + "code": 59212, + "uid": "971be54c1452e2558926d36786e6b1d7", + "search": [ + "popup", + "window" + ], + "charRef": 62829 + }, + { + "css": "down", + "code": 8595, + "uid": "41d90aea465750c2a5dc6cb0bdef9617", + "search": [ + "arrow", + "down" + ], + "charRef": 62830 + }, + { + "css": "left", + "code": 8592, + "uid": "a76545bb6ea4e684505da08d26e58467", + "search": [ + "arrow", + "left" + ], + "charRef": 62831 + }, + { + "css": "right", + "code": 8594, + "uid": "7686897ce7ec808ff19aec948b5aaf43", + "search": [ + "arrow", + "right" + ], + "charRef": 62832 + }, + { + "css": "up", + "code": 8593, + "uid": "98edd99a41fbdc5633151cd21b7e56f8", + "search": [ + "arrow", + "up" + ], + "charRef": 62833 + }, + { + "css": "down-circle", + "code": 58532, + "uid": "524f670504958d3e32ef887b99d8aca2", + "search": [ + "arrow", + "down" + ], + "charRef": 62834 + }, + { + "css": "left-circle", + "code": 58529, + "uid": "a263473d2d406881ea08f991c1b38694", + "search": [ + "arrow", + "left" + ], + "charRef": 62835 + }, + { + "css": "right-circle", + "code": 58530, + "uid": "ccee648b9e12a533f6957967e29ebdef", + "search": [ + "arrow", + "right" + ], + "charRef": 62836 + }, + { + "css": "up-circle", + "code": 58531, + "uid": "55ba7d8f711ce265df7de4ab7f148e65", + "search": [ + "arrow", + "up" + ], + "charRef": 62837 + }, + { + "css": "cw", + "code": 10227, + "uid": "5889f24614ead600acce1af6a861b97c", + "search": [ + "arrow", + "reload", + "redo", + "repeat" + ], + "charRef": 62838 + }, + { + "css": "loop", + "code": 128260, + "uid": "5d3ef4b7c90d2931e641b840ee42f694", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62839 + }, + { + "css": "loop-alt", + "code": 128257, + "uid": "5386cf333c67332c278b798c9fded7e5", + "search": [ + "arrow", + "loop", + "reload", + "refresh" + ], + "charRef": 62840 + }, + { + "css": "exchange", + "code": 8644, + "uid": "e07df3e5b9ae72836b7804f38f0644a9", + "search": [ + "arrow", + "exchange", + "transfer" + ], + "charRef": 62841 + }, + { + "css": "split", + "code": 9095, + "uid": "09b87624e9d9a79109429ea81ed0d02d", + "search": [ + "arrow", + "split", + "fork" + ], + "charRef": 62842 + }, + { + "css": "arrow-curved", + "code": 10549, + "uid": "f3ebd6751c15a280af5cc5f4a764187d", + "search": [ + "arrow" + ], + "charRef": 62843 + }, + { + "css": "play", + "code": 9654, + "uid": "929ff290f0be577d2a2d587d5a53eec1", + "search": [ + "play", + "player" + ], + "charRef": 62844 + }, + { + "css": "play-circle2", + "code": 57416, + "uid": "8a6c569e59c69e9de113978b11c057b8", + "search": [ + "play", + "player" + ], + "charRef": 62845 + }, + { + "css": "stop", + "code": 9642, + "uid": "e25c28400dafedf82c27c46ccd6a49a7", + "search": [ + "stop", + "player" + ], + "charRef": 62846 + }, + { + "css": "pause", + "code": 9097, + "uid": "b660aec4a0c2cdec04a3cd708e00fa07", + "search": [ + "pause", + "player" + ], + "charRef": 62847 + }, + { + "css": "to-start", + "code": 9198, + "uid": "6afd0c334e4d1dd182d44e9e63257174", + "search": [ + "left", + "player" + ], + "charRef": 62848 + }, + { + "css": "to-end", + "code": 9197, + "uid": "f0d8d7ccb0adb92a41c058d7fd9f11b2", + "search": [ + "right", + "player" + ], + "charRef": 62849 + }, + { + "css": "eject", + "code": 9167, + "uid": "e5a569724908d47c2afc964d9b78a477", + "search": [ + "eject", + "player" + ], + "charRef": 62850 + }, + { + "css": "target", + "code": 127919, + "uid": "74ae46b1527f71bad40a91762f4190ef", + "search": [ + "target" + ], + "charRef": 62851 + }, + { + "css": "signal", + "code": 128246, + "uid": "c30b64ea0091fb65b8e084b9a4c4088a", + "search": [ + "chart", + "bar", + "diagram", + "signal", + "wifi" + ], + "charRef": 62852 + }, + { + "css": "award", + "code": 127945, + "uid": "96f70b04affa57b79d70f5874815a912", + "search": [ + "top", + "trophy", + "prize", + "award" + ], + "charRef": 62853 + }, + { + "css": "award-empty", + "code": 59236, + "uid": "01879adc8814a7cb4a5f6d3301558b2f", + "search": [ + "top", + "trophy", + "prize", + "award" + ], + "charRef": 62854 + }, + { + "css": "list", + "code": 59237, + "uid": "ef47651da3866460f27baf85ae234e5c", + "search": [ + "list" + ], + "charRef": 62855 + }, + { + "css": "list-nested", + "code": 59238, + "uid": "96418ab910c40c3bf61a9ba7b718c49d", + "search": [ + "list" + ], + "charRef": 62856 + }, + { + "css": "bat-empty", + "code": 59250, + "uid": "dd28d0426ce746ebaf9a0100a774a6fa", + "search": [ + "battery" + ], + "charRef": 62857 + }, + { + "css": "bat-half", + "code": 59251, + "uid": "a77d168a49c592c0766e9e04bde3a061", + "search": [ + "battery" + ], + "charRef": 62858 + }, + { + "css": "bat-full", + "code": 59252, + "uid": "24a284baa85ebcdcaff1249a6f5c6e1d", + "search": [ + "battery" + ], + "charRef": 62859 + }, + { + "css": "bat-charge", + "code": 59253, + "uid": "49ea09357725720daebc1596f007af57", + "search": [ + "battery", + "charge" + ], + "charRef": 62860 + }, + { + "css": "mobile", + "code": 128241, + "uid": "2adb5fa922bd92ebeef498ec7dbcae6d", + "search": [ + "mobile", + "iphone" + ], + "charRef": 62861 + }, + { + "css": "cd", + "code": 128191, + "uid": "991360fdaaad39ce2e91cae81cdc244c", + "search": [ + "cd", + "vinyl" + ], + "charRef": 62862 + }, + { + "css": "equalizer", + "code": 59285, + "uid": "e3699d145bd628d2a35d4a508b616f0c", + "search": [ + "equalizer" + ], + "charRef": 62863 + }, + { + "css": "cursor", + "code": 59286, + "uid": "e2aba9565be51ca70224c07282afbba6", + "search": [ + "cursor", + "arrow" + ], + "charRef": 62864 + }, + { + "css": "aperture", + "code": 59287, + "uid": "a264b521b6d3e15699d306afcb57a5cf", + "search": [ + "aperture" + ], + "charRef": 62865 + }, + { + "css": "aperture-alt", + "code": 59288, + "uid": "30c680680eee267dcf67edf14418494d", + "search": [ + "aperture" + ], + "charRef": 62866 + }, + { + "css": "steering-wheel", + "code": 59289, + "uid": "4338ab07af9a5bd3a7bd8984047cb018", + "search": [ + "steering", + "wheel" + ], + "charRef": 62867 + }, + { + "css": "book", + "code": 128213, + "uid": "9597c5a31b6bdd94f4936fcc71d30613", + "search": [ + "book" + ], + "charRef": 62868 + }, + { + "css": "book-alt", + "code": 128212, + "uid": "d7059fc5329e1a7fcab80ba87831c957", + "search": [ + "book" + ], + "charRef": 62869 + }, + { + "css": "brush", + "code": 59290, + "uid": "b3a9e2dab4d19ea3b2f628242c926bfe", + "search": [ + "paint", + "brush" + ], + "charRef": 62870 + }, + { + "css": "brush-alt", + "code": 59291, + "uid": "5ad5e617d3c6eb7da3df417a47b27dba", + "search": [ + "paint", + "brush" + ], + "charRef": 62871 + }, + { + "css": "eyedropper", + "code": 59292, + "uid": "b9be509237c9abea9c258d677777b713", + "search": [ + "paint", + "eyedropper" + ], + "charRef": 62872 + }, + { + "css": "layers", + "code": 59293, + "uid": "d2c499942f8a7c037d5a94f123eeb478", + "search": [ + "paint", + "layers" + ], + "charRef": 62873 + }, + { + "css": "layers-alt", + "code": 59294, + "uid": "de456a594a2a4e68413f60d7e2910596", + "search": [ + "paint", + "layers" + ], + "charRef": 62874 + }, + { + "css": "sun", + "code": 9788, + "uid": "9f41cbda67dafb38926a4201a01691c9", + "search": [ + "weather", + "sun", + "brightness" + ], + "charRef": 62875 + }, + { + "css": "sun-inv", + "code": 9728, + "uid": "48050e07077b01021f7fbdbbec8f7de7", + "search": [ + "weather", + "sun" + ], + "charRef": 62876 + }, + { + "css": "cloud", + "code": 9729, + "uid": "432dbf40f2e51008b92829d2c46dfcb8", + "search": [ + "weather", + "cloud" + ], + "charRef": 62877 + }, + { + "css": "rain", + "code": 9926, + "uid": "e399a5bdcbb20744e3a18168a47f918f", + "search": [ + "weather", + "rain" + ], + "charRef": 62878 + }, + { + "css": "flash", + "code": 9889, + "uid": "606054f1c67f8193d59d9c12e3f4d3e1", + "search": [ + "flash", + "bolt" + ], + "charRef": 62879 + }, + { + "css": "moon", + "code": 9790, + "uid": "3dbc94f3878ecb524fd61d9de3aeabd5", + "search": [ + "moon", + "sleep" + ], + "charRef": 62880 + }, + { + "css": "moon-inv", + "code": 59296, + "uid": "c2152732d525871cf35345955854f711", + "search": [ + "moon", + "sleep" + ], + "charRef": 62881 + }, + { + "css": "umbrella", + "code": 9730, + "uid": "fd8e75dc94d9b3ff9ac959fd8f7e83e6", + "search": [ + "weather", + "umbrella" + ], + "charRef": 62882 + }, + { + "css": "chart-bar", + "code": 128202, + "uid": "f1ecd8633b0ec659877c02cd796df1fd", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 62883 + }, + { + "css": "chart-pie", + "code": 59298, + "uid": "ff1cd67dfb30d12965d950e8a609c31f", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62884 + }, + { + "css": "chart-pie-alt", + "code": 59299, + "uid": "8aa58289df2cc42b260897d7e61aa2c2", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62885 + }, + { + "css": "key", + "code": 9919, + "uid": "76fa76eb3472394c9937f7c7734f77b2", + "search": [ + "key" + ], + "charRef": 62886 + }, + { + "css": "key-inv", + "code": 128273, + "uid": "c6ecc52b6db2a649a08ff54e5ea62886", + "search": [ + "key" + ], + "charRef": 62887 + }, + { + "css": "hash", + "code": 35, + "uid": "d6944e1d9af302093d43b299bbecbbbe", + "search": [ + "hash" + ], + "charRef": 62888 + }, + { + "css": "at", + "code": 64, + "uid": "6db15bda083b09a04bd27dcc1d00744d", + "search": [ + "@", + "at" + ], + "charRef": 62889 + }, + { + "css": "pilcrow", + "code": 182, + "uid": "0e43f93967e6db58cc44dfbc1fe7f516", + "search": [ + "pilcrow" + ], + "charRef": 62890 + }, + { + "css": "dial", + "code": 59300, + "uid": "3a5f357ad2f283dbe0ec52eb4d177eb7", + "search": [ + "dial" + ], + "charRef": 62891 + } + ], + "font": { + "version": "1.0", + "fontname": "iconic", + "fullname": "Iconic", + "familyname": "Iconic", + "copyright": "Copyright (C) 2012 by P.J. Onori", + "ascent": 850, + "descent": -150, + "weight": "Medium" + }, + "meta": { + "author": "P.J. Onori", + "homepage": "http://somerandomdude.com/work/iconic/", + "email": "pj@somerandomdude.com", + "twitter": "http://twitter.com/somerandomdude", + "github": "https://github.com/somerandomdude/Iconic", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "search", + "code": 128269, + "uid": "id8wp0cygl9trzbhlbd9o0fygiesi629", + "search": [ + "search", + "find" + ], + "charRef": 62892 + }, + { + "css": "mail", + "code": 9993, + "uid": "ae3so8q0b0n2h8esv9flua2nmwswa8fd", + "search": [ + "mail", + "email" + ], + "charRef": 62893 + }, + { + "css": "heart", + "code": 9829, + "uid": "pt5lb2orj9ms0n4yyxjavefdukcv1scl", + "search": [ + "heart" + ], + "charRef": 62894 + }, + { + "css": "star", + "code": 9733, + "uid": "kfzodo12ciruwganzy6h1bee2bpyz24d", + "search": [ + "star" + ], + "charRef": 62895 + }, + { + "css": "user", + "code": 128100, + "uid": "ma9pq3m9ye6f33psotqr8e68yyv7fbz6", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62896 + }, + { + "css": "user-woman", + "code": 128105, + "uid": "99qmwsnyl7d1848xayggtcwaysc4e415", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 62897 + }, + { + "css": "user-pair", + "code": 128107, + "uid": "d1a7ajpi3149rk5q4861jw9f2lzg27d1", + "search": null, + "charRef": 62898 + }, + { + "css": "video-alt", + "code": 127910, + "uid": "o3ks7v0pzabyrzijuzxmzyzae06it2eh", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 62899 + }, + { + "css": "videocam", + "code": 127909, + "uid": "ny7ydbn558y0aij4evvc199yt345tks4", + "search": [ + "facetime", + "movie", + "video", + "film" + ], + "charRef": 62900 + }, + { + "css": "videocam-alt", + "code": 127993, + "uid": "vsvgkgr7wqknxe7rsjrusvvs43yekcyr", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 62901 + }, + { + "css": "camera", + "code": 128247, + "uid": "1n2jlgp5brxxzpvvrly6jbfutnk2fpra", + "search": [ + "camera", + "photo" + ], + "charRef": 62902 + }, + { + "css": "th", + "code": 9871, + "uid": "3v2lgx3os8ub377alyqm8mn2o7r4zywg", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 62903 + }, + { + "css": "th-list", + "code": 9776, + "uid": "cy7vw87w1slwyalc4vd8cdhrb50asud3", + "search": [ + "list" + ], + "charRef": 62904 + }, + { + "css": "ok", + "code": 10003, + "uid": "in76hg99crrkpcbz2rjnmgbiw74s72y0", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 62905 + }, + { + "css": "cancel", + "code": 10005, + "uid": "rrhco7mfj6ro9yzhe4a1rbln9flw47re", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62906 + }, + { + "css": "cancel-circle", + "code": 10006, + "uid": "wcb87qh0k9smu6zukdhbn5zip98zofkh", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 62907 + }, + { + "css": "plus", + "code": 43, + "uid": "hbvhbnoivp3qj8xpyqrxa7dvq9ntnci3", + "search": [ + "plus" + ], + "charRef": 62908 + }, + { + "css": "home", + "code": 8962, + "uid": "c1d1ix1r5ldq6yl3xwvh3u3fxqale7sy", + "search": [ + "home" + ], + "charRef": 62909 + }, + { + "css": "lock", + "code": 128274, + "uid": "ivdkw88f6me1kxmgrk3qzv6jkgxhbuj7", + "search": [ + "lock" + ], + "charRef": 62910 + }, + { + "css": "lock-open", + "code": 128275, + "uid": "8u06eo32zy61toyj78of6mi7inn3xlcl", + "search": [ + "lock", + "unlock" + ], + "charRef": 62911 + }, + { + "css": "eye", + "code": 59146, + "uid": "frauy9fser6zk9n5ih3rdpz7zzfjbrvu", + "search": [ + "eye", + "subscribe" + ], + "charRef": 62912 + }, + { + "css": "tag", + "code": 59148, + "uid": "9vefjlcta42r6tjjmog0mpx7mf63jgag", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 62913 + }, + { + "css": "thumbs-up", + "code": 128077, + "uid": "jwebw8rhtovm6adljbdixtj9ltdrzkvb", + "search": [ + "thumbs", + "up", + "like", + "vote" + ], + "charRef": 62914 + }, + { + "css": "thumbs-down", + "code": 128078, + "uid": "h9yii6q602rt4dxjmy9k9wc3jkwzk8d0", + "search": [ + "thumbs", + "down", + "unlike", + "vote" + ], + "charRef": 62915 + }, + { + "css": "download", + "code": 128229, + "uid": "kfk635sf697exf2r3jqx06zz54e1rgx4", + "search": [ + "download" + ], + "charRef": 62916 + }, + { + "css": "export", + "code": 59157, + "uid": "fojo3y3ju5f4vge0bepcxl1mgmzgit9k", + "search": [ + "export", + "share" + ], + "charRef": 62917 + }, + { + "css": "pencil", + "code": 9998, + "uid": "587bjlxppui6u4japooa2foe58rsvicp", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62918 + }, + { + "css": "pencil-alt", + "code": 10000, + "uid": "97var6sq7rzo72ktzg1c6ph46u9pftbr", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62919 + }, + { + "css": "edit", + "code": 9997, + "uid": "242giivkgr3e6le7b2xqi2pkdruf85mu", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 62920 + }, + { + "css": "chat", + "code": 59168, + "uid": "7idv5s1f3qkgmbwbat6xukumwqxkrook", + "search": [ + "chat", + "talk" + ], + "charRef": 62921 + }, + { + "css": "print", + "code": 59158, + "uid": "7ssl5z5jrhu13tb13cd3gb4bdfkzbfzw", + "search": [ + "print" + ], + "charRef": 62922 + }, + { + "css": "bell", + "code": 128276, + "uid": "uaps3vfayj05q7h4rvb10m890xvaequb", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 62923 + }, + { + "css": "attention", + "code": 9888, + "uid": "f47srtt9pew19q6kg9jniwtzsb8q1rhy", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 62924 + }, + { + "css": "info", + "code": 61, + "uid": "a66a6e088038a1881d532b6675bf8412", + "search": [ + "info" + ], + "charRef": 62925 + }, + { + "css": "question", + "code": 63, + "uid": "23d1c53bc15ca452df9453450e94a19c", + "search": [ + "question", + "help" + ], + "charRef": 62926 + }, + { + "css": "location", + "code": 59172, + "uid": "too2rspp5e6z6m0y6lconmv23uw3qlqo", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 62927 + }, + { + "css": "trash", + "code": 59177, + "uid": "z18zsyvbrpsea0f49kd61kkue1ofsafy", + "search": [ + "trash", + "delete" + ], + "charRef": 62928 + }, + { + "css": "doc", + "code": 128196, + "uid": "t7uz7sms69yuckjmkp1zqggwr4jkw0o9", + "search": [ + "doc", + "article" + ], + "charRef": 62929 + }, + { + "css": "article", + "code": 59188, + "uid": "573lc53801tfc96xt7fubn59tb0o5s4y", + "search": [ + "document", + "article" + ], + "charRef": 62930 + }, + { + "css": "article-alt", + "code": 59189, + "uid": "pzy4lq1ak4datbxpdfj3ya74vjfhwxg1", + "search": [ + "document", + "article" + ], + "charRef": 62931 + }, + { + "css": "rss", + "code": 59194, + "uid": "33iuue66u2628uv4kz3vnmh8uee8o7rw", + "search": [ + "rss" + ], + "charRef": 62932 + }, + { + "css": "wrench", + "code": 128295, + "uid": "zc0c8s0nyweeeo9i8a3rucu7alwxt56r", + "search": [ + "settings", + "wrench" + ], + "charRef": 62933 + }, + { + "css": "basket", + "code": 59197, + "uid": "vqyhv5kmwcj9zxq28dhq5npykr2k39co", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 62934 + }, + { + "css": "basket-alt", + "code": 59310, + "uid": "s51at1xi1fkaomxvp6dqaax5jmyhtn4h", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 62935 + }, + { + "css": "calendar", + "code": 128197, + "uid": "3v94fy782j1ddju9fbafpqa1x0li3bt6", + "search": [ + "calendar", + "date" + ], + "charRef": 62936 + }, + { + "css": "calendar-alt", + "code": 59198, + "uid": "sz7wtylc6qrwcbsj8aowal9y22hu6lka", + "search": [ + "calendar", + "date" + ], + "charRef": 62937 + }, + { + "css": "volume-off", + "code": 128263, + "uid": "8pcqxtjxtvkqo3dgemy49z7fw1d8xsh9", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 62938 + }, + { + "css": "volume-down", + "code": 128265, + "uid": "ivjrs8ijaooc3a2dw4790kb2rx4l6kjh", + "search": [ + "volume", + "sound" + ], + "charRef": 62939 + }, + { + "css": "volume-up", + "code": 128266, + "uid": "rrb2e7qiu68cw7itzq0wzm2hugw1u4lu", + "search": [ + "volume", + "sound" + ], + "charRef": 62940 + }, + { + "css": "bullhorn", + "code": 128227, + "uid": "uetwmlvm6z9eaot1t74vvsgrte9vwi0n", + "search": [ + "bullhorn", + "loudspeaker" + ], + "charRef": 62941 + }, + { + "css": "clock", + "code": 128340, + "uid": "0ohst63cgq1mf1syayvfl8mphms8dbes", + "search": [ + "clock", + "time" + ], + "charRef": 62942 + }, + { + "css": "clock-alt", + "code": 128339, + "uid": "9avusbdkm7q4vcmevr0x88zxewys65wr", + "search": [ + "clock", + "time" + ], + "charRef": 62943 + }, + { + "css": "stop", + "code": 59315, + "uid": "ip65j4to6y8pionwfd8h22mbl6kp1xya", + "search": [ + "stop", + "block", + "cancel" + ], + "charRef": 62944 + }, + { + "css": "resize-full", + "code": 59204, + "uid": "dsfybb9l0x5fyd7e3o5kyisqppifztfu", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 62945 + }, + { + "css": "resize-small", + "code": 59206, + "uid": "qdhvqjd167ee2byleebhw58j4omhb8pl", + "search": [ + "resize" + ], + "charRef": 62946 + }, + { + "css": "zoom-in", + "code": 59216, + "uid": "yc4vm9xepijcjyfdp6mgkvju8engb212", + "search": [ + "zoom. scale", + "in" + ], + "charRef": 62947 + }, + { + "css": "zoom-out", + "code": 59217, + "uid": "itjusjx5w85jr0udgi40mz7x2kmj1360", + "search": [ + "zoom. scale", + "out" + ], + "charRef": 62948 + }, + { + "css": "popup", + "code": 59212, + "uid": "b2i5x0ka1m6pskm3puj9jppl672knd5c", + "search": [ + "popup", + "window" + ], + "charRef": 62949 + }, + { + "css": "down-dir", + "code": 9662, + "uid": "8ax1xqcbzz1hobyd4i7f0unwib1bztip", + "search": [ + "arrow", + "down" + ], + "charRef": 62950 + }, + { + "css": "left-dir", + "code": 9666, + "uid": "am79573ydakwiicuct1odx7f2e9zv8lv", + "search": [ + "arrow", + "left" + ], + "charRef": 62951 + }, + { + "css": "right-dir", + "code": 9656, + "uid": "gypcofts1tkouwkxbv8d33eanqpreyy9", + "search": [ + "arrow", + "right" + ], + "charRef": 62952 + }, + { + "css": "up-dir", + "code": 9652, + "uid": "6ipws8y9gej6vbloufvhi5qux7rluf64", + "search": [ + "arrow", + "up" + ], + "charRef": 62953 + }, + { + "css": "down", + "code": 8595, + "uid": "3iwbntpxmp0kvbvzaxrh8h30xw1l6zvn", + "search": [ + "arrow", + "down" + ], + "charRef": 62954 + }, + { + "css": "up", + "code": 8593, + "uid": "giaskl13npzvuuz2ovy3vw8s0bewik08", + "search": [ + "arrow", + "up" + ], + "charRef": 62955 + }, + { + "css": "cw", + "code": 10227, + "uid": "v4mhug5rzlh2qzlo09kfx03e6e2alqql", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 62956 + }, + { + "css": "signal", + "code": 59248, + "uid": "e6t4yvmv401e9gpo2anslq4uqy2iz692", + "search": [ + "broadcast", + "wifi", + "signal" + ], + "charRef": 62957 + }, + { + "css": "award", + "code": 127945, + "uid": "lnyme20kl7kh26it9yrqk7at10k6i0sf", + "search": [ + "top", + "trophy", + "prize", + "award" + ], + "charRef": 62958 + }, + { + "css": "mobile", + "code": 128241, + "uid": "m3m8301t2xdy30x4lp7txm0vztl67tcl", + "search": [ + "mobile", + "iphone" + ], + "charRef": 62959 + }, + { + "css": "mobile-alt", + "code": 59312, + "uid": "raxalm7kdj5at9v49bevw6r2cw7fdv9r", + "search": [ + "mobile", + "iphone" + ], + "charRef": 62960 + }, + { + "css": "tablet", + "code": 59313, + "uid": "r36ey62e6pi493s139u528739kjr3o8w", + "search": [ + "tablet" + ], + "charRef": 62961 + }, + { + "css": "ipod", + "code": 59314, + "uid": "hx5rpl1lxy10jqibjq0jmu0dhruapso4", + "search": [ + "player", + "ipod" + ], + "charRef": 62962 + }, + { + "css": "cd", + "code": 128191, + "uid": "80fm9zvbe9habbzvsy6w4aymkgz2vu9i", + "search": [ + "cd", + "vinyl" + ], + "charRef": 62963 + }, + { + "css": "grid", + "code": 59316, + "uid": "o1c30odwfvgcvi5b4jsg95sur8v6ghsp", + "search": [ + "grid", + "table" + ], + "charRef": 62964 + }, + { + "css": "book", + "code": 128213, + "uid": "dplw5xo88mzzr7b45nvjcamyyhni6drs", + "search": [ + "book" + ], + "charRef": 62965 + }, + { + "css": "easel", + "code": 59317, + "uid": "px45pk7jgwms9zb3zcm44h8al4f3xxkd", + "search": [ + "easel", + "stand" + ], + "charRef": 62966 + }, + { + "css": "globe", + "code": 127760, + "uid": "i6ej1r6t84xouh0dct7g9zyx3ya9s9eg", + "search": [ + "globe" + ], + "charRef": 62967 + }, + { + "css": "chart", + "code": 128200, + "uid": "97ylvmgyj79w96iwzdanwmf5o4cvo17w", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62968 + }, + { + "css": "chart-bar", + "code": 128202, + "uid": "ogmm8kz4f7y6ji50gzajnwed8h6ck2u7", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 62969 + }, + { + "css": "chart-pie", + "code": 59298, + "uid": "crns7fze53tnmwvi0wyfhq8whxfmmroz", + "search": [ + "chart", + "pie", + "diagram" + ], + "charRef": 62970 + }, + { + "css": "dollar", + "code": 128181, + "uid": "fhpup8jff2yw9kmuwavhyqxogczcbbhj", + "search": [ + "money", + "dollar" + ], + "charRef": 62971 + }, + { + "css": "at", + "code": 64, + "uid": "mjbsqg8yglgu0esc6ru2vh111jmh7qng", + "search": [ + "@", + "at" + ], + "charRef": 62972 + }, + { + "css": "colon", + "code": 58, + "uid": "2qh229aneb95ds2afi7dbdsxz9jrbhcl", + "search": [ + "colon" + ], + "charRef": 62973 + }, + { + "css": "semicolon", + "code": 59, + "uid": "snfl88dncpfb384hoi4rv4vqm08h8at8", + "search": [ + "semicolon" + ], + "charRef": 62974 + }, + { + "css": "squares", + "code": 10697, + "uid": "a58a5236139282f6c7f906634233157a", + "search": [ + "squares" + ], + "charRef": 62975 + }, + { + "css": "money", + "code": 36, + "uid": "212ab54aac31030950fec3e2448ebee9", + "search": [ + "money", + "dollar" + ], + "charRef": 62976 + }, + { + "css": "facebook", + "code": 62208, + "uid": "w42gjpwdzqeszptpy1xqp8r77o6gcasj", + "search": [ + "facebook" + ], + "charRef": 62977 + }, + { + "css": "facebook-rect", + "code": 62209, + "uid": "03cmb4p7niofd11yos3fpjjuvvpy7mji", + "search": [ + "facebook" + ], + "charRef": 62978 + }, + { + "css": "twitter", + "code": 62210, + "uid": "uor1aru5x0tewrwsl36amx6hogjv61cs", + "search": [ + "twitter" + ], + "charRef": 62979 + }, + { + "css": "twitter-bird", + "code": 62211, + "uid": "h7disbowd4v177zjlsi6anz5nkka08uy", + "search": [ + "twitter" + ], + "charRef": 62980 + }, + { + "css": "twitter-rect", + "code": 62228, + "uid": "gq8m9lqx2hhwxf7rz30adbr37rthzirq", + "search": [ + "twitter" + ], + "charRef": 62981 + }, + { + "css": "youtube", + "code": 62229, + "uid": "897cd776b90c71cb80b467fd9f509775", + "search": [ + "twitter" + ], + "charRef": 62982 + } + ], + "font": { + "fontname": "modernpics", + "fullname": "Modern Pictograms", + "familyname": "Modern Pictograms", + "copyright": "Copyright (c) 2012 by John Caserta. All rights reserved.", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "John Caserta", + "homepage": "http://thedesignoffice.org/project/modern-pictograms/", + "email": "info@johncaserta.com", + "twitter": "https://twitter.com/johncaserta", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "windy-rain-inv", + "code": 33, + "uid": "b69ac48f8ad98e786047ff3d33101045", + "search": [ + "windy", + "rain", + "weather" + ], + "charRef": 62983 + }, + { + "css": "snow-inv", + "code": 34, + "uid": "87cf185e0420ff98e04406c0fbb873eb", + "search": [ + "snow", + "weather" + ], + "charRef": 62984 + }, + { + "css": "snow-heavy-inv", + "code": 35, + "uid": "f1315f7ea135cbea7966cce0e7c10ce0", + "search": [ + "snow", + "weather" + ], + "charRef": 62985 + }, + { + "css": "hail-inv", + "code": 36, + "uid": "ab5c31256cdd1f6b2d6de7202936f5a1", + "search": [ + "hail", + "weather" + ], + "charRef": 62986 + }, + { + "css": "clouds-inv", + "code": 37, + "uid": "8f1bbb4667a8372dc4bb7de767f22f11", + "search": [ + "clouds", + "weather" + ], + "charRef": 62987 + }, + { + "css": "clouds-flash-inv", + "code": 38, + "uid": "b2b73369982f91cddf8ec5f2a692e5ea", + "search": [ + "clouds", + "flash", + "weather" + ], + "charRef": 62988 + }, + { + "css": "temperature", + "code": 39, + "uid": "906a8ebb0faf8db0411028a0364bb16d", + "search": [ + "temperature", + "weather" + ], + "charRef": 62989 + }, + { + "css": "compass", + "code": 40, + "uid": "a6a5b2ea227f86157ba54ae543785161", + "search": [ + "compass", + "weather" + ], + "charRef": 62990 + }, + { + "css": "na", + "code": 41, + "uid": "053a1eaf96184e74876f45bd0f4970eb", + "search": [ + "not available", + "weather" + ], + "charRef": 62991 + }, + { + "css": "celcius", + "code": 42, + "uid": "39a24b1eb625a4a551585745107e8ef0", + "search": [ + "celcius" + ], + "charRef": 62992 + }, + { + "css": "fahrenheit", + "code": 43, + "uid": "5478f7c5cc0ad4897835f711eccea4dd", + "search": [ + "fahrenheit", + "weather" + ], + "charRef": 62993 + }, + { + "css": "clouds-flash-alt", + "code": 48, + "uid": "d05dd160c24e53afc4addd30b5655b74", + "search": [ + "clouds", + "flash", + "weather" + ], + "charRef": 62994 + }, + { + "css": "sun-inv", + "code": 49, + "uid": "c1306ee779029bed4f5a2b9b4f5c79e8", + "search": [ + "sun", + "weather" + ], + "charRef": 62995 + }, + { + "css": "moon-inv", + "code": 50, + "uid": "2adfda136b09532bd8174b025b67fe87", + "search": [ + "moon", + "weather" + ], + "charRef": 62996 + }, + { + "css": "cloud-sun-inv", + "code": 51, + "uid": "2c304ff49075ec9647f498504651abf5", + "search": [ + "cloud", + "sun", + "weather" + ], + "charRef": 62997 + }, + { + "css": "cloud-moon-inv", + "code": 52, + "uid": "c823149b79158a2bd56d802a6a6f1d1c", + "search": [ + "cloud", + "moon", + "weather" + ], + "charRef": 62998 + }, + { + "css": "cloud-inv", + "code": 53, + "uid": "7162ef3c04c51e39b8670cfedb15bcc3", + "search": [ + "cloud", + "weather" + ], + "charRef": 62999 + }, + { + "css": "cloud-flash-inv", + "code": 54, + "uid": "4bc859f73783486400fc769a90d0a8e0", + "search": [ + "cloud", + "flash", + "weather" + ], + "charRef": 63000 + }, + { + "css": "drizzle-inv", + "code": 55, + "uid": "92234661a134ed625a779c534b242b3d", + "search": [ + "rain", + "drizzle", + "weather" + ], + "charRef": 63001 + }, + { + "css": "rain-inv", + "code": 56, + "uid": "8d8a2d9bcc41c7ac794e83ffbb919c3c", + "search": [ + "rain", + "drizzle", + "weather" + ], + "charRef": 63002 + }, + { + "css": "windy-inv", + "code": 57, + "uid": "be6c21cbc48e60a39e80f8b2c33e360e", + "search": [ + "windy", + "weather" + ], + "charRef": 63003 + }, + { + "css": "sunrise", + "code": 65, + "uid": "1c2a34e8bd2f8a53e3b059447a8e544f", + "search": [ + "sun", + "sunrise", + "weather" + ], + "charRef": 63004 + }, + { + "css": "sun", + "code": 66, + "uid": "95fb2e5fdd1ea7e4a420b6ed330e6b08", + "search": [ + "sun", + "weather" + ], + "charRef": 63005 + }, + { + "css": "moon", + "code": 67, + "uid": "34e68aa8fbf61f02a748043ccf448a3b", + "search": [ + "moon", + "weather" + ], + "charRef": 63006 + }, + { + "css": "eclipse", + "code": 68, + "uid": "48ab39ab0ba664052cfbf0e52563246a", + "search": [ + "eclipse", + "weather" + ], + "charRef": 63007 + }, + { + "css": "mist", + "code": 69, + "uid": "a555120b3743d482efcc3058733d3fd9", + "search": [ + "mist", + "fog", + "weather" + ], + "charRef": 63008 + }, + { + "css": "wind", + "code": 70, + "uid": "2efb5347832a09ae69de043f897ec4b9", + "search": [ + "wind", + "weather" + ], + "charRef": 63009 + }, + { + "css": "snowflake", + "code": 71, + "uid": "d0c325468a74095e565664bec2623aa3", + "search": [ + "snowflake", + "weather" + ], + "charRef": 63010 + }, + { + "css": "cloud-sun", + "code": 72, + "uid": "9cd3e294ca3ad3dda66bc5a804021c46", + "search": [ + "cloud", + "sun", + "weather" + ], + "charRef": 63011 + }, + { + "css": "cloud-moon", + "code": 73, + "uid": "2440f961b415837c6bf30424a6711708", + "search": [ + "cloud", + "moon", + "weather" + ], + "charRef": 63012 + }, + { + "css": "fog-sun", + "code": 74, + "uid": "957fd72e52a0e9eb585a0361114c4c83", + "search": [ + "fog", + "sun", + "weather" + ], + "charRef": 63013 + }, + { + "css": "fog-moon", + "code": 75, + "uid": "dbf0f9c3d15e5e8046bb5f5fb5898b49", + "search": [ + "fog", + "moon", + "weather" + ], + "charRef": 63014 + }, + { + "css": "fog-cloud", + "code": 76, + "uid": "aba39b610b88a73d81f0fa683649b92d", + "search": [ + "fog", + "cloud", + "weather" + ], + "charRef": 63015 + }, + { + "css": "fog", + "code": 77, + "uid": "2ca5a006e414e0827f7fc5b187689c04", + "search": [ + "fog", + "weather" + ], + "charRef": 63016 + }, + { + "css": "cloud", + "code": 78, + "uid": "17463471d0f132cee16835507ea51ecf", + "search": [ + "cloud", + "weather" + ], + "charRef": 63017 + }, + { + "css": "cloud-flash", + "code": 79, + "uid": "cc1179bd34dcbe7bf80785075af60d37", + "search": [ + "cloud", + "flash", + "weather" + ], + "charRef": 63018 + }, + { + "css": "cloud-flash-alt", + "code": 80, + "uid": "9af2b75a89bd99b83457f041df26da8b", + "search": [ + "cloud", + "flash", + "weather" + ], + "charRef": 63019 + }, + { + "css": "drizzle", + "code": 81, + "uid": "f59875f40cbc5ad1b04775cd96feabf1", + "search": [ + "rain", + "drizzle", + "weather" + ], + "charRef": 63020 + }, + { + "css": "rain", + "code": 82, + "uid": "d577552bb94bdeb53e6517873481aeea", + "search": [ + "rain", + "drizzle", + "weather" + ], + "charRef": 63021 + }, + { + "css": "windy", + "code": 83, + "uid": "5fad7d41511701337ddd5ad9896edc4b", + "search": [ + "windy", + "weather" + ], + "charRef": 63022 + }, + { + "css": "windy-rain", + "code": 84, + "uid": "86351391d6cbc7a85730414294139661", + "search": [ + "windy", + "rain", + "weather" + ], + "charRef": 63023 + }, + { + "css": "snow", + "code": 85, + "uid": "127ed05f3c024a9c73487f18cf3d530d", + "search": [ + "snow", + "weather" + ], + "charRef": 63024 + }, + { + "css": "snow-alt", + "code": 86, + "uid": "02bb2eaa1515b8fc954abbaf80212739", + "search": [ + "snow", + "weather" + ], + "charRef": 63025 + }, + { + "css": "snow-heavy", + "code": 87, + "uid": "0f6059e468716a93329821bcbf11220d", + "search": [ + "snow", + "weather" + ], + "charRef": 63026 + }, + { + "css": "hail", + "code": 88, + "uid": "b500010a53f4807828ac252725dc6fd1", + "search": [ + "hail", + "weather" + ], + "charRef": 63027 + }, + { + "css": "clouds", + "code": 89, + "uid": "b215adc51ca2aa37e7bbe244d1fa52cc", + "search": [ + "clouds", + "weather" + ], + "charRef": 63028 + }, + { + "css": "clouds-flash", + "code": 90, + "uid": "f4c428e42b86673278e98e6f2e0a8cd2", + "search": [ + "clouds", + "flash", + "weather" + ], + "charRef": 63029 + } + ], + "font": { + "fontname": "meteocons", + "fullname": "Meteocons", + "familyname": "Meteocons", + "copyright": "Copyright (C) 2012 by Alessio Atzeni", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "Alessio Atzeni", + "homepage": "http://www.alessioatzeni.com", + "email": "info@alessioatzeni.com", + "twitter": "http://twitter.com/bluxart", + "dribbble": "http://dribbble.com/Bluxart", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "search", + "code": 62733, + "uid": "ec21fe3492bb04d9e29103c319556ed8", + "search": [ + "search", + "find", + "magnify" + ], + "charRef": 63030 + }, + { + "css": "mail", + "code": 9993, + "uid": "a17986e457f3d85f26c9c240dfd6a4ba", + "search": [ + "mail", + "email" + ], + "charRef": 63031 + }, + { + "css": "heart", + "code": 9829, + "uid": "d02a803276d9e1f42b7393964aa22ce9", + "search": [ + "heart", + "like" + ], + "charRef": 63032 + }, + { + "css": "heart-broken", + "code": 61480, + "uid": "862129f833b09f3d34ae39acf8484a7b", + "search": [ + "heart", + "dislike" + ], + "charRef": 63033 + }, + { + "css": "star", + "code": 9733, + "uid": "b392c847bf41826598f12c02be842253", + "search": [ + "star" + ], + "charRef": 63034 + }, + { + "css": "star-empty", + "code": 9734, + "uid": "ee382df412dfdf65191b52ae33160abc", + "search": [ + "star" + ], + "charRef": 63035 + }, + { + "css": "star-half", + "code": 61474, + "uid": "3fba70399d61e886bce68721edbc71af", + "search": [ + "star" + ], + "charRef": 63036 + }, + { + "css": "star-half_empty", + "code": 61476, + "uid": "689ef8cee6655c255ffdddf5e3188165", + "search": [ + "star" + ], + "charRef": 63037 + }, + { + "css": "user", + "code": 61537, + "uid": "11d74f891bce30f1bdf73d3259d59ed5", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 63038 + }, + { + "css": "user-male", + "code": 61538, + "uid": "e5fdc4247f1f9b3bf98d20a954e1327c", + "search": [ + "user", + "male" + ], + "charRef": 63039 + }, + { + "css": "user-female", + "code": 61539, + "uid": "a6c0e3fce2fbe9ccf9b1c54c8f399106", + "search": [ + "user", + "female" + ], + "charRef": 63040 + }, + { + "css": "users", + "code": 61540, + "uid": "05ef9b5e8742971aa85b23cfcbe71594", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 63041 + }, + { + "css": "movie", + "code": 61504, + "uid": "eea613bc40c77b7eab137b29dba0c62f", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 63042 + }, + { + "css": "videocam", + "code": 61498, + "uid": "40c6538b0fd40540bf78373f8a1fb7af", + "search": [ + "facetime", + "movie", + "video", + "film" + ], + "charRef": 63043 + }, + { + "css": "isight", + "code": 61497, + "uid": "e2df3c577fceec26906169fbee71721e", + "search": [ + "isight", + "video", + "camera" + ], + "charRef": 63044 + }, + { + "css": "camera", + "code": 62711, + "uid": "41c01fe7bfa79a93a2a2971a7f347fc0", + "search": [ + "camera", + "photo" + ], + "charRef": 63045 + }, + { + "css": "menu", + "code": 61448, + "uid": "c55fdf978f617992b43ee7cbaa6ef87e", + "search": [ + "reorder", + "menu" + ], + "charRef": 63046 + }, + { + "css": "th-thumb", + "code": 61450, + "uid": "2b6bf06e87a223ccd1ddc1874932ca86", + "search": [ + "reorder", + "image", + "list", + "thumbnails" + ], + "charRef": 63047 + }, + { + "css": "th-thumb-empty", + "code": 61451, + "uid": "5eb43711f62fb4dcbef10d0224c28065", + "search": [ + "reorder", + "image", + "list", + "thumbnails" + ], + "charRef": 63048 + }, + { + "css": "th-list", + "code": 61449, + "uid": "1b58555745e7378f7634ee7c63eada46", + "search": [ + "reorder", + "image", + "list", + "thumbnails" + ], + "charRef": 63049 + }, + { + "css": "ok", + "code": 10003, + "uid": "ce50292e85eb5d6ee3be61b32bf2bdf3", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63050 + }, + { + "css": "ok-circled", + "code": 61549, + "uid": "5e1ef647438e2204c15197c6efc4151e", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63051 + }, + { + "css": "cancel", + "code": 10060, + "uid": "06301c50d89b5d3e651bd07ebd6d7de7", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 63052 + }, + { + "css": "cancel-circled", + "code": 61550, + "uid": "44eb9d69bf3b9b74629ce6852a2f9681", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 63053 + }, + { + "css": "plus", + "code": 43, + "uid": "63e91725cfc5751fe4d772325fd50830", + "search": [ + "plus" + ], + "charRef": 63054 + }, + { + "css": "help-circled", + "code": 10067, + "uid": "a3d734a5b4bec33fc3aa459d82092b23", + "search": [ + "help", + "question" + ], + "charRef": 63055 + }, + { + "css": "help-circled-alt", + "code": 10068, + "uid": "3e02a8849305ac80a0e36302f461f265", + "search": [ + "help", + "question" + ], + "charRef": 63056 + }, + { + "css": "info-circled", + "code": 61573, + "uid": "8f25d96c5665c84e4403538eef14ec2c", + "search": [ + "info" + ], + "charRef": 63057 + }, + { + "css": "info-circled-alt", + "code": 61574, + "uid": "15ba51cbb4d05e6fb88f03a31a7c711c", + "search": [ + "info" + ], + "charRef": 63058 + }, + { + "css": "home", + "code": 8962, + "uid": "018571e697f22ca41803de480e10ed10", + "search": [ + "home" + ], + "charRef": 63059 + }, + { + "css": "link", + "code": 61563, + "uid": "1fb8776fe6f1d3bbf970996fdfcf0f94", + "search": [ + "link" + ], + "charRef": 63060 + }, + { + "css": "attach", + "code": 61546, + "uid": "9746a4ace95e1797c94cd2fe05c22485", + "search": [ + "attach", + "clip" + ], + "charRef": 63061 + }, + { + "css": "lock", + "code": 62738, + "uid": "7997220c4eb58edae98e04de570089c2", + "search": [ + "lock" + ], + "charRef": 63062 + }, + { + "css": "lock-alt", + "code": 62736, + "uid": "b10e25220faa78c808527a4ba8b5c0f9", + "search": [ + "lock" + ], + "charRef": 63063 + }, + { + "css": "lock-open", + "code": 62739, + "uid": "e67bcab050d99eb04d44027139ae05f5", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 63064 + }, + { + "css": "lock-open-alt", + "code": 61557, + "uid": "8167f6441d2557a90d717a7fc3248760", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 63065 + }, + { + "css": "eye", + "code": 61570, + "uid": "518ed8d836b8f75393d6d239291fedb0", + "search": [ + "eye", + "subscribe" + ], + "charRef": 63066 + }, + { + "css": "download", + "code": 61486, + "uid": "348b04ea17f646fbc6a46e20ebe4fe12", + "search": [ + "download" + ], + "charRef": 63067 + }, + { + "css": "upload", + "code": 61487, + "uid": "4f3b31017c63ba04dc4f78ce7a8f02b1", + "search": [ + "upload" + ], + "charRef": 63068 + }, + { + "css": "download-cloud", + "code": 61461, + "uid": "74ba7c7ac7610225ab8655f50ad179b6", + "search": [ + "download", + "cloud" + ], + "charRef": 63069 + }, + { + "css": "upload-cloud", + "code": 61460, + "uid": "cb0d73e6d41217d85fc81cea45dd6e91", + "search": [ + "upload", + "cloud" + ], + "charRef": 63070 + }, + { + "css": "reply", + "code": 61482, + "uid": "00e1f929aa3c591e05de52eb94eda625", + "search": [ + "reply" + ], + "charRef": 63071 + }, + { + "css": "pencil", + "code": 9999, + "uid": "0299bec28699eedda42f46c77239393e", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63072 + }, + { + "css": "export", + "code": 61569, + "uid": "d4824d88566b0ac66d2cdcff3408690b", + "search": [ + "export", + "share" + ], + "charRef": 63073 + }, + { + "css": "print", + "code": 61575, + "uid": "60e11e35624b5012017eb10d2d7bd060", + "search": [ + "print" + ], + "charRef": 63074 + }, + { + "css": "retweet", + "code": 61483, + "uid": "26abd5de5952c46cf3a31f70330241a0", + "search": [ + "retweet", + "twitter" + ], + "charRef": 63075 + }, + { + "css": "comment", + "code": 62636, + "uid": "51fb22f9ff9d7f60c95ef31e4c59502d", + "search": [ + "comment", + "reply", + "write", + "message" + ], + "charRef": 63076 + }, + { + "css": "chat", + "code": 61501, + "uid": "a8ed7903f8f548da5a8084e1773f0bbb", + "search": [ + "chat", + "talk", + "discussion" + ], + "charRef": 63077 + }, + { + "css": "bell", + "code": 61503, + "uid": "ebb8fb741e0b3e794c90555e5f225adf", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 63078 + }, + { + "css": "attention", + "code": 10071, + "uid": "189edfc41118cccbeb25788fcbb403da", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 63079 + }, + { + "css": "attention-alt", + "code": 10069, + "uid": "55389e7d75fe0458efcb909f78e7ad3f", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 63080 + }, + { + "css": "location", + "code": 61489, + "uid": "291e2e127efe7a6bc580af6d3ead3771", + "search": [ + "location", + "mark", + "marker", + "pin" + ], + "charRef": 63081 + }, + { + "css": "trash", + "code": 61571, + "uid": "a6267a0b7262e1deffcc83076bc0e197", + "search": [ + "trash", + "delete" + ], + "charRef": 63082 + }, + { + "css": "doc", + "code": 61514, + "uid": "7141927f949e757c7e218cf70d9dceb4", + "search": [ + "doc", + "article", + "sheet" + ], + "charRef": 63083 + }, + { + "css": "newspaper", + "code": 62704, + "uid": "18be7ed7a4baf5713f2de51bf83b12f2", + "search": [ + "newspaper", + "article" + ], + "charRef": 63084 + }, + { + "css": "folder", + "code": 61543, + "uid": "c619e17229d6c874dfc70be359b6b3f1", + "search": [ + "folder" + ], + "charRef": 63085 + }, + { + "css": "folder-open", + "code": 61544, + "uid": "8e6b311d40f1002fd6de7d1bdfdc7f17", + "search": [ + "folder" + ], + "charRef": 63086 + }, + { + "css": "folder-empty", + "code": 61545, + "uid": "4c4bb0011585456def6562bf27186b63", + "search": [ + "folder" + ], + "charRef": 63087 + }, + { + "css": "folder-open-empty", + "code": 62658, + "uid": "8f28e6daf83e5c4f1fec8d170a7e21e7", + "search": [ + "folder" + ], + "charRef": 63088 + }, + { + "css": "cog", + "code": 39041, + "uid": "7336247ba3db350dec8d6c0a47cef966", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 63089 + }, + { + "css": "calendar", + "code": 62661, + "uid": "4615d277156195624f442e69958ea863", + "search": [ + "calendar", + "date" + ], + "charRef": 63090 + }, + { + "css": "login", + "code": 61484, + "uid": "5adef5b3275fcd874b0815a0637c5800", + "search": [ + "login", + "signin", + "enter" + ], + "charRef": 63091 + }, + { + "css": "logout", + "code": 61485, + "uid": "a6b6f85116fc55e4a7c83d66973035a7", + "search": [ + "logout", + "signout", + "exit" + ], + "charRef": 63092 + }, + { + "css": "mic", + "code": 61512, + "uid": "858e967d1c67608546add6beebade5b3", + "search": [ + "mic" + ], + "charRef": 63093 + }, + { + "css": "mic-off", + "code": 61511, + "uid": "5dc427ad9f0644447ca5292911c378f1", + "search": [ + "mic", + "mute" + ], + "charRef": 63094 + }, + { + "css": "clock", + "code": 9202, + "uid": "981c9f3d44fd4fd6b37c0b5a981334ce", + "search": [ + "clock", + "time" + ], + "charRef": 63095 + }, + { + "css": "stopwatch", + "code": 9201, + "uid": "53c977df16b09e3f7700a27ec90c43dc", + "search": [ + "stopwatch", + "timer" + ], + "charRef": 63096 + }, + { + "css": "hourglass", + "code": 8987, + "uid": "35ce53990ec0892d7dcea2d0159f8dca", + "search": [ + "clock", + "hourglass", + "busy", + "wait" + ], + "charRef": 63097 + }, + { + "css": "zoom-in", + "code": 61566, + "uid": "baaebda77cf391a9d9ecdec4db11dcb7", + "search": [ + "zoom", + "magnify", + "scale", + "in" + ], + "charRef": 63098 + }, + { + "css": "zoom-out", + "code": 61567, + "uid": "3a9c5809bfc7b653c3b165b979f5d93e", + "search": [ + "zoom", + "magnify", + "scale", + "out" + ], + "charRef": 63099 + }, + { + "css": "down-open", + "code": 61444, + "uid": "d9be617b7f2fe7843118ca2d3a1b8cca", + "search": [ + "arrow", + "down" + ], + "charRef": 63100 + }, + { + "css": "left-open", + "code": 61447, + "uid": "b714be5a812a474811604f700dfc87ce", + "search": [ + "arrow", + "left" + ], + "charRef": 63101 + }, + { + "css": "right-open", + "code": 61446, + "uid": "37910a1398001a5ccb541cb2a253a2c7", + "search": [ + "arrow", + "right" + ], + "charRef": 63102 + }, + { + "css": "up-open", + "code": 61445, + "uid": "440e148d0e21100118eae7036bcd2067", + "search": [ + "arrow", + "up" + ], + "charRef": 63103 + }, + { + "css": "down", + "code": 8595, + "uid": "3838a5aba604532d2dbae5904615ea39", + "search": [ + "arrow", + "down" + ], + "charRef": 63104 + }, + { + "css": "left", + "code": 8592, + "uid": "c21d309f797d3644dc8d28c4617738ce", + "search": [ + "arrow", + "left" + ], + "charRef": 63105 + }, + { + "css": "right", + "code": 8594, + "uid": "1d35198f5190ec004dd4ec742fbe19ca", + "search": [ + "arrow", + "right" + ], + "charRef": 63106 + }, + { + "css": "up", + "code": 8593, + "uid": "040e72500c863813088c9f9c9415f8e9", + "search": [ + "arrow", + "up" + ], + "charRef": 63107 + }, + { + "css": "down-bold", + "code": 8659, + "uid": "bd6176c7f1bd64eec8904241316f2f52", + "search": [ + "arrow", + "down" + ], + "charRef": 63108 + }, + { + "css": "left-bold", + "code": 8656, + "uid": "413160f2a26366d3c1d544bf1221a6ca", + "search": [ + "arrow", + "left" + ], + "charRef": 63109 + }, + { + "css": "right-bold", + "code": 8658, + "uid": "e26b9d4bdcd0b60ed2cafa8f41ffc6d2", + "search": [ + "arrow", + "right" + ], + "charRef": 63110 + }, + { + "css": "up-bold", + "code": 8657, + "uid": "985defa766987e1e038c807527100b15", + "search": [ + "arrow", + "up" + ], + "charRef": 63111 + }, + { + "css": "down-fat", + "code": 8650, + "uid": "335c443d3231b944287309aa2593c880", + "search": [ + "arrow", + "down" + ], + "charRef": 63112 + }, + { + "css": "left-fat", + "code": 8647, + "uid": "fd2ed680ef900acb68836a99ec1a4de7", + "search": [ + "arrow", + "left" + ], + "charRef": 63113 + }, + { + "css": "right-fat", + "code": 8649, + "uid": "54c3330bdeed0fb9042e12d16d46c9ab", + "search": [ + "arrow", + "right" + ], + "charRef": 63114 + }, + { + "css": "up-fat", + "code": 8648, + "uid": "d21293ba68a7dcfec696464ae64949e1", + "search": [ + "arrow", + "up" + ], + "charRef": 63115 + }, + { + "css": "ccw", + "code": 61477, + "uid": "c74dc50bfc8aa68f0d23010ad8960cb2", + "search": [ + "reload", + "undo", + "arrow" + ], + "charRef": 63116 + }, + { + "css": "shuffle", + "code": 61499, + "uid": "9c3b8d8a6d477da4d3e65b92e4e9c290", + "search": [ + "shuffle", + "random" + ], + "charRef": 63117 + }, + { + "css": "play", + "code": 61455, + "uid": "3711151b8b34536498e2a7f4d5188ed2", + "search": [ + "play", + "player" + ], + "charRef": 63118 + }, + { + "css": "pause", + "code": 61454, + "uid": "164f35b55c3346b03fa89a711a4f3980", + "search": [ + "pause", + "player" + ], + "charRef": 63119 + }, + { + "css": "stop", + "code": 61568, + "uid": "0a38a63796b90318b5fca493c3d4a17a", + "search": [ + "stop", + "player" + ], + "charRef": 63120 + }, + { + "css": "to-end", + "code": 61456, + "uid": "dcda6b27f1f63fbd7b8bf8d45cc4d340", + "search": [ + "right", + "player" + ], + "charRef": 63121 + }, + { + "css": "to-start", + "code": 61457, + "uid": "75b228ebc26946ca00360ca10f052e3c", + "search": [ + "left", + "player" + ], + "charRef": 63122 + }, + { + "css": "fast-forward", + "code": 61458, + "uid": "59a3c018a7c1888658e4d93df8f7558f", + "search": [ + "right", + "player" + ], + "charRef": 63123 + }, + { + "css": "fast-backward", + "code": 61459, + "uid": "ee0b543733d75a60ff5647070dc1d4f8", + "search": [ + "left", + "player" + ], + "charRef": 63124 + }, + { + "css": "trophy", + "code": 61556, + "uid": "288c5a1dd34328f851587538998e4b3e", + "search": [], + "charRef": 63125 + }, + { + "css": "monitor", + "code": 61490, + "uid": "700cae9dc028202c4549471b56f516dd", + "search": [ + "tv", + "screen", + "monitor" + ], + "charRef": 63126 + }, + { + "css": "tablet", + "code": 61491, + "uid": "9693479d330d4e539cebdb8a7ce398f4", + "search": [ + "tablet" + ], + "charRef": 63127 + }, + { + "css": "mobile", + "code": 61492, + "uid": "31b90585534c8b455469d84a95f1959b", + "search": [ + "mobile", + "iphone", + "smartphone" + ], + "charRef": 63128 + }, + { + "css": "data-science", + "code": 61462, + "uid": "14c9e8bd3e747ecb08cae42f5564a671", + "search": [ + "data", + "network" + ], + "charRef": 63129 + }, + { + "css": "data-science-inv", + "code": 61463, + "uid": "a1bd477f92e956144558e6b6c671ed6e", + "search": [ + "data", + "network" + ], + "charRef": 63130 + }, + { + "css": "inbox", + "code": 61552, + "uid": "dcbef4ff6ce6ffc7599d23e0c2b029af", + "search": [ + "inbox" + ], + "charRef": 63131 + }, + { + "css": "globe", + "code": 61464, + "uid": "117d7f4e196f826847929c6550734615", + "search": [ + "globe" + ], + "charRef": 63132 + }, + { + "css": "globe-inv", + "code": 61465, + "uid": "77bf693b887ab9243826db6e682ea973", + "search": [ + "globe" + ], + "charRef": 63133 + }, + { + "css": "flash", + "code": 9889, + "uid": "77928c849ac2ae6e77d4eae9f2927c00", + "search": [ + "flash", + "bolt" + ], + "charRef": 63134 + }, + { + "css": "cloud", + "code": 9729, + "uid": "f08fd9b6b61b3670cf88ed64da891cae", + "search": [ + "cloud" + ], + "charRef": 63135 + }, + { + "css": "coverflow", + "code": 61452, + "uid": "d3fa106db96ff869d1ad75506ba5ff50", + "search": [ + "coverflow" + ], + "charRef": 63136 + }, + { + "css": "coverflow-empty", + "code": 61453, + "uid": "cf0523ff3f333523eb6e9f6642dd0ddc", + "search": [ + "coverflow" + ], + "charRef": 63137 + }, + { + "css": "math", + "code": 61466, + "uid": "c5fd68d8253e605e7a78a0c75255b692", + "search": [ + "math", + "sqrt" + ], + "charRef": 63138 + }, + { + "css": "math-circled", + "code": 61468, + "uid": "b74284571c2d4d0d251bd28dace4a1ba", + "search": [ + "math", + "sqrt" + ], + "charRef": 63139 + }, + { + "css": "math-circled-empty", + "code": 61467, + "uid": "ae734e5d304b9680558ab6b4449d55ee", + "search": [ + "math", + "sqrt" + ], + "charRef": 63140 + }, + { + "css": "paper-plane", + "code": 61469, + "uid": "cdb000f745167bbada14e2c1d8404d98", + "search": [ + "paper", + "plane", + "fly" + ], + "charRef": 63141 + }, + { + "css": "paper-plane-alt", + "code": 61471, + "uid": "b50bdfb03ec13c11ff72329eb70b3e2e", + "search": [ + "paper", + "plane", + "fly" + ], + "charRef": 63142 + }, + { + "css": "paper-plane-alt2", + "code": 61470, + "uid": "55035f2a3ae604a7c45a9e2e626aaef5", + "search": [ + "paper", + "plane", + "fly" + ], + "charRef": 63143 + }, + { + "css": "fontsize", + "code": 61576, + "uid": "3b6f20ef4c4940aeaed84d973b2f6e64", + "search": [ + "editor", + "font", + "size" + ], + "charRef": 63144 + }, + { + "css": "color-adjust", + "code": 61472, + "uid": "14e9aa28bf2a3531274f85194e733b71", + "search": [ + "color", + "balance" + ], + "charRef": 63145 + }, + { + "css": "fire", + "code": 62757, + "uid": "cc6a79edb1e82ee90129147ba089c323", + "search": [ + "fire" + ], + "charRef": 63146 + }, + { + "css": "chart-bar", + "code": 62758, + "uid": "c46c42ae95f46394bd2f9c9a9cc5f768", + "search": [ + "chart", + "bar", + "diagram" + ], + "charRef": 63147 + }, + { + "css": "hdd", + "code": 61572, + "uid": "f6650ca3f02625f4e1fcc9d4bd9b7b93", + "search": [ + "hdd", + "drive", + "disk" + ], + "charRef": 63148 + }, + { + "css": "connected-object", + "code": 61493, + "uid": "8dd9284cd4fa233d3972e48b417b3ca2", + "search": [], + "charRef": 63149 + }, + { + "css": "ruler", + "code": 61508, + "uid": "6a96c51e961a2e48dfcbe2c47fd1204e", + "search": [ + "ruler", + "measure" + ], + "charRef": 63150 + }, + { + "css": "vector", + "code": 61509, + "uid": "33afa0f624ce5dae73f62a3f21a67f83", + "search": [ + "vector" + ], + "charRef": 63151 + }, + { + "css": "vector-pencil", + "code": 10002, + "uid": "134af7f39e491515cc1a6d1eb94d9d8a", + "search": [ + "vector", + "pencil" + ], + "charRef": 63152 + }, + { + "css": "at", + "code": 64, + "uid": "874694a9126e8193bca844356d1b6328", + "search": [ + "at" + ], + "charRef": 63153 + }, + { + "css": "hash", + "code": 61481, + "uid": "da72ab64b02d997ff0521339f2997233", + "search": [ + "hash" + ], + "charRef": 63154 + }, + { + "css": "female", + "code": 9792, + "uid": "10b2be8b48bebc1974d6f94bac9de71d", + "search": [ + "person", + "human", + "female" + ], + "charRef": 63155 + }, + { + "css": "male", + "code": 9794, + "uid": "23c2239369a69f752e790de95123b9e9", + "search": [ + "person", + "human male" + ], + "charRef": 63156 + }, + { + "css": "spread", + "code": 62759, + "uid": "500cde26773d15aaac1bfaa2a33cc5a9", + "search": [ + "spread", + "join", + "flow", + "tree" + ], + "charRef": 63157 + }, + { + "css": "king", + "code": 9818, + "uid": "ee8014a23bf900eae0103c7699718bc7", + "search": [ + "king", + "chess" + ], + "charRef": 63158 + }, + { + "css": "anchor", + "code": 9875, + "uid": "dd432b7aa4b7c276a475015a93dec8a3", + "search": [ + "anchor" + ], + "charRef": 63159 + }, + { + "css": "joystick", + "code": 62740, + "uid": "d0df4d152daa276ccf31ac968c1dd103", + "search": [ + "joystick" + ], + "charRef": 63160 + }, + { + "css": "spinner1", + "code": 62760, + "uid": "fccd3ea0efb711b849045bee686b1ceb", + "search": [ + "spinner" + ], + "charRef": 63161 + }, + { + "css": "spinner2", + "code": 62761, + "uid": "9b0229b620364d8704940e408dde73fb", + "search": [ + "spinner" + ], + "charRef": 63162 + }, + { + "css": "github", + "code": 61525, + "uid": "9ea28ba01d59a4410fa3db9c02cce157", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 63163 + }, + { + "css": "github-circled", + "code": 61524, + "uid": "3261112d66c6462ea20893f42b6f799b", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 63164 + }, + { + "css": "github-circled-alt", + "code": 61523, + "uid": "3c2cfcbad5062929d63a249f3858e38b", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 63165 + }, + { + "css": "github-circled-alt2", + "code": 61526, + "uid": "8669af50382b53c48b9b803692828dd0", + "search": [ + "github", + "social", + "logo" + ], + "charRef": 63166 + }, + { + "css": "twitter", + "code": 61528, + "uid": "ec3648a34c41b70671dc38dbb72deb04", + "search": [ + "twitter", + "social", + "logo" + ], + "charRef": 63167 + }, + { + "css": "twitter-circled", + "code": 61527, + "uid": "ccf7ed45e7f05a89376f38abaa9d7d13", + "search": [ + "twitter", + "social", + "logo" + ], + "charRef": 63168 + }, + { + "css": "facebook", + "code": 61522, + "uid": "53d4dc777eeba379412efba3ee1cac9e", + "search": [ + "facebook", + "social", + "logo" + ], + "charRef": 63169 + }, + { + "css": "facebook-circled", + "code": 61521, + "uid": "96aafeab29734d1510805687f7695f8f", + "search": [ + "facebook", + "social", + "logo" + ], + "charRef": 63170 + }, + { + "css": "gplus", + "code": 61530, + "uid": "c896fd4e287aebcf79803e0ece001ec1", + "search": [ + "google", + "plus", + "social", + "logo" + ], + "charRef": 63171 + }, + { + "css": "gplus-circled", + "code": 61529, + "uid": "fef29532e2318a0c604f34947024b990", + "search": [ + "google", + "plus", + "social", + "logo" + ], + "charRef": 63172 + }, + { + "css": "linkedin", + "code": 61532, + "uid": "f09340446e327a78969ea1bfac29c1a6", + "search": [ + "linkedin", + "social", + "logo" + ], + "charRef": 63173 + }, + { + "css": "linkedin-circled", + "code": 61531, + "uid": "d0c177a8e1688175c3445cc6b25bcc90", + "search": [ + "linkedin", + "social", + "logo" + ], + "charRef": 63174 + }, + { + "css": "dribbble", + "code": 61520, + "uid": "2653481d01fec1b76247dbeffb74033e", + "search": [ + "dribbble", + "social", + "logo" + ], + "charRef": 63175 + }, + { + "css": "dribbble-circled", + "code": 61519, + "uid": "c5fa38a7b77f4efad5d8691b05035c7b", + "search": [ + "dribbble", + "social", + "logo" + ], + "charRef": 63176 + }, + { + "css": "instagram", + "code": 61533, + "uid": "603ebbc4040323ef53ba1dc37de67717", + "search": [ + "instagram", + "social", + "logo" + ], + "charRef": 63177 + }, + { + "css": "instagram-circled", + "code": 61534, + "uid": "0a16125788558bcc5d70ae3f10effce5", + "search": [ + "instagram", + "social", + "logo" + ], + "charRef": 63178 + }, + { + "css": "soundcloud", + "code": 61577, + "uid": "c7715df42d0413b3cae83d4bc3943a3e", + "search": [ + "soundcloud", + "social", + "logo" + ], + "charRef": 63179 + }, + { + "css": "soundcloud-circled", + "code": 61578, + "uid": "a12362e50cbf1078c509d85bc3e4431f", + "search": [ + "soundcloud", + "social", + "logo" + ], + "charRef": 63180 + }, + { + "css": "mfg-logo", + "code": 61535, + "uid": "ca4775510f9b79d63d9ad7d258f31af9", + "search": [ + "mfg", + "logo" + ], + "charRef": 63181 + }, + { + "css": "mfg-logo-circled", + "code": 61536, + "uid": "c37cda0d4ee654abafc9a896da259977", + "search": [ + "mfg", + "logo" + ], + "charRef": 63182 + } + ], + "font": { + "fontname": "mfglabs", + "fullname": "MFG Labs", + "familyname": "MFG Labs", + "copyright": "Copyright (C) 2012 by Daniel Bruce", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "MFG Labs", + "homepage": "http://www.mfglabs.com/", + "github": "https://github.com/MfgLabs/mfglabs-iconset", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "aboveground-rail", + "code": 59392, + "uid": "88a1241bcbe45c8e9616fd34d0f68a55", + "search": [ + "railway", + "streetcar" + ], + "charRef": 63183 + }, + { + "css": "airfield", + "code": 59393, + "uid": "ee81e35eef77c7d4d26c75258f028bff", + "search": [ + "airfield" + ], + "charRef": 63184 + }, + { + "css": "airport", + "code": 59394, + "uid": "f7440aaf96d590adceeff59b4dcb32d0", + "search": [ + "airport" + ], + "charRef": 63185 + }, + { + "css": "art-gallery", + "code": 59395, + "uid": "05417ae0104ab18a0fe454358579a987", + "search": [ + "gallery" + ], + "charRef": 63186 + }, + { + "css": "bar", + "code": 59396, + "uid": "5c8822b310f20896a3c55a25b71008a8", + "search": [ + "bar" + ], + "charRef": 63187 + }, + { + "css": "baseball", + "code": 59398, + "uid": "dc4eb27cd8f0cd537206d00dd85c0286", + "search": [ + "baseball" + ], + "charRef": 63188 + }, + { + "css": "basketball", + "code": 59399, + "uid": "9f5ce0d9f586e3df00449ad6ed6b0bf3", + "search": [ + "basketball" + ], + "charRef": 63189 + }, + { + "css": "beer", + "code": 59400, + "uid": "77886ff217450e06c8ffb7c88cb41e8b", + "search": [ + "beer" + ], + "charRef": 63190 + }, + { + "css": "belowground-rail", + "code": 59401, + "uid": "3fcff44d055ea3e68ea50aaa7d91947f", + "search": [ + "railway", + "subway" + ], + "charRef": 63191 + }, + { + "css": "bicycle", + "code": 59402, + "uid": "aab7e7622e6ee1ed8166fb73f20e8c9a", + "search": [ + "bicycle" + ], + "charRef": 63192 + }, + { + "css": "bus", + "code": 59403, + "uid": "2b39f74a074e338a67270567e95142cb", + "search": [ + "bus" + ], + "charRef": 63193 + }, + { + "css": "cafe", + "code": 59404, + "uid": "492fe0ef4cb41d4e4de8502897685399", + "search": [ + "cafe" + ], + "charRef": 63194 + }, + { + "css": "campsite", + "code": 59405, + "uid": "244d3253e3ca5a0d602dd3574050fe93", + "search": [ + "campsite" + ], + "charRef": 63195 + }, + { + "css": "cemetery", + "code": 59406, + "uid": "cc50849b33fcede3d861f5a94a22969f", + "search": [ + "cemetery" + ], + "charRef": 63196 + }, + { + "css": "cinema", + "code": 59407, + "uid": "3fe687c833fa36452029b6d57e9149bf", + "search": [ + "cinema" + ], + "charRef": 63197 + }, + { + "css": "college", + "code": 59408, + "uid": "020dbfb0a5a4a25775bc751e5891e161", + "search": [ + "college" + ], + "charRef": 63198 + }, + { + "css": "commerical-building", + "code": 59409, + "uid": "fc455b9530e0b37facc289f42a120fdd", + "search": [ + "building" + ], + "charRef": 63199 + }, + { + "css": "credit-card", + "code": 59410, + "uid": "5f1e8c36dffb553902e0e5c0c71faf6b", + "search": [ + "card" + ], + "charRef": 63200 + }, + { + "css": "cricket", + "code": 59411, + "uid": "3dfa88388f5e84f8e8fdc4f6320c8b44", + "search": [ + "cricket" + ], + "charRef": 63201 + }, + { + "css": "embassy", + "code": 59412, + "uid": "aec75ed0b4851c282824143392dde047", + "search": [ + "embassy" + ], + "charRef": 63202 + }, + { + "css": "fast-food", + "code": 59413, + "uid": "d27bcf5c8638e4078aaadae1d49b6909", + "search": [ + "fastfood", + "hamburger" + ], + "charRef": 63203 + }, + { + "css": "ferry", + "code": 59414, + "uid": "6d3728ea0e5678ab9cf6840c4a040e34", + "search": [ + "ferry" + ], + "charRef": 63204 + }, + { + "css": "fire-station", + "code": 59415, + "uid": "a9d3392264236bb9fe4d60a130c662d1", + "search": [ + "fire station" + ], + "charRef": 63205 + }, + { + "css": "football", + "code": 59416, + "uid": "429c0a4a7c5aba2f8a894f98b48529b3", + "search": [ + "football" + ], + "charRef": 63206 + }, + { + "css": "fuel", + "code": 59417, + "uid": "63af7ffdab0d3546333634c63554bb82", + "search": [ + "fuel" + ], + "charRef": 63207 + }, + { + "css": "garden", + "code": 59418, + "uid": "d06b13f30947afbbdae6977413144183", + "search": [ + "garden" + ], + "charRef": 63208 + }, + { + "css": "giraffe", + "code": 59419, + "uid": "8815bdcacab2495dd436f029e78a15d7", + "search": [ + "giraffe" + ], + "charRef": 63209 + }, + { + "css": "golf", + "code": 59420, + "uid": "93f72325e13529f1673ae0c3be4b7d22", + "search": [ + "golf" + ], + "charRef": 63210 + }, + { + "css": "grocery-store", + "code": 59422, + "uid": "00341f8df1496285c31db5988db1d8b5", + "search": [ + "grocery" + ], + "charRef": 63211 + }, + { + "css": "harbor", + "code": 59423, + "uid": "484b90ec34c04b0db020143526d3c21a", + "search": [ + "harbor" + ], + "charRef": 63212 + }, + { + "css": "heliport", + "code": 59424, + "uid": "6dddcfc03d1eaa1bfee628ab291072b6", + "search": [ + "heliport" + ], + "charRef": 63213 + }, + { + "css": "hospital", + "code": 59425, + "uid": "f43389fa3f5a5b152ed0231fe7bb18a7", + "search": [ + "hospital" + ], + "charRef": 63214 + }, + { + "css": "industrial-building", + "code": 59426, + "uid": "134184de1e4f1dc3d40e0d93bb1ef15e", + "search": [ + "building", + "industrial" + ], + "charRef": 63215 + }, + { + "css": "library", + "code": 59427, + "uid": "56a766cedf13005162899b02cf9546b9", + "search": [ + "library" + ], + "charRef": 63216 + }, + { + "css": "lodging", + "code": 59428, + "uid": "de3978220965d0d1b1cbe671a5a57f9a", + "search": [ + "lodging" + ], + "charRef": 63217 + }, + { + "css": "london-underground", + "code": 59429, + "uid": "0b9e9d7b951b0acaac25b9d7ed258120", + "search": [ + "underground" + ], + "charRef": 63218 + }, + { + "css": "minefield", + "code": 59430, + "uid": "3e98530afcd866a9d607f8be2b5aa159", + "search": [ + "minefield" + ], + "charRef": 63219 + }, + { + "css": "monument", + "code": 59431, + "uid": "19d9ceb791d76257545e308954808fc1", + "search": [ + "monument" + ], + "charRef": 63220 + }, + { + "css": "museum", + "code": 59432, + "uid": "192955900fa17f5677c4fdf2b3f01be7", + "search": [ + "museum" + ], + "charRef": 63221 + }, + { + "css": "pharmacy", + "code": 59433, + "uid": "ee10c11395b5660a1e10a19cd66ea654", + "search": [ + "pharmacy" + ], + "charRef": 63222 + }, + { + "css": "pitch", + "code": 59434, + "uid": "5040789d726273a910ac5b59e9d8227a", + "search": [ + "pitch" + ], + "charRef": 63223 + }, + { + "css": "police", + "code": 59435, + "uid": "2e7c67db76849147d16a6763d07a03a9", + "search": [ + "police" + ], + "charRef": 63224 + }, + { + "css": "post", + "code": 59436, + "uid": "3333e460aa2cf5a69989c42c334a4194", + "search": [ + "post" + ], + "charRef": 63225 + }, + { + "css": "prison", + "code": 59437, + "uid": "0151454c6a8abec62b1b8810aca0af6a", + "search": [ + "prison" + ], + "charRef": 63226 + }, + { + "css": "rail", + "code": 59438, + "uid": "70276caa975cb1354bc375ca334f6b4b", + "search": [ + "rail" + ], + "charRef": 63227 + }, + { + "css": "religious-christian", + "code": 59439, + "uid": "7f8b6c0519d85119a6f41fa3c5794806", + "search": [ + "religious", + "christian" + ], + "charRef": 63228 + }, + { + "css": "religious-islam", + "code": 59440, + "uid": "2e99947836a643225daf0336e4814bb3", + "search": [ + "religious", + "islam" + ], + "charRef": 63229 + }, + { + "css": "religious-jewish", + "code": 59441, + "uid": "5604bbb863d0ea7b38dc331705aedb13", + "search": [ + "religious", + "jewish" + ], + "charRef": 63230 + }, + { + "css": "restaurant", + "code": 59442, + "uid": "5cc58545bb38c912940470480d3df145", + "search": [ + "restaurant" + ], + "charRef": 63231 + }, + { + "css": "roadblock", + "code": 59443, + "uid": "40664a3e8916bfdcc5fb5655d469723e", + "search": [ + "roadblock" + ], + "charRef": 63232 + }, + { + "css": "school", + "code": 59444, + "uid": "653750436fc99eeb29ccd487e6a5bfa6", + "search": [ + "school" + ], + "charRef": 63233 + }, + { + "css": "shop", + "code": 59445, + "uid": "83a806d41893e8bc6fac601669c76cd2", + "search": [ + "shop" + ], + "charRef": 63234 + }, + { + "css": "skiing", + "code": 59446, + "uid": "ebabd8ff4b67bdbba7660952c30813ca", + "search": [ + "skiing" + ], + "charRef": 63235 + }, + { + "css": "soccer", + "code": 59447, + "uid": "d8813acae9d35ada76fda399a6000587", + "search": [ + "soccer" + ], + "charRef": 63236 + }, + { + "css": "swimming", + "code": 59448, + "uid": "d368c9b110be1daa21f992afca084b8c", + "search": [ + "swimming" + ], + "charRef": 63237 + }, + { + "css": "tennis", + "code": 59449, + "uid": "8a4eb4f98d8e0f3686a741c952b03c08", + "search": [ + "tennis" + ], + "charRef": 63238 + }, + { + "css": "theatre", + "code": 59450, + "uid": "5f89d009e91c94c7c9be2f8711d7a2eb", + "search": [ + "theatre" + ], + "charRef": 63239 + }, + { + "css": "toilet", + "code": 59451, + "uid": "0d0a49f05cb202227853f85ce5f63cdc", + "search": [ + "toilet" + ], + "charRef": 63240 + }, + { + "css": "town-hall", + "code": 59452, + "uid": "4c8822c296f8b46e1b0a1c0f627be146", + "search": [ + "town hall" + ], + "charRef": 63241 + }, + { + "css": "trash", + "code": 59453, + "uid": "cad619ef78a5500c1e5b3d021d2fdd65", + "search": [ + "trash" + ], + "charRef": 63242 + }, + { + "css": "tree-1", + "code": 59454, + "uid": "878dccd7b810bc231a132d86a3028afe", + "search": [ + "tree" + ], + "charRef": 63243 + }, + { + "css": "tree-2", + "code": 59455, + "uid": "35b65a48339004a947a1dea3092e1daa", + "search": [ + "tree" + ], + "charRef": 63244 + }, + { + "css": "warehouse", + "code": 59456, + "uid": "bc6ef9c6531c54e927e9dc18e45524b2", + "search": [ + "warehouse" + ], + "charRef": 63245 + } + ], + "font": { + "fontname": "maki", + "fullname": "Maki", + "familyname": "Maki", + "copyright": "Copyright (C) Mapbox, LCC", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "Mapbox", + "homepage": "http://mapbox.com/maki/", + "twitter": "http://twitter.com/mapbox", + "github": "https://github.com/mapbox/maki", + "license": "BSD", + "license_url": "https://github.com/mapbox/maki/blob/gh-pages/LICENSE.txt", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "duckduckgo", + "code": 33, + "uid": "446acc3b40ca5654627ffb8bc6b906e7", + "search": [ + "duckduckgo" + ], + "charRef": 63246 + }, + { + "css": "aim", + "code": 34, + "uid": "86009860c8331a1d90ae269432d6e24f", + "search": [ + "aol", + "messenger" + ], + "charRef": 63247 + }, + { + "css": "delicious", + "code": 35, + "uid": "1e2035b7cbaeb3d902cf9849e456069d", + "search": [ + "delicious" + ], + "charRef": 63248 + }, + { + "css": "paypal", + "code": 36, + "uid": "f5281239de27061e68f4367ba3efee15", + "search": [ + "paypal" + ], + "charRef": 63249 + }, + { + "css": "flattr", + "code": 37, + "uid": "c71d7db10ede1349b3a8ae0293b1dbf8", + "search": [ + "flattr" + ], + "charRef": 63250 + }, + { + "css": "android", + "code": 38, + "uid": "aaf371ab44841e9aaffebd179d324ce4", + "search": [ + "android" + ], + "charRef": 63251 + }, + { + "css": "eventful", + "code": 39, + "uid": "ca8881bd09267577150cc4637dc65572", + "search": [ + "eventful" + ], + "charRef": 63252 + }, + { + "css": "smashmag", + "code": 42, + "uid": "5556b88a0dc630940f326ab2ffbe7ccc", + "search": [ + "smashmag", + "smashing" + ], + "charRef": 63253 + }, + { + "css": "gplus", + "code": 43, + "uid": "e566d3f1d24f22981f6552d5188e7265", + "search": [ + "google", + "plus" + ], + "charRef": 63254 + }, + { + "css": "wikipedia", + "code": 44, + "uid": "64c2f859fa518d38db7ec7532855ae34", + "search": [ + "wikipedia" + ], + "charRef": 63255 + }, + { + "css": "lanyrd", + "code": 45, + "uid": "846fae80e47217662041242ee1f15a83", + "search": [ + "lanyrd" + ], + "charRef": 63256 + }, + { + "css": "calendar", + "code": 46, + "uid": "fe4b70ed76eb9a48877632032b33c942", + "search": [ + "calendar" + ], + "charRef": 63257 + }, + { + "css": "stumbleupon", + "code": 47, + "uid": "76a8a77019900916d16bad3eb4ee432c", + "search": [ + "stumbleupon" + ], + "charRef": 63258 + }, + { + "css": "fivehundredpx", + "code": 48, + "uid": "d089814548af1441aa00ecec47851f38", + "search": [ + "fivehundredpx" + ], + "charRef": 63259 + }, + { + "css": "pinterest", + "code": 49, + "uid": "799d6108751f684ac9d018983251a08f", + "search": [ + "pinterest" + ], + "charRef": 63260 + }, + { + "css": "bitcoin", + "code": 50, + "uid": "523e56b66e166a5bb7b823844bdf56e6", + "search": [ + "bitcoin" + ], + "charRef": 63261 + }, + { + "css": "w3c", + "code": 51, + "uid": "288a62ca532f76053c4a834ba3746ea2", + "search": [ + "w3c" + ], + "charRef": 63262 + }, + { + "css": "foursquare", + "code": 52, + "uid": "ffecc77dcd9b9dff653ff88b508220d4", + "search": [ + "foursquare" + ], + "charRef": 63263 + }, + { + "css": "html5", + "code": 53, + "uid": "d4d52a448819e8d5e849b8126416b640", + "search": [ + "html5" + ], + "charRef": 63264 + }, + { + "css": "ie", + "code": 54, + "uid": "63208f7386b9384ba1291832de6ceee7", + "search": [ + "ie", + "explorer" + ], + "charRef": 63265 + }, + { + "css": "call", + "code": 55, + "uid": "eb2d71e114d99d85b2ae28ab70d981a6", + "search": [ + "call" + ], + "charRef": 63266 + }, + { + "css": "grooveshark", + "code": 56, + "uid": "c9829449672245d22b3d43d7d1a7cc90", + "search": [ + "grooveshark" + ], + "charRef": 63267 + }, + { + "css": "ninetyninedesigns", + "code": 57, + "uid": "0aeb6f0ea0d091185f5c775401708aa1", + "search": [ + "ninetyninedesigns" + ], + "charRef": 63268 + }, + { + "css": "forrst", + "code": 58, + "uid": "2f6ed771cf99f6826343c31ed0b08026", + "search": [ + "forrst" + ], + "charRef": 63269 + }, + { + "css": "digg", + "code": 59, + "uid": "8625d6e45fba1219638069e21eedbce8", + "search": [ + "digg" + ], + "charRef": 63270 + }, + { + "css": "spotify", + "code": 61, + "uid": "e4b799ca3860a8276dba05b11d7e13db", + "search": [ + "spotify" + ], + "charRef": 63271 + }, + { + "css": "reddit", + "code": 62, + "uid": "b3a537446285bb3510bba57d20374818", + "search": [ + "reddit" + ], + "charRef": 63272 + }, + { + "css": "guest", + "code": 63, + "uid": "e2a0b3edf53a477f66d077cb907e2ab5", + "search": [ + "guest" + ], + "charRef": 63273 + }, + { + "css": "gowalla", + "code": 64, + "uid": "56a3e7f58bbb15252d06a4735e8299dc", + "search": [ + "gowalla" + ], + "charRef": 63274 + }, + { + "css": "appstore", + "code": 65, + "uid": "1dbc2b4a7f00ef209a85e4b5d9fedec4", + "search": [ + "appstore" + ], + "charRef": 63275 + }, + { + "css": "blogger", + "code": 66, + "uid": "2dd7e3046b63beb19616dce63c5782a6", + "search": [ + "blogger" + ], + "charRef": 63276 + }, + { + "css": "cc", + "code": 67, + "uid": "959c9a2360ed00ec9c0a75562d30edc4", + "search": [ + "creative commons" + ], + "charRef": 63277 + }, + { + "css": "dribbble", + "code": 68, + "uid": "003ba8187d6b00ec3e1ba75d00f1246a", + "search": [ + "dribbble" + ], + "charRef": 63278 + }, + { + "css": "evernote", + "code": 69, + "uid": "366510ecfb08cd0110134b1ea907fb81", + "search": [ + "evernote" + ], + "charRef": 63279 + }, + { + "css": "flickr", + "code": 70, + "uid": "231eeeedfdda9dd5d03dc8d03060007d", + "search": [ + "flickr" + ], + "charRef": 63280 + }, + { + "css": "google", + "code": 71, + "uid": "6d6d0efe9717ec2962ef0a77c6210df9", + "search": [ + "google" + ], + "charRef": 63281 + }, + { + "css": "viadeo", + "code": 72, + "uid": "cf31b05e6409526bbea832ca960777ed", + "search": [ + "viadeo" + ], + "charRef": 63282 + }, + { + "css": "instapaper", + "code": 73, + "uid": "5cf33e5f0b89834df4fb10609aec90d6", + "search": [ + "instapaper" + ], + "charRef": 63283 + }, + { + "css": "weibo", + "code": 74, + "uid": "3a171c02a5096c63c7c0e2e84d5eeb5a", + "search": [ + "weibo" + ], + "charRef": 63284 + }, + { + "css": "klout", + "code": 75, + "uid": "f35cf173c6dd32fa6a83208aeb26b527", + "search": [ + "klout" + ], + "charRef": 63285 + }, + { + "css": "linkedin", + "code": 76, + "uid": "cc4e62d1721c863fdc6944d2fd87521d", + "search": [ + "linkedin" + ], + "charRef": 63286 + }, + { + "css": "meetup", + "code": 77, + "uid": "3da502d7bf60ce54298aafe7b6dca55f", + "search": [ + "meetup" + ], + "charRef": 63287 + }, + { + "css": "vk", + "code": 78, + "uid": "12db1f260b5b2ccd1aa4d8942cc7f6dd", + "search": [ + "vkontakte" + ], + "charRef": 63288 + }, + { + "css": "plancast", + "code": 80, + "uid": "6cc1c059e221d7a0bf109870cc48f1a5", + "search": [ + "plancast" + ], + "charRef": 63289 + }, + { + "css": "disqus", + "code": 81, + "uid": "9b345d273b96183674779e05d64274af", + "search": [ + "disqus" + ], + "charRef": 63290 + }, + { + "css": "rss", + "code": 82, + "uid": "2a3192d0f8fe0c7cf959168e68eb16d8", + "search": [ + "rss" + ], + "charRef": 63291 + }, + { + "css": "skype", + "code": 83, + "uid": "1884ff7f89cc02840606d28f9bcf930a", + "search": [ + "skype" + ], + "charRef": 63292 + }, + { + "css": "twitter", + "code": 84, + "uid": "b1ec8e90c2c85cf0035849980a3789b3", + "search": [ + "twitter" + ], + "charRef": 63293 + }, + { + "css": "youtube", + "code": 85, + "uid": "57a4f84c40a0c44d47387105f162a427", + "search": [ + "youtube" + ], + "charRef": 63294 + }, + { + "css": "vimeo", + "code": 86, + "uid": "e47352cd4c5e069288b29a2c9ab9d305", + "search": [ + "vimeo" + ], + "charRef": 63295 + }, + { + "css": "windows", + "code": 87, + "uid": "01dcfef491cd3603565e4a68d1805332", + "search": [ + "windows" + ], + "charRef": 63296 + }, + { + "css": "xing", + "code": 88, + "uid": "d2f0cf090ba9e1a4ecbf8275018a0d61", + "search": [ + "xing" + ], + "charRef": 63297 + }, + { + "css": "yahoo", + "code": 89, + "uid": "aa86b5f7dd6d1087f35cbed951970cd1", + "search": [ + "yahoo" + ], + "charRef": 63298 + }, + { + "css": "chrome", + "code": 91, + "uid": "261a9fed5c3e5883ecc99e354d78a94b", + "search": [ + "chrome" + ], + "charRef": 63299 + }, + { + "css": "email", + "code": 93, + "uid": "a58032f4aafd0eec54803075f5b320d4", + "search": [ + "email" + ], + "charRef": 63300 + }, + { + "css": "macstore", + "code": 94, + "uid": "94b684c4b484712a2506911b68446ad9", + "search": [ + "macstore" + ], + "charRef": 63301 + }, + { + "css": "myspace", + "code": 95, + "uid": "916eba314d66dee45c9859d2fd146d36", + "search": [ + "myspace" + ], + "charRef": 63302 + }, + { + "css": "podcast", + "code": 96, + "uid": "5287c0dd80c29636f3d45b8b52cd3021", + "search": [ + "podcast" + ], + "charRef": 63303 + }, + { + "css": "amazon", + "code": 97, + "uid": "2f85c90013c0af641d18b167ec93d165", + "search": [ + "amazon" + ], + "charRef": 63304 + }, + { + "css": "steam", + "code": 98, + "uid": "785a9b232e86ae750516adc5228a5aa7", + "search": [ + "steam" + ], + "charRef": 63305 + }, + { + "css": "cloudapp", + "code": 99, + "uid": "6c304f746d790c6749f345ac384cbd7c", + "search": [ + "cloudapp" + ], + "charRef": 63306 + }, + { + "css": "dropbox", + "code": 100, + "uid": "d0ce443b8d7376716584f5f660a6bf72", + "search": [ + "dropbox" + ], + "charRef": 63307 + }, + { + "css": "ebay", + "code": 101, + "uid": "eae6db03eb0c9f2673a126967bf4d4ed", + "search": [ + "ebay" + ], + "charRef": 63308 + }, + { + "css": "facebook", + "code": 102, + "uid": "6f7586c6f99798c3c1de6123d1f6cfa9", + "search": [ + "facebook" + ], + "charRef": 63309 + }, + { + "css": "github", + "code": 103, + "uid": "9bba5df43e4e9419975336161e1810c3", + "search": [ + "github" + ], + "charRef": 63310 + }, + { + "css": "github-circled", + "code": 232, + "uid": "ff16079eb4be12c49bf3014d2322acdd", + "search": [ + "github" + ], + "charRef": 63311 + }, + { + "css": "googleplay", + "code": 104, + "uid": "909f99f11c6b6551bf757b6e809f98f3", + "search": [ + "googleplay" + ], + "charRef": 63312 + }, + { + "css": "itunes", + "code": 105, + "uid": "d6096cb47cc4448ac68b6a2e2c52a81d", + "search": [ + "itunes" + ], + "charRef": 63313 + }, + { + "css": "plurk", + "code": 106, + "uid": "bc3411a07338a7ae2dc49b9720f792c5", + "search": [ + "plurk" + ], + "charRef": 63314 + }, + { + "css": "songkick", + "code": 107, + "uid": "df750854b73c819540447f621729fb3a", + "search": [ + "songkick" + ], + "charRef": 63315 + }, + { + "css": "lastfm", + "code": 108, + "uid": "f3d8d921ab15972d3a29da321c5c0558", + "search": [ + "lastfm" + ], + "charRef": 63316 + }, + { + "css": "gmail", + "code": 109, + "uid": "b49fa3e57e92b38143e0fdcc5d9a904b", + "search": [ + "gmail" + ], + "charRef": 63317 + }, + { + "css": "pinboard", + "code": 110, + "uid": "c91522256a4c3972e9a2765b995b7252", + "search": [ + "pinboard" + ], + "charRef": 63318 + }, + { + "css": "openid", + "code": 111, + "uid": "1cf32a32df11230cd182b593752304b4", + "search": [ + "openid" + ], + "charRef": 63319 + }, + { + "css": "quora", + "code": 113, + "uid": "6a85bc0b09a4f21d2a3ced2bdffbc770", + "search": [ + "quora" + ], + "charRef": 63320 + }, + { + "css": "soundcloud", + "code": 115, + "uid": "1e123339045e48ddd01031936b9fc2d9", + "search": [ + "soundcloud" + ], + "charRef": 63321 + }, + { + "css": "tumblr", + "code": 116, + "uid": "90d3360c550556afb7e5d3ea58a34e43", + "search": [ + "tumblr" + ], + "charRef": 63322 + }, + { + "css": "eventasaurus", + "code": 118, + "uid": "60750bcb027f99557abe2fab47f19f2e", + "search": [ + "eventasaurus" + ], + "charRef": 63323 + }, + { + "css": "wordpress", + "code": 119, + "uid": "0636c283a9822288a767609062bbf4a4", + "search": [ + "wordpress" + ], + "charRef": 63324 + }, + { + "css": "yelp", + "code": 121, + "uid": "5d8165146a6d5f2784982aa955f963ce", + "search": [ + "yelp" + ], + "charRef": 63325 + }, + { + "css": "intensedebate", + "code": 123, + "uid": "67a821c2e9dbc2e439142b4aa04a9c4e", + "search": [ + "intensedebate" + ], + "charRef": 63326 + }, + { + "css": "eventbrite", + "code": 124, + "uid": "d99bb6de425328eea70522711d17596d", + "search": [ + "eventbrite" + ], + "charRef": 63327 + }, + { + "css": "scribd", + "code": 125, + "uid": "d549e369e55576b49f999436b9f13f44", + "search": [ + "scribd" + ], + "charRef": 63328 + }, + { + "css": "posterous", + "code": 126, + "uid": "0ec44644bdb6b89bbedb8929bb343a61", + "search": [ + "posterous" + ], + "charRef": 63329 + }, + { + "css": "stripe", + "code": 163, + "uid": "3e10dfa19399b45e9dbb9134c849334f", + "search": [ + "stripe" + ], + "charRef": 63330 + }, + { + "css": "opentable", + "code": 199, + "uid": "7ac996dea1fe6954e68548f0d73cd2b1", + "search": [ + "opentable" + ], + "charRef": 63331 + }, + { + "css": "cart", + "code": 201, + "uid": "c1f0120c5cb9af80a2f56d7d7fb2f489", + "search": [ + "cart", + "basket" + ], + "charRef": 63332 + }, + { + "css": "print", + "code": 209, + "uid": "6dd44b2efdc8c7bb99cbc75ed13b4c1e", + "search": [ + "print" + ], + "charRef": 63333 + }, + { + "css": "angellist", + "code": 214, + "uid": "bdaca8aa91638109e25d72f1dcbb58c1", + "search": [ + "angellist" + ], + "charRef": 63334 + }, + { + "css": "instagram", + "code": 220, + "uid": "6275b63473065457219b9e12024f95f2", + "search": [ + "instagram" + ], + "charRef": 63335 + }, + { + "css": "dwolla", + "code": 224, + "uid": "f39ab571fe73e796e24bb8edc1f9d875", + "search": [ + "dwolla" + ], + "charRef": 63336 + }, + { + "css": "appnet", + "code": 225, + "uid": "40ff77423c882ef32d11b5aec4ab17cf", + "search": [ + "appnet" + ], + "charRef": 63337 + }, + { + "css": "statusnet", + "code": 226, + "uid": "21a454e018faae9de83d19c65e7448d9", + "search": [ + "statusnet" + ], + "charRef": 63338 + }, + { + "css": "acrobat", + "code": 227, + "uid": "fd1c420f4755e275d578d856d7b20c50", + "search": [ + "acrobat" + ], + "charRef": 63339 + }, + { + "css": "drupal", + "code": 228, + "uid": "9794e9b767f192e0d499dfc98d52e802", + "search": [ + "drupal" + ], + "charRef": 63340 + }, + { + "css": "buffer", + "code": 229, + "uid": "58b5f27abdf85c2b2b8db2770d61162d", + "search": [ + "buffer" + ], + "charRef": 63341 + }, + { + "css": "pocket", + "code": 231, + "uid": "a7632b6db17256019e34ec72fb236be0", + "search": [ + "pocket" + ], + "charRef": 63342 + }, + { + "css": "bitbucket", + "code": 233, + "uid": "5b1387fb48babf0748ea04107c9adac3", + "search": [ + "bitbucket" + ], + "charRef": 63343 + }, + { + "css": "lego", + "code": 234, + "uid": "15a2a7646f0f7c0f129bee0f790d12fc", + "search": [ + "lego" + ], + "charRef": 63344 + }, + { + "css": "login", + "code": 235, + "uid": "1dabc07fb86333ee947c283f74ab5fc8", + "search": [ + "login" + ], + "charRef": 63345 + }, + { + "css": "stackoverflow", + "code": 236, + "uid": "e7d17d4d07756f4ab5eb690eea1275ca", + "search": [ + "stack overflow" + ], + "charRef": 63346 + }, + { + "css": "hackernews", + "code": 237, + "uid": "054a8f79ee2dae6c1ba909cc0c6f0cf9", + "search": [ + "hacker news" + ], + "charRef": 63347 + }, + { + "css": "lkdto", + "code": 238, + "uid": "2634442580bb3c5c7d87f30bed0227a8", + "search": [ + "lkdto" + ], + "charRef": 63348 + } + ], + "font": { + "fontname": "zocial", + "fullname": "Zocial", + "familyname": "Zocial", + "copyright": "Copyright (C) 2012 by Sam Collins", + "ascent": 850, + "descent": -150, + "weight": "Medium" + }, + "meta": { + "author": "Sam Collins", + "homepage": "http://zocial.smcllns.com/", + "twitter": "https://twitter.com/smcllns", + "dribbble": "http://dribbble.com/danielbruce", + "github": "https://github.com/samcollins/css-social-buttons/", + "license": "MIT", + "license_url": "http://opensource.org/licenses/mit-license.php", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "facebook", + "code": 62208, + "uid": "240979dd9fcf2e46250e66792edb8092", + "search": [ + "facebook" + ], + "charRef": 63349 + }, + { + "css": "facebook-rect", + "code": 62209, + "uid": "8045477f6a7ef0bd7caff130ad25b88d", + "search": [ + "facebook" + ], + "charRef": 63350 + }, + { + "css": "twitter", + "code": 62210, + "uid": "d611dd319d8c13b4551dc5bd85c1bdfd", + "search": [ + "twitter" + ], + "charRef": 63351 + }, + { + "css": "twitter-bird", + "code": 62211, + "uid": "4c01f5d3ba5fbf029bca8630cce41e6a", + "search": [ + "twitter" + ], + "charRef": 63352 + }, + { + "css": "vimeo", + "code": 62223, + "uid": "70cdf244c51630e09038659d1dcbee87", + "search": [ + "vimeo" + ], + "charRef": 63353 + }, + { + "css": "vimeo-rect", + "code": 62222, + "uid": "31483d870b3f14ac12bdfe7331a6af99", + "search": [ + "vimeo" + ], + "charRef": 63354 + }, + { + "css": "tumblr", + "code": 62225, + "uid": "076f25da90f45dd112e006f2cd7ea76b", + "search": [ + "tumblr" + ], + "charRef": 63355 + }, + { + "css": "tumblr-rect", + "code": 62224, + "uid": "9e6a3483242474b6a1f77739ae3fdfdc", + "search": [ + "tumblr" + ], + "charRef": 63356 + }, + { + "css": "googleplus-rect", + "code": 62217, + "uid": "626fb97a7c0c0db53a1853fb9e96e223", + "search": [ + "google" + ], + "charRef": 63357 + }, + { + "css": "github-text", + "code": 62215, + "uid": "24d1008bf15b6c02a5e7a6af026987dd", + "search": [ + "github" + ], + "charRef": 63358 + }, + { + "css": "github", + "code": 62216, + "uid": "4a0bb1ac004980bb3837560d4c9e8cee", + "search": [ + "github" + ], + "charRef": 63359 + }, + { + "css": "skype", + "code": 62219, + "uid": "5a00c877da3f63d37cdc021815e3f5a9", + "search": [ + "skype" + ], + "charRef": 63360 + }, + { + "css": "icq", + "code": 62212, + "uid": "01f67de2dc0137389f1c3aced6273acd", + "search": [ + "icq" + ], + "charRef": 63361 + }, + { + "css": "yandex", + "code": 62213, + "uid": "b2417d1ce399577d53fff70d54976fea", + "search": [ + "yandex" + ], + "charRef": 63362 + }, + { + "css": "yandex-rect", + "code": 62214, + "uid": "ea0cb6bedac64ae7933b03dad3130ef6", + "search": [ + "yandex" + ], + "charRef": 63363 + }, + { + "css": "vkontakte-rect", + "code": 62218, + "uid": "5b16ceef1c8638bd5389c9302ea04098", + "search": [ + "vkontakte" + ], + "charRef": 63364 + }, + { + "css": "odnoklassniki", + "code": 62220, + "uid": "229e50061df526f24f1ae884fab52101", + "search": [ + "odnoklassniki" + ], + "charRef": 63365 + }, + { + "css": "odnoklassniki-rect", + "code": 62221, + "uid": "4a02cc611ae9fb342d6026b2ed6cc44e", + "search": [ + "odnoklassniki" + ], + "charRef": 63366 + }, + { + "css": "friendfeed", + "code": 62226, + "uid": "eeec90e0e80f11e1aff10800200c9a66", + "search": [ + "friendfeed" + ], + "charRef": 63367 + }, + { + "css": "friendfeed-rect", + "code": 62227, + "uid": "41f4dd00e81111e1aff10800200c9a66", + "search": [ + "friendfeed" + ], + "charRef": 63368 + }, + { + "css": "blogger", + "code": 62228, + "uid": "303f1f30-eda7-11e1-aff1-0800200c9a66", + "search": [ + "blogger" + ], + "charRef": 63369 + }, + { + "css": "blogger-rect", + "code": 62229, + "uid": "a38dfae0ec2d11e1aff10800200c9a66", + "search": [ + "blogger" + ], + "charRef": 63370 + }, + { + "css": "deviantart", + "code": 62230, + "uid": "d04790a0ec2d11e1aff10800200c9a66", + "search": [ + "deviantart" + ], + "charRef": 63371 + }, + { + "css": "jabber", + "code": 62231, + "uid": "466d1430ec2e11e1aff10800200c9a66", + "search": [ + "jabber" + ], + "charRef": 63372 + }, + { + "css": "lastfm", + "code": 62232, + "uid": "9e237480ec2e11e1aff10800200c9a66", + "search": [ + "lastfm" + ], + "charRef": 63373 + }, + { + "css": "lastfm-rect", + "code": 62233, + "uid": "53a3bbcda09740c98a1c3d2e0a6a89fb", + "search": [ + "lastfm" + ], + "charRef": 63374 + }, + { + "css": "linkedin", + "code": 62234, + "uid": "542e3f055aaa4ddfb9ab3e00397db47f", + "search": [ + "linkedin" + ], + "charRef": 63375 + }, + { + "css": "linkedin-rect", + "code": 62235, + "uid": "e9e96618b0f44170930f9b179237c76e", + "search": [ + "linkedin" + ], + "charRef": 63376 + }, + { + "css": "picasa", + "code": 62236, + "uid": "d93230ef6fa54fb9805ba4cc9d9af5b1", + "search": [ + "picasa" + ], + "charRef": 63377 + }, + { + "css": "wordpress", + "code": 62237, + "uid": "1357ba39f8dc4519949cc4da55226b62", + "search": [ + "wordpress" + ], + "charRef": 63378 + }, + { + "css": "instagram", + "code": 62238, + "uid": "dad4e7f8dc2e57c92cffc0231202d9a0", + "search": [ + "instagram" + ], + "charRef": 63379 + }, + { + "css": "instagram-filled", + "code": 62239, + "uid": "cc20f2a7fa05a475130c406740bbbd26", + "search": [ + "instagram" + ], + "charRef": 63380 + }, + { + "css": "diigo", + "code": 62240, + "uid": "ca1c321a95f268ed0e54e7ba11a8264d", + "search": [ + "diigo" + ], + "charRef": 63381 + }, + { + "css": "box", + "code": 62241, + "uid": "968e63a0a36311e29e960800200c9a66", + "search": [ + "box" + ], + "charRef": 63382 + }, + { + "css": "box-rect", + "code": 62242, + "uid": "d52050c0a36711e29e960800200c9a66", + "search": [ + "box" + ], + "charRef": 63383 + }, + { + "css": "tudou", + "code": 62243, + "uid": "5d312ed68325656686a91f6da8fa04bd", + "search": [ + "tudou" + ], + "charRef": 63384 + }, + { + "css": "youku", + "code": 62244, + "uid": "c874a7b43d3f61059bd6db64fc7d6cb3", + "search": [ + "youku" + ], + "charRef": 63385 + }, + { + "css": "win8", + "code": 62245, + "uid": "3f06cdfffd60c5968c601a2e6c8f9a1b", + "search": [ + "windows" + ], + "charRef": 63386 + }, + { + "css": "amex", + "code": 62246, + "uid": "ca0f6425e0c44d613febeb0f23fa8ddf", + "search": [ + "amex" + ], + "charRef": 63387 + }, + { + "css": "discover", + "code": 62247, + "uid": "bbabc3d5d970358cec0a6d19a396b562", + "search": [ + "discover" + ], + "charRef": 63388 + }, + { + "css": "visa", + "code": 62248, + "uid": "cd65196712e52477b9252b4b296b0c44", + "search": [ + "visa" + ], + "charRef": 63389 + }, + { + "css": "mastercard", + "code": 62249, + "uid": "c3043114c56d36658e5cae51d36281c8", + "search": [ + "mastercard" + ], + "charRef": 63390 + }, + { + "css": "houzz", + "code": 62250, + "uid": "bf819a687a180e0e02ef319600c99d3b", + "search": [ + "houzz" + ], + "charRef": 63391 + }, + { + "css": "bandcamp", + "code": 62251, + "uid": "2518846ee21c610004effeae5cb8f9cc", + "search": [ + "bandcamp" + ], + "charRef": 63392 + }, + { + "css": "codepen", + "code": 62252, + "uid": "155970c9f52b23f31026bab7163caa63", + "search": [ + "codepen", + "code", + "pen" + ], + "charRef": 63393 + } + ], + "font": { + "fontname": "brandico", + "fullname": "Brandico", + "familyname": "Brandico", + "copyright": "(C) 2012 by Vitaly Puzrin", + "ascent": 850, + "descent": -150 + }, + "meta": { + "author": "Crowdsourced, for Fontello project", + "github": "https://github.com/fontello/brandico.font", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "glass", + "code": 57572, + "uid": "bcbb9470c9ba0699d5a0e4e97b3d5be9", + "search": [ + "glass" + ], + "charRef": 63394 + }, + { + "css": "music", + "code": 57459, + "uid": "e7ab5637425cce7dd2176302ddaf1c08", + "search": [ + "music", + "note", + "song", + "sound" + ], + "charRef": 63395 + }, + { + "css": "search", + "code": 57406, + "uid": "e45e9f27ce40ba9837cc984076d98067", + "search": [ + "search", + "find" + ], + "charRef": 63396 + }, + { + "css": "search-circled", + "code": 57405, + "uid": "81385e5f1fe091f3d9a20d215d444622", + "search": [ + "search", + "find" + ], + "charRef": 63397 + }, + { + "css": "mail", + "code": 57579, + "uid": "b6ef4443ecc502136135437837d9724b", + "search": [ + "mail", + "email", + "envelope" + ], + "charRef": 63398 + }, + { + "css": "mail-circled", + "code": 57578, + "uid": "7cb7e246fd23672429db603c0077dc79", + "search": [ + "mail", + "email", + "envelope" + ], + "charRef": 63399 + }, + { + "css": "heart", + "code": 57521, + "uid": "628e5fc59fc5965a6b91189467b037d5", + "search": [ + "heart" + ], + "charRef": 63400 + }, + { + "css": "heart-circled", + "code": 57520, + "uid": "5b4b9a59f7acb6839fa7fefe0d433165", + "search": [ + "heart" + ], + "charRef": 63401 + }, + { + "css": "heart-empty", + "code": 57569, + "uid": "7eed700d710c276569f95be26326fa5b", + "search": [ + "heart" + ], + "charRef": 63402 + }, + { + "css": "star", + "code": 57393, + "uid": "e1c372b8d386329b38dff5cd1ec46513", + "search": [ + "star" + ], + "charRef": 63403 + }, + { + "css": "star-circled", + "code": 57392, + "uid": "caed304a2bf6248f01e98c2aa30db1d7", + "search": [ + "star" + ], + "charRef": 63404 + }, + { + "css": "star-empty", + "code": 57391, + "uid": "8346e81b88fa3c57b42978f8b137a93a", + "search": [ + "star" + ], + "charRef": 63405 + }, + { + "css": "user", + "code": 57363, + "uid": "2c576f7c6c3233c31abad0899fc9f4af", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 63406 + }, + { + "css": "group", + "code": 57489, + "uid": "e36d581e4f2844db345bddc205d15dda", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 63407 + }, + { + "css": "group-circled", + "code": 57488, + "uid": "8d40bca7a7f11091ca865e07535fcc47", + "search": [ + "users", + "contacts", + "friends" + ], + "charRef": 63408 + }, + { + "css": "torso", + "code": 57372, + "uid": "6ad86a953a5a76086c5568366863bbca", + "search": [ + "profile", + "contact", + "user", + "torso" + ], + "charRef": 63409 + }, + { + "css": "video", + "code": 57362, + "uid": "31accb20e8819b200c297df608e68830", + "search": [ + "movie", + "video" + ], + "charRef": 63410 + }, + { + "css": "video-circled", + "code": 57361, + "uid": "529244b2b39e0c5a145506ce02271068", + "search": [ + "movie", + "video" + ], + "charRef": 63411 + }, + { + "css": "video-alt", + "code": 57577, + "uid": "09b251f36844ae25d58767d85d21bf88", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 63412 + }, + { + "css": "videocam", + "code": 57499, + "uid": "1e2149558b091788516ef5f589ac011e", + "search": [ + "facetime", + "movie", + "video", + "film" + ], + "charRef": 63413 + }, + { + "css": "video-chat", + "code": 57360, + "uid": "f274acf461473025f0d75518b653ec14", + "search": [ + "video", + "chat", + "talk" + ], + "charRef": 63414 + }, + { + "css": "picture", + "code": 57440, + "uid": "a1be363d4de9be39857893d4134f6215", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 63415 + }, + { + "css": "camera", + "code": 57513, + "uid": "6b6e59e33915710a9f935b04a06d507d", + "search": [ + "camera", + "photo" + ], + "charRef": 63416 + }, + { + "css": "photo", + "code": 57443, + "uid": "745f28cc6b06e5d131f6d650377b6cf5", + "search": [ + "photo" + ], + "charRef": 63417 + }, + { + "css": "photo-circled", + "code": 57442, + "uid": "5aeb40ce835cfcb60727340a347bd666", + "search": [ + "photo" + ], + "charRef": 63418 + }, + { + "css": "th-large", + "code": 57379, + "uid": "76f961b11f65300838a5a78856aca30f", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 63419 + }, + { + "css": "th", + "code": 57380, + "uid": "93faa7cec68bf69ec455bbab61e58e48", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 63420 + }, + { + "css": "th-list", + "code": 57378, + "uid": "50e664a6f12199784c02600b2ccfd60a", + "search": [ + "list", + "thumbnails" + ], + "charRef": 63421 + }, + { + "css": "view-mode", + "code": 57359, + "uid": "630d3c819e595abc344053e18872017b", + "search": [ + "view", + "thumbnails" + ], + "charRef": 63422 + }, + { + "css": "ok", + "code": 57456, + "uid": "ce7452abce8b55ded1c393997a51e6b3", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63423 + }, + { + "css": "ok-circled", + "code": 57454, + "uid": "67a9d2e5512b8aa812eff7da6d36bffc", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63424 + }, + { + "css": "ok-circled2", + "code": 57455, + "uid": "56b0141d7bbb0717fc6246ea145bc0bd", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63425 + }, + { + "css": "cancel", + "code": 57422, + "uid": "499b745a2e2485bdd059c3a53d048e5f", + "search": [ + "close", + "cancel", + "reject", + "remove" + ], + "charRef": 63426 + }, + { + "css": "cancel-circled", + "code": 57420, + "uid": "fd32deda7b2f5b8cad46d13897c19ae8", + "search": [ + "close", + "cancel", + "reject", + "remove" + ], + "charRef": 63427 + }, + { + "css": "cancel-circled2", + "code": 57421, + "uid": "74415da8e36ed0afcea9b2b1454f4176", + "search": [ + "close", + "cancel", + "reject", + "remove" + ], + "charRef": 63428 + }, + { + "css": "plus", + "code": 57434, + "uid": "55e2ff85b1c459c383f46da6e96014b0", + "search": [ + "plus" + ], + "charRef": 63429 + }, + { + "css": "plus-circled", + "code": 57433, + "uid": "d4aeb916de8d3aea716442778346d244", + "search": [ + "plus" + ], + "charRef": 63430 + }, + { + "css": "minus", + "code": 57462, + "uid": "0fb1948386f4581c72424a69587e6471", + "search": [ + "minus" + ], + "charRef": 63431 + }, + { + "css": "minus-circled", + "code": 57461, + "uid": "b35d6abdf5632eafeeb91377b0b6e9a1", + "search": [ + "minus" + ], + "charRef": 63432 + }, + { + "css": "help", + "code": 57430, + "uid": "a7289537a68b15b24bd4e3ee1ac20dfa", + "search": [ + "help", + "question" + ], + "charRef": 63433 + }, + { + "css": "help-circled", + "code": 57429, + "uid": "2105aa6ffb4434ebf82a20d97ac1ed25", + "search": [ + "help", + "question" + ], + "charRef": 63434 + }, + { + "css": "info-circled", + "code": 57481, + "uid": "2355991b4045d64b08fb82988109c0ee", + "search": [ + "info" + ], + "charRef": 63435 + }, + { + "css": "home", + "code": 57568, + "uid": "829c06a0a3b73b02a6224f4bbb73d99c", + "search": [ + "home" + ], + "charRef": 63436 + }, + { + "css": "home-circled", + "code": 57567, + "uid": "d80ef118949b097868584a3b80d55ce4", + "search": [ + "home" + ], + "charRef": 63437 + }, + { + "css": "website", + "code": 57352, + "uid": "cb89a11fa3722b7648ce26f40aaed8f0", + "search": [ + "website" + ], + "charRef": 63438 + }, + { + "css": "website-circled", + "code": 57351, + "uid": "a7dac3a6d7b1fdf3a67a9f2530afaaed", + "search": [ + "website" + ], + "charRef": 63439 + }, + { + "css": "attach", + "code": 57453, + "uid": "0be76e79cf83a68ecb961121c00b9f2d", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 63440 + }, + { + "css": "attach-circled", + "code": 57452, + "uid": "f7838631ee8af22feedf7358e02ef8e2", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 63441 + }, + { + "css": "lock", + "code": 57470, + "uid": "0e26e70b4aa537cc206f41b21dcf2fcc", + "search": [ + "lock", + "close" + ], + "charRef": 63442 + }, + { + "css": "lock-circled", + "code": 57469, + "uid": "ad194658d0e68d781eb334d9c1099d6e", + "search": [ + "lock", + "close" + ], + "charRef": 63443 + }, + { + "css": "lock-open", + "code": 57366, + "uid": "8f562a6dca9c14c9c8268bdb64efa89f", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 63444 + }, + { + "css": "lock-open-alt", + "code": 57365, + "uid": "780293b0d8c799ff73e17555b2ac9b4e", + "search": [ + "lock", + "open", + "unlock" + ], + "charRef": 63445 + }, + { + "css": "eye", + "code": 57501, + "uid": "e45a3da2ebde8bc8e30a873f3bd51f30", + "search": [ + "eye", + "subscribe" + ], + "charRef": 63446 + }, + { + "css": "eye-off", + "code": 57602, + "uid": "d218294e6f9f7191f6b0b3d1ff6239ff", + "search": [ + "eye", + "unsubscribe" + ], + "charRef": 63447 + }, + { + "css": "tag", + "code": 57385, + "uid": "630529f03c319c01101aa167181b650e", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 63448 + }, + { + "css": "tags", + "code": 57384, + "uid": "937a0ad3f6e25611bff801445d6a4885", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 63449 + }, + { + "css": "bookmark", + "code": 57588, + "uid": "8d2b0a28ccbfc06bb840720e554d79cc", + "search": [ + "bookmark" + ], + "charRef": 63450 + }, + { + "css": "bookmark-empty", + "code": 57587, + "uid": "363271b58af838dd4be5013284672322", + "search": [ + "bookmark" + ], + "charRef": 63451 + }, + { + "css": "flag", + "code": 57574, + "uid": "25acee28eb78eaa800b32bb6f20ebc62", + "search": [ + "flag" + ], + "charRef": 63452 + }, + { + "css": "flag-circled", + "code": 57601, + "uid": "3c3fa4ca801f3bdc36c35e497e0fc4fc", + "search": [ + "flag" + ], + "charRef": 63453 + }, + { + "css": "thumbs-up", + "code": 57376, + "uid": "0464d6f35a7fe587434173f42ddace88", + "search": [ + "thumbs", + "up", + "like", + "vote" + ], + "charRef": 63454 + }, + { + "css": "thumbs-down", + "code": 57377, + "uid": "3849753858193b4d6e07afa834aff979", + "search": [ + "thumbs", + "down", + "unlike", + "vote" + ], + "charRef": 63455 + }, + { + "css": "download", + "code": 57540, + "uid": "61a783a38ab7b1e312fc5cd9b13fd349", + "search": [ + "download" + ], + "charRef": 63456 + }, + { + "css": "download-alt", + "code": 57539, + "uid": "05a2f4c4839012434774cc1ceb4c0f9b", + "search": [ + "download" + ], + "charRef": 63457 + }, + { + "css": "upload", + "code": 57364, + "uid": "4fc965c0a4abf27512ac06752c56b3b5", + "search": [ + "upload" + ], + "charRef": 63458 + }, + { + "css": "share", + "code": 57403, + "uid": "d5937c5767642d0336ad599af0e9c992", + "search": [ + "forward", + "share" + ], + "charRef": 63459 + }, + { + "css": "quote", + "code": 57428, + "uid": "34e5d8943b23023d2a9515cfa9173506", + "search": [ + "quote" + ], + "charRef": 63460 + }, + { + "css": "quote-circled", + "code": 57427, + "uid": "173dc34e39eeb98cb748ccc1800a4fcc", + "search": [ + "quote" + ], + "charRef": 63461 + }, + { + "css": "export", + "code": 57404, + "uid": "3e31c5e1720a1545c5024a1796d74e5b", + "search": [ + "export", + "share" + ], + "charRef": 63462 + }, + { + "css": "pencil", + "code": 57448, + "uid": "62b0580ee8edc3a3edfbf68a47c852d5", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63463 + }, + { + "css": "pencil-circled", + "code": 57447, + "uid": "19dae18c34431934a781773e241faec2", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63464 + }, + { + "css": "edit", + "code": 57535, + "uid": "7b6c617d6d1e3f22db493839f0483bf6", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63465 + }, + { + "css": "edit-circled", + "code": 57534, + "uid": "2110049635bb7cea7ef41c28d9c15b32", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63466 + }, + { + "css": "edit-alt", + "code": 57581, + "uid": "6059b7737287728091ce7e4c600cca56", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63467 + }, + { + "css": "print", + "code": 57432, + "uid": "24a1eb628343fabd6f46a0a13456c045", + "search": [ + "print" + ], + "charRef": 63468 + }, + { + "css": "retweet", + "code": 57413, + "uid": "358afb4e7d145cc3384f2db0427fff92", + "search": [ + "retweet" + ], + "charRef": 63469 + }, + { + "css": "comment", + "code": 57606, + "uid": "23710230c21b4af140947e3604cc67a5", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 63470 + }, + { + "css": "comment-alt", + "code": 57507, + "uid": "afdb6de29702e88d79539d600c42d4a8", + "search": [ + "chat", + "talk" + ], + "charRef": 63471 + }, + { + "css": "bell", + "code": 57553, + "uid": "f84e243b91683403debed23b950f7efb", + "search": [ + "alert", + "bell", + "jingle" + ], + "charRef": 63472 + }, + { + "css": "warning", + "code": 57353, + "uid": "3fe5b810589a16bc691e3e979b2789dc", + "search": [ + "warning", + "attention" + ], + "charRef": 63473 + }, + { + "css": "exclamation", + "code": 57603, + "uid": "711fdb6caa365d5b69d4a72da2009cf6", + "search": [ + "exclamation", + "attention" + ], + "charRef": 63474 + }, + { + "css": "error", + "code": 57605, + "uid": "3ab229dd9bccaaaf6c71096da4b72c04", + "search": [ + "error", + "stop" + ], + "charRef": 63475 + }, + { + "css": "error-alt", + "code": 57604, + "uid": "3c0ef77f5fbb5c933c23f2c437d8cab8", + "search": [ + "error", + "stop" + ], + "charRef": 63476 + }, + { + "css": "location", + "code": 57466, + "uid": "22cfc7af2c4f158b37317c65c92b48c2", + "search": [ + "location", + "map", + "mark", + "marker" + ], + "charRef": 63477 + }, + { + "css": "location-circled", + "code": 57465, + "uid": "c54c00a5b7fba94b9fbc940de38a7beb", + "search": [ + "location", + "map", + "mark", + "marker" + ], + "charRef": 63478 + }, + { + "css": "compass", + "code": 57506, + "uid": "d8579082214a1c550b5d1ab2fee8b02c", + "search": [ + "compass" + ], + "charRef": 63479 + }, + { + "css": "compass-circled", + "code": 57505, + "uid": "1748e31f171a4060d1b498bf3a1af254", + "search": [ + "compass" + ], + "charRef": 63480 + }, + { + "css": "trash", + "code": 57371, + "uid": "3ab2abf6f936d3e53ee8c184cedaed82", + "search": [ + "trash", + "delete" + ], + "charRef": 63481 + }, + { + "css": "trash-circled", + "code": 57370, + "uid": "972c9374fbfca1e9095da9f104181be9", + "search": [ + "trash", + "delete" + ], + "charRef": 63482 + }, + { + "css": "doc", + "code": 57537, + "uid": "64fb13a798e934810c303e6b07791816", + "search": [ + "doc", + "article" + ], + "charRef": 63483 + }, + { + "css": "doc-circled", + "code": 57536, + "uid": "d932eda1eba18a387cf20f3aeea427b1", + "search": [ + "doc", + "article" + ], + "charRef": 63484 + }, + { + "css": "doc-new", + "code": 57533, + "uid": "9e0404ba55575a540164db9a5ad511df", + "search": [ + "doc", + "article" + ], + "charRef": 63485 + }, + { + "css": "doc-new-circled", + "code": 57532, + "uid": "3a3b9605e79d81475ebe85e9f68086cd", + "search": [ + "doc", + "article" + ], + "charRef": 63486 + }, + { + "css": "folder", + "code": 57599, + "uid": "9eece2885134734c5bc085fdd4955af1", + "search": [ + "folder" + ], + "charRef": 63487 + }, + { + "css": "folder-circled", + "code": 57494, + "uid": "f5fb170e83573af48438ea9e44f772ec", + "search": [ + "folder" + ], + "charRef": 63488 + }, + { + "css": "folder-close", + "code": 57598, + "uid": "3a9aa648fce45a316e70e1613bda57ac", + "search": [ + "folder" + ], + "charRef": 63489 + }, + { + "css": "folder-open", + "code": 57495, + "uid": "df09e8471b1f0ffb10db52d28dd8104d", + "search": [ + "folder" + ], + "charRef": 63490 + }, + { + "css": "rss", + "code": 57410, + "uid": "d881e6436253ef6cffe0f3fb10562643", + "search": [ + "rss" + ], + "charRef": 63491 + }, + { + "css": "phone", + "code": 57445, + "uid": "c91098f07ff0df45b3f8666b72b75801", + "search": [ + "phone", + "telephone", + "call" + ], + "charRef": 63492 + }, + { + "css": "phone-circled", + "code": 57444, + "uid": "23a1de57eb7b0c8281656a3ddadf3ee3", + "search": [ + "phone", + "telephone", + "call" + ], + "charRef": 63493 + }, + { + "css": "cog", + "code": 57609, + "uid": "6083c8aa5e3345476a24a28ac1afaa61", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 63494 + }, + { + "css": "cog-circled", + "code": 57608, + "uid": "7560ca08e3d83e43c58fcbf8f16d8f03", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 63495 + }, + { + "css": "cogs", + "code": 57607, + "uid": "1e32e1f8787cf3cb9f52f8850822dcb6", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 63496 + }, + { + "css": "wrench", + "code": 57348, + "uid": "cde79a37774e5817bc68fff2464aee28", + "search": [ + "wrench", + "tools", + "settings" + ], + "charRef": 63497 + }, + { + "css": "wrench-circled", + "code": 57347, + "uid": "e1a8092efb690eeb6c41d58b549e9074", + "search": [ + "wrench", + "tools", + "settings" + ], + "charRef": 63498 + }, + { + "css": "basket", + "code": 57402, + "uid": "f5686c8ccdc0213b081ef95678160b6d", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 63499 + }, + { + "css": "basket-circled", + "code": 57401, + "uid": "fbc62ccfe2241037d5b9abf65204aef8", + "search": [ + "basket", + "shopping", + "cart" + ], + "charRef": 63500 + }, + { + "css": "calendar", + "code": 57611, + "uid": "64abb7c56aefca89046bb69f7251d2e2", + "search": [ + "calendar", + "date" + ], + "charRef": 63501 + }, + { + "css": "calendar-circled", + "code": 57610, + "uid": "7689d722f0cb41f16f74b8149de5f71a", + "search": [ + "calendar", + "date" + ], + "charRef": 63502 + }, + { + "css": "mic", + "code": 57464, + "uid": "8ca5f77677a66dbe813213ca75ac1474", + "search": [ + "mic" + ], + "charRef": 63503 + }, + { + "css": "mic-circled", + "code": 57463, + "uid": "4d2f54ceffd4645d3ce6fe82b404190d", + "search": [ + "mic" + ], + "charRef": 63504 + }, + { + "css": "volume-off", + "code": 57356, + "uid": "8489d61496923b1159b01d8a0a7b2df0", + "search": [ + "volume", + "sound", + "mute" + ], + "charRef": 63505 + }, + { + "css": "volume-down", + "code": 57357, + "uid": "5d9730dc93976d27eb07914eab50a507", + "search": [ + "volume", + "sound" + ], + "charRef": 63506 + }, + { + "css": "volume", + "code": 57395, + "uid": "b59b3b618699b467541f631edd5a02ed", + "search": [ + "volume", + "sound", + "speaker" + ], + "charRef": 63507 + }, + { + "css": "volume-up", + "code": 57355, + "uid": "012ff5762ccb18c16bdfdd6baf187406", + "search": [ + "volume", + "sound" + ], + "charRef": 63508 + }, + { + "css": "headphones", + "code": 57523, + "uid": "7480a298ce334eef70193895e799c3fd", + "search": [ + "sound", + "music", + "headphones" + ], + "charRef": 63509 + }, + { + "css": "clock", + "code": 57375, + "uid": "d1fd686179920f26e0f1e83816fb40fe", + "search": [ + "clock", + "time" + ], + "charRef": 63510 + }, + { + "css": "clock-circled", + "code": 57374, + "uid": "15b7db710f718315e467df2502e4d592", + "search": [ + "clock", + "time" + ], + "charRef": 63511 + }, + { + "css": "lightbulb", + "code": 57566, + "uid": "599d6c088f4a1c64611b989459d65f6b", + "search": [ + "idea", + "lamp", + "light" + ], + "charRef": 63512 + }, + { + "css": "lightbulb-alt", + "code": 57593, + "uid": "629a8f18105619d27c013109a4064b46", + "search": [ + "idea", + "lamp", + "light" + ], + "charRef": 63513 + }, + { + "css": "block", + "code": 57514, + "uid": "2e3c51fc718aeb8b01604c8d039bcaeb", + "search": [ + "block", + "deny", + "ban" + ], + "charRef": 63514 + }, + { + "css": "resize-full", + "code": 57417, + "uid": "57776e51a50e3b4d92701bdbbba01588", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 63515 + }, + { + "css": "resize-full-alt", + "code": 57528, + "uid": "6707ea950c24c5b01625f7ea73b2172e", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 63516 + }, + { + "css": "resize-small", + "code": 57415, + "uid": "8c7e34dcc8cc90ed5f4fd59949201f41", + "search": [ + "resize" + ], + "charRef": 63517 + }, + { + "css": "resize-vertical", + "code": 57414, + "uid": "f8b0d36761ba4c7e51d0af49d3386713", + "search": [ + "resize" + ], + "charRef": 63518 + }, + { + "css": "resize-horizontal", + "code": 57416, + "uid": "f8d887df13c5f95ede5fb0e2cdb042b1", + "search": [ + "resize" + ], + "charRef": 63519 + }, + { + "css": "move", + "code": 57460, + "uid": "dea46bc85920f9a05bf7c7251fb10f10", + "search": [ + "move" + ], + "charRef": 63520 + }, + { + "css": "zoom-in", + "code": 57345, + "uid": "68c7be0f4cab6b82d5725b1ba7cec4d6", + "search": [ + "zoom", + "scale", + "in" + ], + "charRef": 63521 + }, + { + "css": "zoom-out", + "code": 57344, + "uid": "295287b96e50d494ba38a1ed9e06d8db", + "search": [ + "zoom", + "scale", + "out" + ], + "charRef": 63522 + }, + { + "css": "down-open", + "code": 57508, + "uid": "616b755d0f4c7d2dc7a1dcc2e5427039", + "search": [ + "arrow", + "down" + ], + "charRef": 63523 + }, + { + "css": "left-open", + "code": 57549, + "uid": "c0a07aca383ff2a164a4d691fa46e35c", + "search": [ + "arrow", + "left" + ], + "charRef": 63524 + }, + { + "css": "right-open", + "code": 57548, + "uid": "dc4a03854ef986d64565143bea4241aa", + "search": [ + "arrow", + "right" + ], + "charRef": 63525 + }, + { + "css": "up-open", + "code": 57547, + "uid": "b91c0e6aaab5e3146732b69dd418e120", + "search": [ + "arrow", + "up" + ], + "charRef": 63526 + }, + { + "css": "down", + "code": 57557, + "uid": "a79ef2d6f102af86440aa80238d5f4b0", + "search": [ + "arrow", + "down" + ], + "charRef": 63527 + }, + { + "css": "left", + "code": 57556, + "uid": "1b2ef17b42012a1e46743f9be8384f83", + "search": [ + "arrow", + "left" + ], + "charRef": 63528 + }, + { + "css": "right", + "code": 57519, + "uid": "23012c4e68769e1f133bba1f93a734d1", + "search": [ + "arrow", + "right" + ], + "charRef": 63529 + }, + { + "css": "up", + "code": 57518, + "uid": "cbb11c546600a92fde108476faf5d337", + "search": [ + "arrow", + "up" + ], + "charRef": 63530 + }, + { + "css": "down-circled", + "code": 57545, + "uid": "da74e2a8125fdbca337031474a48215a", + "search": [ + "arrow", + "down" + ], + "charRef": 63531 + }, + { + "css": "left-circled", + "code": 57544, + "uid": "a81de1d804430408892a8291b2372013", + "search": [ + "arrow", + "left" + ], + "charRef": 63532 + }, + { + "css": "right-circled", + "code": 57585, + "uid": "4c84ab263a198ea543aff93843c5ce87", + "search": [ + "arrow", + "right" + ], + "charRef": 63533 + }, + { + "css": "up-circled", + "code": 57584, + "uid": "6079b9663aede6ed5882db16bb04da3b", + "search": [ + "arrow", + "up" + ], + "charRef": 63534 + }, + { + "css": "down-hand", + "code": 57486, + "uid": "36c667650817d62f4e8089280ea49774", + "search": [ + "arrow", + "down" + ], + "charRef": 63535 + }, + { + "css": "left-hand", + "code": 57485, + "uid": "8216d5211b81d2a7344e2b7d76d019b0", + "search": [ + "arrow", + "left" + ], + "charRef": 63536 + }, + { + "css": "right-hand", + "code": 57484, + "uid": "c38baded20e83769843f48fbbfab5db3", + "search": [ + "arrow", + "right" + ], + "charRef": 63537 + }, + { + "css": "up-hand", + "code": 57525, + "uid": "86cc7238838f8a1d9d442ee34120c78e", + "search": [ + "arrow", + "up" + ], + "charRef": 63538 + }, + { + "css": "cw", + "code": 57419, + "uid": "081a030199f3ab4e18fd3ebdac1bd367", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 63539 + }, + { + "css": "cw-circled", + "code": 57418, + "uid": "5cbd2b6707adf3ec68a36ec195efe9bd", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 63540 + }, + { + "css": "arrows-cw", + "code": 57423, + "uid": "d5fabfa46384953ae055fceacb2229a7", + "search": [ + "reload", + "refresh", + "update", + "sync" + ], + "charRef": 63541 + }, + { + "css": "shuffle", + "code": 57426, + "uid": "8c23ecabc7d5df3666a038ad7c699421", + "search": [ + "shuffle" + ], + "charRef": 63542 + }, + { + "css": "play", + "code": 57437, + "uid": "20370af73ca90f73b4bda366d92303d9", + "search": [ + "play", + "player" + ], + "charRef": 63543 + }, + { + "css": "play-circled", + "code": 57436, + "uid": "fc006ff27e50163bdec3a7588226171b", + "search": [ + "play", + "player" + ], + "charRef": 63544 + }, + { + "css": "play-circled2", + "code": 57435, + "uid": "7acc2dfe18c6f4548626696fab27ba8a", + "search": [ + "play", + "player" + ], + "charRef": 63545 + }, + { + "css": "stop", + "code": 57388, + "uid": "fb3f247b54ed6149e1978bc3145e239a", + "search": [ + "stop", + "player" + ], + "charRef": 63546 + }, + { + "css": "stop-circled", + "code": 57387, + "uid": "fa2a253fba2da626ef08edcc62d1e4b6", + "search": [ + "stop", + "player" + ], + "charRef": 63547 + }, + { + "css": "pause", + "code": 57450, + "uid": "4f805cf4ac0dd68ab439dc36859b85d3", + "search": [ + "pause", + "player" + ], + "charRef": 63548 + }, + { + "css": "pause-circled", + "code": 57449, + "uid": "8710d1e404dcb3a55b3ab97f797355b5", + "search": [ + "pause", + "player" + ], + "charRef": 63549 + }, + { + "css": "record", + "code": 57425, + "uid": "14cab076c708524c1031b29ffd1c188f", + "search": [ + "record", + "player" + ], + "charRef": 63550 + }, + { + "css": "eject", + "code": 57580, + "uid": "755e3f2fc18b603c3ea62b9ee25e1322", + "search": [ + "eject", + "player" + ], + "charRef": 63551 + }, + { + "css": "backward", + "code": 57515, + "uid": "a76bd0de8b24c94f7fe0e1f93c34e65f", + "search": [ + "backward", + "player" + ], + "charRef": 63552 + }, + { + "css": "backward-circled", + "code": 57412, + "uid": "705a184307d39acdb41b595fef478416", + "search": [ + "backward", + "player" + ], + "charRef": 63553 + }, + { + "css": "fast-backward", + "code": 57498, + "uid": "c69425891f0b3ba4883e692a55e83bfd", + "search": [ + "backward", + "player" + ], + "charRef": 63554 + }, + { + "css": "fast-forward", + "code": 57497, + "uid": "c03284ddefae90dfd5ae9f0ee03325a2", + "search": [ + "forward", + "player" + ], + "charRef": 63555 + }, + { + "css": "forward", + "code": 57491, + "uid": "86bf86dba2ca65051aa87794221fee1c", + "search": [ + "forward", + "player" + ], + "charRef": 63556 + }, + { + "css": "forward-circled", + "code": 57490, + "uid": "b9589ab3313e83200f5e16e1c0c7cfa1", + "search": [ + "forward", + "player" + ], + "charRef": 63557 + }, + { + "css": "step-backward", + "code": 57390, + "uid": "1e25340c5d25e252264419f11422b5fe", + "search": [ + "backward", + "step", + "player" + ], + "charRef": 63558 + }, + { + "css": "step-forward", + "code": 57389, + "uid": "a5971b6a03c85ab6835c6c2418fed5c5", + "search": [ + "forward", + "step", + "player" + ], + "charRef": 63559 + }, + { + "css": "target", + "code": 57407, + "uid": "cf772d9d1eca484c9772a98045dd39d6", + "search": [ + "target", + "screenshot" + ], + "charRef": 63560 + }, + { + "css": "signal", + "code": 57400, + "uid": "184919c94792a0dc855d8342bb28276e", + "search": [ + "broadcast", + "wifi", + "signal" + ], + "charRef": 63561 + }, + { + "css": "desktop", + "code": 57409, + "uid": "abe051e31ad705400cf6226b24b6e828", + "search": [ + "desktop", + "screen", + "monitor" + ], + "charRef": 63562 + }, + { + "css": "desktop-circled", + "code": 57408, + "uid": "54ee0df068f4afe93779eb184f9b77f2", + "search": [ + "desktop", + "screen", + "monitor" + ], + "charRef": 63563 + }, + { + "css": "laptop", + "code": 57476, + "uid": "949f56916cd9c4f45ef76cc604f02e2e", + "search": [ + "laptop", + "notebook" + ], + "charRef": 63564 + }, + { + "css": "laptop-circled", + "code": 57475, + "uid": "3ccaec0f82abb6c57aa6fc8feeba9f45", + "search": [ + "laptop", + "notebook" + ], + "charRef": 63565 + }, + { + "css": "network", + "code": 57458, + "uid": "b89d4f9c40feef06ad3b2e121f95c60b", + "search": [ + "network" + ], + "charRef": 63566 + }, + { + "css": "inbox", + "code": 57592, + "uid": "1a94339c1ab20395e6a1475d8745714d", + "search": [ + "inbox" + ], + "charRef": 63567 + }, + { + "css": "inbox-circled", + "code": 57591, + "uid": "79b6617cefe785018f0354965c73f87d", + "search": [ + "inbox" + ], + "charRef": 63568 + }, + { + "css": "inbox-alt", + "code": 57590, + "uid": "967c5bc59a043f85bfce1434029c6a1c", + "search": [ + "inbox" + ], + "charRef": 63569 + }, + { + "css": "globe", + "code": 57570, + "uid": "5403802c07a547ae140985f9e2c6bc73", + "search": [ + "globe" + ], + "charRef": 63570 + }, + { + "css": "globe-alt", + "code": 57597, + "uid": "a92d5722d47933c1d6e20b6e6d5fd308", + "search": [ + "globe" + ], + "charRef": 63571 + }, + { + "css": "cloud", + "code": 57583, + "uid": "df4bad7f2eb18034fdfa1cbb3ddf8ac4", + "search": [ + "cloud" + ], + "charRef": 63572 + }, + { + "css": "cloud-circled", + "code": 57582, + "uid": "b9a3ecf978bd8c42e3d31596118d9dbc", + "search": [ + "cloud" + ], + "charRef": 63573 + }, + { + "css": "flight", + "code": 57438, + "uid": "8d673577ce96c5c2eec7f01a251fad26", + "search": [ + "flight", + "plane", + "airplane" + ], + "charRef": 63574 + }, + { + "css": "leaf", + "code": 57474, + "uid": "a904215f9fea569335d2a8addb4356b4", + "search": [ + "leaf" + ], + "charRef": 63575 + }, + { + "css": "font", + "code": 57493, + "uid": "3cdeca193a3d47ef93a4b45f5d88ba0c", + "search": [ + "editor", + "font" + ], + "charRef": 63576 + }, + { + "css": "fontsize", + "code": 57492, + "uid": "2c26914ed707706773028b28e8aa5bd6", + "search": [ + "editor", + "font", + "size" + ], + "charRef": 63577 + }, + { + "css": "bold", + "code": 57550, + "uid": "cc1de8eafc95f6faffcd8683aa8e9aa1", + "search": [ + "editor", + "bold" + ], + "charRef": 63578 + }, + { + "css": "italic", + "code": 57478, + "uid": "d88a8035fea40c4d6b934d788c2f5251", + "search": [ + "editor", + "italic" + ], + "charRef": 63579 + }, + { + "css": "text-height", + "code": 57382, + "uid": "7c8ccee198bdf2ba9f36c884a6c1cd95", + "search": [ + "editor", + "text", + "height" + ], + "charRef": 63580 + }, + { + "css": "text-width", + "code": 57381, + "uid": "dbcb2495fc2b934b13ac6992e0429e2f", + "search": [ + "editor", + "text", + "width" + ], + "charRef": 63581 + }, + { + "css": "align-left", + "code": 57559, + "uid": "3a3b33acd5fe66d84ff303baf9d8efa8", + "search": [ + "editor", + "align", + "left" + ], + "charRef": 63582 + }, + { + "css": "align-center", + "code": 57561, + "uid": "3c4b20e86f774f150402354b9cfeb95b", + "search": [ + "editor", + "align", + "center" + ], + "charRef": 63583 + }, + { + "css": "align-right", + "code": 57558, + "uid": "4d622484db3311a1a7322aae6b253984", + "search": [ + "editor", + "align", + "right" + ], + "charRef": 63584 + }, + { + "css": "align-justify", + "code": 57560, + "uid": "55f7ab3f2bedec72e8400fa2798a7a1a", + "search": [ + "editor", + "align", + "justify" + ], + "charRef": 63585 + }, + { + "css": "list", + "code": 57472, + "uid": "cd9ad52ef0740bb86ff11af9646d4859", + "search": [ + "editor", + "list" + ], + "charRef": 63586 + }, + { + "css": "indent-left", + "code": 57483, + "uid": "2a6cc3252195b53ed77ad3bdd73391b3", + "search": [ + "editor", + "indent" + ], + "charRef": 63587 + }, + { + "css": "indent-right", + "code": 57482, + "uid": "9efefb69aea6de9c20e56405a6aa2fd2", + "search": [ + "editor", + "indent" + ], + "charRef": 63588 + }, + { + "css": "briefcase", + "code": 57613, + "uid": "310c0c174fb8843a83ad0a7c6da85c56", + "search": [ + "briefcase" + ], + "charRef": 63589 + }, + { + "css": "off", + "code": 57457, + "uid": "c835a3a0692cca9dffde9a8a561da938", + "search": [ + "off" + ], + "charRef": 63590 + }, + { + "css": "road", + "code": 57411, + "uid": "7ea2f977b793b6044189122babbaa8eb", + "search": [ + "road" + ], + "charRef": 63591 + }, + { + "css": "qrcode", + "code": 57431, + "uid": "04f7e0bbd0bba658464ca2b49097f37f", + "search": [ + "qrcode" + ], + "charRef": 63592 + }, + { + "css": "barcode", + "code": 57555, + "uid": "b622423405bcc984de6553e2f23c9fb6", + "search": [ + "barcode" + ], + "charRef": 63593 + }, + { + "css": "braille", + "code": 57586, + "uid": "39a3467af0c8c49807ec54899774319c", + "search": [ + "braille" + ], + "charRef": 63594 + }, + { + "css": "book", + "code": 57589, + "uid": "a4232c4b087d715e826ba0793dab59ae", + "search": [ + "book" + ], + "charRef": 63595 + }, + { + "css": "adjust", + "code": 57563, + "uid": "545d79e9787941a08fb80642102850d4", + "search": [ + "ajust", + "contrast" + ], + "charRef": 63596 + }, + { + "css": "tint", + "code": 57373, + "uid": "1bedd7992ce00dc412fb02b39c1e9ebf", + "search": [ + "tint" + ], + "charRef": 63597 + }, + { + "css": "check", + "code": 57510, + "uid": "e2d87e7631c608efe71762a9f4c95e75", + "search": [ + "check" + ], + "charRef": 63598 + }, + { + "css": "check-empty", + "code": 57509, + "uid": "cc8e2a0eff0356811984b84a868524f8", + "search": [ + "check", + "empty" + ], + "charRef": 63599 + }, + { + "css": "asterisk", + "code": 57516, + "uid": "9de7039d5c9559926fe13880aa03ff51", + "search": [ + "asterisk" + ], + "charRef": 63600 + }, + { + "css": "gift", + "code": 57527, + "uid": "5e5a88921aa39b292bdd56c3b9c923d3", + "search": [ + "gift", + "present", + "package", + "box" + ], + "charRef": 63601 + }, + { + "css": "fire", + "code": 57575, + "uid": "dc73bee1d58539abe8c96b958bf4c931", + "search": [ + "fire" + ], + "charRef": 63602 + }, + { + "css": "magnet", + "code": 57468, + "uid": "2ce7a354773ee044f3c61e616e0c34dd", + "search": [ + "magnet" + ], + "charRef": 63603 + }, + { + "css": "chart", + "code": 57595, + "uid": "08fcae555c22437a112411038ac28e16", + "search": [ + "chart", + "diagram" + ], + "charRef": 63604 + }, + { + "css": "chart-circled", + "code": 57594, + "uid": "c4987116a2c796f034f0857db51fcaf5", + "search": [ + "chart", + "diagram" + ], + "charRef": 63605 + }, + { + "css": "credit-card", + "code": 57504, + "uid": "8c9fbdd92132007cf2f5e13b7ecb38f0", + "search": [ + "card", + "plastic", + "credit" + ], + "charRef": 63606 + }, + { + "css": "megaphone", + "code": 57612, + "uid": "d9ca3bd7577f1110305a2ca1841826cb", + "search": [ + "megaphone", + "bullhorn" + ], + "charRef": 63607 + }, + { + "css": "clipboard", + "code": 57471, + "uid": "c9bef3dc67fea47e94c4a5030ea64dad", + "search": [ + "list", + "clipboard" + ], + "charRef": 63608 + }, + { + "css": "hdd", + "code": 57524, + "uid": "7a2707491ef57c1e98921df65b572a66", + "search": [ + "hdd", + "drive", + "disk" + ], + "charRef": 63609 + }, + { + "css": "key", + "code": 57477, + "uid": "272e08e0e16226aadf94dcbf33aab2b2", + "search": [ + "key" + ], + "charRef": 63610 + }, + { + "css": "certificate", + "code": 57511, + "uid": "1a14e43d8e27f5b63fb418b586a2ade3", + "search": [ + "certificate" + ], + "charRef": 63611 + }, + { + "css": "tasks", + "code": 57383, + "uid": "84ab84920cd038d5b4b003f63e59aac6", + "search": [ + "tasks" + ], + "charRef": 63612 + }, + { + "css": "filter", + "code": 57576, + "uid": "5048fb5dd929882d2bac1ad3777b0b7d", + "search": [ + "filter" + ], + "charRef": 63613 + }, + { + "css": "gauge", + "code": 57502, + "uid": "c053ebe321823b081483d332b06eee54", + "search": [ + "dashboard", + "indicator", + "gauge" + ], + "charRef": 63614 + }, + { + "css": "smiley", + "code": 57397, + "uid": "f6d4106b0e134e9c20838a4437db2bdd", + "search": [ + "smiley" + ], + "charRef": 63615 + }, + { + "css": "smiley-circled", + "code": 57396, + "uid": "0a3ee424064f6ad4df821ea758d3399b", + "search": [ + "smiley" + ], + "charRef": 63616 + }, + { + "css": "address-book", + "code": 57565, + "uid": "361e7d7e271443ea2c48443142dbe404", + "search": [ + "address book" + ], + "charRef": 63617 + }, + { + "css": "address-book-alt", + "code": 57564, + "uid": "7b8d4298f52e82954959c0566e9929f9", + "search": [ + "address book" + ], + "charRef": 63618 + }, + { + "css": "asl", + "code": 57517, + "uid": "10fdd98fb50c590b805a3ad6ff9c55f5", + "search": [ + "asl", + "sign", + "language" + ], + "charRef": 63619 + }, + { + "css": "glasses", + "code": 57571, + "uid": "a3662e0fce8c28f9b91a3889094cd1e9", + "search": [ + "glasses" + ], + "charRef": 63620 + }, + { + "css": "hearing-impaired", + "code": 57522, + "uid": "5add73d9688b3ccd8e7e7a58197dbaeb", + "search": [ + "hearing", + "impaired", + "deaf", + "muffle" + ], + "charRef": 63621 + }, + { + "css": "iphone-home", + "code": 57479, + "uid": "babd288a0685a4b701a934fd40679a80", + "search": [ + "iphone", + "button" + ], + "charRef": 63622 + }, + { + "css": "person", + "code": 57446, + "uid": "d92a3efcdf848fb0abd9410b8d95813e", + "search": [ + "person", + "human" + ], + "charRef": 63623 + }, + { + "css": "adult", + "code": 57562, + "uid": "1e394b6cd5e0da3e10d8e4f3fe355960", + "search": [ + "person", + "human", + "adult" + ], + "charRef": 63624 + }, + { + "css": "child", + "code": 57546, + "uid": "c737078cb69dfd2e8484e134ecbce791", + "search": [ + "person", + "human", + "child" + ], + "charRef": 63625 + }, + { + "css": "blind", + "code": 57552, + "uid": "b7685cc9e721c9430986e03e08afed83", + "search": [ + "person", + "human", + "blind" + ], + "charRef": 63626 + }, + { + "css": "guidedog", + "code": 57487, + "uid": "88ae7d00391a440ac7ccd009bcb34e4e", + "search": [ + "dog" + ], + "charRef": 63627 + }, + { + "css": "accessibility", + "code": 57350, + "uid": "afe93fc3d2e6e389194bb3771f00fdb1", + "search": [ + "person", + "human", + "wheelchair", + "accessibility" + ], + "charRef": 63628 + }, + { + "css": "universal-access", + "code": 57367, + "uid": "d4385b9337eeaa7feb48465b50649042", + "search": [ + "person", + "human", + "accessibility", + "universal access" + ], + "charRef": 63629 + }, + { + "css": "male", + "code": 57467, + "uid": "51d26008d35b3c8b15a48f49e2b08860", + "search": [ + "person", + "human", + "male" + ], + "charRef": 63630 + }, + { + "css": "female", + "code": 57496, + "uid": "471497b78b90ca63aa21b13bf4c46cf4", + "search": [ + "person", + "human", + "female" + ], + "charRef": 63631 + }, + { + "css": "behance", + "code": 57554, + "uid": "a0b54315916e54beb4737562e203f674", + "search": [ + "social", + "logo", + "picasa" + ], + "charRef": 63632 + }, + { + "css": "blogger", + "code": 57551, + "uid": "166d4e3accccb0dfec9334cdab946db5", + "search": [ + "social", + "logo", + "picasa" + ], + "charRef": 63633 + }, + { + "css": "cc", + "code": 57512, + "uid": "9019381ddbf3c1007639974a480c86c2", + "search": [ + "social", + "logo", + "creative commons" + ], + "charRef": 63634 + }, + { + "css": "css", + "code": 57503, + "uid": "43be174b82af7559a7550ea38650ae4f", + "search": [ + "logo", + "css" + ], + "charRef": 63635 + }, + { + "css": "delicious", + "code": 57543, + "uid": "82c1a53a806cc33aab8bdef9dabf3e42", + "search": [ + "social", + "logo", + "delicious" + ], + "charRef": 63636 + }, + { + "css": "deviantart", + "code": 57542, + "uid": "aec2c281c91ca07d01e47f444545036f", + "search": [ + "social", + "logo", + "deviantart" + ], + "charRef": 63637 + }, + { + "css": "digg", + "code": 57541, + "uid": "1a2b14f7b24937389346c858ae711f25", + "search": [ + "social", + "logo", + "digg" + ], + "charRef": 63638 + }, + { + "css": "dribbble", + "code": 57538, + "uid": "c39ce49cb99649ba86ebc65f27335621", + "search": [ + "social", + "logo", + "dribbble" + ], + "charRef": 63639 + }, + { + "css": "facebook", + "code": 57500, + "uid": "c99e966e3d22ec0b9d8678fd524e5512", + "search": [ + "social", + "logo", + "facebook" + ], + "charRef": 63640 + }, + { + "css": "flickr", + "code": 57600, + "uid": "f9e7869be96161992f476eaa4219637d", + "search": [ + "social", + "logo", + "flickr" + ], + "charRef": 63641 + }, + { + "css": "foursquare", + "code": 57531, + "uid": "1a4351807d92cb6b27eabb24ec239889", + "search": [ + "social", + "logo", + "foursquare" + ], + "charRef": 63642 + }, + { + "css": "friendfeed", + "code": 57530, + "uid": "818869a1eb50dbf4ad9d2655fe835201", + "search": [ + "social", + "logo", + "friendfeed" + ], + "charRef": 63643 + }, + { + "css": "friendfeed-rect", + "code": 57529, + "uid": "72534675ded399a0fa8c73467d02101d", + "search": [ + "social", + "logo", + "friendfeed" + ], + "charRef": 63644 + }, + { + "css": "github", + "code": 57526, + "uid": "aa18911cd641967c899c575aeb80cd7e", + "search": [ + "social", + "logo", + "github" + ], + "charRef": 63645 + }, + { + "css": "github-text", + "code": 57573, + "uid": "798f480ad47c7c7fa6c64ece88ea2180", + "search": [ + "social", + "logo", + "github" + ], + "charRef": 63646 + }, + { + "css": "googleplus", + "code": 57596, + "uid": "a58fe946fe31826f0b19cb4dfaaf13d2", + "search": [ + "social", + "logo", + "google plus" + ], + "charRef": 63647 + }, + { + "css": "instagram", + "code": 57480, + "uid": "94ca559902b8930f0b267a588ffddb0b", + "search": [ + "social", + "logo", + "instagram" + ], + "charRef": 63648 + }, + { + "css": "linkedin", + "code": 57473, + "uid": "09cad6e46ec29b279626434802012bba", + "search": [ + "social", + "logo", + "linkedin" + ], + "charRef": 63649 + }, + { + "css": "path", + "code": 57451, + "uid": "c37b15dbb7b146c359d45b577fba6c0e", + "search": [ + "social", + "logo", + "path" + ], + "charRef": 63650 + }, + { + "css": "picasa", + "code": 57441, + "uid": "866934e4e5cfbc2d2a00d08f30257397", + "search": [ + "social", + "logo", + "picasa" + ], + "charRef": 63651 + }, + { + "css": "pinterest", + "code": 57439, + "uid": "1b813c4a33217fc20f46f3c157a9c90c", + "search": [ + "social", + "logo", + "pinterest" + ], + "charRef": 63652 + }, + { + "css": "reddit", + "code": 57424, + "uid": "e7f91449144fb058ad8125e2d35b2363", + "search": [ + "social", + "logo", + "reddit" + ], + "charRef": 63653 + }, + { + "css": "skype", + "code": 57399, + "uid": "eb2180f5d31d3e2fcc08856edbd3fb8f", + "search": [ + "social", + "logo", + "skype" + ], + "charRef": 63654 + }, + { + "css": "slideshare", + "code": 57398, + "uid": "326b529aa8b8913d3bc4a632f3dcec69", + "search": [ + "social", + "logo", + "slideshare" + ], + "charRef": 63655 + }, + { + "css": "stackoverflow", + "code": 57394, + "uid": "a5e7f5574a71d31bdf2012f0c2acb2a3", + "search": [ + "social", + "logo", + "stackoverflow" + ], + "charRef": 63656 + }, + { + "css": "stumbleupon", + "code": 57386, + "uid": "f90c6acf12a82ff9c9ce6878bdffd595", + "search": [ + "social", + "logo", + "stumbleupon" + ], + "charRef": 63657 + }, + { + "css": "twitter", + "code": 57368, + "uid": "26969cfbd811730075e4c657cc9fda2a", + "search": [ + "social", + "logo", + "twitter" + ], + "charRef": 63658 + }, + { + "css": "tumblr", + "code": 57369, + "uid": "a816e83fc27dae26ad37e0c209b19920", + "search": [ + "social", + "logo", + "tumblr" + ], + "charRef": 63659 + }, + { + "css": "vimeo", + "code": 57358, + "uid": "0d024b966c51aff0cd02527eb7f21950", + "search": [ + "social", + "logo", + "vimeo" + ], + "charRef": 63660 + }, + { + "css": "vkontakte", + "code": 57614, + "uid": "34cfa573b7d6c70c298dfad4cac4d466", + "search": [ + "social", + "logo", + "vkontakte" + ], + "charRef": 63661 + }, + { + "css": "w3c", + "code": 57354, + "uid": "e8ac3bb8871f23096fcab025ba5373cb", + "search": [ + "logo", + "w3c" + ], + "charRef": 63662 + }, + { + "css": "wordpress", + "code": 57349, + "uid": "c72edf6fd8549ee6b7578254145715d5", + "search": [ + "social", + "logo", + "wordpress" + ], + "charRef": 63663 + }, + { + "css": "youtube", + "code": 57346, + "uid": "990d39e5b7e9750c55d2593b1cc61a0a", + "search": [ + "social", + "logo", + "youtube" + ], + "charRef": 63664 + } + ], + "font": { + "fontname": "elusive", + "fullname": "Elusive", + "familyname": "Elusive", + "copyright": "Copyright (C) 2013 by Aristeides Stathopoulos", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "Aristeides Stathopoulos", + "homepage": "http://aristeides.com/", + "email": "aristath@gmail.com", + "twitter": "https://twitter.com/aristath", + "github": "https://github.com/aristath/elusive-iconfont", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "music", + "code": 57378, + "uid": "572c9ded6a688698dc275b30ff30fefa", + "search": [ + "music", + "note", + "song", + "sound" + ], + "charRef": 63665 + }, + { + "css": "search", + "code": 57353, + "uid": "9725db89b610135dc76cd8a21afffa83", + "search": [ + "search", + "find" + ], + "charRef": 63666 + }, + { + "css": "mail", + "code": 57369, + "uid": "91bac16b22827347e9ee20477f0b44d2", + "search": [ + "mail", + "email" + ], + "charRef": 63667 + }, + { + "css": "heart", + "code": 57344, + "uid": "b19ac67070bc44e310990016288e449c", + "search": [ + "heart" + ], + "charRef": 63668 + }, + { + "css": "star", + "code": 57346, + "uid": "0817b47d6e5f1d85f2428640a021f0c4", + "search": [ + "star" + ], + "charRef": 63669 + }, + { + "css": "user", + "code": 57351, + "uid": "56a0672588820ab1a16363e5d07dd22e", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 63670 + }, + { + "css": "videocam", + "code": 57349, + "uid": "f2a37db235ca1951d60d7ebc9733eb54", + "search": [ + "facetime", + "movie", + "video", + "film" + ], + "charRef": 63671 + }, + { + "css": "camera", + "code": 57355, + "uid": "b59cc4d390a6df564a055f43c03a6af5", + "search": [ + "camera", + "photo" + ], + "charRef": 63672 + }, + { + "css": "photo", + "code": 57371, + "uid": "8573943a49ed6dd8f7819070445baa46", + "search": [ + "photo" + ], + "charRef": 63673 + }, + { + "css": "attach", + "code": 57385, + "uid": "359f380b2113cb40259269aed843e33d", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 63674 + }, + { + "css": "lock", + "code": 57357, + "uid": "47e9e56d2b5abe839bcf1e014d643dea", + "search": [ + "lock", + "close" + ], + "charRef": 63675 + }, + { + "css": "eye", + "code": 57363, + "uid": "a58c05a8a3ba59ababd4860a30892560", + "search": [ + "eye", + "subscribe" + ], + "charRef": 63676 + }, + { + "css": "tag", + "code": 57356, + "uid": "930c31d4c72bd792b5dceb6de607c3e0", + "search": [ + "tag", + "category", + "price", + "offer" + ], + "charRef": 63677 + }, + { + "css": "thumbs-up", + "code": 57370, + "uid": "06a2fbb04dffecdb444936073cae9123", + "search": [ + "thumbs", + "up", + "like", + "vote" + ], + "charRef": 63678 + }, + { + "css": "pencil", + "code": 57359, + "uid": "2aeb4987b469d22fcb8b471b6d2cdfff", + "search": [ + "pencil", + "write", + "reply", + "edit" + ], + "charRef": 63679 + }, + { + "css": "comment", + "code": 57364, + "uid": "5b1a68729f60f8be3769238379d1b8e9", + "search": [ + "comment", + "reply", + "write", + "chat" + ], + "charRef": 63680 + }, + { + "css": "location", + "code": 57362, + "uid": "1ea8ad6dbe1ae9a73565ad16cf88de19", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 63681 + }, + { + "css": "cup", + "code": 57366, + "uid": "c2958cfd1eed4434ab6e4bd6ab337af9", + "search": [ + "cup" + ], + "charRef": 63682 + }, + { + "css": "trash", + "code": 57350, + "uid": "2cc73cc335f054682c04fe63439c4dcb", + "search": [ + "trash", + "delete" + ], + "charRef": 63683 + }, + { + "css": "doc", + "code": 57368, + "uid": "f978da58836f23373882916f05fb70b4", + "search": [ + "doc", + "article", + "news" + ], + "charRef": 63684 + }, + { + "css": "note", + "code": 57372, + "uid": "29f4bce4a60650057c5248e30baa15a6", + "search": [ + "doc", + "note" + ], + "charRef": 63685 + }, + { + "css": "cog", + "code": 57354, + "uid": "484b4ad2058d17849f205c4054b6f315", + "search": [ + "settings", + "cog", + "gear", + "params" + ], + "charRef": 63686 + }, + { + "css": "params", + "code": 57375, + "uid": "3e2bd88137dd7ceec98b4bfd8640e5ec", + "search": [ + "settings", + "cog", + "gear", + "params" + ], + "charRef": 63687 + }, + { + "css": "calendar", + "code": 57387, + "uid": "43e4647c57186b5e06874621b5e665be", + "search": [ + "calendar", + "date" + ], + "charRef": 63688 + }, + { + "css": "sound", + "code": 57348, + "uid": "143d93c9abdee0f4a7a2a810acc62b91", + "search": [ + "volume", + "sound" + ], + "charRef": 63689 + }, + { + "css": "clock", + "code": 57373, + "uid": "ee22dc89481ea63f27654f59dcace804", + "search": [ + "clock", + "time" + ], + "charRef": 63690 + }, + { + "css": "lightbulb", + "code": 57358, + "uid": "fb3ee9c192c946342e0cdd12f06d7774", + "search": [ + "idea", + "lamp", + "light" + ], + "charRef": 63691 + }, + { + "css": "tv", + "code": 57347, + "uid": "cc5e3696cf6c3ad8c32daaea05355a99", + "search": [], + "charRef": 63692 + }, + { + "css": "desktop", + "code": 57361, + "uid": "7697f1734d53461137f05faab3f79cf0", + "search": [ + "desktop", + "screen", + "monitor", + "display" + ], + "charRef": 63693 + }, + { + "css": "mobile", + "code": 57367, + "uid": "6a9f3405aba67bcaee81e7ea38946b27", + "search": [ + "mobile", + "phone" + ], + "charRef": 63694 + }, + { + "css": "cd", + "code": 57389, + "uid": "52cde78d270e411ccf22c9ec02910d69", + "search": [ + "cd", + "vynil" + ], + "charRef": 63695 + }, + { + "css": "inbox", + "code": 57365, + "uid": "efaf7e97e8b1aa7c2b52cc29432c96ca", + "search": [ + "inbox", + "stack" + ], + "charRef": 63696 + }, + { + "css": "globe", + "code": 57391, + "uid": "1e89103762be72b0720eda0468e62b90", + "search": [ + "globe", + "world" + ], + "charRef": 63697 + }, + { + "css": "cloud", + "code": 57345, + "uid": "f6eb7f8aed5dc03a323d5ef2895ae50b", + "search": [ + "cloud" + ], + "charRef": 63698 + }, + { + "css": "paper-plane", + "code": 57374, + "uid": "6fbd93c0d220507921015a15575009e5", + "search": [ + "paper", + "plane", + "fly" + ], + "charRef": 63699 + }, + { + "css": "fire", + "code": 57384, + "uid": "04309fefab5210bf502d278d65d134cf", + "search": [ + "fire" + ], + "charRef": 63700 + }, + { + "css": "graduation-cap", + "code": 57380, + "uid": "4b7f817f780705a5d267ad59e855da91", + "search": [ + "graduation", + "study" + ], + "charRef": 63701 + }, + { + "css": "megaphone", + "code": 57379, + "uid": "cdcc1a6693235d1205370c1f47d5e7ad", + "search": [ + "megaphone", + "bullhorn" + ], + "charRef": 63702 + }, + { + "css": "database", + "code": 57377, + "uid": "02ad0683eaa9826f396fa7ccf1f1fb25", + "search": [ + "data", + "database" + ], + "charRef": 63703 + }, + { + "css": "key", + "code": 57352, + "uid": "75347b319511175da51af3955919dbac", + "search": [ + "key" + ], + "charRef": 63704 + }, + { + "css": "beaker", + "code": 57381, + "uid": "6cc796276697d8a75ae21bb2df4badc9", + "search": [ + "beaker" + ], + "charRef": 63705 + }, + { + "css": "truck", + "code": 57390, + "uid": "f5053e43ef8be31afb905801449ae26d", + "search": [ + "truck" + ], + "charRef": 63706 + }, + { + "css": "money", + "code": 57376, + "uid": "b8e88705f42bd79580be828233c65da0", + "search": [ + "money", + "banknote" + ], + "charRef": 63707 + }, + { + "css": "food", + "code": 57382, + "uid": "b08f8c33777cd6b512d9576fc6e7f405", + "search": [ + "food" + ], + "charRef": 63708 + }, + { + "css": "shop", + "code": 57386, + "uid": "5d27926667773d186de09fda4312af27", + "search": [ + "shop" + ], + "charRef": 63709 + }, + { + "css": "diamond", + "code": 57360, + "uid": "f8e8b267a9b949804f0c9dd7fed8e477", + "search": [ + "diamond", + "crystal" + ], + "charRef": 63710 + }, + { + "css": "t-shirt", + "code": 57383, + "uid": "862d4faacb164c0412cb3249d43d5d39", + "search": [ + "t-shirt" + ], + "charRef": 63711 + }, + { + "css": "wallet", + "code": 57388, + "uid": "d58dc0a0927a7dea2992f615f2fbf400", + "search": [ + "wallet", + "money" + ], + "charRef": 63712 + } + ], + "font": { + "fontname": "linecons", + "fullname": "Linecons", + "familyname": "Linecons", + "copyright": "Copyright (C) 2013 by Designmodo", + "ascent": 850, + "descent": -150, + "weight": "Normal" + }, + "meta": { + "author": "Designmodo for Smashing Magazine", + "homepage": "http://designmodo.com/linecons-free/", + "email": "info@designmodo.com", + "twitter": "https://www.twitter.com/designmodo", + "license": "CC BY", + "css_prefix_text": "icon-", + "columns": 4 + } + }, + { + "glyphs": [ + { + "css": "search", + "code": 128269, + "uid": "221947bea81f49a11b863c686a7bd235", + "search": [ + "search", + "find" + ], + "charRef": 63713 + }, + { + "css": "mail", + "code": 9993, + "uid": "cba6018f5de17c76f70b7d2c06037e5a", + "search": [ + "mail", + "email" + ], + "charRef": 63714 + }, + { + "css": "heart", + "code": 9829, + "uid": "2a3cd95de2621bd87479396f236fd2a4", + "search": [ + "heart" + ], + "charRef": 63715 + }, + { + "css": "heart-empty", + "code": 9825, + "uid": "1bcc6c6369c3d475fa27115f806ff2ad", + "search": [ + "heart" + ], + "charRef": 63716 + }, + { + "css": "star", + "code": 9733, + "uid": "1526e1ee08023c1542cbf65d3a9afa93", + "search": [ + "star" + ], + "charRef": 63717 + }, + { + "css": "user", + "code": 128100, + "uid": "fd3128bf109153952b1b775ea574504b", + "search": [ + "profile", + "contact", + "user" + ], + "charRef": 63718 + }, + { + "css": "video", + "code": 127916, + "uid": "c23a66951b34ed7d449688d559afb213", + "search": [ + "movie", + "video", + "film" + ], + "charRef": 63719 + }, + { + "css": "picture", + "code": 127748, + "uid": "baa375529925294ea0a2bc889c93ba2d", + "search": [ + "image", + "picture", + "photo" + ], + "charRef": 63720 + }, + { + "css": "th-large", + "code": 59144, + "uid": "46cacfc5030a225f338323a3538a18e8", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 63721 + }, + { + "css": "th", + "code": 9871, + "uid": "9e22a8a67fe3b88cdd5e4253c85debdb", + "search": [ + "image", + "list", + "thumbnails" + ], + "charRef": 63722 + }, + { + "css": "th-list", + "code": 9776, + "uid": "84d19120538dd143b9cf5433f2417f48", + "search": [ + "list" + ], + "charRef": 63723 + }, + { + "css": "ok", + "code": 10003, + "uid": "7b16b22168e762c88333f465da862098", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63724 + }, + { + "css": "ok-circle", + "code": 10004, + "uid": "157f2382d2c608c41d984c693174c83b", + "search": [ + "ok", + "yes", + "check", + "mark" + ], + "charRef": 63725 + }, + { + "css": "cancel", + "code": 10005, + "uid": "8da3ac534210aae9c0f0e13804c1df97", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 63726 + }, + { + "css": "cancel-circle", + "code": 10006, + "uid": "15739f3032c2aa3df67efc96b3ffef56", + "search": [ + "close", + "cancel", + "reject" + ], + "charRef": 63727 + }, + { + "css": "plus-circle", + "code": 10133, + "uid": "a66e72da83c98248ae3ef43808efc452", + "search": [ + "plus" + ], + "charRef": 63728 + }, + { + "css": "minus-circle", + "code": 10134, + "uid": "994eaa764b3f30721f3839c64c390ce3", + "search": [ + "minus" + ], + "charRef": 63729 + }, + { + "css": "link", + "code": 128279, + "uid": "3c4a596e8ee3584c4c9e7002371db19f", + "search": [ + "link", + "url", + "address" + ], + "charRef": 63730 + }, + { + "css": "attach", + "code": 128206, + "uid": "21115bb09fa242341cb91ed34710aa13", + "search": [ + "attach", + "clip", + "paperclip" + ], + "charRef": 63731 + }, + { + "css": "lock", + "code": 128274, + "uid": "95c84da411a955a12baff8b0859c9276", + "search": [ + "lock" + ], + "charRef": 63732 + }, + { + "css": "lock-open", + "code": 128275, + "uid": "5184430eda6a2b9c989990e4bca70746", + "search": [ + "lock" + ], + "charRef": 63733 + }, + { + "css": "tag", + "code": 59148, + "uid": "e6ad31134a018fdeb64efe72d39edd65", + "search": [ + "tag", + "price", + "offer" + ], + "charRef": 63734 + }, + { + "css": "reply", + "code": 59154, + "uid": "77dc6351a75ce82023a99696c9dd1ed3", + "search": [ + "reply" + ], + "charRef": 63735 + }, + { + "css": "reply-all", + "code": 59155, + "uid": "0f9d6be0e0fe72ddcfd75c8a6401d1aa", + "search": [ + "reply" + ], + "charRef": 63736 + }, + { + "css": "forward", + "code": 10150, + "uid": "32eebd7bef491a0cbf9bc839e40d271c", + "search": [ + "forward" + ], + "charRef": 63737 + }, + { + "css": "code", + "code": 59156, + "uid": "838db85de51df09e2d0c34a17dc30ff6", + "search": [ + "code" + ], + "charRef": 63738 + }, + { + "css": "retweet", + "code": 59159, + "uid": "63e2a597d744c3093e09fdd6108ee44f", + "search": [ + "retweet", + "twitter" + ], + "charRef": 63739 + }, + { + "css": "comment", + "code": 59160, + "uid": "889a8bd0b481e3523ede8a7d75164cd1", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 63740 + }, + { + "css": "comment-alt", + "code": 59162, + "uid": "b52aa05c9c55c41f1768cdaa940401a8", + "search": [ + "comment", + "reply", + "write" + ], + "charRef": 63741 + }, + { + "css": "chat", + "code": 59168, + "uid": "21f6a88daf13c62e5a70f5ef6ad9e23f", + "search": [ + "chat", + "talk" + ], + "charRef": 63742 + }, + { + "css": "attention", + "code": 9888, + "uid": "97ac1a82370ae58f02e4ff1bdc58ee86", + "search": [ + "attention", + "warning", + "alert" + ], + "charRef": 63743 + }, + { + "css": "location", + "code": 59172, + "uid": "69f76f7134f721d16c28ab23f84d4882", + "search": [ + "location", + "mark", + "marker" + ], + "charRef": 63744 + }, + { + "css": "doc", + "code": 59184, + "uid": "22baa2ff73747e588f6c066010654d6d", + "search": [ + "doc", + "article" + ], + "charRef": 63745 + }, + { + "css": "docs-landscape", + "code": 59191, + "uid": "eb1d9ac1cfa79d55aaf290c5a4ff266b", + "search": [ + "doc", + "article" + ], + "charRef": 63746 + }, + { + "css": "folder", + "code": 128193, + "uid": "f242fed2af708c938523b0e14d9c6b07", + "search": [ + "folder" + ], + "charRef": 63747 + }, + { + "css": "archive", + "code": 59192, + "uid": "bb1090404a4d33340a9ad7302ef8b6e8", + "search": [ + "archive" + ], + "charRef": 63748 + }, + { + "css": "rss", + "code": 59194, + "uid": "26f5aa38f3889213334b3990b4ad483b", + "search": [ + "rss" + ], + "charRef": 63749 + }, + { + "css": "rss-alt", + "code": 59195, + "uid": "7645346d5ab8b17f69a9c765c180aca3", + "search": [ + "rss" + ], + "charRef": 63750 + }, + { + "css": "cog", + "code": 9881, + "uid": "26aba7edd46944209b4961670675a813", + "search": [ + "settings", + "cog", + "gear" + ], + "charRef": 63751 + }, + { + "css": "logout", + "code": 59201, + "uid": "74b2f1d1ee541715b3f389f7cdf63d1c", + "search": [ + "logout", + "signout", + "exit" + ], + "charRef": 63752 + }, + { + "css": "clock", + "code": 128340, + "uid": "501f33ed61da407feb057a7699ef93f7", + "search": [ + "clock", + "time" + ], + "charRef": 63753 + }, + { + "css": "block", + "code": 128683, + "uid": "2d070116ca776192ee8e8c7e00c4d5a6", + "search": [ + "block", + "deny" + ], + "charRef": 63754 + }, + { + "css": "resize-full", + "code": 59204, + "uid": "8667827e81897cf8b8d19dc492920f8d", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 63755 + }, + { + "css": "resize-full-circle", + "code": 59302, + "uid": "9990c2588fd50406f36987e80e1e905b", + "search": [ + "resize", + "fullscreen" + ], + "charRef": 63756 + }, + { + "css": "popup", + "code": 59212, + "uid": "c9d395b295ad7d9c28298dcea916c6df", + "search": [ + "popup", + "window" + ], + "charRef": 63757 + }, + { + "css": "left-open", + "code": 59229, + "uid": "04960bf02134620e6c61bac8d6569502", + "search": [ + "arrow", + "left" + ], + "charRef": 63758 + }, + { + "css": "right-open", + "code": 59230, + "uid": "715e1003368da5e5c41ae35190af68a1", + "search": [ + "arrow", + "right" + ], + "charRef": 63759 + }, + { + "css": "down-circle", + "code": 58532, + "uid": "e160a7e42e4e818463fd5a8607b9f608", + "search": [ + "arrow", + "down" + ], + "charRef": 63760 + }, + { + "css": "left-circle", + "code": 58529, + "uid": "7e092c82e9a758b6e95297007969aac1", + "search": [ + "arrow", + "left" + ], + "charRef": 63761 + }, + { + "css": "right-circle", + "code": 58530, + "uid": "d30928620bda0d5eaa85d3b65bf19963", + "search": [ + "arrow", + "right" + ], + "charRef": 63762 + }, + { + "css": "up-circle", + "code": 58531, + "uid": "a7e3ce91275bb77c0f4ec44a548b325c", + "search": [ + "arrow", + "up" + ], + "charRef": 63763 + }, + { + "css": "down-dir", + "code": 9662, + "uid": "1821ddf00a08cef133824b1a4fd4790e", + "search": [ + "arrow", + "down" + ], + "charRef": 63764 + }, + { + "css": "right-dir", + "code": 9656, + "uid": "9c5557d93ab810b192b13adcf77e8c84", + "search": [ + "arrow", + "right" + ], + "charRef": 63765 + }, + { + "css": "down-micro", + "code": 59303, + "uid": "35674c31693db324f2fd6a48f1079263", + "search": [ + "arrow", + "down" + ], + "charRef": 63766 + }, + { + "css": "up-micro", + "code": 59304, + "uid": "fbed8311a5af2a8e5599246d9939a475", + "search": [ + "arrow", + "right" + ], + "charRef": 63767 + }, + { + "css": "cw-circle", + "code": 59305, + "uid": "141d5c2168c8b09979b75ecfab004e71", + "search": [ + "reload", + "redo", + "repeat" + ], + "charRef": 63768 + }, + { + "css": "arrows-cw", + "code": 59232, + "uid": "41eeea14413f2539da21b4d1754bf4be", + "search": [ + "reload", + "refresh", + "update", + "sync" + ], + "charRef": 63769 + }, + { + "css": "updown-circle", + "code": 59306, + "uid": "50ae91f6ed0e10a5e9eec6c63afedfb5", + "search": [ + "arrow", + "move" + ], + "charRef": 63770 + }, + { + "css": "target", + "code": 127919, + "uid": "006ab50770cd7183b27004f856b989e4", + "search": [ + "target" + ], + "charRef": 63771 + }, + { + "css": "signal", + "code": 128246, + "uid": "af3a08c6f521a065252ee35392864e15", + "search": [ + "chart", + "bar", + "diagram", + "signal", + "wifi" + ], + "charRef": 63772 + }, + { + "css": "progress-0", + "code": 48, + "uid": "c87205006317fa2c4baa78a8f010336e", + "search": [ + "progress", + "wait" + ], + "charRef": 63773 + }, + { + "css": "progress-1", + "code": 49, + "uid": "219f912320853b772ced5ef8dcd90aa8", + "search": [ + "progress", + "wait" + ], + "charRef": 63774 + }, + { + "css": "progress-2", + "code": 50, + "uid": "52a572564b343cac4094f4065d9a60c7", + "search": [ + "progress", + "wait" + ], + "charRef": 63775 + }, + { + "css": "progress-3", + "code": 51, + "uid": "e1619edac8d9d337c29dad11e661b5ca", + "search": [ + "progress", + "wait" + ], + "charRef": 63776 + }, + { + "css": "progress-4", + "code": 52, + "uid": "7eb19468929f2d110339227ab4ea795f", + "search": [ + "progress", + "wait" + ], + "charRef": 63777 + }, + { + "css": "progress-5", + "code": 53, + "uid": "be68e15ee051e52d4922090cd05c176c", + "search": [ + "progress", + "wait" + ], + "charRef": 63778 + }, + { + "css": "progress-6", + "code": 54, + "uid": "5c56ff8528dc54a54e8c1d4a850b9014", + "search": [ + "progress", + "wait" + ], + "charRef": 63779 + }, + { + "css": "progress-7", + "code": 55, + "uid": "a54fbbda12ee4eff1a91d04a80f836b1", + "search": [ + "progress", + "wait" + ], + "charRef": 63780 + }, + { + "css": "font", + "code": 59257, + "uid": "9ecf5170254e332a2c92cbbe85df94a8", + "search": [ + "editor", + "font" + ], + "charRef": 63781 + }, + { + "css": "list", + "code": 59266, + "uid": "cf1d7ee3d5c367a5c5a3cc9e77acec68", + "search": [ + "editor", + "list" + ], + "charRef": 63782 + }, + { + "css": "list-numbered", + "code": 59309, + "uid": "00d6d0f4cda0621ae03893dcfeb9bb1d", + "search": [ + "editor", + "list" + ], + "charRef": 63783 + }, + { + "css": "indent-left", + "code": 59267, + "uid": "beb54ffa9c4b49c62af6fa72354d1740", + "search": [ + "editor", + "indent" + ], + "charRef": 63784 + }, + { + "css": "indent-right", + "code": 59268, + "uid": "a3f13abf118d3c6abe3e99a6c296a9a5", + "search": [ + "editor", + "indent" + ], + "charRef": 63785 + }, + { + "css": "cloud", + "code": 9729, + "uid": "7e25a96981e6bd6b1592c409da293c45", + "search": [ + "cloud" + ], + "charRef": 63786 + }, + { + "css": "terminal", + "code": 59308, + "uid": "e92e6cad2da0ee4bc374a1ef4c6ab12b", + "search": [ + "terminal", + "prompt" + ], + "charRef": 63787 + }, + { + "css": "facebook-rect", + "code": 62209, + "uid": "ebbe0cc0600cb69375abc20af545967f", + "search": [ + "facebook" + ], + "charRef": 63788 + }, + { + "css": "twitter-bird", + "code": 62211, + "uid": "a4765de460cc6485b1ca5b36222f41d5", + "search": [ + "twitter" + ], + "charRef": 63789 + }, + { + "css": "vimeo-rect", + "code": 62222, + "uid": "335bfd225407f1205eddd3d47744e6be", + "search": [ + "vimeo" + ], + "charRef": 63790 + }, + { + "css": "tumblr-rect", + "code": 62224, + "uid": "9829cb345a4512f5aece933ba836ff1f", + "search": [ + "tumblr" + ], + "charRef": 63791 + }, + { + "css": "googleplus-rect", + "code": 62217, + "uid": "0e5740f288f6f5cb04eef63f7f0a1506", + "search": [ + "google" + ], + "charRef": 63792 + }, + { + "css": "linkedin-rect", + "code": 62226, + "uid": "8870252f5da59a63564fb6790a347c8e", + "search": [ + "linkedin" + ], + "charRef": 63793 + }, + { + "css": "skype", + "code": 62219, + "uid": "a25ef3626c7bd7031709a8264f280bfe", + "search": [ + "skype" + ], + "charRef": 63794 + }, + { + "css": "vkontakte-rect", + "code": 62218, + "uid": "f6dfd6896053ff75262b8ad4baec251e", + "search": [ + "vkontakte" + ], + "charRef": 63795 + }, + { + "css": "youtube", + "code": 62227, + "uid": "2d3ce9463ed5525c6faa01f84c957843", + "charRef": 63796 + }, + { + "css": "odnoklassniki-rect", + "code": 62221, + "uid": "5fb90c2cd2cc4ceb3fb6e787aae73fd3", + "search": [ + "odnoklassniki" + ], + "charRef": 63797 + } + ], + "font": { + "fontname": "websymbols", + "fullname": "Web Symbols", + "familyname": "Web Symbols", + "copyright": "Copyright (c) 2011 by Just Be Nice studio. All rights reserved.", + "ascent": 850, + "descent": -150, + "weight": "Medium" + }, + "meta": { + "author": "Just Be Nice studio", + "homepage": "http://www.justbenicestudio.com/", + "email": "yes@justbenice.ru", + "license": "SIL", + "license_url": "http://scripts.sil.org/OFL", + "css_prefix_text": "icon-", + "columns": 4 + } + } +] -- cgit v1.2.3 From 4f100db4cb1ebb180ad619c6ba26b2910cbd36dd Mon Sep 17 00:00:00 2001 From: pml68 Date: Mon, 28 Apr 2025 23:46:44 +0200 Subject: ci: remove `libgtk-3-dev` dependency --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ae1107..a4d1301 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: run: | export DEBIAN_FRONTED=noninteractive sudo apt-get -qq update - sudo apt-get install -y libxkbcommon-dev libgtk-3-dev clang mold + sudo apt-get install -y libxkbcommon-dev clang mold - uses: actions/cache@v4 with: path: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 356e2e9..e2316f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: run: | export DEBIAN_FRONTED=noninteractive sudo apt-get -qq update - sudo apt-get install -y libxkbcommon-dev libgtk-3-dev clang mold + sudo apt-get install -y libxkbcommon-dev clang mold - uses: actions/cache@v4 with: path: | -- cgit v1.2.3 From 74ce597cf1ba4f2f28436d84e019baf171d15b48 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 29 Apr 2025 00:19:13 +0200 Subject: chore: remove `theme_test`, dependency cleanup --- Cargo.lock | 87 ++++++------ Cargo.toml | 7 +- crates/material_theme/Cargo.toml | 6 +- theme_test/Cargo.toml | 11 -- theme_test/src/main.rs | 276 --------------------------------------- 5 files changed, 48 insertions(+), 339 deletions(-) delete mode 100644 theme_test/Cargo.toml delete mode 100644 theme_test/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 02b475d..96ac115 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,14 +232,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", + "pin-project-lite", "slab", ] @@ -1941,7 +1942,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_core", "iced_debug", @@ -1976,7 +1977,7 @@ dependencies = [ [[package]] name = "iced_beacon" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bincode", "futures", @@ -2017,7 +2018,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2046,7 +2047,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_beacon", "iced_core", @@ -2056,7 +2057,7 @@ dependencies = [ [[package]] name = "iced_devtools" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_debug", "iced_program", @@ -2094,7 +2095,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "futures", "iced_core", @@ -2108,7 +2109,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2129,7 +2130,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_graphics", "iced_runtime", @@ -2138,7 +2139,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2150,7 +2151,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bytes", "iced_core", @@ -2163,7 +2164,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bytemuck", "cosmic-text", @@ -2180,7 +2181,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2201,7 +2202,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_renderer", "iced_runtime", @@ -2219,7 +2220,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#11c915418f2ad45922d3ca9c113e8c2352497067" dependencies = [ "iced_debug", "iced_program", @@ -2554,9 +2555,9 @@ dependencies = [ [[package]] name = "kurbo" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +checksum = "1077d333efea6170d9ccb96d3c3026f300ca0773da4938cc4c811daa6df68b0c" dependencies = [ "arrayvec", "smallvec", @@ -4600,7 +4601,7 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" dependencies = [ - "kurbo 0.11.1", + "kurbo 0.11.2", "siphasher", ] @@ -4737,16 +4738,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "theme_test" -version = "0.0.1" -dependencies = [ - "iced", - "iced_anim", - "iced_dialog", - "material_theme", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -4954,9 +4945,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -4975,9 +4966,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.25" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", @@ -4989,9 +4980,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" [[package]] name = "tower" @@ -5210,7 +5201,7 @@ dependencies = [ "flate2", "fontdb 0.18.0", "imagesize", - "kurbo 0.11.1", + "kurbo 0.11.2", "log", "pico-args", "roxmltree", @@ -5414,9 +5405,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +checksum = "c2bea670be0e24795f39416e5461ccef0185b47df2749ed2b226b8a7557ac871" dependencies = [ "cc", "downcast-rs", @@ -5428,9 +5419,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.8" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +checksum = "5029b0ff4f7be961c326169ee8e247d534d8507dbe390cac6aa3d2cc7c268825" dependencies = [ "bitflags 2.9.0", "rustix 0.38.44", @@ -5451,9 +5442,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.8" +version = "0.31.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +checksum = "28d6ec438d7c38bde05a10e80c3e3a1212d85f941be9fc9f80c86e6f5f498252" dependencies = [ "rustix 0.38.44", "wayland-client", @@ -5462,9 +5453,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.6" +version = "0.32.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +checksum = "ba8de1f9dda5e589d08848af3ad4cd694bbfd059c3eb3c6d89c7120e8c0efa71" dependencies = [ "bitflags 2.9.0", "wayland-backend", @@ -5474,9 +5465,9 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +checksum = "87e10c27e3290310d7e0d3221bc4e945d9b296b249577af2eb595726b546a3f8" dependencies = [ "bitflags 2.9.0", "wayland-backend", @@ -5487,9 +5478,9 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" +checksum = "9f3334ee752fbe3c228adfda339a9e7a03e0ba65a78806d8d464b69928cf4ef2" dependencies = [ "bitflags 2.9.0", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index 9ffaa5d..a653682 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,14 +35,14 @@ thiserror = "2.0.12" dirs-next = "2.0.0" [workspace.dependencies] +iced_widget = "0.14.0-dev" iced_anim = { version = "0.2.1", features = ["derive"] } iced_dialog = { git = "https://github.com/pml68/iced_dialog", branch = "iced/personal" } serde = { version = "1.0.219", features = ["derive"] } toml = "0.8.21" [workspace.dependencies.iced] -git = "https://github.com/pml68/iced" -branch = "feat/rehighlight-on-redraw" +version = "0.14.0-dev" default-features = false features = ["wgpu", "tiny-skia", "web-colors", "auto-detect-theme", "advanced", "tokio", "image", "svg", "lazy"] @@ -75,7 +75,7 @@ name = "iced-builder" path = "src/main.rs" [workspace] -members = ["crates/*", "theme_test"] +members = ["crates/*"] default-members = ["crates/material_theme", "."] [lints.rust] @@ -100,5 +100,6 @@ useless_conversion = "deny" clone_on_copy = "deny" [patch.crates-io] +iced = { git = "https://github.com/pml68/iced", branch = "feat/rehighlight-on-redraw" } iced_anim = { git = "https://github.com/pml68/iced_anim" } iced_widget = { git = "https://github.com/pml68/iced", branch = "feat/rehighlight-on-redraw" } diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index 30de38b..0116c1e 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -29,7 +29,6 @@ svg = ["iced_widget/svg"] qr_code = ["iced_widget/qr_code"] [dependencies] -iced_widget = "0.14.0-dev" dark-light = "2.0.0" serde.workspace = true @@ -38,6 +37,11 @@ serde.optional = true iced_dialog.workspace = true iced_dialog.optional = true +[dependencies.iced_widget] +version = "0.14.0-dev" +git = "https://github.com/pml68/iced" +branch = "feat/rehighlight-on-redraw" + [dependencies.iced_anim] workspace = true features = ["derive"] diff --git a/theme_test/Cargo.toml b/theme_test/Cargo.toml deleted file mode 100644 index 300a7af..0000000 --- a/theme_test/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "theme_test" -version = "0.0.1" -edition = "2024" - -[dependencies] -iced.workspace = true -iced.features = ["debug"] -iced_anim.workspace = true -iced_dialog.workspace = true -material_theme = { path = "../crates/material_theme", features = ["dialog", "animate"] } diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs deleted file mode 100644 index cba4377..0000000 --- a/theme_test/src/main.rs +++ /dev/null @@ -1,276 +0,0 @@ -use iced::widget::{ - button, center, checkbox, column, container, horizontal_rule, pane_grid, - pick_list, progress_bar, radio, row, slider, text_editor, text_input, - toggler, -}; -use iced::{Element, Length}; -use iced_anim::{Animated, Animation, Event}; -use iced_dialog::dialog; -use material_theme::Theme; -use material_theme::button::{elevated, filled_tonal, outlined, text}; -use material_theme::container::{ - error, error_container, inverse_surface, primary, primary_container, - secondary, secondary_container, surface, surface_container, - surface_container_high, surface_container_highest, surface_container_low, - surface_container_lowest, tertiary, tertiary_container, -}; -use material_theme::text::surface_variant; - -fn main() -> iced::Result { - iced::application(State::default, State::update, State::view) - .theme(|state| state.theme.value().clone()) - .run() -} - -#[allow(dead_code)] -#[derive(Debug, Clone)] -enum Message { - Noop, - OpenDialog, - CloseDialog, - Input(String), - Bool(bool), - Radio(Choice), - Slider(f32), - Edit(text_editor::Action), - Resize(pane_grid::ResizeEvent), - SwitchTheme(Event), -} - -#[derive(Debug)] -pub struct State { - theme: Animated, - show_dialog: bool, - content: String, - is_checked: bool, - selection: Option, - value: f32, - editor_content: text_editor::Content, - panes: pane_grid::State, -} - -impl Default for State { - fn default() -> Self { - Self { - theme: Default::default(), - show_dialog: Default::default(), - content: Default::default(), - is_checked: Default::default(), - selection: Default::default(), - value: Default::default(), - editor_content: text_editor::Content::new(), - panes: pane_grid::State::with_configuration( - pane_grid::Configuration::Split { - axis: pane_grid::Axis::Vertical, - ratio: 0.5, - a: Box::new(pane_grid::Configuration::Pane(Pane::Left)), - b: Box::new(pane_grid::Configuration::Pane(Pane::Right)), - }, - ), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Choice { - A, - B, - C, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Pane { - Left, - Right, -} - -impl State { - fn update(&mut self, message: Message) { - match message { - Message::Noop => {} - Message::OpenDialog => { - self.show_dialog = true; - } - Message::CloseDialog => { - self.show_dialog = false; - } - Message::Input(content) => self.content = content, - Message::Bool(is_checked) => self.is_checked = is_checked, - Message::Radio(choice) => self.selection = Some(choice), - Message::Slider(value) => self.value = value, - Message::Edit(action) => self.editor_content.perform(action), - Message::Resize(pane_grid::ResizeEvent { split, ratio }) => { - self.panes.resize(split, ratio); - } - Message::SwitchTheme(event) => { - self.theme.update(event); - } - } - } - fn view(&self) -> Element<'_, Message, Theme> { - let base: pane_grid::PaneGrid<'_, Message, Theme> = - pane_grid(&self.panes, |_pane, state, _is_maximized| { - pane_grid::Content::new(match state { - Pane::Left => container( - row![ - column![ - button("Disabled"), - button("Filled").on_press(Message::Noop), - button("Filled Tonal") - .on_press(Message::Noop) - .style(filled_tonal), - button("Elevated") - .on_press(Message::Noop) - .style(elevated), - button("Outlined") - .on_press(Message::Noop) - .style(outlined), - button("Text") - .on_press(Message::Noop) - .style(text), - button("Text Disabled").style(text), - ] - .spacing(10), - column![ - container("None").padding(8), - container("Primary").padding(8).style(primary), - container("Primary Container") - .padding(8) - .style(primary_container), - container("Secondary") - .padding(8) - .style(secondary), - container("Secondary Container") - .padding(8) - .style(secondary_container), - container("Tertiary") - .padding(8) - .style(tertiary), - container("Tertiary Container") - .padding(8) - .style(tertiary_container), - container("Error").padding(8).style(error), - container("Error Container") - .padding(8) - .style(error_container), - container("Surface").padding(8).style(surface), - container( - iced::widget::text("Surface Variant") - .style(surface_variant) - ) - .padding(8) - .style(surface), - container("Inverse Surface") - .padding(8) - .style(inverse_surface), - container("Surface Container Lowest") - .padding(8) - .style(surface_container_lowest), - container("Surface Container Low") - .padding(8) - .style(surface_container_low), - container("Surface Container") - .padding(8) - .style(surface_container), - container("Surface Container High") - .padding(8) - .style(surface_container_high), - container("Surface Container Highest") - .padding(8) - .style(surface_container_highest), - ] - .spacing(10), - ] - .spacing(10), - ) - .width(Length::Fill) - .height(Length::Fill) - .padding(12), - - Pane::Right => container( - column![ - // Pick List - pick_list( - Theme::ALL, - Some(self.theme.target()), - |theme| Message::SwitchTheme(theme.into()) - ) - .placeholder("Select a theme..."), - horizontal_rule(1), - // Dialog - button("Open Dialog").on_press(Message::OpenDialog), - horizontal_rule(1), - // Text Input - text_input("Type something here...", &self.content) - .on_input(Message::Input), - text_input("Disabled", "Disabled"), - horizontal_rule(1), - // Checkbox - checkbox("Normal", self.is_checked) - .on_toggle(Message::Bool), - checkbox("Error", self.is_checked) - .on_toggle(Message::Bool) - .style(material_theme::checkbox::error), - checkbox("Disabled", self.is_checked), - horizontal_rule(1), - // Radio - radio( - "A", - Choice::A, - self.selection, - Message::Radio, - ), - radio( - "B", - Choice::B, - self.selection, - Message::Radio, - ), - radio( - "C", - Choice::C, - self.selection, - Message::Radio, - ), - horizontal_rule(1), - // Slider - center(iced::widget::text!("{:.1}", self.value)) - .width(Length::Fill) - .height(Length::Shrink), - slider(0.0..=100.0, self.value, Message::Slider) - .step(0.1), - progress_bar(0.0..=100.0, self.value), - horizontal_rule(1), - // Toggler - toggler(self.is_checked) - .on_toggle(Message::Bool) - .size(24.0), - toggler(self.is_checked).size(24.0), - horizontal_rule(1), - // Text Editor - text_editor(&self.editor_content) - .on_action(Message::Edit), - text_editor(&self.editor_content) - .placeholder("Disabled") - ] - .spacing(10), - ) - .width(Length::Fill) - .height(Length::Fill) - .padding(12), - }) - }) - .on_resize(10, Message::Resize); - - let dialog = - dialog(self.show_dialog, base, iced::widget::text("Say Hi!")) - .title("This is a Dialog.") - .push_button(iced_dialog::button("Hi!", Message::CloseDialog)) - .width(280) - .height(186); - - Animation::new(&self.theme, dialog) - .on_update(Message::SwitchTheme) - .into() - } -} -- cgit v1.2.3 From 0c12ef78b697c0f57ac1d35bcfcd089cb269a433 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 29 Apr 2025 23:32:01 +0200 Subject: fix(material_theme): broken serde impl on `Theme` --- crates/material_theme/src/lib.rs | 191 ++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 81 deletions(-) diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 7b6ac58..b04edf0 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -1,7 +1,8 @@ +use std::borrow::Cow; use std::sync::LazyLock; -use iced_widget::core::Color; use iced_widget::core::theme::{Base, Style}; +use iced_widget::core::{Color, color}; use utils::{lightness, mix}; pub mod button; @@ -49,6 +50,7 @@ macro_rules! from_argb { #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(from = "Custom", into = "Custom"))] pub enum Theme { Dark, Light, @@ -58,27 +60,22 @@ pub enum Theme { impl Theme { pub const ALL: &'static [Self] = &[Self::Dark, Self::Light]; - pub fn new(name: impl Into, colorscheme: ColorScheme) -> Self { + pub fn new( + name: impl Into>, + colorscheme: ColorScheme, + ) -> Self { Self::Custom(Custom { name: name.into(), - colorscheme, is_dark: lightness(colorscheme.surface.color) <= 0.5, + colorscheme, }) } - pub fn name(&self) -> &str { + pub fn name(&self) -> Cow<'static, str> { match self { - Self::Dark => "Dark", - Self::Light => "Light", - Self::Custom(custom) => &custom.name, - } - } - - pub fn colors(&self) -> ColorScheme { - match self { - Self::Dark => ColorScheme::DARK, - Self::Light => ColorScheme::LIGHT, - Self::Custom(custom) => custom.colorscheme, + Self::Dark => "Dark".into(), + Self::Light => "Light".into(), + Self::Custom(custom) => custom.name.clone(), } } @@ -89,6 +86,14 @@ impl Theme { Self::Custom(custom) => custom.is_dark, } } + + pub fn colors(&self) -> ColorScheme { + match self { + Self::Dark => ColorScheme::DARK, + Self::Light => ColorScheme::LIGHT, + Self::Custom(custom) => custom.colorscheme, + } + } } impl Default for Theme { @@ -144,7 +149,11 @@ impl iced_anim::Animate for Theme { fn update(&mut self, components: &mut impl Iterator) { let mut colorscheme = self.colors(); colorscheme.update(components); - *self = Self::new("Animating Theme", colorscheme); + *self = Self::Custom(Custom { + name: "Animating Theme".into(), + is_dark: self.is_dark(), + colorscheme, + }); } fn distance_to(&self, end: &Self) -> Vec { @@ -154,32 +163,52 @@ impl iced_anim::Animate for Theme { fn lerp(&mut self, start: &Self, end: &Self, progress: f32) { let mut colorscheme = self.colors(); colorscheme.lerp(&start.colors(), &end.colors(), progress); - *self = Self::new("Animating Theme", colorscheme); + *self = Self::Custom(Custom { + name: "Animating Theme".into(), + is_dark: self.is_dark(), + colorscheme, + }); } } #[derive(Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Custom { - pub name: String, + pub name: Cow<'static, str>, + pub is_dark: bool, #[cfg_attr(feature = "serde", serde(flatten))] pub colorscheme: ColorScheme, - pub is_dark: bool, +} + +impl From for Theme { + fn from(custom: Custom) -> Self { + Self::Custom(custom) + } +} + +impl From for Custom { + fn from(theme: Theme) -> Self { + Self { + name: theme.name(), + is_dark: theme.is_dark(), + colorscheme: theme.colors(), + } + } } impl Clone for Custom { fn clone(&self) -> Self { Self { name: self.name.clone(), - colorscheme: self.colorscheme, is_dark: self.is_dark, + colorscheme: self.colorscheme, } } fn clone_from(&mut self, source: &Self) { self.name.clone_from(&source.name); - self.colorscheme = source.colorscheme; self.is_dark = source.is_dark; + self.colorscheme = source.colorscheme; } } @@ -204,101 +233,101 @@ pub struct ColorScheme { impl ColorScheme { const DARK: Self = Self { primary: Primary { - color: from_argb!(0xff9bd4a1), - on_primary: from_argb!(0xff003916), - primary_container: from_argb!(0xff1b5129), - on_primary_container: from_argb!(0xffb6f1bb), + color: color!(0x9bd4a1), + on_primary: color!(0x003916), + primary_container: color!(0x1b5129), + on_primary_container: color!(0xb6f1bb), }, secondary: Secondary { - color: from_argb!(0xffb8ccb6), - on_secondary: from_argb!(0xff233425), - secondary_container: from_argb!(0xff394b3a), - on_secondary_container: from_argb!(0xffd3e8d1), + color: color!(0xb8ccb6), + on_secondary: color!(0x233425), + secondary_container: color!(0x394b3a), + on_secondary_container: color!(0xd3e8d1), }, tertiary: Tertiary { - color: from_argb!(0xffa1ced7), - on_tertiary: from_argb!(0xff00363e), - tertiary_container: from_argb!(0xff1f4d55), - on_tertiary_container: from_argb!(0xffbdeaf4), + color: color!(0xa1ced7), + on_tertiary: color!(0x00363e), + tertiary_container: color!(0x1f4d55), + on_tertiary_container: color!(0xbdeaf4), }, error: Error { - color: from_argb!(0xffffb4ab), - on_error: from_argb!(0xff690005), - error_container: from_argb!(0xff93000a), - on_error_container: from_argb!(0xffffdad6), + color: color!(0xffb4ab), + on_error: color!(0x690005), + error_container: color!(0x93000a), + on_error_container: color!(0xffdad6), }, surface: Surface { - color: from_argb!(0xff101510), - on_surface: from_argb!(0xffe0e4dc), - on_surface_variant: from_argb!(0xffc1c9be), + color: color!(0x101510), + on_surface: color!(0xe0e4dc), + on_surface_variant: color!(0xc1c9be), surface_container: SurfaceContainer { - lowest: from_argb!(0xff0b0f0b), - low: from_argb!(0xff181d18), - base: from_argb!(0xff1c211c), - high: from_argb!(0xff262b26), - highest: from_argb!(0xff313631), + lowest: color!(0x0b0f0b), + low: color!(0x181d18), + base: color!(0x1c211c), + high: color!(0x262b26), + highest: color!(0x313631), }, }, inverse: Inverse { - inverse_surface: from_argb!(0xffe0e4dc), - inverse_on_surface: from_argb!(0xff2d322c), - inverse_primary: from_argb!(0xff34693f), + inverse_surface: color!(0xe0e4dc), + inverse_on_surface: color!(0x2d322c), + inverse_primary: color!(0x34693f), }, outline: Outline { - color: from_argb!(0xff8b9389), - variant: from_argb!(0xff414941), + color: color!(0x8b9389), + variant: color!(0x414941), }, - shadow: from_argb!(0xff000000), + shadow: color!(0x000000), scrim: from_argb!(0x4d000000), }; const LIGHT: Self = Self { primary: Primary { - color: from_argb!(0xff34693f), - on_primary: from_argb!(0xffffffff), - primary_container: from_argb!(0xffb6f1bb), - on_primary_container: from_argb!(0xff1b5129), + color: color!(0x34693f), + on_primary: color!(0xffffff), + primary_container: color!(0xb6f1bb), + on_primary_container: color!(0x1b5129), }, secondary: Secondary { - color: from_argb!(0xff516351), - on_secondary: from_argb!(0xffffffff), - secondary_container: from_argb!(0xffd3e8d1), - on_secondary_container: from_argb!(0xff394b3a), + color: color!(0x516351), + on_secondary: color!(0xffffff), + secondary_container: color!(0xd3e8d1), + on_secondary_container: color!(0x394b3a), }, tertiary: Tertiary { - color: from_argb!(0xff39656d), - on_tertiary: from_argb!(0xffffffff), - tertiary_container: from_argb!(0xffbdeaf4), - on_tertiary_container: from_argb!(0xff1f4d55), + color: color!(0x39656d), + on_tertiary: color!(0xffffff), + tertiary_container: color!(0xbdeaf4), + on_tertiary_container: color!(0x1f4d55), }, error: Error { - color: from_argb!(0xffba1a1a), - on_error: from_argb!(0xffffffff), - error_container: from_argb!(0xffffdad6), - on_error_container: from_argb!(0xff93000a), + color: color!(0xba1a1a), + on_error: color!(0xffffff), + error_container: color!(0xffdad6), + on_error_container: color!(0x93000a), }, surface: Surface { - color: from_argb!(0xfff7fbf2), - on_surface: from_argb!(0xff181d18), - on_surface_variant: from_argb!(0xff414941), + color: color!(0xf7fbf2), + on_surface: color!(0x181d18), + on_surface_variant: color!(0x414941), surface_container: SurfaceContainer { - lowest: from_argb!(0xffffffff), - low: from_argb!(0xfff1f5ed), - base: from_argb!(0xffebefe7), - high: from_argb!(0xffe5e9e1), - highest: from_argb!(0xffe0e4dc), + lowest: color!(0xffffff), + low: color!(0xf1f5ed), + base: color!(0xebefe7), + high: color!(0xe5e9e1), + highest: color!(0xe0e4dc), }, }, inverse: Inverse { - inverse_surface: from_argb!(0xff2d322c), - inverse_on_surface: from_argb!(0xffeef2ea), - inverse_primary: from_argb!(0xff9bd4a1), + inverse_surface: color!(0x2d322c), + inverse_on_surface: color!(0xeef2ea), + inverse_primary: color!(0x9bd4a1), }, outline: Outline { - color: from_argb!(0xff727970), - variant: from_argb!(0xffc1c9be), + color: color!(0x727970), + variant: color!(0xc1c9be), }, - shadow: from_argb!(0xff000000), + shadow: color!(0x000000), scrim: from_argb!(0x4d000000), }; } -- cgit v1.2.3 From 0faeafa482e2b21d8021d3150e7341131a1db7bd Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 29 Apr 2025 23:32:53 +0200 Subject: fix(material_theme): missing `abs` when checking the alpha values in `mix` --- crates/material_theme/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/material_theme/src/utils.rs b/crates/material_theme/src/utils.rs index 963c9fc..4c62ec3 100644 --- a/crates/material_theme/src/utils.rs +++ b/crates/material_theme/src/utils.rs @@ -116,7 +116,7 @@ pub fn mix(color1: Color, color2: Color, p2: f32) -> Color { let p1 = 1.0 - p2; if (color1.a - 1.0).abs() > COLOR_ERROR_MARGIN - || (color2.a - 1.0) > COLOR_ERROR_MARGIN + || (color2.a - 1.0).abs() > COLOR_ERROR_MARGIN { let a = color1.a * p1 + color2.a * p2; if a > 0.0 { -- cgit v1.2.3 From 9ecd689c2b708894b9cf88576aa8dfa5b5797a63 Mon Sep 17 00:00:00 2001 From: pml68 Date: Tue, 29 Apr 2025 23:33:07 +0200 Subject: style: `theme` -> `appearance` --- src/config.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7f6f8ce..369a505 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,17 +14,17 @@ use crate::{Error, environment}; #[derive(Debug, Clone, Default)] pub struct Config { - theme: Appearance, + appearance: Appearance, last_project: Option, } impl Config { pub fn selected_theme(&self) -> Theme { - self.theme.selected.clone() + self.appearance.selected.clone() } pub fn themes(&self) -> Arc<[Theme]> { - self.theme.all.clone() + self.appearance.all.clone() } pub fn last_project(&self) -> Option<&Path> { @@ -77,10 +77,11 @@ impl Config { last_project, } = toml::from_str(content.as_ref())?; - let theme = Self::load_appearance(&theme).await.unwrap_or_default(); + let appearance = + Self::load_appearance(&theme).await.unwrap_or_default(); Ok(Self { - theme, + appearance, last_project, }) } -- cgit v1.2.3