mirror of
https://github.com/yewprint/yewprint
synced 2024-11-25 04:50:20 +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"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"regex",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"yew",
|
||||
|
@ -247,6 +249,15 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.1"
|
||||
|
@ -366,6 +377,21 @@ dependencies = [
|
|||
"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]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
@ -440,6 +466,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
|
|
|
@ -13,3 +13,7 @@ crate-type = ["cdylib"]
|
|||
wasm-bindgen = "^0.2"
|
||||
yew = "0.17"
|
||||
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
|
||||
fi
|
||||
|
||||
mkdir -p static
|
||||
rm -fR static/.gitignore static/*
|
||||
tar xvzf core.tgz -C static --wildcards \*.css --transform='s/.*\///'
|
||||
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::collapse::*;
|
||||
use crate::forms::controls::*;
|
||||
use crate::buttons::Button;
|
||||
use crate::collapse::Collapse;
|
||||
use crate::forms::controls::Switch;
|
||||
use crate::tree::Tree;
|
||||
use yew::prelude::*;
|
||||
|
||||
const DARK_BG_COLOR: &str = "#30404d";
|
||||
|
@ -78,6 +79,7 @@ impl Component for App {
|
|||
</Button>
|
||||
<Collapse
|
||||
is_open=!self.collapsed
|
||||
keep_children_mounted=true
|
||||
>
|
||||
<pre class="bp3-code-block">
|
||||
<div>{"[INFO]: Installing wasm-bindgen..."}</div>
|
||||
|
@ -98,6 +100,9 @@ impl Component for App {
|
|||
</pre>
|
||||
</Collapse>
|
||||
</div>
|
||||
<div>
|
||||
<Tree />
|
||||
</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"]
|
||||
|
||||
mod app;
|
||||
mod buttons;
|
||||
mod collapse;
|
||||
mod forms;
|
||||
mod tree;
|
||||
pub mod buttons;
|
||||
pub mod collapse;
|
||||
pub mod forms;
|
||||
pub mod icon;
|
||||
pub mod tree;
|
||||
|
||||
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::*;
|
||||
|
||||
pub struct Tree {
|
||||
|
@ -5,7 +7,10 @@ pub struct Tree {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
pub struct Props {}
|
||||
pub struct Props {
|
||||
#[prop_or_default]
|
||||
is_expanded: bool,
|
||||
}
|
||||
|
||||
impl Component for Tree {
|
||||
type Message = ();
|
||||
|
@ -32,7 +37,9 @@ impl Component for Tree {
|
|||
html! {
|
||||
<div class="bp3-tree">
|
||||
<ul class="bp3-tree-node-list">
|
||||
<TreeNode/>
|
||||
<TreeNode is_expanded=self.props.is_expanded has_caret=true>
|
||||
{"Example Stuff"}
|
||||
</TreeNode>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
@ -44,7 +51,14 @@ pub struct TreeNode {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
type Message = ();
|
||||
|
@ -71,9 +85,22 @@ impl Component for TreeNode {
|
|||
html! {
|
||||
<li class="bp3-tree-node">
|
||||
<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"}
|
||||
</div>
|
||||
// missing <Collapse/>
|
||||
<Collapse is_open=self.props.is_expanded>
|
||||
{self.props.children.clone()}
|
||||
</Collapse>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue