mirror of
https://github.com/cosscom/coss.git
synced 2026-09-14 20:06:50 +08:00
9302c06311
* 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
130 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
}
|