Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

Dashboard

A web app with a sidebar, an overview of the week's numbers, a table of orders with a page for each, products, search, settings with a plan page, and a sign-in screen, made from the App kit.

The dashboard template is a small web app for running a shop: a sidebar of pages beside a top bar with a search, an overview of metric cards and a chart, a table of orders with filters and a page for each order, products by category, search results, a page with nothing in it yet, a feature to turn on, settings with a plan page under them, and a sign-in screen that the account menu's Sign out leads to. It has a page of every kind buttery add page writes for an app's shell. Use it for an admin, a back office or any app whose screens are pages of numbers, lists and settings.

Start from it

  1. Make the app

    bash

    npx create-buttery my-app --template dashboard

    create-buttery makes my-app in the folder you're in and installs it with the package manager that ran it. The app takes the folder's name, which also replaces "buttery dashboard" in the sidebar.

    Inside the buttery repository, pnpm new-app my-app --template dashboard copies apps/templates/dashboard to apps/my-app instead, with the next free port.

  2. Start it

    bash

    cd my-app
    npm run dev

    Open the address it prints. The template is a web app; --desktop adds the Tauri shell to it, as it does to any template.

What's inside

FileWhat it does
src/App.tsxThe shell: AppShell with a Sidebar, an AccountMenu and a TopBar with a CommandSearch and a New order button that opens a dialog, and the page the address names
src/pages/OverviewPage.tsxTwo MetricCards for the week and a BarChart of sales each day
src/pages/OrdersPage.tsxA DataTable of orders, sorted by a column, with a status filter and a search in a FilterBar
src/pages/OrderPage.tsxA DetailPage for one order, its next step at the top of the aside, under breadcrumbs back to the orders
src/pages/ProductsPage.tsxA CatalogPage of products, one category at a time
src/pages/SearchPage.tsxSearchResults for what the top bar's search found, orders first
src/pages/ReturnsPage.tsxAn EmptyState in a page with no returns yet
src/pages/SubscriptionsPage.tsxA FeatureIntro for subscriptions, before they're turned on
src/pages/SettingsPage.tsxA SettingsIndex of every setting, each opening its own page
src/pages/ShopSettingsPage.tsxA SettingsPage with a form section that saves and a SettingRow that turns emails on and off
src/pages/PlanPage.tsxA PlanComparison of the two plans, monthly or yearly, with the shop's own marked
src/pages/SignInPage.tsxAn AuthFlow on a screen of its own, outside the shell, which goes on to the overview once a code is accepted
src/auth.tsStand-ins for your server's two calls, sending a code and checking it, which accept the demo code 123456; replace them with calls to your server
src/NewOrderDialog.tsxA FormDialog that adds an order once its three fields are filled in
src/data.tsMade-up orders, products and numbers, and the helpers that format them
src/search.tsWhat the top bar's search and the search page look through: the orders and the products
src/status.tsHow each order status reads, and its badge's tone
src/app.cssMakes the app as tall as the window
src/router.tsxThe router every template has; see Routing below
src/main.tsxFollows links, then renders the app inside ButteryProvider
src/index.tsWhat another app imports to show this one, as the docs site does for the preview
e2e/smoke.spec.tsRenders every page with no console errors, and drives the sidebar, the filters, New order, and signing out and back in
e2e/layout.spec.tsRuns expectButtery on every page, with its menus and dialogs open

It's made from these patterns: the app shell, an overview, a data table page, a detail page, a catalog page, search and results, settings pages, plans and authentication.

The overview screen

The app opens on src/pages/OverviewPage.tsx, its main screen: the week's sales and orders in two MetricCards, then sales each day in a BarChart.

tsx

import type { ReactElement } from "react";
import { Grid } from "@butteryui/core";
import {
  AppPage,
  ArrowLink,
  BarChart,
  MetricCard,
  PageHeader,
} from "@butteryui/react";
import { ORDER_COUNTS, SALES, WEEK, change, money, total } from "../data.ts";
import { useLink } from "../router.tsx";

