From 059fd1a50d218e99cfc29d83fb181882dfe1db5a Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 16 Feb 2025 01:48:38 -0800 Subject: [PATCH] Show status of importing opml --- static/css/components/topbar.css | 81 ++++++++++++++++++++++++++++++-- static/js/app.js | 38 +++++++++++---- templates/index.html.tera | 12 +++-- 3 files changed, 117 insertions(+), 14 deletions(-) diff --git a/static/css/components/topbar.css b/static/css/components/topbar.css index e7c63b3..deded8a 100644 --- a/static/css/components/topbar.css +++ b/static/css/components/topbar.css @@ -3,19 +3,76 @@ background-color: var(--topbar-bg); color: white; padding: 0.5rem 1rem; - display: flex; - justify-content: space-between; + display: grid; + grid-template-columns: auto 1fr auto; align-items: center; + gap: 1rem; margin-bottom: 1rem; } +.left-controls { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.hamburger-menu { + display: none; + background: none; + border: none; + color: var(--text-color); + font-size: 1.2rem; + cursor: pointer; + padding: 0.5rem; +} + +.add-feed-button { + background: none; + border: none; + color: var(--text-color); + font-size: 1.2rem; + cursor: pointer; + padding: 0.5rem; + display: flex; + align-items: center; +} + +.job-status { + display: flex; + align-items: center; + gap: 0.5rem; + color: var(--text-color); + font-size: 0.9rem; +} + +.job-status i { + color: var(--primary-red); +} + +.job-status.completed i { + animation: none; + color: #28a745; +} + +.job-status-text { + white-space: nowrap; +} + +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +.job-status.fade-out { + animation: fadeOut 0.5s ease-out forwards; +} + .top-bar-title { font-size: 1.5rem; margin: 0; color: var(--primary-red); font-weight: 500; text-align: center; - grid-column: 2; } .feed-title-separator { @@ -23,6 +80,24 @@ margin: 0 0.5rem; } +@media (max-width: 768px) { + .hamburger-menu { + display: block; + } + + .job-status { + display: none !important; + } + + .top-bar { + padding: 0.5rem; + } + + .top-bar-title { + font-size: 1.2rem; + } +} + /* User menu styles */ .user-menu { position: relative; diff --git a/static/js/app.js b/static/js/app.js index 6bb97e1..68354e6 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -87,25 +87,47 @@ document.addEventListener('DOMContentLoaded', function() { if (response.ok) { const result = await response.json(); if (result.success) { - showStatusModal(result.message, false); + showJobStatus("Validating OPML file..."); if (result.job_id) { pollJobStatus(result.job_id); } } else { - showStatusModal('OPML import failed: ' + result.message, true); + showError('OPML import failed: ' + result.message); } } else { - showStatusModal('Failed to import OPML file. Please try again.', true); + showError('Failed to import OPML file. Please try again.'); } } catch (error) { console.error('OPML import failed:', error); - showStatusModal('Failed to import OPML file. Please try again.', true); + showError('Failed to import OPML file. Please try again.'); } } // Clear the input so the same file can be selected again e.target.value = ''; }); + function showJobStatus(message, isCompleted = false) { + const jobStatus = document.getElementById('jobStatus'); + const jobStatusText = jobStatus.querySelector('.job-status-text'); + + jobStatus.style.display = 'flex'; + jobStatusText.textContent = message; + + if (isCompleted) { + jobStatus.classList.add('completed'); + // Hide after 5 seconds + setTimeout(() => { + jobStatus.classList.add('fade-out'); + setTimeout(() => { + jobStatus.style.display = 'none'; + jobStatus.classList.remove('completed', 'fade-out'); + }, 500); + }, 5000); + } else { + jobStatus.classList.remove('completed'); + } + } + async function pollJobStatus(jobId) { const maxAttempts = 30; // 30 attempts * 2 second delay = 1 minute maximum let attempts = 0; @@ -116,15 +138,15 @@ document.addEventListener('DOMContentLoaded', function() { if (response.ok) { const status = await response.json(); if (status.status === 'completed') { - showStatusModal(`Import completed. Successfully imported ${status.completed} feeds.`, false); + showJobStatus(`Import completed. Successfully imported ${status.completed} feeds.`, true); handleFeeds(); return; } else if (status.status === 'in_progress') { - showStatusModal(`Importing feeds... ${status.completed}/${status.total} completed`, false); + showJobStatus(`Importing feeds... ${status.completed}/${status.total} completed`); if (attempts++ < maxAttempts) { setTimeout(poll, 2000); // Poll every 2 seconds } else { - showStatusModal('Import taking longer than expected. Check feeds list in a few minutes.', false); + showJobStatus('Import taking longer than expected. Check feeds list in a few minutes.', true); setTimeout(handleFeeds, 5000); } } @@ -133,7 +155,7 @@ document.addEventListener('DOMContentLoaded', function() { } } catch (error) { console.error('Failed to poll job status:', error); - showStatusModal('Failed to check import status. Please refresh the page.', true); + showError('Failed to check import status. Please refresh the page.'); } }; diff --git a/templates/index.html.tera b/templates/index.html.tera index 17e91c8..d5916cb 100644 --- a/templates/index.html.tera +++ b/templates/index.html.tera @@ -66,9 +66,15 @@ - +
+ + +

RSS Reader