feat(transcript): show per-segment timestamps in live and finalized views
This commit is contained in:
@@ -35,6 +35,17 @@
|
|||||||
return speakers.find((s) => s.label === label)?.display_name ?? label;
|
return speakers.find((s) => s.label === label)?.display_name ?? label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transcript timestamps: segment start_ms → "m:ss" (or "h:mm:ss" past an
|
||||||
|
// hour). Shown as a quiet monospace prefix so a line reads "0:42 Alice: …".
|
||||||
|
function fmtTs(ms: number): string {
|
||||||
|
const total = Math.floor(ms / 1000);
|
||||||
|
const h = Math.floor(total / 3600);
|
||||||
|
const m = Math.floor((total % 3600) / 60);
|
||||||
|
const s = total % 60;
|
||||||
|
const mm = h ? String(m).padStart(2, "0") : String(m);
|
||||||
|
return `${h ? `${h}:` : ""}${mm}:${String(s).padStart(2, "0")}`;
|
||||||
|
}
|
||||||
|
|
||||||
// T8.7/FR-TRX-4: the meeting view shows the language actually used, not
|
// T8.7/FR-TRX-4: the meeting view shows the language actually used, not
|
||||||
// just the raw ISO code — falls back to the code itself if it's not in
|
// just the raw ISO code — falls back to the code itself if it's not in
|
||||||
// the (curated) catalog, and to "auto-detecting…" before any is known.
|
// the (curated) catalog, and to "auto-detecting…" before any is known.
|
||||||
@@ -266,7 +277,11 @@
|
|||||||
<p class="muted">No transcript for this meeting.</p>
|
<p class="muted">No transcript for this meeting.</p>
|
||||||
{:else}
|
{:else}
|
||||||
{#each m.segments as s (s.id)}
|
{#each m.segments as s (s.id)}
|
||||||
<p><strong>{speakerName(s.speaker, m.speakers)}:</strong> {s.text}</p>
|
<p>
|
||||||
|
<span class="ts">{fmtTs(s.start_ms)}</span>
|
||||||
|
<strong>{speakerName(s.speaker, m.speakers)}:</strong>
|
||||||
|
{s.text}
|
||||||
|
</p>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
@@ -428,6 +443,7 @@
|
|||||||
class:active={open}
|
class:active={open}
|
||||||
onclick={() => (selectedSegmentMs = open ? null : s.start_ms)}
|
onclick={() => (selectedSegmentMs = open ? null : s.start_ms)}
|
||||||
>
|
>
|
||||||
|
<span class="ts">{fmtTs(s.start_ms)}</span>
|
||||||
<strong>{speakerName(s.speaker)}:</strong>
|
<strong>{speakerName(s.speaker)}:</strong>
|
||||||
{s.text}
|
{s.text}
|
||||||
{#if hasNote}
|
{#if hasNote}
|
||||||
@@ -561,6 +577,14 @@
|
|||||||
.note-badge {
|
.note-badge {
|
||||||
margin-left: 0.3rem;
|
margin-left: 0.3rem;
|
||||||
}
|
}
|
||||||
|
/* Transcript timestamp: a quiet monospace prefix, not competing with the
|
||||||
|
speaker name or text for attention. */
|
||||||
|
.ts {
|
||||||
|
font-family: var(--font-mono, ui-monospace, monospace);
|
||||||
|
font-size: 0.78em;
|
||||||
|
color: var(--muted);
|
||||||
|
margin-right: 0.15rem;
|
||||||
|
}
|
||||||
.segment-note-input {
|
.segment-note-input {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Reference in New Issue
Block a user