agent: history — restyle with brand tokens and empty state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jake
2026-03-21 11:04:06 +00:00
parent 3f69543f73
commit 5caf886252

View File

@@ -4,8 +4,10 @@
import { history, saveHistory, deleteFromHistory } from "$lib/stores/page.svelte.js";
import { convertFileSrc } from "@tauri-apps/api/core";
import Card from "$lib/components/Card.svelte";
import EmptyState from "$lib/components/EmptyState.svelte";
import { formatTime, formatDuration } from "$lib/utils/time.js";
import { PLAYBACK_SPEEDS, FEEDBACK_TIMEOUT_MS } from "$lib/utils/constants.js";
import { Search, Clock, Play, Pause, FileText, Mic, ChevronDown } from 'lucide-svelte';
let searchQuery = $state("");
let expandedId = $state(null);
@@ -157,9 +159,7 @@
<div class="px-7 pb-4">
<Card>
<div class="flex items-center gap-3 px-4 py-2.5">
<svg class="w-4 h-4 text-text-tertiary flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8" /><path d="M21 21l-4.35-4.35" />
</svg>
<Search size={16} class="text-text-tertiary flex-shrink-0" aria-hidden="true" />
<input
class="flex-1 bg-transparent text-text text-[13px] placeholder:text-text-tertiary focus:outline-none"
placeholder="Search all transcripts..."
@@ -181,25 +181,17 @@
<div class="flex-1 px-7 pb-4 min-h-0">
<Card classes="h-full flex flex-col overflow-hidden">
{#if filtered.length === 0}
<div class="flex-1 flex flex-col items-center justify-center gap-3">
<div class="w-12 h-12 rounded-full bg-bg-elevated flex items-center justify-center">
<svg class="w-6 h-6 text-text-tertiary" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7Z" />
</svg>
</div>
<p class="text-[13px] text-text-tertiary">
{searchQuery ? "No matching transcripts" : "No history yet"}
</p>
<p class="text-[11px] text-text-tertiary">
{searchQuery ? "Try a different search" : "Transcripts auto-save after recording"}
</p>
</div>
<EmptyState
icon={Clock}
message={searchQuery ? "No matching transcripts" : "Your transcriptions will be saved here"}
/>
{:else}
<div class="flex-1 overflow-y-auto">
{#each filtered as item}
<!-- Compact row -->
<div
class="flex items-center gap-3 px-4 py-3 border-b border-border-subtle hover:bg-hover cursor-pointer transition-colors duration-150"
class="flex items-center gap-3 px-4 py-3 border-b border-border-subtle bg-bg-card hover:bg-hover cursor-pointer"
style="transition-duration: var(--duration-ui)"
onclick={() => toggleExpand(item.id)}
onkeydown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleExpand(item.id); } }}
role="button"
@@ -215,18 +207,12 @@
aria-label={playingId === item.id && audioEl && !audioEl.paused ? "Pause" : "Play"}
>
{#if playingId === item.id && audioEl && !audioEl.paused}
<svg class="w-2.5 h-2.5" viewBox="0 0 24 24" fill="currentColor">
<rect x="6" y="4" width="4" height="16" rx="1" />
<rect x="14" y="4" width="4" height="16" rx="1" />
</svg>
<Pause size={10} aria-hidden="true" />
{:else}
<svg class="w-2.5 h-2.5 ml-0.5" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z" />
</svg>
<Play size={10} class="ml-0.5" aria-hidden="true" />
{/if}
</button>
{:else}
<!-- Spacer to keep alignment when no audio -->
<div class="w-6 h-6 flex-shrink-0"></div>
{/if}
@@ -245,19 +231,9 @@
<!-- Source icon -->
<span class="flex-shrink-0 text-text-tertiary" title={item.source}>
{#if item.source && item.source.toLowerCase().includes("file")}
<!-- File icon -->
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<FileText size={14} aria-hidden="true" />
{:else}
<!-- Microphone icon -->
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
<path d="M19 10v2a7 7 0 0 1-14 0v-2" />
<line x1="12" y1="19" x2="12" y2="23" />
<line x1="8" y1="23" x2="16" y2="23" />
</svg>
<Mic size={14} aria-hidden="true" />
{/if}
</span>
@@ -267,17 +243,17 @@
</span>
<!-- Expand chevron -->
<svg
class="w-3.5 h-3.5 text-text-tertiary flex-shrink-0 transition-transform duration-150 {expandedId === item.id ? 'rotate-180' : ''}"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
>
<polyline points="6 9 12 15 18 9" />
</svg>
<ChevronDown
size={14}
class="text-text-tertiary flex-shrink-0 {expandedId === item.id ? 'rotate-180' : ''}"
style="transition: transform var(--duration-ui)"
aria-hidden="true"
/>
</div>
<!-- Expanded detail -->
{#if expandedId === item.id}
<div class="px-4 py-4 bg-bg-elevated border-b border-border animate-slide-up">
<div class="px-4 py-4 bg-bg-elevated border-b border-border-subtle animate-slide-up">
<!-- Audio player (if playing this item) -->
{#if item.audioPath && playingId === item.id}
<div class="flex items-center gap-3 mb-4 px-1">
@@ -315,22 +291,26 @@
<!-- Action buttons -->
<div class="flex items-center gap-2 flex-wrap">
<button
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-text transition-colors"
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-text"
style="transition-duration: var(--duration-ui)"
onclick={(e) => { e.stopPropagation(); renameItem(item); }}
>Rename</button>
<button
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-text transition-colors"
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-text"
style="transition-duration: var(--duration-ui)"
onclick={(e) => { e.stopPropagation(); copyItem(item); }}
>Copy</button>
{#if item.audioPath && item.segments && item.segments.length > 0}
<button
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-accent hover:text-accent-hover transition-colors"
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-accent hover:text-accent-hover"
style="transition-duration: var(--duration-ui)"
onclick={(e) => { e.stopPropagation(); openViewer(item); }}
>Open viewer</button>
{/if}
<div class="flex-1"></div>
<button
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-danger transition-colors"
class="text-[11px] px-3 py-1.5 rounded-lg bg-hover text-text-secondary hover:text-danger"
style="transition-duration: var(--duration-ui)"
onclick={(e) => { e.stopPropagation(); removeItem(item); }}
>Delete</button>
</div>