diff --git a/gallery/__init__.py b/gallery/__init__.py index 7f4c6b1..ce8bbe2 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -5,59 +5,62 @@ print(""" | |_| | | | | | |_| | |__| __/ (_| \\__ \\ \\___/|_| |_|_|\\__, |_____\\___|\\__, |___/ |___/ |___/ -Created by Fluffy Bean - Version 170123 +Created by Fluffy Bean - Version 210123 """) from flask import Flask, render_template +from flask_compress import Compress from dotenv import load_dotenv import yaml import os -def create_app(test_config=None): +compress = Compress() + + +def create_app(test_config=None): # create and configure the app app = Flask(__name__) - + compress.init_app(app) + # Get environment variables load_dotenv(os.path.join(app.root_path, 'user', '.env')) print("Loaded env") - + # Get config file with open(os.path.join(app.root_path, 'user', 'conf.yml'), 'r') as f: conf = yaml.load(f, Loader=yaml.FullLoader) print("Loaded config") - # App configuration + # App configuration app.config.from_mapping( SECRET_KEY=os.environ.get('FLASK_SECRET'), DATABASE=os.path.join(app.instance_path, 'gallery.sqlite'), UPLOAD_FOLDER=os.path.join(app.root_path, 'user', 'uploads'), - MAX_CONTENT_LENGTH = 1024 * 1024 * conf['upload']['max-size'], + MAX_CONTENT_LENGTH=1024 * 1024 * conf['upload']['max-size'], ALLOWED_EXTENSIONS=conf['upload']['allowed-extensions'], ) - + if test_config is None: # load the instance config, if it exists, when not testing app.config.from_pyfile('config.py', silent=True) else: # load the test config if passed in app.config.from_mapping(test_config) - + # ensure the instance folder exists try: os.makedirs(app.instance_path) except OSError: pass - - + # Load database from . import db db.init_app(app) - + # Load theme from . import sassy sassy.compile('default', app.root_path) - @app.errorhandler(405) def method_not_allowed(e): error = '405' @@ -87,21 +90,16 @@ def create_app(test_config=None): error = '500' msg = 'Server died inside :c' return render_template('error.html', error=error, msg=msg), 500 - - + # Load login, registration and logout manager from . import auth app.register_blueprint(auth.blueprint) - + # Load routes for home and images from . import gallery app.register_blueprint(gallery.blueprint) app.add_url_rule('/', endpoint='index') - - # Load routes for images - from . import image - app.register_blueprint(image.blueprint) - + # Load APIs from . import api app.register_blueprint(api.blueprint) diff --git a/gallery/api.py b/gallery/api.py index 6ab06ea..24dbbc8 100644 --- a/gallery/api.py +++ b/gallery/api.py @@ -14,18 +14,24 @@ blueprint = Blueprint('viewsbp', __name__, url_prefix='/api') def uploads(file, quality): # If quality is 0, return original file if quality == 0: - return send_from_directory(current_app.config['UPLOAD_FOLDER'], secure_filename(file), as_attachment=True) + return send_from_directory(current_app.config['UPLOAD_FOLDER'], + secure_filename(file), + as_attachment=True) # Set variables set_ext = {'jpg': 'jpeg', 'jpeg': 'jpeg', 'png': 'png', 'webp': 'webp'} buff = io.BytesIO() - + # Open image and set extension - 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 = 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 = set_ext[img_ext] - img_icc = img.info.get("icc_profile") # Get ICC profile as it alters colours - + img_icc = img.info.get( + "icc_profile") # Get ICC profile as it alters colours + # Resize image and orientate correctly img.thumbnail((quality, quality), Image.LANCZOS) img = ImageOps.exif_transpose(img) @@ -34,7 +40,8 @@ def uploads(file, quality): # Seek to beginning of buffer and return buff.seek(0) - return send_file(buff, mimetype='image/'+img_ext) + return send_file(buff, mimetype='image/' + img_ext) + @blueprint.route('/upload', methods=['POST']) @login_required @@ -44,56 +51,59 @@ def upload(): if not form_file: return abort(404) - + img_ext = os.path.splitext(secure_filename(form_file.filename))[-1].lower() img_name = f"GWAGWA_{uuid4().__str__()}{img_ext}" if not img_ext in current_app.config['ALLOWED_EXTENSIONS']: abort(403) - + # Save to database try: db = get_db() db.execute( 'INSERT INTO posts (file_name, author_id, description, alt)' ' VALUES (?, ?, ?, ?)', - (img_name, g.user['id'], form['description'], form['alt']) - ) + (img_name, g.user['id'], form['description'], form['alt'])) db.commit() except Exception as e: abort(500) - - # Save file + + # Save file try: - form_file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], img_name)) + form_file.save( + os.path.join(current_app.config['UPLOAD_FOLDER'], img_name)) except: abort(500) - + return 'Gwa Gwa' + @blueprint.route('/remove/', methods=['POST']) @login_required def remove(id): img = get_db().execute( 'SELECT author_id, file_name FROM posts WHERE id = ?', - (id,) - ).fetchone() + (id, )).fetchone() if img is None: abort(404) if img['author_id'] != g.user['id']: abort(403) - + try: - os.remove(os.path.join(current_app.config['UPLOAD_FOLDER'], img['file_name'])) + os.remove( + os.path.join(current_app.config['UPLOAD_FOLDER'], + img['file_name'])) except Exception as e: abort(500) - + try: db = get_db() - db.execute('DELETE FROM posts WHERE id = ?', (id,)) + db.execute('DELETE FROM posts WHERE id = ?', (id, )) db.commit() except: abort(500) - + + flash(['Image was all in Le Head!', 1]) return 'Gwa Gwa' \ No newline at end of file diff --git a/gallery/auth.py b/gallery/auth.py index 295a250..5a23713 100644 --- a/gallery/auth.py +++ b/gallery/auth.py @@ -1,7 +1,8 @@ import functools -from flask import Blueprint, flash, g, redirect, render_template, request, session, url_for +from flask import Blueprint, flash, g, redirect, render_template, request, session, url_for, abort, jsonify from werkzeug.security import check_password_hash, generate_password_hash from gallery.db import get_db +import re blueprint = Blueprint('auth', __name__, url_prefix='/auth') @@ -17,61 +18,68 @@ def load_logged_in_user(): 'SELECT * FROM users WHERE id = ?', (user_id,) ).fetchone() - -@blueprint.route('/register', methods=('GET', 'POST')) +@blueprint.route('/register', methods=['POST']) def register(): - if request.method == 'POST': - username = request.form['username'] - password = request.form['password'] - db = get_db() - error = None + username = request.form['username'] + email = request.form['email'] + password = request.form['password'] + password_repeat = request.form['password-repeat'] + db = get_db() + error = [] - if not username: - error = 'Username is required.' - elif not password: - error = 'Password is required.' + if not username: + error.append('Username is empty!') + + if not email: + error.append('Email is empty!') + elif not re.match(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', email): + error.append('Email is invalid!') + + if not password: + error.append('Password is empty!') + elif len(password) < 8: + error.append('Password is too short! Longer than 8 characters pls') + + if not password_repeat: + error.append('Password repeat is empty!') + elif password_repeat != password: + error.append('Passwords do not match!') - if error is None: - try: - db.execute( - "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", - (username,'dummy@email.com' , generate_password_hash(password)), - ) - db.commit() - except db.IntegrityError: - error = f"User {username} is already registered." - else: - return redirect(url_for("auth.login")) - - flash(error) - - return render_template('auth/register.html') + if not error: + try: + db.execute( + "INSERT INTO users (username, email, password) VALUES (?, ?, ?)", + (username, email, generate_password_hash(password)), + ) + db.commit() + except db.IntegrityError: + error.append(f"User {username} is already registered!") + else: + return 'gwa gwa' + + return jsonify(error) -@blueprint.route('/login', methods=('GET', 'POST')) +@blueprint.route('/login', methods=['POST']) def login(): - if request.method == 'POST': - username = request.form['username'] - password = request.form['password'] - db = get_db() - error = None - user = db.execute( - 'SELECT * FROM users WHERE username = ?', (username,) - ).fetchone() + username = request.form['username'] + password = request.form['password'] + db = get_db() + error = None + user = db.execute( + 'SELECT * FROM users WHERE username = ?', (username,) + ).fetchone() - if user is None: - error = 'Incorrect username.' - elif not check_password_hash(user['password'], password): - error = 'Incorrect password.' + if user is None: + abort(403) + elif not check_password_hash(user['password'], password): + abort(403) - if error is None: - session.clear() - session['user_id'] = user['id'] - return redirect(url_for('index')) - - flash(error) - - return render_template('auth/login.html') + if error is None: + session.clear() + session['user_id'] = user['id'] + flash(['Logged in successfully!', '4']) + return 'gwa gwa' @blueprint.route('/logout') diff --git a/gallery/db.py b/gallery/db.py index dc2648d..d09bc14 100644 --- a/gallery/db.py +++ b/gallery/db.py @@ -6,10 +6,8 @@ from flask import current_app, g def get_db(): if 'db' not in g: - g.db = sqlite3.connect( - current_app.config['DATABASE'], - detect_types=sqlite3.PARSE_DECLTYPES - ) + g.db = sqlite3.connect(current_app.config['DATABASE'], + detect_types=sqlite3.PARSE_DECLTYPES) g.db.row_factory = sqlite3.Row return g.db diff --git a/gallery/gallery.py b/gallery/gallery.py index 0aeaa3b..a9bd750 100644 --- a/gallery/gallery.py +++ b/gallery/gallery.py @@ -4,8 +4,10 @@ from werkzeug.utils import secure_filename from gallery.auth import login_required from gallery.db import get_db from PIL import Image +from PIL.ExifTags import TAGS import os import datetime + dt = datetime.datetime.now() blueprint = Blueprint('gallery', __name__) @@ -14,19 +16,60 @@ blueprint = Blueprint('gallery', __name__) @blueprint.route('/') def index(): db = get_db() - images = db.execute( - 'SELECT * FROM posts' - ' ORDER BY created_at DESC' - ).fetchall() - + images = db.execute('SELECT * FROM posts' + ' ORDER BY created_at DESC').fetchall() + return render_template('index.html', images=images) + +@blueprint.route('/image/') +def image(id): + # Get image from database + db = get_db() + image = db.execute('SELECT * FROM posts' + ' WHERE id = ?', (id, )).fetchone() + + if image is None: + abort(404) + + # Get exif data from image + try: + file = Image.open( + os.path.join(current_app.config['UPLOAD_FOLDER'], + image['file_name'])) + raw_exif = file.getexif() + human_exif = {} + + for tag in raw_exif: + name = TAGS.get(tag, tag) + value = raw_exif.get(tag) + + if isinstance(value, bytes): + value = value.decode() + + human_exif[name] = value + + if len(human_exif) == 0: + human_exif = False + except: + # Cringe, no file present + human_exif = False + file = False + + # All in le head + return render_template('image.html', + image=image, + exif=human_exif, + file=file) + + @blueprint.route('/group') def groups(): return render_template('group.html', group_id='gwa gwa') + @blueprint.route('/group/') -def group(id): +def group(id): return render_template('group.html', group_id=id) diff --git a/gallery/image.py b/gallery/image.py deleted file mode 100644 index e2664cd..0000000 --- a/gallery/image.py +++ /dev/null @@ -1,49 +0,0 @@ -from flask import Blueprint, flash, g, redirect, render_template, request, url_for, jsonify, current_app -from werkzeug.exceptions import abort -from werkzeug.utils import secure_filename -from gallery.db import get_db -import os -import datetime -from PIL import Image -from PIL.ExifTags import TAGS -dt = datetime.datetime.now() - -blueprint = Blueprint('image', __name__, url_prefix='/image') - -@blueprint.route('/') -def image(id): - # Get image from database - db = get_db() - image = db.execute( - 'SELECT * FROM posts' - ' WHERE id = ?', - (id,) - ).fetchone() - - if image is None: - abort(404) - - # Get exif data from image - try: - file = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], image['file_name'])) - raw_exif = file.getexif() - human_exif = {} - - for tag in raw_exif: - name = TAGS.get(tag, tag) - value = raw_exif.get(tag) - - if isinstance(value, bytes): - value = value.decode() - - human_exif[name] = value - - if len(human_exif) == 0: - human_exif = False - except: - # Cringe, no file present - human_exif = False - file = False - - # All in le head - return render_template('image.html', image=image, exif=human_exif, file=file) \ No newline at end of file diff --git a/gallery/sassy.py b/gallery/sassy.py index cd67194..bc5edb2 100644 --- a/gallery/sassy.py +++ b/gallery/sassy.py @@ -1,43 +1,56 @@ import datetime + now = datetime.datetime.now() import sys import shutil import os import sass + class compile(): + def __init__(self, theme, dir): print(f"Loading '{theme}' theme...") - - theme_path = os.path.join(dir, 'user', 'themes', theme, 'style.scss') + + theme_path = os.path.join(dir, 'user', 'themes', theme) font_path = os.path.join(dir, 'user', 'themes', theme, 'fonts') dest = os.path.join(dir, 'static', 'theme') - + print(f"Theme path: {theme_path}") - + if os.path.exists(theme_path): + if os.path.exists(os.path.join(theme_path, 'style.scss')): + theme_path = os.path.join(theme_path, 'style.scss') + elif os.path.exists(os.path.join(theme_path, 'style.sass')): + theme_path = os.path.join(theme_path, 'style.sass') + else: + print("Theme does not contain a style file!") + sys.exit(1) + self.sass = sass - + self.loadTheme(theme_path, dest) self.loadFonts(font_path, dest) else: print("No theme found!") sys.exit(1) - + print(f"{now.hour}:{now.minute}:{now.second} - Done!\n") - - def loadTheme (self, theme, dest): + + def loadTheme(self, theme, dest): with open(os.path.join(dest, 'style.css'), 'w') as f: try: - f.write(self.sass.compile(filename=theme, output_style='compressed')) + f.write( + self.sass.compile(filename=theme, + output_style='compressed')) print("Compiled successfully!") except self.sass.CompileError as e: print("Failed to compile!\n", e) sys.exit(1) - - def loadFonts (self, source, dest): + + def loadFonts(self, source, dest): dest = os.path.join(dest, 'fonts') - + if os.path.exists(dest): print("Removing old fonts...") try: @@ -45,7 +58,7 @@ class compile(): except Exception as e: print("Failed to remove old fonts!\n", e) sys.exit(1) - + try: shutil.copytree(source, dest) print("Copied fonts to:", dest) diff --git a/gallery/templates/auth/login.html b/gallery/templates/auth/login.html deleted file mode 100644 index 6a83515..0000000 --- a/gallery/templates/auth/login.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends 'layout.html' %} - -{% block header %} - -{% endblock %} - -{% block content %} -
- -
-{% endblock %} \ No newline at end of file diff --git a/gallery/templates/auth/register.html b/gallery/templates/auth/register.html deleted file mode 100644 index 98a788f..0000000 --- a/gallery/templates/auth/register.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends 'layout.html' %} - -{% block header %} - -{% endblock %} - -{% block content %} -
-
-
- - - -

