Osy#betaRun it on Osyrin: osyrin.com

Reference / UI

WorkspaceShell, WorkspaceFrame and [Nav] — a kit's pages in your app's shell and navigation

component MyShell() : WorkspaceShell { render { … Slot; … } } · [Layout(WorkspaceFrame)] · [Nav("Label", Icon = Icons.X, Group = "G", Order = n)] · Nav.Pages() · Nav.Pages("G")

A kit's working pages (a knowledge base's desk, its review queue) name `[Layout(WorkspaceFrame)]`, and the settings area stands in it too: design `WorkspaceShell` once — your top bar, your rail, your account menu — and every one of them stands in your shell. A page marked `[Nav]` puts itself in the navigation; your shell lists them with `Nav.Pages()`, each only for a reader the page's `[Authorize]` admits.

preview2 examples compiled by CIuicompositionkitlayout

Summary#

You reuse a kit's pages and still decide where they stand and how they look. Design the shell once:

component DeskShellDesign() : WorkspaceShell {
  render { AppShell(new AppChrome { Product = "Harbour", Nav = [new NavItem { Kind = NavKind.Section, Label = "Desk",
                                                                             Children = Nav.Pages() }] }) { Slot; } }
}

…and every kit page in [Layout(WorkspaceFrame)] — and every settings page, since SettingsFrame stands in the same shell — is drawn inside it, with the kits' [Nav] pages listed beside your own.

Signature#

public abstract component WorkspaceShell();                 // Osysharp.Ui — the frame; `Slot` is the page
component MyShell() : WorkspaceShell { render { … Slot; … } }   // your design of it, once (the kit's own: nothing around)
[Layout] public component WorkspaceFrame();                 // what a kit's working page names: your shell, the page inside

[Nav("Reports", Icon = Icons.Chart, Group = "Desk", Order = 40)]   // on a [Route] with no route parameters
Nav.Pages()            → NavItem[]                          // every [Nav] page the reader may open, in order
Nav.Pages("Desk")      → NavItem[]                          // the ones whose Group is "Desk"

app.Nav = [ReportsPage, KnowledgeDeskPage];                 // your order: these first, in this order, then the rest

Description#

Where do a kit's pages stand?#

A kit page names [Layout(WorkspaceFrame)]: Osysharp.Ui's layout, which draws your design of WorkspaceShell with the page inside, scrolling, across the width. Your design is a look contract implementation (Looks — a site's whole design, picked per version): it takes no parameters and draws Slot where the page goes.

If your app has ONE layout its pages stand in, you need not write a design at all. With no : WorkspaceShell of your own, the compiler writes one from that layout — the same component, its state and live reads included, with its Outlet as the Slot — so a kit's page (the settings area, /settings/people) stands in your sidebar and account menu exactly as your own pages do. An app with two layouts (a public one and a staff one) is not guessed for: write the design, as below, and it is the one used. With no layout and no design, a kit's page is the page and nothing around it.

[Nav] on a page says its row's words (else its [Title], else its name in words), its icon, its group and its place — Order, lower first, then the package order (a kit before the kits built on it, your own last), then the name. Your shell asks Nav.Pages() and gets nav rows, written out at compile time: a reader the page's [Authorize] refuses is not shown its row, and nothing is fetched to decide it. A page whose route takes a value cannot be a nav row — mark the page a person starts from. Because the rows are written out, a [Render(SSR)] page that lists them is painted by the server with its navigation in place.

How does the app put a kit's page somewhere else in the nav?#

Say the order in app.osy, naming the pages as code:

app.Nav = [ReportsPage, KnowledgeDeskPage];

The pages it names lead the navigation in the order written; every other [Nav] page follows in its own order. A kit's page keeps everything else the kit gave it — its words, its icon, its group, its [Authorize] — and stays the kit's page: re-ordering it is not taking it over. Nav.Pages("Group") keeps the same order within the group. A name that is no page in the navigation is refused, listing the ones there are; a page without leaves out cannot be placed.

How do you still decide?#

  • Where they stand — your WorkspaceShell, once; or name a different layout by taking a page over by name.
  • Where they are listed — Nav.Pages("Group") lists one group, so you lay groups out yourself; a kit's page you do not want listed is left out with without KnowledgeDeskPage; on its use line, and app.Nav = [ … ]; puts the pages in your order (above).
  • How they look — your theme's tokens paint every kit page (theme tokens).
  • One page your own way — a component of the same name as the kit's page takes it over, at its route or yours.

Examples#

component AppFrameDesign() : WorkspaceShell {
  render {
    Stack(gap: 0, w: "100%", minH: "100vh", bg: Colors.Bg) {
      Row(gap: 4, p: 3, bg: Colors.Surface, label: "Top bar") {
        Text("Larkspur", fontWeight: FontWeight.Semibold);
        foreach (var n in Nav.Pages()) { TextLink(n.Label, to: n.To); }
      }
      Slot;
    }
  }
}

[Route("/inbox")] [Layout(WorkspaceFrame)] [Nav("Inbox", Icon = Icons.Inbox, Order = 10)]
component InboxPage() { render { Text("Everything waiting for you."); } }

[Route("/reports")] [Layout(WorkspaceFrame)] [Nav("Reports", Icon = Icons.Chart, Order = 40)]
component ReportsPage() { render { Text("How the week went."); } }
[Route("/inbox")] [Nav("Inbox", Icon = Icons.Inbox, Order = 10)]
component InboxPage() {
  render { Stack { foreach (var n in Nav.Pages()) { TextLink(n.Label, to: n.To); } Text("Everything waiting for you."); } }
}

[Route("/reports")] [Nav("Reports", Icon = Icons.Chart, Order = 40)]
component ReportsPage() { render { Text("How the week went."); } }

app.Nav = [ReportsPage, InboxPage];

See also#

Related

[Slot] and contributions — a place on a page that other kits, and the app, add to

A slot is a place on a page others add to. A kit marks one (`[Slot] public abstract component QuotePanel(Quote…

Looks — a site's whole design, picked per version

A LOOK is a site's whole design — its frame, its pages, its theme and fonts, its design of every block type — declared…

layout primitives

The built-in layout primitives and how they arrange children. `Stack` stacks children in a column, `Row` lays them in a…

ISettingsProvider and [OrgPolicy]: kits announce their settings, and a setting says whether an organisation may govern it

A kit with something an admin configures implements `ISettingsProvider` and serves its pages under…

App shells

An app shell is the frame around every page: a brand, a navigation tree, the signed-in person and a menu behind them, a…