slint-ui-templates 0.1.0

Composable Slint UI building blocks — mother-child pattern, token-driven
Documentation
// DesktopShell — WinUI3 layout: Toolbar + SideNav + Content + StatusBar.
// MenuBar is NOT here — it must live in the Window (Slint constraint).
// Parent provides content as @children (placed inside the content frame).

import { Colors, Spacing } from "../../tokens/theme.slint";
import { Sizes }           from "../../tokens/sizes.slint";
import { NavItem }         from "../types.slint";
import { ShellToolbarItem } from "../types.slint";
import { ShellToolbar }    from "tool-bar.slint";
import { ShellSideNav }    from "side-nav.slint";
import { ShellContentFrame } from "content-frame.slint";
import { ShellStatusBar }  from "status-bar.slint";
import { DragHandle }      from "../../modules/DragHandle.slint";

/// Fluent desktop shell composed of toolbar, side navigation, content frame, and status bar.
export component DesktopShell inherits VerticalLayout {
    /// Navigation items rendered in the left side navigation.
    in property <[NavItem]>          nav-items;
    /// Toolbar items rendered in the optional toolbar row.
    in property <[ShellToolbarItem]> toolbar-items;
    /// Controls whether the toolbar row is shown.
    in property <bool>               show-toolbar: false;
    /// Id of the currently active content view.
    in property <string>             active-view: "";
    /// Status text shown in the bottom status bar.
    in property <string>             status-text: "Ready";
    /// Optional progress value shown in the status bar. Negative hides it.
    in property <float>              progress: -1.0;

    // State
    /// Private property "nav-width" used internally.
    private property <length> nav-width: Sizes.panel-sm;
    /// Private property "nav-collapsed" used internally.
    private property <bool>   nav-collapsed: nav-width <= Spacing.xl + Spacing.sm + Spacing.xs;

    /// Fired when a navigation destination is selected.
    callback navigate(string);
    /// Fired when a toolbar action is selected.
    callback toolbar-clicked(string);

    spacing: Sizes.no-size;

    // ── Toolbar (optional) ────────────────────────────────────────────────
    if root.show-toolbar: ShellToolbar {
        items: root.toolbar-items;
        item-clicked(id) => { root.toolbar-clicked(id); }
    }

    // ── SideNav + Content (main area) ─────────────────────────────────────
    HorizontalLayout {
        vertical-stretch: Sizes.one;
        spacing: Sizes.no-size;

        ShellSideNav {
            horizontal-stretch: Sizes.zero;
            min-width: root.nav-width;
            max-width: root.nav-width;
            items: root.nav-items;
            active-item: root.active-view;
            collapsed: root.nav-collapsed;
            navigate(id) => { root.navigate(id); }
            toggle-collapsed() => {
                root.nav-width = root.nav-collapsed
                    ? Sizes.panel-sm
                    : Spacing.xl + Spacing.sm;
            }
        }

        DragHandle {
            min-width: Spacing.handle-thickness;
            max-width: Spacing.handle-thickness;
            vertical: false;
            dragged(dx, dy) => { root.nav-width = clamp(root.nav-width + dx * Sizes.border-w, Spacing.xl + Spacing.sm, Sizes.panel-xxl); }
        }

        ShellContentFrame {
            horizontal-stretch: Sizes.one;
            @children
        }
    }

    // ── StatusBar (bottom) ────────────────────────────────────────────────
    ShellStatusBar {
        status-text: root.status-text;
        progress: root.progress;
    }
}