# The site's frame — a menu, a strip and a footer staff change

> The frame around every page — the menu, the strip across the top, the footer — can be the staff's to change, like a page's regions: `SiteMenu(…)` makes the menu a list of links they add to, rename, reorder and hide, and a `Region` in the layout's `promo` slot or in `StoreFooter`'s `about` slot makes the strip and the footer blocks they arrange. All of it follows the site's versions, dates and preview; the header's structure and the account and bag stay code.

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

## Summary        {#summary}
A shop changes its frame as often as its front page: a strip saying "order by the 20th for Christmas", a "Christmas
gifts" entry in the menu for three weeks, the holiday opening hours in the footer. Write the frame once, with what it
says TODAY as its default, and those three become the staff's to change at the page desk ([The PageBuilder kit — the desk staff arrange the site at](https://osysharp.com/reference/ui/pages-kit/)) — in
versions of the site, dated, previewed first.

```osy syntax
live var menu = SiteMenu("menu", [ new NavItem { Label = "Lamps", To = "/lamps" } ]);   // the menu, as data
slot promo { Region("announcement", allow: [Strip]) { Strip(words: "…"); } }            // the strip across the top
StoreFooter(chrome) { slot about { Region("footer", allow: [About]) { About(words: "…"); } } }   // the footer
```

## Signature      {#signature}
```osy syntax
live var <name> = SiteMenu("<menu name>", [ new NavItem { Label = "…", To = "/…", Exact = false, Children = [ … ] }, … ]);
slot promo { Region("<region name>", allow: [<blocks>]) { <default blocks> } }                     // in the layout
StoreFooter(chrome) { slot about { Region("<region name>", allow: [<blocks>]) { <default blocks> } } }
```

## Description    {#description}

### The menu — `SiteMenu` {#menu}
`SiteMenu("name", [ … ])` is the value of a `live var` in the layout: the menu's name, and its default entries written
out as `NavItem`s — `Label`, `To`, `Exact`, and one level of `Children`. Hand it to the shell (`Nav = menu`) and the
header, the phone's bar, the menu drawer and the footer's columns all read it.

Until staff publish a menu of their own it IS that list, entry for entry — the site looks exactly as the code has it.
At the desk a menu is edited as a LIST, not as blocks: each entry's words and where it goes (a page of the site, a
campaign page, or an outside `https://` address), up and down, **Hide** (the entry and the entries inside it), **Move
in** (under the entry above), dates it shows between, and its words in each language.

```osy title="a menu, a strip and a footer staff change" test app=ui-site-frame
app Lantern {
  use Osysharp.Ui;
  use Osysharp.Storage;
  use Osysharp.Blocks;
  use Osysharp.PageBuilder@1;
  model "model/**/*.osy";
}

using Osysharp.Blocks;
using Osysharp.PageBuilder;

[Role] public enum AppRole { Authenticator, Staff }

[Principal]
public entity Member {
  [Required, Unique, MaxLength(200)] string Email;
  security { allow read when IsAuthenticated where Id == user.Id; }
}

[RoleGrant] public entity RoleGrant {
  [Required] Member Member;
  [Required] AppRole Role;
  security { allow read when IsAuthenticated; }
}

policy IsStaff => RoleGrant.Any(g => g.Member == user && g.Role == AppRole.Staff);

policy ArrangesPages => IsStaff;   // Osysharp.Blocks' one question: who arranges the site

/// One line across the top of every page.
[Block("Strip")]
component Strip([Label("What it says"), MaxLength(140)] string words, [Label("Goes to")] PageLink link = "/") {
  render { StorePromo(words); }
}

/// A few words under the shop's name in the footer.
[Block("About")]
component About([Label("Words"), MaxLength(300)] string words) {
  render { Text(words, color: Colors.TextMuted); }
}

[Layout]
[AllowAnonymous]
component Shop() {
  live var menu = SiteMenu("menu", [
    new NavItem { Label = "Lamps", To = "/lamps" },
    new NavItem { Label = "Bulbs", To = "/bulbs" },
  ]);
  live var chrome = new AppChrome { Product = "Lantern", Home = "/", Nav = menu };
  render {
    StorefrontShell(chrome) {
      SiteLook();
      Outlet;
      slot promo {
        Region("announcement", allow: [Strip]) { Strip(words: "Free delivery on anything that glows"); }
      }
      slot footer {
        StoreFooter(chrome) {
          slot about {
            Region("footer", allow: [About]) { About(words: "Old lamps, rewired by hand."); }
          }
        }
      }
    }
  }
}

[Route("/")]
[AllowAnonymous]
component Front() { render { Text("Lamps for dark evenings", p: 8); } }

[Route("/lamps")]
[AllowAnonymous]
component Lamps() { render { Text("The lamps", p: 8); } }

[Route("/bulbs")]
[AllowAnonymous]
component Bulbs() { render { Text("The bulbs", p: 8); } }

[Route("/staff/pages")]
[Authorize(IsStaff)]
component StaffPages() { render { Box(p: 6) { PagesDesk(); } } }
```

