major updates to theming, creation of showcase view and polish of existing systems including tagging editting.
This commit is contained in:
@@ -1,39 +1,44 @@
|
||||
<!-- /app/templates/_gallery_grid.html -->
|
||||
<div class="gallery-grid">
|
||||
{% for image in images.items %}
|
||||
<div class="gallery-item">
|
||||
<div class="gallery-thumb img-clickable"
|
||||
data-id="{{ image.id }}"
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '') ) }}"
|
||||
data-type="{{ 'video' if image.filename.lower().endswith(('.mp4', '.mov')) else 'image' }}"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');"
|
||||
data-filename="{{ image.filename }}">
|
||||
<div class="gallery-item img-clickable"
|
||||
data-id="{{ image.id }}"
|
||||
data-full="{{ url_for('main.serve_image', filename=image.filepath | replace('/images/', '') ) }}"
|
||||
data-type="{{ 'video' if image.filename.lower().endswith(('.mp4', '.mov')) else 'image' }}"
|
||||
data-filename="{{ image.filename }}">
|
||||
|
||||
{% if image.tags %}
|
||||
<div class="tag-overlay">
|
||||
{% for t in image.tags %}
|
||||
<a class="tag-chip"
|
||||
href="{{ url_for('main.gallery', tag=t.name) }}"
|
||||
title="Filter by {{ t.name }}"
|
||||
onclick="event.stopPropagation()">
|
||||
{% if t.kind == 'artist' %}
|
||||
🎨 {{ t.name.split(':', 1)[1] }}
|
||||
{% elif t.kind == 'archive' %}
|
||||
🗜️ {{ t.name.split(':', 1)[1] }}
|
||||
{% else %}
|
||||
#{{ t.name }}
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="gallery-thumb"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');"></div>
|
||||
|
||||
{% if image.filename.lower().endswith(('.mp4', '.mov')) %}
|
||||
<div class="play-overlay">▶</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if image.tags %}
|
||||
<div class="tag-overlay">
|
||||
{% for t in image.tags %}
|
||||
<a class="tag-chip"
|
||||
href="{{ url_for('main.gallery', tag=t.name) }}"
|
||||
title="Filter by {{ t.name }}"
|
||||
onclick="event.stopPropagation()">
|
||||
{% if t.kind == 'artist' %}
|
||||
🎨 {{ t.name.split(':', 1)[1] if ':' in t.name else t.name }}
|
||||
{% elif t.kind == 'archive' %}
|
||||
🗜️ {{ t.name.split(':', 1)[1] if ':' in t.name else t.name }}
|
||||
{% elif t.kind == 'character' %}
|
||||
👤 {{ t.name.split(':', 1)[1] if ':' in t.name else t.name }}
|
||||
{% elif t.kind == 'series' %}
|
||||
📺 {{ t.name.split(':', 1)[1] if ':' in t.name else t.name }}
|
||||
{% elif t.kind == 'rating' %}
|
||||
⚠️ {{ t.name.split(':', 1)[1] if ':' in t.name else t.name }}
|
||||
{% else %}
|
||||
#{{ t.name }}
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if image.filename.lower().endswith(('.mp4', '.mov')) %}
|
||||
<div class="play-overlay">▶</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Removed the artist link; keep date only -->
|
||||
<span class="image-date">{{ image.taken_at or image.imported_at | datetimeformat }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -44,20 +49,23 @@
|
||||
<!-- Modal -->
|
||||
<div id="imageModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<!-- Navigation buttons -->
|
||||
<button id="modalPrev" class="modal-button modal-prev">←</button>
|
||||
<button id="modalNext" class="modal-button modal-next">→</button>
|
||||
<button id="modalClose" class="modal-close-btn" title="Close (ESC)">×</button>
|
||||
<button id="modalPrev" class="modal-button modal-prev">‹</button>
|
||||
<button id="modalNext" class="modal-button modal-next">›</button>
|
||||
<span class="modal-close-hint">ESC to close</span>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="modalImageWrapper" class="modal-image-wrapper">
|
||||
<img id="modalImage" src="" alt="Full View">
|
||||
</div>
|
||||
|
||||
<!-- Tag editor (inline, minimal UI) -->
|
||||
<div id="modalTagEditor" class="tag-editor" data-image-id="">
|
||||
<div id="modalTagList" class="tags"></div>
|
||||
<form id="modalTagForm" class="tag-form" autocomplete="off">
|
||||
<input type="text" name="name" placeholder="Add tag… (artist:foo, archive:bar, or freeform)">
|
||||
<div class="tag-form-wrapper">
|
||||
<input type="text" id="tagInput" name="name" placeholder="Add tag..." autocomplete="off">
|
||||
<div id="tagAutocomplete" class="tag-autocomplete"></div>
|
||||
</div>
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<!-- /app/templates/_pagination_floating.html -->
|
||||
{% set total_pages = images.pages %}
|
||||
{% set current_page = images.page %}
|
||||
{% set endpoint = request.endpoint %}
|
||||
|
||||
{# Build a merged param dict: query args + path args #}
|
||||
{% set params = request.args.to_dict(flat=True) %}
|
||||
{% for k, v in request.view_args.items() %}
|
||||
{% set _ = params.update({k: v}) %}
|
||||
{% endfor %}
|
||||
|
||||
{# Helper to make a page URL while preserving all other params #}
|
||||
{% macro page_url(p) -%}
|
||||
{%- set pmap = params.copy() -%}
|
||||
{%- set _ = pmap.update({'page': p}) -%}
|
||||
{{ url_for(endpoint, **pmap) }}
|
||||
{%- endmacro %}
|
||||
|
||||
<div class="floating-pagination">
|
||||
<a class="fp-btn fp-prev {% if not images.has_prev %}disabled{% endif %}"
|
||||
{% if images.has_prev %}href="{{ page_url(images.prev_num) }}"{% endif %}
|
||||
title="Previous page">
|
||||
‹
|
||||
</a>
|
||||
|
||||
<span class="fp-indicator">
|
||||
<span class="fp-current">{{ current_page }}</span>
|
||||
<span class="fp-sep">/</span>
|
||||
<span class="fp-total">{{ total_pages }}</span>
|
||||
</span>
|
||||
|
||||
<a class="fp-btn fp-next {% if not images.has_next %}disabled{% endif %}"
|
||||
{% if images.has_next %}href="{{ page_url(images.next_num) }}"{% endif %}
|
||||
title="Next page">
|
||||
›
|
||||
</a>
|
||||
</div>
|
||||
@@ -1,17 +0,0 @@
|
||||
<!-- /app/templates/artist_gallery.html -->
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}{{ artist }}'s Gallery{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 style="text-align:center; margin-top: 1rem;">{{ artist }}</h1>
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
<!-- Gallery Grid -->
|
||||
{% include '_gallery_grid.html' %}
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,22 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Artists{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Artists</h1>
|
||||
<div class="artist-grid">
|
||||
{% for artist in artist_data %}
|
||||
<a href="{{ url_for('main.artist_gallery', artist_name=artist.name) }}" class="artist-card-link">
|
||||
<div class="artist-card">
|
||||
<h3>{{ artist.name }}</h3>
|
||||
<div class="artist-preview">
|
||||
{% for image in artist.images %}
|
||||
<div class="artist-thumb"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -5,13 +5,12 @@
|
||||
{% block content %}
|
||||
<h1 style="text-align:center; margin-top: 1rem;">Gallery</h1>
|
||||
|
||||
<!-- Pagination Controls (Top) -->
|
||||
{% include '_pagination.html' %}
|
||||
|
||||
<!-- Gallery Grid -->
|
||||
{% include '_gallery_grid.html' %}
|
||||
|
||||
<!-- Pagination Controls (Bottom) -->
|
||||
{% include '_pagination.html' %}
|
||||
<!-- Floating Pagination Bar -->
|
||||
{% if images.pages > 1 %}
|
||||
{% include '_pagination_floating.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}Welcome{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="index-hero" style="background-image: url('{{ background_url }}');">
|
||||
<div class="index-overlay">
|
||||
<div class="index-message">
|
||||
<h1>Private Image Repository</h1>
|
||||
<p>This is a private image collection. You must register for access to browse and contribute.</p>
|
||||
<a href="{{ url_for('auth.register') }}" class="btn primary-btn">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -11,24 +11,11 @@
|
||||
|
||||
<header>
|
||||
<nav class="navbar">
|
||||
<a class="nav-button" href="{{ url_for('main.gallery') }}">Home</a>
|
||||
<a class="nav-button" href="{{ url_for('main.index') }}">Showcase</a>
|
||||
<a class="nav-button" href="{{ url_for('main.gallery') }}">Gallery</a>
|
||||
<a class="nav-button" href="{{ url_for('main.tag_list', kind='artist') }}">Artists</a>
|
||||
<a class="nav-button" href="{{ url_for('main.tag_list') }}">Tags</a>
|
||||
<a class="nav-button" href="{{ url_for('main.settings') }}">Settings</a>
|
||||
<!-- <a class="nav-button" href="{{ url_for('main.gallery') if current_user.is_authenticated else url_for('main.index') }}">Home</a>
|
||||
|
||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
||||
<a class="nav-button" href="{{ url_for('main.settings') }}">Settings</a>
|
||||
{% endif %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<a class="nav-button" href="{{ url_for('main.tag_list', kind='artist') }}">Artists</a>
|
||||
<a class="nav-button" href="{{ url_for('main.tag_list') }}">Tags</a>
|
||||
<a class="nav-button" href="{{ url_for('auth.logout') }}">Logout</a>
|
||||
{% else %}
|
||||
<a class="nav-button" href="{{ url_for('auth.login') }}">Login</a>
|
||||
<a class="nav-button" href="{{ url_for('auth.register') }}">Register</a>
|
||||
{% endif %} -->
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -44,15 +31,13 @@
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<div class="content">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if request.endpoint == 'main.gallery' or request.endpoint == 'main.artist_gallery' %}
|
||||
{% if request.endpoint == 'main.gallery' %}
|
||||
<input type="hidden" id="hasNextPage" value="{{ has_next|lower }}">
|
||||
<input type="hidden" id="nextPageUrl" value="{{ next_page_url }}">
|
||||
<input type="hidden" id="hasPrevPage" value="{{ has_prev|lower }}">
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="form-container">
|
||||
<h2>Login</h2>
|
||||
<form method="POST" class="form-card">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.email.label(class="form-label") }}
|
||||
{{ form.email(class="form-input", placeholder=form.email.label.text) }}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.password.label(class="form-label") }}
|
||||
{{ form.password(class="form-input", placeholder=form.password.label.text) }}
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
{{ form.submit(class="form-button") }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="form-footer-text">
|
||||
Don’t have an account? <a href="{{ url_for('auth.register') }}">Register here</a>.
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,52 +0,0 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}Register{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="form-container">
|
||||
<h2>Register</h2>
|
||||
<form method="POST" class="form-card">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.username.label(class="form-label") }}
|
||||
{{ form.username(class="form-input", placeholder=form.username.label.text) }}
|
||||
{% for error in form.username.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.email.label(class="form-label") }}
|
||||
{{ form.email(class="form-input", placeholder=form.email.label.text) }}
|
||||
{% for error in form.email.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.password.label(class="form-label") }}
|
||||
{{ form.password(class="form-input", placeholder=form.password.label.text) }}
|
||||
{% for error in form.password.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
{{ form.confirm_password.label(class="form-label") }}
|
||||
{{ form.confirm_password(class="form-input", placeholder=form.confirm_password.label.text) }}
|
||||
{% for error in form.confirm_password.errors %}
|
||||
<span class="error">{{ error }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
{{ form.submit(class="form-button") }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="form-footer-text">
|
||||
Already have an account? <a href="{{ url_for('auth.login') }}">Login here</a>.
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,70 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>ImageRepo - Showcase</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||
</head>
|
||||
<body class="showcase-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>
|
||||
<a class="nav-link" href="{{ url_for('main.tag_list', kind='artist') }}">Artists</a>
|
||||
<a class="nav-link" href="{{ url_for('main.tag_list') }}">Tags</a>
|
||||
<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' }},
|
||||
"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 -->
|
||||
<div id="imageModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<button id="modalClose" class="modal-close-btn" title="Close (ESC)">×</button>
|
||||
<button id="modalPrev" class="modal-button modal-prev">‹</button>
|
||||
<button id="modalNext" class="modal-button modal-next">›</button>
|
||||
<span class="modal-close-hint">ESC to close</span>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="modalImageWrapper" class="modal-image-wrapper">
|
||||
<img id="modalImage" src="" alt="Full View">
|
||||
</div>
|
||||
|
||||
<div id="modalTagEditor" class="tag-editor" data-image-id="">
|
||||
<div id="modalTagList" class="tags"></div>
|
||||
<form id="modalTagForm" class="tag-form" autocomplete="off">
|
||||
<div class="tag-form-wrapper">
|
||||
<input type="text" id="tagInput" name="name" placeholder="Add tag..." autocomplete="off">
|
||||
<div id="tagAutocomplete" class="tag-autocomplete"></div>
|
||||
</div>
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/modal-pagination.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/showcase.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +1,25 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block title %}{{ 'Artists' if active_kind == 'artist' else 'Tags' }}{% endblock %}
|
||||
{% block title %}
|
||||
{%- if active_kind == 'artist' -%}Artists
|
||||
{%- elif active_kind == 'character' -%}Characters
|
||||
{%- elif active_kind == 'series' -%}Series
|
||||
{%- elif active_kind == 'rating' -%}Ratings
|
||||
{%- elif active_kind == 'archive' -%}Archives
|
||||
{%- elif active_kind == 'user' -%}User Tags
|
||||
{%- else -%}Tags{%- endif -%}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ 'Artists' if active_kind == 'artist' else 'Tags' }}</h1>
|
||||
<h1>
|
||||
{%- if active_kind == 'artist' -%}Artists
|
||||
{%- elif active_kind == 'character' -%}Characters
|
||||
{%- elif active_kind == 'series' -%}Series
|
||||
{%- elif active_kind == 'rating' -%}Ratings
|
||||
{%- elif active_kind == 'archive' -%}Archives
|
||||
{%- elif active_kind == 'user' -%}User Tags
|
||||
{%- else -%}All Tags{%- endif -%}
|
||||
</h1>
|
||||
|
||||
<!-- Small kind filter nav (optional) -->
|
||||
<!-- Tag kind filter -->
|
||||
<div class="filter-bar" role="tablist" aria-label="Filter tags by kind">
|
||||
<a class="filter-btn {{ 'is-active' if not active_kind }}"
|
||||
@@ -15,6 +30,18 @@
|
||||
href="{{ url_for('main.tag_list', kind='artist') }}"
|
||||
aria-current="{{ 'page' if active_kind=='artist' else 'false' }}">🎨 Artists</a>
|
||||
|
||||
<a class="filter-btn {{ 'is-active' if active_kind=='character' }}"
|
||||
href="{{ url_for('main.tag_list', kind='character') }}"
|
||||
aria-current="{{ 'page' if active_kind=='character' else 'false' }}">👤 Characters</a>
|
||||
|
||||
<a class="filter-btn {{ 'is-active' if active_kind=='series' }}"
|
||||
href="{{ url_for('main.tag_list', kind='series') }}"
|
||||
aria-current="{{ 'page' if active_kind=='series' else 'false' }}">📺 Series</a>
|
||||
|
||||
<a class="filter-btn {{ 'is-active' if active_kind=='rating' }}"
|
||||
href="{{ url_for('main.tag_list', kind='rating') }}"
|
||||
aria-current="{{ 'page' if active_kind=='rating' else 'false' }}">⚠️ Ratings</a>
|
||||
|
||||
<a class="filter-btn {{ 'is-active' if active_kind=='archive' }}"
|
||||
href="{{ url_for('main.tag_list', kind='archive') }}"
|
||||
aria-current="{{ 'page' if active_kind=='archive' else 'false' }}">🗜️ Archives</a>
|
||||
@@ -24,25 +51,74 @@
|
||||
aria-current="{{ 'page' if active_kind=='user' else 'false' }}"># User</a>
|
||||
</div>
|
||||
|
||||
<div class="artist-grid">
|
||||
{% if tag_data %}
|
||||
<div class="tag-grid">
|
||||
{% for tag in tag_data %}
|
||||
<a href="{{ url_for('main.gallery', tag=tag.tag) }}" class="artist-card-link">
|
||||
<div class="artist-card">
|
||||
<div class="card-title" title="{{ tag.name }}">
|
||||
<h3 class="card-title-text">
|
||||
{% if tag.kind == 'artist' %}🎨{% elif tag.kind == 'archive' %}🗜️{% else %}# {% endif %}
|
||||
{{ tag.name }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="artist-preview">
|
||||
<div class="tag-card" data-tag-id="{{ tag.id }}" data-tag-name="{{ tag.tag }}" data-tag-kind="{{ tag.kind }}">
|
||||
<a href="{{ url_for('main.gallery', tag=tag.tag) }}" class="tag-card-link">
|
||||
<div class="tag-preview">
|
||||
{% for image in tag.images %}
|
||||
<div class="artist-thumb"
|
||||
<div class="tag-thumb"
|
||||
style="background-image: url('{{ url_for('main.serve_image', filename=(image.thumb_path or image.filepath) | replace('/images/', '') ) }}');">
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if tag.images|length == 0 %}
|
||||
<div class="tag-thumb tag-thumb-empty"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="tag-card-info">
|
||||
<span class="tag-icon">
|
||||
{%- if tag.kind == 'artist' -%}🎨
|
||||
{%- elif tag.kind == 'character' -%}👤
|
||||
{%- elif tag.kind == 'series' -%}📺
|
||||
{%- elif tag.kind == 'rating' -%}⚠️
|
||||
{%- elif tag.kind == 'archive' -%}🗜️
|
||||
{%- else -%}#{%- endif -%}
|
||||
</span>
|
||||
<span class="tag-name" title="{{ tag.name }}">{{ tag.name }}</span>
|
||||
<span class="tag-count">{{ tag.count }}</span>
|
||||
</div>
|
||||
</a>
|
||||
<button class="tag-edit-btn" title="Edit tag" data-tag-id="{{ tag.id }}">✏️</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="empty-state">No tags found in this category.</p>
|
||||
{% endif %}
|
||||
|
||||
<!-- Tag Edit Modal -->
|
||||
<div id="tagEditModal" class="modal">
|
||||
<div class="modal-content tag-edit-modal-content">
|
||||
<button id="tagEditClose" class="modal-close-btn" title="Close">×</button>
|
||||
<h2>Edit Tag</h2>
|
||||
<form id="tagEditForm" class="tag-edit-form">
|
||||
<input type="hidden" id="editTagId" name="tag_id">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="editTagName">Tag Name</label>
|
||||
<input type="text" id="editTagName" name="name" class="form-input" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="editTagKind">Category</label>
|
||||
<select id="editTagKind" name="kind" class="form-input">
|
||||
<option value="user"># User Tag</option>
|
||||
<option value="artist">🎨 Artist</option>
|
||||
<option value="character">👤 Character</option>
|
||||
<option value="series">📺 Series</option>
|
||||
<option value="rating">⚠️ Rating</option>
|
||||
<option value="archive">🗜️ Archive</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn primary-btn">Save Changes</button>
|
||||
<button type="button" id="tagDeleteBtn" class="btn danger-btn">Delete Tag</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/tag-editor.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user