# AppShell

Places a sticky sidebar beside the main content column.

[View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/AppShell.tsx)

## Overview

An app shell places a sticky sidebar beside a content column. On narrow viewports, the sidebar moves into a drawer.

Use it as the outer frame of an application, and name the sidebar with `aria-label`.

## Examples

### Basic

```tsx
import { AppShell, Button, Identicon, Menu, SidebarMenu, style, Surface } from '@tempoxyz/ds'
import {
  Document,
  ExternalLink,
  GasFee,
  Grid,
  Key,
  LogOut,
  MoreHorizontal,
  Plus,
  Settings,
  Sort,
  Users,
} from '@tempoxyz/ds/icons'

const keys = ['Production', 'Staging', 'Local development']

export function Demo() {
  return (
    <div {...styles.frame()}>
      <AppShell.Root style={{ height: '100%', minHeight: 0 }}>
        <AppShell.Sidebar aria-label="Workspace" style={{ height: '100%' }}>
          <AppShell.SidebarHeader>
            <SidebarMenu.Item render={<button type="button" />} style={{ padding: 6 }}>
              <Identicon address="0x71C7656EC7ab88b098defB751B7401B5f6d8976F" size="32" />
              <span {...styles.stack()}>
                <span {...styles.caption()}>Tempo Labs</span>
                <span {...styles.name()}>Checkout</span>
              </span>
              <Sort />
            </SidebarMenu.Item>
          </AppShell.SidebarHeader>
          <AppShell.SidebarBody>
            <SidebarMenu.Root>
              <SidebarMenu.Group aria-label="Project">
                <SidebarMenu.Item active href="#">
                  <Grid />
                  Home
                </SidebarMenu.Item>
                <SidebarMenu.Item href="#">
                  <Key />
                  API Keys
                </SidebarMenu.Item>
                <SidebarMenu.Item href="#">
                  <Document />
                  <span {...styles.grow()}>API Docs</span>
                  <ExternalLink />
                </SidebarMenu.Item>
              </SidebarMenu.Group>
              <SidebarMenu.Group>
                <SidebarMenu.GroupLabel>Organization</SidebarMenu.GroupLabel>
                <SidebarMenu.Item href="#">
                  <Users />
                  Team
                </SidebarMenu.Item>
                <SidebarMenu.Item href="#">
                  <GasFee />
                  Fee payer
                </SidebarMenu.Item>
                <SidebarMenu.Item href="#">
                  <Settings />
                  Settings
                </SidebarMenu.Item>
              </SidebarMenu.Group>
            </SidebarMenu.Root>
          </AppShell.SidebarBody>
          <AppShell.SidebarFooter>
            <Menu.Root>
              <Menu.Trigger
                render={<SidebarMenu.Item render={<button type="button" />} />}
                aria-label="Account menu"
              >
                <Identicon address="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" size="24" />
                <span {...styles.grow()}>jake@tempo.xyz</span>
                <MoreHorizontal />
              </Menu.Trigger>
              <Menu.Popup side="top">
                <Menu.Item>
                  <Plus />
                  New organization
                </Menu.Item>
                <Menu.Item intent="negative">
                  <LogOut />
                  Log out
                </Menu.Item>
              </Menu.Popup>
            </Menu.Root>
          </AppShell.SidebarFooter>
        </AppShell.Sidebar>
        <AppShell.Main style={{ overflowY: 'auto' }}>
          <AppShell.Header>
            <AppShell.Title>API Keys</AppShell.Title>
            <div {...styles.actions()}>
              <Button size="small">New key</Button>
              <AppShell.Trigger />
            </div>
          </AppShell.Header>
          <div {...styles.list()}>
            {keys.map((key) => (
              <Surface key={key}>
                <p {...styles.name()}>{key}</p>
                <p {...styles.caption()}>Created 3 days ago</p>
              </Surface>
            ))}
          </div>
        </AppShell.Main>
      </AppShell.Root>
    </div>
  )
}

namespace styles {
  export const actions = style({ alignItems: 'center', columnGap: '2', display: 'flex' })

  export const caption = style({ color: 'gray.900', margin: '0', typography: 'label.12' })

  // The transform makes the frame the containing block for the mobile drawer.
  export const frame = style({
    borderRadius: '3xl',
    height: '32rem !custom',
    overflow: 'hidden',
    transform: 'translateZ(0) !custom',
    selectors: {
      // The maximized gallery preview shows the shell at full window height.
      ':root[data-maximized] &': { borderRadius: '0px !custom', height: '100vh !custom' },
    },
  })

  export const grow = style({ flex: '1 !custom', minWidth: '0 !custom' })

  export const list = style({ display: 'flex', flexDirection: 'column', rowGap: '3' })

  export const name = style({ margin: '0', typography: 'label.14' })

  export const stack = style({ display: 'flex', flex: '1 !custom', flexDirection: 'column' })
}
```

[View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/AppShell/Basic.tsx)

## Guidelines

TODO: Write guidelines for AppShell.
