nightshade_api/web/base/
layout.rs1use leptos::html;
2use leptos::prelude::*;
3
4#[component]
7pub fn AppShell(children: Children) -> impl IntoView {
8 view! { <div class="nightshade-app-shell">{children()}</div> }
9}
10
11#[derive(Clone, Copy, PartialEq, Eq)]
14pub enum ResizeAxis {
15 Horizontal,
16 Vertical,
17}
18
19#[component]
24pub fn ResizeHandle(
25 value: RwSignal<f64>,
26 axis: ResizeAxis,
27 #[prop(default = 120.0)] min: f64,
28 #[prop(default = 2000.0)] max: f64,
29 #[prop(optional)] invert: bool,
30) -> impl IntoView {
31 let handle_ref = NodeRef::<html::Div>::new();
32 let drag = StoredValue::new(None::<(f64, f64)>);
33
34 let pointer_position = move |event: &web_sys::PointerEvent| match axis {
35 ResizeAxis::Horizontal => event.client_x() as f64,
36 ResizeAxis::Vertical => event.client_y() as f64,
37 };
38
39 let on_pointerdown = move |event: web_sys::PointerEvent| {
40 event.prevent_default();
41 drag.set_value(Some((pointer_position(&event), value.get_untracked())));
42 if let Some(node) = handle_ref.get() {
43 let _ = node.set_pointer_capture(event.pointer_id());
44 }
45 };
46
47 let on_pointermove = move |event: web_sys::PointerEvent| {
48 if let Some((start_pointer, start_value)) = drag.get_value() {
49 let mut delta = pointer_position(&event) - start_pointer;
50 if invert {
51 delta = -delta;
52 }
53 value.set((start_value + delta).clamp(min, max));
54 }
55 };
56
57 let on_pointerup = move |event: web_sys::PointerEvent| {
58 drag.set_value(None);
59 if let Some(node) = handle_ref.get() {
60 let _ = node.release_pointer_capture(event.pointer_id());
61 }
62 };
63
64 let class = match axis {
65 ResizeAxis::Horizontal => "nightshade-resize-handle horizontal",
66 ResizeAxis::Vertical => "nightshade-resize-handle vertical",
67 };
68
69 view! {
70 <div
71 node_ref=handle_ref
72 class=class
73 on:pointerdown=on_pointerdown
74 on:pointermove=on_pointermove
75 on:pointerup=on_pointerup
76 ></div>
77 }
78}
79
80#[component]
82pub fn Row(#[prop(into, optional)] class: String, children: Children) -> impl IntoView {
83 view! { <div class=format!("nightshade-row {class}")>{children()}</div> }
84}
85
86#[component]
88pub fn Column(#[prop(into, optional)] class: String, children: Children) -> impl IntoView {
89 view! { <div class=format!("nightshade-column {class}")>{children()}</div> }
90}
91
92#[component]
94pub fn Grid(#[prop(into, optional)] class: String, children: Children) -> impl IntoView {
95 view! { <div class=format!("nightshade-grid {class}")>{children()}</div> }
96}