flams_router_vscode/
components.rs1#![allow(clippy::must_use_candidate)]
2
3use ftml_dom::utils::css::inject_css;
4pub use leptos::prelude::*;
5
6#[component]
7pub fn VSCodeButton(children: Children) -> AnyView {
8 inject_css("flams-vscode-button", include_str!("button.css"));
9 view!(<button class="flams-vscode-button">{children()}</button>).into_any()
11}
12
13struct RadioGroup {
14 name: String,
15 selected: RwSignal<Option<String>>,
16}
17
18#[component]
19pub fn VSCodeRadioGroup(
20 #[prop(into)] name: String,
21 selected: RwSignal<Option<String>>,
22 children: Children,
23) -> AnyView {
24 inject_css("flams-vscode-radio", include_str!("radio.css"));
25 provide_context(RadioGroup { name, selected });
27 children()
28}
29
30#[component]
31pub fn VSCodeRadio(
32 #[prop(into)] id: String,
33 children: Children,
34 #[prop(optional, into)] disabled: Option<Signal<bool>>,
35) -> AnyView {
36 let Some((name, selected)) = with_context(|g: &RadioGroup| (g.name.clone(), g.selected)) else {
38 panic!("VSCodeRadio outside of VSCodeRadioGroup");
39 };
40 let idc = id.clone();
41 let checked = Memo::new(move |_| {
42 if selected.with(|s| s.as_ref().is_some_and(|s| *s == idc)) {
43 "icon checked"
44 } else {
45 "icon"
46 }
47 });
48 let top_class = Memo::new(move |_| {
49 if disabled.is_some_and(|b| b.get()) {
50 "flams-vscode-radio disabled"
51 } else {
52 "flams-vscode-radio"
53 }
54 });
55 let idc = id.clone();
56 let on_click = move |_| {
57 if !disabled.is_some_and(|b| b.get()) {
58 selected.set(Some(idc.clone()));
59 }
60 };
61 view! {
62 <div class=top_class on:click=on_click><div class="wrapper">
63 <input type="radio" id=id.clone() name=name checked=checked disabled=disabled/>
64 <div class=checked></div>
65 <label for=id><div>
66 {children()}
67 </div></label>
68 </div></div>
69 }.into_any()
70}
71
72#[component]
73pub fn VSCodeCheckbox(
74 checked: RwSignal<bool>,
75 children: Children,
76 #[prop(optional, into)] disabled: Option<Signal<bool>>,
77) -> AnyView {
78 inject_css("flams-vscode-checkbox", include_str!("checkbox.css"));
79 let top_class = Memo::new(move |_| {
82 if disabled.is_some_and(|b| b.get()) {
83 "flams-vscode-checkbox disabled"
84 } else {
85 "flams-vscode-checkbox"
86 }
87 });
88 let on_click = move |_| {
89 if !disabled.is_some_and(|b| b.get()) {
90 checked.update(|v| *v = !*v);
91 }
92 };
93 view! {
94 <div class=top_class on:click=on_click><div class="wrapper">
95 <input type="checkbox" checked=checked disabled=disabled/>
96 <div class="icon">
97 {move || if checked.get() {Some(view!{
98 <svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="check-icon">
99 <path fill-rule="evenodd" clip-rule="evenodd" d="M14.431 3.323l-8.47 10-.79-.036-3.35-4.77.818-.574 2.978 4.24 8.051-9.506.764.646z"></path>
100 </svg>
101 })} else {None}}
102 </div>
103 <label><div>
104 {children()}
105 </div></label>
106 </div></div>
107 }.into_any()
108}
109
110#[component]
111pub fn VSCodeTextbox(
112 value: RwSignal<String>,
113 #[prop(optional)] placeholder: Option<&'static str>,
114 #[prop(optional, into)] disabled: Option<Signal<bool>>,
115) -> impl IntoView {
116 inject_css("flams-vscode-textbox", include_str!("textbox.css"));
117 view! {
118 <input type="text" placeholder=placeholder bind:value=value class="flams-vscode-textbox" disabled=disabled></input>
119 }.into_any()
120}