Blocks / Marketing

Testimonials

A large pull quote with the figure behind it, three short quotes with results, and a row of customer names.

Width

From the kitchens

Less in the bin, and fewer late calls to suppliers.

We cut waste from 7% to 3% of food spend in ten weeks. Nobody worked harder. We just stopped ordering cream for a Tuesday that was never going to come.

Ines DuarteHead chef, Marrow, Wilton Way, Hackney
Waste, as a share of food spend3%Was 7% the week before Larder
Values, oldest first: 7.1, 6.8, 6.4, 5.7, 5.2, 4.6, 4.1, 3.6, 3.2, 3
  • I used to count flour sacks on a Sunday night. Now they are scanned in when the pallet lands, and Sunday is mine again.

    Aoife BrennanOwner and baker, Halfmoon Bakery, Bristol
    4 hours a week back
  • Moving oat milk between three cafes was a group chat and a guess. Now it is a transfer, and both counts agree at close.

    Dev MalhotraOperations lead, Fieldhouse Cafes, Manchester
    3 sites, one stock count
  • It showed we were binning a third of the Sunday beef. We dropped two ribs from the order and only the accountant noticed.

    Rhian EvansLandlady and cook, The Drovers Arms, Llandeilo
    £310 a month less on beef

Kitchens counting with Larder

  • Marrow
  • Halfmoon Bakery
  • The Drovers Arms
  • Fieldhouse
  • Little Fennel
  • Bramble & Rye
  • Tidewater
  • Okra Kitchen

Install

Writes the block to components/blocks/testimonials.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:testimonials

Built from 7 parts

Notes

  • Every quote is a figure with a blockquote and a figcaption, so the words stay tied to the person who said them.
  • Avatars take an empty alt because the name is written beside them; pass src for real photos.
  • The customer names are styled text in a labelled list; swap in logo images with alt text if you have them.

Source

components/blocks/testimonials.tsx158 lines
import { Avatar } from "@/components/equip/avatar";
import { Badge } from "@/components/equip/badge";
import { Card } from "@/components/equip/card";
import { Heading } from "@/components/equip/heading";
import { Sparkline } from "@/components/equip/sparkline";
import { Stat } from "@/components/equip/stat";
import { Text } from "@/components/equip/text";
import "./testimonials.css";

/*
 * What kitchens say after a few months: one long quote with the number behind it, three short ones
 * hung on a ticket rail like orders on the pass, and a row of kitchens set as type.
 */
