Die App hatte zwei Routable-Enums, zwischen denen ein Signal<bool> umschaltete.
Der Schalter wurde nie gesetzt - beim ersten Umlegen waere aufgefallen, dass
sich beide Router dieselbe History teilen und beide "/" belegen: Wer im
Selector auf "Open Workspace" klickt, steht auf /ws_open, und der
Editor-Router kennt nur / und /editor.
Jetzt ein Enum, der Editor-Teil unter #[nest("/workspace")]. An die Stelle des
bool tritt Signal<Option<Workspace>> in einem Context-Provider - Props
scheiden aus, weil sich durch ein Outlet keine durchreichen lassen. Fehlt der
Workspace, schickt ein Guard im EditorShell-Layout zurueck zum Selector; der
Fall tritt real bei Hot-Reload auf, wo der Context faellt und die Route bleibt.
Der Selector verliert seine Reiter und wird eine einzige Route. Das folgt aus
dem UI-Prototyp in Issue #8: Oeffnen ist der Alltagsfall, Hinzufuegen passiert
pro Workspace einmal - zwei gleichrangige Reiter verlangten bei jedem Start
eine Entscheidung, die fast immer dieselbe ist. Damit entfallen der leere
Stub create_new_workspace.rs, die Tab-Konstante fuer den Selector und die
zugehoerigen CSS-Klassen.
Weil EnumIter nicht mehr gebraucht wird, faellt strum_macros als direkte
Abhaengigkeit weg; strum re-exportiert die Derives bereits.
Entscheidungen dazu in den Issues #5, #6 und #8.
98 lines
3.0 KiB
Rust
98 lines
3.0 KiB
Rust
use dioxus::prelude::*;
|
|
use dioxus_code::Theme;
|
|
use dioxus_code_editor::{CodeEditor, Language};
|
|
use strum::EnumMessage;
|
|
|
|
use crate::components::custom_link::custom_link_component::CustomLink;
|
|
use crate::route::Route;
|
|
use crate::workspace::Workspace;
|
|
|
|
const HEADER_SVG: Asset = asset!("/assets/header.svg");
|
|
|
|
/// Home page
|
|
#[component]
|
|
pub fn Home() -> Element {
|
|
rsx! {
|
|
Hero {}
|
|
}
|
|
}
|
|
|
|
// TODO: Unveränderter Dioxus-Vorlagentext. Ersetzen, sobald klar ist, was
|
|
// beim Öffnen eines Workspace angezeigt wird, bevor eine Notiz gewählt wurde.
|
|
#[component]
|
|
pub fn Hero() -> Element {
|
|
rsx! {
|
|
div {
|
|
id: "hero",
|
|
img { src: HEADER_SVG, id: "header" }
|
|
div { id: "links",
|
|
a { href: "https://dioxuslabs.com/learn/0.7/", "📚 Learn Dioxus" }
|
|
a { href: "https://dioxuslabs.com/awesome", "🚀 Awesome Dioxus" }
|
|
a { href: "https://github.com/dioxus-community/", "📡 Community Libraries" }
|
|
a { href: "https://github.com/DioxusLabs/sdk", "⚙️ Dioxus Development Kit" }
|
|
a { href: "https://marketplace.visualstudio.com/items?itemName=DioxusLabs.dioxus", "💫 VSCode Extension" }
|
|
a { href: "https://discord.gg/XgGxMSkvUM", "👋 Community Discord" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
pub fn Editor() -> Element {
|
|
let mut source = use_signal(String::new);
|
|
|
|
rsx! {
|
|
CodeEditor {
|
|
class: "editor-class",
|
|
value: source(),
|
|
language: Language::Markdown,
|
|
theme: Theme::CATPPUCCIN_MOCHA,
|
|
oninput: move |value| source.set(value),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Die Editor-Hülle: Datei-Leiste links, Editorfläche rechts.
|
|
///
|
|
/// Trägt zugleich den Zustands-Guard — ohne offenen Workspace hat der Editor
|
|
/// nichts anzuzeigen. Der Fall ist real: Hot-Reload setzt den Context zurück,
|
|
/// während die Route bestehen bleibt.
|
|
#[component]
|
|
pub fn EditorShell() -> Element {
|
|
let workspace = use_context::<Signal<Option<Workspace>>>();
|
|
let navigator = use_navigator();
|
|
|
|
use_effect(move || {
|
|
if workspace.read().is_none() {
|
|
navigator.replace(Route::Selector {});
|
|
}
|
|
});
|
|
|
|
if workspace.read().is_none() {
|
|
return rsx! {};
|
|
}
|
|
|
|
rsx! {
|
|
div {
|
|
class: "layout-container",
|
|
div {
|
|
class: "files-bar",
|
|
// TODO: Durch den Notiz-Baum des offenen Workspace ersetzen
|
|
// (rekursiv eingelesen, aufklappbar). Bis dahin die Routen.
|
|
for entry in Route::EDITOR_TABS {
|
|
CustomLink {
|
|
key: "{entry}",
|
|
label: entry.get_message().unwrap_or_default(),
|
|
href: entry.clone(),
|
|
css: "file-selector"
|
|
}
|
|
}
|
|
}
|
|
div {
|
|
class: "editor-container",
|
|
Outlet::<Route> { }
|
|
}
|
|
}
|
|
}
|
|
}
|