Skip to content

Meeting Card

Meeting recap glass card: title, time / duration / platform meta, gradient participant stack with +N, AI summary panel, action items with checkboxes and owners, and a transcript link.

glass/ui/meeting-card
Open ↗

Source

import { Clock, FileText, Sparkles, Video } from "lucide-react";
import { cn } from "@/lib/utils";

export interface MeetingCardProps {
  title?: string;
  when?: string;
  duration?: string;
  platform?: string;
  participants?: string[];
  summary?: string[];
  actions?: { text: string; owner: string; done?: boolean }[];
  href?: string;
  className?: string;
}

const GLASS = "da-stroke bg-da-surface backdrop-blur-da backdrop-saturate-150";
const TONES = [
  "from-da-primary to-da-accent",
  "from-da-accent to-da-success",
  "from-da-danger to-da-primary",
  "from-da-warning to-da-danger",
  "from-da-success to-da-primary",
];

/** Meeting recap card: title, time/platform meta, participant stack, AI summary bullets, action items with owners and a link to the transcript. */
export function MeetingCard({
  title = "Q4 roadmap sync",
  when = "Today, 10:00",
  duration = "32 min",
  platform = "Google Meet",
  participants = ["Amara Diallo", "Leo Park", "Sofia Rossi", "Noah Klein", "Jin Park"],
  summary = ["Offline mode moves to November.", "Pricing variant B wins (+18% trial starts).", "Second designer role approved."],
  actions = [
    { text: "Draft offline mode RFC", owner: "Leo" },
    { text: "Ship pricing variant B to 100%", owner: "Sofia", done: true },
  ],
  href = "#transcript",
  className,
}: MeetingCardProps) {
  const shown = participants.slice(0, 4);
  const more = participants.length - shown.length;
  return (
    <article className={cn("relative rounded-da-lg p-5 shadow-da-md", GLASS, className)}>
      <header className="flex items-start justify-between gap-4">
        <div>
          <h3 className="font-da-display text-lg font-semibold tracking-da-display">{title}</h3>
          <p className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-da-muted-fg">
            <span>{when}</span>
            <span className="inline-flex items-center gap-1">
              <Clock aria-hidden className="size-3.5" /> {duration}
            </span>
            <span className="inline-flex items-center gap-1">
              <Video aria-hidden className="size-3.5" /> {platform}
            </span>
          </p>
        </div>
        <div className="flex -space-x-2" aria-label={`${participants.length} participants: ${participants.join(", ")}`} role="img">
          {shown.map((p, i) => (
            <span
              key={p}
              className={cn(
                "grid size-8 place-items-center rounded-full bg-gradient-to-br text-[10px] font-semibold text-da-primary-fg ring-2 ring-da-bg",
                TONES[i % TONES.length],
              )}
            >
              {p
                .split(" ")
                .map((w) => w[0])
                .join("")}
            </span>
          ))}
          {more > 0 && <span className="grid size-8 place-items-center rounded-full bg-da-surface-2 text-[10px] font-semibold ring-2 ring-da-bg">+{more}</span>}
        </div>
      </header>
      <div className="mt-4 rounded-da-md bg-da-surface-2 p-4">
        <p className="inline-flex items-center gap-1.5 text-xs font-semibold text-da-primary">
          <Sparkles aria-hidden className="size-3.5" /> AI summary
        </p>
        <ul className="mt-2 space-y-1.5 text-sm">
          {summary.map((s) => (
            <li key={s} className="flex gap-2">
              <span aria-hidden className="mt-2 size-1 shrink-0 rounded-full bg-da-fg" />
              {s}
            </li>
          ))}
        </ul>
      </div>
      <p className="mt-4 text-xs font-semibold text-da-muted-fg">Action items</p>
      <ul className="mt-2 space-y-1.5">
        {actions.map((a) => (
          <li key={a.text} className="flex items-center gap-2 text-sm">
            <span
              aria-hidden
              className={cn(
                "grid size-4 place-items-center rounded-[5px] border",
                a.done ? "border-da-success bg-da-success text-da-success-fg" : "border-da-border-strong",
              )}
            >
              {a.done && "✓"}
            </span>
            <span className={cn("flex-1", a.done && "text-da-muted-fg line-through")}>
              {a.text}
              <span className="sr-only">{a.done ? " (done)" : " (open)"}</span>
            </span>
            <span className="rounded-da-pill bg-da-surface-2 px-2 py-0.5 text-[11px] font-medium">@{a.owner}</span>
          </li>
        ))}
      </ul>
      <a
        href={href}
        className="da-focus da-transition mt-5 inline-flex items-center gap-1.5 rounded-da-pill text-sm font-semibold text-da-primary hover:underline"
      >
        <FileText aria-hidden className="size-4" /> Open transcript
      </a>
    </article>
  );
}

