feat(ui): polish the meetings list — icons, accent colors, hover states

Search icon inside the input, Trash2/Download/RotateCcw replacing
emoji, tag chips and the selected-item state now use the semantic
accent tokens instead of a hardcoded blue hex, and list rows get a
hover state + an accent-colored left border when selected.
This commit is contained in:
iamdoubz committed 2026-07-02 12:57:09 -05:00
1 parent d50342d865
commit 9052d69912
1 file changed
+77 -25
+77 -25
View File
@@ -4,6 +4,7 @@
import { recording } from "../stores/recording.svelte";
import { api, type MeetingListItem, type SearchHit } from "../api";
import { open } from "@tauri-apps/plugin-dialog";
import { Search, Trash2, Download, RotateCcw } from "@lucide/svelte";
let query = $state("");
let searchTimer: ReturnType<typeof setTimeout> | undefined;
@@ -100,12 +101,15 @@
</script>
<div class="wrap">
<input
placeholder="Search meetings…"
aria-label="Search meetings"
bind:value={query}
oninput={onSearchInput}
/>
<div class="search-box">
<Search size={15} aria-hidden="true" />
<input
placeholder="Search meetings…"
aria-label="Search meetings"
bind:value={query}
oninput={onSearchInput}
/>
</div>
<div class="filters">
<select aria-label="Filter by tag" bind:value={tagFilter} onchange={onFilterChange}>
<option value="">All tags</option>
@@ -124,10 +128,12 @@
<option value="bundle">bundle</option>
</select>
<button
class="bulk-btn"
onclick={bulkExport}
disabled={bulkExporting}
title="Export every meeting matching the tag/date filters above"
>
<Download size={13} aria-hidden="true" />
{bulkExporting ? "Exporting…" : "Bulk export"}
</button>
</div>
@@ -141,7 +147,7 @@
{:else if displayItems.length === 0 && meetings.searchResults !== null}
<p class="muted">No matches.</p>
{:else if displayItems.length === 0}
<p class="muted">No meetings yet. Click ● Record to start.</p>
<p class="muted">No meetings yet — click Record above to start.</p>
{:else}
<ul>
{#each displayItems as m (m.id)}
@@ -174,16 +180,18 @@
</button>
<div class="row actions">
{#if m.status === "recovering"}
<button class="link" onclick={(e) => resumeMeeting(e, m.id)}
>Resume transcription</button
>
<button class="link" onclick={(e) => resumeMeeting(e, m.id)}>
<RotateCcw size={12} aria-hidden="true" />
Resume transcription
</button>
{/if}
<button
class="link danger"
onclick={(e) => removeMeeting(e, m.id)}
aria-label="Delete meeting"
title="Delete meeting"
>
🗑
<Trash2 size={14} aria-hidden="true" />
</button>
</div>
</li>
@@ -196,11 +204,34 @@
.wrap {
padding: 0.75rem;
}
.search-box {
position: relative;
margin-bottom: 0.5rem;
}
.search-box :global(svg) {
position: absolute;
left: 0.55rem;
top: 50%;
transform: translateY(-50%);
color: var(--fg-subtle);
pointer-events: none;
}
.search-box input {
padding-left: 1.9rem;
margin-bottom: 0;
}
input {
width: 100%;
padding: 0.4rem;
padding: 0.45rem 0.6rem;
margin-bottom: 0.5rem;
box-sizing: border-box;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
}
input:focus-visible {
border-color: var(--accent);
}
.muted {
color: var(--muted);
@@ -220,7 +251,7 @@
}
.filters {
display: flex;
gap: 0.3rem;
gap: 0.35rem;
margin-bottom: 0.5rem;
}
.filters select,
@@ -228,24 +259,34 @@
.filters button {
flex: 1;
min-width: 0;
padding: 0.25rem;
padding: 0.3rem;
font-size: 0.78rem;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: 5px;
border-radius: var(--radius-sm);
}
.bulk-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.3rem;
cursor: pointer;
}
.bulk-btn:hover {
background: var(--bg-hover);
}
.tags {
justify-content: flex-start;
flex-wrap: wrap;
margin-top: 0.2rem;
margin-top: 0.25rem;
}
.chip {
font-size: 0.68rem;
padding: 0.05rem 0.35rem;
border-radius: 8px;
background: color-mix(in srgb, var(--muted) 15%, transparent);
color: var(--muted);
padding: 0.1rem 0.45rem;
border-radius: var(--radius-full);
background: var(--accent-soft);
color: var(--accent);
}
ul {
list-style: none;
@@ -253,11 +294,17 @@
margin: 0;
}
li {
padding: 0.5rem 0.4rem;
padding: 0.55rem 0.7rem 0.55rem 0.6rem;
border-bottom: 1px solid var(--border);
border-left: 2px solid transparent;
transition: background-color 120ms ease-out;
}
li:hover {
background: var(--bg-hover);
}
li.active {
background: color-mix(in srgb, #2563eb 12%, transparent);
background: var(--accent-soft);
border-left-color: var(--accent);
}
.item-btn {
display: block;
@@ -280,11 +327,13 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
}
.badge {
font-size: 0.65rem;
padding: 0.1rem 0.4rem;
border-radius: 10px;
font-weight: 600;
padding: 0.1rem 0.45rem;
border-radius: var(--radius-full);
border: 1px solid var(--border);
}
.badge.live {
@@ -300,11 +349,14 @@
border-color: var(--muted);
}
.actions {
margin-top: 0.2rem;
margin-top: 0.3rem;
justify-content: flex-end;
gap: 0.6rem;
}
.link {
display: inline-flex;
align-items: center;
gap: 0.3rem;
background: none;
border: none;
cursor: pointer;