yew_bs/components/
placeholders.rs1use yew::prelude::*;
2#[derive(Clone, Copy, PartialEq, Debug)]
3pub enum PlaceholderAnimation {
4 Glow,
5 Wave,
6}
7impl PlaceholderAnimation {
8 pub fn as_str(&self) -> &'static str {
9 match self {
10 PlaceholderAnimation::Glow => "placeholder-glow",
11 PlaceholderAnimation::Wave => "placeholder-wave",
12 }
13 }
14}
15#[derive(Clone, Copy, PartialEq, Debug)]
17pub enum PlaceholderSize {
18 ExtraSmall,
19 Small,
20 Medium,
21 Large,
22 ExtraLarge,
23}
24impl PlaceholderSize {
25 pub fn as_str(&self) -> &'static str {
26 match self {
27 PlaceholderSize::ExtraSmall => "placeholder-xs",
28 PlaceholderSize::Small => "placeholder-sm",
29 PlaceholderSize::Medium => "",
30 PlaceholderSize::Large => "placeholder-lg",
31 PlaceholderSize::ExtraLarge => "placeholder-xl",
32 }
33 }
34}
35#[derive(Properties, PartialEq)]
36pub struct PlaceholderProps {
37 #[prop_or_default]
38 pub children: Children,
39 #[prop_or(PlaceholderSize::Medium)]
40 pub size: PlaceholderSize,
41 #[prop_or_default]
42 pub class: Option<AttrValue>,
43 #[prop_or_default]
44 pub width: Option<AttrValue>,
45 #[prop_or_default]
46 pub height: Option<AttrValue>,
47 #[prop_or_default]
48 pub variant: Option<AttrValue>,
49 #[prop_or_default]
50 pub aria_label: Option<AttrValue>,
51}
52#[function_component(Placeholder)]
53pub fn placeholder(props: &PlaceholderProps) -> Html {
54 let mut classes_vec = vec!["placeholder".to_string()];
55 let size_class = props.size.as_str();
56 if !size_class.is_empty() {
57 classes_vec.push(size_class.to_string());
58 }
59 if let Some(variant) = &props.variant {
60 classes_vec.push(format!("bg-{}", variant.as_str()));
61 }
62 if let Some(class) = &props.class {
63 classes_vec.push(class.to_string());
64 }
65 let classes = classes!(classes_vec);
66 let mut style = String::new();
67 if let Some(width) = &props.width {
68 style.push_str(&format!("width: {};", width.as_str()));
69 }
70 if let Some(height) = &props.height {
71 style.push_str(&format!("height: {};", height.as_str()));
72 }
73 let style_attr: Option<AttrValue> = if style.is_empty() {
74 None
75 } else {
76 Some(style.into())
77 };
78 html! {
79 < span class = { classes } style = { style_attr } aria - label = { props
80 .aria_label.clone() } > { for props.children.iter() } </ span >
81 }
82}
83#[derive(Properties, PartialEq)]
84pub struct PlaceholderButtonProps {
85 #[prop_or(PlaceholderSize::Medium)]
86 pub size: PlaceholderSize,
87 #[prop_or_default]
88 pub class: Option<AttrValue>,
89 #[prop_or_default]
90 pub width: Option<AttrValue>,
91 #[prop_or_default]
92 pub variant: Option<AttrValue>,
93}
94#[function_component(PlaceholderButton)]
95pub fn placeholder_button(props: &PlaceholderButtonProps) -> Html {
96 let mut classes_vec = vec![
97 "btn".to_string(), "disabled".to_string(), "placeholder".to_string()
98 ];
99 let size_class = props.size.as_str();
100 if !size_class.is_empty() {
101 classes_vec.push(size_class.to_string());
102 }
103 if let Some(variant) = &props.variant {
104 classes_vec.push(format!("btn-{}", variant.as_str()));
105 }
106 if let Some(class) = &props.class {
107 classes_vec.push(class.to_string());
108 }
109 let classes = classes!(classes_vec);
110 let style = props.width.as_ref().map(|w| format!("width: {};", w.as_str()));
111 html! {
112 < span class = { classes } style = { style } aria - hidden = "true" > < span
113 class = "placeholder" > { "Button" } </ span > </ span >
114 }
115}
116#[derive(Properties, PartialEq)]
117pub struct PlaceholderWrapperProps {
118 #[prop_or_default]
119 pub children: Children,
120 #[prop_or_default]
121 pub animation: Option<PlaceholderAnimation>,
122 #[prop_or_default]
123 pub class: Option<AttrValue>,
124}
125#[function_component(PlaceholderWrapper)]
126pub fn placeholder_wrapper(props: &PlaceholderWrapperProps) -> Html {
127 let mut classes_vec = Vec::new();
128 if let Some(animation) = &props.animation {
129 classes_vec.push(animation.as_str().to_string());
130 }
131 if let Some(class) = &props.class {
132 classes_vec.push(class.to_string());
133 }
134 let classes = if classes_vec.is_empty() {
135 None
136 } else {
137 Some(classes!(classes_vec))
138 };
139 html! {
140 < div class = { classes } > { for props.children.iter() } </ div >
141 }
142}
143#[derive(Properties, PartialEq)]
144pub struct PlaceholderCardProps {
145 #[prop_or_default]
146 pub animation: Option<PlaceholderAnimation>,
147 #[prop_or_default]
148 pub class: Option<AttrValue>,
149}
150#[function_component(PlaceholderCard)]
151pub fn placeholder_card(props: &PlaceholderCardProps) -> Html {
152 let mut wrapper_classes = Vec::new();
153 if let Some(animation) = &props.animation {
154 wrapper_classes.push(animation.as_str().to_string());
155 }
156 if let Some(class) = &props.class {
157 wrapper_classes.push(class.to_string());
158 }
159 let wrapper_classes = if wrapper_classes.is_empty() {
160 None
161 } else {
162 Some(classes!(wrapper_classes))
163 };
164 html! {
165 < div class = { wrapper_classes } > < div class = "card" > < div class =
166 "card-body" > < div class = "d-flex align-items-center mb-3" > < Placeholder size
167 = { PlaceholderSize::Large } width = { Some(AttrValue::from("3rem")) } height = {
168 Some(AttrValue::from("3rem")) } class = {
169 Some(AttrValue::from("rounded-circle me-3")) } /> < div class = "flex-grow-1" > <
170 Placeholder width = { Some(AttrValue::from("60%")) } class = {
171 Some(AttrValue::from("mb-1")) } /> < Placeholder width = {
172 Some(AttrValue::from("40%")) } size = { PlaceholderSize::Small } /> </ div > </
173 div > < Placeholder class = { Some(AttrValue::from("mb-2")) } /> < Placeholder
174 width = { Some(AttrValue::from("80%")) } class = { Some(AttrValue::from("mb-2"))
175 } /> < Placeholder width = { Some(AttrValue::from("70%")) } /> </ div > < div
176 class = "card-footer" > < div class =
177 "d-flex justify-content-between align-items-center" > < Placeholder width = {
178 Some(AttrValue::from("30%")) } size = { PlaceholderSize::Small } /> < div > <
179 PlaceholderButton size = { PlaceholderSize::Small } variant = {
180 Some(AttrValue::from("primary")) } class = { Some(AttrValue::from("me-2")) } /> <
181 PlaceholderButton size = { PlaceholderSize::Small } variant = {
182 Some(AttrValue::from("secondary")) } /> </ div > </ div > </ div > </ div > </
183 div >
184 }
185}
186#[derive(Properties, PartialEq)]
187pub struct PlaceholderTableProps {
188 #[prop_or(5)]
189 pub rows: usize,
190 #[prop_or(4)]
191 pub columns: usize,
192 #[prop_or_default]
193 pub animation: Option<PlaceholderAnimation>,
194 #[prop_or_default]
195 pub class: Option<AttrValue>,
196}
197#[function_component(PlaceholderTable)]
198pub fn placeholder_table(props: &PlaceholderTableProps) -> Html {
199 let mut wrapper_classes = Vec::new();
200 if let Some(animation) = &props.animation {
201 wrapper_classes.push(animation.as_str().to_string());
202 }
203 if let Some(class) = &props.class {
204 wrapper_classes.push(class.to_string());
205 }
206 let wrapper_classes = if wrapper_classes.is_empty() {
207 None
208 } else {
209 Some(classes!(wrapper_classes))
210 };
211 html! {
212 < div class = { wrapper_classes } > < table class = "table" > < thead > < tr > {
213 (0..props.columns).map(| _ | { html! { < th >< Placeholder width = {
214 Some(AttrValue::from("80%")) } size = { PlaceholderSize::Small } /></ th > } })
215 .collect::< Html > () } </ tr > </ thead > < tbody > { (0..props.rows).map(| _ |
216 { html! { < tr > { (0..props.columns).map(| _ | { html! { < td >< Placeholder
217 width = { Some(AttrValue::from("70%")) } /></ td > } }).collect::< Html > () } </
218 tr > } }).collect::< Html > () } </ tbody > </ table > </ div >
219 }
220}