All Taste components
Dashboard widgets
Activity feed card
A timeline of what happened in the workspace: payments, moves, bookings and comments.
icon & avatar rows · quoted comment · timeline rail
Activity
View all- Ritika Shah paid invoice INV-2041 · ₹48,500
- AMArjun Mehta moved Menu redesign to Review
- New booking from Meera Iyer for Fri 16 Oct, 11:00
- KRKabir Rao commented on Q3 reportNumbers match the bank statement. Good to send.
- You invited neha@saffronstudio.in to the team
import { CalendarDays, CreditCard, Mail } from "lucide-react";
import { cn } from "@/lib/utils";
export interface ActivityItem {
id: string;
/** An icon kind, or a person's initials for an avatar. */
icon?: "payment" | "booking" | "invite";
initials?: string;
text: React.ReactNode;
quote?: string;
time: string;
}
const icons = { payment: CreditCard, booking: CalendarDays, invite: Mail };
const sample: ActivityItem[] = [
{ id: "1", icon: "payment", text: <><b className="font-medium">Ritika Shah</b> paid invoice INV-2041 · ₹48,500</>, time: "12 min ago" },
{ id: "2", initials: "AM", text: <><b className="font-medium">Arjun Mehta</b> moved <b className="font-medium">Menu redesign</b> to Review</>, time: "1 h ago" },
{ id: "3", icon: "booking", text: <>New booking from <b className="font-medium">Meera Iyer</b> for Fri 16 Oct, 11:00</>, time: "2 h ago" },
{ id: "4", initials: "KR", text: <><b className="font-medium">Kabir Rao</b> commented on <b className="font-medium">Q3 report</b></>, quote: "Numbers match the bank statement. Good to send.", time: "4 h ago" },
{ id: "5", icon: "invite", text: <>You invited <b className="font-medium">neha@saffronstudio.in</b> to the team</>, time: "Yesterday" },
];
export function ActivityFeed({ items = sample }: { items?: ActivityItem[] }) {
return (
<section className="w-full max-w-md rounded-lg border border-border bg-bg p-4">
<div className="flex items-center justify-between">
<h3 className="text-sm font-medium">Activity</h3>
<a href="/activity" className="text-[12.5px] text-primary hover:underline">View all</a>
</div>
<ol className="mt-4">
{items.map((item, i) => {
const Icon = item.icon ? icons[item.icon] : null;
return (
<li key={item.id} className={cn("relative grid grid-cols-[28px_minmax(0,1fr)] gap-3 text-[13.5px]", i < items.length - 1 && "pb-[18px]")}>
{i < items.length - 1 && <span className="absolute bottom-1.5 left-[13.5px] top-[34px] w-px bg-border" aria-hidden />}
{Icon ? (
<span className={cn("grid size-7 place-items-center rounded-full",
item.icon === "payment" ? "bg-success-soft text-success-fg" : "bg-surface-2 text-fg-muted")}>
<Icon className="size-3.5" aria-hidden />
</span>
) : (
<span className="grid size-7 place-items-center rounded-full bg-primary-soft text-[11px] font-medium text-primary-soft-fg">{item.initials}</span>
)}
<div>
<p>{item.text}</p>
{item.quote && <p className="mt-2 rounded bg-surface px-3 py-2 text-[13px] text-fg-muted">{item.quote}</p>}
<time className="mt-0.5 block text-xs text-fg-subtle">{item.time}</time>
</div>
</li>
);
})}
</ol>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.