dioxus_material_icons/
lib.rs

1#![allow(non_snake_case)]
2#![warn(missing_docs)]
3
4//! # 🧬 Dioxus Material Icons
5//!
6//! This project provides a simple but configurable component to render Google's Material Icons in Dioxus.
7//!
8//! ## 🚀 How to get started
9//!
10//! `cargo add dioxus-material-icons`
11//!
12//! This project introduces two components:
13//!
14//! 1. [`MaterialIconStylesheet`](MaterialIconStylesheet)
15//! 2. [`MaterialIcon`](MaterialIcon)
16//!
17//! To be able to use the [`MaterialIcon`](MaterialIcon) component anywhere in your code, you first have to include
18//! a [`MaterialIconStylesheet`](MaterialIconStylesheet) component. When you want to use the default settings,
19//! just add it to your app's root component like this:
20//!
21//! ```no_rust
22//! MaterialIconStylesheet { }
23//! ```
24//!
25//! Have a look at the [`MaterialIconStylesheet`](MaterialIconStylesheet) docs for more options like self-hosting the icon font file.
26//!
27//! After that you can use the `MaterialIcon` component like you would expect it:
28//!
29//! ```no_rust
30//! MaterialIcon { name: "settings" }
31//! ```
32//!
33//! You can additionally specify the color and size.
34//!
35//! ```no_rust
36//! MaterialIcon {
37//!     name: "settings",
38//!     size: 24,
39//!     color: MaterialIconColor::Light,
40//! }
41//! ```
42//!
43//! ## 💡 Examples
44//!
45//! - [Button Example](https://github.com/lennartkloock/dioxus-material-icons/blob/main/examples/button.rs)
46//!
47//! ## 🔗 Useful links
48//!
49//! - [Overview of all icons](https://fonts.google.com/icons?selected=Material+Icons) (including names)
50//!
51//! ### Alternatives
52//!
53//! - [dioxus-free-icons](https://crates.io/crates/dioxus-free-icons) (Support for other icon packs)
54//!
55//! ## 📜 License
56//!
57//! This software is licensed under the terms of the MIT License.
58//!
59//! Note: All Material Icons are licensed under the Apache License 2.0.
60//!
61//! © 2023 Lennart Kloock
62
63use dioxus::prelude::*;
64
65/// Props for the [`MaterialIconStylesheet`](MaterialIconStylesheet) component
66#[derive(Props, PartialEq, Clone)]
67pub struct MaterialIconStylesheetProps {
68    /// Variant prop for the [`MaterialIconStylesheet`](MaterialIconStylesheet) component
69    ///
70    /// See [`MaterialIconVariant`](MaterialIconVariant) for more information.
71    #[props(default = MaterialIconVariant::Regular)]
72    pub variant: MaterialIconVariant,
73}
74
75/// Variants (also called categories) of the Material Icon font
76///
77/// See all variants [here](https://fonts.google.com/icons?selected=Material+Icons).
78#[derive(PartialEq, Clone)]
79pub enum MaterialIconVariant {
80    /// Regular
81    ///
82    /// Also called Filled.
83    Regular,
84    /// Outlined
85    Outlined,
86    /// Round
87    Round,
88    /// Sharp
89    Sharp,
90    /// Two tone
91    TwoTone,
92    /// Self hosted font file
93    ///
94    /// Provide an url to a ttf or otf file.
95    /// You can download the files [here](https://github.com/google/material-design-icons/tree/master/font).
96    SelfHosted(String),
97}
98
99/// Stylesheet component
100///
101/// This component includes the Material Icon stylesheet.
102/// This is required to render all Material Icons correctly.
103///
104/// You can provide a variant as a prop (e.g. Round).
105/// When you want to provide your own self-hosted font file,
106/// please use [`MaterialIconVariant::SelfHosted`](MaterialIconVariant::SelfHosted) and pass the
107/// file path or url to your .ttf or .otf file to it.
108/// See the [button example](https://github.com/lennartkloock/dioxus-material-icons/blob/main/examples/button.rs).
109pub fn MaterialIconStylesheet(props: MaterialIconStylesheetProps) -> Element {
110    let href = match &props.variant {
111        MaterialIconVariant::SelfHosted(file) => {
112            return rsx!(
113                style { {format!(include_str!("./self-hosted-styles.css"), file)} }
114            );
115        }
116        MaterialIconVariant::Regular => "https://fonts.googleapis.com/icon?family=Material+Icons",
117        MaterialIconVariant::Outlined => {
118            "https://fonts.googleapis.com/icon?family=Material+Icons+Outlined"
119        }
120        MaterialIconVariant::Round => {
121            "https://fonts.googleapis.com/icon?family=Material+Icons+Round"
122        }
123        MaterialIconVariant::Sharp => {
124            "https://fonts.googleapis.com/icon?family=Material+Icons+Sharp"
125        }
126        MaterialIconVariant::TwoTone => {
127            "https://fonts.googleapis.com/icon?family=Material+Icons+Two+Tone"
128        }
129    };
130    rsx!(document::Link {
131        href: "{href}",
132        rel: "stylesheet"
133    })
134}
135
136/// Props for the [`MaterialIcon`](MaterialIcon) component
137#[derive(Props, PartialEq, Clone)]
138pub struct MaterialIconProps {
139    /// Name (e.g. `home`)
140    ///
141    /// Browse all icons [here](https://fonts.google.com/icons?selected=Material+Icons).
142    #[props(into)]
143    pub name: String,
144    /// Size in pixels
145    ///
146    /// Optional
147    pub size: Option<u32>,
148    /// Color
149    ///
150    /// Optional
151    #[props(into)]
152    pub color: Option<MaterialIconColor>,
153}
154
155/// Colors of Material Icons
156///
157/// As described [here](https://developers.google.com/fonts/docs/material_icons#styling_icons_in_material_design).
158#[derive(PartialEq, Clone)]
159pub enum MaterialIconColor {
160    /// For using icons as black on a light background.
161    Dark,
162    /// For using icons as black on a light background.
163    DarkInactive,
164    /// For using icons as white on a dark background.
165    Light,
166    /// For using icons as white on a dark background.
167    LightInactive,
168    /// Custom color, any valid CSS color
169    ///
170    /// E.g.: `#0000ff` or `red`
171    Custom(String),
172}
173
174impl<T: Into<String>> From<T> for MaterialIconColor {
175    fn from(value: T) -> Self {
176        Self::Custom(value.into())
177    }
178}
179
180impl MaterialIconColor {
181    /// Converts the color to its corresponding CSS color
182    pub fn to_css_color(&self) -> &str {
183        match self {
184            MaterialIconColor::Dark => "rgba(0, 0, 0, 0.54)",
185            MaterialIconColor::DarkInactive => "rgba(0, 0, 0, 0.26)",
186            MaterialIconColor::Light => "rgba(255, 255, 255, 1)",
187            MaterialIconColor::LightInactive => "rgba(255, 255, 255, 0.3)",
188            MaterialIconColor::Custom(c) => c,
189        }
190    }
191}
192
193/// Create a new `MaterialIconColor::Custom` variant
194pub fn IconColor<T: Into<String>>(color: T) -> MaterialIconColor {
195    MaterialIconColor::Custom(color.into())
196}
197
198/// Material Icon component
199///
200/// This component can be used to render a Material Icon.
201pub fn MaterialIcon(props: MaterialIconProps) -> Element {
202    // The `font-size` attribute has to be explicitly declared as `inherit` because the stylesheet sets a default of 24px
203    let css_size = props
204        .size
205        .map(|s| format!("{s}px"))
206        .unwrap_or_else(|| "inherit".to_string());
207    let css_color = props
208        .color
209        .as_ref()
210        .map(|c| format!("color: {};", c.to_css_color()))
211        .unwrap_or_default();
212    rsx!(
213        span {
214            class: "material-icons material-icons-outlined material-icons-round material-icons-sharp material-icons-two-tone md-48",
215            style: "font-size: {css_size}; {css_color} user-select: none;",
216            {props.name}
217        }
218    )
219}