/// import { Cell, computed, type Default, handler, NAME, pattern, UI, } from "commontools"; // Type definition for transcription data (from ct-voice-input component) interface TranscriptionChunk { timestamp: [number, number]; text: string; } interface TranscriptionData { id: string; text: string; chunks?: TranscriptionChunk[]; audioData?: string; duration: number; timestamp: number; } type Input = { title?: Cell>; }; type Output = { transcription: Default; notes: Default; }; const handleTranscriptionComplete = handler< { detail: { transcription: TranscriptionData } }, { notes: Cell } >(({ detail }, { notes }) => { // Add the transcription to our notes list notes.push(detail.transcription); }); const handleDeleteNote = handler< undefined, { noteId: string; notes: Cell } >((_, { noteId, notes }) => { const currentNotes = notes.get(); const filtered = currentNotes.filter((note) => note.id !== noteId); notes.set(filtered); }); const VoiceNote = pattern(({ title }) => { const transcription = Cell.of(null); const notes = Cell.of([]); // Computed values for type-safe JSX access const hasTranscription = computed(() => transcription.get() !== null); const transcriptionText = computed(() => transcription.get()?.text || ""); const transcriptionDuration = computed( () => transcription.get()?.duration || 0, ); const notesCount = computed(() => notes.get().length); const hasNotes = computed(() => notes.get().length > 0); return { [NAME]: title, [UI]: (

Record a Voice Note

Hold the microphone button to record. Release to transcribe.

{hasTranscription && (
Latest Transcription:

{transcriptionText}

Duration: {transcriptionDuration.toFixed(1)}s
)}

Saved Notes ({notesCount})

{!hasNotes ? (

No voice notes yet. Record one above!

) : ( {notes.map((note) => (

{note.text}

{new Date(note.timestamp).toLocaleString()} ·{" "} {note.duration.toFixed(1)}s
×
))}
)}
), transcription, notes, }; }); export default VoiceNote;