Register

-
-
- {% for message in get_flashed_messages() %} -
{{ message }}
- {% endfor %} - -
- - - - - - - - - - - - - - - -
- - Login -
-
-
-{% endblock %} \ No newline at end of file diff --git a/gallery/templates/error.html b/gallery/templates/error.html index 42f157a..464532c 100644 --- a/gallery/templates/error.html +++ b/gallery/templates/error.html @@ -1,12 +1,13 @@ {% extends 'layout.html' %} {% block header %} - +
+ + +
{% endblock %} {% block content %} -
-

{{error}}

-

{{msg}}

-
+

{{error}}

+

{{msg}}

{% endblock %} \ No newline at end of file diff --git a/gallery/templates/group.html b/gallery/templates/group.html index a54d4f5..c18f4df 100644 --- a/gallery/templates/group.html +++ b/gallery/templates/group.html @@ -1,12 +1,15 @@ {% extends 'layout.html' %} {% block header %} - +
+ + +
{% endblock %} +{% block nav_groups %}navigation-item__selected{% endblock %} + {% block content %} -
-

Image Group

-

{{group_id}}

-
+

Image Group

+

{{group_id}}

{% endblock %} \ No newline at end of file diff --git a/gallery/templates/image.html b/gallery/templates/image.html index 89d773d..017ac30 100644 --- a/gallery/templates/image.html +++ b/gallery/templates/image.html @@ -1,11 +1,16 @@ {% extends 'layout.html' %} {% block header %} - leaves +
+ + +
{% endblock %} +{% block wrapper_class %}image-wrapper{% endblock %} + {% block content %} -
+
-
-
- +
+ +
+ +
+
+ +
-
+ {% if g.user['id'] == image['author_id'] %}
- - -
- {% if g.user['id'] == image['author_id'] %} -
- - -
- {% endif %} -
-
+ {% endif %} + +
+ +
{% if image['alt'] != '' %} -
-
+
+

