Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-app/GETTING-STARTED.md

Getting started with facett-app

facett-app is the app-framework layer over facett's egui components — a Leptos-spirit framework, but immediate-mode and canvas-only (native + wasm from one codebase; no DOM/SSR/SEO, no signals). It gives you navigation, a router, overlays and an app shell so you compose whole apps out of Facets.

Full template: examples/starter_app.rs — cargo run -p facett-app --example starter_app.

1. Add the deps

[dependencies]
facett-core = { path = "../facett-core", version = "0.1" }
facett-app  = { path = "../facett-app",  version = "0.1" }
egui = "0.34"
[dev-dependencies]
eframe = { version = "0.34", default-features = false, features = ["default_fonts", "glow"] }

2. A page is just a Facet

use facett_core::{Facet, FacetCaps};
struct HelloPage { title: String }
impl Facet for HelloPage {
    fn title(&self) -> &str { &self.title }
    fn ui(&mut self, ui: &mut egui::Ui) { ui.heading("Hello"); }
    fn state_json(&self) -> serde_json::Value { serde_json::json!({}) }
    fn caps(&self) -> FacetCaps { FacetCaps::NONE.themeable() }
}

3. Describe navigation once (NavModel), mount pages in an AppShell

use facett_app::{AppShell, NavItem, NavModel};
let model = NavModel::new([
    NavItem::new("home", "Home").icon("🏠"),
    NavItem::new("hello", "Hello").icon("👋"),
]);
let shell = AppShell::new("My App", model)
    .with_body("home", "Welcome!")
    .with_pane("hello", Box::new(HelloPage { title: "hello".into() }));

AppShell draws a topbar (title + back/forward + clickable breadcrumb), a left Sidebar from the NavModel, the active route's mounted pane, and a statusbar.

4. Run it (the shell is the whole window)

impl eframe::App for App {
    fn ui(&mut self, root: &mut egui::Ui, _f: &mut eframe::Frame) {
        egui::CentralPanel::default().show(root, |ui| self.shell.ui(ui));
    }
}

What else is in the box

Need Use
Nav model → sidebar/breadcrumb/menubar NavModel / NavItem
Route → view, back/forward, deep-link Router (navigate, to_hash, sync_from_hash)
Persistent nav rail Sidebar
Select / combobox Dropdown
Dialogs (scrim + Esc) Modal
Notifications Toasts (Info/Success/Warn/Error, TTL)
Collapsible sections / number / pager Accordion / Stepper / Pagination
Lightweight nav+content shell NavShell

Deep links

Router::to_hash() gives #route; on wasm write it to window.location.hash, and restore on load with router.sync_from_hash(&location.hash()). Pure strings, so the native build can use the same routes (e.g. a CLI arg).

The contract

Every facett component (yours included) should keep observable state in the struct (not egui memory), expose it via state_json, and stay headless-renderable — so the whole app is robot-testable without a human. See .nornir/component-contract.md.