/** The dashboard's front page: the week's numbers, then sales day by day. */
export function OverviewPage(): ReactElement {
  const link = useLink();
  const sales = total(SALES.now);
  const orders = total(ORDER_COUNTS.now);
  return (
    <AppPage
      header={
        <PageHeader
          title="Overview"
          description="How the shop did over the last seven days."
        />
      }
    >
      <AppPage.Section title="This week">
        <Grid columns={{ base: 1, md: 2 }} gap={4}>
          <MetricCard
            title="Sales"
            info="Every sale, before refunds and fees."
            value={money(sales)}
            delta={change(sales, total(SALES.before))}
            labels={WEEK}
            series={[
              { key: "now", label: "This week", values: SALES.now },
              {
                key: "before",
                label: "Last week",
                values: SALES.before,
                comparison: true,
              },
            ]}
            formatValue={money}
            updated="Updated just now"
            href={link("/orders")}
          />
          <MetricCard
            title="Orders"
            value={String(orders)}
            delta={change(orders, total(ORDER_COUNTS.before))}
            labels={WEEK}
            series={[
              { key: "now", label: "This week", values: ORDER_COUNTS.now },
              {
                key: "before",
                label: "Last week",
                values: ORDER_COUNTS.before,
                comparison: true,
              },
            ]}
            updated="Updated just now"
            href={link("/orders")}
          />
        </Grid>
      </AppPage.Section>
      <AppPage.Section
        title="Sales each day"
        actions={<ArrowLink href={link("/orders")}>See orders</ArrowLink>}
      >
        <BarChart
          label="Sales each day this week"
          summary={`${money(sales)} this week, against ${money(total(SALES.before))} the week before.`}
          labels={WEEK}
          labelsHeading="Day"
          series={[
            { key: "now", label: "This week", values: SALES.now },
            {
              key: "before",
              label: "Last week",
              values: SALES.before,
              comparison: true,
            },
          ]}
          formatValue={money}
        />
      </AppPage.Section>
    </AppPage>
  );
}

src/App.tsx shows it inside the AppShell, beside the sidebar and under the top bar, as it does every page. useLink comes from the template's router, and the numbers from src/data.ts.

Routing

Each template has a small router of its own in src/router.tsx, with no dependency, so its pages have real addresses, such as /orders and /settings. The app uses four of its exports:

ExportWhat it does
useRoute()Reads the path and the query from the address, and follows it as it changes
useLink()Turns a path in the app into its address
useNavigate()Goes to a path in the app
followLinks()Makes a click on any link to the app a move within the page, so buttery's link components, which render a plain <a href>, work as they are; src/main.tsx calls it

An order's page answers at its own path, such as /orders/1048, and the search page reads what to look for from the query, such as /search?q=tote.

An app served under a path of its own takes it as base, and every link and deep link keeps that start. The docs site shows this template at /templates/dashboard/preview with:

tsx

<App base="/templates/dashboard/preview" />

A demo made from it

Halfmoon Roastery is this template with a coffee roaster's pages in place of the template's: orders, customers, wholesale, settings and a search across all of it.

  • App shell

    The frame of a whole app, as an editor or a dashboard, and the page that goes in it.

  • Overview

    An app's home page, with headline metrics, a chart, what needs attention and guidance for a new account.

  • Data table page

    A page whose main block is a table, with filters, saved views and the table taking the rest of the height.

  • Detail page

    A page about one thing, with its main column and an aside holding its one primary action.

  • Catalog page

    A page of things to browse, with a filter column beside featured items and grids of cards.

  • Search and results

    The search in an app's top bar, and the page of every result it leads to.

  • Settings pages

    A settings page made of sections, each with a heading, one line about it and its one action.

  • Authentication

    A passwordless sign-in that's also the sign-up, with an email or phone number and then a one-time code, on one surface.