feat: add mini progress circle to progress panel when collapsed

This commit is contained in:
Will Miao
2025-04-30 15:18:18 +08:00
parent 61f723a1f5
commit e1efff19f0
3 changed files with 169 additions and 18 deletions

View File

@@ -25,6 +25,7 @@
.progress-panel.collapsed .progress-panel-header { .progress-panel.collapsed .progress-panel-header {
border-bottom: none; border-bottom: none;
padding-bottom: calc(var(--space-2) + 12px);
} }
.progress-panel-header { .progress-panel-header {
@@ -61,6 +62,7 @@
justify-content: center; justify-content: center;
opacity: 0.6; opacity: 0.6;
transition: all 0.2s; transition: all 0.2s;
position: relative;
} }
.icon-button:hover { .icon-button:hover {
@@ -166,3 +168,48 @@
.hidden { .hidden {
display: none !important; display: none !important;
} }
/* Mini progress indicator on pause button when panel collapsed */
.mini-progress-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
pointer-events: none;
opacity: 0; /* Hide by default */
transition: opacity 0.2s ease;
}
/* Show mini progress when panel is collapsed */
.progress-panel.collapsed .mini-progress-container {
opacity: 1;
}
.mini-progress-circle {
stroke: var(--lora-accent);
fill: none;
stroke-width: 2.5;
stroke-linecap: round;
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset 0.3s ease;
}
.mini-progress-background {
stroke: var(--lora-border);
fill: none;
stroke-width: 2;
}
.progress-percent {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
font-size: 0.65em;
color: var(--text-color);
opacity: 0.8;
white-space: nowrap;
}

View File

@@ -9,6 +9,8 @@ class ExampleImagesManager {
this.progressUpdateInterval = null; this.progressUpdateInterval = null;
this.startTime = null; this.startTime = null;
this.progressPanel = null; this.progressPanel = null;
this.isProgressPanelCollapsed = false;
this.pauseButton = null; // Store reference to the pause button
// Initialize download path field and check download status // Initialize download path field and check download status
this.initializePathOptions(); this.initializePathOptions();
@@ -23,12 +25,22 @@ class ExampleImagesManager {
// Initialize progress panel reference // Initialize progress panel reference
this.progressPanel = document.getElementById('exampleImagesProgress'); this.progressPanel = document.getElementById('exampleImagesProgress');
// Load collapse state from storage
this.isProgressPanelCollapsed = getStorageItem('progress_panel_collapsed', false);
if (this.progressPanel && this.isProgressPanelCollapsed) {
this.progressPanel.classList.add('collapsed');
const icon = document.querySelector('#collapseProgressBtn i');
if (icon) {
icon.className = 'fas fa-chevron-up';
}
}
// Initialize progress panel button handlers // Initialize progress panel button handlers
const pauseBtn = document.getElementById('pauseExampleDownloadBtn'); this.pauseButton = document.getElementById('pauseExampleDownloadBtn');
const collapseBtn = document.getElementById('collapseProgressBtn'); const collapseBtn = document.getElementById('collapseProgressBtn');
if (pauseBtn) { if (this.pauseButton) {
pauseBtn.onclick = () => this.pauseDownload(); this.pauseButton.onclick = () => this.pauseDownload();
} }
if (collapseBtn) { if (collapseBtn) {
@@ -245,8 +257,16 @@ class ExampleImagesManager {
if (data.success) { if (data.success) {
this.isPaused = true; this.isPaused = true;
document.getElementById('downloadStatusText').textContent = 'Paused'; document.getElementById('downloadStatusText').textContent = 'Paused';
document.getElementById('pauseExampleDownloadBtn').innerHTML = '<i class="fas fa-play"></i>';
document.getElementById('pauseExampleDownloadBtn').onclick = () => this.resumeDownload(); // Only update the icon element, not the entire innerHTML
if (this.pauseButton) {
const iconElement = this.pauseButton.querySelector('i');
if (iconElement) {
iconElement.className = 'fas fa-play';
}
this.pauseButton.onclick = () => this.resumeDownload();
}
this.updateDownloadButtonText(); this.updateDownloadButtonText();
showToast('Download paused', 'info'); showToast('Download paused', 'info');
} else { } else {
@@ -273,8 +293,16 @@ class ExampleImagesManager {
if (data.success) { if (data.success) {
this.isPaused = false; this.isPaused = false;
document.getElementById('downloadStatusText').textContent = 'Downloading'; document.getElementById('downloadStatusText').textContent = 'Downloading';
document.getElementById('pauseExampleDownloadBtn').innerHTML = '<i class="fas fa-pause"></i>';
document.getElementById('pauseExampleDownloadBtn').onclick = () => this.pauseDownload(); // Only update the icon element, not the entire innerHTML
if (this.pauseButton) {
const iconElement = this.pauseButton.querySelector('i');
if (iconElement) {
iconElement.className = 'fas fa-pause';
}
this.pauseButton.onclick = () => this.pauseDownload();
}
this.updateDownloadButtonText(); this.updateDownloadButtonText();
showToast('Download resumed', 'success'); showToast('Download resumed', 'success');
} else { } else {
@@ -357,6 +385,9 @@ class ExampleImagesManager {
if (progressBar) { if (progressBar) {
const progressPercent = status.total > 0 ? (status.completed / status.total) * 100 : 0; const progressPercent = status.total > 0 ? (status.completed / status.total) * 100 : 0;
progressBar.style.width = `${progressPercent}%`; progressBar.style.width = `${progressPercent}%`;
// Update mini progress circle
this.updateMiniProgress(progressPercent);
} }
// Update current model // Update current model
@@ -372,21 +403,76 @@ class ExampleImagesManager {
this.updateErrors(status); this.updateErrors(status);
// Update pause/resume button // Update pause/resume button
const pauseBtn = document.getElementById('pauseExampleDownloadBtn'); if (!this.pauseButton) {
const resumeBtn = document.getElementById('resumeExampleDownloadBtn'); this.pauseButton = document.getElementById('pauseExampleDownloadBtn');
}
if (pauseBtn) { if (this.pauseButton) {
if (status.status === 'paused') { // Check if the button already has the SVG elements
pauseBtn.innerHTML = '<i class="fas fa-play"></i>'; let hasProgressElements = !!this.pauseButton.querySelector('.mini-progress-circle');
pauseBtn.onclick = () => this.resumeDownload();
if (!hasProgressElements) {
// If elements don't exist, add them
this.pauseButton.innerHTML = `
<i class="${status.status === 'paused' ? 'fas fa-play' : 'fas fa-pause'}"></i>
<svg class="mini-progress-container" width="24" height="24" viewBox="0 0 24 24">
<circle class="mini-progress-background" cx="12" cy="12" r="10"></circle>
<circle class="mini-progress-circle" cx="12" cy="12" r="10" stroke-dasharray="62.8" stroke-dashoffset="62.8"></circle>
</svg>
<span class="progress-percent"></span>
`;
} else { } else {
pauseBtn.innerHTML = '<i class="fas fa-pause"></i>'; // If elements exist, just update the icon
pauseBtn.onclick = () => this.pauseDownload(); const iconElement = this.pauseButton.querySelector('i');
if (iconElement) {
iconElement.className = status.status === 'paused' ? 'fas fa-play' : 'fas fa-pause';
}
}
// Update click handler
this.pauseButton.onclick = status.status === 'paused'
? () => this.resumeDownload()
: () => this.pauseDownload();
// Update progress immediately
const progressBar = document.getElementById('downloadProgressBar');
if (progressBar) {
const progressPercent = status.total > 0 ? (status.completed / status.total) * 100 : 0;
this.updateMiniProgress(progressPercent);
}
}
}
// Update the mini progress circle in the pause button
updateMiniProgress(percent) {
// Ensure we have the pause button reference
if (!this.pauseButton) {
this.pauseButton = document.getElementById('pauseExampleDownloadBtn');
if (!this.pauseButton) {
console.error('Pause button not found');
return;
} }
} }
if (resumeBtn) { // Query elements within the context of the pause button
resumeBtn.style.display = status.status === 'paused' ? 'block' : 'none'; const miniProgressCircle = this.pauseButton.querySelector('.mini-progress-circle');
const percentText = this.pauseButton.querySelector('.progress-percent');
if (miniProgressCircle && percentText) {
// Circle circumference = 2πr = 2 * π * 10 = 62.8
const circumference = 62.8;
const offset = circumference - (percent / 100) * circumference;
miniProgressCircle.style.strokeDashoffset = offset;
percentText.textContent = `${Math.round(percent)}%`;
// Only show percent text when panel is collapsed
percentText.style.display = this.isProgressPanelCollapsed ? 'block' : 'none';
} else {
console.warn('Mini progress elements not found within pause button',
this.pauseButton,
'mini-progress-circle:', !!miniProgressCircle,
'progress-percent:', !!percentText);
} }
} }
@@ -485,17 +571,30 @@ class ExampleImagesManager {
if (!this.progressPanel) return; if (!this.progressPanel) return;
} }
this.isProgressPanelCollapsed = !this.isProgressPanelCollapsed;
this.progressPanel.classList.toggle('collapsed'); this.progressPanel.classList.toggle('collapsed');
// Save collapsed state to storage
setStorageItem('progress_panel_collapsed', this.isProgressPanelCollapsed);
// Update icon // Update icon
const icon = document.querySelector('#collapseProgressBtn i'); const icon = document.querySelector('#collapseProgressBtn i');
if (icon) { if (icon) {
if (this.progressPanel.classList.contains('collapsed')) { if (this.isProgressPanelCollapsed) {
icon.className = 'fas fa-chevron-up'; icon.className = 'fas fa-chevron-up';
} else { } else {
icon.className = 'fas fa-chevron-down'; icon.className = 'fas fa-chevron-down';
} }
} }
// Force update mini progress if panel is collapsed
if (this.isProgressPanelCollapsed) {
const progressBar = document.getElementById('downloadProgressBar');
if (progressBar) {
const progressPercent = parseFloat(progressBar.style.width) || 0;
this.updateMiniProgress(progressPercent);
}
}
} }
} }

View File

@@ -7,6 +7,11 @@
<div class="progress-panel-actions"> <div class="progress-panel-actions">
<button id="pauseExampleDownloadBtn" class="icon-button"> <button id="pauseExampleDownloadBtn" class="icon-button">
<i class="fas fa-pause"></i> <i class="fas fa-pause"></i>
<svg class="mini-progress-container" width="24" height="24" viewBox="0 0 24 24">
<circle class="mini-progress-background" cx="12" cy="12" r="10"></circle>
<circle class="mini-progress-circle" cx="12" cy="12" r="10" stroke-dasharray="62.8" stroke-dashoffset="62.8"></circle>
</svg>
<span class="progress-percent"></span>
</button> </button>
<button id="collapseProgressBtn" class="icon-button"> <button id="collapseProgressBtn" class="icon-button">
<i class="fas fa-chevron-down"></i> <i class="fas fa-chevron-down"></i>