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