The GENERATE NEW button was only sending sampler/scheduler/steps/cfg/
denoise/lora — missing model, seed, prompts, and all advanced settings.
The generated image would use whatever the sampler node had as defaults
instead of the actual parameters from the source image.
Fixed triggerGen() to build a complete config entry:
- Model and seed from the (now editable) modal fields
- Positive and negative prompts from the modal textareas
- seed_behavior set to "fixed" so the exact seed is used
- All advanced settings carried from the source item: vae, clip_type,
model_type, text_encoders, attention_mode, clip_skip,
model_sampling_override + shift values, advanced_sampling,
flux_guidance, gguf_options
Also wraps output in {"configs": [...]} format (was sending bare array).
Template changes:
- Model input: removed disabled attribute + opacity
- Seed input: removed disabled attribute + opacity
Both are now editable so users can change model or seed before re-gen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
766 lines
46 KiB
HTML
766 lines
46 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<style>
|
|
/* INJECTED CSS */
|
|
__CSS_CONTENT__
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<!-- COMPACT SINGLE-LINE HEADER -->
|
|
<div id="header">
|
|
<button class="filter-popup-btn" onclick="toggleFiltersPopup()" title="Open Filters & Info">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon>
|
|
</svg>
|
|
</button>
|
|
|
|
<div style="flex-grow: 1;"></div>
|
|
|
|
<div class="meta-box" style="overflow: visible;"> <span class="meta-label">Sort</span>
|
|
|
|
<div class="sort-container" id="sort-container">
|
|
<button class="sort-btn" id="sort-main-btn" onclick="toggleSortPopup()">
|
|
<span id="sort-primary-label">Oldest</span>
|
|
<span style="opacity:0.5; font-size:8px;">▼</span>
|
|
</button>
|
|
|
|
<div id="sort-popup" class="sort-popup-panel" style="display: none;">
|
|
<div class="sort-col">
|
|
<div class="sort-col-header" style="color:var(--accent);">PRIMARY</div>
|
|
<div id="sort-list-primary">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sort-col">
|
|
<div class="sort-col-header" style="color:var(--accent-sch);">SECONDARY</div>
|
|
<div id="sort-list-secondary">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="fs-btn" onclick="loadSession()" title="Reload Session (R)">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<polyline points="23 4 23 10 17 10"></polyline>
|
|
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<button class="fs-btn" onclick="resetZoom();" title="Center Grid (0)">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<line x1="22" y1="12" x2="18" y2="12"></line>
|
|
<line x1="6" y1="12" x2="2" y2="12"></line>
|
|
<line x1="12" y1="6" x2="12" y2="2"></line>
|
|
<line x1="12" y1="22" x2="12" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- COG WHEEL MENU -->
|
|
<div class="cog-menu-container">
|
|
<button class="action-btn" onclick="toggleCogMenu()" title="Settings">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<button class="fs-btn" onclick="toggleFullscreen()" title="Toggle Fullscreen">⛶</button>
|
|
</div>
|
|
|
|
<!-- SETTINGS PANEL (Unified Cog + Session) -->
|
|
<div id="cog-menu-dropdown" class="cog-menu-panel" style="display: none;">
|
|
<div class="cog-panel-header">
|
|
<span style="font-size: 13px; font-weight: 700; color: #fff;">Settings</span>
|
|
<button class="close-popup-btn" onclick="toggleCogMenu()">✕</button>
|
|
</div>
|
|
<div class="cog-panel-content">
|
|
|
|
<!-- Section 1: Session Management -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">SESSION</div>
|
|
<input id="session-input" class="session-name-input" type="text" value="__TITLE__"
|
|
placeholder="Session name...">
|
|
<div class="session-actions" style="margin-top: 6px;">
|
|
<button class="session-action-btn save-btn" onclick="saveState()">SAVE</button>
|
|
</div>
|
|
<div style="margin-top: 8px;">
|
|
<span class="meta-label" style="font-size: 10px;">Load Session: <span style="color:#666;">(sorted by most recent)</span></span>
|
|
<input type="text" id="session-search" placeholder="Search sessions..."
|
|
style="width: 100%; margin-top: 4px; background: #1a1a1a; color: #ccc; border: 1px solid #444; border-radius: 4px; padding: 4px 6px; font-size: 11px; box-sizing: border-box;"
|
|
oninput="filterSessionPicker(this.value)">
|
|
<div id="session-picker-list" style="max-height: 180px; overflow-y: auto; margin-top: 4px; border: 1px solid #333; border-radius: 4px; background: #1a1a1a;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 2: Grid Display -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">GRID DISPLAY</div>
|
|
<div class="cog-menu-item">
|
|
<span class="meta-label">Go To Card #: </span>
|
|
<input type="text" inputmode="numeric" id="goto-input" min="1" placeholder="#"
|
|
title="Jump to image number (press Enter)" style="width: 45px;">
|
|
</div>
|
|
<div class="cog-menu-item">
|
|
<span class="meta-label">Number Of Columns In Grid: </span>
|
|
<input type="text" inputmode="numeric" id="col-count" min="0" placeholder="Auto"
|
|
title="Set grid columns (0 = Auto)">
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 3: Label Mode -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">LABEL MODE</div>
|
|
<div style="font-size: 9px; color: #666; margin-bottom: 8px;">
|
|
Show metadata labels as overlays on card images. Unique-only filters out values shared by every card.
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 6px; margin-bottom: 8px;">
|
|
<input type="checkbox" id="label-mode-toggle"
|
|
style="width: 14px; height: 14px; cursor: pointer;"
|
|
onchange="toggleLabelMode(this.checked)">
|
|
<label for="label-mode-toggle"
|
|
style="font-size: 11px; color: #ccc; cursor: pointer; user-select: none; font-weight: bold;">
|
|
Enable Label Overlays
|
|
</label>
|
|
</div>
|
|
<div id="label-fields-container" style="display: none;">
|
|
<div style="display: flex; align-items: center; gap: 6px; margin-bottom: 8px;">
|
|
<label for="label-size-slider" style="font-size: 10px; color: #999; white-space: nowrap;">Size:</label>
|
|
<input type="range" id="label-size-slider" min="6" max="16" value="9" step="1"
|
|
style="flex: 1; height: 14px; cursor: pointer;"
|
|
oninput="updateLabelSize(this.value)">
|
|
<span id="label-size-value" style="font-size: 10px; color: #999; min-width: 20px;">9px</span>
|
|
</div>
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 4px;">
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-model" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-model" style="font-size: 10px; color: #b43cc8; cursor: pointer; user-select: none;">Model</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-lora" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-lora" style="font-size: 10px; color: #c88c28; cursor: pointer; user-select: none;">LoRA</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-prompt" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-prompt" style="font-size: 10px; color: #28a078; cursor: pointer; user-select: none;">Prompt</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-sampler" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-sampler" style="font-size: 10px; color: #3c82c8; cursor: pointer; user-select: none;">Sampler</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-scheduler" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-scheduler" style="font-size: 10px; color: #3c82c8; cursor: pointer; user-select: none;">Scheduler</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-cfg" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-cfg" style="font-size: 10px; color: #c85050; cursor: pointer; user-select: none;">CFG</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-steps" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-steps" style="font-size: 10px; color: #c85050; cursor: pointer; user-select: none;">Steps</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-seed" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-seed" style="font-size: 10px; color: #888; cursor: pointer; user-select: none;">Seed</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-denoise" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-denoise" style="font-size: 10px; color: #00b4a0; cursor: pointer; user-select: none;">Denoise</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscale" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscale" style="font-size: 10px; color: #e06090; cursor: pointer; user-select: none;">Upscale (all)</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleMode" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleMode" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Up Mode</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleModel" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleModel" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Up Model</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleRatio" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleRatio" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Up Ratio</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleDenoise" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleDenoise" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Up Denoise</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleResizeMethod" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleResizeMethod" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Resize Method</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleHiresSteps" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleHiresSteps" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">HiRes Steps</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-upscaleTiling" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-upscaleTiling" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">Tiling Info</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-hiresPromptBehavior" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-hiresPromptBehavior" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">HiRes Prompt</label>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 4px;">
|
|
<input type="checkbox" id="label-field-hiresPromptText" onchange="updateLabelFields()" style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-field-hiresPromptText" style="font-size: 10px; color: #d06080; cursor: pointer; user-select: none;">HiRes Prompt Text</label>
|
|
</div>
|
|
</div>
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="label-unique-only" checked
|
|
onchange="updateLabelFields()"
|
|
style="width: 12px; height: 12px; cursor: pointer;">
|
|
<label for="label-unique-only"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Hide values shared by every card (unique-only)
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section 4: Export Favorites -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">EXPORT FAVORITES</div>
|
|
|
|
<button class="session-action-btn"
|
|
style="background: #6366f1; width: 100%; font-size: 11px; padding: 10px; margin-bottom: 8px;"
|
|
onclick="exportFavoritesAsConfigJSON()" title="Generate a Config Builder JSON from favorited items — paste into the Builder to re-run with different settings">
|
|
📋 EXPORT FAVORITES AS CONFIG JSON
|
|
</button>
|
|
<div style="font-size: 9px; color: #666; margin-bottom: 10px;">
|
|
Copies a Config Builder JSON to clipboard with all favorited items' settings (models, LoRAs, prompts, samplers, etc.). Paste into the Config Builder's lora_config widget to re-run with different sizes/settings.
|
|
</div>
|
|
|
|
<button class="session-action-btn"
|
|
style="background: #00d1b2; width: 100%; font-size: 11px; padding: 10px;"
|
|
onclick="exportFavorites()" title="Export favorited images to benchmark_favorites folder">
|
|
COPY FAVORITES TO BENCHMARK FAVORITES FOLDER
|
|
</button>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" checked id="pack-metadata-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="pack-metadata-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Pack metadata into copied favorites (for CivitAI)
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="organize-by-prompt-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="organize-by-prompt-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Organize into separate folders by prompt (Prompt1, Prompt2, etc.)
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="organize-by-lora-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="organize-by-lora-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Organize into separate folders by lora sets (loras1, loras2, etc.)
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="export-prompt-txt-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="export-prompt-txt-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Export positive prompt as .txt file alongside each image
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" checked id="copy-manifest-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="copy-manifest-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Copy cleaned favorites-only manifest into favorites folder
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="pack-workflow-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="pack-workflow-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Pack full ComfyUI workflow into image metadata (drag into ComfyUI to load)
|
|
</label>
|
|
</div>
|
|
|
|
<div style="margin-top: 8px; display: flex; align-items: center; gap: 6px;">
|
|
<input type="checkbox" id="pack-nodes-workflow-checkbox"
|
|
style="width: 14px; height: 14px; cursor: pointer;">
|
|
<label for="pack-nodes-workflow-checkbox"
|
|
style="font-size: 10px; color: #999; cursor: pointer; user-select: none;">
|
|
Pack config data as pure nodes workflow into image metadata
|
|
</label>
|
|
</div>
|
|
|
|
<div id="export-status" style="margin-top: 8px; font-size: 10px; color: #666; min-height: 16px;"></div>
|
|
<button class="session-action-btn"
|
|
style="background: #cc2222; width: 100%; font-size: 11px; padding: 10px; margin-top: 12px; border: 2px solid #ff4444;"
|
|
onclick="deleteNonFavorites()" title="Permanently delete all non-favorited images and update manifest">
|
|
🗑️ DELETE ALL NON FAVORITED ITEMS
|
|
</button>
|
|
<div id="delete-status" style="margin-top: 4px; font-size: 10px; color: #666; min-height: 16px;"></div>
|
|
</div>
|
|
|
|
<!-- Section 5: Manifest Analytics -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">MANIFEST ANALYTICS</div>
|
|
<div style="font-size: 9px; color: #666; margin-bottom: 8px;">
|
|
Analyze favorited items in the current session manifest.
|
|
</div>
|
|
<button class="session-action-btn"
|
|
style="background: #8b5cf6; width: 100%; font-size: 11px; padding: 10px; margin-bottom: 6px;"
|
|
onclick="runManifestAnalysis('lora')" title="Count LoRA usage across favorited items">
|
|
LORA USAGE STATS
|
|
</button>
|
|
<button class="session-action-btn"
|
|
style="background: #6366f1; width: 100%; font-size: 11px; padding: 10px; margin-bottom: 6px;"
|
|
onclick="runManifestAnalysis('model')" title="Count model/checkpoint usage across favorited items">
|
|
MODEL USAGE STATS
|
|
</button>
|
|
<button class="session-action-btn"
|
|
style="background: #00d1b2; color: #000; width: 100%; font-size: 11px; padding: 10px; margin-bottom: 6px;"
|
|
onclick="runManifestAnalysis('prompt')" title="Count full prompts with favorited vs total">
|
|
FULL PROMPT STATS
|
|
</button>
|
|
<button class="session-action-btn"
|
|
style="background: #d0873e; width: 100%; font-size: 11px; padding: 10px; margin-bottom: 6px;"
|
|
onclick="runManifestAnalysis('tags')" title="Count individual prompt tags from favorited items">
|
|
PROMPT TAG STATS
|
|
</button>
|
|
<div id="analytics-status" style="margin-top: 4px; font-size: 10px; color: #666; min-height: 16px;"></div>
|
|
</div>
|
|
|
|
<!-- Section 6: Scan External Directory -->
|
|
<div class="cog-panel-section">
|
|
<div class="cog-panel-section-title">SCAN EXTERNAL DIRECTORY</div>
|
|
<div style="font-size: 9px; color: #666; margin-bottom: 8px;">
|
|
Load any folder of images into the dashboard. Reads PNG metadata for filtering/sorting.
|
|
</div>
|
|
<div style="display: flex; gap: 6px; align-items: center;">
|
|
<input type="text" id="scan-directory-input"
|
|
placeholder="Paste absolute directory path..."
|
|
style="flex: 1; background: #000; border: 1px solid #333; color: #fff;
|
|
padding: 8px; font-size: 11px; font-family: monospace; border-radius: 3px;"
|
|
onkeydown="if(event.key==='Enter')scanDirectory()">
|
|
<button class="session-action-btn" id="scan-directory-btn"
|
|
style="background: #6366f1; white-space: nowrap; padding: 8px 16px; font-size: 11px; font-weight: bold;"
|
|
onclick="scanDirectory()">
|
|
SCAN
|
|
</button>
|
|
</div>
|
|
<div id="scan-status" style="margin-top: 6px; font-size: 10px; color: #666; min-height: 16px;"></div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overlay for settings panel -->
|
|
<div id="cog-menu-overlay" class="filters-overlay" onclick="toggleCogMenu()" style="display: none;"></div>
|
|
|
|
<!-- REAL-TIME ETA BAR -->
|
|
<div id="eta-bar" style="display: none; align-items: center; gap: 10px; padding: 4px 12px; background: #1a1a2e; border-bottom: 1px solid #333; font-size: 11px; color: #aaa; position: relative;">
|
|
<span style="color: #0af; font-weight: bold;">ETA</span>
|
|
<span id="eta-text" style="flex: 1;">--</span>
|
|
<div style="position: absolute; bottom: 0; left: 0; height: 2px; width: 100%; background: #222;">
|
|
<div id="eta-progress" style="height: 100%; width: 0%; background: linear-gradient(90deg, #0af, #0f6); transition: width 0.5s ease;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div id="filters-popup" class="filters-popup" style="display: none;">
|
|
<div class="filters-popup-header">
|
|
<h3>Filters & Info</h3>
|
|
<button class="close-popup-btn" onclick="toggleFiltersPopup()">✕</button>
|
|
</div>
|
|
|
|
<div class="filters-popup-content">
|
|
<!-- TOP-LEVEL FILTERS SECTION -->
|
|
<div class="popup-section"
|
|
style="border-bottom: 2px solid #333; padding-bottom: 16px; margin-bottom: 16px;">
|
|
<div class="popup-section-title">VISIBILITY</div>
|
|
<div style="display: flex; gap: 10px; margin-top: 10px;">
|
|
<button id="top-filter-favorites" class="filter-btn top-filter-btn active"
|
|
onclick="toggleFavoritesFilter()" title="Toggle visibility of favorited images">
|
|
⭐ Favorites
|
|
</button>
|
|
<button id="top-filter-nonfavorited" class="filter-btn top-filter-btn active"
|
|
onclick="toggleNonFavoritedFilter()" title="Toggle visibility of non-favorited images">
|
|
◯ Non-Favorited
|
|
</button>
|
|
<button id="top-filter-rejected" class="filter-btn top-filter-btn" onclick="toggleRejectedFilter()"
|
|
title="Toggle visibility of rejected images">
|
|
✕ Rejected
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SEARCH FILTER SECTION -->
|
|
<div class="popup-section">
|
|
<div class="popup-section-title">SEARCH FILTER</div>
|
|
<div class="search-filter-container">
|
|
<div class="search-filter-row">
|
|
<select id="search-filter-type" class="search-filter-select">
|
|
<option value="">Select filter type...</option>
|
|
<option value="model">Model</option>
|
|
<option value="positive">Positive Prompt</option>
|
|
<option value="negative">Negative Prompt</option>
|
|
<option value="sampler">Sampler</option>
|
|
<option value="scheduler">Scheduler</option>
|
|
<option value="lora">LoRA</option>
|
|
</select>
|
|
<input type="text" id="search-filter-input" class="search-filter-input"
|
|
placeholder="Enter search term..." onkeypress="if(event.key==='Enter') addSearchFilter()">
|
|
<button class="search-filter-add-btn" onclick="addSearchFilter()">ADD</button>
|
|
</div>
|
|
<div id="active-search-filters" class="active-search-filters"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Meta Info Section -->
|
|
|
|
|
|
<!-- Filters Section -->
|
|
<div class="popup-section">
|
|
<div class="popup-section-title">FILTERS <span
|
|
style="font-size: 9px; color: #555; font-weight: normal;">(Shift+Click to isolate)</span></div>
|
|
<div style="margin: 6px 0 2px 0; padding: 4px 0;">
|
|
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: 11px; color: #aaa;">
|
|
<input type="checkbox" id="toggle-triggers" checked
|
|
style="cursor: pointer;"
|
|
onchange="if(typeof toggleTriggerWords==='function') toggleTriggerWords(this.checked)">
|
|
Show Lora Trigger Words in Prompts
|
|
</label>
|
|
</div>
|
|
<br />
|
|
<div class="filter-row">
|
|
<span class="filter-label">Model</span>
|
|
<div id="filter-model" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Positive Prompt</span>
|
|
<div id="filter-positive" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Negative Prompt</span>
|
|
<div id="filter-negative" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Sampler</span>
|
|
<div id="filter-sampler" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Scheduler</span>
|
|
<div id="filter-scheduler" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Denoise</span>
|
|
<div id="filter-denoise" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">LoRA</span>
|
|
<div id="filter-lora" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Size</span>
|
|
<div id="filter-size" class="filter-buttons-container"></div>
|
|
</div>
|
|
|
|
<div class="filter-row">
|
|
<span class="filter-label">Seed</span>
|
|
<div id="filter-seed" class="filter-buttons-container"></div>
|
|
</div>
|
|
<div class="filter-row">
|
|
<span class="filter-label">Steps</span>
|
|
<div id="filter-steps" class="filter-buttons-container"></div>
|
|
</div>
|
|
<div class="filter-row">
|
|
<span class="filter-label">CFG</span>
|
|
<div id="filter-cfg" class="filter-buttons-container"></div>
|
|
</div>
|
|
<div class="filter-row">
|
|
<span class="filter-label">Upscale</span>
|
|
<div id="filter-upscaleMethod" class="filter-buttons-container"></div>
|
|
</div>
|
|
<div class="filter-row">
|
|
<span class="filter-label">Type</span>
|
|
<div id="filter-mediaType" class="filter-buttons-container"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Keyboard Shortcuts Reference -->
|
|
<div class="popup-section">
|
|
<div class="popup-section-title">KEYBOARD SHORTCUTS</div>
|
|
<table style="width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 11px;">
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Space</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Scroll down one row</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Shift+Space</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Scroll up one row</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Arrow Keys</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Pan in any direction</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">+ / -</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Zoom in / out</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">0</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Auto-fit first row to viewport</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">F</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Toggle fullscreen</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">R</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Reload session</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">1-9</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Quick favorite Nth visible card</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Shift+0-9</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Set column count (0 = auto)</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Ctrl+S</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Save (forwarded to ComfyUI)</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Escape</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Close modal / lightbox</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid #333;">
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Double-click</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Toggle favorite on card</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 4px 8px; color: #0af; font-family: monospace;">Shift+Click</td>
|
|
<td style="padding: 4px 8px; color: #ccc;">Isolate a single filter</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overlay for popup -->
|
|
<div id="filters-overlay" class="filters-overlay" onclick="toggleFiltersPopup()" style="display: none;"></div>
|
|
|
|
|
|
<!-- Session landing page (shown when no session is loaded) -->
|
|
<div id="session-landing" style="display: none; padding: 40px 20px; text-align: center; height: 100%; overflow-y: auto; box-sizing: border-box;">
|
|
<h2 style="color: #888; font-size: 18px; margin-bottom: 8px;">Ultimate Grid Dashboard</h2>
|
|
<p style="color: #555; font-size: 12px; margin-bottom: 24px;">Select a session to view</p>
|
|
<div id="session-cards" style="display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; max-width: 900px; margin: 0 auto; padding-bottom: 40px;"></div>
|
|
</div>
|
|
|
|
<div id="viewport">
|
|
<div id="canvas">
|
|
<div class="grid" id="grid"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- MOBILE NAVIGATION BUTTONS -->
|
|
<button id="mobile-nav-up" class="mobile-nav-btn mobile-nav-up" onclick="scrollUpOneRow()" title="Scroll Up">
|
|
▲
|
|
</button>
|
|
<button id="mobile-nav-down" class="mobile-nav-btn mobile-nav-down" onclick="scrollDownOneRow()"
|
|
title="Scroll Down">
|
|
▼
|
|
</button>
|
|
|
|
<div class="json-container">
|
|
<!-- Button row -->
|
|
<div style="display: flex; gap: 0;">
|
|
<button id="json-btn-good" class="json-view-btn" onclick="viewGoodJSON()"
|
|
title="Click to view accepted configs JSON">
|
|
View Configs (0)
|
|
</button>
|
|
<button id="json-btn-favorite" class="json-view-btn" onclick="viewFavoritedJSON()"
|
|
title="Click to view favorited configs JSON">
|
|
View Favorited (0)
|
|
</button>
|
|
<button id="json-btn-bad" class="json-view-btn" onclick="viewRejectedJSON()"
|
|
title="Click to view rejected configs JSON">
|
|
View Rejected (0)
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Hidden JSON display areas (shown when button is clicked) -->
|
|
<div id="json-bar-good" class="json-bar" style="display: none;" title="ACCEPTED CONFIGS (Click to select)"
|
|
onclick="selectJSON('json-bar-good')">[]</div>
|
|
<div id="json-bar-favorite" class="json-bar" style="display: none;" title="FAVORITED CONFIGS (Click to select)"
|
|
onclick="selectJSON('json-bar-favorite')">[]</div>
|
|
<div id="json-bar-bad" class="json-bar" style="display: none;" title="REJECTED CONFIGS (Click to select)"
|
|
onclick="selectJSON('json-bar-bad')">[]</div>
|
|
</div>
|
|
|
|
<div id="modal">
|
|
<button class="modal-close-x" onclick="closeM()" title="Close (Esc)">×</button>
|
|
<div class="modal-main">
|
|
<div class="preview"><img id="m-img" src=""></div>
|
|
<div class="controls">
|
|
<h2 style="margin:0 0 10px 0; color:#fff;">Revise & Generate</h2>
|
|
<button class="modal-action-btn copy-comfy-btn" onclick="copyConfigsAsComfyNodes(window.currentModalId)"
|
|
style="background: #6366f1; margin-top: 10px;">
|
|
📋 Copy Configs To Clipboard As Comfy Nodes
|
|
</button>
|
|
<div class="field"><label>Model</label><input id="f-model"></div>
|
|
<div class="field"><label>Seed</label><input id="f-seed" type="number">
|
|
</div>
|
|
<div class="field"><label>Positive Prompt</label><textarea id="f-pos" rows="3"
|
|
style="background:#000; border:1px solid #333; color:#fff; padding:8px; font-size:12px; font-family:inherit; resize:vertical;"></textarea>
|
|
</div>
|
|
<div class="field"><label>Negative Prompt</label><textarea id="f-neg" rows="2"
|
|
style="background:#000; border:1px solid #333; color:#fff; padding:8px; font-size:12px; font-family:inherit; resize:vertical;"></textarea>
|
|
</div>
|
|
<div style="border-top:1px solid #333; margin:10px 0; padding-top:10px;">
|
|
<div style="font-size:11px; color:#666; margin-bottom:8px;">ADJUST PARAMETERS:</div>
|
|
</div>
|
|
<div class="field"><label>Sampler</label><input id="f-smp"></div>
|
|
<div class="field"><label>Scheduler</label><input id="f-sch"></div>
|
|
<div class="field"><label>Steps</label><input id="f-stp" type="number"></div>
|
|
<div class="field"><label>CFG</label><input id="f-cfg" type="number" step="0.5"></div>
|
|
<div class="field"><label>Denoise</label><input id="f-den" type="number" step="0.05"></div>
|
|
<div class="field"><label>LoRA</label><input id="f-lor"></div>
|
|
<div style="margin-top:auto; display:flex; gap:10px;">
|
|
<button class="action-btn"
|
|
style="flex:2; background:var(--accent); color:#000; border:none; height:36px; font-weight:800"
|
|
onclick="triggerGen(this)">GENERATE NEW</button>
|
|
<button class="action-btn" style="flex:1" onclick="closeM()">CANCEL</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="reel-wrap">
|
|
<div style="font-size:10px; font-weight:bold; color:#666;">RELATED VARIANTS</div>
|
|
<div class="reel" id="reel"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// INJECTED DATA
|
|
const TARGET_NODE_ID = "__NODE_ID__";
|
|
let fullManifest = __JSON_DATA__;
|
|
|
|
// INJECTED LOGIC
|
|
__JS_CONTENT__
|
|
|
|
</script>
|
|
<style>
|
|
/* Default behavior: The button is visible */
|
|
.gh-hide-on-mobile {
|
|
display: block;
|
|
}
|
|
|
|
/* CONDITION 1: Hide if screen is narrower than 768px (Mobile/Tablets) */
|
|
@media (max-width: 768px) {
|
|
.gh-hide-on-mobile {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* CONDITION 2: Hide if screen is in Portrait Mode (Taller than it is wide) */
|
|
@media (orientation: portrait) {
|
|
.gh-hide-on-mobile {
|
|
display: none !important;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="gh-hide-on-mobile"
|
|
style="position: absolute; top: 2px; left: 50%; transform: translateX(-50%); z-index: 999;">
|
|
<a href="https://github.com/JasonHoku/ComfyUI-Ultimate-Auto-Sampler-Config-Grid-Testing-Suite" target="_blank"
|
|
style="
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
background-color: #313131;
|
|
border: 1px solid rgba(27, 31, 35, 0.15);
|
|
border-radius: 6px;
|
|
color: #e6e6e6;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
line-height: 1;
|
|
padding: 3px 10px;
|
|
line-height: 20px;
|
|
text-decoration: none;
|
|
white-space: nowrap;
|
|
" onmouseover="this.style.backgroundColor='#747474'" onmouseout="this.style.backgroundColor='#313131'">
|
|
<svg height="20" viewBox="0 0 16 16" width="20" style="fill: currentColor; opacity: 0.7;">
|
|
<path
|
|
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z">
|
|
</path>
|
|
</svg>
|
|
|
|
<span>Star</span>
|
|
|
|
<span id="gh-star-count" style="
|
|
background-color: rgba(27, 31, 35, 0.08);
|
|
padding: 2px 6px;
|
|
border-radius: 10px;
|
|
font-size: 12px;
|
|
display: none; /* Hidden until loaded */
|
|
"></span>
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
(async function () {
|
|
try {
|
|
const repo = 'JasonHoku/ComfyUI-Ultimate-Auto-Sampler-Config-Grid-Testing-Suite';
|
|
const response = await fetch(`https://api.github.com/repos/${repo}`);
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
const countSpan = document.getElementById('gh-star-count');
|
|
|
|
// Format number (e.g. 1500 -> 1.5k) if needed, or just show raw
|
|
countSpan.textContent = data.stargazers_count;
|
|
countSpan.style.display = 'inline-block'; // Show it now that we have data
|
|
}
|
|
} catch (e) {
|
|
console.log('Could not fetch GitHub stars');
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<!-- Upscale Modal -->
|
|
<div id="upscale-modal-overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1000; align-items: center; justify-content: center;" onclick="if(event.target===this)closeUpscaleModal()">
|
|
<div id="upscale-modal-content" style="background: #1e1e1e; border: 1px solid #444; border-radius: 8px; padding: 20px; width: 600px; max-width: 92vw; max-height: 90vh; overflow-y: auto; box-shadow: 0 8px 32px rgba(0,0,0,0.5);"></div>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html> |