Files
gui-video-clipper/src/lib/components/StatusBar.svelte

176 lines
4.5 KiB
Svelte

<script lang="ts">
import { getVersion } from '@tauri-apps/api/app';
import { session, upgradePreview, reprocessCurrentVideo } from '$lib/stores/videoSession.svelte';
let { onOpenAbout }: { onOpenAbout?: () => void } = $props();
let appVersion = $state('');
$effect(() => {
getVersion().then((v) => {
appVersion = v;
});
});
let previewPercent = $derived(Math.round(session.previewProgress * 100));
let exportPercent = $derived(Math.round(session.exportProgress * 100));
let isPreviewDownloading = $derived(
session.status === 'ready' &&
session.previewStatus === 'downloading' &&
session.previewProgress > 0 &&
session.previewProgress < 1
);
let isPreviewComplete = $derived(session.previewStatus === 'complete');
let isExportDownloading = $derived(session.exportStatus === 'downloading');
let isExportComplete = $derived(session.exportStatus === 'complete');
let canReprocess = $derived(
session.status === 'ready' &&
session.processingStep === 'done' &&
session.activeVideoPath !== null
);
let reprocessing = $state(false);
async function handleReprocess() {
reprocessing = true;
try {
await reprocessCurrentVideo();
} finally {
reprocessing = false;
}
}
</script>
<div class="status-bar">
{#if isPreviewDownloading}
<div class="progress-bar">
<div class="progress-fill" style="width: {previewPercent}%"></div>
</div>
<span class="status-text">Preview: {previewPercent}%</span>
{:else if isPreviewComplete && isExportDownloading}
<span class="status-text success">✓ Preview ready</span>
<div class="progress-bar">
<div class="progress-fill" style="width: {exportPercent}%"></div>
</div>
<span class="status-text">Best quality: {exportPercent}%</span>
{:else if isPreviewComplete && isExportComplete}
<span class="status-text success">✓ {session.title} — ready to export</span>
{#if session.showUpgradeToast}
<button class="upgrade-link" onclick={upgradePreview}>Reload Preview (HQ)</button>
{/if}
{:else if session.status === 'resolving'}
<span class="status-text">Resolving URL…</span>
{:else if session.status === 'ready' && session.previewStatus === 'idle'}
<span class="status-text">Preparing download…</span>
{:else if session.previewStatus === 'failed' || session.exportStatus === 'failed'}
<span class="status-text">Download failed</span>
{:else}
<span class="status-text">Ready</span>
{/if}
{#if canReprocess && !isPreviewDownloading}
<button
class="reprocess-btn"
onclick={handleReprocess}
disabled={reprocessing}
title="Reprocess video (re-extract waveform, thumbnails, keyframes)"
>
{reprocessing ? '⏳' : '↻'}
</button>
{/if}
{#if appVersion}
<button class="version-btn" onclick={() => onOpenAbout?.()} title="About GUI Video Clipper">
v{appVersion}
</button>
{/if}
</div>
<style>
.status-bar {
display: flex;
align-items: center;
padding: 4px 12px;
background: var(--bg-tertiary);
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--text-secondary);
min-height: 24px;
gap: 8px;
}
.progress-bar {
flex: 1;
height: 4px;
background: var(--bg-primary);
border-radius: 2px;
overflow: hidden;
max-width: 200px;
}
.progress-fill {
height: 100%;
background: var(--accent);
transition: width 0.3s ease;
}
.success {
color: var(--success);
}
.upgrade-link {
background: none;
border: 1px solid var(--accent, #89b4fa);
color: var(--accent, #89b4fa);
font-size: 11px;
padding: 2px 8px;
border-radius: 3px;
cursor: pointer;
white-space: nowrap;
}
.upgrade-link:hover {
background: var(--accent, #89b4fa);
color: var(--bg-primary, #1e1e2e);
}
.reprocess-btn {
background: none;
border: 1px solid var(--border);
color: var(--text-secondary);
font-size: 14px;
padding: 2px 6px;
border-radius: 3px;
cursor: pointer;
line-height: 1;
}
.reprocess-btn:hover {
background: var(--bg-secondary);
color: var(--text-primary);
}
.reprocess-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.version-btn {
margin-left: auto;
background: none;
border: none;
color: var(--text-muted);
font-size: 11px;
font-family: var(--font-mono);
padding: 2px 6px;
cursor: pointer;
border-radius: 3px;
}
.version-btn:hover {
background: var(--bg-secondary);
color: var(--text-secondary);
}
</style>