feat(model-manager): generated-photo Gallery + device-routing landing

- Gallery view: grid of generated photos from ComfyUI's output/, full-size
  lightbox, and permanent delete (with confirm). Paginated ("Load more").
- Backend: GET /api/gallery, GET /gallery/file (path-guarded image serve),
  DELETE /api/gallery (path-guarded; clear error on permission denial).
- Mount ./output read-write into model-manager so the gallery can delete.
- Device-routing landing at /start: phones -> ComfyUIMini, desktops ->
  the Gallery; ?force=mobile|desktop overrides. Ports come from the new
  /api/ui-config (COMFYUI_PORT / COMFYUIMINI_PORT env).
- Responsive tweaks so the gallery is usable if opened directly on a phone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 15:41:46 -04:00
parent 0b606721dd
commit c9fa3fcab5
8 changed files with 388 additions and 1 deletions
+34
View File
@@ -20,6 +20,9 @@
<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>
@@ -48,6 +51,23 @@
</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">
@@ -160,6 +180,20 @@
</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>
<script src="/app.js"></script>
</body>
</html>