Initial release: DictIA v0.8.14-alpha (fork de Speakr, AGPL-3.0)
This commit is contained in:
130
templates/components/detail/mobile-transcript-panel.html
Normal file
130
templates/components/detail/mobile-transcript-panel.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<!-- Mobile Transcript Panel -->
|
||||
<div v-if="mobileTab === 'transcript'" class="h-full flex flex-col space-y-4">
|
||||
<div class="flex items-center justify-between gap-2 flex-shrink-0 px-3">
|
||||
<!-- Follow Player Checkbox -->
|
||||
<div v-if="processedTranscription.isJson && processedTranscription.hasDialogue"
|
||||
class="follow-player-control text-[var(--text-muted)]"
|
||||
@click="toggleFollowPlayerMode"
|
||||
:title="followPlayerMode ? t('tooltips.followPlayerEnabled') : t('tooltips.followPlayerDisabled')">
|
||||
<input type="checkbox"
|
||||
:checked="followPlayerMode"
|
||||
@click.stop="toggleFollowPlayerMode">
|
||||
<i class="fas fa-arrows-alt-v follow-icon"></i>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="processedTranscription.hasDialogue" class="view-mode-toggle">
|
||||
<button @click="toggleTranscriptionViewMode" :class="['toggle-button', transcriptionViewMode === 'simple' ? 'active' : '']"><i class="fas fa-list"></i></button>
|
||||
<button @click="toggleTranscriptionViewMode" :class="['toggle-button', transcriptionViewMode === 'bubble' ? 'active' : '']"><i class="fas fa-comments"></i></button>
|
||||
</div>
|
||||
<button @click="copyTranscription" class="copy-btn" :title="t('tooltips.copyTranscript')"><i class="fas fa-copy"></i></button>
|
||||
<button @click="downloadTranscript" v-if="selectedRecording && selectedRecording.transcription" class="copy-btn" :title="t('tooltips.downloadTranscriptWithTemplate')"><i class="fas fa-download"></i></button>
|
||||
<button @click="openTranscriptionEditor" v-if="selectedRecording && selectedRecording.transcription" class="copy-btn" :title="t('tooltips.editTranscript')"><i class="fas fa-edit"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow overflow-y-auto mobile-content-box relative">
|
||||
<!-- Floating Processing Indicator (Mobile) -->
|
||||
<div v-if="selectedRecording.status === 'PROCESSING'"
|
||||
:class="['processing-indicator-floating', processingIndicatorMinimized ? 'minimized' : '']">
|
||||
<template v-if="!processingIndicatorMinimized">
|
||||
<div class="processing-indicator-content">
|
||||
<i class="fas fa-spinner fa-spin text-[var(--text-accent)]"></i>
|
||||
<span class="text-sm text-[var(--text-secondary)]" v-text="t('help.processingTranscription')"></span>
|
||||
</div>
|
||||
<button @click="processingIndicatorMinimized = true"
|
||||
class="processing-indicator-minimize"
|
||||
:title="t('tooltips.minimize')">
|
||||
<i class="fas fa-chevron-up"></i>
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button @click="processingIndicatorMinimized = false"
|
||||
class="processing-indicator-expand"
|
||||
:title="t('help.processingTranscription')">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- No transcription state (only show if not processing and no transcription) -->
|
||||
<div v-if="!selectedRecording.transcription && selectedRecording.status !== 'PROCESSING'" class="text-center py-8">
|
||||
<i class="fas fa-file-text text-3xl text-[var(--text-muted)] mb-3"></i>
|
||||
<p class="text-[var(--text-muted)]" v-text="t('transcription.noTranscription')"></p>
|
||||
</div>
|
||||
|
||||
<!-- Error Display (when transcription is an error message) -->
|
||||
<div v-if="processedTranscription.isError" class="error-display-container p-2">
|
||||
<div :class="[
|
||||
'rounded-lg p-4 border',
|
||||
processedTranscription.error.type === 'size_limit' ? 'bg-amber-500/10 border-amber-500/30' :
|
||||
processedTranscription.error.type === 'timeout' ? 'bg-orange-500/10 border-orange-500/30' :
|
||||
processedTranscription.error.type === 'auth' ? 'bg-red-500/10 border-red-500/30' :
|
||||
'bg-gray-500/10 border-gray-500/30'
|
||||
]">
|
||||
<div class="flex items-start gap-3">
|
||||
<div :class="[
|
||||
'flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center',
|
||||
processedTranscription.error.type === 'size_limit' ? 'bg-amber-500/20' :
|
||||
processedTranscription.error.type === 'timeout' ? 'bg-orange-500/20' :
|
||||
processedTranscription.error.type === 'auth' ? 'bg-red-500/20' :
|
||||
'bg-gray-500/20'
|
||||
]">
|
||||
<i :class="[
|
||||
'fas',
|
||||
processedTranscription.error.icon,
|
||||
processedTranscription.error.type === 'size_limit' ? 'text-amber-500' :
|
||||
processedTranscription.error.type === 'timeout' ? 'text-orange-500' :
|
||||
processedTranscription.error.type === 'auth' ? 'text-red-500' :
|
||||
'text-gray-500'
|
||||
]"></i>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="font-semibold text-[var(--text-primary)] mb-1">
|
||||
${processedTranscription.error.title}
|
||||
</h3>
|
||||
<p class="text-sm text-[var(--text-secondary)] mb-2">
|
||||
${processedTranscription.error.message}
|
||||
</p>
|
||||
<div v-if="processedTranscription.error.guidance" class="text-xs text-[var(--text-muted)] bg-[var(--bg-tertiary)]/50 rounded p-2">
|
||||
<i class="fas fa-lightbulb text-yellow-500 mr-1"></i>
|
||||
${processedTranscription.error.guidance}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 pt-3 border-t border-[var(--border-secondary)]">
|
||||
<button @click="reprocessTranscription(selectedRecording.id)"
|
||||
v-if="selectedRecording.can_edit !== false"
|
||||
class="w-full px-3 py-2 bg-[var(--bg-accent)] hover:bg-[var(--bg-accent-hover)] text-white rounded-lg transition-colors text-sm">
|
||||
<i class="fas fa-redo-alt mr-2"></i>Reprocess
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transcription content (show regardless of processing state if transcription exists) -->
|
||||
<div v-if="selectedRecording.transcription && !processedTranscription.isError">
|
||||
<div v-if="!processedTranscription.hasDialogue || transcriptionViewMode === 'simple'" class="transcription-simple-view">
|
||||
<div v-if="processedTranscription.hasDialogue">
|
||||
<div v-for="(segment, index) in processedTranscription.simpleSegments" :key="`seg-${index}-${segment.startTime}`" :class="['speaker-segment', { 'active-playing-segment': currentPlayingSegmentIndex === index }]" @click="seekAudioFromEvent" :data-start-time="segment.startTime" :data-segment-index="index">
|
||||
<div v-if="segment.showSpeaker" :class="['speaker-tablet', segment.color]">${segment.speaker}</div>
|
||||
<div class="speaker-text">${segment.sentence}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-if="processedTranscription.simpleSegments && processedTranscription.simpleSegments.length > 0">
|
||||
<div v-for="(segment, index) in processedTranscription.simpleSegments" :key="`seg-${index}-${segment.startTime}`" :class="['transcript-segment cursor-pointer hover:bg-[var(--bg-accent-hover)] p-2 rounded transition-colors', { 'active-playing-segment': currentPlayingSegmentIndex === index }]" @click="seekAudioFromEvent" :data-start-time="segment.startTime" :data-segment-index="index">${segment.sentence}</div>
|
||||
</div>
|
||||
<div v-else class="whitespace-pre-wrap">${processedTranscription.content}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="transcriptionViewMode === 'bubble'" class="transcription-with-speakers">
|
||||
<template v-for="(row, rowIndex) in processedTranscription.bubbleRows" :key="`${selectedRecording.id}-bubble-row-${rowIndex}`">
|
||||
<div :class="['bubble-row', row.isMe ? 'speaker-me' : '']">
|
||||
<div v-for="(bubble, bubbleIndex) in row.bubbles" :key="`bubble-${rowIndex}-${bubbleIndex}-${bubble.startTime}`" :class="['speaker-bubble', bubble.color, row.isMe ? 'speaker-me' : '', { 'active-playing-segment': currentPlayingSegmentIndex === getBubbleGlobalIndex(rowIndex, bubbleIndex) }]" @click="seekAudioFromEvent" :data-start-time="bubble.startTime" :data-segment-index="getBubbleGlobalIndex(rowIndex, bubbleIndex)">
|
||||
<div class="speaker-bubble-content">${bubble.sentence}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user