Alt

-
+

{{ image['alt'] }}

{% endif %} {% if image['description'] != '' %} -
-
+
+

Description

-
+

{{ image['description'] }}

{% endif %} -
-
+
+

Info

-
+

Filename: {{ image['file_name'] }}

Image ID: {{ image['id'] }}

Author: {{ image['author_id'] }}

@@ -108,14 +116,14 @@
{% if exif is not false %} -
-
+
+

Metadata

-
+
{% for tag in exif %}

{{ tag }}: {{ exif[tag] }}

{% endfor %} @@ -123,15 +131,18 @@
{% endif %}
+{% endblock %} + +{% block script %} {% endblock %} \ No newline at end of file diff --git a/gallery/templates/index.html b/gallery/templates/index.html index 82e2774..ee307f1 100644 --- a/gallery/templates/index.html +++ b/gallery/templates/index.html @@ -1,35 +1,34 @@ {% extends 'layout.html' %} -{% block header %} - -{% endblock %} +{% block nav_home %}navigation-item__selected{% endblock %} +{% block wrapper_class %}index-wrapper{% endblock %} {% block content %} -
- - + +{% endblock %} + +{% block script %} + -
- -
-
- {% block header %}{% endblock %} - -
- {% block content %} - {% endblock %} - - - -
+
+ {% block content %} + {% endblock %} +
+ +
+
+
+

Title

+

Very very very drawn out example description

+
+
+ +
+
+
+
+ {% block script %}{% endblock %} \ No newline at end of file diff --git a/gallery/templates/profile.html b/gallery/templates/profile.html index ab8dc45..96f9c31 100644 --- a/gallery/templates/profile.html +++ b/gallery/templates/profile.html @@ -1,22 +1,25 @@ {% extends 'layout.html' %} {% block header %} - -{% endblock %} - -{% block content %} -
-

User

-

{{user_id}}

-
    - {% if g.user %} -
  • {{ g.user['username'] }} -
  • Log Out - {% else %} -
  • Register -
  • Log In - {% endif %} -
+
+ +
{% endblock %} +{% block nav_profile %}navigation-item__selected{% endblock %} + +{% block content %} +

User

+

{{user_id}}

+
    + {% if g.user %} +
  • {{ g.user['username'] }} +
  • Log Out + {% else %} +
  • Register +
  • Log In + {% endif %} +
+{% endblock %} + diff --git a/gallery/templates/settings.html b/gallery/templates/settings.html index 5c4c405..5dddd44 100644 --- a/gallery/templates/settings.html +++ b/gallery/templates/settings.html @@ -1,11 +1,14 @@ {% extends 'layout.html' %} {% block header %} - +
+ + +
{% endblock %} +{% block nav_settings %}navigation-item__selected{% endblock %} + {% block content %} -
-

Settings

-
+

Settings

{% endblock %} \ No newline at end of file diff --git a/gallery/templates/upload.html b/gallery/templates/upload.html deleted file mode 100644 index 3550188..0000000 --- a/gallery/templates/upload.html +++ /dev/null @@ -1,97 +0,0 @@ -{% extends 'layout.html' %} - -{% block header %} - -{% endblock %} - -{% block content %} -
-
-
- - - -

