Files
SparkyUI/model-manager/app/static/index.html
T
TBNilles 15e0dc3772 feat(model-manager): base-model multi-select filter on CivitAI browse
Add a checkbox dropdown to filter the CivitAI catalog by one or more base
models (SD 1.5, SDXL, Pony, Illustrious, Flux, etc.), mapped to the API's
`baseModels` array param. Backend search accepts comma-separated
base_models; button shows the selected count with a Clear action.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 16:37:33 -04:00

221 lines
8.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SparkyUI · Model Manager</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand">
<span class="spark"></span>
<div>
<div class="brand-title">SparkyUI</div>
<div class="brand-sub">Model Manager</div>
</div>
</div>
<nav>
<button class="nav-item active" data-view="installed">
<span class="nav-ico"></span> Installed Models
</button>
<button class="nav-item" data-view="gallery">
<span class="nav-ico">🖼</span> Gallery
</button>
<button class="nav-item" data-view="browse">
<span class="nav-ico">🔍</span> Browse CivitAI
</button>
<button class="nav-item" data-view="download">
<span class="nav-ico"></span> Add / Download
</button>
<button class="nav-item" data-view="settings">
<span class="nav-ico"></span> Settings
</button>
</nav>
<div class="sidebar-foot" id="modelsDir"></div>
</aside>
<main class="content">
<!-- Installed Models -->
<section class="view active" id="view-installed">
<header class="view-head">
<h1>Installed Models</h1>
<div class="head-actions">
<input type="search" id="modelSearch" placeholder="Filter…" />
<button class="btn" id="refreshModels">Refresh</button>
</div>
</header>
<div id="modelsContainer" class="models-container">
<p class="empty">Loading…</p>
</div>
</section>
<!-- Gallery (generated photos) -->
<section class="view" id="view-gallery">
<header class="view-head">
<h1>Gallery</h1>
<div class="head-actions">
<span class="form-msg" id="galleryToast"></span>
<button class="btn" id="refreshGallery">Refresh</button>
<button class="btn danger" id="deleteAllGallery">Delete all</button>
</div>
</header>
<div id="galleryGrid" class="gallery-grid">
<p class="empty">Loading…</p>
</div>
<div class="browse-more">
<button class="btn" id="galleryMore" style="display:none">Load more</button>
</div>
</section>
<!-- Browse CivitAI -->
<section class="view" id="view-browse">
<header class="view-head">
<h1>Browse CivitAI</h1>
<div class="head-actions">
<span class="form-msg" id="browseToast"></span>
</div>
</header>
<div class="browse-controls">
<input type="search" id="bSearch" placeholder="Search models…" />
<select id="bType">
<option value="">All types</option>
<option value="Checkpoint">Checkpoint</option>
<option value="LORA">LoRA</option>
<option value="LoCon">LyCORIS</option>
<option value="TextualInversion">Embedding</option>
<option value="Controlnet">ControlNet</option>
<option value="VAE">VAE</option>
<option value="Upscaler">Upscaler</option>
<option value="Hypernetwork">Hypernetwork</option>
<option value="Poses">Poses</option>
</select>
<select id="bSort">
<option>Most Downloaded</option>
<option>Highest Rated</option>
<option>Newest</option>
</select>
<select id="bPeriod">
<option>AllTime</option>
<option>Year</option>
<option>Month</option>
<option>Week</option>
<option>Day</option>
</select>
<div class="multi-dd" id="bBaseDD">
<button type="button" class="btn multi-btn" id="bBaseBtn">Base model ▾</button>
<div class="multi-panel" id="bBasePanel" hidden>
<div class="multi-panel-actions">
<button type="button" class="link-btn" id="bBaseClear">Clear</button>
</div>
<!-- checkboxes injected by app.js -->
</div>
</div>
<label class="check"><input type="checkbox" id="bNsfw" /> NSFW</label>
<button class="btn primary" id="bGo">Search</button>
</div>
<div id="browseGrid" class="browse-grid">
<p class="empty">Search the CivitAI catalog, then click <b>Download</b> on a model.</p>
</div>
<div class="browse-more">
<button class="btn" id="bMore" style="display:none">Load more</button>
</div>
</section>
<!-- Add / Download -->
<section class="view" id="view-download">
<header class="view-head"><h1>Add / Download Model</h1></header>
<div class="card form-card">
<label>Download URL</label>
<input type="text" id="dlUrl"
placeholder="Direct URL, CivitAI model link, or HuggingFace resolve URL" />
<div class="source-hint" id="sourceHint"></div>
<div class="row">
<div class="col">
<label>Model type</label>
<select id="dlType"></select>
<div class="hint">CivitAI links auto-detect type; leave as-is to use it.</div>
</div>
<div class="col">
<label>Filename (optional)</label>
<input type="text" id="dlFilename" placeholder="Auto-detected if blank" />
</div>
</div>
<div class="form-actions">
<button class="btn primary" id="startDownload">Start Download</button>
<span class="form-msg" id="dlMsg"></span>
</div>
</div>
<h2 class="subhead">Downloads</h2>
<div id="downloadsContainer" class="downloads-container">
<p class="empty">No downloads yet.</p>
</div>
</section>
<!-- Settings -->
<section class="view" id="view-settings">
<header class="view-head"><h1>Settings</h1></header>
<div class="card form-card">
<h2 class="subhead first">API Keys</h2>
<p class="hint">
Stored persistently and sent as auth headers when downloading from the
matching site. Leave blank to keep the existing value.
</p>
<label>CivitAI API Key <span class="badge" id="civitaiBadge"></span></label>
<input type="password" id="civitaiKey" placeholder="••••••••" autocomplete="off" />
<label>HuggingFace Token <span class="badge" id="hfBadge"></span></label>
<input type="password" id="hfToken" placeholder="••••••••" autocomplete="off" />
<div class="form-actions">
<button class="btn primary" id="saveSettings">Save</button>
<span class="form-msg" id="settingsMsg"></span>
</div>
</div>
<div class="card form-card">
<h2 class="subhead first">Model Storage</h2>
<p class="hint">
Models are saved into the project <code>models/</code> directory, sorted into
ComfyUI's standard sub-folders by type. ComfyUI reads from the same folder.
</p>
</div>
</section>
</main>
</div>
<!-- Lightbox for full-size photo viewing -->
<div id="lightbox" class="lightbox" hidden>
<button class="lb-close" id="lbClose" title="Close"></button>
<img id="lbImage" alt="" />
<div class="lb-bar">
<span id="lbName" class="lb-name"></span>
<span class="lb-actions">
<a id="lbOpen" class="btn" target="_blank" rel="noopener">Open original</a>
<button class="btn danger" id="lbDelete">Delete</button>
</span>
</div>
</div>
<!-- In-app confirmation dialog (replaces native window.confirm) -->
<div id="confirmModal" class="modal-overlay" hidden>
<div class="modal">
<p id="confirmMsg"></p>
<div class="modal-actions">
<button class="btn" id="confirmCancel">Cancel</button>
<button class="btn danger-solid" id="confirmOk">Delete</button>
</div>
</div>
</div>
<script src="/app.js"></script>
</body>
</html>