snora-core 0.7.0

Vocabulary and contract layer for the Snora iced GUI framework.
docs.rs failed to build snora-core-0.7.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: snora-core-0.4.3

Snora

snora snora Docs snora Deps Status
snora-core snora-core Docs snora-core Deps Status
License

An iced GUI framework that gets out of the way of your application.

Overview

Snora gives an iced application a small, opinionated skeleton (header, sidebar, body, footer) plus the overlay surfaces it almost certainly needs (dialog, bottom sheet, context menu, toasts) — and then steps back. Every slot accepts any iced::Element, so your UI code stays your UI code.

When to use it

snora is a good fit when you are building:

  • a local-first desktop app that runs heavy work alongside an interactive UI (AI inference, dataset converters, file processors);
  • an app that needs accessibility correct from day one — RTL layout, theme-aware colors, logical edges baked into the API;
  • a standard desktop chrome (header / sidebar / body / footer) with a few overlays.

snora is not the right tool for games, real-time visualization, or web-first applications. See docs/getting-started/05-when-to-use.md for fuller fit guidance.

Quick start

[dependencies]
iced  = { version = "0.14", features = ["tokio"] }
snora = "0.7"
use iced::{Element, widget::text};
use snora::{AppLayout, render};

#[derive(Debug, Clone)]
enum Message {}

#[derive(Default)]
struct App;

impl App {
    fn update(&mut self, _msg: Message) {}
    fn view(&self) -> Element<'_, Message> {
        let body: Element<'_, Message> = text("Hello, snora!").into();
        render(AppLayout::new(body))
    }
}

fn main() -> iced::Result {
    iced::application(App::default, App::update, App::view)
        .title(|_: &App| String::from("Hello"))
        .run()
}

That's the whole program. Adding a header, sidebar, and footer is three more chained calls — see docs/getting-started.

Features

  • Skeleton + injected slots. AppLayout::new(body).header(h).side_bar(s).footer(f). Each slot is any iced::Element. No trait to implement, no dispatcher enum to write.
  • Framework-managed toasts. Vec<Toast<Message>> on your state, two one-liners (subscription + sweep_expired) for lifetime, intent → theme color, six anchor positions including RTL-aware ones.
  • One close sink per channel. on_close_modals for dialogs and sheets, on_close_menus for header / context menus. Wired once.
  • Vocabulary instead of magic numbers. SheetSize::Half, SheetEdge::Start, ToastPosition::TopEnd, LayoutDirection::Rtl, Edge::Start — explicit choices, not hardcoded constants.
  • Navigation widgets out of the box. app_header, app_side_bar, app_tab_bar, app_breadcrumb, plus dropdown menus and context menus — direction-aware, theme-aware, and entirely opt-in.
  • Three crates, one umbrella. snora-core is the iced-free vocabulary, snora-widgets is the optional prefab UI parts, and snora is the engine — applications only depend on snora.

Design notes

  • Accessible by Default and by Design. Layout is described in logical edges (Edge::Start / Edge::End); LTR ↔ RTL is one setter on AppLayout.
  • No silent drops. If you populate an overlay but leave its close sink None, the overlay still renders — snora omits only the click-outside backdrop, never the content.
  • Skeleton, not styling. Snora positions and stacks. The look of your dialog card, the typography of your header — those are your decisions, not ours.

Read more

For the full picture, head to docs/:

Per-release notes live in CHANGELOG.md; the direction of upcoming work is sketched in ROADMAP.md.

Built with iced.