roundabout,
created on Friday, 3 January 2025, 13:59:30 (1735912770),
received on Friday, 3 January 2025, 13:59:35 (1735912775)
Author identity: vlad <vlad.muntoiu@gmail.com>
52f6eef3041879cee9e88562c7ee880b62b1e6ea
app.py
@@ -894,9 +894,11 @@ def gallery(id):
current_user = db.session.get(User, flask.session.get("username")) have_permission = current_user and (current_user == gallery.owner or current_user.admin or UserInGallery.query.filter_by(user=current_user, gallery=gallery).first()) have_extended_permission = current_user and (current_user == gallery.owner or current_user.admin)return flask.render_template("gallery.html", gallery=gallery, have_permission=have_permission)have_permission=have_permission, have_extended_permission=have_extended_permission)@app.route("/create-gallery")
static/style.css
@@ -248,12 +248,33 @@ iconify-icon {
} } @keyframes slide-in { from { transform: translateX(-1.5rem); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slide-out { from { transform: translateX(0); opacity: 1; } to { transform: translateX(-1.5rem); opacity: 0; } } @media (prefers-reduced-motion: no-preference) { .thumbnail-list > li:is(:hover, :focus, :has(:focus)) > a > .annotation-zone, #annotation-zone { view-transition-name: thumbnail; } ::view-transition-old(root), ::view-transition-new(root) { transform-origin: top;
@@ -592,6 +613,11 @@ dd {
margin: 0 auto; } #picture-view > x-frame { flex: 1 0 var(--width); margin: 0; } #picture-actions { --width: 256px; position: sticky;
templates/default.html
@@ -61,7 +61,7 @@
<nav class="navbar" id="desktop-navbar"> <ul> {% if back_url %} <li id="back-button"><li id="back-button-desktop"><a class="button button-flat button-neutral" href="{{ back_url | safe }}"> <iconify-icon icon="ic:baseline-arrow-back">Back</iconify-icon> </a>
templates/gallery.html
@@ -4,73 +4,93 @@
{% block title %}Gallery {{ gallery.title }} | {{ site_name }}{% endblock %} {% block content %} <x-frame style="--width: 768px" class="vbox"><h1>{{ gallery.title }}</h1><p>{{ gallery.description }}</p><p><a href="/gallery/{{ gallery.id }}/users">Users</a> {% if have_permission %} |<a href="/gallery/{{ gallery.id }}/edit">Edit</a>{% endif %}</p>{% if have_permission %}<form class="buttonbox" method="POST" action="/gallery/{{ gallery.id }}/add-picture"><input name="picture_id" type="text" placeholder="Picture ID" required aria-label="Picture ID"><button type="submit">Add picture</button></form><details><summary>Add from query</summary><form method="POST" action="/gallery/{{ gallery.id }}/add-pictures-from-query"><label><span class="required-asterisk">Query YAML</span><textarea name="query" required rows="8"></textarea></label><button type="submit">Add pictures</button><div id="picture-view"> <x-frame id="picture-actions"> <ul class="action-list"> <li><a href="/gallery/{{ gallery.id }}/users"> <iconify-icon icon="mdi:user"></iconify-icon>Users </a></li> {% if have_extended_permission %} <li><a href="/gallery/{{ gallery.id }}/edit"> <iconify-icon icon="mdi:edit"></iconify-icon>Edit </a></li> {% endif %} {% if have_extended_permission %} <li><details> <summary> <iconify-icon icon="mdi:delete"></iconify-icon>Delete </summary> <a href="/gallery/{{ gallery.id }}/delete">Confirm deletion</a> </details></li> {% endif %} </ul> </x-frame> <x-frame style="--width: 768px" class="vbox"> <h1>{{ gallery.title }}</h1> <p>owned by <a href="/profile/{{ gallery.owner.username }}">{{ gallery.owner.formatted_name }}</a></p> <p>{{ gallery.description }}</p> {% if have_permission %} <form class="buttonbox" method="POST" action="/gallery/{{ gallery.id }}/add-picture"> <input name="picture_id" type="text" placeholder="Picture ID" required aria-label="Picture ID"> <button type="submit">Add picture</button></form> </details>{% endif %}<h2>Pictures</h2><ul class="thumbnail-list">{% for picture in gallery.pictures %}<li><a href="/picture/{{ picture.resource.id }}"><div class="annotation-zone"><img src="/raw/picture/{{ picture.resource.id }}" alt="{{ picture.resource.title }}">{% for region in picture.resource.regions %}{% if region.json.type == "bbox" %}<svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"><rect x="{{ region.json.shape.x * picture.resource.width }}"y="{{ region.json.shape.y * picture.resource.height }}"width="{{ region.json.shape.w * picture.resource.width }}"height="{{ region.json.shape.h * picture.resource.height }}"fill="none" class="shape-bbox shape"></rect></svg>{% elif region.json.type == "polygon" %}<svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"><polygon points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polygon shape"></polygon></svg>{% elif region.json.type == "polyline" %}<svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"><polyline points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polyline shape"></polyline></svg>{% elif region.json.type == "point" %}<svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"><circle cx="{{ region.json.shape.x * picture.resource.width }}" cy="{{ region.json.shape.y * picture.resource.height }}" r="0" fill="none" class="shape-point shape"></circle></svg>{% endif %}{% endfor %}</div><div class="list-detail">{{ picture.resource.title }}<details> <summary>Add from query</summary> <form method="POST" action="/gallery/{{ gallery.id }}/add-pictures-from-query"> <label> <span class="required-asterisk">Query YAML</span> <textarea name="query" required rows="8"></textarea> </label> <button type="submit">Add pictures</button> </form> </details> {% endif %} <h2>Pictures</h2> <ul class="thumbnail-list"> {% for picture in gallery.pictures %} <li> <a href="/picture/{{ picture.resource.id }}"> <div class="annotation-zone"> <img src="/raw/picture/{{ picture.resource.id }}" alt="{{ picture.resource.title }}"> {% for region in picture.resource.regions %} {% if region.json.type == "bbox" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <rect x="{{ region.json.shape.x * picture.resource.width }}" y="{{ region.json.shape.y * picture.resource.height }}" width="{{ region.json.shape.w * picture.resource.width }}" height="{{ region.json.shape.h * picture.resource.height }}" fill="none" class="shape-bbox shape" ></rect> </svg> {% elif region.json.type == "polygon" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <polygon points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polygon shape"></polygon> </svg> {% elif region.json.type == "polyline" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <polyline points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polyline shape"></polyline> </svg> {% elif region.json.type == "point" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <circle cx="{{ region.json.shape.x * picture.resource.width }}" cy="{{ region.json.shape.y * picture.resource.height }}" r="0" fill="none" class="shape-point shape"></circle> </svg> {% endif %} {% endfor %} </div> <div class="list-detail"> {{ picture.resource.title }} </div> </a> <div class="list-more"> <form action="/gallery/{{ gallery.id }}/remove-picture" method="POST"> <input type="hidden" name="picture_id" value="{{ picture.resource.id }}"> <button type="submit" class="button-flat">Remove</button> </form></div> </a><div class="list-more"><form action="/gallery/{{ gallery.id }}/remove-picture" method="POST"><input type="hidden" name="picture_id" value="{{ picture.resource.id }}"><button type="submit" class="button-flat">Remove</button></form></div></li>{% endfor %}</ul></x-frame></li> {% endfor %} </ul> </x-frame> </div>{% endblock %}