diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e62fa..024eab1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht ## [Unreleased] +## [0.11.0] - 2026-09-16 + +### Changed + +- Refined the recording library into compact two-line rows with regular-weight + truncated titles, trailing semantic status badges, flatter selection, + subtle inset separators, quieter progressive quick-play actions, a narrow + scrollbar, and playback controls free of the redundant persistent + network-use reminder. Refreshed the shared neutral palette to cleaner white + and cool-neutral surfaces with stronger secondary-text legibility. + ## [0.10.0] - 2026-09-15 ### Added @@ -395,7 +406,8 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht - Added GitHub Actions workflows for continuous integration and tagged Windows releases. - Added English and Simplified Chinese README documentation. -[Unreleased]: https://github.com/kwp-lab/nota/compare/v0.10.0...HEAD +[Unreleased]: https://github.com/kwp-lab/nota/compare/v0.11.0...HEAD +[0.11.0]: https://github.com/kwp-lab/nota/compare/v0.10.0...v0.11.0 [0.10.0]: https://github.com/kwp-lab/nota/compare/v0.9.0...v0.10.0 [0.9.0]: https://github.com/kwp-lab/nota/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/kwp-lab/nota/compare/v0.7.0...v0.8.0 diff --git a/README.md b/README.md index d253d06..3aff6bd 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@

Platform: Windows 11 x64 - Version: 0.10.0 + Version: 0.11.0 Status: early preview Privacy: local first Telemetry: none diff --git a/README.zh-CN.md b/README.zh-CN.md index a2d450d..4c91f00 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,7 @@

平台:Windows 11 x64 - 版本:0.10.0 + 版本:0.11.0 状态:早期预览 隐私:本地优先 遥测:无 diff --git a/THIRD_PARTY_NOTICES.txt b/THIRD_PARTY_NOTICES.txt index b129cac..899a904 100644 --- a/THIRD_PARTY_NOTICES.txt +++ b/THIRD_PARTY_NOTICES.txt @@ -4242,7 +4242,7 @@ developed by Chen Jiaju, licensed under the MIT License and the Apache License 2 ------------------------------------------------------------------------------- MIT License (MIT) Used by: -- nota 0.10.0 +- nota 0.11.0 - brotli-decompressor 5.0.3 - cargo_toml 0.22.3 - dpi 0.1.2 diff --git a/bom.cyclonedx.json b/bom.cyclonedx.json index 691cdcc..f7694e6 100644 --- a/bom.cyclonedx.json +++ b/bom.cyclonedx.json @@ -1,14 +1,14 @@ { "bomFormat": "CycloneDX", "specVersion": "1.6", - "serialNumber": "urn:uuid:2e51a386-9432-4a50-a3c3-0e7d998d7106", + "serialNumber": "urn:uuid:30a8310e-8b01-43a9-a4ca-542abf91333f", "version": 1, "metadata": { "component": { "type": "application", "bom-ref": "pkg:github/kwp-lab/nota", "name": "Nota", - "version": "0.10.0", + "version": "0.11.0", "licenses": [ { "license": { diff --git a/docs/design-system.md b/docs/design-system.md index 48f21ca..01665de 100644 --- a/docs/design-system.md +++ b/docs/design-system.md @@ -11,7 +11,7 @@ It is intentionally separate from marketing artwork and release assets. ## Product Character Nota should feel calm, trustworthy, local, and precise. The visual language -uses warm neutral surfaces and a restrained jade accent so recording state and +uses clean neutral surfaces and a restrained jade accent so recording state and meeting content remain more prominent than decoration. Interfaces should feel native to Windows 11 without impersonating a Microsoft product. @@ -225,6 +225,25 @@ available when the list is hidden. The compact title, detail tabs, contextual toolbar, reading region, and native audio player follow DOM order. The list and reading region scroll independently; the outer detail pane must not scroll. Playback remains mounted across tabs. +The recording list uses compact two-line rows rather than individual cards. A +row contains a regular-weight, single-line recording title followed by a +two-ended metadata line: date and duration stay at the leading edge, while a +compact semantic transcription badge aligns to the trailing edge. Long titles +truncate with an ellipsis without displacing the fixed quick-play action; the +full title remains available to assistive technology and on pointer hover. File +size remains available in the selected recording header instead of being +repeated throughout the list. Status badges use Caption text, a small radius, +semantic foreground/surface colors, and a subtle border instead of relying on +text color alone. Quiet inter-row spacing, comfortable vertical padding, and +subtle inset hairline separators establish rhythm without turning rows into +individual cards or restoring a permanent leading icon. Separators sit between +rows and disappear when a row is hovered, selected, or owns an open context +menu so the interactive surface reads as one unit. The selected row uses a +flat brand surface. The quick-play action appears for hover, keyboard focus, +selection, or active playback, and Space toggles playback for the focused row. +Its compact trailing slot remains reserved so row content does not shift when +the action appears. The list scrollbar uses a narrow neutral thumb on a +transparent track while retaining a visible high-contrast fallback. AI documents use shared select styling for document/version selection instead of a permanent nested document sidebar. The document selector may grow to a @@ -268,7 +287,8 @@ At 1280×800 and 980×640, normal completed-document content targets at least that area. Controls must not wrap into multiple toolbar rows, and long titles, models, and paths must not cause page-level horizontal overflow. Use existing semantic tokens; do not shrink body type to achieve density. The playback -footer retains the local-recording/network-use reminder. +footer contains only playback controls. Network-use disclosure belongs at the +transcription or AI-generation action boundary, not beneath local playback. ## Change and Review Checklist diff --git a/docs/testing.md b/docs/testing.md index 65fcd60..06031c4 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -113,6 +113,21 @@ Automated coverage must include: dismissal, focus restoration, and an accessible name for every option; - PID rebinding by executable path and no silent switch to another application. +## Recording Library Visual Regression Matrix + +Automated coverage and Windows acceptance must include: + +- compact two-line rows that keep title, date, duration, and transcription + state readable without repeating file size or a leading recording icon; +- quick playback exposed on row hover, keyboard focus, selection, and active + playback, with Space toggling playback while Enter keeps its selection role; +- flat selected, context-menu, processing, completed, and failed states with + visible focus and no card border or elevation; +- an independently scrolling list with a narrow neutral scrollbar, transparent + track, and usable forced-colors behavior; +- a playback footer with no persistent network-use note, verified at 100%, + 125%, and 150% Windows scaling and at the 980×640 minimum window size. + ## Audio Import Regression Matrix Automated coverage must include: diff --git a/package-lock.json b/package-lock.json index 0370a83..6306c66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nota", - "version": "0.10.0", + "version": "0.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nota", - "version": "0.10.0", + "version": "0.11.0", "license": "MIT", "dependencies": { "@radix-ui/react-select": "^2.3.7", diff --git a/package.json b/package.json index fcef732..a3970cd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nota", "private": true, - "version": "0.10.0", + "version": "0.11.0", "license": "MIT", "repository": { "type": "git", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 74bea21..07e3b70 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2299,7 +2299,7 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nota" -version = "0.10.0" +version = "0.11.0" dependencies = [ "anyhow", "arboard", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ec3990d..4c5e060 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nota" -version = "0.10.0" +version = "0.11.0" description = "A private, local-first Windows meeting recorder" authors = ["Nota Contributors"] license = "MIT" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index df2ab66..16bd508 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Nota", - "version": "0.10.0", + "version": "0.11.0", "identifier": "com.local.meetingnote", "build": { "beforeDevCommand": "npm run dev:web", diff --git a/src/components/RecordingsWorkspace.test.tsx b/src/components/RecordingsWorkspace.test.tsx index d83c304..efec842 100644 --- a/src/components/RecordingsWorkspace.test.tsx +++ b/src/components/RecordingsWorkspace.test.tsx @@ -315,6 +315,47 @@ describe("RecordingsWorkspace", () => { expect(screen.getByText("客户访谈")).toBeInTheDocument(); }); + it("renders recordings as compact two-line rows without redundant list chrome", async () => { + const actions = renderWorkspace(); + await waitFor(() => expect(actions.onPreparePlayback).toHaveBeenCalled()); + + const list = screen.getByLabelText("录音列表"); + const row = within(list).getByText("产品周会").closest("article")!; + const metadata = row.querySelector(".history-item-meta"); + const title = within(row).getByText("产品周会"); + const status = within(row).getByText("已转写"); + + expect(screen.getByLabelText("2 条录音")).toHaveTextContent("2 条"); + expect(row.querySelector(".history-item-icon")).toBeNull(); + expect(row.querySelector(".history-status-dot")).toBeNull(); + expect(title).toHaveClass("history-item-title"); + expect(title).toHaveAttribute("title", "产品周会"); + expect(metadata?.firstElementChild).toHaveClass("history-item-facts"); + expect(metadata?.lastElementChild).toBe(status); + expect(status).toHaveClass("transcription-badge", "history-transcription-status", "status-completed"); + expect(metadata).toHaveTextContent("1:02"); + expect(metadata).toHaveTextContent("已转写"); + expect(within(list).queryByText("1.0 MB")).not.toBeInTheDocument(); + expect(screen.queryByText(/本地录音;仅在转写或手动生成 AI 文档时连接所选服务/)).not.toBeInTheDocument(); + }); + + it("plays the focused recording with Space while Enter remains selection", async () => { + const play = vi.spyOn(HTMLMediaElement.prototype, "play").mockResolvedValue(); + const actions = renderWorkspace(); + await waitFor(() => expect(document.querySelector("audio")).toHaveAttribute( + "src", + `asset://${completed.path}`, + )); + const select = within(screen.getByLabelText("录音列表")) + .getByText("产品周会") + .closest("button")!; + + fireEvent.keyDown(select, { key: "Enter" }); + expect(play).not.toHaveBeenCalled(); + fireEvent.keyDown(select, { key: " " }); + expect(play).toHaveBeenCalledOnce(); + }); + it("shows provider speaker labels and timestamp controls without inventing roles", () => { renderWorkspace(); expect(screen.getByText("speaker_1")).toBeInTheDocument(); diff --git a/src/components/RecordingsWorkspace.tsx b/src/components/RecordingsWorkspace.tsx index bb8f302..b41ffe7 100644 --- a/src/components/RecordingsWorkspace.tsx +++ b/src/components/RecordingsWorkspace.tsx @@ -1,7 +1,6 @@ import { convertFileSrc } from "@tauri-apps/api/core"; import { AlertCircle, - Check, Clipboard, Download, FileAudio, @@ -707,7 +706,9 @@ export function RecordingsWorkspace(props: RecordingsWorkspaceProps) { 导入录音 - {props.items.length} + + {props.items.length} 条 +

{ event.preventDefault(); openContextMenu(item, event.clientX, event.clientY); }} > - @@ -1194,7 +1204,6 @@ export function RecordingsWorkspace(props: RecordingsWorkspaceProps) { }} /> -
本地录音;仅在转写或手动生成 AI 文档时连接所选服务
)}
diff --git a/src/design-tokens.css b/src/design-tokens.css index ec62cbd..fae4d90 100644 --- a/src/design-tokens.css +++ b/src/design-tokens.css @@ -23,15 +23,15 @@ --font-weight-semibold: 600; --font-weight-bold: 700; - /* Nota's warm-neutral, calm-jade semantic color system. */ - --color-text-primary: #242726; - --color-text-secondary: #59615d; - --color-text-muted: #737a76; - --color-text-subtle: #858a86; - --color-text-disabled: #999d99; + /* Nota's clean-neutral, calm-jade semantic color system. */ + --color-text-primary: #2b302e; + --color-text-secondary: #4f5954; + --color-text-muted: #626c67; + --color-text-subtle: #66706b; + --color-text-disabled: #8d9590; --color-text-inverse: #ffffff; - --color-text-brand: #285f58; - --color-text-success: #2d675e; + --color-text-brand: #245e55; + --color-text-success: #285f57; --color-text-info: #3d6875; --color-text-warning: #80621e; --color-text-danger: #a23e3e; @@ -45,45 +45,45 @@ --color-syntax-null: var(--color-text-muted); --color-syntax-punctuation: var(--color-text-secondary); - --color-surface-canvas: #f4f3ef; - --color-surface-primary: #fbfaf7; + --color-surface-canvas: #f4f6f4; + --color-surface-primary: #ffffff; --color-surface-raised: #ffffff; - --color-surface-subtle: #f1f0ec; - --color-surface-sunken: #efeee9; - --color-surface-hover: #ebeae5; - --color-surface-brand: #e4eeeb; - --color-surface-brand-strong: #dce9e6; - --color-surface-success: #dfebe7; - --color-surface-info: #deebef; - --color-surface-warning: #f5eedf; - --color-surface-danger: #f2e3df; + --color-surface-subtle: #f7f8f6; + --color-surface-sunken: #eef1ee; + --color-surface-hover: #e9eeea; + --color-surface-brand: #e1eeea; + --color-surface-brand-strong: #d8e9e4; + --color-surface-success: #deede8; + --color-surface-info: #e2edf0; + --color-surface-warning: #f7f1e4; + --color-surface-danger: #f4e7e3; --color-surface-tooltip: #26312e; - --color-border-default: #d8d7d1; - --color-border-subtle: #e5e4df; - --color-border-strong: #bed2cc; - --color-border-danger: #e7cfca; + --color-border-default: #dce1dd; + --color-border-subtle: #e7ebe8; + --color-border-strong: #b8d3cb; + --color-border-danger: #e5ccc5; --color-border-inverse: #ffffff; - --color-focus-ring: #4d7f77; + --color-focus-ring: #477a72; - --color-control-primary: #285f58; - --color-control-primary-hover: #214f49; + --color-control-primary: #245e55; + --color-control-primary-hover: #1f514a; --color-control-secondary: #ffffff; --color-control-danger: #a23e3e; - --color-icon-primary: #59615d; - --color-icon-muted: #737a76; - --color-icon-brand: #39786e; - --color-brand-accent: #4b8178; - --color-brand-accent-soft: #72a49b; + --color-icon-primary: #56615c; + --color-icon-muted: #66706b; + --color-icon-brand: #34766b; + --color-brand-accent: #468078; + --color-brand-accent-soft: #70a49b; --color-status-recording: #c84f45; --color-status-paused: #bd8b35; --color-status-warning-accent: #d99a42; /* Translucent surfaces and effect colors. */ - --color-surface-app-chrome: rgba(248, 247, 243, 0.92); - --color-surface-app-chrome-soft: rgba(248, 247, 243, 0.88); - --color-surface-glass: rgba(255, 254, 251, 0.98); - --color-surface-hover-translucent: rgba(255, 255, 255, 0.55); + --color-surface-app-chrome: rgba(247, 249, 247, 0.92); + --color-surface-app-chrome-soft: rgba(247, 249, 247, 0.88); + --color-surface-glass: rgba(255, 255, 255, 0.98); + --color-surface-hover-translucent: rgba(255, 255, 255, 0.62); --color-surface-selected-translucent: rgba(255, 255, 255, 0.72); --color-border-inverse-subtle: rgba(255, 255, 255, 0.09); --color-fill-inverse-subtle: rgba(255, 255, 255, 0.18); diff --git a/src/recording-detail.css b/src/recording-detail.css index f7b338f..9129517 100644 --- a/src/recording-detail.css +++ b/src/recording-detail.css @@ -3,11 +3,12 @@ .library-workspace { grid-template-columns: 280px minmax(0, 1fr); } .library-workspace.is-focused { grid-template-columns: minmax(0, 1fr); } .library-workspace [hidden] { display: none !important; } -.library-workspace .history-pane { padding: var(--space-4) var(--space-3) 0; } -.library-workspace .history-header { align-items: center; gap: var(--space-2); } +.library-workspace .history-pane { padding: var(--space-3) var(--space-2) 0; } +.library-workspace .history-header { align-items: center; gap: var(--space-2); padding: 0 var(--space-1-5) var(--space-3); } .library-workspace .history-header .eyebrow { display: none; } .library-workspace .history-header-actions { gap: var(--space-1); } -.library-workspace .history-item { padding-inline: var(--space-2); } +.library-workspace .history-search { min-height: var(--control-height-large); margin-bottom: var(--space-2); padding-block: var(--space-1-5); border-radius: var(--radius-medium); } +.library-workspace .history-item { padding-inline: var(--space-1); } .library-workspace .transcript-pane { padding: 0; overflow: hidden; } .library-workspace .recording-active-banner { flex: 0 0 auto; margin: var(--space-2) var(--space-4) 0; } .library-workspace .record-detail-header { flex: 0 0 auto; align-items: center; margin: 0; padding: var(--space-3) var(--space-5); gap: var(--space-3); } @@ -31,8 +32,7 @@ .library-workspace .transcription-version-select { min-width: 0; max-width: 190px; } .library-workspace .transcription-version-select > span { display: none; } .library-workspace .transcription-progress, .library-workspace .transcript-error { flex: 0 0 auto; margin: var(--space-2) var(--space-4); } -.library-workspace .unified-player { flex: 0 0 auto; margin: 0; padding: var(--space-2) var(--space-4) 0; border: 0; border-top: 1px solid var(--color-border-subtle); border-radius: 0; background: var(--color-surface-primary); } -.record-privacy-note { flex: 0 0 auto; padding: var(--space-1) var(--space-5) var(--space-2); color: var(--color-text-secondary); font-size: var(--font-size-caption); line-height: var(--line-height-caption); } +.library-workspace .unified-player { flex: 0 0 auto; margin: 0; padding: var(--space-2) var(--space-4); border: 0; border-top: 1px solid var(--color-border-subtle); border-radius: 0; background: var(--color-surface-primary); } .ai-documents-layout { min-height: 0; min-width: 0; display: flex; flex-direction: column; margin: 0; border: 0; border-radius: 0; overflow: visible; } .ai-document-preview { flex: 1 1 0; } .ai-document-toolbar { flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-5); border-block: 1px solid var(--color-border-subtle); background: var(--color-surface-primary); } diff --git a/src/styles.css b/src/styles.css index 6f71e7b..7149bfa 100644 --- a/src/styles.css +++ b/src/styles.css @@ -452,7 +452,7 @@ body.capture-prompt-body { .app-sidebar { position: relative; z-index: 10; display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); min-height: 100vh; padding: var(--space-4) var(--space-2-5) var(--space-3); border-right: 1px solid var(--color-border-default); - background: var(--color-surface-hover); + background: var(--color-surface-sunken); } .sidebar-brand { width: 42px; height: 42px; display: grid; place-items: center; align-self: center; @@ -506,6 +506,10 @@ body.capture-prompt-body { .history-header { display: flex; align-items: end; justify-content: space-between; padding: 0 var(--space-1-5) var(--space-4); } .history-header h1 { font-size: var(--font-size-subtitle); line-height: var(--line-height-subtitle); } .history-header-actions { display: flex; align-items: center; gap: var(--space-2); } +.history-count { + min-width: max-content; color: var(--color-text-muted); font-size: var(--font-size-caption); line-height: var(--line-height-caption); + font-weight: var(--font-weight-semibold); font-variant-numeric: tabular-nums; +} .import-audio-button { white-space: nowrap; } .history-search { display: flex; align-items: center; gap: var(--space-2); margin: 0 var(--space-1) var(--space-3); padding: var(--space-2) var(--space-3); @@ -548,32 +552,60 @@ body.capture-prompt-body { .audio-import-progress.indeterminate i { animation: none; } } .history-list { - flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto; - overscroll-behavior: contain; scrollbar-gutter: stable; padding: 0 var(--space-1) var(--space-5); -} + flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: var(--space-1); overflow-x: hidden; overflow-y: auto; + overscroll-behavior: contain; padding: 0 var(--space-1) var(--space-5); + scrollbar-width: thin; scrollbar-color: var(--color-border-default) transparent; +} +.history-list::-webkit-scrollbar { width: var(--space-1-5); } +.history-list::-webkit-scrollbar-track { background: transparent; } +.history-list::-webkit-scrollbar-thumb { border-radius: var(--radius-round); background: var(--color-border-default); } +.history-list:hover::-webkit-scrollbar-thumb { background: var(--color-icon-muted); } +.history-list::-webkit-scrollbar-button { display: none; } .history-item { - width: 100%; display: grid; grid-template-columns: minmax(0,1fr) 30px; align-items: center; - margin-bottom: var(--space-1); padding: var(--space-1); border: 1px solid transparent; border-radius: var(--radius-large); background: transparent; + position: relative; + width: 100%; display: grid; grid-template-columns: minmax(0,1fr) var(--control-height-compact); align-items: center; + margin: 0; padding: 0 var(--space-1); border: 0; border-radius: var(--radius-medium); background: transparent; + transition: background-color var(--motion-duration-fast) var(--motion-easing-standard); +} +.history-item::after { + content: ""; position: absolute; right: var(--space-1); bottom: calc(-1 * var(--space-0-5)); left: var(--space-3); height: 1px; + background: var(--color-border-default); pointer-events: none; + transition: opacity var(--motion-duration-fast) var(--motion-easing-standard); } +.history-item:last-child::after, .history-item:is(:hover, .selected, .menu-target)::after { opacity: 0; } .history-item:hover { background: var(--color-surface-hover-translucent); } -.history-item.selected { border-color: var(--color-border-subtle); background: var(--color-surface-raised); box-shadow: var(--shadow-sm); } -.history-item.menu-target { border-color: var(--color-border-default); background: var(--color-surface-raised); } +.history-item.selected { background: var(--color-surface-brand); } +.history-item.menu-target { background: var(--color-surface-brand-strong); } .history-select { - min-width: 0; display: flex; align-items: flex-start; gap: var(--space-2-5); padding: var(--space-2) var(--space-1-5); + min-width: 0; display: flex; align-items: center; padding: var(--space-2-5) var(--space-3); border: 0; text-align: left; background: transparent; cursor: pointer; } -.history-quick-play { - width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: 50%; - color: var(--color-text-success); background: var(--color-surface-brand); cursor: pointer; +.history-select:focus-visible { + outline: 0; border-radius: var(--radius-medium); box-shadow: var(--shadow-focus-compact); } -.history-quick-play:hover { color: var(--color-text-inverse); background: var(--color-control-primary); } -.history-item-icon { - width: 29px; height: 29px; display: grid; place-items: center; flex: 0 0 auto; - border-radius: var(--radius-medium); color: var(--color-text-info); background: var(--color-surface-brand); +.history-quick-play { + width: var(--control-height-compact); height: var(--control-height-compact); display: grid; place-items: center; + border: 0; border-radius: var(--radius-small); color: var(--color-icon-primary); background: transparent; cursor: pointer; + opacity: 0; visibility: hidden; + transition: color var(--motion-duration-fast) var(--motion-easing-standard), background-color var(--motion-duration-fast) var(--motion-easing-standard), opacity var(--motion-duration-fast) var(--motion-easing-standard), transform var(--motion-duration-fast) var(--motion-easing-standard); +} +.history-item:is(:hover, :focus-within, .selected, .is-playing, .menu-target) .history-quick-play { + opacity: 1; visibility: visible; +} +.history-quick-play:hover { color: var(--color-text-primary); background: var(--color-surface-raised); } +.history-quick-play:focus-visible { outline: 0; box-shadow: var(--shadow-focus-compact); } +.history-quick-play:active { transform: scale(.97); } +.history-item.is-playing .history-quick-play { color: var(--color-text-inverse); background: var(--color-control-primary); } +.history-item-main { min-width: 0; display: grid; gap: var(--space-0-5); } +.history-item-title { + display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + color: var(--color-text-primary); font-size: var(--font-size-body); line-height: var(--line-height-body); font-weight: var(--font-weight-regular); +} +.history-item-meta { + min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); + color: var(--color-text-subtle); font-size: var(--font-size-caption); line-height: var(--line-height-caption); font-variant-numeric: tabular-nums; } -.history-item-main { min-width: 0; display: grid; gap: var(--space-1); } -.history-item-main strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--font-size-body); line-height: var(--line-height-body); } -.history-item-main small { color: var(--color-text-subtle); font-size: var(--font-size-caption); line-height: var(--line-height-caption); } +.history-item-facts { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .transcription-badge { width: max-content; display: inline-flex; align-items: center; padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-round); color: var(--color-text-muted); background: var(--color-surface-hover); font-size: var(--font-size-caption); line-height: var(--line-height-caption); font-weight: var(--font-weight-semibold); @@ -581,6 +613,18 @@ body.capture-prompt-body { .status-completed { color: var(--color-text-success); background: var(--color-surface-success); } .status-queued, .status-preparing, .status-transcribing { color: var(--color-text-info); background: var(--color-surface-info); } .status-failed, .status-interrupted, .status-cancelled { color: var(--color-text-danger); background: var(--color-surface-danger); } +.history-transcription-status { + width: auto; max-width: 50%; min-width: 0; min-height: var(--line-height-caption); flex: 0 1 auto; justify-content: center; + overflow: hidden; padding: 0 var(--space-1-5); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-small); + font-weight: var(--font-weight-medium); line-height: 1; text-overflow: ellipsis; white-space: nowrap; +} +.history-transcription-status.status-completed { border-color: var(--color-border-strong); } +.history-transcription-status:is(.status-failed, .status-interrupted, .status-cancelled) { border-color: var(--color-border-danger); } +@media (forced-colors: active) { + .history-list { scrollbar-color: auto; } + .history-item.selected { outline: 1px solid Highlight; outline-offset: -1px; } + .history-transcription-status { border-color: currentColor; } +} .history-empty { display: grid; place-items: center; gap: var(--space-2); padding: var(--space-14) var(--space-4); color: var(--color-text-subtle); } .history-empty strong { font-size: var(--font-size-body); line-height: var(--line-height-body); color: var(--color-text-secondary); }.history-empty span { font-size: var(--font-size-caption); line-height: var(--line-height-caption); } .transcript-pane {