update queue

This commit is contained in:
phamhungd 2025-11-25 13:22:15 +07:00
parent 41d14dcd24
commit b95950978f
4 changed files with 208 additions and 22 deletions

View file

@ -231,7 +231,6 @@ export function createTemplateGallery({ container, onSelectTemplate }) {
const deleteBtn = document.createElement('button'); const deleteBtn = document.createElement('button');
deleteBtn.className = 'template-edit-btn'; // Reuse same style deleteBtn.className = 'template-edit-btn'; // Reuse same style
deleteBtn.style.marginLeft = '4px';
deleteBtn.innerHTML = ` deleteBtn.innerHTML = `
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 6H5H21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M3 6H5H21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>

View file

@ -195,31 +195,43 @@ document.addEventListener('DOMContentLoaded', () => {
aspectRatioInput.addEventListener('change', persistSettings); aspectRatioInput.addEventListener('change', persistSettings);
resolutionInput.addEventListener('change', persistSettings); resolutionInput.addEventListener('change', persistSettings);
generateBtn.addEventListener('click', async () => { const queueCounter = document.getElementById('queue-counter');
const prompt = promptInput.value.trim(); const queueCountText = document.getElementById('queue-count-text');
const aspectRatio = aspectRatioInput.value;
const resolution = resolutionInput.value;
const apiKey = apiKeyInput.value.trim();
if (!apiKey) { let generationQueue = [];
openApiSettings(); let isProcessingQueue = false;
function updateQueueCounter() {
// Count includes current processing item + items in queue
const count = generationQueue.length + (isProcessingQueue ? 1 : 0);
if (count > 0) {
queueCounter.classList.remove('hidden');
queueCountText.textContent = count;
} else {
queueCounter.classList.add('hidden');
}
}
async function processNextInQueue() {
if (generationQueue.length === 0) {
isProcessingQueue = false;
updateQueueCounter();
return; return;
} }
if (!prompt) { // Take task from queue FIRST, then update state
showError('Please enter a prompt.'); const task = generationQueue.shift();
return; isProcessingQueue = true;
} updateQueueCounter();
setViewState('loading');
generateBtn.disabled = true;
try { try {
setViewState('loading');
const formData = buildGenerateFormData({ const formData = buildGenerateFormData({
prompt, prompt: task.prompt,
aspect_ratio: aspectRatio, aspect_ratio: task.aspectRatio,
resolution, resolution: task.resolution,
api_key: apiKey, api_key: task.apiKey,
}); });
const response = await fetch('/generate', { const response = await fetch('/generate', {
@ -241,9 +253,46 @@ document.addEventListener('DOMContentLoaded', () => {
} }
} catch (error) { } catch (error) {
showError(error.message); showError(error.message);
// Wait a bit before next task if error
await new Promise(resolve => setTimeout(resolve, 2000));
} finally { } finally {
generateBtn.disabled = false; // Process next task
processNextInQueue();
} }
}
function addToQueue() {
const prompt = promptInput.value.trim();
const aspectRatio = aspectRatioInput.value;
const resolution = resolutionInput.value;
const apiKey = apiKeyInput.value.trim();
if (!apiKey) {
openApiSettings();
return;
}
if (!prompt) {
showError('Please enter a prompt.');
return;
}
generationQueue.push({
prompt,
aspectRatio,
resolution,
apiKey
});
updateQueueCounter();
if (!isProcessingQueue) {
processNextInQueue();
}
}
generateBtn.addEventListener('click', () => {
addToQueue();
}); });
document.addEventListener('keydown', handleGenerateShortcut); document.addEventListener('keydown', handleGenerateShortcut);
@ -251,6 +300,32 @@ document.addEventListener('DOMContentLoaded', () => {
document.addEventListener('keydown', handleDownloadShortcut); document.addEventListener('keydown', handleDownloadShortcut);
document.addEventListener('keydown', handleTemplateShortcut); document.addEventListener('keydown', handleTemplateShortcut);
// Fix for download issue: use fetch/blob to force download
if (downloadLink) {
downloadLink.addEventListener('click', async (event) => {
event.preventDefault();
const url = downloadLink.href;
const filename = downloadLink.getAttribute('download') || 'image.png';
try {
const response = await fetch(url);
const blob = await response.blob();
const blobUrl = window.URL.createObjectURL(blob);
const tempLink = document.createElement('a');
tempLink.href = blobUrl;
tempLink.download = filename;
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
window.URL.revokeObjectURL(blobUrl);
} catch (error) {
console.error('Download failed:', error);
window.open(url, '_blank');
}
});
}
if (imageDisplayArea) { if (imageDisplayArea) {
imageDisplayArea.addEventListener('wheel', handleCanvasWheel, { passive: false }); imageDisplayArea.addEventListener('wheel', handleCanvasWheel, { passive: false });
imageDisplayArea.addEventListener('pointerdown', handleCanvasPointerDown); imageDisplayArea.addEventListener('pointerdown', handleCanvasPointerDown);

View file

@ -1182,7 +1182,7 @@ button#generate-btn:disabled {
top: 0.5rem; top: 0.5rem;
right: 0.5rem; right: 0.5rem;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
gap: 0.35rem; gap: 0.35rem;
z-index: 5; z-index: 5;
opacity: 0; opacity: 0;
@ -1616,6 +1616,97 @@ button#generate-btn:disabled {
opacity: 0.5; opacity: 0.5;
} }
#queue-btn {
position: relative;
padding: 1rem;
background: linear-gradient(135deg, #3b82f6, #60a5fa);
color: #fff;
border: none;
border-radius: 0.75rem;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
overflow: hidden;
box-shadow: 0 10px 15px rgba(59, 130, 246, 0.25);
transition: transform 0.1s, filter 0.2s;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
#queue-btn:hover {
filter: brightness(1.1);
transform: translateY(-1px);
box-shadow: 0 15px 25px rgba(59, 130, 246, 0.35);
}
#queue-btn:active {
transform: scale(0.98);
}
#queue-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.queue-counter {
position: absolute;
top: 1.5rem;
right: 1.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
color: var(--text-primary);
font-size: 0.875rem;
font-weight: 500;
z-index: 100;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
}
.queue-counter.hidden {
opacity: 0;
transform: translateY(-10px);
pointer-events: none;
}
.queue-icon {
display: flex;
align-items: center;
color: var(--accent-color);
}
.queue-spinner {
display: flex;
align-items: center;
color: var(--accent-color);
animation: spin 1s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.controls-footer {
display: flex;
gap: 0.75rem;
}
.controls-footer button {
flex: 1;
}
.category-input-wrapper { .category-input-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -132,6 +132,27 @@
<div class="content-area"> <div class="content-area">
<main class="main-content"> <main class="main-content">
<div class="image-display-area"> <div class="image-display-area">
<div id="queue-counter" class="queue-counter hidden">
<span class="queue-spinner">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M12 2V6M12 18V22M6 12H2M22 12H18M19.07 4.93L16.24 7.76M7.76 16.24L4.93 19.07M19.07 19.07L16.24 16.24M7.76 7.76L4.93 4.93"
stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</span>
<span class="queue-icon">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M19 11H5M19 11C20.1046 11 21 11.8954 21 13V19C21 20.1046 20.1046 21 19 21H5C3.89543 21 3 20.1046 3 19V13C3 11.8954 3.89543 11 5 11M19 11V9C19 7.89543 18.1046 7 17 7M5 11V9C5 7.89543 5.89543 7 7 7M7 7V5C7 3.89543 7.89543 3 9 3H15C16.1046 3 17 3.89543 17 5V7M7 7H17"
stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" />
</svg>
</span>
<span id="queue-count-text">0</span>
</div>
<div id="placeholder-state" class="state-view"> <div id="placeholder-state" class="state-view">
<div class="icon-placeholder"></div> <div class="icon-placeholder"></div>
</div> </div>