This commit is contained in:
Yohan Boogaert 2021-03-19 19:10:19 +01:00 committed by GitHub
parent c9b23d91e6
commit 24ae8f898d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 269 additions and 8 deletions

View file

@ -10,6 +10,7 @@ use crate::icon::*;
use crate::input_group::*;
use crate::menu::*;
use crate::progressbar::*;
use crate::spinner::*;
use crate::switch::*;
use crate::tabs::*;
use crate::tag::*;
@ -183,6 +184,12 @@ impl Component for App {
onclick=self.link
.callback(|_| Msg::GoToMenu(DocMenu::ProgressBar))
/>
<MenuItem
text={html!("Spinner")}
href="#spinner"
onclick=self.link
.callback(|_| Msg::GoToMenu(DocMenu::Spinner))
/>
<MenuItem
text={html!("Switch")}
href="#switch"
@ -243,6 +250,7 @@ impl Component for App {
DocMenu::InputGroup => html!(<InputGroupDoc />),
DocMenu::Menu => html!(<MenuDoc />),
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
DocMenu::Spinner => html!(<SpinnerDoc />),
DocMenu::Switch => html!(<SwitchDoc />),
DocMenu::Tabs => html!(<TabsDoc />),
DocMenu::Tag => html!(<TagDoc />),
@ -285,6 +293,8 @@ pub enum DocMenu {
Menu,
#[to = "/#progress-bar"]
ProgressBar,
#[to = "/#spinner"]
Spinner,
#[to = "/#switch"]
Switch,
#[to = "/#tabs"]

View file

@ -12,6 +12,7 @@ mod icon;
mod input_group;
mod menu;
mod progressbar;
mod spinner;
mod switch;
mod tabs;
mod tag;

View file

@ -0,0 +1,45 @@
use yew::prelude::*;
use yewprint::{Intent, Spinner};
pub struct Example {
props: ExampleProps,
}
#[derive(Clone, PartialEq, Properties)]
pub struct ExampleProps {
pub intent: Option<Intent>,
pub size: u32,
}
impl Component for Example {
type Message = ();
type Properties = ExampleProps;
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
Example { 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 {
html! {
<div>
<Spinner
size=self.props.size as f32
intent=self.props.intent
/>
</div>
}
}
}

View file

@ -0,0 +1,101 @@
mod example;
use crate::ExampleContainer;
use example::*;
use yew::prelude::*;
use yewprint::{HtmlSelect, Intent, H1, H5};
pub struct SpinnerDoc {
callback: Callback<ExampleProps>,
state: ExampleProps,
}
impl Component for SpinnerDoc {
type Message = ExampleProps;
type Properties = ();
fn create(_: Self::Properties, link: ComponentLink<Self>) -> Self {
SpinnerDoc {
callback: link.callback(|x| x),
state: ExampleProps {
intent: None,
size: 10,
},
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
self.state = msg;
true
}
fn change(&mut self, _props: Self::Properties) -> ShouldRender {
true
}
fn view(&self) -> Html {
let example_props = self.state.clone();
let source = crate::include_raw_html!(
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
"bp3-code-block"
);
html! {
<div>
<H1 class=classes!("docs-title")>{"Spinner"}</H1>
<div>
<ExampleContainer
source=source
props=Some(html! {
<SpinnerProps
callback={self.callback.clone()}
props=example_props.clone()
/>
})
>
<Example with example_props />
</ExampleContainer>
</div>
</div>
}
}
}
crate::build_example_prop_component! {
SpinnerProps for ExampleProps =>
fn view(&self) -> Html {
html! {
<div>
<H5>{"Props"}</H5>
<div>
<p>{"Select intent:"}</p>
<HtmlSelect<Option<Intent>>
options={vec![
(None, "None".to_string()),
(Some(Intent::Primary), "Primary".to_string()),
(Some(Intent::Success), "Success".to_string()),
(Some(Intent::Warning), "Warning".to_string()),
(Some(Intent::Danger), "Danger".to_string()),
]}
onchange=self.update_props(|props, intent| ExampleProps {
intent,
..props
})
/>
<p>{"Select Size:"}</p>
<HtmlSelect<u32>
options={vec![
(20, "Small".to_string()),
(50, "Standard".to_string()),
(100, "Large".to_string()),
]}
onchange=self.update_props(|props, size| ExampleProps {
size,
..props
})
/>
</div>
</div>
}
}
}

View file

@ -1,4 +1,4 @@
use crate::icon::SIZE_LARGE;
use crate::icon::ICON_SIZE_LARGE;
use crate::{Icon, IconName, Intent};
use yew::prelude::*;
@ -64,7 +64,7 @@ impl Component for Callout {
<div class=classes>
{
icon.iter()
.map(|name| html!{<Icon icon=name icon_size=SIZE_LARGE/>})
.map(|name| html!{<Icon icon=name icon_size=ICON_SIZE_LARGE/>})
.collect::<Html>()
}
{

View file

@ -9,8 +9,8 @@ impl Default for IconName {
}
}
pub const SIZE_STANDARD: i32 = 16;
pub const SIZE_LARGE: i32 = 20;
pub const ICON_SIZE_STANDARD: i32 = 16;
pub const ICON_SIZE_LARGE: i32 = 20;
pub struct Icon {
props: IconProps,
@ -55,15 +55,15 @@ impl Component for Icon {
}
fn view(&self) -> Html {
let paths = if self.props.icon_size == SIZE_STANDARD {
let paths = if self.props.icon_size == ICON_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
let pixel_grid_size = if self.props.icon_size >= ICON_SIZE_LARGE {
ICON_SIZE_LARGE
} else {
SIZE_STANDARD
ICON_SIZE_STANDARD
};
let icon_string = format!("{:?}", self.props.icon);

View file

@ -11,6 +11,7 @@ mod icon;
mod input_group;
mod menu;
mod progressbar;
mod spinner;
mod switch;
mod tabs;
mod tag;
@ -33,6 +34,7 @@ pub use id_tree;
pub use input_group::*;
pub use menu::*;
pub use progressbar::*;
pub use spinner::*;
pub use switch::*;
pub use tabs::*;
pub use tag::*;

102
yewprint/src/spinner.rs Normal file
View file

@ -0,0 +1,102 @@
use crate::Intent;
use yew::prelude::*;
const R: f32 = 45.0;
const PATH_LENGTH: f32 = 280.0;
const SPINNER_MIN_SIZE: f32 = 10.0;
const STROKE_WIDTH: f32 = 4.0;
const MIN_STROKE_WIDTH: f32 = 16.0;
pub const SPINNER_SIZE_SMALL: f32 = 20.0;
pub const SPINNER_SIZE_STANDARD: f32 = 50.0;
pub const SPINNER_SIZE_LARGE: f32 = 100.0;
pub struct Spinner {
props: SpinnerProps,
}
#[derive(Clone, PartialEq, Properties)]
pub struct SpinnerProps {
#[prop_or_default]
pub intent: Option<Intent>,
#[prop_or_default]
pub class: Classes,
#[prop_or(SPINNER_SIZE_STANDARD)]
pub size: f32,
#[prop_or(0.25)]
pub value: f32,
}
impl Component for Spinner {
type Message = ();
type Properties = SpinnerProps;
fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self {
Spinner { 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 size = f32::max(SPINNER_MIN_SIZE, self.props.size);
let stroke_width = f32::min(MIN_STROKE_WIDTH, (STROKE_WIDTH * SPINNER_SIZE_LARGE) / size);
let view_box = {
let radius = R + stroke_width / 2.00;
let view_box_x = 50.00 - radius;
let view_box_width = radius * 2.00;
format!(
"{:.2} {:.2} {:.2} {:.2}",
view_box_x, view_box_x, view_box_width, view_box_width,
)
};
let spinner_track = format!(
"M 50,50 m 0,-{R:.0} a {R:.0},{R:.0} 0 1 1 0,{R2:.0} a {R:.0},{R:.0} 0 1 1 0,-{R2:.0}",
R = R,
R2 = R * 2.0,
);
let stroke_offset = PATH_LENGTH - PATH_LENGTH * self.props.value.clamp(0.0, 1.0);
html! {
<div
class=classes!(
"bp3-spinner",
self.props.intent,
self.props.class.clone(),
)
>
<div
class=classes!("bp3-spinner-animation")
>
<svg
width=size
height=size
stroke-width=stroke_width
viewBox=view_box
>
<path
class=classes!("bp3-spinner-track")
d=spinner_track
/>
<path
class=classes!("bp3-spinner-head")
d=spinner_track
pathLength=PATH_LENGTH
stroke-dasharray=format!("{} {}", PATH_LENGTH, PATH_LENGTH)
stroke-dashoffset=stroke_offset
/>
</svg>
</div>
</div>
}
}
}