### The strip and the footer — regions in the layout {#regions}
A `Region` in the layout is part of the FRAME: it is on every page, the desk lists it under **Around every page**, and
previews it on the front page. Put the strip's region in the shell's `promo` slot, and the footer's in `StoreFooter`'s
`about` slot — under the site's name, beside the menu's columns. They are ordinary regions ([[ui-blocks#region]]): the
code's blocks, the default written inside, dates per block — so a strip dated 1–21 December comes and goes by itself,
and a region whose only block has ended shows nothing at all.

The general site contract ships the block TYPES for both (`Osysharp.Site.Looks`, [Looks — a site's whole design, picked per version](https://osysharp.com/reference/ui/looks/)): `Announcement` for the
strip, and `FooterWords`, `FooterLink`, `OpeningHours`, `Address` and `FooterSignUp` for the footer — drawn by the shop
kit's plain design, or by the look the site wears. In an app with looks, each look's frame declares the menu and these two
regions under the same names, so what staff arranged comes along to every look.

### Versions, dates and the preview {#versions}
The menu and the frame's regions follow the site's VERSIONS like every region: a Christmas version carries its own
strip, a "Christmas gifts" entry and its holiday footer words as well as its palette, live on its schedule, and a member
of staff previewing "Christmas as of 14 December" sees all of it on every page — nobody else does. A version made before
the menu was arranged shows the main version's menu.

### What reaches a customer {#security}
Only the PUBLISHED menu of the version that is live — never a draft, never a hidden entry, never an entry outside its
dates. An entry's address is a page of the site (`/…`) or an `http(s)://` web address: anything else — `javascript:`,
`//elsewhere` — is refused by name when it is saved, and left out if a row says it anyway. An outside address is shown
marked as leaving the site: the outside glyph beside it, and "(another site)" in its accessible name. Only staff the app
grants the tables to may change any of it.

### What the compiler refuses {#refusals}
- `SiteMenu(…)` anywhere but as a `live var`'s value — a plain field would not follow what staff publish;
- a name that is not a constant lowercase string, or one another region or menu already has;
- a default entry that is not a constant `new NavItem { … }` — only `Label`, `To`, `Exact` and one level of `Children`
  (an icon or a badge is not something staff edit);
- `SiteMenu` without `use Osysharp.Blocks;` in the manifest.

## See also   {#see-also}
- [Blocks and regions — pages the staff arrange](https://osysharp.com/reference/ui/blocks/) — blocks, regions, and what a value may be.
- [The PageBuilder kit — the desk staff arrange the site at](https://osysharp.com/reference/ui/pages-kit/) — the desk: versions, the preview, arranging a region.
- [App shells](https://osysharp.com/reference/ui/shell/) — the shells; `StorefrontShell`, whose `promo` and `footer` slots the frame fills.
- [Looks — a site's whole design, picked per version](https://osysharp.com/reference/ui/looks/) — a look's frame: the menu and the frame's regions, drawn in each look's design.
