Files
Pasquale Vitiello 9302c06311 refactor: align biome settings with calcom (#718)
* update biome config + resolve issues

* improve the ui:sync command to run organizeImports on packages

* reformat

* build registry

* exclude base-ui stuff

* fix useExportsLast

* further improvements

* silence errors

* exclude examples app

* update biome + reformat

* format all the other files

* include examples app

* improve copyable-field

* remove unwanted comment

* remove a few unneeded biome comments

* avoid nested ternary

* refactored some shared components

* upgrade base ui to 1.2.0

* fix
2026-03-11 23:09:19 +00:00

130 lines
3.3 KiB
TypeScript

import {
BookOpenIcon,
type LucideIcon,
MessageCircleIcon,
PencilIcon,
PlusIcon,
} from "lucide-react";
import {
Timeline,
TimelineContent,
TimelineItem,
} from "@/registry/default/ui/timeline";
const items: {
id: number;
user: string;
image: string;
action: ActionType;
date: Date;
}[] = [
{
action: "post",
date: new Date(Date.now() - 59000), // 59 seconds ago
id: 1,
image: "/origin/avatar-40-02.jpg",
user: "Matt",
},
{
action: "reply",
date: new Date(Date.now() - 180000), // 3 minutes ago
id: 2,
image: "/origin/avatar-40-02.jpg",
user: "Matt",
},
{
action: "edit",
date: new Date(Date.now() - 300000), // 5 minutes ago
id: 3,
image: "/origin/avatar-40-02.jpg",
user: "Matt",
},
{
action: "create",
date: new Date(Date.now() - 600000), // 10 minutes ago
id: 4,
image: "/origin/avatar-40-02.jpg",
user: "Matt",
},
];
type ActionType = "post" | "reply" | "edit" | "create";
function getActionIcon(action: ActionType): LucideIcon {
const icons: Record<ActionType, LucideIcon> = {
create: PlusIcon,
edit: PencilIcon,
post: BookOpenIcon,
reply: MessageCircleIcon,
};
return icons[action];
}
function getActionText(action: ActionType): string {
const texts: Record<ActionType, string> = {
create: "created a new project",
edit: "edited a post",
post: "wrote a new post",
reply: "replied to a comment",
};
return texts[action];
}
function getRelativeTimeString(date: Date): string {
const now = new Date();
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
if (diffInSeconds < 60) {
return `${diffInSeconds} seconds ago`;
}
if (diffInSeconds < 3600) {
const minutes = Math.floor(diffInSeconds / 60);
return `${minutes} ${minutes === 1 ? "minute" : "minutes"} ago`;
}
if (diffInSeconds < 86400) {
const hours = Math.floor(diffInSeconds / 3600);
return `${hours} ${hours === 1 ? "hour" : "hours"} ago`;
}
const days = Math.floor(diffInSeconds / 86400);
return `${days} ${days === 1 ? "day" : "days"} ago`;
}
export default function Component() {
return (
<div className="space-y-3">
<div className="font-medium text-muted-foreground text-xs">Activity</div>
<Timeline>
{items.map((item) => {
const ActionIcon = getActionIcon(item.action);
return (
<TimelineItem
className="m-0! flex-row items-center gap-3 py-2.5!"
key={item.id}
step={item.id}
>
<ActionIcon className="text-muted-foreground/80" size={16} />
<img
alt={item.user}
className="size-6 rounded-full"
src={item.image}
/>
<TimelineContent className="text-foreground">
<a className="font-medium hover:underline" href="#">
{item.user}
</a>
<span className="font-normal">
{" "}
{getActionText(item.action)}{" "}
<a className="hover:underline" href="#">
{getRelativeTimeString(item.date)}
</a>
</span>
</TimelineContent>
</TimelineItem>
);
})}
</Timeline>
</div>
);
}