Includes: - Extended caption styling (font, shadow, dimmed color, bg toggle) - Media server, subtitle downloader, VTT parser, processing modal - Waveform tiers, thumbnail/timeline improvements, transport controls - Hybrid download model, dependency management, clip export enhancements - 21 chat summaries, 2 implementation plans, 2 design specs Co-authored-by: Cursor <cursoragent@cursor.com>
184 lines
4.0 KiB
Svelte
184 lines
4.0 KiB
Svelte
<script lang="ts">
|
|
import { session, type ProcessingStep } from '$lib/stores/videoSession.svelte';
|
|
|
|
const STEP_LABELS: Record<ProcessingStep, string> = {
|
|
idle: '',
|
|
downloading: 'Downloading preview…',
|
|
waveform: 'Generating waveform…',
|
|
keyframes: 'Extracting keyframes…',
|
|
thumbnails: 'Generating thumbnails…',
|
|
captions: 'Downloading captions…',
|
|
done: 'Ready!',
|
|
};
|
|
|
|
const STEP_ORDER: ProcessingStep[] = [
|
|
'downloading',
|
|
'waveform',
|
|
'keyframes',
|
|
'thumbnails',
|
|
'captions',
|
|
'done',
|
|
];
|
|
|
|
let currentStepIndex = $derived(STEP_ORDER.indexOf(session.processingStep));
|
|
|
|
// Pick progress source based on current step
|
|
let stepProgress = $derived(() => {
|
|
switch (session.processingStep) {
|
|
case 'downloading':
|
|
return session.previewProgress;
|
|
case 'waveform':
|
|
case 'keyframes':
|
|
case 'thumbnails':
|
|
case 'captions':
|
|
return session.processingProgress;
|
|
case 'done':
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
let progressPercent = $derived(Math.round(stepProgress() * 100));
|
|
let showProgressBar = $derived(
|
|
session.processingStep !== 'idle' && session.processingStep !== 'done'
|
|
);
|
|
</script>
|
|
|
|
<div class="modal-overlay">
|
|
<div class="modal">
|
|
<h2>Processing Video</h2>
|
|
<p class="title">{session.title}</p>
|
|
|
|
<div class="steps">
|
|
{#each STEP_ORDER as step, i}
|
|
{@const stepLabel = STEP_LABELS[step]}
|
|
{@const isDone = i < currentStepIndex}
|
|
{@const isCurrent = step === session.processingStep}
|
|
<div class="step" class:done={isDone} class:current={isCurrent}>
|
|
<span class="icon">
|
|
{#if isDone}
|
|
✓
|
|
{:else if isCurrent}
|
|
⏳
|
|
{:else}
|
|
○
|
|
{/if}
|
|
</span>
|
|
<span class="label">{stepLabel}</span>
|
|
{#if isCurrent && progressPercent > 0}
|
|
<span class="step-pct">{progressPercent}%</span>
|
|
{/if}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
|
|
{#if showProgressBar}
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: {progressPercent}%"></div>
|
|
</div>
|
|
<p class="progress-text">{progressPercent}%</p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.modal-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.modal {
|
|
background: var(--bg-primary, #1e1e2e);
|
|
border: 1px solid var(--border, #353550);
|
|
border-radius: 12px;
|
|
padding: 32px 40px;
|
|
min-width: 360px;
|
|
max-width: 480px;
|
|
text-align: center;
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
h2 {
|
|
margin: 0 0 4px;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: var(--text-primary, #cdd6f4);
|
|
}
|
|
|
|
.title {
|
|
margin: 0 0 24px;
|
|
font-size: 13px;
|
|
color: var(--text-secondary, #6c7086);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.steps {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
text-align: left;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.step {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
font-size: 13px;
|
|
color: var(--text-secondary, #6c7086);
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.step.done {
|
|
color: #a6e3a1;
|
|
}
|
|
|
|
.step.current {
|
|
color: var(--text-primary, #cdd6f4);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.icon {
|
|
width: 18px;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.step-pct {
|
|
margin-left: auto;
|
|
font-size: 12px;
|
|
color: var(--text-secondary, #6c7086);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 6px;
|
|
background: var(--bg-tertiary, #2a2a3e);
|
|
border-radius: 3px;
|
|
overflow: hidden;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: #89b4fa;
|
|
border-radius: 3px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.progress-text {
|
|
margin: 0;
|
|
font-size: 12px;
|
|
color: var(--text-secondary, #6c7086);
|
|
}
|
|
</style>
|