Skip to main content

nightshade_api/web/
editor_shell.rs

1use leptos::prelude::*;
2
3use crate::web::{ResizeAxis, ResizeHandle};
4
5/// A code-editor layout with a top toolbar, collapsible and resizable left,
6/// right, and bottom slots around the central `children`, and a status footer.
7/// Each `*_open` signal toggles a slot's visibility; providing a matching
8/// `*_size` signal makes that slot resizable (and drives its pixel size) via an
9/// inserted [`ResizeHandle`].
10#[component]
11pub fn EditorShell(
12    #[prop(optional, into)] toolbar: ViewFn,
13    #[prop(optional, into)] left: ViewFn,
14    #[prop(optional, into)] right: ViewFn,
15    #[prop(optional, into)] bottom: ViewFn,
16    #[prop(optional, into)] status: ViewFn,
17    #[prop(optional)] left_open: Option<RwSignal<bool>>,
18    #[prop(optional)] right_open: Option<RwSignal<bool>>,
19    #[prop(optional)] bottom_open: Option<RwSignal<bool>>,
20    #[prop(optional)] left_size: Option<RwSignal<f64>>,
21    #[prop(optional)] right_size: Option<RwSignal<f64>>,
22    #[prop(optional)] bottom_size: Option<RwSignal<f64>>,
23    children: Children,
24) -> impl IntoView {
25    let left_open = left_open.unwrap_or_else(|| RwSignal::new(true));
26    let right_open = right_open.unwrap_or_else(|| RwSignal::new(true));
27    let bottom_open = bottom_open.unwrap_or_else(|| RwSignal::new(true));
28
29    let left_style = move || match left_size {
30        Some(size) if left_open.get() => format!("width:{}px", size.get()),
31        _ => String::new(),
32    };
33    let right_style = move || match right_size {
34        Some(size) if right_open.get() => format!("width:{}px", size.get()),
35        _ => String::new(),
36    };
37    let bottom_style = move || match bottom_size {
38        Some(size) if bottom_open.get() => format!("height:{}px", size.get()),
39        _ => String::new(),
40    };
41
42    view! {
43        <div class="nightshade-editor-shell">
44            <div class="nightshade-editor-toolbar">{toolbar.run()}</div>
45            <div class="nightshade-editor-main">
46                <aside class="nightshade-editor-left" class:closed=move || !left_open.get() style=left_style>
47                    {left.run()}
48                </aside>
49                {left_size
50                    .map(|size| {
51                        view! {
52                            <Show when=move || left_open.get() fallback=|| ()>
53                                <ResizeHandle value=size axis=ResizeAxis::Horizontal min=140.0 max=680.0 />
54                            </Show>
55                        }
56                    })}
57                <main class="nightshade-editor-center">{children()}</main>
58                {right_size
59                    .map(|size| {
60                        view! {
61                            <Show when=move || right_open.get() fallback=|| ()>
62                                <ResizeHandle
63                                    value=size
64                                    axis=ResizeAxis::Horizontal
65                                    min=180.0
66                                    max=680.0
67                                    invert=true
68                                />
69                            </Show>
70                        }
71                    })}
72                <aside
73                    class="nightshade-editor-right"
74                    class:closed=move || !right_open.get()
75                    style=right_style
76                >
77                    {right.run()}
78                </aside>
79            </div>
80            {bottom_size
81                .map(|size| {
82                    view! {
83                        <Show when=move || bottom_open.get() fallback=|| ()>
84                            <ResizeHandle
85                                value=size
86                                axis=ResizeAxis::Vertical
87                                min=100.0
88                                max=680.0
89                                invert=true
90                            />
91                        </Show>
92                    }
93                })}
94            <section
95                class="nightshade-editor-bottom"
96                class:closed=move || !bottom_open.get()
97                style=bottom_style
98            >
99                {bottom.run()}
100            </section>
101            <footer class="nightshade-editor-status">{status.run()}</footer>
102        </div>
103    }
104}