Blocks / Application

Empty project

A first-run screen: a large empty state with one way in, an onboarding checklist and an offer of a call.

Width

Marrow, Wilton Way

Marrow is set up. Now give it something to count.

No stock on the shelves yet

Larder only knows what you tell it you keep. Bring in your stock list and the first full count takes about 40 minutes for a kitchen of 60 covers.

Getting Marrow ready

  1. Add your stock list

    Import the spreadsheet you already keep, with names, units and par levels. Larder matches the columns and asks about the ones it cannot place.

  2. Connect your till

    Each dish sold takes its ingredients off the shelf, so stock falls during service without anyone counting.

  3. Add your suppliers

    Natoora, Neal's Yard Dairy, Flock & Herd: add who you buy from and their cut-off times, and orders build themselves from what is low.

  4. Do your first count

    Walk the walk-in, the dry store and the bar with a phone. Every count after this one is shorter.

  5. Invite your team, done

    Priya invited Ines, Tom, Kasia, Sam and Leo on Monday.

Install

Writes the block to components/blocks/empty-project.tsx and its .css, and every part it uses to components/equip/, with the parts those are built from.

npx https://equip.studio311.app/equip.tgz add block:empty-project

Built from 8 parts

Notes

  • The page heading is its own h1, because EmptyState titles go from h2 to h4; the empty state, checklist and help card are each an h2.
  • Checklist counts its direct ChecklistItem children for the progress bar, so keep the items as direct children and set done from your own data.
  • The glyph is an inline SVG passed to EmptyState's icon, drawn on a 48 grid so its stroke stays light in the 96px tile of size="l".
  • It renders on the server; wire the Buttons to your router or upload flow.

Source

components/blocks/empty-project.tsx150 lines
import { Avatar } from "@/components/equip/avatar";
import { Button } from "@/components/equip/button";
import { Card, CardBody } from "@/components/equip/card";
import { Checklist, ChecklistItem } from "@/components/equip/checklist";
import { EmptyState, EmptyStateActions } from "@/components/equip/empty-state";
import { Heading } from "@/components/equip/heading";
import { Icon } from "@/components/equip/icon";
import { Text } from "@/components/equip/text";
import "./empty-project.css";

/* Two bare shelves: one jar and one box drawn in dashes, waiting to be counted. */
function EmptyShelf() {
  return (
    <svg
      className="blk-empty-project-glyph"
      viewBox="0 0 48 48"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      <path d="M6 19h36" />
      <path d="M6 37h36" />
      <path d="M10 19v3M38 19v3M10 37v3M38 37v3" />
      <path d="M27 19v4.5h8V19" />
      <path d="M13 37v-7.5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2V37" strokeDasharray="2 3" />
      <path d="M14 27.5v-2h6v2" strokeDasharray="2 3" />
      <path d="M25 37v-9h10v9" strokeDasharray="2 3" />
    </svg>
  );
}

/*
 * The first screen of a new kitchen: nothing counted yet, one clear way in, the five
 * things that make Larder useful, and a person to call for anyone who would rather not.
 */
