b919e55206
Browsers suppress native confirm() dialogs after repeated use (the "prevent this page from creating additional dialogs" checkbox), which silently broke deletes. Add a promise-based in-app confirmation modal and use it for gallery photo and installed-model deletes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
211 lines
7.6 KiB
HTML
211 lines
7.6 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>
|
|
</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>
|
|
<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>
|