Voice-to-text edit mode (Variant C) + adopt shared @aymurai/ui#89
Voice-to-text edit mode (Variant C) + adopt shared @aymurai/ui#89lionelchamorro wants to merge 267 commits into
Conversation
Dev-only: pre-set api baseURL from VITE_DEV_HOST so APIProtected screens render under pnpm dev:web (pairs with VITE_USE_MOCK_STT for offline UI work). Inert in production and when unset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@aymurai/ui DialogContent caps max-width at 700px, collapsing the tutorial grid's text columns. Override width from the consumer (90vw/920px) and replace the inline style with a Panda css class per panda-css rules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
It is a dev/CI browser-automation CLI with no runtime import; keeping it under dependencies would ship it with the app. (final-review finding) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Actualización: alineación con Figma "Speech to text WIP" + arreglos de toolchainSe agregaron 8 commits ( Auditoría visual vs Figma (sección "Speech to text WIP"). Se verificó toda la pantalla a pantalla con Playwright + Chrome sobre Único bug encontrado y corregido
Soporte / toolchain
Gates: 19/19 tests · typecheck (node+web) · biome · knip — todo en verde.
|
Drop .npmrc (its pnpm-only key triggered a cosmetic npm warning on every `npm run typecheck`); the setting lives in pnpm-workspace.yaml instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Points at AymurAI/ui-components#chore/release-v0.3.0 (commit b11645e); the v0.3.0 tag is not published yet. Repin to the tag once released. Brings the ArchiveProgress component (near-square progress bar) + transcript-block/side-panel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- process: replace the custom pill-shaped progress bar (border-radius 9999px) with @aymurai/ui ArchiveProgress (near-square bar matching Figma); map transcription status -> ArchiveProgress states; drop now-orphaned i18n keys (label/stop/replace text now rendered by the component). - transcript editor: read-mode body + title background bg.primary (gray #F6F5F7) -> bg.secondary (white) to match the design; edit banner stays gray. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the chore/release-v0.3.0 branch ref with the published v0.3.1 tag. ArchiveProgress API unchanged; progress bar + screens verified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
From the Figma node spec (get_design_context): - preview file row: border 2px->4px, padding ->24px, heading->row gap ->32px - play button: gray bg -> bg.primary-alternative (#E5E8FF), icon 20->28 - file name: paragraph.sm.strong -> paragraph.md.default (16px regular) - trash icon: 18->24px, text.lighter -> text.default - drop title: constrain maxWidth so it wraps to 2 lines like Figma Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- edit-mode panel: replace custom TurnSidePanel internals with the library SidePanel (pills, timestamp, merge/add/delete), wired to the reducer and constrained to a 360px right column. Drops the app-only inline global rename, free-form new-person naming, and timestamp-invalid hint (not in the Figma design / not in the library API), per product decision. - read mode: render turns via the library TranscriptBlock (Figma display component); edit mode keeps the custom TurnBlock (editable text, search highlight, click-to-seek). Read-mode turns keep a ref wrapper so search scroll-to-match still works. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The @aymurai/ui Player renders rightSlot flush against the time readout, so the Finalizar button sat glued to '00:00 / 25:03'. Wrap rightSlot with a left margin. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The @aymurai/ui ArchiveProgress always renders a 'Descartar' (✕) button, which the Figma transcription screen doesn't include. Hide it via a scoped consumer CSS rule until the library makes it conditional. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backend switched the /asr/transcribe/stream SSE format from a full-snapshot-per-event payload to a discriminated event stream keyed on `type`. Every event now failed the old schema, so safeParse silently dropped them all and transcription ended with "no document_id". - schema/asr: replace ASRStreamEventSchema with a discriminated union over meta (document_id, duration), delta (text, progress), segments (document) and done (progress). - transcribeStream: dispatch on event.type — capture document_id from meta, drive progress from delta/done (already a 0..1 ratio), build the throwaway preview from delta chunks, and take the authoritative paragraphs from the single segments event. Drops the old per-event dedup Map and current_time/total_time math. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In read mode the @aymurai/ui TranscriptBlock migration dropped two behaviours: clicking a turn no longer seeked the player, and the playing turn was no longer kept in view. Restore both — clicking a block seeks to its startMs (with keyboard activation + aria-label), the active turn is highlighted, and an effect keyed on activeTurnId scrolls the playing turn into view as the audio advances while staying out of the way when paused. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the bottom-to-top marquee animation on the processing screen with a plain scrollable container. Each new ASR fragment updates the text in place; the view sticks to the bottom to keep the newest fragment visible but stops following once the user scrolls up to re-read earlier text. Drops the inline keyframe, the per-character scroll-duration estimate and the pending-text swap that the marquee required. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… related functionality
Edit mode was missing the click-to-seek and follow-scroll behavior already present in read mode. Clicking a turn now seeks the player and selects it (without re-seeking on later clicks within an already-selected block, so placing the caret while editing doesn't yank playback back to the block's start), and auto-scroll pauses while the user is typing in a turn so it doesn't lose their place if playback moves to another turn meanwhile. Also fixes SPLIT_TURN duplicating the original [startMs,endMs) range across all resulting pieces instead of apportioning it — now that split pieces are independently clickable/seekable, they need distinct time ranges. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… in re-seek guard Clicking a turn's speaker/timestamp header in edit mode bubbled up to the block's own click handler, firing onSeekTo/onSelect twice per click. Also, the "don't re-seek on an already-selected block" guard only checked isSelected (set by mouse clicks), so tabbing into a block's text via keyboard and then clicking to place the caret still incorrectly re-seeked the player, since isSelected was never set for keyboard-only focus. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ace-only SPLIT_TURN drops a pre/post piece when its trimmed text is empty, but was still computing the middle piece's boundaries from the raw (untrimmed) character offsets. When the dropped edge had non-zero width (e.g. a leading space before the split point), that time span belonged to no turn at all, so playback silently lost its highlight while passing through it. The middle piece now absorbs a dropped edge's span instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…imestamp edits "Agregar turno debajo" inserted a new turn with startMs === endMs — a zero-width range that useActiveTurn can never match (it requires startMs <= currentMs < endMs), so a manually inserted turn could never be highlighted or followed by auto-scroll no matter what timestamp it was given. The new turn now starts where the active turn ends and fills the gap to the next turn (capped, or a default duration if there's no next turn). Also validate manual timestamp edits in the side panel against the previous/next turns' start times, rejecting values that would break the turns array's chronological order (e.g. typing 00:30 for a turn sitting between 00:10 and 00:20) instead of silently applying them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pulled the trailing-media-extension-stripping logic out of asrMapper's transcriptionTitleFromFile into its own utility, since the upcoming transcript export feature needs the same behavior (a title carried over from the source audio's file name shouldn't leak its ".wav"/".mp3"/etc. suffix into the exported file name). No behavior change for asrMapper. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a client-side export module (services/export/) that turns a transcription into a downloadable file: a shared ExportDocument built once from the transcription + options, then serialized per format. .txt and .odt are generated entirely client-side (.odt is a hand-built minimal ODF package via jszip, including a page footer watermark matching the anonymizer's own document watermark); .pdf reuses the anonymizer's existing /convert/odt/pdf backend endpoint by feeding it the client-built .odt, avoiding a second PDF generator (queries.ts's odtToPdf mutation is refactored to expose that call as a standalone convertOdtToPdf function). The Finish screen's single "Descargar .txt" button becomes a format-picker menu. finish-anonymizer.tsx adopts the new shared downloadBlob helper in place of its local copy, removing that duplication. The ExportOptions/ExportDocument split is intentionally kept format-agnostic and decoupled from any UI, so a future export-preview screen can reuse buildExportDocument/exportTranscription directly instead of duplicating this logic. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
This branch delivers the redesigned voice-to-text flow with the Variant-C side-panel edit mode, and migrates its UI primitives onto the shared
@aymurai/uicomponent library.The most recent change (this session) does two things:
@aymurai/ui— replaces the in-repo Panda primitives (Button,Card,Switch,Avatar, audioPlayer, stepper colors) with the shared library and imports its compiledstyles.cssinmain.tsx.SpeakerAvataris now a thin wrapper preserving the existingspeakerprop API.buildFixture.Dependency wiring (important for CI)
@aymurai/uiis a private repo (AymurAI/ui-components), consumed as a git dependency over SSH, pinned to thev0.2.1tag:Because the library's
dist/is gitignored, pnpm builds it on install via the package'spreparescript (added inui-componentsand released inv0.2.1). This requires:pnpm-workspace.yaml→allowBuilds: '@aymurai/ui': true(added here) so pnpm 11 permits the git dep's build scripts.AymurAI/ui-componentsat install time. Local dev with an SSH key works out of the box; CI needs a deploy key / SSH agent with read access to that repo, orpnpm installwill fail to clone.Verification
pnpm typecheck— passes (node + web).pnpm knip— passes (warn-only).pnpm installrebuilds@aymurai/uidist/(incl.styles.css) viaprepareat tagv0.2.1.🤖 Generated with Claude Code