Fix image ICC profile getting lost on compression

Fix setup not holding all required modules
Add temporary theme to login and upload page
Other random bug fixes
This commit is contained in:
Michał 2023-01-17 22:13:52 +00:00
parent 4efd9a04ee
commit 0414cda5d3
14 changed files with 509 additions and 243 deletions

View file

@ -5,21 +5,13 @@ print("""
| |_| | | | | | |_| | |__| __/ (_| \\__ \\ | |_| | | | | | |_| | |__| __/ (_| \\__ \\
\\___/|_| |_|_|\\__, |_____\\___|\\__, |___/ \\___/|_| |_|_|\\__, |_____\\___|\\__, |___/
|___/ |___/ |___/ |___/
Created by Fluffy Bean - Version 140123 Created by Fluffy Bean - Version 170123
""") """)
# Import base packages from flask import Flask, render_template
import time
import sys
import os
import yaml
# Import flask
from flask import *
from werkzeug.utils import secure_filename
# Import dotenv
from dotenv import load_dotenv from dotenv import load_dotenv
import yaml
import os
def create_app(test_config=None): def create_app(test_config=None):
# create and configure the app # create and configure the app
@ -27,6 +19,7 @@ def create_app(test_config=None):
# Get environment variables # Get environment variables
load_dotenv(os.path.join(app.root_path, 'user', '.env')) load_dotenv(os.path.join(app.root_path, 'user', '.env'))
print("Loaded env")
# Get config file # Get config file
with open(os.path.join(app.root_path, 'user', 'conf.yml'), 'r') as f: with open(os.path.join(app.root_path, 'user', 'conf.yml'), 'r') as f:

View file

@ -24,11 +24,13 @@ def uploads(file, quality):
img = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], secure_filename(file))) img = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], secure_filename(file)))
img_ext = os.path.splitext(secure_filename(file))[-1].lower().replace('.', '') img_ext = os.path.splitext(secure_filename(file))[-1].lower().replace('.', '')
img_ext = set_ext[img_ext] img_ext = set_ext[img_ext]
img_icc = img.info.get("icc_profile") # Get ICC profile as it alters colours
# Resize image and orientate correctly # Resize image and orientate correctly
img.thumbnail((quality, quality), Image.LANCZOS) img.thumbnail((quality, quality), Image.LANCZOS)
img = ImageOps.exif_transpose(img) img = ImageOps.exif_transpose(img)
img.save(buff, img_ext) img.save(buff, img_ext, icc_profile=img_icc)
img.close()
# Seek to beginning of buffer and return # Seek to beginning of buffer and return
buff.seek(0) buff.seek(0)

View file

@ -25,7 +25,7 @@ def image(id):
# Get exif data from image # Get exif data from image
try: try:
file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'original', image['file_name'])) file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], image['file_name']))
raw_exif = file.getexif() raw_exif = file.getexif()
human_exif = {} human_exif = {}

View file

@ -1,24 +1,43 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block header %} {% block header %}
<img src="{{ url_for('static', filename='images/leaves.jpg') }}" alt="leaves" onload="imgFade(this)" style="display: none;"/> <img src="{{ url_for('static', filename='images/background.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="app"> <div class="app">
<h1>Login</h1> <div class="login box-ui">
<div id="login" class="login"> <div class="box-ui-header">
<form method="post"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor">
<label for="username">Username</label> <path d="M3 0h10a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm2 1h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 12h2a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"></path>
<input name="username" id="username" required> </svg>
<label for="password">Password</label> <h2>Login</h2>
<input type="password" name="password" id="password" required> </div>
<input type="submit" value="Log In"> <div class="box-ui-content">
</form> {% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% for message in get_flashed_messages() %} {% endfor %}
<div class="flash">{{ message }}</div>
{% endfor %} <form method="post" class="nice-form">
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" fill="currentColor">
<path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-14a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V8a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V8a2 2 0 0 0-2-2zM5.91 16.876a8.033 8.033 0 0 1-1.58-1.232 5.57 5.57 0 0 1 2.204-1.574 1 1 0 1 1 .733 1.86c-.532.21-.993.538-1.358.946zm8.144.022a3.652 3.652 0 0 0-1.41-.964 1 1 0 1 1 .712-1.868 5.65 5.65 0 0 1 2.284 1.607 8.032 8.032 0 0 1-1.586 1.225z"></path>
</svg>
<input name="username" id="username" required>
</span>
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -2 24 24" fill="currentColor">
<path d="M2 12v6h10v-6H2zm10-2a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2V5a5 5 0 1 1 10 0v5zm-2 0V5a3 3 0 1 0-6 0v5h6zm-3 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"></path>
</svg>
<input type="password" name="password" id="password" required>
</span>
<input class="form-button" type="submit" value="Log In">
</form>
<a class="form-button faded" href="{{ url_for('auth.register') }}">Register</a>
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,24 +1,43 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block header %} {% block header %}
<img src="{{ url_for('static', filename='images/leaves.jpg') }}" alt="leaves" onload="imgFade(this)" style="display: none;"/> <img src="{{ url_for('static', filename='images/background.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="app"> <div class="app">
<h1>register</h1> <div class="register box-ui">
<div id="register" class="register"> <div class="box-ui-header">
<form method="post"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor">
<label for="username">Username</label> <path d="M3 0h10a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm2 1h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 12h2a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"></path>
<input name="username" id="username" required> </svg>
<label for="password">Password</label> <h2>Register</h2>
<input type="password" name="password" id="password" required> </div>
<input type="submit" value="Register"> <div class="box-ui-content">
</form> {% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% for message in get_flashed_messages() %} {% endfor %}
<div class="flash">{{ message }}</div>
{% endfor %} <form method="post" class="nice-form">
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" fill="currentColor">
<path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-14a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V8a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V8a2 2 0 0 0-2-2zM5.91 16.876a8.033 8.033 0 0 1-1.58-1.232 5.57 5.57 0 0 1 2.204-1.574 1 1 0 1 1 .733 1.86c-.532.21-.993.538-1.358.946zm8.144.022a3.652 3.652 0 0 0-1.41-.964 1 1 0 1 1 .712-1.868 5.65 5.65 0 0 1 2.284 1.607 8.032 8.032 0 0 1-1.586 1.225z"></path>
</svg>
<input name="username" id="username" required>
</span>
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -2 24 24" fill="currentColor">
<path d="M2 12v6h10v-6H2zm10-2a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-6a2 2 0 0 1 2-2V5a5 5 0 1 1 10 0v5zm-2 0V5a3 3 0 1 0-6 0v5h6zm-3 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"></path>
</svg>
<input type="password" name="password" id="password" required>
</span>
<input class="form-button" type="submit" value="Register">
</form>
<a class="form-button faded" href="{{ url_for('auth.login') }}">Login</a>
</div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,7 +1,7 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% block header %} {% block header %}
<img src="{{ url_for('static', filename='images/background.svg') }}" onload="imgFade(this)" style="display: none;"/> <img src="{{ url_for('static', filename='images/background.svg') }}" onload="imgFade(this)" style="opacity:0;"/>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View file

@ -8,7 +8,7 @@
<div class="image__fullscreen"> <div class="image__fullscreen">
<img <img
src="" src=""
onload="imgFade(this)" onload="imgFade(this);"
style="opacity:0;" style="opacity:0;"
/> />
</div> </div>
@ -20,6 +20,8 @@
src="/api/uploads/{{ image['file_name'] }}/1000" src="/api/uploads/{{ image['file_name'] }}/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="{{ file['width'] }}"
height="{{ file['height'] }}"
/> />
</div> </div>
<div class="img-tools"> <div class="img-tools">
@ -122,29 +124,23 @@
{% endif %} {% endif %}
</div> </div>
<script> <script>
/*
const url = new URL(window.location);
if (url.searchParams.get('i') == 'full') {
$('.image__fullscreen').addClass('image__fullscreen--active');
$('.image__fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}/0');
} else {
$('.image__fullscreen').removeClass('image__fullscreen--active');
}
*/
$('.image__fullscreen').click(function() { $('.image__fullscreen').click(function() {
$('.image__fullscreen').removeClass('image__fullscreen--active'); $('.image__fullscreen').removeClass('image__fullscreen--active');
//window.history.replaceState({}, '', `${url}`);
}); });
$('#img-fullscreen').click(function() { $('#img-fullscreen').click(function() {
$('.image__fullscreen').addClass('image__fullscreen--active'); $('.image__fullscreen').addClass('image__fullscreen--active');
$('.image__fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}/0'); if ($('.image__fullscreen img').attr('src') == '') {
//window.history.replaceState({}, '', url+'?i=full'); $('.image__fullscreen img').attr('src', '/api/uploads/{{ image['file_name'] }}/0');
}
}); });
$('#img-share').click(function() { $('#img-share').click(function() {
//navigator.clipboard.writeText(window.location.href); try {
addNotification("Copied link!", 4); navigator.clipboard.writeText(window.location.href);
addNotification("Copied link!", 4);
} catch (err) {
addNotification("Failed to copy link! Are you on HTTP?", 2);
}
}); });
$('#img-info').click(function() { $('#img-info').click(function() {

View file

@ -12,7 +12,7 @@
<a class="gallery__item" href="/image/{{ image['id'] }}"> <a class="gallery__item" href="/image/{{ image['id'] }}">
<div class="gallery__item-info"> <div class="gallery__item-info">
<p>{{ image['id'] }}</p> <p>{{ image['id'] }}</p>
<h2>{{ image['file_name'] }}</h2> <h2>{{ image['created_at'] }}</h2>
</div> </div>
<span class="gallery__item-filter"></span> <span class="gallery__item-filter"></span>
<img <img

View file

@ -26,27 +26,38 @@
<span>Groups</span> <span>Groups</span>
</a> </a>
<a href="{{url_for('gallery.upload')}}"> {% if g.user %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor"> <a href="{{url_for('gallery.upload')}}">
<path d="M8 3.414v5.642a1 1 0 1 1-2 0V3.414L4.879 4.536A1 1 0 0 1 3.464 3.12L6.293.293a1 1 0 0 1 1.414 0l2.829 2.828A1 1 0 1 1 9.12 4.536L8 3.414zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
</svg> <path d="M8 3.414v5.642a1 1 0 1 1-2 0V3.414L4.879 4.536A1 1 0 0 1 3.464 3.12L6.293.293a1 1 0 0 1 1.414 0l2.829 2.828A1 1 0 1 1 9.12 4.536L8 3.414zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path>
<span>Upload</span> </svg>
</a> <span>Upload</span>
</a>
{% endif %}
</div> </div>
<div> <div>
<a href="{{url_for('gallery.profile')}}"> {% if g.user %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" fill="currentColor"> <a href="{{url_for('gallery.profile')}}">
<path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-14a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V8a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V8a2 2 0 0 0-2-2zM5.91 16.876a8.033 8.033 0 0 1-1.58-1.232 5.57 5.57 0 0 1 2.204-1.574 1 1 0 1 1 .733 1.86c-.532.21-.993.538-1.358.946zm8.144.022a3.652 3.652 0 0 0-1.41-.964 1 1 0 1 1 .712-1.868 5.65 5.65 0 0 1 2.284 1.607 8.032 8.032 0 0 1-1.586 1.225z"></path> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" fill="currentColor">
</svg> <path d="M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-14a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V8a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V8a2 2 0 0 0-2-2zM5.91 16.876a8.033 8.033 0 0 1-1.58-1.232 5.57 5.57 0 0 1 2.204-1.574 1 1 0 1 1 .733 1.86c-.532.21-.993.538-1.358.946zm8.144.022a3.652 3.652 0 0 0-1.41-.964 1 1 0 1 1 .712-1.868 5.65 5.65 0 0 1 2.284 1.607 8.032 8.032 0 0 1-1.586 1.225z"></path>
<span>Profile</span> </svg>
</a> <span>Profile</span>
</a>
<a href="{{url_for('gallery.settings')}}"> <a href="{{url_for('gallery.settings')}}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -2 24 24" width="24" fill="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -2 24 24" width="24" fill="currentColor">
<path d="M9.815 3.094a3.467 3.467 0 0 1-2.78-1.09l-.084-.001a3.467 3.467 0 0 1-2.781 1.09 3.477 3.477 0 0 1-1.727 2.51 3.471 3.471 0 0 1 0 2.794 3.477 3.477 0 0 1 1.727 2.51 3.467 3.467 0 0 1 2.78 1.09h.084a3.467 3.467 0 0 1 2.78-1.09 3.477 3.477 0 0 1 1.727-2.51 3.471 3.471 0 0 1 0-2.794 3.477 3.477 0 0 1-1.726-2.51zM14 5.714a1.474 1.474 0 0 0 0 2.572l-.502 1.684a1.473 1.473 0 0 0-1.553 2.14l-1.443 1.122A1.473 1.473 0 0 0 8.143 14l-2.304-.006a1.473 1.473 0 0 0-2.352-.765l-1.442-1.131A1.473 1.473 0 0 0 .5 9.968L0 8.278a1.474 1.474 0 0 0 0-2.555l.5-1.69a1.473 1.473 0 0 0 1.545-2.13L3.487.77A1.473 1.473 0 0 0 5.84.005L8.143 0a1.473 1.473 0 0 0 2.358.768l1.444 1.122a1.473 1.473 0 0 0 1.553 2.14L14 5.714zm-5.812 9.198a7.943 7.943 0 0 0 2.342-.73 3.468 3.468 0 0 1-.087.215 3.477 3.477 0 0 1 1.727 2.51 3.467 3.467 0 0 1 2.78 1.09h.084a3.467 3.467 0 0 1 2.78-1.09 3.477 3.477 0 0 1 1.727-2.51 3.471 3.471 0 0 1 0-2.794 3.477 3.477 0 0 1-1.726-2.51 3.467 3.467 0 0 1-2.78-1.09h-.084l-.015.016a8.077 8.077 0 0 0 .002-2.016L16.144 6a1.473 1.473 0 0 0 2.358.768l1.444 1.122a1.473 1.473 0 0 0 1.553 2.14L22 11.714a1.474 1.474 0 0 0 0 2.572l-.502 1.684a1.473 1.473 0 0 0-1.553 2.14l-1.443 1.122a1.473 1.473 0 0 0-2.359.768l-2.304-.006a1.473 1.473 0 0 0-2.352-.765l-1.442-1.131a1.473 1.473 0 0 0-1.545-2.13l-.312-1.056zM7 10a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 8a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> <path d="M9.815 3.094a3.467 3.467 0 0 1-2.78-1.09l-.084-.001a3.467 3.467 0 0 1-2.781 1.09 3.477 3.477 0 0 1-1.727 2.51 3.471 3.471 0 0 1 0 2.794 3.477 3.477 0 0 1 1.727 2.51 3.467 3.467 0 0 1 2.78 1.09h.084a3.467 3.467 0 0 1 2.78-1.09 3.477 3.477 0 0 1 1.727-2.51 3.471 3.471 0 0 1 0-2.794 3.477 3.477 0 0 1-1.726-2.51zM14 5.714a1.474 1.474 0 0 0 0 2.572l-.502 1.684a1.473 1.473 0 0 0-1.553 2.14l-1.443 1.122A1.473 1.473 0 0 0 8.143 14l-2.304-.006a1.473 1.473 0 0 0-2.352-.765l-1.442-1.131A1.473 1.473 0 0 0 .5 9.968L0 8.278a1.474 1.474 0 0 0 0-2.555l.5-1.69a1.473 1.473 0 0 0 1.545-2.13L3.487.77A1.473 1.473 0 0 0 5.84.005L8.143 0a1.473 1.473 0 0 0 2.358.768l1.444 1.122a1.473 1.473 0 0 0 1.553 2.14L14 5.714zm-5.812 9.198a7.943 7.943 0 0 0 2.342-.73 3.468 3.468 0 0 1-.087.215 3.477 3.477 0 0 1 1.727 2.51 3.467 3.467 0 0 1 2.78 1.09h.084a3.467 3.467 0 0 1 2.78-1.09 3.477 3.477 0 0 1 1.727-2.51 3.471 3.471 0 0 1 0-2.794 3.477 3.477 0 0 1-1.726-2.51 3.467 3.467 0 0 1-2.78-1.09h-.084l-.015.016a8.077 8.077 0 0 0 .002-2.016L16.144 6a1.473 1.473 0 0 0 2.358.768l1.444 1.122a1.473 1.473 0 0 0 1.553 2.14L22 11.714a1.474 1.474 0 0 0 0 2.572l-.502 1.684a1.473 1.473 0 0 0-1.553 2.14l-1.443 1.122a1.473 1.473 0 0 0-2.359.768l-2.304-.006a1.473 1.473 0 0 0-2.352-.765l-1.442-1.131a1.473 1.473 0 0 0-1.545-2.13l-.312-1.056zM7 10a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 8a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path>
</svg> </svg>
<span>Settings</span> <span>Settings</span>
</a> </a>
{% else %}
<a href="{{url_for('auth.login')}}">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -3 24 24" fill="currentColor">
<path d="M6.641 9.828H1a1 1 0 1 1 0-2h5.641l-1.12-1.12a1 1 0 0 1 1.413-1.415L9.763 8.12a.997.997 0 0 1 0 1.415l-2.829 2.828A1 1 0 0 1 5.52 10.95l1.121-1.122zM13 0a1 1 0 0 1 1 1v16a1 1 0 0 1-2 0V1a1 1 0 0 1 1-1z"></path>
</svg>
<span>Register</span>
</a>
{% endif %}
</div> </div>
</nav> </nav>
<main> <main>
@ -85,6 +96,7 @@
function imgFade(obj) { function imgFade(obj) {
$(obj).animate({opacity: 1}, 500); $(obj).animate({opacity: 1}, 500);
$(obj).parent().css('background', 'transparent');
} }
function addNotification(text='Sample notification', type=4) { function addNotification(text='Sample notification', type=4) {
@ -144,17 +156,16 @@
// Append notification to container // Append notification to container
container.appendChild(div); container.appendChild(div);
// Remove notification after 6.9 seconds // Remove notification after 5 seconds
setTimeout(function() { setTimeout(function() {
if (div.parentNode) { if (div.parentNode) {
div.style.opacity = 0; div.classList.add('sniffle__notification--hide');
div.style.transform = 'translateX(100%)';
setTimeout(function() { setTimeout(function() {
container.removeChild(div); container.removeChild(div);
}, 500); }, 500);
} }
}, 2500); }, 5000);
} }
</script> </script>
</body> </body>

View file

@ -6,31 +6,46 @@
{% block content %} {% block content %}
<div class="app"> <div class="app">
<h1>Upload!!!!!</h1> <div class="upload box-ui">
<div id="upload" class="upload"> <div class="box-ui-header">
<form method="post" enctype="multipart/form-data" id="uploadForm"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor"> <path d="M3 0h10a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3zm0 2a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H3zm2 1h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2zm0 12h2a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2zm0-4h6a1 1 0 0 1 0 2H5a1 1 0 1 1 0-2z"></path>
<path d="M8 3.414v5.642a1 1 0 1 1-2 0V3.414L4.879 4.536A1 1 0 0 1 3.464 3.12L6.293.293a1 1 0 0 1 1.414 0l2.829 2.828A1 1 0 1 1 9.12 4.536L8 3.414zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path> </svg>
</svg> <h2>Upload!!!!!!!</h2>
<input type="file" name="file" id="file" class="input-file"/> </div>
<div class="box-ui-content">
<form method="post" class="nice-form" id="uploadForm">
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 24 24" width="24" fill="currentColor">
<path d="M8 3.414v5.642a1 1 0 1 1-2 0V3.414L4.879 4.536A1 1 0 0 1 3.464 3.12L6.293.293a1 1 0 0 1 1.414 0l2.829 2.828A1 1 0 1 1 9.12 4.536L8 3.414zM1 12h12a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"></path>
</svg>
<input type="file" name="file" id="file" class="input-file"/>
</span>
<span class="form-box">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" width="24" fill="currentColor">
<path d="M14 8.322V2H2v12h3.576l3.97-5.292A3 3 0 0 1 14 8.322zm0 3.753l-1.188-2.066a1 1 0 0 0-1.667-.101L8.076 14H14v-1.925zM14 16H2v2h12v-2zM2 0h12a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm4 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path>
</svg>
<input type="text" name="alt" placeholder="alt" id="alt"/>
</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" width="24" fill="currentColor"> <span class="form-box">
<path d="M14 8.322V2H2v12h3.576l3.97-5.292A3 3 0 0 1 14 8.322zm0 3.753l-1.188-2.066a1 1 0 0 0-1.667-.101L8.076 14H14v-1.925zM14 16H2v2h12v-2zM2 0h12a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm4 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" fill="currentColor">
</svg> <path d="M5.72 14.456l1.761-.508 10.603-10.73a.456.456 0 0 0-.003-.64l-.635-.642a.443.443 0 0 0-.632-.003L6.239 12.635l-.52 1.82zM18.703.664l.635.643c.876.887.884 2.318.016 3.196L8.428 15.561l-3.764 1.084a.901.901 0 0 1-1.11-.623.915.915 0 0 1-.002-.506l1.095-3.84L15.544.647a2.215 2.215 0 0 1 3.159.016zM7.184 1.817c.496 0 .898.407.898.909a.903.903 0 0 1-.898.909H3.592c-.992 0-1.796.814-1.796 1.817v10.906c0 1.004.804 1.818 1.796 1.818h10.776c.992 0 1.797-.814 1.797-1.818v-3.635c0-.502.402-.909.898-.909s.898.407.898.91v3.634c0 2.008-1.609 3.636-3.593 3.636H3.592C1.608 19.994 0 18.366 0 16.358V5.452c0-2.007 1.608-3.635 3.592-3.635h3.592z"></path>
<input type="text" name="alt" placeholder="alt" id="alt"/> </svg>
<input type="text" name="description" placeholder="description" id="description"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" fill="currentColor"> </span>
<path d="M5.72 14.456l1.761-.508 10.603-10.73a.456.456 0 0 0-.003-.64l-.635-.642a.443.443 0 0 0-.632-.003L6.239 12.635l-.52 1.82zM18.703.664l.635.643c.876.887.884 2.318.016 3.196L8.428 15.561l-3.764 1.084a.901.901 0 0 1-1.11-.623.915.915 0 0 1-.002-.506l1.095-3.84L15.544.647a2.215 2.215 0 0 1 3.159.016zM7.184 1.817c.496 0 .898.407.898.909a.903.903 0 0 1-.898.909H3.592c-.992 0-1.796.814-1.796 1.817v10.906c0 1.004.804 1.818 1.796 1.818h10.776c.992 0 1.797-.814 1.797-1.818v-3.635c0-.502.402-.909.898-.909s.898.407.898.91v3.634c0 2.008-1.609 3.636-3.593 3.636H3.592C1.608 19.994 0 18.366 0 16.358V5.452c0-2.007 1.608-3.635 3.592-3.635h3.592z"></path>
</svg>
<input type="text" name="description" placeholder="description" id="description"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 24 24" width="24" fill="currentColor"> <span class="form-box">
<path d="M11.586 15.071L13 13.657l1.414 1.414 6.165-6.165 1.09-3.552-2.484-2.483-1.079.336-1.598-1.598L18.591.96a2 2 0 0 1 2.008.496l2.483 2.483a2 2 0 0 1 .498 2L22.345 9.97l-7.93 7.93-2.83-2.828zM14.236.75l2.482 2.483a2 2 0 0 1 .498 2l-1.235 4.028-7.93 7.931-7.78-7.778L8.17 1.516 12.227.254a2 2 0 0 1 2.008.496zM3.1 9.414l4.95 4.95 6.164-6.165 1.09-3.552-2.484-2.483-3.585 1.115L3.1 9.414zm7.424-2.475a1.5 1.5 0 1 1 2.121-2.121 1.5 1.5 0 0 1-2.12 2.121zm6.886 1.022l.782-2.878c.45.152.755.325.917.518a1.5 1.5 0 0 1-.185 2.113c-.29.244-.795.326-1.514.247z"></path> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 24 24" width="24" fill="currentColor">
</svg> <path d="M11.586 15.071L13 13.657l1.414 1.414 6.165-6.165 1.09-3.552-2.484-2.483-1.079.336-1.598-1.598L18.591.96a2 2 0 0 1 2.008.496l2.483 2.483a2 2 0 0 1 .498 2L22.345 9.97l-7.93 7.93-2.83-2.828zM14.236.75l2.482 2.483a2 2 0 0 1 .498 2l-1.235 4.028-7.93 7.931-7.78-7.778L8.17 1.516 12.227.254a2 2 0 0 1 2.008.496zM3.1 9.414l4.95 4.95 6.164-6.165 1.09-3.552-2.484-2.483-3.585 1.115L3.1 9.414zm7.424-2.475a1.5 1.5 0 1 1 2.121-2.121 1.5 1.5 0 0 1-2.12 2.121zm6.886 1.022l.782-2.878c.45.152.755.325.917.518a1.5 1.5 0 0 1-.185 2.113c-.29.244-.795.326-1.514.247z"></path>
<input type="text" name="tags" placeholder="tags" id="tags"/> </svg>
<input type="submit" value="Upload" name="submit" id="submit"/> <input type="text" name="tags" placeholder="tags" id="tags"/>
</form> </span>
<input class="form-button" type="submit" value="Upload" name="submit" id="submit"/>
</form>
</div>
</div> </div>
</div> </div>
<script> <script>

View file

@ -4,6 +4,7 @@
@import 'ui/reset'; @import 'ui/reset';
@import 'ui/nav'; @import 'ui/nav';
@import 'ui/main'; @import 'ui/main';
@import 'ui/gallery';
@import 'ui/notification'; @import 'ui/notification';
@import 'buttons/img-tool'; @import 'buttons/img-tool';
@ -69,19 +70,177 @@
*/ */
} }
@keyframes imgLoading { .box-ui {
0% { margin: 0 auto;
background-position: 0% 50%; padding: 0;
width: 100%;
height: 100%;
max-width: 621px;
position: relative;
display: flex;
flex-direction: column;
background-color: $black200;
border-radius: $rad;
}
.box-ui-header {
margin: 0;
padding: 0.5rem;
width: 100%;
height: 2.5rem;
display: flex;
justify-content: start;
align-items: center;
gap: 0.5rem;
background-color: $black300;
border-radius: $rad $rad 0 0;
svg {
margin: 0;
padding: 0;
width: 1.25rem;
height: 1.25rem;
fill: $green;
} }
50% { h2 {
background-position: 100% 50%; margin: 0;
} padding: 0;
100% { font-family: $font-header;
background-position: 0% 50%; font-size: 1.25rem;
font-stretch: ultra-expanded;
font-weight: 600;
color: $green;
text-overflow: ellipsis;
overflow: hidden;
} }
} }
.box-ui-content {
margin: 0;
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
p {
margin: 0;
padding: 0;
font-family: $font-body;
font-size: 1rem;
font-weight: 500;
color: $white100;
text-overflow: ellipsis;
overflow: hidden;
}
}
.nice-form {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.form-box {
margin: 0;
padding: 0;
width: 100%;
height: 2rem;
display: flex;
flex-direction: row;
svg {
margin: 0;
padding: 0.3rem;
width: 2rem;
height: 2rem;
background-color: $black300;
color: $white100;
border: 1px solid $black400;
border-radius: $rad 0 0 $rad;
border-right: none;
}
input {
margin: 0;
padding: 0.5rem;
width: 100%;
height: 2rem;
font-family: $font-body;
font-size: 1rem;
font-weight: 500;
color: $white100;
background-color: $black200;
border: 1px solid $black400;
border-radius: 0 $rad $rad 0;
border-left: none;
&:focus {
outline: none;
~ svg {
color: $green;
background-color: $black200;
}
}
&::placeholder {
color: $white100;
}
}
}
.form-button {
margin: 0;
padding: 0;
width: 100%;
height: 2rem;
display: flex;
justify-content: center;
align-items: center;
font-family: $font-body;
font-size: 1rem;
font-weight: 500;
text-align: center;
text-decoration: none;
color: $white100;
background-color: $black300;
border: 1px solid $black400;
border-radius: $rad;
&:hover {
cursor: pointer;
color: $green;
}
}
.faded {
background-color: $black200;
border-color: $black200;
}
.err-warning { .err-warning {
min-height: 100vh; min-height: 100vh;
@ -114,129 +273,6 @@
} }
} }
.gallery {
margin: 0;
padding: 0;
width: 100%;
display: grid;
grid-template-columns: auto auto auto auto auto auto;
gap: 0.5rem;
.gallery__item {
margin: 0;
padding: 0;
height: auto;
position: relative;
background: linear-gradient(-45deg, $black100, $black400 40%, $black100);
background-size: 400% 400%;
border-radius: $rad;
animation: imgLoading 10s ease infinite;
box-sizing: border-box;
overflow: hidden;
&:after {
content: "";
display: block;
padding-bottom: 100%;
}
.gallery__item-info {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
left: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
background-image: linear-gradient(to bottom, #00000000, rgba($black100, 0.8));
z-index: +1;
opacity: 0; // hide
transform: scale(1.05); // scale up
transition: all 0.5s cubic-bezier(.79, .14, .15, .86);
h2 {
margin: 0;
padding: 0 1rem 0.5rem;
font-family: $font-header;
font-size: 1rem;
font-stretch: ultra-expanded;
font-weight: 600;
color: $green;
text-overflow: ellipsis;
overflow: hidden;
opacity: 0; // hide
transition: all 0.2s ease-in-out;
}
p {
margin: 0;
padding: 0 1rem 0.5rem;
font-family: $font-body;
font-size: 0.8rem;
font-weight: 500;
color: $white100;
text-overflow: ellipsis;
overflow: hidden;
opacity: 0; // hide
transition: all 0.2s ease-in-out;
}
&:hover {
opacity: 1;
transform: scale(1);
h2,
p {
opacity: 1;
}
}
}
.gallery__item-image {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
object-fit: cover;
object-position: center;
border-radius: $rad;
}
}
}
.image__fullscreen { .image__fullscreen {
margin: 0; margin: 0;
padding: 0 0 0 3.5rem; padding: 0 0 0 3.5rem;
@ -293,6 +329,8 @@
width: 100%; width: 100%;
height: auto; height: auto;
max-width: 100%;
max-height: 69vh;
position: sticky; position: sticky;
top: 0; top: 0;
@ -300,6 +338,10 @@
display: flex; display: flex;
overflow: hidden; overflow: hidden;
background: linear-gradient(-45deg, $black100, $black400 40%, $black100);
background-size: 400% 400%;
border-radius: $rad;
animation: imgLoading 10s ease infinite;
border-radius: $rad; border-radius: $rad;
box-sizing: border-box; box-sizing: border-box;
@ -308,8 +350,9 @@
margin: auto; margin: auto;
padding: 0; padding: 0;
width: auto;
height: auto;
max-width: 100%; max-width: 100%;
height: 100%;
max-height: 69vh; max-height: 69vh;
background-color: $black200; background-color: $black200;
@ -341,7 +384,7 @@
padding: 0.5rem; padding: 0.5rem;
width: 100%; width: 100%;
height: 2rem; height: 2.5rem;
display: flex; display: flex;
justify-content: start; justify-content: start;

View file

@ -0,0 +1,161 @@
@keyframes imgLoading {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.gallery {
margin: 0;
padding: 0;
width: 100%;
display: grid;
grid-template-columns: auto auto auto auto auto auto auto auto;
gap: 0.5rem;
}
@media (max-width: 1550px) {
.gallery {
grid-template-columns: auto auto auto auto auto auto auto;
}
}
@media (max-width: 1300px) {
.gallery {
grid-template-columns: auto auto auto auto auto auto;
}
}
@media (max-width: 1050px) {
.gallery {
grid-template-columns: auto auto auto auto auto;
}
}
@media (max-width: 800px) {
.gallery {
grid-template-columns: auto auto auto auto;
}
}
@media (max-width: 550px) {
.gallery {
grid-template-columns: auto auto auto;
}
}
.gallery__item {
margin: 0;
padding: 0;
height: auto;
position: relative;
background: linear-gradient(-45deg, $black100, $black400, $black100);
background-size: 400% 400%;
border-radius: $rad;
animation: imgLoading 10s ease infinite;
box-sizing: border-box;
overflow: hidden;
&:after {
content: "";
display: block;
padding-bottom: 100%;
}
}
.gallery__item-info {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
left: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
background-image: linear-gradient(to bottom, #00000000, rgba($black100, 0.8));
z-index: +1;
opacity: 0; // hide
transform: scale(1.05); // scale up
transition: all 0.5s cubic-bezier(.79, .14, .15, .86);
h2 {
margin: 0;
padding: 0 1rem 0.5rem;
font-family: $font-header;
font-size: 1rem;
font-stretch: ultra-expanded;
font-weight: 600;
color: $green;
text-overflow: ellipsis;
overflow: hidden;
opacity: 0; // hide
transition: all 0.2s ease-in-out;
}
p {
margin: 0;
padding: 0 1rem 0.5rem;
font-family: $font-body;
font-size: 0.8rem;
font-weight: 500;
color: $white100;
text-overflow: ellipsis;
overflow: hidden;
opacity: 0; // hide
transition: all 0.2s ease-in-out;
}
&:hover {
opacity: 1;
transform: scale(1);
h2,
p {
opacity: 1;
}
}
}
.gallery__item-image {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
object-fit: cover;
object-position: center;
background-color: $black200;
border-radius: $rad;
}

View file

@ -43,7 +43,7 @@
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
transition: all 0.5s ease-in-out; transition: all 0.25s ease-in-out;
} }
.sniffle__notification-icon { .sniffle__notification-icon {
margin: 0; margin: 0;
@ -94,7 +94,7 @@
background-color: $white100; background-color: $white100;
animation: sniffle 2.5s linear; animation: sniffle 4.9s linear;
} }
.sniffle__notification--success { .sniffle__notification--success {
color: $green; color: $green;
@ -123,4 +123,9 @@
.sniffle__notification-time { .sniffle__notification-time {
background-color: $blue; background-color: $blue;
} }
}
.sniffle__notification--hide {
opacity: 0;
transform: translateX(100%);
} }

View file

@ -2,13 +2,15 @@ from setuptools import find_packages, setup
setup( setup(
name='onlylegs', name='onlylegs',
version='140123', version='170123',
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
install_requires=[ install_requires=[
'flask', 'flask',
'libsass', 'libsass',
'dotenv', 'python-dotenv',
'Pillow', 'pillow',
'colorthief',
'pyyaml',
], ],
) )