- applications/iknowyou: new Next.js chat application with persona-aware conversations, briefing API, cohort logic, vLLM streaming, and sidebar navigation - tidal M8: add replication control plane (control.rs), tenant migration state machine (migration.rs), tenant/upgrade coordinators, cluster/fault test harnesses - tidal M8 tests: expand m8p2/m8p3/m8p4 test suites; add m8p5_multitenancy and m8_uat - tidal db: split replication_ops out of db/mod.rs (was 647 lines, now 574) - .claude: add kai-park, kaya-osei, mira-vasquez agents; add aeries-design-architect, aeries-fullstack-engineer, aeries-product-visionary skills - docs: update ROADMAP.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
"use client";
|
|
|
|
import type { Conversation } from "@/lib/types";
|
|
|
|
interface ConversationItemProps {
|
|
conversation: Conversation;
|
|
isActive: boolean;
|
|
onClick: () => void;
|
|
}
|
|
|
|
function timeAgo(ts: number): string {
|
|
const diff = Date.now() - ts;
|
|
const mins = Math.floor(diff / 60_000);
|
|
if (mins < 1) return "now";
|
|
if (mins < 60) return `${mins}m`;
|
|
const hours = Math.floor(mins / 60);
|
|
if (hours < 24) return `${hours}h`;
|
|
const days = Math.floor(hours / 24);
|
|
if (days < 7) return `${days}d`;
|
|
return `${Math.floor(days / 7)}w`;
|
|
}
|
|
|
|
export function ConversationItem({
|
|
conversation,
|
|
isActive,
|
|
onClick,
|
|
}: ConversationItemProps) {
|
|
return (
|
|
<button
|
|
onClick={onClick}
|
|
className={`w-full text-left px-3 py-2.5 rounded-lg transition-colors group ${
|
|
isActive
|
|
? "bg-bg-elevated text-text"
|
|
: "text-text-muted hover:bg-bg-hover hover:text-text"
|
|
}`}
|
|
>
|
|
<div className="flex items-baseline justify-between gap-2 min-w-0">
|
|
<span className="text-[13px] leading-snug truncate">
|
|
{conversation.title}
|
|
</span>
|
|
<span className="text-[11px] text-text-faint shrink-0">
|
|
{timeAgo(conversation.lastMessageAt)}
|
|
</span>
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|