Skip to content
All Taste components

App screens

Project issues

A team’s issue list grouped by status, with priority, labels, due dates, assignees and cycle progress.

team sidebar · list/board switch · filter chips · 3 status groups · 4 priorities

Storefront / Issues
Cycle progress
58%
In progress3
!KRV-142Checkout fails when a coupon and UPI are used togetherBugOct 16AK
KRV-139Distributor dashboard: outstanding by regionDashboardOct 18MN
KRV-131GST invoice PDF with HSN codesBillingOct 20RS
In review1
KRV-128Order status WhatsApp templates (Hindi, Tamil)MessagingOct 17SR
Todo3
KRV-147Bulk price update from CSVCatalogueOct 23AK
KRV-145Low-stock alerts per warehouseInventoryOct 25MN
KRV-144Empty state for the returns tabDesignOct 28SR
import { Calendar, CircleDashed, Columns3, Filter, Inbox, List, Plus, Target, Users } from "lucide-react";
import { cn } from "@/lib/utils";

const personal = [
  { label: "Inbox", icon: Inbox },
  { label: "My issues", icon: Target },
  { label: "Views", icon: List },
];

type Status = "progress" | "review" | "todo";
type Priority = "urgent" | "high" | "medium" | "low";

const groups: { status: Status; name: string; issues: { id: string; title: string; priority: Priority; label: { name: string; dot: string }; assignee: string; due: string }[] }[] = [
  { status: "progress", name: "In progress", issues: [
    { id: "KRV-142", title: "Checkout fails when a coupon and UPI are used together", priority: "urgent", label: { name: "Bug", dot: "bg-danger" }, assignee: "AK", due: "Oct 16" },
    { id: "KRV-139", title: "Distributor dashboard: outstanding by region", priority: "high", label: { name: "Dashboard", dot: "bg-info" }, assignee: "MN", due: "Oct 18" },
    { id: "KRV-131", title: "GST invoice PDF with HSN codes", priority: "medium", label: { name: "Billing", dot: "bg-primary" }, assignee: "RS", due: "Oct 20" },
  ] },
  { status: "review", name: "In review", issues: [
    { id: "KRV-128", title: "Order status WhatsApp templates (Hindi, Tamil)", priority: "medium", label: { name: "Messaging", dot: "bg-success" }, assignee: "SR", due: "Oct 17" },
  ] },
  { status: "todo", name: "Todo", issues: [
    { id: "KRV-147", title: "Bulk price update from CSV", priority: "high", label: { name: "Catalogue", dot: "bg-warning" }, assignee: "AK", due: "Oct 23" },
    { id: "KRV-145", title: "Low-stock alerts per warehouse", priority: "medium", label: { name: "Inventory", dot: "bg-info" }, assignee: "MN", due: "Oct 25" },
    { id: "KRV-144", title: "Empty state for the returns tab", priority: "low", label: { name: "Design", dot: "bg-primary" }, assignee: "SR", due: "Oct 28" },
  ] },
];

const statusColour: Record<Status, string> = { progress: "text-warning", review: "text-success", todo: "text-fg-subtle" };

function StatusIcon({ status }: { status: Status }) {
  return (
    <svg viewBox="0 0 14 14" className={cn("size-3.5 shrink-0", statusColour[status])} aria-hidden>
      <circle cx="7" cy="7" r="5.5" fill="none" stroke="currentColor" strokeWidth="1.5" />
      {status === "progress" && <path d="M7 3.5A3.5 3.5 0 0 1 7 10.5Z" fill="currentColor" />}
      {status === "review" && <path d="M7 3.5A3.5 3.5 0 1 1 3.5 7H7Z" fill="currentColor" />}
    </svg>
  );
}

function PriorityIcon({ priority }: { priority: Priority }) {
  if (priority === "urgent") return <span aria-label="Urgent" className="grid size-4 shrink-0 place-items-center rounded-sm bg-danger text-[10px] font-bold text-bg">!</span>;
  const bars = { high: 3, medium: 2, low: 1 }[priority];
  return (
    <svg viewBox="0 0 16 16" className="size-4 shrink-0" aria-label={priority + " priority"}>
      {[0, 1, 2].map((i) => (
        <rect key={i} x={2 + i * 4.5} y={11 - i * 3.5} width="3" height={3 + i * 3.5} rx="1" className={i < bars ? "fill-fg-muted" : "fill-border-strong"} />
      ))}
    </svg>
  );
}

