From 9b3c28114d1161a7d75f4de9d3874d759d3a9e2d Mon Sep 17 00:00:00 2001 From: xpltd Date: Wed, 18 Mar 2026 23:01:36 -0500 Subject: [PATCH] =?UTF-8?q?M002/S04:=20UX=20review=20fixes=20=E2=80=94=20r?= =?UTF-8?q?ound=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move Video/Audio toggle to same row as Download button - Auto-condense toggle to icon-only below 540px - Move gear icon to right of Download button - Fix file download URLs: normalize filenames to relative paths in progress hook - Display filename with visible extension (truncate middle, preserve ext) - Remove border/box from dark mode toggle — glyph only - Fix light/dark theme fonts: use monospace display font across all themes --- backend/app/services/download.py | 12 ++ frontend/src/components/DarkModeToggle.vue | 6 +- frontend/src/components/DownloadTable.vue | 20 ++- frontend/src/components/UrlInput.vue | 143 +++++++++++---------- frontend/src/themes/dark.css | 2 +- frontend/src/themes/light.css | 2 +- 6 files changed, 109 insertions(+), 76 deletions(-) diff --git a/backend/app/services/download.py b/backend/app/services/download.py index 7c4b37e..f30ec23 100644 --- a/backend/app/services/download.py +++ b/backend/app/services/download.py @@ -203,6 +203,18 @@ class DownloadService: try: event = ProgressEvent.from_yt_dlp(job_id, d) + # Normalize filename to be relative to the output directory + # so the frontend can construct download URLs correctly. + if event.filename: + from pathlib import PurePosixPath, Path + abs_path = Path(event.filename).resolve() + out_dir = Path(self._config.downloads.output_dir).resolve() + try: + event.filename = str(abs_path.relative_to(out_dir)) + except ValueError: + # Not under output_dir — use basename as fallback + event.filename = abs_path.name + # Always publish to SSE broker (cheap, in-memory) self._broker.publish(session_id, event) diff --git a/frontend/src/components/DarkModeToggle.vue b/frontend/src/components/DarkModeToggle.vue index 42cdd2d..aaae9c9 100644 --- a/frontend/src/components/DarkModeToggle.vue +++ b/frontend/src/components/DarkModeToggle.vue @@ -39,16 +39,14 @@ const theme = useThemeStore() height: 40px; background: transparent; color: var(--color-text-muted); - border: 1px solid var(--color-border); + border: none; border-radius: var(--radius-sm); cursor: pointer; - transition: all var(--transition-normal); + transition: color var(--transition-normal); padding: 0; } .dark-mode-toggle:hover { color: var(--color-accent); - border-color: var(--color-accent); - background: color-mix(in srgb, var(--color-accent) 8%, transparent); } diff --git a/frontend/src/components/DownloadTable.vue b/frontend/src/components/DownloadTable.vue index f81cb63..b2af378 100644 --- a/frontend/src/components/DownloadTable.vue +++ b/frontend/src/components/DownloadTable.vue @@ -55,7 +55,17 @@ const sortedJobs = computed(() => { function displayName(job: Job): string { if (job.filename) { const parts = job.filename.replace(/\\/g, '/').split('/') - return parts[parts.length - 1] + const name = parts[parts.length - 1] + // Ensure extension is visible: if name is long, truncate the middle + if (name.length > 60) { + const ext = name.lastIndexOf('.') + if (ext > 0) { + const extension = name.slice(ext) + const base = name.slice(0, 55 - extension.length) + return `${base}…${extension}` + } + } + return name } try { const u = new URL(job.url) @@ -92,11 +102,13 @@ function isCompleted(job: Job): boolean { return job.status === 'completed' } -// File download URL +// File download URL — filename is relative to the output directory +// (normalized by the backend). May contain subdirectories for source templates. function downloadUrl(job: Job): string { if (!job.filename) return '#' - const name = job.filename.replace(/\\/g, '/').split('/').pop() || '' - return `/api/downloads/${encodeURIComponent(name)}` + const normalized = job.filename.replace(/\\/g, '/') + // Encode each path segment separately to preserve directory structure + return `/api/downloads/${normalized.split('/').map(encodeURIComponent).join('/')}` } // Copy download link to clipboard diff --git a/frontend/src/components/UrlInput.vue b/frontend/src/components/UrlInput.vue index b211346..980549f 100644 --- a/frontend/src/components/UrlInput.vue +++ b/frontend/src/components/UrlInput.vue @@ -84,16 +84,40 @@ function toggleOptions(): void {