export default function Testimonials() {
  return (
    <section className="blk-testimonials" aria-labelledby="testimonials-title">
      <div className="blk-testimonials-inner">
        <header className="blk-testimonials-head">
          <Text size="s" weight="strong" tone="quiet">
            From the kitchens
          </Text>
          <Heading level={2} id="testimonials-title" className="blk-testimonials-title">
            Less in the bin, and fewer late calls to suppliers.
          </Heading>
        </header>

        <div className="blk-testimonials-feature">
          <figure className="blk-testimonials-feature-words">
            <span className="blk-testimonials-mark" aria-hidden="true">
              &ldquo;
            </span>
            <blockquote className="blk-testimonials-quote">
              <p>
                We cut waste from 7% to 3% of food spend in ten weeks. Nobody worked harder. We just stopped ordering
                cream for a Tuesday that was never going to come.
              </p>
            </blockquote>
            <figcaption className="blk-testimonials-who">
              <Avatar name="Ines Duarte" alt="" size="l" />
              <span className="blk-testimonials-who-text">
                <Text as="span" weight="strong">Ines Duarte</Text>
                <Text as="span" size="s" tone="quiet">Head chef, Marrow, Wilton Way, Hackney</Text>
              </span>
            </figcaption>
          </figure>

          <div className="blk-testimonials-proof">
            <Stat
              label="Waste, as a share of food spend"
              value={3}
              unit="%"
              hint="Was 7% the week before Larder"
              locale="en-GB"
            />
            <div className="blk-testimonials-spark">
              <Sparkline
                className="blk-testimonials-spark-line"
                label="Waste as a percent of food spend, weekly for ten weeks"
                values={[7.1, 6.8, 6.4, 5.7, 5.2, 4.6, 4.1, 3.6, 3.2, 3]}
                width={200}
                height={56}
                min={0}
                area
                showLast
                locale="en-GB"
              />
              <span className="blk-testimonials-spark-axis" aria-hidden="true">
                <span>Week 1</span>
                <span>Week 10</span>
              </span>
            </div>
          </div>
        </div>

        <ul className="blk-testimonials-rail" aria-label="More kitchens">
          <Card as="li" className="blk-testimonials-ticket">
            <figure className="blk-testimonials-small">
              <blockquote className="blk-testimonials-small-quote">
                <p>
                  I used to count flour sacks on a Sunday night. Now they are scanned in when the pallet lands, and
                  Sunday is mine again.
                </p>
              </blockquote>
              <figcaption className="blk-testimonials-who">
                <Avatar name="Aoife Brennan" alt="" />
                <span className="blk-testimonials-who-text">
                  <Text as="span" size="s" weight="strong">Aoife Brennan</Text>
                  <Text as="span" size="s" tone="quiet">Owner and baker, Halfmoon Bakery, Bristol</Text>
                </span>
              </figcaption>
            </figure>
            <div className="blk-testimonials-result">
              <Badge tone="ok" dot>4 hours a week back</Badge>
            </div>
          </Card>

          <Card as="li" className="blk-testimonials-ticket">
            <figure className="blk-testimonials-small">
              <blockquote className="blk-testimonials-small-quote">
                <p>
                  Moving oat milk between three cafes was a group chat and a guess. Now it is a transfer, and both
                  counts agree at close.
                </p>
              </blockquote>
              <figcaption className="blk-testimonials-who">
                <Avatar name="Dev Malhotra" alt="" />
                <span className="blk-testimonials-who-text">
                  <Text as="span" size="s" weight="strong">Dev Malhotra</Text>
                  <Text as="span" size="s" tone="quiet">Operations lead, Fieldhouse Cafes, Manchester</Text>
                </span>
              </figcaption>
            </figure>
            <div className="blk-testimonials-result">
              <Badge dot>3 sites, one stock count</Badge>
            </div>
          </Card>

          <Card as="li" className="blk-testimonials-ticket">
            <figure className="blk-testimonials-small">
              <blockquote className="blk-testimonials-small-quote">
                <p>
                  It showed we were binning a third of the Sunday beef. We dropped two ribs from the order and only
                  the accountant noticed.
                </p>
              </blockquote>
              <figcaption className="blk-testimonials-who">
                <Avatar name="Rhian Evans" alt="" />
                <span className="blk-testimonials-who-text">
                  <Text as="span" size="s" weight="strong">Rhian Evans</Text>
                  <Text as="span" size="s" tone="quiet">Landlady and cook, The Drovers Arms, Llandeilo</Text>
                </span>
              </figcaption>
            </figure>
            <div className="blk-testimonials-result">
              <Badge tone="ok" dot>£310 a month less on beef</Badge>
            </div>
          </Card>
        </ul>

        <div className="blk-testimonials-kitchens">
          <Text size="s" tone="faint" className="blk-testimonials-kitchens-label" id="testimonials-kitchens-label">
            Kitchens counting with Larder
          </Text>
          <ul className="blk-testimonials-marks" aria-labelledby="testimonials-kitchens-label">
            <li className="blk-testimonials-wordmark" data-look="heavy">Marrow</li>
            <li className="blk-testimonials-wordmark" data-look="italic">Halfmoon Bakery</li>
            <li className="blk-testimonials-wordmark" data-look="mono">The Drovers Arms</li>
            <li className="blk-testimonials-wordmark" data-look="spaced">Fieldhouse</li>
            <li className="blk-testimonials-wordmark" data-look="boxed">Little Fennel</li>
            <li className="blk-testimonials-wordmark" data-look="italic">Bramble &amp; Rye</li>
            <li className="blk-testimonials-wordmark" data-look="heavy">Tidewater</li>
            <li className="blk-testimonials-wordmark" data-look="mono">Okra Kitchen</li>
          </ul>
        </div>
      </div>
    </section>
  );
}
components/blocks/testimonials.css293 lines
@layer blocks {
  .blk-testimonials {
    container: blk-testimonials / inline-size;
    background: var(--eq-bg);
    color: var(--eq-ink);
  }

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

  .blk-testimonials-head {
    display: grid;
    justify-items: start;
    gap: var(--eq-space-3);
    max-width: 40rem;
  }

  .blk-testimonials-head > * {
    margin: 0;
  }

  .blk-testimonials-title {
    font-size: clamp(1.75rem, 5.5cqi, 3rem);
    line-height: 1.06;
    letter-spacing: -0.025em;
    text-wrap: balance;
  }

  /* ---- The pull quote ---- */

  .blk-testimonials-feature {
    display: grid;
    gap: var(--eq-space-6);
    padding: var(--eq-space-5) var(--eq-space-4);
    border: 1px solid var(--eq-line);
    border-radius: var(--eq-radius-l);
    background: var(--eq-surface);
  }

  .blk-testimonials-feature-words {
    display: grid;
    align-content: start;
    gap: var(--eq-space-5);
    min-width: 0;
    margin: 0;
  }

  .blk-testimonials-mark {
    display: block;
    height: 0.5em;
    margin-bottom: calc(var(--eq-space-3) * -1);
    color: var(--eq-ink-3);
    font: var(--eq-weight-strong) calc(var(--eq-text-l) * 5) / 1 var(--eq-font);
  }

  .blk-testimonials-quote {
    margin: 0;
  }

  .blk-testimonials-quote > p {
    margin: 0;
    color: var(--eq-ink);
    font: var(--eq-weight-strong) clamp(1.375rem, 4.2cqi, 2.375rem) / 1.18 var(--eq-font);
    letter-spacing: -0.02em;
    text-wrap: pretty;
  }

  .blk-testimonials-who {
    display: flex;
    align-items: center;
    gap: var(--eq-space-3);
    min-width: 0;
  }

  .blk-testimonials-who-text {
    display: grid;
    min-width: 0;
  }

  .blk-testimonials-who-text > * {
    margin: 0;
  }

  /* The number behind the quote: a figure and ten weeks of it falling. */
  .blk-testimonials-proof {
    display: grid;
    align-content: space-between;
    gap: var(--eq-space-5);
    min-width: 0;
    padding: var(--eq-space-4);
    border-radius: var(--eq-radius-m);
    border: 1px solid var(--eq-line);
    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) 60%, var(--eq-bg));
  }

  .blk-testimonials-spark {
    display: grid;
    gap: var(--eq-space-1);
    width: fit-content;
    max-width: 100%;
  }

  .blk-testimonials-spark-line {
    color: var(--eq-chart-1);
  }

  .blk-testimonials-spark-axis {
    display: flex;
    justify-content: space-between;
    color: var(--eq-ink-3);
    font: var(--eq-weight) var(--eq-text-xs) / 1.2 var(--eq-font-mono);
    font-variation-settings: var(--eq-font-mono-settings);
  }

  /* ---- The ticket rail: short quotes hang from a bar like orders on the pass ---- */

  .blk-testimonials-rail {
    --_hang: calc(var(--eq-space-5) + var(--eq-space-2));

    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: calc(var(--_hang) + var(--eq-space-5)) var(--eq-space-4);
    margin: 0;
    padding: var(--_hang) 0 0;
    list-style: none;
  }

  .blk-testimonials-ticket {
    justify-content: space-between;
  }

  /* The rail, drawn per ticket so a stacked column still hangs; side by side the pieces meet in the gap. */
  .blk-testimonials-ticket::after {
    content: "";
    position: absolute;
    z-index: 0;
    top: calc(var(--_hang) * -1);
    inset-inline: calc(var(--eq-space-4) / -2);
    height: var(--eq-space-2);
    box-sizing: border-box;
    border-block: 1px solid var(--eq-line-strong);
    background: var(--eq-tint-strong);
  }

  /* The clip each ticket hangs from. */
  .blk-testimonials-ticket::before {
    content: "";
    position: absolute;
    z-index: 1;
    top: calc(var(--_hang) * -1 + var(--eq-space-1));
    inset-inline-start: var(--eq-space-5);
    box-sizing: border-box;
    width: var(--eq-space-3);
    height: calc(var(--_hang) - var(--eq-space-1) + 1px);
    border: 1px solid var(--eq-line-strong);
    border-radius: var(--eq-radius-s);
    background: var(--eq-surface);
  }

  .blk-testimonials-small {
    display: grid;
    gap: var(--eq-space-4);
    margin: 0;
  }

  .blk-testimonials-small-quote {
    margin: 0;
  }

  .blk-testimonials-small-quote > p {
    margin: 0;
    color: var(--eq-ink);
    font-size: var(--eq-text-l);
    line-height: 1.45;
    text-wrap: pretty;
  }

  .blk-testimonials-result {
    display: flex;
    padding-top: var(--eq-space-3);
    border-top: 1px dashed var(--eq-line-strong);
  }

  /* ---- Kitchens, set as type ---- */

  .blk-testimonials-kitchens {
    display: grid;
    gap: var(--eq-space-4);
    padding-top: var(--eq-space-5);
    border-top: 1px solid var(--eq-line);
  }

  .blk-testimonials-kitchens-label {
    margin: 0;
  }

  .blk-testimonials-marks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--eq-space-4) var(--eq-space-6);
    margin: 0;
    padding: 0;
    list-style: none;
    color: var(--eq-ink-2);
  }

  .blk-testimonials-wordmark {
    margin: 0;
    font: var(--eq-weight-strong) var(--eq-text-l) / 1.2 var(--eq-font);
    white-space: nowrap;
  }

  .blk-testimonials-wordmark[data-look="heavy"] {
    font-size: calc(var(--eq-text-l) * 1.25);
    letter-spacing: -0.04em;
  }

  .blk-testimonials-wordmark[data-look="italic"] {
    font-style: italic;
    font-weight: var(--eq-weight);
    letter-spacing: -0.01em;
  }

  .blk-testimonials-wordmark[data-look="mono"] {
    font: var(--eq-weight) var(--eq-text-m) / 1.2 var(--eq-font-mono);
    font-variation-settings: var(--eq-font-mono-settings);
  }

  .blk-testimonials-wordmark[data-look="spaced"] {
    font-size: var(--eq-text-s);
    letter-spacing: 0.24em;
  }

  .blk-testimonials-wordmark[data-look="boxed"] {
    padding: var(--eq-space-1) var(--eq-space-2);
    border: 1px solid currentColor;
    border-radius: var(--eq-radius-s);
    font-size: var(--eq-text-m);
  }

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

    .blk-testimonials-feature {
      padding: var(--eq-space-6);
    }

    .blk-testimonials-rail {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .blk-testimonials-rail > :last-child {
      grid-column: 1 / -1;
    }
  }

  @container blk-testimonials (width >= 60rem) {
    .blk-testimonials-inner {
      padding-block: calc(var(--eq-space-6) * 2.5);
      gap: calc(var(--eq-space-6) * 1.75);
    }

    .blk-testimonials-feature {
      grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
      gap: calc(var(--eq-space-6) * 1.5);
      padding: calc(var(--eq-space-6) * 1.5);
    }

    .blk-testimonials-rail {
      grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .blk-testimonials-rail > :last-child {
      grid-column: auto;
    }

    .blk-testimonials-kitchens {
      grid-template-columns: auto minmax(0, 1fr);
      align-items: center;
      gap: var(--eq-space-6);
    }
  }
}

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