mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-01-04 05:46:14 +00:00
Add basic Image Group functions
Make the Upload Pannel usable on mobile Remove useless code as Django had built-in functions to read the config Remove useless JS code Cleanup tempaltes
This commit is contained in:
parent
35c5951318
commit
e3a0eaf60b
|
@ -84,6 +84,8 @@ def create_app(test_config=None):
|
||||||
ALLOWED_EXTENSIONS=conf['upload']['allowed-extensions'],
|
ALLOWED_EXTENSIONS=conf['upload']['allowed-extensions'],
|
||||||
MAX_CONTENT_LENGTH=1024 * 1024 * conf['upload']['max-size'],
|
MAX_CONTENT_LENGTH=1024 * 1024 * conf['upload']['max-size'],
|
||||||
WEBSITE=conf['website'],
|
WEBSITE=conf['website'],
|
||||||
|
ADMIN=conf['admin'],
|
||||||
|
APP_VERSION='23.03.09',
|
||||||
)
|
)
|
||||||
|
|
||||||
if test_config is None:
|
if test_config is None:
|
||||||
|
@ -139,6 +141,10 @@ def create_app(test_config=None):
|
||||||
app.register_blueprint(routing.blueprint)
|
app.register_blueprint(routing.blueprint)
|
||||||
app.add_url_rule('/', endpoint='index')
|
app.add_url_rule('/', endpoint='index')
|
||||||
|
|
||||||
|
# Load routes for groups
|
||||||
|
from . import groups
|
||||||
|
app.register_blueprint(groups.blueprint)
|
||||||
|
|
||||||
# Load routes for settings
|
# Load routes for settings
|
||||||
from . import settings
|
from . import settings
|
||||||
app.register_blueprint(settings.blueprint)
|
app.register_blueprint(settings.blueprint)
|
||||||
|
|
|
@ -6,10 +6,11 @@ from uuid import uuid4
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Blueprint, current_app, send_from_directory, send_file, request, g, abort, flash, jsonify)
|
Blueprint, send_from_directory, send_file, abort, flash, jsonify, request, g, current_app)
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
from colorthief import ColorThief
|
from colorthief import ColorThief
|
||||||
|
@ -128,7 +129,6 @@ def upload():
|
||||||
if os.path.isdir(current_app.config['UPLOAD_FOLDER']) is False:
|
if os.path.isdir(current_app.config['UPLOAD_FOLDER']) is False:
|
||||||
os.mkdir(current_app.config['UPLOAD_FOLDER'])
|
os.mkdir(current_app.config['UPLOAD_FOLDER'])
|
||||||
|
|
||||||
|
|
||||||
# Save file
|
# Save file
|
||||||
try:
|
try:
|
||||||
form_file.save(img_path)
|
form_file.save(img_path)
|
||||||
|
@ -159,14 +159,13 @@ def upload():
|
||||||
|
|
||||||
return 'Gwa Gwa'
|
return 'Gwa Gwa'
|
||||||
|
|
||||||
|
@blueprint.route('/delete/<int:image_id>', methods=['POST'])
|
||||||
@blueprint.route('/remove/<int:img_id>', methods=['POST'])
|
|
||||||
@login_required
|
@login_required
|
||||||
def remove(img_id):
|
def delete_image(image_id):
|
||||||
"""
|
"""
|
||||||
Deletes an image from the server and database
|
Deletes an image from the server and database
|
||||||
"""
|
"""
|
||||||
img = db_session.query(db.Posts).filter_by(id=img_id).first()
|
img = db_session.query(db.Posts).filter_by(id=image_id).first()
|
||||||
|
|
||||||
if img is None:
|
if img is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
@ -183,17 +182,65 @@ def remove(img_id):
|
||||||
abort(500)
|
abort(500)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db_session.query(db.Posts).filter_by(id=img_id).delete()
|
db_session.query(db.Posts).filter_by(id=image_id).delete()
|
||||||
|
|
||||||
|
groups = db_session.query(db.GroupJunction).filter_by(post_id=image_id).all()
|
||||||
|
for group in groups:
|
||||||
|
db_session.delete(group)
|
||||||
|
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logging.error('Could not remove from database: %s', err)
|
logging.error('Could not remove from database: %s', err)
|
||||||
abort(500)
|
abort(500)
|
||||||
|
|
||||||
logging.info('Removed image (%s) %s', img_id, img.file_name)
|
logging.info('Removed image (%s) %s', image_id, img.file_name)
|
||||||
flash(['Image was all in Le Head!', 1])
|
flash(['Image was all in Le Head!', 1])
|
||||||
return 'Gwa Gwa'
|
return 'Gwa Gwa'
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/group/create', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def create_group():
|
||||||
|
"""
|
||||||
|
Creates a group
|
||||||
|
"""
|
||||||
|
group_name = request.form['name']
|
||||||
|
group_description = request.form['description']
|
||||||
|
group_author = g.user.id
|
||||||
|
|
||||||
|
new_group = db.Groups(name=group_name,
|
||||||
|
description=group_description,
|
||||||
|
author_id=group_author,
|
||||||
|
created_at=dt.utcnow())
|
||||||
|
|
||||||
|
db_session.add(new_group)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return ':3'
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/group/modify', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def modify_group():
|
||||||
|
"""
|
||||||
|
Changes the images in a group
|
||||||
|
"""
|
||||||
|
group_id = request.form['group_id']
|
||||||
|
image_id = request.form['images']
|
||||||
|
action = request.form['action']
|
||||||
|
|
||||||
|
if action == 'add':
|
||||||
|
# Check if image is already in group
|
||||||
|
if db_session.query(db.GroupJunction).filter_by(group_id=group_id, post_id=image_id).first() is None:
|
||||||
|
db_session.add(db.GroupJunction(group_id=group_id, post_id=image_id, date_added=dt.utcnow()))
|
||||||
|
db_session.commit()
|
||||||
|
elif action == 'remove':
|
||||||
|
db_session.query(db.GroupJunction).filter_by(group_id=group_id, post_id=image_id).delete()
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
return ':3'
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/metadata/<int:img_id>', methods=['GET'])
|
@blueprint.route('/metadata/<int:img_id>', methods=['GET'])
|
||||||
def metadata(img_id):
|
def metadata(img_id):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,7 +3,6 @@ OnlyLegs - Database
|
||||||
Database models and functions for SQLAlchemy
|
Database models and functions for SQLAlchemy
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
|
||||||
import platformdirs
|
import platformdirs
|
||||||
|
|
||||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType
|
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, ForeignKey, PickleType
|
||||||
|
@ -83,6 +82,7 @@ class GroupJunction (base): # pylint: disable=too-few-public-methods, C0103
|
||||||
__tablename__ = 'group_junction'
|
__tablename__ = 'group_junction'
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
|
date_added = Column(DateTime, nullable=False)
|
||||||
group_id = Column(Integer, ForeignKey('groups.id'))
|
group_id = Column(Integer, ForeignKey('groups.id'))
|
||||||
post_id = Column(Integer, ForeignKey('posts.id'))
|
post_id = Column(Integer, ForeignKey('posts.id'))
|
||||||
|
|
||||||
|
|
89
gallery/groups.py
Normal file
89
gallery/groups.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
"""
|
||||||
|
Onlylegs - API endpoints
|
||||||
|
Used intermally by the frontend and possibly by other applications
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
from datetime import datetime as dt
|
||||||
|
|
||||||
|
from flask import Blueprint, abort, jsonify, render_template, url_for, request, g
|
||||||
|
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
|
from gallery.auth import login_required
|
||||||
|
|
||||||
|
from . import db # Import db to create a session
|
||||||
|
|
||||||
|
|
||||||
|
blueprint = Blueprint('group', __name__, url_prefix='/group')
|
||||||
|
db_session = sessionmaker(bind=db.engine)
|
||||||
|
db_session = db_session()
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/', methods=['GET'])
|
||||||
|
def groups():
|
||||||
|
"""
|
||||||
|
Group overview, shows all image groups
|
||||||
|
"""
|
||||||
|
groups = db_session.query(db.Groups).all()
|
||||||
|
|
||||||
|
for group in groups:
|
||||||
|
thumbnail = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group.id).order_by(db.GroupJunction.date_added.desc()).first()
|
||||||
|
|
||||||
|
if thumbnail is not None:
|
||||||
|
thumbnail_filename = db_session.query(db.Posts.file_name).filter(db.Posts.id == thumbnail[0]).first()
|
||||||
|
group.thumbnail = thumbnail_filename[0]
|
||||||
|
else:
|
||||||
|
group.thumbnail = None
|
||||||
|
|
||||||
|
return render_template('groups/list.html', groups=groups)
|
||||||
|
|
||||||
|
@blueprint.route('/<int:group_id>')
|
||||||
|
def group(group_id):
|
||||||
|
"""
|
||||||
|
Group view, shows all images in a group
|
||||||
|
"""
|
||||||
|
group = db_session.query(db.Groups).filter(db.Groups.id == group_id).first()
|
||||||
|
|
||||||
|
if group is None:
|
||||||
|
abort(404, 'Group not found')
|
||||||
|
|
||||||
|
group_images = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).order_by(db.GroupJunction.date_added.desc()).all()
|
||||||
|
|
||||||
|
images = []
|
||||||
|
for image in group_images:
|
||||||
|
image = db_session.query(db.Posts).filter(db.Posts.id == image[0]).first()
|
||||||
|
images.append(image)
|
||||||
|
|
||||||
|
return render_template('groups/group.html', group=group, images=images)
|
||||||
|
|
||||||
|
@blueprint.route('/<int:group_id>/<int:image_id>')
|
||||||
|
def group_post(group_id, image_id):
|
||||||
|
"""
|
||||||
|
Image view, shows the image and its metadata from a specific group
|
||||||
|
"""
|
||||||
|
img = db_session.query(db.Posts).filter(db.Posts.id == image_id).first()
|
||||||
|
|
||||||
|
if img is None:
|
||||||
|
abort(404, 'Image not found')
|
||||||
|
|
||||||
|
img.author_username = db_session.query(db.Users.username).filter(db.Users.id == img.author_id).first()[0]
|
||||||
|
|
||||||
|
groups = db_session.query(db.GroupJunction.group_id).filter(db.GroupJunction.post_id == image_id).all()
|
||||||
|
img.groups = []
|
||||||
|
for group in groups:
|
||||||
|
group = db_session.query(db.Groups).filter(db.Groups.id == group[0]).first()
|
||||||
|
img.groups.append(group)
|
||||||
|
|
||||||
|
next = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id > image_id).order_by(db.GroupJunction.date_added.asc()).first()
|
||||||
|
prev = db_session.query(db.GroupJunction.post_id).filter(db.GroupJunction.group_id == group_id).filter(db.GroupJunction.post_id < image_id).order_by(db.GroupJunction.date_added.desc()).first()
|
||||||
|
|
||||||
|
if next is not None:
|
||||||
|
next = url_for('group.group_post', group_id=group_id, image_id=next[0])
|
||||||
|
if prev is not None:
|
||||||
|
prev = url_for('group.group_post', group_id=group_id, image_id=prev[0])
|
||||||
|
|
||||||
|
return render_template('image.html',
|
||||||
|
image=img,
|
||||||
|
next_url=next,
|
||||||
|
prev_url=prev)
|
|
@ -3,7 +3,7 @@ Onlylegs Gallery - Routing
|
||||||
"""
|
"""
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
|
|
||||||
from flask import Blueprint, render_template, current_app, request, g
|
from flask import Blueprint, render_template, url_for
|
||||||
from werkzeug.exceptions import abort
|
from werkzeug.exceptions import abort
|
||||||
|
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
@ -24,15 +24,10 @@ def index():
|
||||||
"""
|
"""
|
||||||
images = db_session.query(db.Posts.file_name,
|
images = db_session.query(db.Posts.file_name,
|
||||||
db.Posts.image_colours,
|
db.Posts.image_colours,
|
||||||
db.Posts.author_id,
|
|
||||||
db.Posts.created_at,
|
db.Posts.created_at,
|
||||||
db.Posts.id).order_by(db.Posts.id.desc()).all()
|
db.Posts.id).order_by(db.Posts.id.desc()).all()
|
||||||
|
|
||||||
return render_template('index.html',
|
return render_template('index.html', images=images)
|
||||||
images=images,
|
|
||||||
image_count=len(images),
|
|
||||||
name=current_app.config['WEBSITE']['name'],
|
|
||||||
motto=current_app.config['WEBSITE']['motto'])
|
|
||||||
|
|
||||||
@blueprint.route('/image/<int:image_id>')
|
@blueprint.route('/image/<int:image_id>')
|
||||||
def image(image_id):
|
def image(image_id):
|
||||||
|
@ -42,53 +37,25 @@ def image(image_id):
|
||||||
img = db_session.query(db.Posts).filter(db.Posts.id == image_id).first()
|
img = db_session.query(db.Posts).filter(db.Posts.id == image_id).first()
|
||||||
|
|
||||||
if img is None:
|
if img is None:
|
||||||
abort(404, 'Image not found')
|
abort(404, 'Image not found :<')
|
||||||
|
|
||||||
author = db_session.query(db.Users.username).filter(db.Users.id == img.author_id).first()[0]
|
img.author_username = db_session.query(db.Users.username).filter(db.Users.id == img.author_id).first()[0]
|
||||||
img.author_username = author
|
|
||||||
|
groups = db_session.query(db.GroupJunction.group_id).filter(db.GroupJunction.post_id == image_id).all()
|
||||||
|
img.groups = []
|
||||||
|
for group in groups:
|
||||||
|
group = db_session.query(db.Groups).filter(db.Groups.id == group[0]).first()
|
||||||
|
img.groups.append(group)
|
||||||
|
|
||||||
next = db_session.query(db.Posts.id).filter(db.Posts.id > image_id).order_by(db.Posts.id.asc()).first()
|
next = db_session.query(db.Posts.id).filter(db.Posts.id > image_id).order_by(db.Posts.id.asc()).first()
|
||||||
prev = db_session.query(db.Posts.id).filter(db.Posts.id < image_id).order_by(db.Posts.id.desc()).first()
|
prev = db_session.query(db.Posts.id).filter(db.Posts.id < image_id).order_by(db.Posts.id.desc()).first()
|
||||||
|
|
||||||
if next is not None:
|
if next is not None:
|
||||||
next = next[0]
|
next = url_for('gallery.image', image_id=next[0])
|
||||||
if prev is not None:
|
if prev is not None:
|
||||||
prev = prev[0]
|
prev = url_for('gallery.image', image_id=prev[0])
|
||||||
|
|
||||||
return render_template('image.html',
|
return render_template('image.html', image=img, next_url=next, prev_url=prev)
|
||||||
image=img,
|
|
||||||
exif=img.image_exif,
|
|
||||||
next=next,
|
|
||||||
prev=prev,
|
|
||||||
next_id=next,
|
|
||||||
prev_id=prev)
|
|
||||||
|
|
||||||
@blueprint.route('/group', methods=['GET', 'POST'])
|
|
||||||
def groups():
|
|
||||||
"""
|
|
||||||
Group overview, shows all image groups
|
|
||||||
"""
|
|
||||||
if request.method == 'GET':
|
|
||||||
groups = db_session.query(db.Groups.name, db.Groups.author_id).all()
|
|
||||||
|
|
||||||
return render_template('group.html', groups=groups)
|
|
||||||
elif request.method == 'POST':
|
|
||||||
group_name = request.form['name']
|
|
||||||
group_description = request.form['description']
|
|
||||||
group_author = g.user.id
|
|
||||||
|
|
||||||
new_group = db.Groups(name=group_name, description=group_description, author_id=group_author, created_at=dt.now())
|
|
||||||
|
|
||||||
db_session.add(new_group)
|
|
||||||
|
|
||||||
return ':3'
|
|
||||||
|
|
||||||
@blueprint.route('/group/<int:group_id>')
|
|
||||||
def group(group_id):
|
|
||||||
"""
|
|
||||||
Group view, shows all images in a group
|
|
||||||
"""
|
|
||||||
return render_template('group.html', group_id=group_id)
|
|
||||||
|
|
||||||
@blueprint.route('/profile')
|
@blueprint.route('/profile')
|
||||||
def profile():
|
def profile():
|
||||||
|
|
|
@ -1,18 +1,3 @@
|
||||||
let navToggle = true;
|
|
||||||
|
|
||||||
document.onscroll = function() {
|
|
||||||
if (document.body.scrollTop > 300 || document.documentElement.scrollTop > 20) {
|
|
||||||
document.querySelector('.jumpUp').classList = 'jumpUp jumpUp--show';
|
|
||||||
} else {
|
|
||||||
document.querySelector('.jumpUp').classList = 'jumpUp';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.querySelector('.jumpUp').onclick = function() {
|
|
||||||
document.body.scrollTop = 0;
|
|
||||||
document.documentElement.scrollTop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function imgFade(obj) {
|
function imgFade(obj) {
|
||||||
$(obj).animate({opacity: 1}, 250);
|
$(obj).animate({opacity: 1}, 250);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +21,43 @@ for (let i = 0; i < times.length; i++) {
|
||||||
times[i].innerHTML = dateTime.toLocaleDateString() + ' ' + dateTime.toLocaleTimeString();
|
times[i].innerHTML = dateTime.toLocaleDateString() + ' ' + dateTime.toLocaleTimeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let images = document.querySelectorAll('.gallery-item img');
|
||||||
|
function loadOnView() {
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
let image = images[i];
|
||||||
|
if (image.getBoundingClientRect().top < window.innerHeight && image.getBoundingClientRect().bottom > 0) {
|
||||||
|
if (!image.src) {
|
||||||
|
image.src = `/api/uploads/${image.getAttribute('data-src')}?w=500&h=500`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (images.length > 0) {
|
||||||
|
window.onload = function() {
|
||||||
|
loadOnView();
|
||||||
|
};
|
||||||
|
window.onscroll = function() {
|
||||||
|
loadOnView();
|
||||||
|
};
|
||||||
|
window.onresize = function() {
|
||||||
|
loadOnView();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
document.onscroll = function() {
|
||||||
|
if (document.body.scrollTop > 300 || document.documentElement.scrollTop > 20) {
|
||||||
|
document.querySelector('.jumpUp').classList = 'jumpUp jumpUp--show';
|
||||||
|
} else {
|
||||||
|
document.querySelector('.jumpUp').classList = 'jumpUp';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.querySelector('.jumpUp').onclick = function() {
|
||||||
|
document.body.scrollTop = 0;
|
||||||
|
document.documentElement.scrollTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function uploadFile(){
|
function uploadFile(){
|
||||||
// AJAX takes control of subby form
|
// AJAX takes control of subby form
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
{% extends 'layout.html' %}
|
|
||||||
|
|
||||||
{% block nav_groups %}navigation-item__selected{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="banner">
|
|
||||||
<img src="{{ url_for('static', filename='images/bg.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
|
|
||||||
<span></span>
|
|
||||||
|
|
||||||
<div class="banner-content">
|
|
||||||
{% block banner_subtitle%}{% endblock %}
|
|
||||||
<h1>Groups</h1>
|
|
||||||
<p>gwa gwa</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gallery-grid">
|
|
||||||
{% for group in groups %}
|
|
||||||
<a id="group-{{ group['id'] }}" class="gallery-item" href="/group/{{ group['id'] }}">
|
|
||||||
<span>
|
|
||||||
<p>{{ group['id'] }}</p>
|
|
||||||
<h2><span class="time">{{ group['created_at'] }}</span></h2>
|
|
||||||
</span>
|
|
||||||
<img
|
|
||||||
data-src="{{ group['file_name'] }}"
|
|
||||||
onload="imgFade(this)"
|
|
||||||
style="opacity:0;"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<form action="/group" method="post" enctype="multipart/form-data">
|
|
||||||
<input type="text" name="name" placeholder="name">
|
|
||||||
<input type="text" name="description" placeholder="description">
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
</form>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block script %}
|
|
||||||
<script>
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
60
gallery/templates/groups/group.html
Normal file
60
gallery/templates/groups/group.html
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block nav_groups %}navigation-item__selected{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="banner">
|
||||||
|
{% if images %}
|
||||||
|
<img
|
||||||
|
src="/api/uploads/{{ images.0.file_name }}?w=1920&h=1080"
|
||||||
|
onload="imgFade(this)"
|
||||||
|
style="opacity:0; background-color:rgb({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }})"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style="background-image: linear-gradient(to right, rgb({{ images.0.image_colours.0.0 }}, {{ images.0.image_colours.0.1 }}, {{ images.0.image_colours.0.2 }}), transparent)"
|
||||||
|
></span>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ url_for('static', filename='images/bg.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
|
<span></span>
|
||||||
|
{% endif %}
|
||||||
|
<div class="banner-content">
|
||||||
|
<p>{{ group.description }}</p>
|
||||||
|
<h1>{{ group.name }}</h1>
|
||||||
|
<p>{{ images|length }} Images</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="/api/group/modify" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="text" name="group_id" placeholder="group id" value="{{ group.id }}">
|
||||||
|
<input type="text" name="images" placeholder="image id">
|
||||||
|
<input type="text" name="action" placeholder="add/remove" value="add">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if images %}
|
||||||
|
<div class="gallery-grid">
|
||||||
|
{% for image in images %}
|
||||||
|
<a id="image-{{ image.id }}" class="gallery-item" href="{{ url_for('group.group_post', group_id=group.id, image_id=image.id) }}" style="background-color: rgb({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }})">
|
||||||
|
<span>
|
||||||
|
<p></p>
|
||||||
|
<h2><span class="time">{{ image.created_at }}</span></h2>
|
||||||
|
</span>
|
||||||
|
<img data-src="{{ image.file_name }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="big-text">
|
||||||
|
<h1>No image!</h1>
|
||||||
|
{% if g.user %}
|
||||||
|
<p>You can get started by uploading an image!</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Login to start uploading images!</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script></script>
|
||||||
|
{% endblock %}
|
52
gallery/templates/groups/list.html
Normal file
52
gallery/templates/groups/list.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block nav_groups %}navigation-item__selected{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="banner">
|
||||||
|
<img src="{{ url_for('static', filename='images/bg.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
|
<span></span>
|
||||||
|
|
||||||
|
<div class="banner-content">
|
||||||
|
<p>{{ config.WEBSITE.motto }}</p>
|
||||||
|
<h1>Groups</h1>
|
||||||
|
<p>{{ groups|length }} Groups</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="/api/group/create" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="text" name="name" placeholder="name">
|
||||||
|
<input type="text" name="description" placeholder="description">
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if groups %}
|
||||||
|
<div class="gallery-grid">
|
||||||
|
{% for group in groups %}
|
||||||
|
<a id="group-{{ group.id }}" class="gallery-item" href="{{ url_for('group.group', group_id=group.id) }}">
|
||||||
|
<span>
|
||||||
|
<h2>{{ group.name }}</h2>
|
||||||
|
</span>
|
||||||
|
{% if group.thumbnail %}
|
||||||
|
<img data-src="{{ group.thumbnail }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ url_for('static', filename='images/error.png') }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="big-text">
|
||||||
|
<h1>No image groups!</h1>
|
||||||
|
{% if g.user %}
|
||||||
|
<p>You can get started by creating a new image group!</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Login to get started!</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block script %}
|
||||||
|
<script></script>
|
||||||
|
{% endblock %}
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<img src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000" onload="imgFade(this)" style="opacity:0;"/>
|
<img src="/api/uploads/{{ image.file_name }}?w=1000&h=1000" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
<span style="background-image: linear-gradient(to top, rgba({{ image['image_colours'][0][0] }}, {{ image['image_colours'][0][1] }}, {{ image['image_colours'][0][2] }}, 1), transparent);"></span>
|
<span style="background-image: linear-gradient(to top, rgba({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }}, 1), transparent);"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-fullscreen">
|
<div class="image-fullscreen">
|
||||||
|
@ -15,18 +15,18 @@
|
||||||
<div class="image-grid">
|
<div class="image-grid">
|
||||||
<div class="image-container" id="image-container">
|
<div class="image-container" id="image-container">
|
||||||
<img
|
<img
|
||||||
src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000"
|
src="/api/uploads/{{ image.file_name }}?w=1000&h=1000"
|
||||||
onload="imgFade(this)" style="opacity:0;"
|
onload="imgFade(this)" style="opacity:0;"
|
||||||
onerror="this.src='/static/images/error.png'"
|
onerror="this.src='/static/images/error.png'"
|
||||||
width="{{ exif['File']['Width']['raw'] }}"
|
width="{{ image.image_exif.File.Width.raw }}"
|
||||||
height="{{ exif['File']['Height']['raw'] }}"
|
height="{{ image.image_exif.File.Height.raw }}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pill-row" id="image-tools">
|
<div class="pill-row" id="image-tools">
|
||||||
{% if next_id %}
|
{% if next_url %}
|
||||||
<div>
|
<div>
|
||||||
<a class="pill-item" href="{{ url_for('gallery.image', image_id=next_id) }}">
|
<a class="pill-item" href="{{ next_url }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
|
||||||
<path d="M3.414 7.657l3.95 3.95A1 1 0 0 1 5.95 13.02L.293 7.364a.997.997 0 0 1 0-1.414L5.95.293a1 1 0 1 1 1.414 1.414l-3.95 3.95H13a1 1 0 0 1 0 2H3.414z"></path>
|
<path d="M3.414 7.657l3.95 3.95A1 1 0 0 1 5.95 13.02L.293 7.364a.997.997 0 0 1 0-1.414L5.95.293a1 1 0 1 1 1.414 1.414l-3.95 3.95H13a1 1 0 0 1 0 2H3.414z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,48,88H208a8,8,0,0,1,5.66,13.66Z"></path></svg>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<a class="pill-item" id="img-download" href="/api/uploads/{{ image['file_name'] }}" download>
|
<a class="pill-item" id="img-download" href="/api/uploads/{{ image.file_name }}" download>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z" opacity="0.2"></path><path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M232,136v64a8,8,0,0,1-8,8H32a8,8,0,0,1-8-8V136a8,8,0,0,1,8-8H224A8,8,0,0,1,232,136Z" opacity="0.2"></path><path d="M240,136v64a16,16,0,0,1-16,16H32a16,16,0,0,1-16-16V136a16,16,0,0,1,16-16H72a8,8,0,0,1,0,16H32v64H224V136H184a8,8,0,0,1,0-16h40A16,16,0,0,1,240,136Zm-117.66-2.34a8,8,0,0,0,11.32,0l48-48a8,8,0,0,0-11.32-11.32L136,108.69V24a8,8,0,0,0-16,0v84.69L85.66,74.34A8,8,0,0,0,74.34,85.66ZM200,168a12,12,0,1,0-12,12A12,12,0,0,0,200,168Z"></path></svg>
|
||||||
<span class="tool-tip">
|
<span class="tool-tip">
|
||||||
Download
|
Download
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% if g.user['id'] == image['author_id'] %}
|
{% if image.author_id == g.user.id %}
|
||||||
<div>
|
<div>
|
||||||
<button class="pill-item pill__critical" id="img-delete">
|
<button class="pill-item pill__critical" id="img-delete">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M200,56V208a8,8,0,0,1-8,8H64a8,8,0,0,1-8-8V56Z" opacity="0.2"></path><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M200,56V208a8,8,0,0,1-8,8H64a8,8,0,0,1-8-8V56Z" opacity="0.2"></path><path d="M216,48H176V40a24,24,0,0,0-24-24H104A24,24,0,0,0,80,40v8H40a8,8,0,0,0,0,16h8V208a16,16,0,0,0,16,16H192a16,16,0,0,0,16-16V64h8a8,8,0,0,0,0-16ZM96,40a8,8,0,0,1,8-8h48a8,8,0,0,1,8,8v8H96Zm96,168H64V64H192ZM112,104v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Zm48,0v64a8,8,0,0,1-16,0V104a8,8,0,0,1,16,0Z"></path></svg>
|
||||||
|
@ -78,9 +78,9 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if prev_id %}
|
{% if prev_url %}
|
||||||
<div>
|
<div>
|
||||||
<a class="pill-item" href="{{ url_for('gallery.image', image_id=prev_id) }}">
|
<a class="pill-item" href="{{ prev_url }}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
|
||||||
<path d="M10.586 5.657l-3.95-3.95A1 1 0 0 1 8.05.293l5.657 5.657a.997.997 0 0 1 0 1.414L8.05 13.021a1 1 0 1 1-1.414-1.414l3.95-3.95H1a1 1 0 1 1 0-2h9.586z"></path>
|
<path d="M10.586 5.657l-3.95-3.95A1 1 0 0 1 8.05.293l5.657 5.657a.997.997 0 0 1 0 1.414L8.05 13.021a1 1 0 1 1-1.414-1.414l3.95-3.95H1a1 1 0 1 1 0-2h9.586z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
@ -94,23 +94,23 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-container" id="image-info">
|
<div class="info-container" id="image-info">
|
||||||
{% if image['post_description'] %}
|
{% if image.post_description %}
|
||||||
<div class="info-tab">
|
<div class="info-tab">
|
||||||
<div class="info-header">
|
<div class="info-header">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#e8e3e3" viewBox="0 0 256 256"><path d="M224,56V200a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H216A8,8,0,0,1,224,56Z" opacity="0.2"></path><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM184,96a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,96Zm0,32a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,128Zm0,32a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,160Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M224,56V200a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H216A8,8,0,0,1,224,56Z" opacity="0.2"></path><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM184,96a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,96Zm0,32a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,128Zm0,32a8,8,0,0,1-8,8H80a8,8,0,0,1,0-16h96A8,8,0,0,1,184,160Z"></path></svg>
|
||||||
<h2>Description</h2>
|
<h2>Description</h2>
|
||||||
<svg class="collapse-indicator" xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
<svg class="collapse-indicator" xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
||||||
<path d="M7.071 5.314l4.95-4.95a1 1 0 1 1 1.414 1.414L7.778 7.435a1 1 0 0 1-1.414 0L.707 1.778A1 1 0 1 1 2.121.364l4.95 4.95z"></path>
|
<path d="M7.071 5.314l4.95-4.95a1 1 0 1 1 1.414 1.414L7.778 7.435a1 1 0 0 1-1.414 0L.707 1.778A1 1 0 1 1 2.121.364l4.95 4.95z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-table">
|
<div class="info-table">
|
||||||
<p>{{ image['post_description'] }}</p>
|
<p>{{ image.post_description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="info-tab">
|
<div class="info-tab">
|
||||||
<div class="info-header">
|
<div class="info-header">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#e8e3e3" viewBox="0 0 256 256"><path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path><path d="M144,176a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176Zm88-48A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128ZM124,96a12,12,0,1,0-12-12A12,12,0,0,0,124,96Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a96,96,0,1,1-96-96A96,96,0,0,1,224,128Z" opacity="0.2"></path><path d="M144,176a8,8,0,0,1-8,8,16,16,0,0,1-16-16V128a8,8,0,0,1,0-16,16,16,0,0,1,16,16v40A8,8,0,0,1,144,176Zm88-48A104,104,0,1,1,128,24,104.11,104.11,0,0,1,232,128Zm-16,0a88,88,0,1,0-88,88A88.1,88.1,0,0,0,216,128ZM124,96a12,12,0,1,0-12-12A12,12,0,0,0,124,96Z"></path></svg>
|
||||||
<h2>Info</h2>
|
<h2>Info</h2>
|
||||||
<svg class="collapse-indicator" xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
<svg class="collapse-indicator" xmlns="http://www.w3.org/2000/svg" viewBox="-5 -8 24 24" fill="currentColor">
|
||||||
<path d="M7.071 5.314l4.95-4.95a1 1 0 1 1 1.414 1.414L7.778 7.435a1 1 0 0 1-1.414 0L.707 1.778A1 1 0 1 1 2.121.364l4.95 4.95z"></path>
|
<path d="M7.071 5.314l4.95-4.95a1 1 0 1 1 1.414 1.414L7.778 7.435a1 1 0 0 1-1.414 0L.707 1.778A1 1 0 1 1 2.121.364l4.95 4.95z"></path>
|
||||||
|
@ -124,21 +124,35 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Author</td>
|
<td>Author</td>
|
||||||
<td>{{ image['author_username'] }}</td>
|
<td>{{ image.author_username }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Upload date</td>
|
<td>Upload date</td>
|
||||||
<td><span class="time">{{ image['created_at'] }}</span></td>
|
<td><span class="time">{{ image.created_at }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="img-colours">
|
<div class="img-colours">
|
||||||
{% for col in image.image_colours %}
|
{% for col in image.image_colours %}
|
||||||
<span style="background-color: rgb({{col[0]}}, {{col[1]}}, {{col[2]}})"></span>
|
<span style="background-color: rgb({{col.0}}, {{col.1}}, {{col.2}})"></span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="img-groups">
|
||||||
|
{% for group in image.groups %}
|
||||||
|
<a href="/group/{{ group.id }}" class="tag-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M224,88V200.89a7.11,7.11,0,0,1-7.11,7.11H40a8,8,0,0,1-8-8V64a8,8,0,0,1,8-8H93.33a8,8,0,0,1,4.8,1.6l27.74,20.8a8,8,0,0,0,4.8,1.6H216A8,8,0,0,1,224,88Z" opacity="0.2"></path><path d="M216,72H130.67L102.93,51.2a16.12,16.12,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V200a16,16,0,0,0,16,16H216.89A15.13,15.13,0,0,0,232,200.89V88A16,16,0,0,0,216,72Zm0,128H40V64H93.33l27.74,20.8a16.12,16.12,0,0,0,9.6,3.2H216Z"></path></svg>
|
||||||
|
{{ group['name'] }}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% if image.author_id == g.user.id %}
|
||||||
|
<button class="tag-icon" id="#img-group">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"></path></svg>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for tag in exif %}
|
</div>
|
||||||
|
{% for tag in image.image_exif %}
|
||||||
<div class="info-tab">
|
<div class="info-tab">
|
||||||
<div class="info-header">
|
<div class="info-header">
|
||||||
{% if tag == 'Photographer' %}
|
{% if tag == 'Photographer' %}
|
||||||
|
@ -163,17 +177,17 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="info-table">
|
<div class="info-table">
|
||||||
<table>
|
<table>
|
||||||
{% for subtag in exif[tag] %}
|
{% for subtag in image.image_exif[tag] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ subtag }}</td>
|
<td>{{ subtag }}</td>
|
||||||
{% if exif[tag][subtag]['formatted'] %}
|
{% if image.image_exif[tag][subtag]['formatted'] %}
|
||||||
{% if exif[tag][subtag]['type'] == 'date' %}
|
{% if image.image_exif[tag][subtag]['type'] == 'date' %}
|
||||||
<td><span class="time">{{exif[tag][subtag]['formatted']}}</span></td>
|
<td><span class="time">{{ image.image_exif[tag][subtag]['formatted'] }}</span></td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td>{{exif[tag][subtag]['formatted']}}</td>
|
<td>{{ image.image_exif[tag][subtag]['formatted'] }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif exif[tag][subtag]['raw'] %}
|
{% elif image.image_exif[tag][subtag]['raw'] %}
|
||||||
<td>{{exif[tag][subtag]['raw']}}</td>
|
<td>{{ image.image_exif[tag][subtag]['raw'] }}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="empty-table">Oops, an error</td>
|
<td class="empty-table">Oops, an error</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -213,7 +227,7 @@
|
||||||
$('.image-fullscreen').addClass('image-fullscreen__active');
|
$('.image-fullscreen').addClass('image-fullscreen__active');
|
||||||
|
|
||||||
if ($('.image-fullscreen img').attr('src') == '') {
|
if ($('.image-fullscreen img').attr('src') == '') {
|
||||||
$('.image-fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}');
|
$('.image-fullscreen img').attr('src', '/api/uploads/{{ image.file_name }}');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -235,18 +249,14 @@
|
||||||
'DESTRUCTION!!!!!!',
|
'DESTRUCTION!!!!!!',
|
||||||
'This will delete the image and all of its data!!! This action is irreversible!!!!! Are you sure you want to do this?????',
|
'This will delete the image and all of its data!!! This action is irreversible!!!!! Are you sure you want to do this?????',
|
||||||
'<button class="pop-up__btn pop-up__btn-critical-fill" onclick="deleteImage()">Dewww eeeet!</button>',
|
'<button class="pop-up__btn pop-up__btn-critical-fill" onclick="deleteImage()">Dewww eeeet!</button>',
|
||||||
'<img src="/api/uploads/{{ image['file_name'] }}?w=1000&h=1000" />'
|
'<img src="/api/uploads/{{ image.file_name }}?w=1000&h=1000" />'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
$('#img-edit').click(function() {
|
|
||||||
window.location.href = '/image/{{ image['id'] }}/edit';
|
|
||||||
});
|
|
||||||
|
|
||||||
function deleteImage() {
|
function deleteImage() {
|
||||||
popupDissmiss();
|
popupDissmiss();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/api/remove/{{ image['id'] }}',
|
url: '{{ url_for('api.delete_image', image_id=image['id']) }}',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
data: {
|
data: {
|
||||||
action: 'delete'
|
action: 'delete'
|
||||||
|
@ -259,6 +269,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#img-edit').click(function() {
|
||||||
|
window.location.href = '/image/{{ image.id }}/edit';
|
||||||
|
});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -8,53 +8,45 @@
|
||||||
<span></span>
|
<span></span>
|
||||||
|
|
||||||
<div class="banner-content">
|
<div class="banner-content">
|
||||||
<p>{{ motto }}</p>
|
<p>{{ config.WEBSITE.motto }}</p>
|
||||||
<h1>{{ name }}</h1>
|
<h1>{{ config.WEBSITE.name }}</h1>
|
||||||
<p>Serving {{ image_count }} images</p>
|
<p>Serving {{ images|length }} images</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if images %}
|
||||||
<div class="gallery-grid">
|
<div class="gallery-grid">
|
||||||
{% for image in images %}
|
{% for image in images %}
|
||||||
<a id="image-{{ image['id'] }}" class="gallery-item" href="/image/{{ image['id'] }}" style="background-color: rgb({{ image['image_colours'][0][0] }}, {{ image['image_colours'][0][1] }}, {{ image['image_colours'][0][2] }})">
|
<a id="image-{{ image.id }}" class="gallery-item" href="/image/{{ image.id }}" style="background-color: rgb({{ image.image_colours.0.0 }}, {{ image.image_colours.0.1 }}, {{ image.image_colours.0.2 }})">
|
||||||
<span>
|
<span>
|
||||||
<p></p>
|
<p></p>
|
||||||
<h2><span class="time">{{ image['created_at'] }}</span></h2>
|
<h2><span class="time">{{ image.created_at }}</span></h2>
|
||||||
</span>
|
</span>
|
||||||
<img
|
<img data-src="{{ image.file_name }}" onload="imgFade(this)" style="opacity:0;"/>
|
||||||
data-src="{{ image['file_name'] }}"
|
|
||||||
onload="imgFade(this)"
|
|
||||||
style="opacity:0;"
|
|
||||||
/>
|
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="big-text">
|
||||||
|
<h1>No image!</h1>
|
||||||
|
{% if g.user %}
|
||||||
|
<p>You can get started by uploading an image!</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Login to start uploading images!</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<footer>
|
||||||
|
<a>V{{ config['APP_VERSION'] }}</a>
|
||||||
|
<p>Rights reserved to {{ config['ADMIN']['name'] }}</p>
|
||||||
|
</footer>
|
||||||
|
-->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script>
|
<script>
|
||||||
function loadOnView() {
|
|
||||||
var images = document.querySelectorAll('.gallery-item img');
|
|
||||||
|
|
||||||
for (var i = 0; i < images.length; i++) {
|
|
||||||
var image = images[i];
|
|
||||||
if (image.getBoundingClientRect().top < window.innerHeight && image.getBoundingClientRect().bottom > 0) {
|
|
||||||
if (!image.src) {
|
|
||||||
image.src = `/api/uploads/${image.getAttribute('data-src')}?w=500&h=500`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.onload = function() {
|
|
||||||
loadOnView();
|
|
||||||
};
|
|
||||||
window.onscroll = function() {
|
|
||||||
loadOnView();
|
|
||||||
};
|
|
||||||
window.onresize = function() {
|
|
||||||
loadOnView();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (document.referrer.includes('image')) {
|
if (document.referrer.includes('image')) {
|
||||||
try {
|
try {
|
||||||
var referrerId = document.referrer.split('/').pop();
|
var referrerId = document.referrer.split('/').pop();
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{url_for('gallery.groups')}}" class="navigation-item {% block nav_groups %}{% endblock %}">
|
<a href="{{url_for('group.groups')}}" class="navigation-item {% block nav_groups %}{% endblock %}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M208,88v24H146.42a8.07,8.07,0,0,0-4.44,1.34l-20,13.32a8.07,8.07,0,0,1-4.44,1.34H69.42A8,8,0,0,0,62,133L32,208V64a8,8,0,0,1,8-8H93.33a8,8,0,0,1,4.8,1.6l27.74,20.8a8,8,0,0,0,4.8,1.6H200A8,8,0,0,1,208,88Z" opacity="0.2"></path><path d="M245,110.64A16,16,0,0,0,232,104H216V88a16,16,0,0,0-16-16H130.67L102.94,51.2a16.14,16.14,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V208h0a8,8,0,0,0,8,8H211.1a8,8,0,0,0,7.59-5.47l28.49-85.47A16.05,16.05,0,0,0,245,110.64ZM93.34,64l27.73,20.8a16.12,16.12,0,0,0,9.6,3.2H200v16H146.43a16,16,0,0,0-8.88,2.69l-20,13.31H69.42a15.94,15.94,0,0,0-14.86,10.06L40,166.46V64Zm112,136H43.82l25.6-64h48.16a16,16,0,0,0,8.88-2.69l20-13.31H232Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 256 256"><path d="M208,88v24H146.42a8.07,8.07,0,0,0-4.44,1.34l-20,13.32a8.07,8.07,0,0,1-4.44,1.34H69.42A8,8,0,0,0,62,133L32,208V64a8,8,0,0,1,8-8H93.33a8,8,0,0,1,4.8,1.6l27.74,20.8a8,8,0,0,0,4.8,1.6H200A8,8,0,0,1,208,88Z" opacity="0.2"></path><path d="M245,110.64A16,16,0,0,0,232,104H216V88a16,16,0,0,0-16-16H130.67L102.94,51.2a16.14,16.14,0,0,0-9.6-3.2H40A16,16,0,0,0,24,64V208h0a8,8,0,0,0,8,8H211.1a8,8,0,0,0,7.59-5.47l28.49-85.47A16.05,16.05,0,0,0,245,110.64ZM93.34,64l27.73,20.8a16.12,16.12,0,0,0,9.6,3.2H200v16H146.43a16,16,0,0,0-8.88,2.69l-20,13.31H69.42a15.94,15.94,0,0,0-14.86,10.06L40,166.46V64Zm112,136H43.82l25.6-64h48.16a16,16,0,0,0,8.88-2.69l20-13.31H232Z"></path></svg>
|
||||||
<span>
|
<span>
|
||||||
Groups
|
Groups
|
||||||
|
@ -97,11 +97,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
{% block content %}
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<div class="upload-panel">
|
<div class="upload-panel">
|
||||||
<span class="click-off" onclick="closeUploadTab()"></span>
|
<span class="click-off" onclick="closeUploadTab()"></span>
|
||||||
|
@ -119,6 +114,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
24
gallery/themes/default/components/elements/tags.sass
Normal file
24
gallery/themes/default/components/elements/tags.sass
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
.tag-icon
|
||||||
|
margin: 0
|
||||||
|
padding: 0.25rem 0.5rem
|
||||||
|
|
||||||
|
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: center
|
||||||
|
gap: 0.25rem
|
||||||
|
|
||||||
|
font-size: 1rem
|
||||||
|
font-weight: 500
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
|
border-radius: $rad-inner
|
||||||
|
background-color: $primary
|
||||||
|
color: $black
|
||||||
|
border: none
|
||||||
|
|
||||||
|
cursor: pointer
|
||||||
|
|
||||||
|
svg
|
||||||
|
width: 1.15rem
|
||||||
|
height: 1.15rem
|
|
@ -1,11 +1,11 @@
|
||||||
.upload-panel
|
.upload-panel
|
||||||
position: fixed
|
position: fixed
|
||||||
top: 0
|
left: 3.5rem
|
||||||
left: 0
|
bottom: 0
|
||||||
|
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
width: 100%
|
width: calc(100% - 3.5rem)
|
||||||
height: 100vh
|
height: 100vh
|
||||||
|
|
||||||
background-color: rgba($black, 0)
|
background-color: rgba($black, 0)
|
||||||
|
@ -98,8 +98,8 @@
|
||||||
padding: 0.5rem
|
padding: 0.5rem
|
||||||
|
|
||||||
position: absolute
|
position: absolute
|
||||||
top: 0
|
bottom: 0
|
||||||
left: calc(-400px + 3.5rem)
|
left: -400px
|
||||||
|
|
||||||
width: 400px
|
width: 400px
|
||||||
height: 100%
|
height: 100%
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
|
|
||||||
z-index: +2
|
z-index: +2
|
||||||
|
|
||||||
transition: left 0.25s cubic-bezier(0.76, 0, 0.17, 1), opacity 0.25s cubic-bezier(0.76, 0, 0.17, 1)
|
transition: left 0.25s cubic-bezier(0.76, 0, 0.17, 1), bottom 0.25s cubic-bezier(0.76, 0, 0.17, 1), opacity 0.25s cubic-bezier(0.76, 0, 0.17, 1)
|
||||||
|
|
||||||
.upload-jobs
|
.upload-jobs
|
||||||
display: flex
|
display: flex
|
||||||
|
@ -213,7 +213,27 @@
|
||||||
background-color: rgba($black, 0.5)
|
background-color: rgba($black, 0.5)
|
||||||
|
|
||||||
.container
|
.container
|
||||||
left: 3.5rem
|
left: 0
|
||||||
opacity: 1
|
opacity: 1
|
||||||
|
|
||||||
|
@media (max-width: $breakpoint)
|
||||||
|
.upload-panel
|
||||||
|
width: 100%
|
||||||
|
height: calc(100vh - 3.5rem)
|
||||||
|
|
||||||
|
left: 0
|
||||||
|
bottom: 3.5rem
|
||||||
|
|
||||||
|
.container
|
||||||
|
padding: 1rem
|
||||||
|
|
||||||
|
width: 100%
|
||||||
|
height: calc(100% - 10rem)
|
||||||
|
|
||||||
|
left: 0
|
||||||
|
bottom: calc(-100vh + 3.5rem)
|
||||||
|
|
||||||
|
&.open
|
||||||
|
.container
|
||||||
|
left: 0
|
||||||
|
bottom: 0
|
|
@ -44,7 +44,7 @@
|
||||||
transform: scale(1.05) // scale up
|
transform: scale(1.05) // scale up
|
||||||
transition: all 0.3s cubic-bezier(.79, .14, .15, .86)
|
transition: all 0.3s cubic-bezier(.79, .14, .15, .86)
|
||||||
|
|
||||||
h2
|
> h2
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
opacity: 0 // hide
|
opacity: 0 // hide
|
||||||
transition: all 0.2s ease-in-out
|
transition: all 0.2s ease-in-out
|
||||||
|
|
||||||
p
|
> p
|
||||||
margin: 0
|
margin: 0
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
opacity: 1
|
opacity: 1
|
||||||
transform: scale(1)
|
transform: scale(1)
|
||||||
|
|
||||||
h2, p
|
> h2, > p
|
||||||
opacity: 1
|
opacity: 1
|
||||||
|
|
||||||
img
|
img
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
|
gap: 0.5rem
|
||||||
|
|
||||||
background-color: $black
|
background-color: $black
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@
|
||||||
|
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
gap: 0.5rem
|
gap: 1rem
|
||||||
|
|
||||||
color: $white
|
color: $white
|
||||||
|
|
||||||
|
@ -163,9 +164,6 @@
|
||||||
padding-bottom: 0
|
padding-bottom: 0
|
||||||
|
|
||||||
.img-colours
|
.img-colours
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
display: flex
|
display: flex
|
||||||
|
@ -182,5 +180,11 @@
|
||||||
justify-content: center
|
justify-content: center
|
||||||
align-items: center
|
align-items: center
|
||||||
|
|
||||||
border-radius: $rad
|
border-radius: $rad-inner
|
||||||
border: 1px solid $white
|
// border: 1px solid $white
|
||||||
|
|
||||||
|
.img-groups
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
display: flex
|
||||||
|
gap: 0.5rem
|
|
@ -51,7 +51,6 @@
|
||||||
padding: 0
|
padding: 0
|
||||||
|
|
||||||
.info-container
|
.info-container
|
||||||
gap: 0.5rem
|
|
||||||
background: transparent
|
background: transparent
|
||||||
|
|
||||||
.info-header
|
.info-header
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
@import "components/elements/notification"
|
@import "components/elements/notification"
|
||||||
@import "components/elements/pop-up"
|
@import "components/elements/pop-up"
|
||||||
@import "components/elements/upload-panel"
|
@import "components/elements/upload-panel"
|
||||||
|
@import "components/elements/tags"
|
||||||
|
|
||||||
@import "components/navigation"
|
@import "components/navigation"
|
||||||
@import "components/banner"
|
@import "components/banner"
|
||||||
|
@ -46,6 +47,30 @@ html, body
|
||||||
background-color: $white
|
background-color: $white
|
||||||
color: $black
|
color: $black
|
||||||
|
|
||||||
|
.big-text
|
||||||
|
height: 60vh
|
||||||
|
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
color: $black
|
||||||
|
|
||||||
|
h1
|
||||||
|
margin: 0 2rem
|
||||||
|
|
||||||
|
font-size: 4rem
|
||||||
|
font-weight: 900
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
p
|
||||||
|
margin: 0 2rem
|
||||||
|
|
||||||
|
max-width: 40rem
|
||||||
|
font-size: 1rem
|
||||||
|
font-weight: 400
|
||||||
|
text-align: center
|
||||||
|
|
||||||
.error-page
|
.error-page
|
||||||
width: 100%
|
width: 100%
|
||||||
|
@ -77,10 +102,50 @@ html, body
|
||||||
|
|
||||||
color: $white
|
color: $white
|
||||||
|
|
||||||
|
footer
|
||||||
|
margin: 0
|
||||||
|
padding: 0.25rem 1rem
|
||||||
|
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
align-items: center
|
||||||
|
gap: 1rem
|
||||||
|
|
||||||
|
background-color: $white
|
||||||
|
|
||||||
|
p
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
font-size: 0.75rem
|
||||||
|
font-weight: 400
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
color: $black
|
||||||
|
|
||||||
|
a
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
font-size: 0.75rem
|
||||||
|
font-weight: 400
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
color: $primary
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: $breakpoint)
|
@media (max-width: $breakpoint)
|
||||||
.wrapper
|
.wrapper
|
||||||
padding: 0 0 3.5rem 0
|
padding: 0 0 3.5rem 0
|
||||||
|
|
||||||
|
.big-text
|
||||||
|
height: calc(75vh - 3.5rem)
|
||||||
|
|
||||||
|
h1
|
||||||
|
font-size: 3.5rem
|
||||||
|
|
||||||
.error-page
|
.error-page
|
||||||
height: calc(100vh - 3.5rem)
|
height: calc(100vh - 3.5rem)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue