Skip to content
All Taste components

Dashboards

Sales pipeline

A deal board for a services team, with stage totals, owners, due dates and a card mid-drag.

sidebar · pipeline totals · filters · 4-stage board · tags · drag state

Pipelines / Projects
Open pipeline
₹28,30,000
Weighted
₹11,64,000
Won this month
₹8,20,000
New lead3₹6.8L
Sahyadri Clinics
Patient booking app
₹3,20,000·TodayRS
Mehta Textiles
B2B order portal
₹2,10,000·FriAK
Pinecrest School
Fee collection
₹1,50,000·Oct 22RS
Qualified2₹9.4L
Kaveri Foods
Distributor dashboard
Hot
₹4,80,000·MonMN
Orbit Logistics
Driver tracking
₹4,60,000·Oct 24AK
Proposal sent3₹12.1L
Bluefern Studio
Website redesign
Viewed twice
₹1,90,000·Waiting 3dMN
Coastal Spice Co.
D2C store + app
₹7,40,000·Oct 19RS
Nilgiri Traders
Inventory sync
₹2,80,000·Oct 25AK
Won2₹8.2L
Sharma Hardware
Billing + GST
Paid 50%
₹2,40,000·Signed 12 OctMN
Lotus Yoga Studio
Class booking
₹1,10,000·Signed 9 OctRS
import { ChevronDown, Filter, Home, Inbox, KanbanSquare, LineChart, Plus, Search, Building2, Users } from "lucide-react";
import { cn } from "@/lib/utils";

const nav = [
  { label: "Home", icon: Home },
  { label: "Pipeline", icon: KanbanSquare, current: true },
  { label: "Contacts", icon: Users, count: 248 },
  { label: "Companies", icon: Building2 },
  { label: "Inbox", icon: Inbox, count: 5 },
  { label: "Reports", icon: LineChart },
];

type Deal = { company: string; project: string; value: string; owner: string; due: string; tag?: { label: string; tone: "danger" | "info" | "success" } };

const stages: { name: string; dot: string; total: string; deals: Deal[] }[] = [
  { name: "New lead", dot: "bg-fg-subtle", total: "₹6.8L", deals: [
    { company: "Sahyadri Clinics", project: "Patient booking app", value: "₹3,20,000", owner: "RS", due: "Today" },
    { company: "Mehta Textiles", project: "B2B order portal", value: "₹2,10,000", owner: "AK", due: "Fri" },
    { company: "Pinecrest School", project: "Fee collection", value: "₹1,50,000", owner: "RS", due: "Oct 22" },
  ] },
  { name: "Qualified", dot: "bg-info", total: "₹9.4L", deals: [
    { company: "Kaveri Foods", project: "Distributor dashboard", value: "₹4,80,000", owner: "MN", due: "Mon", tag: { label: "Hot", tone: "danger" } },
    { company: "Orbit Logistics", project: "Driver tracking", value: "₹4,60,000", owner: "AK", due: "Oct 24" },
  ] },
  { name: "Proposal sent", dot: "bg-warning", total: "₹12.1L", deals: [
    { company: "Bluefern Studio", project: "Website redesign", value: "₹1,90,000", owner: "MN", due: "Waiting 3d", tag: { label: "Viewed twice", tone: "info" } },
    { company: "Coastal Spice Co.", project: "D2C store + app", value: "₹7,40,000", owner: "RS", due: "Oct 19" },
    { company: "Nilgiri Traders", project: "Inventory sync", value: "₹2,80,000", owner: "AK", due: "Oct 25" },
  ] },
  { name: "Won", dot: "bg-success", total: "₹8.2L", deals: [
    { company: "Sharma Hardware", project: "Billing + GST", value: "₹2,40,000", owner: "MN", due: "Signed 12 Oct", tag: { label: "Paid 50%", tone: "success" } },
    { company: "Lotus Yoga Studio", project: "Class booking", value: "₹1,10,000", owner: "RS", due: "Signed 9 Oct" },
  ] },
];

const tagTone = { danger: "bg-danger-soft text-danger-fg", info: "bg-info-soft text-info-fg", success: "bg-success-soft text-success-fg" };

const summary = [
  { label: "Open pipeline", value: "₹28,30,000" },
  { label: "Weighted", value: "₹11,64,000" },
  { label: "Won this month", value: "₹8,20,000" },
];

export default function PipelinePage() {
  return (
    <div className="flex min-h-screen bg-bg font-sans text-sm text-fg">
      <aside aria-label="Main" className="hidden w-56 shrink-0 flex-col gap-0.5 border-r border-border bg-surface p-3 lg:flex">
        <p className="mb-2 flex h-8 items-center gap-2 px-1.5 font-medium">
          <span className="grid size-6 place-items-center rounded-sm bg-primary text-xs font-semibold text-primary-fg">N</span>Northwind Studio
        </p>
        <nav className="grid gap-0.5">
          {nav.map(({ label, icon: Icon, current, count }) => (
            <a key={label} href="#" aria-current={current ? "page" : undefined}
              className={cn("flex h-8 items-center gap-2.5 rounded px-2 font-medium text-fg-muted hover:bg-surface-2 hover:text-fg",
                current && "bg-bg text-fg shadow-sm ring-1 ring-border")}>
              <Icon className="size-4" aria-hidden />{label}
              {count && <span className="ml-auto text-xs tabular-nums text-fg-subtle">{count}</span>}
            </a>
          ))}
        </nav>
      </aside>

      <div className="flex min-w-0 flex-1 flex-col">
        <header className="flex h-14 items-center gap-3 border-b border-border px-4 sm:px-6">
          <p className="text-fg-muted">Pipelines <span className="text-fg-subtle">/</span> <span className="font-medium text-fg">Projects</span></p>
          <label className="ml-auto hidden h-9 w-64 items-center gap-2 rounded border border-border bg-surface px-2.5 text-fg-subtle md:flex">
            <Search className="size-4" aria-hidden />
            <input placeholder="Search deals and people" className="w-full bg-transparent text-[13px] text-fg outline-none placeholder:text-fg-subtle" />
          </label>
          <button type="button" className="inline-flex h-9 items-center gap-1.5 rounded bg-primary px-3 font-medium text-primary-fg hover:bg-primary-hover">
            <Plus className="size-4" aria-hidden /> Add deal
          </button>
        </header>

        <main className="flex min-h-0 flex-1 flex-col gap-4 p-4 sm:p-6">
          <h1 className="sr-only">Projects pipeline</h1>
          <div className="flex flex-wrap items-center justify-between gap-4">
            <dl className="flex flex-wrap gap-6">
              {summary.map((s) => (
                <div key={s.label}><dt className="text-xs text-fg-subtle">{s.label}</dt><dd className="text-xl font-medium tracking-tight tabular-nums">{s.value}</dd></div>
              ))}
            </dl>
            <div className="flex items-center gap-2">
              <button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-full border border-border bg-surface px-3 text-xs font-medium">
                <Users className="size-3.5" aria-hidden /> Owner: Everyone <ChevronDown className="size-3.5" aria-hidden />
              </button>
              <button type="button" className="inline-flex h-8 items-center gap-1.5 rounded-full border border-dashed border-border-strong px-3 text-xs font-medium text-fg-muted">
                <Filter className="size-3.5" aria-hidden /> Filter
              </button>
            </div>
          </div>

          <div className="-mx-4 flex snap-x gap-3 overflow-x-auto px-4 pb-2 sm:mx-0 sm:px-0 lg:grid lg:grid-cols-4">
            {stages.map((stage) => (
              <section key={stage.name} aria-label={stage.name} className="flex w-72 shrink-0 snap-start flex-col gap-2 rounded-lg bg-surface p-2 lg:w-auto">
                <div className="flex items-center gap-1.5 px-1 py-0.5 text-[13px] font-medium">
                  <span className={cn("size-2 rounded-full", stage.dot)} />{stage.name}
                  <span className="text-xs text-fg-subtle">{stage.deals.length}</span>
                  <span className="ml-auto text-xs tabular-nums text-fg-muted">{stage.total}</span>
                </div>
                {stage.deals.map((d) => (
                  <article key={d.company} className="grid cursor-grab gap-2 rounded border border-border bg-bg p-3 shadow-sm transition hover:border-border-strong">
                    <div>
                      <h3 className="text-[13px] font-medium">{d.company}</h3>
                      <p className="text-xs text-fg-subtle">{d.project}</p>
                    </div>
                    {d.tag && <span className={cn("w-fit rounded-full px-2 py-0.5 text-[11px] font-medium", tagTone[d.tag.tone])}>{d.tag.label}</span>}
                    <div className="flex items-center gap-1.5 text-xs text-fg-muted">
                      <span className="font-medium tabular-nums text-fg">{d.value}</span><span>·</span><span>{d.due}</span>
                      <span className="ml-auto grid size-6 place-items-center rounded-full bg-primary-soft text-[10px] font-semibold text-primary-soft-fg">{d.owner}</span>
                    </div>
                  </article>
                ))}
                <button type="button" className="flex h-8 items-center gap-1.5 rounded px-2 text-[13px] text-fg-subtle hover:bg-surface-2 hover:text-fg">
                  <Plus className="size-4" aria-hidden /> Add
                </button>
              </section>
            ))}
          </div>
        </main>
      </div>
    </div>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.