3944605d33
Bulk editor now loads consensus ML suggestions across the current selection via a new POST /api/suggestions/bulk endpoint, powered by get_bulk_suggestions() in tag_suggestions.py. A tag is surfaced only if it was suggested for or already applied to >= 80% of the selection; coverage counts include images that already have the tag so a near- universal tag isn't penalized for dropping out of suggestion lists. Accept-only chips (no reject) match the rest of the suggestions UX. Frontend polish in the same commit: - Showcase session dedup (exclude seen ids, reset on second lap) and aspect-ratio-aware placeholder heights for better column balancing - Modal touch-swipe navigation on the image wrapper, auto-focus of the tag input on desktop (>=768px), and autocomplete flip-up when the dropdown would cover the Suggestions section - Settings template inline styles replaced with utility classes - Inline series-editor script extracted to gallery-series-editor.js Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
61 lines
2.7 KiB
HTML
61 lines
2.7 KiB
HTML
{% extends "layout.html" %}
|
|
|
|
{% block title %}Showcase{% endblock %}
|
|
|
|
{% block body_attrs %} class="showcase-body"{% endblock %}
|
|
|
|
{% block body %}
|
|
<!-- Floating navbar overlay -->
|
|
<nav class="showcase-nav">
|
|
<div class="showcase-nav-links">
|
|
<a class="nav-link" href="{{ url_for('main.index') }}">Showcase</a>
|
|
<a class="nav-link" href="{{ url_for('main.gallery') }}">Gallery</a>
|
|
<div class="nav-dropdown">
|
|
<button class="nav-link nav-dropdown-trigger">Tags</button>
|
|
<div class="nav-dropdown-menu">
|
|
<a href="{{ url_for('main.tag_list') }}">All Tags</a>
|
|
<a href="{{ url_for('main.tag_list', kind='artist') }}">Artists</a>
|
|
<a href="{{ url_for('main.tag_list', kind='character') }}">Characters</a>
|
|
<a href="{{ url_for('main.tag_list', kind='series') }}">Series</a>
|
|
<a href="{{ url_for('main.tag_list', kind='fandom') }}">Fandoms</a>
|
|
<a href="{{ url_for('main.tag_list', kind='rating') }}">Ratings</a>
|
|
<a href="{{ url_for('main.tag_list', kind='archive') }}">Archives</a>
|
|
<a href="{{ url_for('main.tag_list', kind='source') }}">Sources</a>
|
|
<a href="{{ url_for('main.tag_list', kind='post') }}">Posts</a>
|
|
<a href="{{ url_for('main.tag_list', kind='user') }}">User Tags</a>
|
|
</div>
|
|
</div>
|
|
<a class="nav-link" href="{{ url_for('main.settings') }}">Settings</a>
|
|
</div>
|
|
<span class="nav-hint">Press R to shuffle</span>
|
|
</nav>
|
|
|
|
<!-- Masonry grid container - columns created by JS -->
|
|
<div id="showcaseGrid" class="masonry-container"></div>
|
|
|
|
<!-- Initial image data for JS to distribute -->
|
|
<script id="initialImages" type="application/json">
|
|
[{% for image in images %}
|
|
{
|
|
"id": {{ image.id }},
|
|
"filename": "{{ image.filename | e }}",
|
|
"thumb_url": "{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '')) }}",
|
|
"full_url": "{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '')) }}",
|
|
"is_video": {{ 'true' if image.filename.lower().endswith(('.mp4', '.mov')) else 'false' }},
|
|
"width": {{ image.width if image.width else 'null' }},
|
|
"height": {{ image.height if image.height else 'null' }},
|
|
"tags": [{% for t in image.tags %}{"name": "{{ t.name | e }}", "kind": "{{ t.kind }}"}{% if not loop.last %}, {% endif %}{% endfor %}]
|
|
}{% if not loop.last %},{% endif %}
|
|
{% endfor %}]
|
|
</script>
|
|
|
|
<!-- Modal viewer (shared with gallery) -->
|
|
{% include '_gallery_modal.html' %}
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='js/tag-utils.js') }}"></script>
|
|
<script src="{{ url_for('static', filename='js/view-modal.js') }}"></script>
|
|
<script src="{{ url_for('static', filename='js/showcase.js') }}"></script>
|
|
{% endblock %}
|