Files
openchamber/packages/vscode/webview/components/SessionItem.tsx
T
Bohdan Triapitsyn bb72c0fb0c feat: vscode extension (#59)
* feat: add initial VS Code extension plan and implementation tasks

* feat(vscode): added initial version of an Openchamber VSCode extension

* feat(vscode): enhance VS Code extension with theme integration and session management

* feat(vscode): implement connection status handling and overlay in VSCode layout

* feat: move extension to secondary sidebar

* chore: upgrade @opencode-ai/sdk to 1.0.150

* vscode: editor bridge, file picker, click-to-open in tool parts

* vscode: layout session lifecycle, theme sync, typography overrides

* ui: compact mode for vscode, model search, autocomplete width fixes

* perf: scroll force flag, raf placeholder, git polling backoff

* ui: tool output styling, markdown code block fix, gitignore

* refactor: update typography handling for VSCode runtime, remove unused styles

* docs: update README with VS Code extension details and add extension image

* docs: update changelog with new features and performance improvements
2025-12-13 16:34:17 +02:00

72 lines
2.4 KiB
TypeScript

import React from 'react';
import type { Session } from '@opencode-ai/sdk';
interface SessionItemProps {
session: Session;
isActive: boolean;
isStreaming?: boolean;
onClick: () => void;
}
const formatRelativeTime = (timestamp: number | undefined): string => {
if (!timestamp) return '';
const date = new Date(timestamp);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMs / 3600000);
const diffDays = Math.floor(diffMs / 86400000);
if (diffMins < 1) return 'Just now';
if (diffMins < 60) return `${diffMins}m ago`;
if (diffHours < 24) return `${diffHours}h ago`;
if (diffDays === 1) return 'Yesterday';
if (diffDays < 7) return `${diffDays}d ago`;
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
};
export function SessionItem({ session, isActive, isStreaming, onClick }: SessionItemProps) {
const title = session.title || 'New Session';
const time = formatRelativeTime(session.time?.created);
return (
<button
onClick={onClick}
className={`w-full text-left px-3 py-2.5 flex items-start gap-2 transition-colors ${
isActive
? 'bg-primary/10 border-l-2 border-primary'
: 'hover:bg-muted/50 border-l-2 border-transparent'
}`}
>
{/* Activity indicator */}
<div className="mt-1.5 flex-shrink-0">
{isStreaming ? (
<span className="block w-2 h-2 rounded-full bg-green-500 animate-pulse" />
) : (
<span className={`block w-2 h-2 rounded-full ${isActive ? 'bg-primary' : 'bg-muted-foreground/30'}`} />
)}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="text-sm font-medium truncate">{title}</div>
<div className="text-xs text-muted-foreground flex items-center gap-2">
<span>{time}</span>
{session.summary && (
<span className="text-[10px]">
{session.summary.additions !== undefined && (
<span className="text-green-600">+{session.summary.additions}</span>
)}
{session.summary.deletions !== undefined && (
<span className="text-red-500 ml-1">-{session.summary.deletions}</span>
)}
</span>
)}
</div>
</div>
</button>
);
}