export default function IssuesPage() {
  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">K</span>Kaveri Product
        </p>
        {personal.map(({ label, icon: Icon }) => (
          <a key={label} href="#" className="flex h-8 items-center gap-2.5 rounded px-2 font-medium text-fg-muted hover:bg-surface-2 hover:text-fg">
            <Icon className="size-4" aria-hidden />{label}
          </a>
        ))}
        <p className="px-2 pb-1 pt-4 text-[11px] font-medium text-fg-subtle">Your teams</p>
        <a href="#" className="flex h-8 items-center gap-2.5 rounded px-2 font-medium"><span className="size-2 rounded-sm bg-primary" />Storefront</a>
        <a href="#" aria-current="page" className="flex h-8 items-center rounded bg-bg pl-7 pr-2 font-medium shadow-sm ring-1 ring-border">Issues<span className="ml-auto text-xs text-fg-subtle">42</span></a>
        <a href="#" className="flex h-8 items-center rounded pl-7 pr-2 font-medium text-fg-muted hover:bg-surface-2">Cycles</a>
        <a href="#" className="flex h-8 items-center rounded pl-7 pr-2 font-medium text-fg-muted hover:bg-surface-2">Projects</a>
      </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-5">
          <h1 className="text-fg-muted">Storefront <span className="text-fg-subtle">/</span> <span className="font-medium text-fg">Issues</span></h1>
          <div className="ml-auto flex items-center gap-2">
            <div className="hidden rounded-lg bg-surface-2 p-0.5 sm:flex" role="group" aria-label="Layout">
              <button type="button" aria-label="List" aria-pressed="true" className="grid size-7 place-items-center rounded bg-bg shadow-sm"><List className="size-3.5" /></button>
              <button type="button" aria-label="Board" aria-pressed="false" className="grid size-7 place-items-center rounded text-fg-muted"><Columns3 className="size-3.5" /></button>
            </div>
            <button type="button" className="inline-flex h-8 items-center gap-1.5 rounded bg-primary px-3 text-[13px] font-medium text-primary-fg hover:bg-primary-hover">
              <Plus className="size-4" aria-hidden /> New issue
            </button>
          </div>
        </header>

        <div className="flex flex-wrap items-center gap-2 border-b border-border px-4 py-2 sm:px-5">
          <button type="button" className="inline-flex h-7 items-center gap-1.5 rounded-full border border-border bg-surface px-2.5 text-xs font-medium"><Users className="size-3.5" aria-hidden />Assignee: Anyone</button>
          <button type="button" className="inline-flex h-7 items-center gap-1.5 rounded-full border border-border bg-surface px-2.5 text-xs font-medium"><Calendar className="size-3.5" aria-hidden />Cycle 14 · ends Fri</button>
          <button type="button" className="inline-flex h-7 items-center gap-1.5 rounded-full border border-dashed border-border-strong px-2.5 text-xs font-medium text-fg-muted"><Filter className="size-3.5" aria-hidden />Filter</button>
          <div className="ml-auto hidden items-center gap-2 text-xs sm:flex">
            <span className="text-fg-muted">Cycle progress</span>
            <div className="h-1.5 w-28 rounded-full bg-surface-2"><div className="h-full w-[58%] rounded-full bg-primary" /></div>
            <span className="font-medium tabular-nums">58%</span>
          </div>
        </div>

        <main>
          {groups.map((g) => (
            <section key={g.status} aria-labelledby={"group-" + g.status}>
              <h2 id={"group-" + g.status} className="flex h-9 items-center gap-2 border-b border-border bg-surface px-4 text-[13px] font-medium sm:px-5">
                <StatusIcon status={g.status} />{g.name}<span className="text-xs text-fg-subtle">{g.issues.length}</span>
              </h2>
              <ul>
                {g.issues.map((i) => (
                  <li key={i.id}>
                    <a href={"/issues/" + i.id} className="flex h-10 items-center gap-2.5 border-b border-border px-4 text-[13px] hover:bg-surface sm:px-5">
                      <PriorityIcon priority={i.priority} />
                      <span className="hidden w-16 shrink-0 tabular-nums text-fg-muted sm:block">{i.id}</span>
                      <StatusIcon status={g.status} />
                      <span className="min-w-0 flex-1 truncate">{i.title}</span>
                      <span className="hidden items-center gap-1.5 rounded-full border border-border px-2 py-0.5 text-[11px] text-fg-muted md:inline-flex">
                        <i className={cn("size-1.5 rounded-full", i.label.dot)} />{i.label.name}
                      </span>
                      <span className="hidden w-12 text-right text-xs tabular-nums text-fg-subtle sm:block">{i.due}</span>
                      <span className="grid size-6 shrink-0 place-items-center rounded-full bg-primary-soft text-[10px] font-semibold text-primary-soft-fg">{i.assignee}</span>
                    </a>
                  </li>
                ))}
              </ul>
            </section>
          ))}
          <p className="flex items-center gap-2 px-5 py-3 text-xs text-fg-subtle"><CircleDashed className="size-3.5" aria-hidden />18 more in Backlog</p>
        </main>
      </div>
    </div>
  );
}

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