Admin: create/delete mysteries, asset library, cutscene component picker

- Mysteries tab: "+ New" (slug + title) and per-row delete; opens the graph editor.
- Assets tab: upload images/audio/PDFs to the shared osint.assets store, grid with
  thumbnails/icons, copy id/url, delete (blocked with 409 when the asset is in use).
- Cutscene component_key is now a datalist of registered keys with a
  "not registered" warning, instead of free text.

Backend: DELETE /api/admin/mysteries/:id and POST/GET/DELETE /api/admin/assets
(reusing the deduplicated, MinIO-backed asset store).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 19:05:29 +02:00
co-authored by Claude Opus 4.8
parent 3b72f38d00
commit 7fe8fadd8a
6 changed files with 179 additions and 11 deletions
+26
View File
@@ -548,3 +548,29 @@ button:focus-visible { outline: 2px solid #e99a44; outline-offset: 2px; }
/* Utterance canvas vertical flow: input on top, output on the bottom */
.uinput { top: -6px; bottom: auto; left: 50%; right: auto; transform: translateX(-50%); }
.uport.flow { bottom: -7px; top: auto; left: 50%; right: auto; transform: translateX(-50%); }
/* Admin: mystery list actions + asset library */
.mystery-list-head { display: flex; justify-content: space-between; align-items: center; padding: 16px 0 10px; font: 600 9px IBM Plex Mono; letter-spacing: .18em; color: #78958d; }
.mystery-list-head button, .asset-upload-btn { background: #143229; border: 1px solid #3c5a52; color: #d79754; font: 9px IBM Plex Mono; padding: 6px 12px; cursor: pointer; }
.mystery-list-head button:hover, .asset-upload-btn:hover { background: #1c463a; }
.asset-upload-btn { display: inline-flex; align-items: center; letter-spacing: .1em; }
.asset-upload-btn input { display: none; }
.mystery-row { display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 6px; border: 0; border-bottom: 1px solid #1c352e; background: none; text-align: left; cursor: pointer; }
.mystery-row:hover { background: #12312a; }
.mystery-row-main { flex: 1; display: grid; gap: 3px; min-width: 0; }
.mystery-del { flex: 0 0 auto; background: none; border: 1px solid #3c5a52; color: #9bb0a9; width: 26px; height: 26px; font-size: 15px; cursor: pointer; }
.mystery-del:hover { border-color: #d78a7f; color: #e5b3ab; background: #4a221d; }
.ins-warn { color: #d78a7f; font-weight: 600; }
.asset-store { padding: 0 24px 24px; overflow: auto; }
.asset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
.asset-card { margin: 0; border: 1px solid #35544c; background: #0e2a24; display: flex; flex-direction: column; }
.asset-thumb { aspect-ratio: 4 / 3; display: grid; place-items: center; overflow: hidden; background: #0a211d; }
.asset-thumb img { width: 100%; height: 100%; object-fit: cover; }
.asset-icon { font: 600 20px IBM Plex Mono; color: #7f9a92; letter-spacing: .06em; }
.asset-card figcaption { padding: 7px 9px 2px; font: 10px IBM Plex Mono; color: #cfe0d9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.asset-card small { padding: 0 9px 6px; font: 8px IBM Plex Mono; color: #7f9a92; }
.asset-actions { display: flex; gap: 4px; padding: 0 8px 8px; margin-top: auto; }
.asset-actions button { flex: 1; background: #143229; border: 1px solid #3c5a52; color: #9bb0a9; font: 8px IBM Plex Mono; padding: 5px; cursor: pointer; }
.asset-actions button:hover { background: #1c463a; color: #e4e9e4; }
.asset-actions .asset-del { flex: 0 0 26px; }
.asset-actions .asset-del:hover { border-color: #d78a7f; color: #e5b3ab; background: #4a221d; }