UI overhaul rebase
This commit is contained in:
13
dioxus-free-icons/packages/codegen/Cargo.toml
Normal file
13
dioxus-free-icons/packages/codegen/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "dioxus-fontawesome-examples"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
codegen = "0.1.3"
|
||||
heck = "0.4.0"
|
||||
regex = "1.6.0"
|
||||
scraper = "0.13.0"
|
||||
walkdir = "2.3.2"
|
||||
215
dioxus-free-icons/packages/codegen/src/create_icon_file.rs
Normal file
215
dioxus-free-icons/packages/codegen/src/create_icon_file.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{ffi::OsStr, path::Path};
|
||||
|
||||
use heck::ToSnakeCase;
|
||||
use heck::ToUpperCamelCase;
|
||||
use regex::Regex;
|
||||
use scraper::node::Element;
|
||||
use scraper::ElementRef;
|
||||
use scraper::Html;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
const ICON_TEMPLATE: &str = r#"#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct {ICON_NAME};
|
||||
impl IconShape for {ICON_NAME} {
|
||||
fn view_box(&self) -> &str {
|
||||
"{VIEW_BOX}"
|
||||
}
|
||||
fn xmlns(&self) -> &str {
|
||||
"{XMLNS}"
|
||||
}
|
||||
fn fill_and_stroke<'a>(&self, user_color: &'a str) -> (&'a str, &'a str, &'a str) {
|
||||
({FILL_COLOR}, {STROKE_COLOR}, {STROKE_WIDTH})
|
||||
}
|
||||
fn stroke_linecap(&self) -> &str {
|
||||
"{STROKE_LINECAP}"
|
||||
}
|
||||
fn stroke_linejoin(&self) -> &str {
|
||||
"{STROKE_LINEJOIN}"
|
||||
}
|
||||
fn child_elements(&self) -> Element {
|
||||
rsx! {
|
||||
{CHILD_ELEMENTS}
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
pub fn create_icon_file(svg_path: &str, output_path: &str, icon_prefix: &str) {
|
||||
let files = collect_svg_files(svg_path, icon_prefix);
|
||||
|
||||
let icon_file = files
|
||||
.into_iter()
|
||||
.map(|file| {
|
||||
let svg_str = fs::read_to_string(&file).unwrap();
|
||||
let fragment = Html::parse_fragment(&svg_str);
|
||||
|
||||
let elements = fragment
|
||||
.tree
|
||||
.nodes()
|
||||
.filter_map(|node| {
|
||||
if node.value().is_element() {
|
||||
let element = ElementRef::wrap(node).unwrap().value();
|
||||
if !element.attrs.is_empty() {
|
||||
return Some(element);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let svg_element = &elements[0];
|
||||
let svg_child_elements = &elements[1..];
|
||||
let icon_name = icon_name(&file, icon_prefix);
|
||||
let (view_box, xmlns) = extract_svg_attrs(svg_element);
|
||||
let child_elements = extract_svg_child_elements(svg_child_elements, icon_prefix);
|
||||
let (fill_color, stroke_color, stroke_width) = extract_svg_colors(icon_prefix);
|
||||
let stroke_linecap = extract_stroke_linecap(icon_prefix);
|
||||
let stroke_linejoin = extract_stroke_linejoin(icon_prefix);
|
||||
|
||||
ICON_TEMPLATE
|
||||
.replace("{ICON_NAME}", &format!("{}{}", icon_prefix, &icon_name))
|
||||
.replace("{VIEW_BOX}", &view_box)
|
||||
.replace("{XMLNS}", &xmlns)
|
||||
.replace("{CHILD_ELEMENTS}", &child_elements)
|
||||
.replace("{FILL_COLOR}", &fill_color)
|
||||
.replace("{STROKE_COLOR}", &stroke_color)
|
||||
.replace("{STROKE_WIDTH}", &stroke_width)
|
||||
.replace("{STROKE_LINECAP}", &stroke_linecap)
|
||||
.replace("{STROKE_LINEJOIN}", &stroke_linejoin)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
// write to file
|
||||
let mut file = File::create(output_path).unwrap();
|
||||
file.write_all(
|
||||
format!(
|
||||
"{}\n\n{}",
|
||||
"use super::super::IconShape;\nuse dioxus::prelude::*;", icon_file
|
||||
)
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
file.flush().unwrap();
|
||||
}
|
||||
|
||||
fn collect_svg_files(svg_path: &str, icon_prefix: &str) -> Vec<PathBuf> {
|
||||
let dir_entries = WalkDir::new(svg_path)
|
||||
.sort_by_file_name()
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
dir_entries
|
||||
.into_iter()
|
||||
.filter(|e| match icon_prefix {
|
||||
"Go" => {
|
||||
let re = Regex::new(r".*-16.svg$").unwrap();
|
||||
return re.is_match(e.path().to_str().unwrap());
|
||||
}
|
||||
"Md" => {
|
||||
let split_vec = e.path().components().collect::<Vec<_>>();
|
||||
return split_vec.iter().any(|c| c.as_os_str() == "materialicons")
|
||||
&& e.file_name().to_str().unwrap() == "24px.svg";
|
||||
}
|
||||
_ => return e.path().extension() == Some(OsStr::new("svg")),
|
||||
})
|
||||
.map(|dir| PathBuf::from(dir.path()))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn icon_name(path: &Path, icon_prefix: &str) -> String {
|
||||
match icon_prefix {
|
||||
"Go" => {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let name = filename.split('.').next().unwrap();
|
||||
name.replace("-16", "").to_upper_camel_case()
|
||||
}
|
||||
"Md" => {
|
||||
let split_vec = path.components().collect::<Vec<_>>();
|
||||
let name = split_vec[split_vec.len() - 3];
|
||||
name.as_os_str().to_str().unwrap().to_upper_camel_case()
|
||||
}
|
||||
_ => {
|
||||
let filename = path.file_name().unwrap().to_str().unwrap();
|
||||
let name = filename.split('.').next().unwrap();
|
||||
name.to_upper_camel_case()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_svg_attrs(element: &Element) -> (String, String) {
|
||||
let view_box = element.attr("viewBox").unwrap_or("0 0 16 16");
|
||||
let xmlns = element
|
||||
.attr("xmlns")
|
||||
.unwrap_or("http://www.w3.org/2000/svg");
|
||||
(String::from(view_box), String::from(xmlns))
|
||||
}
|
||||
|
||||
fn extract_svg_colors(icon_prefix: &str) -> (&str, &str, &str) {
|
||||
match icon_prefix {
|
||||
"Fi" => ("\"none\"", "user_color", "\"2\""),
|
||||
"Ld" => ("\"none\"", "user_color", "\"2\""),
|
||||
"Io" => ("user_color", "user_color", "\"0\""),
|
||||
_ => ("user_color", "\"none\"", "\"0\""),
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_stroke_linecap(icon_prefix: &str) -> &str {
|
||||
match icon_prefix {
|
||||
"Ld" => "round",
|
||||
"Fi" => "round",
|
||||
_ => "butt",
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_stroke_linejoin(icon_prefix: &str) -> &str {
|
||||
match icon_prefix {
|
||||
"Ld" => "round",
|
||||
"Fi" => "round",
|
||||
_ => "miter",
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_svg_child_elements(elements: &[&Element], icon_prefix: &str) -> String {
|
||||
let elements = match icon_prefix {
|
||||
"Md" => &elements[1..],
|
||||
_ => elements,
|
||||
};
|
||||
elements
|
||||
.iter()
|
||||
.map(|element| {
|
||||
let tag_name = element.name();
|
||||
let mut element_attrs = element
|
||||
.attrs()
|
||||
.filter_map(|(name, value)| {
|
||||
let value = if icon_prefix == "Io" {
|
||||
value.replace("fill:none;stroke:#000;", "")
|
||||
} else {
|
||||
value.to_string()
|
||||
};
|
||||
let re = Regex::new(r"^data-.*$").unwrap();
|
||||
if !re.is_match(name) && name != "fill" {
|
||||
Some(format!(
|
||||
" {}: \"{}\",",
|
||||
name.to_snake_case(),
|
||||
value
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
element_attrs.sort();
|
||||
let attrs_str = element_attrs.join("\n");
|
||||
" {TAG_NAME} {\n{ATTRS}\n }"
|
||||
.replace("{TAG_NAME}", tag_name)
|
||||
.replace("{ATTRS}", &attrs_str)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
79
dioxus-free-icons/packages/codegen/src/main.rs
Normal file
79
dioxus-free-icons/packages/codegen/src/main.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
mod create_icon_file;
|
||||
|
||||
fn main() {
|
||||
const OUTPUT_BASE_PATH: &str = "../lib/src/icons";
|
||||
|
||||
// create font awesome icons
|
||||
const FA_SVG_BASE_PATH: &str = "../../icon_resources/font-awesome/svgs";
|
||||
for icon_type in vec!["brands", "regular", "solid"].into_iter() {
|
||||
let svg_path = format!("{}/{}", FA_SVG_BASE_PATH, icon_type);
|
||||
let output_path = format!("{}/fa_{}_icons.rs", OUTPUT_BASE_PATH, icon_type);
|
||||
create_icon_file::create_icon_file(&svg_path, &output_path, "Fa");
|
||||
}
|
||||
|
||||
// create hero icons
|
||||
const HI_SVG_BASE_PATH: &str = "../../icon_resources/heroicons/src";
|
||||
for icon_type in vec!["outline", "solid"].into_iter() {
|
||||
let svg_path = format!("{}/{}", HI_SVG_BASE_PATH, icon_type);
|
||||
let output_path = format!("{}/hi_{}_icons.rs", OUTPUT_BASE_PATH, icon_type);
|
||||
create_icon_file::create_icon_file(&svg_path, &output_path, "Hi");
|
||||
}
|
||||
|
||||
// create ionicons
|
||||
const IO_SVG_BASE_PATH: &str = "../../icon_resources/ionicons/src/svg";
|
||||
let output_path = format!("{}/io_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(IO_SVG_BASE_PATH, &output_path, "Io");
|
||||
|
||||
// create octicons
|
||||
const GO_SVG_BASE_PATH: &str = "../../icon_resources/octicons/icons";
|
||||
let go_output_path = format!("{}/go_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(GO_SVG_BASE_PATH, &go_output_path, "Go");
|
||||
|
||||
// create bootstrap icons
|
||||
const BS_SVG_BASE_PATH: &str = "../../icon_resources/bootstrap/icons";
|
||||
let bs_output_path = format!("{}/bs_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(BS_SVG_BASE_PATH, &bs_output_path, "Bs");
|
||||
|
||||
// create feather icons
|
||||
const FI_SVG_BASE_PATH: &str = "../../icon_resources/feather/icons";
|
||||
let fi_output_path = format!("{}/fi_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(FI_SVG_BASE_PATH, &fi_output_path, "Fi");
|
||||
|
||||
// create feather icons
|
||||
const LD_SVG_BASE_PATH: &str = "../../icon_resources/lucide/icons";
|
||||
let ld_output_path = format!("{}/ld_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(LD_SVG_BASE_PATH, &ld_output_path, "Ld");
|
||||
|
||||
// create material design icons
|
||||
const MI_SVG_BASE_PATH: &str = "../../icon_resources/material-design-icons/src";
|
||||
for icon_type in vec![
|
||||
"action",
|
||||
"alert",
|
||||
"av",
|
||||
"communication",
|
||||
"content",
|
||||
"device",
|
||||
"editor",
|
||||
"file",
|
||||
"hardware",
|
||||
"home",
|
||||
"image",
|
||||
"maps",
|
||||
"navigation",
|
||||
"notification",
|
||||
"places",
|
||||
"social",
|
||||
"toggle",
|
||||
]
|
||||
.into_iter()
|
||||
{
|
||||
let svg_path = format!("{}/{}", MI_SVG_BASE_PATH, icon_type);
|
||||
let output_path = format!("{}/md_{}_icons.rs", OUTPUT_BASE_PATH, icon_type);
|
||||
create_icon_file::create_icon_file(&svg_path, &output_path, "Md");
|
||||
}
|
||||
|
||||
// create vscode-codicons
|
||||
const VS_SVG_BASE_PATH: &str = "../../icon_resources/vscode-codicons/src/icons";
|
||||
let vs_output_path = format!("{}/vsc_icons.rs", OUTPUT_BASE_PATH);
|
||||
create_icon_file::create_icon_file(VS_SVG_BASE_PATH, &vs_output_path, "Vsc");
|
||||
}
|
||||
Reference in New Issue
Block a user