zen_rs/layouts/html/icon.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
//! This module contains the `icon_html` function for rendering an `Icon` component
//! into an SVG string with specified styles and attributes.
//!
//! The `icon_html` function takes an `Icon` component, extracts its properties
//! (such as foreground and background colors, width, height, viewBox, stroke
//! attributes, and paths), and generates an SVG element with the appropriate
//! attributes and content. The paths are wrapped inside `<path>` tags, and
//! the SVG attributes are applied accordingly, such as stroke and fill styles.
//!
//! # Example
//! ```rust
//! let icon = Icon::new()
//! .foreground_color((255, 0, 0))
//! .background_color((0, 0, 0))
//! .width(24)
//! .height(24)
//! .content(vec!["M10 10 H 90 V 90 H 10 Z"]);
//! let svg = icon_html(&icon);
//! assert_eq!(svg, r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 100 100" fill="rgb(0, 0, 0)" stroke="rgb(255, 0, 0)" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="1"><path d="M10 10 H 90 V 90 H 10 Z" fill="rgb(0, 0, 0)" /></svg>"#);
//! ```
use crate::components::{icon::Icon, XMLNS};
/// Renders an `Icon` component into an SVG string with the specified attributes
/// such as foreground and background colors, width, height, viewBox, and paths.
///
/// # Arguments
/// * `component` - A reference to an `Icon` component containing the properties
/// such as content (paths), size, stroke attributes, and colors.
///
/// # Returns
/// A string representing the SVG element that renders the icon with the
/// specified properties and styles.
///
/// # Example
/// ```rust
/// let icon = Icon::new()
/// .foreground_color((255, 0, 0))
/// .background_color((0, 0, 0))
/// .width(24)
/// .height(24)
/// .content(vec!["M10 10 H 90 V 90 H 10 Z"]);
/// let svg = icon_html(&icon);
/// assert_eq!(svg, r#"<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 100 100" fill="rgb(0, 0, 0)" stroke="rgb(255, 0, 0)" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="1"><path d="M10 10 H 90 V 90 H 10 Z" fill="rgb(0, 0, 0)" /></svg>"#);
/// ```
pub fn icon_html(component: &Icon) -> String {
let xmlns = XMLNS;
// data
let fg = component.get_foreground_color().to_string();
let bg = component.get_background_color().to_string();
let w = component.get_width();
let h = component.get_height();
let (bl, bt, bb, br) = component.get_view_box();
// content
let content = component.get_content();
// content formating
let first_path_wrap = |path: &str| format!(r#"<path stroke="none" d="{path}" fill="{bg}" />"#);
let path_wrap = |path: &str| format!(r#"<path d="{path}"/>"#);
let first = if let Some(path) = content.first() {
first_path_wrap(path)
} else {
"".to_string()
};
let content = &content[1..];
let paths: String = content.iter().map(|x| path_wrap(x)).collect();
// Specific svg attributes
let slp = component
.get_stroke_linecap()
.map(|x| format!(r#"stroke-linecap="{x}""#))
.unwrap_or_default();
let slj = component
.get_stroke_linejoin()
.map(|x| format!(r#"stroke-linejoin="{x}""#))
.unwrap_or_default();
let sw = component
.get_stroke_width()
.map(|x| format!(r#"stroke-width="{x}""#))
.unwrap_or_default();
let vb = format!(r#"viewBox="{bl} {bt} {bb} {br}""#);
// out
format!(
r#"
<svg xmlns="{xmlns}"
width="{w}"
height="{h}"
{vb}
fill="{bg}"
stroke="{fg}"
{slp}
{slj}
{sw}>
{first}
{paths}</svg>
"#
)
}