mirror of
https://github.com/yewprint/yewprint
synced 2024-11-28 22:40:22 +00:00
Component Icon
This commit is contained in:
parent
0307fbea11
commit
066dc90444
8 changed files with 229 additions and 11 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -32,6 +32,8 @@ dependencies = [
|
||||||
name = "blueprint-rs"
|
name = "blueprint-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"regex",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"yew",
|
"yew",
|
||||||
|
@ -247,6 +249,15 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -366,6 +377,21 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
@ -440,6 +466,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
|
|
@ -13,3 +13,7 @@ crate-type = ["cdylib"]
|
||||||
wasm-bindgen = "^0.2"
|
wasm-bindgen = "^0.2"
|
||||||
yew = "0.17"
|
yew = "0.17"
|
||||||
web-sys = "0.3"
|
web-sys = "0.3"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
regex = { version = "1", default-features = false, features = ["std"] }
|
||||||
|
heck = "0.3"
|
||||||
|
|
58
build.rs
Normal file
58
build.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use heck::CamelCase;
|
||||||
|
use regex::Regex;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
const ICON_URL: &str = "https://registry.npmjs.org/@blueprintjs/icons/-/icons-3.19.0.tgz";
|
||||||
|
const ICON_PATH: &str = "package/lib/esnext/generated/iconSvgPaths.js";
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let icon_svg_paths = Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(format!(
|
||||||
|
"curl -sSLo - {} | tar xOzf - {}",
|
||||||
|
ICON_URL, ICON_PATH
|
||||||
|
))
|
||||||
|
.output()
|
||||||
|
.map(|x| String::from_utf8(x.stdout).expect("source file is not UTF-8"))?;
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let dest_path = Path::new(&out_dir).join("icon_svg_paths.rs");
|
||||||
|
|
||||||
|
let mut src = String::new();
|
||||||
|
let re_map = Regex::new(r"export const IconSvgPaths([0-9]+) = \{([^}]+)\};").unwrap();
|
||||||
|
let re_item = Regex::new(r#"(?m)(?s)"([^"]+)": (\[.*?\]),$"#).unwrap();
|
||||||
|
let mut keys = HashSet::new();
|
||||||
|
|
||||||
|
for map in re_map.captures_iter(icon_svg_paths.as_str()) {
|
||||||
|
src.push_str("fn icon_svg_paths_");
|
||||||
|
src.push_str(&map[1]);
|
||||||
|
src.push_str("(icon: IconName) -> &'static [&'static str] { match icon {\n");
|
||||||
|
for item in re_item.captures_iter(&map[2]) {
|
||||||
|
let key = item[1].to_camel_case();
|
||||||
|
src.push_str("IconName::");
|
||||||
|
src.push_str(&key);
|
||||||
|
src.push_str(" => &");
|
||||||
|
src.push_str(&item[2]);
|
||||||
|
src.push_str(",\n");
|
||||||
|
keys.insert(key);
|
||||||
|
}
|
||||||
|
src.push_str(" }}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut keys: Vec<_> = keys.iter().collect();
|
||||||
|
keys.sort();
|
||||||
|
src.push_str("#[derive(Debug, Copy, Clone, PartialEq)]\npub enum IconName {\n");
|
||||||
|
for icon in keys {
|
||||||
|
src.push_str(icon);
|
||||||
|
src.push_str(",\n");
|
||||||
|
}
|
||||||
|
src.push_str("}\n\n");
|
||||||
|
|
||||||
|
fs::write(&dest_path, src).unwrap();
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
1
build.sh
1
build.sh
|
@ -10,6 +10,7 @@ if ! [ -f core.tgz ]; then
|
||||||
curl -o core.tgz https://registry.npmjs.org/@blueprintjs/core/-/core-3.30.0.tgz
|
curl -o core.tgz https://registry.npmjs.org/@blueprintjs/core/-/core-3.30.0.tgz
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
mkdir -p static
|
||||||
rm -fR static/.gitignore static/*
|
rm -fR static/.gitignore static/*
|
||||||
tar xvzf core.tgz -C static --wildcards \*.css --transform='s/.*\///'
|
tar xvzf core.tgz -C static --wildcards \*.css --transform='s/.*\///'
|
||||||
wasm-pack build --no-typescript --target web --out-name wasm --out-dir ./static "${options[@]}" "$@"
|
wasm-pack build --no-typescript --target web --out-name wasm --out-dir ./static "${options[@]}" "$@"
|
||||||
|
|
11
src/app.rs
11
src/app.rs
|
@ -1,6 +1,7 @@
|
||||||
use crate::buttons::*;
|
use crate::buttons::Button;
|
||||||
use crate::collapse::*;
|
use crate::collapse::Collapse;
|
||||||
use crate::forms::controls::*;
|
use crate::forms::controls::Switch;
|
||||||
|
use crate::tree::Tree;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
const DARK_BG_COLOR: &str = "#30404d";
|
const DARK_BG_COLOR: &str = "#30404d";
|
||||||
|
@ -78,6 +79,7 @@ impl Component for App {
|
||||||
</Button>
|
</Button>
|
||||||
<Collapse
|
<Collapse
|
||||||
is_open=!self.collapsed
|
is_open=!self.collapsed
|
||||||
|
keep_children_mounted=true
|
||||||
>
|
>
|
||||||
<pre class="bp3-code-block">
|
<pre class="bp3-code-block">
|
||||||
<div>{"[INFO]: Installing wasm-bindgen..."}</div>
|
<div>{"[INFO]: Installing wasm-bindgen..."}</div>
|
||||||
|
@ -98,6 +100,9 @@ impl Component for App {
|
||||||
</pre>
|
</pre>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Tree />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
90
src/icon.rs
Normal file
90
src/icon.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/icon_svg_paths.rs"));
|
||||||
|
|
||||||
|
pub const SIZE_STANDARD: i32 = 16;
|
||||||
|
pub const SIZE_LARGE: i32 = 20;
|
||||||
|
|
||||||
|
pub struct Icon {
|
||||||
|
props: Props,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
pub struct Props {
|
||||||
|
pub icon: IconName,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub class: String,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub title: Option<String>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub color: Option<String>,
|
||||||
|
#[prop_or(16)]
|
||||||
|
pub icon_size: i32,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub onclick: Callback<MouseEvent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Icon {
|
||||||
|
type Message = ();
|
||||||
|
type Properties = Props;
|
||||||
|
|
||||||
|
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
|
||||||
|
Icon { props }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _msg: Self::Message) -> ShouldRender {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change(&mut self, props: Self::Properties) -> ShouldRender {
|
||||||
|
if self.props != props {
|
||||||
|
self.props = props;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self) -> Html {
|
||||||
|
let mut class = "bp3-icon ".to_string();
|
||||||
|
class.push_str(self.props.class.as_str());
|
||||||
|
|
||||||
|
let paths = if self.props.icon_size == SIZE_STANDARD {
|
||||||
|
icon_svg_paths_16(self.props.icon)
|
||||||
|
} else {
|
||||||
|
icon_svg_paths_20(self.props.icon)
|
||||||
|
};
|
||||||
|
let pixel_grid_size = if self.props.icon_size >= SIZE_LARGE {
|
||||||
|
SIZE_LARGE
|
||||||
|
} else {
|
||||||
|
SIZE_STANDARD
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<span class="bp3-icon" onclick={self.props.onclick.clone()}>
|
||||||
|
<svg
|
||||||
|
fill={self.props.color.clone().unwrap_or_default()}
|
||||||
|
data-icon={format!("{:?}", self.props.icon)}
|
||||||
|
width={self.props.icon_size}
|
||||||
|
height={self.props.icon_size}
|
||||||
|
viewBox={format!("0 0 {x} {x}", x=pixel_grid_size)}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
if let Some(title) = self.props.title.clone() {
|
||||||
|
html!(<desc>{title}</desc>)
|
||||||
|
} else {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
paths.iter()
|
||||||
|
.map(|x| html! {
|
||||||
|
<path d=x fillRule="evenodd" />
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod buttons;
|
pub mod buttons;
|
||||||
mod collapse;
|
pub mod collapse;
|
||||||
mod forms;
|
pub mod forms;
|
||||||
mod tree;
|
pub mod icon;
|
||||||
|
pub mod tree;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
|
35
src/tree.rs
35
src/tree.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::collapse::Collapse;
|
||||||
|
use crate::icon::{Icon, IconName};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct Tree {
|
pub struct Tree {
|
||||||
|
@ -5,7 +7,10 @@ pub struct Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct Props {}
|
pub struct Props {
|
||||||
|
#[prop_or_default]
|
||||||
|
is_expanded: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Component for Tree {
|
impl Component for Tree {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -32,7 +37,9 @@ impl Component for Tree {
|
||||||
html! {
|
html! {
|
||||||
<div class="bp3-tree">
|
<div class="bp3-tree">
|
||||||
<ul class="bp3-tree-node-list">
|
<ul class="bp3-tree-node-list">
|
||||||
<TreeNode/>
|
<TreeNode is_expanded=self.props.is_expanded has_caret=true>
|
||||||
|
{"Example Stuff"}
|
||||||
|
</TreeNode>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -44,7 +51,14 @@ pub struct TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
pub struct TreeNodeProps {}
|
pub struct TreeNodeProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub is_expanded: bool,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub has_caret: bool,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: html::Children,
|
||||||
|
}
|
||||||
|
|
||||||
impl Component for TreeNode {
|
impl Component for TreeNode {
|
||||||
type Message = ();
|
type Message = ();
|
||||||
|
@ -71,9 +85,22 @@ impl Component for TreeNode {
|
||||||
html! {
|
html! {
|
||||||
<li class="bp3-tree-node">
|
<li class="bp3-tree-node">
|
||||||
<div class="bp3-tree-node-content">
|
<div class="bp3-tree-node-content">
|
||||||
|
{
|
||||||
|
if self.props.has_caret {
|
||||||
|
html! {
|
||||||
|
<Icon class="bp3-tree-node-caret" icon=IconName::ChevronRight />
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
html! {
|
||||||
|
<span class="bp3-tree-node-caret-none" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
{"content"}
|
{"content"}
|
||||||
</div>
|
</div>
|
||||||
// missing <Collapse/>
|
<Collapse is_open=self.props.is_expanded>
|
||||||
|
{self.props.children.clone()}
|
||||||
|
</Collapse>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue