Transcribed Note Card
A transcription list item pairing transcript text with inline audio playback — with a "transcribing…" placeholder that morphs into the populated card.
Transcribed Note Card
Transcribed Note Card is a list item that pairs transcribed text with inline audio playback. It has two variants from one component:
- Placeholder (
transcribing) — a waveform row + a "Transcribing…" label, the canonical loading state for auseOperationList-backed STT list where items stream in. - Populated — a relative timestamp (hover → absolute), the transcript body, a native
<audio>footer, and a hover-revealed delete.
Drive it from useTranscribe + useOperationList.
When to use it: render a growing list of voice notes / meeting snippets where each item starts as a placeholder and morphs into the finished transcription.
Preview
Installation
pnpm dlx shadcn@latest add @localmode/ui/audio/transcribed-note-cardnpx shadcn@latest add @localmode/ui/audio/transcribed-note-cardyarn dlx shadcn@latest add @localmode/ui/audio/transcribed-note-cardbunx --bun shadcn@latest add @localmode/ui/audio/transcribed-note-cardData source & dependencies
Data source: renders the transcript text + audio Blob you pass — works with any backend. Recommended producer: useTranscribe + useOperationList (with the Whisper STT model from @localmode/transformers) from @localmode/react (on-device, optional).
@localmode/ui/lib/browser-utils—useObjectUrlfor Blob lifecycle (installed automatically as a registry dependency)clsx+tailwind-merge— via the sharedcn()util
Files installed
transcribed-note-card.tsx— the componentwaveform-activity-bars.tsx— the placeholder indicator (registry dependency)lib/browser-utils.ts— generic browser helpers (useObjectUrl)lib/utils.ts— thecn()helper (if not already present)
Props
TranscribedNoteCard
Prop
Type
Examples
A streaming transcription list
import { TranscribedNoteCard } from '@/components/transcribed-note-card';
import { useOperationList, useVoiceRecorder } from '@localmode/react';
import { transcribe } from '@localmode/core';
import { transformers } from '@localmode/transformers';
export function VoiceNotes() {
const recorder = useVoiceRecorder();
const { items, isLoading, execute, removeItem } = useOperationList({
fn: (audio: Blob, signal) =>
transcribe({ model: transformers.speechToText('onnx-community/whisper-base'), audio, abortSignal: signal }),
transform: (result, audio) => ({ id: crypto.randomUUID(), text: result.text, audio, timestamp: new Date() }),
});
return (
<div className="flex flex-col gap-3">
{isLoading && <TranscribedNoteCard transcribing />}
{items.map((note) => (
<TranscribedNoteCard
key={note.id}
text={note.text}
audio={note.audio}
timestamp={note.timestamp}
onDelete={() => removeItem((n) => n.id === note.id)}
/>
))}
</div>
);
}Customization
The relative-time formatter lives in the copied file — swap it for your own (or a library) if you need finer granularity. The delete control is hover-revealed via group-hover; remove the opacity-0 classes to keep it always visible. Pass either a Blob or an object-URL string for audio.
Voice Comparison Panel
A/B voice comparison — two language-grouped pickers with audio players, a shared textarea, and a Compare button to synthesize the same text through two voices.
Voice Orb
An animated canvas voice-agent orb that reflects discrete agent states and pulses with input/output volume via callbacks — visual state decoupled from the audio source.