export default function EmptyProject() {
  return (
    <div className="blk-empty-project">
      <div className="blk-empty-project-inner">
        <header className="blk-empty-project-top">
          <Text size="s" tone="faint">
            Marrow, Wilton Way
          </Text>
          <Heading level={1} className="blk-empty-project-title">
            Marrow is set up. Now give it something to count.
          </Heading>
        </header>

        <div className="blk-empty-project-layout">
          <div className="blk-empty-project-main">
            <div className="blk-empty-project-stage">
              <EmptyState
                className="blk-empty-project-empty"
                size="l"
                headingLevel={2}
                title="No stock on the shelves yet"
                icon={<EmptyShelf />}
              >
                <Text size="m" tone="quiet">
                  Larder only knows what you tell it you keep. Bring in your stock list and the first full count takes
                  about 40 minutes for a kitchen of 60 covers.
                </Text>
                <EmptyStateActions>
                  <Button variant="accent" size="l" lead={<Icon name="upload" />}>
                    Import a stock list
                  </Button>
                  <Button variant="outline" size="l">
                    Add items by hand
                  </Button>
                </EmptyStateActions>
              </EmptyState>
            </div>

            <Checklist title="Getting Marrow ready" className="blk-empty-project-checklist">
              <ChecklistItem title="Add your stock list" defaultOpen>
                <Text size="s" tone="quiet">
                  Import the spreadsheet you already keep, with names, units and par levels. Larder matches the columns
                  and asks about the ones it cannot place.
                </Text>
                <Button size="s" lead={<Icon name="file-plus" />}>
                  Import a spreadsheet
                </Button>
              </ChecklistItem>
              <ChecklistItem title="Connect your till">
                <Text size="s" tone="quiet">
                  Each dish sold takes its ingredients off the shelf, so stock falls during service without anyone
                  counting.
                </Text>
                <Button size="s" variant="outline" lead={<Icon name="plug" />}>
                  Choose your till
                </Button>
              </ChecklistItem>
              <ChecklistItem title="Add your suppliers">
                <Text size="s" tone="quiet">
                  Natoora, Neal&apos;s Yard Dairy, Flock &amp; Herd: add who you buy from and their cut-off times, and
                  orders build themselves from what is low.
                </Text>
                <Button size="s" variant="outline" lead={<Icon name="truck" />}>
                  Add suppliers
                </Button>
              </ChecklistItem>
              <ChecklistItem title="Do your first count">
                <Text size="s" tone="quiet">
                  Walk the walk-in, the dry store and the bar with a phone. Every count after this one is shorter.
                </Text>
                <Button size="s" variant="outline" lead={<Icon name="clipboard-check" />}>
                  Start a count
                </Button>
              </ChecklistItem>
              <ChecklistItem title="Invite your team" done>
                <Text size="s" tone="quiet">
                  Priya invited Ines, Tom, Kasia, Sam and Leo on Monday.
                </Text>
                <Button size="s" variant="outline" lead={<Icon name="user-plus" />}>
                  Invite someone else
                </Button>
              </ChecklistItem>
            </Checklist>
          </div>

          <aside className="blk-empty-project-side" aria-labelledby="empty-project-help-title">
            <Card className="blk-empty-project-help">
              <CardBody className="blk-empty-project-help-body">
                <Avatar name="Rosa Mendes" size="l" alt="" />
                <div className="blk-empty-project-help-copy">
                  <Heading level={2} size="s" id="empty-project-help-title">
                    Prefer a hand?
                  </Heading>
                  <Text size="s" tone="quiet">
                    Rosa Mendes ran the pass at a 50-cover place in Peckham for nine years. On a 30 minute call she
                    will set up your stock list with you, from whatever you have.
                  </Text>
                </div>
                <Button variant="outline" lead={<Icon name="calendar" />}>
                  Book a call with Rosa
                </Button>
                <Text size="s" tone="faint">
                  Free on every plan. Weekdays, 10:00 to 16:00, between services.
                </Text>
              </CardBody>
            </Card>
          </aside>
        </div>
      </div>
    </div>
  );
}
components/blocks/empty-project.css96 lines
@layer blocks {
  .blk-empty-project {
    container: blk-empty-project / inline-size;
    background: var(--eq-bg);
    color: var(--eq-ink);
  }

  .blk-empty-project-inner {
    display: grid;
    gap: calc(var(--eq-space-6) * 1.25);
    max-width: 76rem;
    margin-inline: auto;
    padding: calc(var(--eq-space-6) * 1.25) var(--eq-space-4) calc(var(--eq-space-6) * 1.5);
  }

  .blk-empty-project-top {
    display: grid;
    gap: var(--eq-space-2);
    max-width: 40rem;
  }

  .blk-empty-project-top > * {
    margin: 0;
  }

  .blk-empty-project-title {
    font-size: clamp(1.875rem, 6.5cqi, 3.25rem);
    line-height: 1.04;
    letter-spacing: -0.03em;
    text-wrap: balance;
  }

  .blk-empty-project-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--eq-space-5);
  }

  .blk-empty-project-main {
    display: grid;
    gap: var(--eq-space-5);
    min-width: 0;
  }

  /* The empty shelf sits on the dotted grid used for product pictures: a space waiting to be filled. */
  .blk-empty-project-stage {
    border: 1px solid var(--eq-line);
    border-radius: var(--eq-radius-l);
    background:
      radial-gradient(circle at 1px 1px, var(--eq-line-strong) 1px, transparent 0) 0 0 / 18px 18px,
      color-mix(in oklab, var(--eq-surface) 70%, var(--eq-bg));
  }

  .blk-empty-project-checklist {
    min-width: 0;
  }

  .blk-empty-project-side {
    min-width: 0;
  }

  .blk-empty-project-help-body {
    display: grid;
    justify-items: start;
    gap: var(--eq-space-3);
  }

  .blk-empty-project-help-body > p,
  .blk-empty-project-help-copy > * {
    margin: 0;
  }

  .blk-empty-project-help-copy {
    display: grid;
    gap: var(--eq-space-1);
  }

  @container blk-empty-project (width >= 40rem) {
    .blk-empty-project-inner {
      padding-inline: var(--eq-space-6);
    }
  }

  @container blk-empty-project (width >= 60rem) {
    .blk-empty-project-layout {
      grid-template-columns: minmax(0, 1fr) 18rem;
      gap: calc(var(--eq-space-6) * 1.25);
      align-items: start;
    }

    .blk-empty-project-side {
      position: sticky;
      top: var(--eq-space-4);
    }
  }
}

EqUIp is in beta: free for non-commercial use, no warranty, and things can change. Terms

Nothing picked yet. Press A on a part, or use the plus on the board, and the install command builds here.

Loading the index.

Loading the index