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}