Upload!!!!!!!

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -{% endblock %} \ No newline at end of file diff --git a/gallery/user/themes/default/animations.sass b/gallery/user/themes/default/animations.sass new file mode 100644 index 0000000..0464be2 --- /dev/null +++ b/gallery/user/themes/default/animations.sass @@ -0,0 +1,13 @@ +@keyframes imgLoading + 0% + background-position: -468px 0 + + 100% + background-position: 468px 0 + +@keyframes notificationTimeout + 0% + left: -100% + + 100% + left: 0% diff --git a/gallery/user/themes/default/buttons/btn.scss b/gallery/user/themes/default/buttons/btn.scss deleted file mode 100644 index d7d46f3..0000000 --- a/gallery/user/themes/default/buttons/btn.scss +++ /dev/null @@ -1,15 +0,0 @@ -.btn { - padding: 0.5rem 1rem; - border-radius: 0.25rem; - - border: 1px solid rgba($white100, 0.3); - background-color: rgba($white100, 0); - color: $white100; - - transition: background-color 0.3s ease-in-out, border-color 0.3s ease-in-out, color 0.3s ease-in-out; - - &:active { - border-color: rgba($white100, 1); - color: $white100; - } -} \ No newline at end of file diff --git a/gallery/user/themes/default/buttons/img-tool.scss b/gallery/user/themes/default/buttons/img-tool.scss deleted file mode 100644 index c7ebac1..0000000 --- a/gallery/user/themes/default/buttons/img-tool.scss +++ /dev/null @@ -1,79 +0,0 @@ -.tool-btn { - margin: 0; - padding: 0.5rem; - - width: 2.5rem; - height: 2.5rem; - - position: relative; - - border: none; - background-color: transparent; - color: $white100; - - svg { - width: 1.25rem; - height: 1.25rem; - } - - &:hover { - cursor: pointer; - - color: $green; - - .tool-tip { - opacity: 1; - top: -2.5rem; - transform: translateX(calc(-50% + 1.25rem )); - } - } -} -.tool-btn--evil { - color: $red; - - span { - color: $red; - } - - &:hover { - color: $white100; - } -} -.tool-btn--blu { - color: $blue; - - span { - color: $blue; - } - - &:hover { - color: $white100; - } -} - -.tool-tip { - margin: 0; - padding: 0.5rem 0.75rem; - - width: auto; - - display: block; - - position: absolute; - top: -1.7rem; - left: 0; - transform: translateX(calc(-50% + 1.25rem )); - - font-family: $font-body; - font-size: 1rem; - font-weight: 600; - - background-color: $black300; - color: $white100; - opacity: 0; - border-radius: $rad; - - transition: opacity 0.2s cubic-bezier(.76,0,.17,1), top 0.2s cubic-bezier(.76,0,.17,1); - - pointer-events: none; -} \ No newline at end of file diff --git a/gallery/user/themes/default/buttons/jumpUp.sass b/gallery/user/themes/default/buttons/jumpUp.sass new file mode 100644 index 0000000..eed83d5 --- /dev/null +++ b/gallery/user/themes/default/buttons/jumpUp.sass @@ -0,0 +1,29 @@ +.jumpUp + margin: 0 + padding: 0.5rem + + width: 2.5rem + height: 2.5rem + + position: fixed + bottom: 0.75rem + right: -3rem + + display: flex // hidden + justify-content: center + align-items: center + + border-radius: 50% + background-color: $black + color: $white + opacity: 0 // hidden + + z-index: 2 + + cursor: pointer + + transition: all 0.2s cubic-bezier(.86, 0, .07, 1) + + &:hover + background-color: $black + color: $primary diff --git a/gallery/user/themes/default/buttons/pill.sass b/gallery/user/themes/default/buttons/pill.sass new file mode 100644 index 0000000..b1b2773 --- /dev/null +++ b/gallery/user/themes/default/buttons/pill.sass @@ -0,0 +1,94 @@ +.pill-row + margin: 0 + padding: 0 + + width: 100% + height: auto + + display: flex + justify-content: center + align-items: center + gap: 0.5rem + + > div + margin: 0 + padding: 0 + + display: flex + + background-color: $black + border-radius: $rad + +.pill-item + margin: 0 + padding: 0.5rem + + width: 2.5rem + height: 2.5rem + + display: flex + justify-content: center + align-items: center + + position: relative + + border: none + background-color: transparent + color: $white + + svg + width: 1.25rem + height: 1.25rem + + &:hover + cursor: pointer + + color: $primary + + .tool-tip + opacity: 1 + top: -2.5rem + transform: translateX(calc(-50% + 1.25rem )) + +.pill__critical + color: $critical + + span + color: $critical + + &:hover + color: $white + +.pill__info + color: $info + + span + color: $info + + &:hover + color: $white + +.tool-tip + margin: 0 + padding: 0.5rem 0.75rem + + width: auto + + display: block + + position: absolute + top: -1.7rem + left: 0 + transform: translateX(calc(-50% + 1.25rem )) + + font-size: 1rem + font-weight: 600 + + background-color: $black2 + color: $white + opacity: 0 + border-radius: $rad-inner + + transition: opacity 0.2s cubic-bezier(.76,0,.17,1), top 0.2s cubic-bezier(.76,0,.17,1) + + pointer-events: none diff --git a/gallery/user/themes/default/buttons/up.scss b/gallery/user/themes/default/buttons/up.scss deleted file mode 100644 index ec73f18..0000000 --- a/gallery/user/themes/default/buttons/up.scss +++ /dev/null @@ -1,30 +0,0 @@ -#topButton { - margin: 0; - padding: 0.5rem; - - width: 2.5rem; - height: 2.5rem; - - position: fixed; - bottom: 0.75rem; - right: -3rem; - - display: flex; // hidden - justify-content: center; - align-items: center; - - border-radius: 50%; - background-color: $black300; - opacity: 0; // hidden - - z-index: 2; - - cursor: pointer; - - transition: all 0.2s cubic-bezier(.86, 0, .07, 1); - - &:hover { - background-color: $black200; - color: $green; - } -} \ No newline at end of file diff --git a/gallery/user/themes/default/fonts/Hubot-Sans.woff2 b/gallery/user/themes/default/fonts/Hubot-Sans.woff2 deleted file mode 100644 index 5089fc4..0000000 Binary files a/gallery/user/themes/default/fonts/Hubot-Sans.woff2 and /dev/null differ diff --git a/gallery/user/themes/default/fonts/Mona-Sans.woff2 b/gallery/user/themes/default/fonts/Mona-Sans.woff2 deleted file mode 100644 index 8208a50..0000000 Binary files a/gallery/user/themes/default/fonts/Mona-Sans.woff2 and /dev/null differ diff --git a/gallery/user/themes/default/style.sass b/gallery/user/themes/default/style.sass new file mode 100644 index 0000000..847fb3f --- /dev/null +++ b/gallery/user/themes/default/style.sass @@ -0,0 +1,39 @@ +// Default theme for OnlyLegs by FluffyBean +// Mockup link: https://www.figma.com/file/IMZT5kZr3sAngrSHSGu5di/OnlyLegs?node-id=0%3A1 + +@import "variables" +@import "animations" + +@import "ui/notification" +@import "ui/pop-up" +@import "ui/navigation" +@import "ui/content" +@import "ui/background" +@import "ui/gallery" + +@import "buttons/jumpUp" +@import "buttons/pill" + +// Reset +* + box-sizing: border-box + font-family: $font + +html, body + margin: 0 + padding: 0 + + min-height: 100vh + + background-color: $white + + scroll-behavior: smooth + +.wrapper + margin: 0 + padding: 0 + + min-height: 100vh + + background-color: $white + color: $black diff --git a/gallery/user/themes/default/style.scss b/gallery/user/themes/default/style.scss deleted file mode 100644 index bc5171d..0000000 --- a/gallery/user/themes/default/style.scss +++ /dev/null @@ -1,464 +0,0 @@ -@import 'variables/variables'; -@import 'variables/fonts'; - -@import 'ui/reset'; -@import 'ui/nav'; -@import 'ui/main'; -@import 'ui/gallery'; -@import 'ui/notification'; - -@import 'buttons/img-tool'; -@import 'buttons/btn'; -@import 'buttons/up'; - -.app { - margin: 0 0 0 3.5rem; - padding: 0.5rem; - - width: auto; - min-height: 100vh; - - position: relative; - - display: flex; - flex-direction: column; - gap: 1rem; - - //background-color: $black100; - color: $white100; - - box-sizing: border-box; - z-index: 1; - overflow: unset; - - > h1 { - margin: 0 auto; - padding: 0; - - font-family: $font-header; - font-size: 5rem; - font-weight: 900; - line-height: 1; - text-align: center; - - color: $green; - } - > p { - margin: 0 auto; - padding: 0; - - font-family: $font-body; - font-size: 2rem; - font-weight: 600; - line-height: 1; - text-align: center; - - color: $white100; - } - /* - h1 { - margin: 0; - padding: 0; - - font-family: $font-header; - font-size: 2.5rem; - font-stretch: ultra-expanded; - font-weight: 600; - - color: $green; - } - */ -} - -.box-ui { - margin: 0 auto; - 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; - } - - h2 { - margin: 0; - padding: 0; - - font-family: $font-header; - 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 { - min-height: 100vh; - - gap: 0; - - > h1 { - margin: 0 auto; - padding: 0; - - font-family: $font-header; - font-size: 5rem; - font-weight: 900; - line-height: 1; - text-align: center; - - color: $green; - } - > p { - margin: 0 auto; - padding: 0; - - font-family: $font-body; - font-size: 2rem; - font-weight: 600; - line-height: 1; - text-align: center; - - color: $white100; - } -} - -.image__fullscreen { - margin: 0; - padding: 0 0 0 3.5rem; - - width: 100%; - height: 100dvh; - - position: fixed; - top: -100%; - left: 0; - - display: flex; - opacity: 0; // hide - - background-color: rgba($black100, 0.8); - backdrop-filter: blur(1rem); - z-index: 21; - - box-sizing: border-box; - - img { - margin: auto; - padding: 0; - - width: auto; - height: auto; - max-width: calc(100% - 1rem); - max-height: calc(100% - 1rem); - - object-fit: contain; - object-position: center; - - transform: scale(0.8); - - border-radius: $rad; - } -} -.image__fullscreen--active { - top: 0; - - opacity: 1; // show - - transition: opacity 0.3s cubic-bezier(.79, .14, .15, .86); - - img { - transform: scale(1); - transition: transform 0.2s cubic-bezier(.68,-0.55,.27,1.55); - } -} - -.image__container { - margin: 0; - padding: 0; - - width: 100%; - height: auto; - max-width: 100%; - max-height: 69vh; - - position: sticky; - top: 0; - - display: flex; - 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; - - box-sizing: border-box; - - img { - margin: auto; - padding: 0; - - width: auto; - height: auto; - max-width: 100%; - max-height: 69vh; - - background-color: $black200; - - object-fit: contain; - object-position: center; - - border-radius: $rad; - } -} - -.image__info { - margin: 0; - padding: 0; - - width: 100%; - - display: flex; - flex-direction: column; - - background-color: $black200; - border-radius: $rad; - //border-left: $rad solid $green; - - box-sizing: border-box; -} -.image__info-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; - } - - h2 { - margin: 0; - padding: 0; - - font-family: $font-header; - font-size: 1.25rem; - font-stretch: ultra-expanded; - font-weight: 600; - - color: $green; - - text-overflow: ellipsis; - overflow: hidden; - } -} -.image__info-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; - } -} - -.img-tools { - width: 100%; - height: 2rem; - - display: flex; - justify-content: center; - align-items: center; - gap: 0.5rem; - - > div { - margin: 0; - padding: 0; - - display: flex; - //gap: 0.5rem; - - background-color: $black200; - border-radius: $rad; - } -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/background.sass b/gallery/user/themes/default/ui/background.sass new file mode 100644 index 0000000..99ace47 --- /dev/null +++ b/gallery/user/themes/default/ui/background.sass @@ -0,0 +1,45 @@ +.background-decoration + margin: 0 + padding: 0 + + width: 100% + height: 100vh + + position: fixed + top: 0 + left: 0 + + background-color: $white + + background-image: linear-gradient(to right, darken($white, 1%) 15%, darken($white, 10%) 35%, darken($white, 1%) 50%) + background-size: 1000px 640px + animation: imgLoading 1.8s linear infinite forwards + + user-select: none + overflow: hidden + + img + position: absolute + top: 0 + left: 0 + + width: 100% + height: 100% + + filter: blur(1rem) + transform: scale(1.1) + + object-fit: cover + object-position: center center + + span + position: absolute + top: 0 + left: 0 + + width: 100% + height: 100% + + background-image: linear-gradient(to bottom, rgba($white, 0), rgba($white, 1)) + + z-index: +1 diff --git a/gallery/user/themes/default/ui/content.sass b/gallery/user/themes/default/ui/content.sass new file mode 100644 index 0000000..faf82bf --- /dev/null +++ b/gallery/user/themes/default/ui/content.sass @@ -0,0 +1,14 @@ +@import "wrappers/index" +@import "wrappers/image" + +.content + width: calc(100% - 3.5rem) + min-height: 100vh + + position: relative + left: 3.5rem + +@media (max-width: $breakpoint) + .content + width: 100% + left: 0 diff --git a/gallery/user/themes/default/ui/gallery.sass b/gallery/user/themes/default/ui/gallery.sass new file mode 100644 index 0000000..cb0a7cb --- /dev/null +++ b/gallery/user/themes/default/ui/gallery.sass @@ -0,0 +1,117 @@ +.gallery + margin: 0 + padding: 0 + + width: 100% + + display: grid + grid-template-columns: auto auto auto auto auto auto + gap: 0.5rem + +@media (max-width: 1300px) + .gallery + grid-template-columns: auto auto auto auto + +@media (max-width: 800px) + .gallery + grid-template-columns: auto auto auto + +.gallery__item + margin: 0 + padding: 0 + + height: auto + + position: relative + + background: linear-gradient(to right, darken($white, 1%) 15%, darken($white, 10%) 35%, darken($white, 1%) 50%) + background-size: 1000px 640px + animation: imgLoading 1.8s linear infinite forwards + border-radius: $rad + + 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, rgba($black, 0), rgba($black, 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-size: 1rem + font-weight: 600 + + color: $primary + + text-overflow: ellipsis + overflow: hidden + + opacity: 0 // hide + transition: all 0.2s ease-in-out + + p + margin: 0 + padding: 0 1rem 0.5rem + + font-size: 0.8rem + font-weight: 500 + + color: $white + + 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: $black + border-radius: $rad diff --git a/gallery/user/themes/default/ui/gallery.scss b/gallery/user/themes/default/ui/gallery.scss deleted file mode 100644 index e5c3125..0000000 --- a/gallery/user/themes/default/ui/gallery.scss +++ /dev/null @@ -1,161 +0,0 @@ -@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; -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/main.scss b/gallery/user/themes/default/ui/main.scss deleted file mode 100644 index 55a64e0..0000000 --- a/gallery/user/themes/default/ui/main.scss +++ /dev/null @@ -1,57 +0,0 @@ -main { - margin: 0; - padding: 0; - - background-color: $black100; - color: $white100; - - min-height: 100vh; - - overflow-y: auto; - box-sizing: border-box; - - header { - margin: 0; - padding: 0; - - width: 100%; - height: 69vh; - - position: fixed; - top: 0; - left: 0; - - background-color: $black200; - border-radius: $rad; - - box-sizing: border-box; - - user-select: none; - - img { - position: absolute; - top: 0; - left: 0; - - width: 100%; - height: 100%; - - object-fit: cover; - object-position: center 0px; - } - - span { - position: absolute; - top: 0; - left: 0; - - width: 100%; - height: 100%; - - background-image: linear-gradient(to bottom, #00000000, rgba($black100, 1)); - backdrop-filter: blur(1rem); - - z-index: +1; - } - } -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/nav.scss b/gallery/user/themes/default/ui/nav.scss deleted file mode 100644 index 4b4a892..0000000 --- a/gallery/user/themes/default/ui/nav.scss +++ /dev/null @@ -1,95 +0,0 @@ -nav { - margin: 0; - padding: 0; - - max-width: 100vw; - width: 3.5rem; - height: 100dvh; - - display: flex; - flex-direction: column; - justify-content: space-between; - - position: fixed; - top: 0; - left: 0; - - background-color: $black300; - color: $white100; - - box-sizing: border-box; - z-index: 69; - transition: width 0.4s cubic-bezier(.76,0,.17,1), background-color 0.3s ease-in-out; - - div { - display: flex; - flex-direction: column; - //gap: 0.25rem; - - a { - margin: 0; - padding: 1rem; - - width: 3.5rem; - height: 3.5rem; - - display: flex; - flex-direction: row; - align-items: center; - //gap: 0.5rem; - - position: relative; - - text-decoration: none; - color: $white100; - - box-sizing: border-box; - - i, svg { - margin: 0; - font-size: 1.5rem; - color: $white100; - transition: color 0.2s ease-out; - } - - span { - margin: 0; - padding: 0.5rem 0.75rem; - - display: block; - - position: absolute; - top: 50%; - left: 3rem; - transform: translateY(-50%); - - font-family: $font-body; - font-size: 1rem; - font-weight: 600; - - background-color: $black300; - color: $white100; - opacity: 0; - border-radius: $rad; - - transition: opacity 0.2s cubic-bezier(.76,0,.17,1), left 0.2s cubic-bezier(.76,0,.17,1); - - pointer-events: none; - } - - &:hover { - //background-color: $black200; - - i, svg { - color: $green; - } - - span { - opacity: 1; - left: 3.8rem; - transform: translateY(-50%); - } - } - } - } -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/navigation.sass b/gallery/user/themes/default/ui/navigation.sass new file mode 100644 index 0000000..ac0fd9f --- /dev/null +++ b/gallery/user/themes/default/ui/navigation.sass @@ -0,0 +1,127 @@ +.navigation + margin: 0 + padding: 0 + + width: 3.5rem + height: 100dvh + + display: flex + flex-direction: column + justify-content: space-between + + position: fixed + top: 0 + left: 0 + + background-color: $black2 + color: $white + + z-index: 69 + + // Spacer + > span + height: 100% + +.navigation-item + margin: 0 + padding: 1rem + + width: 3.5rem + height: 3.5rem + + display: flex + flex-direction: row + align-items: center + + position: relative + + background-color: $black2 + border: none + + text-decoration: none + + svg + margin: 0 + font-size: 1.5rem + color: $white + transition: color 0.2s ease-out + + span + margin: 0 + padding: 0.5rem 0.75rem + + display: block + + position: absolute + top: 50% + left: 3rem + transform: translateY(-50%) + + font-size: 1rem + font-weight: 600 + + background-color: $black2 + color: $white + opacity: 0 + border-radius: $rad-inner + + transition: opacity 0.2s cubic-bezier(.76,0,.17,1), left 0.2s cubic-bezier(.76,0,.17,1) + + pointer-events: none + + &:hover + background-color: $black2 + + svg + color: $primary + + span + opacity: 1 + left: 3.8rem + +.navigation-item__selected + background: $primary + + svg + color: $black + + &:hover + background: $primary + + svg + color: $white + + +@media (max-width: $breakpoint) + .navigation + width: 100vw + height: 3.5rem + + flex-direction: row + justify-content: space-around + + position: fixed + top: unset + bottom: 0 + left: 0 + + > span + display: none + + .navigation-item + margin: 0.25rem + padding: 0 + + width: 3rem + height: 3rem + + border-radius: $rad-inner + + svg + margin: auto + + width: 1.5rem + height: 1.5rem + + span + display: none diff --git a/gallery/user/themes/default/ui/notification.sass b/gallery/user/themes/default/ui/notification.sass new file mode 100644 index 0000000..8b6225b --- /dev/null +++ b/gallery/user/themes/default/ui/notification.sass @@ -0,0 +1,131 @@ +@mixin notification($color) + color: $color + + .sniffle__notification-time + background-color: $color + +.notifications + margin: 0 + padding: 0 + + width: 450px + height: auto + + position: fixed + top: 0.3rem + right: 0.3rem + + display: flex + flex-direction: column + gap: 0.3rem + + z-index: 70 + +.sniffle__notification + margin: 0 + padding: 0 + + width: 450px + height: auto + + display: flex + flex-direction: row + + position: relative + + background-color: $black + border-radius: $rad-inner + color: $white + opacity: 0 + transform: scale(0.8) + + box-sizing: border-box + overflow: hidden + + transition: all 0.25s ease-in-out, opacity 0.2s ease-in-out, transform 0.2s cubic-bezier(.68,-0.55,.27,1.55) + +.sniffle__notification-icon + margin: 0 + padding: 1rem + + width: auto + height: auto + + display: flex + justify-content: center + align-items: center + + background-color: $black2 + + svg + width: 1.25rem + height: 1.25rem + +.sniffle__notification-text + margin: 0 + padding: 1rem + + width: auto + height: auto + + display: flex + flex-direction: column + justify-self: center + align-self: center + + font-size: 1rem + font-weight: 600 + line-height: 1 + text-align: left + +.sniffle__notification-time + margin: 0 + padding: 0 + + width: 450px + height: 3px + + position: absolute + bottom: 0px + left: 0px + + background-color: $white + + animation: notificationTimeout 4.9s linear + +.sniffle__notification--success + @include notification($succes) + +.sniffle__notification--error + @include notification($critical) + +.sniffle__notification--warning + @include notification($warning) + +.sniffle__notification--info + @include notification($info) + +.sniffle__notification-show + opacity: 1 + transform: scale(1) + +.sniffle__notification--hide + opacity: 0 + transform: translateX(100%) + + transition: all 0.25s ease-in-out + +@media (max-width: $breakpoint) + .notifications + width: calc(100vw - 0.6rem) + height: auto + + .sniffle__notification + width: 100% + + .sniffle__notification-time + width: 100% + + .sniffle__notification--hide + opacity: 0 + transform: translateY(-5rem) \ No newline at end of file diff --git a/gallery/user/themes/default/ui/notification.scss b/gallery/user/themes/default/ui/notification.scss deleted file mode 100644 index 5388efe..0000000 --- a/gallery/user/themes/default/ui/notification.scss +++ /dev/null @@ -1,131 +0,0 @@ -@keyframes sniffle { - 0% { - left: -450px; - } - 100% { - left: 0; - } -} - -.sniffle { - margin: 0; - padding: 0; - - width: 450px; - height: auto; - - position: fixed; - top: 0.3rem; - right: 0.3rem; - - display: flex; - flex-direction: column; - gap: 0.3rem; - - z-index: 6969; -} -.sniffle__notification { - margin: 0; - padding: 0; - - width: 450px; - height: auto; - - display: flex; - flex-direction: row; - - position: relative; - - background-color: $black200; - border-radius: $rad; - color: $white100; - - box-sizing: border-box; - overflow: hidden; - - transition: all 0.25s ease-in-out; -} -.sniffle__notification-icon { - margin: 0; - padding: 1rem; - - width: auto; - height: 100%; - - display: flex; - justify-content: center; - align-items: center; - - background-color: $black300; - - svg { - width: 1.25rem; - height: 1.25rem; - } -} -.sniffle__notification-text { - margin: 0; - padding: 1rem; - - width: auto; - height: auto; - - display: flex; - flex-direction: column; - justify-self: center; - align-self: center; - - font-family: $font-body; - font-size: 1rem; - font-weight: 600; - line-height: 1; - text-align: left; -} -.sniffle__notification-time { - margin: 0; - padding: 0; - - width: 450px; - height: 3px; - - position: absolute; - bottom: 0px; - left: 0px; - - background-color: $white100; - - animation: sniffle 4.9s linear; -} -.sniffle__notification--success { - color: $green; - - .sniffle__notification-time { - background-color: $green; - } -} -.sniffle__notification--error { - color: $red; - - .sniffle__notification-time { - background-color: $red; - } -} -.sniffle__notification--warning { - color: $yellow; - - .sniffle__notification-time { - background-color: $yellow; - } -} -.sniffle__notification--info { - color: $blue; - - .sniffle__notification-time { - background-color: $blue; - } -} - -.sniffle__notification--hide { - opacity: 0; - transform: translateX(100%); -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/pop-up.sass b/gallery/user/themes/default/ui/pop-up.sass new file mode 100644 index 0000000..82101ab --- /dev/null +++ b/gallery/user/themes/default/ui/pop-up.sass @@ -0,0 +1,259 @@ +@mixin pop-up-btn($color, $fill: false) + @if $fill + color: $white + background-color: $color + border: 2px solid $color + + &:hover + background-color: $white + color: $color + @else + color: $color + background-color: $white + border: 2px solid $color + + &:hover + background-color: $color + color: $white + +.pop-up + width: calc(100% - 3.5rem) + height: 100vh + + position: fixed + top: 100% + left: 3.5rem + + background-color: rgba($black, 0.8) + backdrop-filter: blur(1rem) + + opacity: 0 + z-index: 68 + + transition: opacity 0.2s ease + +.pop-up-wrapper + margin: 0 + padding: 0.5rem + + width: 621px + height: auto + + position: absolute + bottom: 50% + left: 50% + transform: translate(-50%, 50%) scale(0.8) + + display: flex + flex-direction: column + gap: 0.5rem + + background-color: $white + border-radius: $rad + + overflow: hidden + + transition: transform 0.2s cubic-bezier(.68,-0.55,.27,1.55) + +.pop-up-content + margin: 0 + padding: 0 + + width: 100% + height: auto + max-height: 50vh + + display: flex + flex-direction: column + gap: 0.5rem + + overflow-y: auto + overflow-x: hidden + text-size-adjust: auto; + text-overflow: ellipsis + + h3 + margin: 0 + + width: 100% + + position: sticky + top: 0 + + font-size: 2.5rem + font-weight: 600 + text-align: center + line-height: 1 + + color: $black + background-color: $white + + p + margin: 0 + + width: 100% + + font-size: 1rem + font-weight: 500 + text-align: center + line-height: 1 + + color: $black + + img + margin: auto + padding: 0 + + width: auto + height: auto + max-width: 100% + max-height: 40vh + + border-radius: $rad-inner + + form + margin: 0 + padding: 0 + + width: 100% + height: auto + + display: flex + flex-direction: column + gap: 0.5rem + + justify-content: center + +.pop-up-controlls + margin: 0 + padding: 0 + + width: 100% + height: auto + + display: flex + flex-direction: column + gap: 0.5rem + + justify-content: center + +.pop-up__btn + margin: 0 + padding: 0.5rem + + width: 100% + height: 2.5rem + + display: flex + justify-content: center + align-items: center + + font-size: 1rem + font-weight: 600 + text-align: center + line-height: 1 + + border-radius: $rad-inner + + cursor: pointer + transition: background-color 0.2s ease, color 0.2s ease + + @include pop-up-btn($black) + + &:focus + outline: none +.pop-up__btn-fill + @include pop-up-btn($black, true) + +.pop-up__btn-primary + @include pop-up-btn($primary) +.pop-up__btn-primary-fill + @include pop-up-btn($primary, true) + +.pop-up__btn-info + @include pop-up-btn($info) +.pop-up__btn-info-fill + @include pop-up-btn($info, true) + +.pop-up__btn-warning + @include pop-up-btn($warning) +.pop-up__btn-warning-fill + @include pop-up-btn($warning, true) + +.pop-up__btn-critical + @include pop-up-btn($critical) +.pop-up__btn-critical-fill + @include pop-up-btn($critical, true) + +.pop-up__input + margin: 0 + padding: 0.5rem + + width: 100% + height: 2.5rem + + font-size: 1rem + font-weight: 600 + text-align: left + line-height: 1 + + border-radius: $rad-inner + + background-color: $white + border: 2px solid $black + + &:focus + outline: none + border-color: $primary + +.pop-up__link + color: $primary + text-decoration: none + + &:hover + text-decoration: underline + cursor: pointer + +.pop-up__active + opacity: 1 + top: 0 + + .pop-up-wrapper + transform: translate(-50%, 50%) scale(1) + +@media (max-width: $breakpoint) + .pop-up + width: 100% + height: calc(100vh - 3.5rem) + height: calc(100dvh - 3.5rem) + + position: fixed + left: 0 + bottom: 3.5rem + + backdrop-filter: blur(0.5rem) + + .pop-up-wrapper + width: 100% + max-height: calc(100vh - 1rem) + max-height: calc(100dvh - 1rem) + + left: 0 + bottom: 0 + + border-radius: $rad + transform: translateY(5rem) + box-shadow: 0px 8px 0px $black2; + + .pop-up-content + max-height: 100% + + img + max-height: 50vh + + .pop-up__active + opacity: 1 + top: unset + + .pop-up-wrapper + transform: translateY(0) \ No newline at end of file diff --git a/gallery/user/themes/default/ui/reset.scss b/gallery/user/themes/default/ui/reset.scss deleted file mode 100644 index cf2b1ef..0000000 --- a/gallery/user/themes/default/ui/reset.scss +++ /dev/null @@ -1,16 +0,0 @@ -* { - box-sizing: border-box; - line-height: 1; -} - -html, -body { - margin: 0; - padding: 0; - - min-height: 100vh; - - background-color: $black100; - - scroll-behavior: smooth; -} \ No newline at end of file diff --git a/gallery/user/themes/default/ui/wrappers/image.sass b/gallery/user/themes/default/ui/wrappers/image.sass new file mode 100644 index 0000000..3b0fd05 --- /dev/null +++ b/gallery/user/themes/default/ui/wrappers/image.sass @@ -0,0 +1,216 @@ +.image-wrapper + padding: 0 + + display: grid + grid-template-areas: 'info image' 'info tools' + grid-template-columns: 25rem 1fr + grid-template-rows: 1fr auto + gap: 0 + + height: 100vh + +.image-fullscreen + margin: 0 + padding: 0 0 0 3.5rem + + width: 100% + height: 100dvh + + position: fixed + top: -100% + left: 0 + + display: flex + opacity: 0 // hide + + background-color: rgba($black, 0.8) + backdrop-filter: blur(1rem) + z-index: 21 + + box-sizing: border-box + + img + margin: auto + padding: 0 + + width: auto + height: auto + max-width: 100% + max-height: 100% + + object-fit: contain + object-position: center + + transform: scale(0.8) + + &__active + top: 0 + + opacity: 1 // show + + transition: opacity 0.3s cubic-bezier(.79, .14, .15, .86) + + img + transform: scale(1) + transition: transform 0.2s cubic-bezier(.68,-0.55,.27,1.55) + +.image-container + margin: auto + padding: 0.5rem + + width: 100% + height: 100% + + display: flex + overflow: hidden + + grid-area: image + + img + margin: auto + padding: 0 + + width: auto + height: auto + max-width: 100% + max-height: 100% + + object-fit: contain + object-position: center + + border-radius: $rad + +.image-info__container + margin: 0 + padding: 0 + + width: 100% + height: 100% + + display: flex + flex-direction: column + + background-color: $black + + overflow-y: auto + + grid-area: info + +.image-info + margin: 0 + padding: 0 + + width: 100% + + display: flex + flex-direction: column + + background-color: $black + border-radius: $rad +.image-info__header + margin: 0 + padding: 0.5rem + + width: 100% + height: 2.5rem + + display: flex + justify-content: start + align-items: center + gap: 0.5rem + + background-color: $black2 + + svg + margin: 0 + padding: 0 + + width: 1.25rem + height: 1.25rem + + fill: $primary + + h2 + margin: 0 + padding: 0 + + font-size: 1.25rem + font-weight: 600 + + color: $primary + + text-overflow: ellipsis + overflow: hidden + +.image-info__content + margin: 0 + padding: 0.5rem + + display: flex + flex-direction: column + gap: 0.5rem + + p + margin: 0 + padding: 0 + + font-size: 1rem + font-weight: 500 + + color: $white + + text-overflow: ellipsis + overflow: hidden + +#image-tools + margin-bottom: 0.5rem + + grid-area: tools + +@media (max-width: 1100px) + .image-wrapper + padding: 0.5rem + + display: flex !important + flex-direction: column + gap: 0.5rem + + height: auto + + .image-container + margin: 0 auto + padding: 0 + + max-height: 69vh + + img + max-height: 69vh + + #image-tools + margin: 0 + + .image-info__container + margin: 0 + padding: 0 + + width: 100% + height: auto + + display: flex + flex-direction: column + gap: 0.5rem + + background: none + + .image-info__container + border-radius: $rad + + .image-info__header + border-radius: $rad $rad 0 0 + +@media (max-width: $breakpoint) + .image-fullscreen + padding: 0 0 3.5rem 0 + + .image-wrapper + padding-bottom: 4rem diff --git a/gallery/user/themes/default/ui/wrappers/index.sass b/gallery/user/themes/default/ui/wrappers/index.sass new file mode 100644 index 0000000..9533649 --- /dev/null +++ b/gallery/user/themes/default/ui/wrappers/index.sass @@ -0,0 +1,12 @@ +.index-wrapper + padding: 0.5rem + + position: relative + + display: flex + flex-direction: column + gap: 0.5rem + +@media (max-width: $breakpoint) + .index-wrapper + padding-bottom: 4rem diff --git a/gallery/user/themes/default/variables.sass b/gallery/user/themes/default/variables.sass new file mode 100644 index 0000000..5bb6dbb --- /dev/null +++ b/gallery/user/themes/default/variables.sass @@ -0,0 +1,40 @@ +$black: #151515 +$black2: #101010 +$white: #E8E3E3 + +$red: #B66467 +$orange: #D8A657 +$yellow: #D9BC8C +$green: #8C977D +$blue: #8DA3B9 +$purple: #A988B0 + +$primary: $green +$warning: $orange +$critical: $red +$succes: $green +$info: $blue + +$rad: 8px +$rad-inner: 3px + +//$font: "Work Sans", sans-serif +$font: "Work Sans", sans-serif + +$breakpoint: 800px // responsive breakpoint for mobile + +// Work Sans +@font-face + font-family: 'Work Sans' + src: url('fonts/worksans-regular.woff2') + font-weight: 400 + +@font-face + font-family: 'Work Sans' + src: url('fonts/worksans-bold.woff2') + font-weight: 600 + +@font-face + font-family: 'Work Sans' + src: url('fonts/worksans-black.woff2') + font-weight: 900 \ No newline at end of file diff --git a/gallery/user/themes/default/variables/fonts.scss b/gallery/user/themes/default/variables/fonts.scss deleted file mode 100644 index f6aba3b..0000000 --- a/gallery/user/themes/default/variables/fonts.scss +++ /dev/null @@ -1,35 +0,0 @@ -@font-face { - font-family: "Mona-Sans"; - src: url("fonts/Mona-Sans.woff2") format("woff2 supports variations"), - url("fonts/Mona-Sans.woff2") format("woff2-variations"); - font-weight: 200 900; - font-stretch: 75% 125%; - font-display: swap; -} - -@font-face { - font-family: "Hubot-Sans"; - src: url("fonts/Hubot-Sans.woff2") format("woff2 supports variations"), - url("fonts/Hubot-Sans.woff2") format("woff2-variations"); - font-weight: 200 900; - font-stretch: 75% 125%; - font-display: swap; -} - -@font-face { - font-family: 'Work Sans'; - src: url('fonts/worksans-regular.woff2'); - font-weight: 400; -} - -@font-face { - font-family: 'Work Sans'; - src: url('fonts/worksans-bold.woff2'); - font-weight: 600; -} - -@font-face { - font-family: 'Work Sans'; - src: url('fonts/worksans-black.woff2'); - font-weight: 900; -} \ No newline at end of file diff --git a/gallery/user/themes/default/variables/variables.scss b/gallery/user/themes/default/variables/variables.scss deleted file mode 100644 index f4b9854..0000000 --- a/gallery/user/themes/default/variables/variables.scss +++ /dev/null @@ -1,18 +0,0 @@ -$black100: #1a1a1a; -$black200: #151515; -$black300: #101010; -$black400: #0b0b0b; - -$white100: #e8e3e3; - -$red: #B66467; -$orange: #D8A657; -$yellow: #D9BC8C; -$green: #8C977D; -$blue: #8DA3B9; -$purple: #A988B0; - -$rad: 3px; - -$font-header: "Work Sans", sans-serif; -$font-body: "Work Sans", sans-serif; \ No newline at end of file diff --git a/setup.py b/setup.py index b706e18..3bbf416 100644 --- a/setup.py +++ b/setup.py @@ -2,11 +2,12 @@ from setuptools import find_packages, setup setup( name='onlylegs', - version='170123', + version='210123', packages=find_packages(), include_package_data=True, install_requires=[ 'flask', + 'flask-compress', 'libsass', 'python-dotenv', 'pillow',