export default MeetingCard;

modules/glass/ui/meeting-card/index.tsx

Props

PropTypeDefaultDescription
title / when / duration / platform / hrefstring—Meta.
participantsstring[]—Names.
summarystring[]—Bullets.
actions{ text, owner, done? }[]—Action items.
classNamestring—Classes.

Other card variants in Glass

Card in other art directions

Card

Composable card (Card, CardHeader, CardKicker, CardTitle, CardDescription, CardContent, CardFooter) with 5 solid tones, 3 hard-shadow depths and an interactive press-on-hover mode.

BrutalistCard

Profile Card

User/team member card: striped blue banner with status chip, overlapping yellow initials square, uppercase name and mono role, bio, ruled stat strip and a split action bar.

BrutalistCard

Release Card

Changelog entry card: yellow version/date column (top bar on mobile), uppercase title (optional link), summary and a list of changes tagged new / improved / fixed / breaking with fixed-width colored labels.

BrutalistCard

Stat Card

KPI card: mono label, icon square, giant value, green/red delta chip with arrow, and an outlined mini bar chart whose last bar is filled. Four solid tones.

BrutalistCard

Card

Composable hairline card (Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter) with default / raised / ghost variants and an interactive hover lift.

MinimalCard

Incident Card

Incident summary card: severity chip, id and duration, linked title, service chips, a 4-step status progress bar, commander avatar, stacked responder avatars and update count.

MinimalCard

Integration Card

Integration tile: logo/monogram, name, category, description, a Radix Switch to enable it, live status meta and a Configure link. Controlled or uncontrolled.

MinimalCard

Metric Card

KPI card: muted label, big mono value, inline SVG sparkline with area fill and end dot, and a colored delta chip vs. the previous period (lowerIsBetter flips the colors).

MinimalCard

Profile Card

Studio/person profile card in the Read.cv spirit: square gray portrait with initials, name, role and city in mono, availability dot in signal color, short bio and a list of links with ↗.

Mono CleanCard

Project Card

Portfolio project card: neutral image frame that darkens slightly on hover with a “View case ↗” overlay, then a mono meta row (index, client, year) and the title with discipline tags.

Mono CleanCard

Stat Card

Analytics stat: mono label, large display value, change in mono, and a row of thin vertical bars (last bar in ink, others gray) — no chart chrome.

Mono CleanCard

Template Card

Template tile: a wireframe preview drawn with hairlines (nav, giant title, image grid) in a bordered frame, then name, author, category and usage count, with a “Use template” button revealed on hover/focus.

Mono CleanCard

Account Card

Bank account card: institution + masked number header, big balance with available amount, sync timestamp, and three recent inflow/outflow rows.

Neo CorporateCard

Invoice Card

Invoice summary card: number + status, bill-to and dates grid, line items table with mono amounts, subtotal/tax/total, and download/send actions.

Neo CorporateCard

Kpi Card

Metric card: label, big mono value, colored delta vs. period and an area sparkline in the primary color along the bottom.

Neo CorporateCard

Plan Card

Billing/subscription card: current plan + price + renewal date, usage meters (progressbar semantics, turning amber at 80% and red at 95%), manage and upgrade actions.

Neo CorporateCard

Action Card

Reduction action card: serif title, description, saving and cost figures, leaf-rated impact/effort, and an “Add to plan” pill that toggles to a sage “In your plan” state.

Organic SoftCard

Article Card

Journal article card: an organic shaped “cover” (arch, blob or circle) with a hand-drawn leaf, category and read time, serif title that underlines on hover, excerpt; whole card is one link.

Organic SoftCard

Metric Card

Emissions metric card: label, big serif value with mono unit, a change chip (down = good, sage; up = clay) and a human equivalence line with a small leaf.

Organic SoftCard

Supplier Card

Supplier card: arch-shaped initials avatar, name, category and country, status pill, share of your footprint and a rounded data-completeness bar with a reminder action.

Organic SoftCard

Profile Card

Rounded teammate card: pastel header band, big emoji avatar in a white circle, name, role, status pill, three stats in soft wells, skill pills and a “Say hi” button.

Soft FlatCard

Project Card

Pastel project card: white emoji tile, name link covering the card, description, chunky rounded progress bar with percentage, tasks-left and due chips, member dots.

Soft FlatCard

Stat Card

Friendly KPI tile: emoji in a white circle, change pill, label, big rounded number and a row of rounded mini bars (last one highlighted); five tones.

Soft FlatCard

Task Card

Kanban task card: round done checkbox with bouncy tick, pastel label, title (struck when done), subtask progress, due chip that turns red when overdue, comment/attachment counts and avatar dots.

Soft FlatCard