# Shop

> A complete screen built from Alert, Button, Funnel, PageHeader and 5 more components.

Pattern · Pro kit · [Live page](https://ui.twentyfirst.media/pro/patterns/ShopScreen/)

## Code

```tsx
import * as React from "react";
import {
  Alert,
  Button,
  Funnel,
  PageHeader,
  Panel,
  StackedBarChart,
  StatTile,
} from "@twentyfirstmedia/pro";
import { Shell } from "./_workspace";
import type { SubNavItem } from "@twentyfirstmedia/pro";

function App() {
  const pages: SubNavItem[] = [
    {
      id: "Overview",
      label: "Overview",
      icon: "chart",
    },
    {
      id: "Products",
      label: "Products",
      icon: "package",
    },
    {
      id: "Orders",
      label: "Orders",
      icon: "truck",
      count: 8,
    },
    {
      id: "Storefront",
      label: "Storefront",
      icon: "cart",
    },
  ];
  return (
    <Shell
      area="Shop"
      current="Overview"
      action={{
        label: "Add product",
        icon: "plus",
      }}
      pages={pages}
    >
      <PageHeader
        title="Shop"
        subtitle="Halo Goods · last 7 days"
        actions={[
          <Button key="v" variant="secondary" icon="arrowUpRight">
            View store
          </Button>,
        ]}
      />
      <Alert
        tone="warning"
        title="3 products are running low"
        action={
          <Button size="sm" variant="secondary">
            Review stock
          </Button>
        }
      >
        Studio Mug (6 left), Canvas Tote (sold out), Court Sneaker (9 left).
      </Alert>
      <div
        className="tf-grid"
        style={
          {
            "--cols": "repeat(4, minmax(0, 1fr))",
            "--cols-sm": "repeat(2, minmax(0, 1fr))",
            "--cols-md": "repeat(2, minmax(0, 1fr))",
          } as React.CSSProperties
        }
      >
        <StatTile tint="butter" value="€5,592" label="Revenue" />
        <StatTile tint="sky" value="36" label="Orders" />
        <StatTile tint="mint" value="€155" label="Average order" />
        <StatTile tint="placeholder" value="11" label="To fulfil" />
      </div>
      <div
        className="tf-grid"
        style={
          {
            "--cols": "minmax(0, 1.6fr) minmax(0, 1fr)",
          } as React.CSSProperties
        }
      >
        <Panel title="Sales by channel">
          <StackedBarChart
            height={160}
            labels={["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]}
            format={(v) => "€" + Math.round(v)}
            series={[
              {
                name: "Online store",
                tint: "sky",
                values: [420, 380, 510, 460, 620, 840, 760],
              },
              {
                name: "Instagram",
                tint: "lilac",
                values: [120, 160, 140, 210, 260, 380, 300],
              },
              {
                name: "Marketplace",
                tint: "butter",
                values: [90, 110, 80, 130, 150, 170, 160],
              },
            ]}
          />
        </Panel>
        <Panel title="Conversion">
          <Funnel
            steps={[
              {
                label: "Visited",
                value: 8420,
              },
              {
                label: "Viewed product",
                value: 3910,
              },
              {
                label: "Added to cart",
                value: 812,
              },
              {
                label: "Ordered",
                value: 214,
              },
            ]}
          />
        </Panel>
      </div>
    </Shell>
  );
}
export default App;
```

## Props

### Alert

| Prop | Type | Notes |
| --- | --- | --- |
| `tone?` | `Exclude<Tone, "neutral">` |  |
| `title?` | `ReactNode` |  |
| `icon?` | `IconName` |  |
| `action?` | `ReactNode` |  |
| `onDismiss?` | `() => void` |  |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Button

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `"primary" \| "secondary" \| "soft" \| "ghost" \| "danger" \| "danger-solid"` |  |
| `size?` | `"md" \| "sm"` |  |
| `icon?` | `IconName` |  |
| `iconRight?` | `IconName` |  |
| `disabled?` | `boolean` |  |
| `type?` | `"button" \| "submit" \| "reset"` |  |
| `onClick?` | `(e: MouseEvent<HTMLButtonElement>) => void` |  |
| `children?` | `ReactNode` |  |
| `asChild?` | `boolean` | Render the single child element (a link, a router Link) with the button's look instead of a <button>. |
| `id?` | `string` |  |
| `name?` | `string` | Form field name and value, sent with the form when this button submits it. |
| `value?` | `string` |  |
| `form?` | `string` | The id of the form this button belongs to, when it sits outside it. |
| `title?` | `string` |  |
| `tabIndex?` | `number` |  |
| `autoFocus?` | `boolean` |  |
| `aria-label?` | `string` |  |
| `aria-labelledby?` | `string` |  |
| `aria-describedby?` | `string` |  |
| `aria-expanded?` | `boolean \| "true" \| "false"` | For disclosure and menu triggers: whether what the button controls is open. |
| `aria-controls?` | `string` |  |
| `aria-haspopup?` | `boolean \| "true" \| "false" \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog"` |  |
| `aria-pressed?` | `boolean \| "true" \| "false" \| "mixed"` | For toggle buttons. |
| `aria-current?` | `boolean \| "true" \| "false" \| "page" \| "step" \| "location" \| "date" \| "time"` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Funnel

| Prop | Type | Notes |
| --- | --- | --- |
| `steps` | `{ label: string; value: number; tint?: Tint }[]` | Required |
| `tint?` | `Tint` |  |
| `format?` | `(v: number) => string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Icon

| Prop | Type | Notes |
| --- | --- | --- |
| `name` | `IconName` | Required |
| `size?` | `number` |  |
| `label?` | `string` |  |
| `className?` | `string` |  |
| `style?` | `CSSProperties` | Inline style on the root element. |

### PageHeader

| Prop | Type | Notes |
| --- | --- | --- |
| `crumbs?` | `(string \| Crumb)[]` | A breadcrumb above the title (see `Breadcrumb`): labels, or items with `href`/`onClick`. |
| `crumbLinkAs?` | `ElementType` | The element crumb links render as, e.g. Next.js `Link`. |
| `title` | `string` | Required |
| `subtitle?` | `string` |  |
| `actions?` | `ReactNode[]` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### Panel

| Prop | Type | Notes |
| --- | --- | --- |
| `side?` | `boolean` |  |
| `title?` | `string` |  |
| `subtitle?` | `string` |  |
| `action?` | `ReactNode` |  |
| `children?` | `ReactNode` |  |
| `surface?` | `Surface` | `"glass"`: translucent glass over what is behind (maps, 3D, video, photos); `"solid"` opts out inside a glass `UIProvider`. |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### StackedBarChart

| Prop | Type | Notes |
| --- | --- | --- |
| `labels` | `string[]` | Required |
| `series` | `Series[]` | Required |
| `height?` | `number` |  |
| `width?` | `number` |  |
| `barWidth?` | `number` |  |
| `format?` | `(v: number) => string` |  |
| `legend?` | `boolean` |  |
| `label?` | `string` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### StatTile

| Prop | Type | Notes |
| --- | --- | --- |
| `value` | `ReactNode` | Required |
| `label` | `string` | Required |
| `tint?` | `Tint \| "surface" \| "placeholder"` |  |
| `delta?` | `string` |  |
| `delay?` | `number` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### SubNav

| Prop | Type | Notes |
| --- | --- | --- |
| `eyebrow?` | `string` |  |
| `action?` | `{ label: string; icon?: IconName; onClick?: () => void }` |  |
| `items` | `SubNavItem[]` | Required |
| `current?` | `string` |  |
| `onPick?` | `(id: string) => void` |  |
| `children?` | `ReactNode` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |

### TopBar

| Prop | Type | Notes |
| --- | --- | --- |
| `brand?` | `ReactNode` | The product name, or a node (a logo mark with the name). |
| `tag?` | `string` |  |
| `items` | `NavItem[]` | Required |
| `active?` | `string` |  |
| `user?` | `{ name: string; email?: string }` |  |
| `onNavigate?` | `(label: string) => void` |  |
| `extra?` | `ReactNode` |  |
| `userOpen?` | `boolean` |  |
| `onUser?` | `() => void` |  |
| `className?` | `string` | Extra class on the root element. |
| `style?` | `CSSProperties` | Inline style on the root element. |
