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

> 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.

<!-- id: ui-workspace-frame · area: ui · stability: preview · html: https://osysharp.com/reference/ui/workspace-frame/ -->

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

```osy syntax
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      {#signature}
```osy syntax
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    {#description}

### Where do a kit's pages stand?   {#frame}
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](https://osysharp.com/reference/ui/looks/)): 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.

### How does a page get into the navigation?   {#nav}
`[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?   {#order}
Say the order in `app.osy`, naming the pages as code:

```osy syntax
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?   {#tailor}
- **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](https://osysharp.com/reference/ui/theming/)).
- **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       {#examples}

```osy title="an app's shell, its own pages in the nav, and a page standing in the frame" test app=ui-workspace-frame
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."); } }
```

```osy title="the app's order for the navigation — one of its pages first, no page taken over" test app=ui-workspace-frame-order
[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       {#see-also}
- [[Slot] and contributions — a place on a page that other kits, and the app, add to](https://osysharp.com/reference/ui/contributions/) — slots: a place on a kit's page that other kits and the app add to
- [ISettingsProvider and [OrgPolicy]: kits announce their settings, and a setting says whether an organisation may govern it](https://osysharp.com/reference/ui/settings-registry/) — the settings area, which stands in the same shell
- [Looks — a site's whole design, picked per version](https://osysharp.com/reference/ui/looks/) — designing a kit's contract
- [layout primitives](https://osysharp.com/reference/ui/layout/) — layouts and `Outlet`
