flams_router_vscode/
components.rs

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