'use client'; import { selectAnnouncedGenerationActivity, type GenerationActivityItem } from '@/lib/generation-activity'; import type { HistoryMetadata } from '@/lib/history-metadata'; import { cn } from '@/lib/utils'; import Image from 'next/image'; type ActivityTimelineProps = { activityItems: GenerationActivityItem[]; history: HistoryMetadata[]; onSelectImage: (item: HistoryMetadata) => void; onClearHistory: () => void; getImageSrc: (filename: string) => string | undefined; formatStatusTime: (timestamp: number) => string; formatDuration: (ms: number) => string; t: (key: string, values?: Record) => string; }; function getActivityToneClass(tone: GenerationActivityItem['tone']): string { if (tone === 'progress') return 'bg-sky-500'; if (tone === 'success') return 'bg-emerald-500'; if (tone === 'warning') return 'bg-amber-500'; return 'bg-slate-400'; } function getActivityToneLabel(tone: GenerationActivityItem['tone'], t: ActivityTimelineProps['t']): string { if (tone === 'progress') return t('history.activityToneProgress'); if (tone === 'success') return t('history.activityToneSuccess'); if (tone === 'warning') return t('history.activityToneWarning'); return t('history.activityToneNeutral'); } function GenerationActivityRows({ items, t, compact = false }: { items: GenerationActivityItem[]; t: ActivityTimelineProps['t']; compact?: boolean; }) { return ( <> {items.map((item, index) => (
{getActivityToneLabel(item.tone, t)} {item.label} {item.detail}
))} ); } function ActivityHistoryRow({ item, index, hasLiveActivity, onSelectImage, getImageSrc, formatStatusTime, formatDuration, t }: { item: HistoryMetadata; index: number; hasLiveActivity: boolean; onSelectImage: (item: HistoryMetadata) => void; getImageSrc: (filename: string) => string | undefined; formatStatusTime: (timestamp: number) => string; formatDuration: (ms: number) => string; t: (key: string, values?: Record) => string; }) { const isLatestQuietActivity = index === 0 && !hasLiveActivity; const isFailedItem = item.status === 'failed'; const activityLabel = isFailedItem ? t('history.failedStatus') : item.mode === 'edit' ? t('history.statusEditDone') : t('history.statusCreateDone'); const activityDetail = isFailedItem ? item.failureMessage?.trim() || t('history.failedReasonUnavailable') : t('history.statusBatchSummary', { count: item.images.length, duration: formatDuration(item.durationMs) }); return ( ); } export function ActivityTimeline({ activityItems, history, onSelectImage, onClearHistory, getImageSrc, formatStatusTime, formatDuration, t }: ActivityTimelineProps) { const hasActivity = activityItems.length > 0 || history.length > 0; const liveActivity = selectAnnouncedGenerationActivity(activityItems); if (!hasActivity) return null; return (

{t('history.generationStatus')}

{t('history.generationStatusHint')}

{history.length > 0 ? ( ) : null}

{liveActivity ? `${liveActivity.label} ${liveActivity.detail}` : ''}

{history.slice(0, 4).map((item, index) => ( 0} onSelectImage={onSelectImage} getImageSrc={getImageSrc} formatStatusTime={formatStatusTime} formatDuration={formatDuration} t={t} /> ))}
); }