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 %}