Better CSS support (#583)

* Remove banner hardcoding

* Refactor "colors" to "stylesheet"

* Remove logo hardcoding

* Remove stylesheet hardcoding

* Add very basic static CSS scanning and a new style

* Respect environment settings

* Check if selected stylesheet still exists

* New theme and title formatting

* Revert migration change

* Code linting

* More outlines for Matrix style

* Change wording in settings

* Forgot this wording

* Add suggested changes
This commit is contained in:
extome 2023-11-08 21:33:03 -05:00 committed by GitHub
parent 6bc0111d0a
commit 7133d6b441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 154 additions and 48 deletions

View File

@ -162,11 +162,11 @@ class Command(BaseCommand):
for user in users:
new_conf = UserConfig(user)
colors_key = f"{user}:colors"
colors = redis.get_message(colors_key).get("status")
if colors:
new_conf.set_value("colors", colors)
redis.del_message(colors_key)
stylesheet_key = f"{user}:color"
stylesheet = redis.get_message(stylesheet_key).get("status")
if stylesheet:
new_conf.set_value("stylesheet", stylesheet)
redis.del_message(stylesheet_key)
sort_by_key = f"{user}:sort_by"
sort_by = redis.get_message(sort_by_key).get("status")

View File

@ -2,9 +2,12 @@
- hold all form classes used in the views
"""
import os
from django import forms
from django.contrib.auth.forms import AuthenticationForm
from django.forms.widgets import PasswordInput, TextInput
from home.src.ta.helper import get_stylesheets
class CustomAuthForm(AuthenticationForm):
@ -29,14 +32,16 @@ class CustomAuthForm(AuthenticationForm):
class UserSettingsForm(forms.Form):
"""user configurations values"""
CHOICES = [
("", "-- change color scheme --"),
("dark", "Dark"),
("light", "Light"),
]
STYLESHEET_CHOICES = [("", "-- change stylesheet --")]
STYLESHEET_CHOICES.extend(
[
(stylesheet, os.path.splitext(stylesheet)[0].title())
for stylesheet in get_stylesheets()
]
)
colors = forms.ChoiceField(
widget=forms.Select, choices=CHOICES, required=False
stylesheet = forms.ChoiceField(
widget=forms.Select, choices=STYLESHEET_CHOICES, required=False
)
page_size = forms.IntegerField(required=False)

View File

@ -12,6 +12,7 @@ from datetime import datetime
from urllib.parse import urlparse
import requests
from home.src.ta.settings import EnvironmentSettings
def ignore_filelist(filelist: list[str]) -> list[str]:
@ -203,3 +204,21 @@ def ta_host_parser(ta_host: str) -> tuple[list[str], list[str]]:
csrf_trusted_origins.append(f"{parsed.scheme}://{parsed.hostname}")
return allowed_hosts, csrf_trusted_origins
def get_stylesheets():
"""Get all valid stylesheets from /static/css"""
app_root = EnvironmentSettings.APP_DIR
stylesheets = os.listdir(os.path.join(app_root, "static/css"))
stylesheets.remove("style.css")
stylesheets.sort()
stylesheets = list(filter(lambda x: x.endswith(".css"), stylesheets))
return stylesheets
def check_stylesheet(stylesheet: str):
"""Check if a stylesheet exists. Return dark.css as a fallback"""
if stylesheet in get_stylesheets():
return stylesheet
return "dark.css"

View File

@ -7,12 +7,13 @@ Functionality:
from typing import TypedDict
from home.src.es.connect import ElasticWrap
from home.src.ta.helper import get_stylesheets
class UserConfigType(TypedDict, total=False):
"""describes the user configuration"""
colors: str
stylesheet: str
page_size: int
sort_by: str
sort_order: str
@ -31,7 +32,7 @@ class UserConfig:
"""Handle settings for an individual user"""
_DEFAULT_USER_SETTINGS = UserConfigType(
colors="dark",
stylesheet="dark.css",
page_size=12,
sort_by="published",
sort_order="desc",
@ -46,7 +47,7 @@ class UserConfig:
sponsorblock_id=None,
)
VALID_COLORS = ["dark", "light"]
VALID_STYLESHEETS = get_stylesheets()
VALID_VIEW_STYLE = ["grid", "list"]
VALID_SORT_ORDER = ["asc", "desc"]
VALID_SORT_BY = ["published", "downloaded", "views", "likes"]
@ -91,7 +92,7 @@ class UserConfig:
)
valid_values = {
"colors": self.VALID_COLORS,
"stylesheet": self.VALID_STYLESHEETS,
"sort_by": self.VALID_SORT_BY,
"sort_order": self.VALID_SORT_ORDER,
"view_style_home": self.VALID_VIEW_STYLE,

View File

@ -23,11 +23,7 @@
{% else %}
<title>TubeArchivist</title>
{% endif %}
{% if colors == "dark" %}
<link rel="stylesheet" href="{% static 'css/dark.css' %}">
{% else %}
<link rel="stylesheet" href="{% static 'css/light.css' %}">
{% endif %}
<link rel="stylesheet" href="{% static 'css/' %}{{ stylesheet }}">
<script type="text/javascript" src="{% static 'script.js' %}"></script>
{% if cast %}
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
@ -39,12 +35,7 @@
<div class="boxed-content">
<div class="top-banner">
<a href="{% url 'home' %}">
{% if colors == 'dark' %}
<img src="{% static 'img/banner-tube-archivist-dark.png' %}" alt="tube-archivist-banner">
{% endif %}
{% if colors == 'light' %}
<img src="{% static 'img/banner-tube-archivist-light.png' %}" alt="tube-archivist-banner">
{% endif %}
<img alt="tube-archivist-banner">
</a>
</div>
<div class="top-nav">

View File

@ -18,20 +18,11 @@
<meta name="msapplication-TileColor" content="#01202e">
<meta name="msapplication-config" content="{% static 'favicon/browserconfig.xml' %}">
<meta name="theme-color" content="#01202e">
{% if colors == "dark" %}
<link rel="stylesheet" href="{% static 'css/dark.css' %}">
{% else %}
<link rel="stylesheet" href="{% static 'css/light.css' %}">
{% endif %}
<link rel="stylesheet" href="{% static 'css/' %}{{ stylesheet }}">
</head>
<body>
<div class="boxed-content login-page">
{% if colors == 'dark' %}
<img src="{% static 'img/logo-tube-archivist-dark.png' %}" alt="tube-archivist-logo">
{% endif %}
{% if colors == 'light' %}
<img src="{% static 'img/logo-tube-archivist-light.png' %}" alt="tube-archivist-banner">
{% endif %}
<img alt="tube-archivist-logo">
<h1>Tube Archivist</h1>
<h2>Your Self Hosted YouTube Media Server</h2>
{% if form_error %}

View File

@ -7,11 +7,11 @@
<form action="{% url 'settings_user' %}" method="POST" name="user-update">
{% csrf_token %}
<div class="settings-group">
<h2>Color scheme</h2>
<h2>Stylesheet</h2>
<div class="settings-item">
<p>Current color scheme: <span class="settings-current">{{ colors }}</span></p>
<i>Select your preferred color scheme between dark and light mode.</i><br>
{{ user_form.colors }}
<p>Current stylesheet: <span class="settings-current">{{ stylesheet }}</span></p>
<i>Select your preferred stylesheet.</i><br>
{{ user_form.stylesheet }}
</div>
</div>
<div class="settings-group">

View File

@ -39,7 +39,7 @@ from home.src.index.playlist import YoutubePlaylist
from home.src.index.reindex import ReindexProgress
from home.src.index.video_constants import VideoTypeEnum
from home.src.ta.config import AppConfig, ReleaseVersion, ScheduleBuilder
from home.src.ta.helper import time_parser
from home.src.ta.helper import check_stylesheet, time_parser
from home.src.ta.settings import EnvironmentSettings
from home.src.ta.ta_redis import RedisArchivist
from home.src.ta.users import UserConfig
@ -73,7 +73,9 @@ class ArchivistViewConfig(View):
self.user_conf = UserConfig(self.user_id)
self.context = {
"colors": self.user_conf.get_value("colors"),
"stylesheet": check_stylesheet(
self.user_conf.get_value("stylesheet")
),
"cast": EnvironmentSettings.ENABLE_CAST,
"sort_by": self.user_conf.get_value("sort_by"),
"sort_order": self.user_conf.get_value("sort_order"),
@ -220,7 +222,9 @@ class MinView(View):
def get_min_context(request):
"""build minimal vars for context"""
return {
"colors": UserConfig(request.user.id).get_value("colors"),
"stylesheet": check_stylesheet(
UserConfig(request.user.id).get_value("stylesheet")
),
"version": settings.TA_VERSION,
"ta_update": ReleaseVersion().get_update(),
}
@ -977,9 +981,9 @@ class SettingsUserView(MinView):
config_handler = UserConfig(request.user.id)
if user_form.is_valid():
user_form_post = user_form.cleaned_data
if user_form_post.get("colors"):
if user_form_post.get("stylesheet"):
config_handler.set_value(
"colors", user_form_post.get("colors")
"stylesheet", user_form_post.get("stylesheet")
)
if user_form_post.get("page_size"):
config_handler.set_value(

View File

@ -9,4 +9,6 @@
--accent-font-light: #97d4c8;
--img-filter: invert(50%) sepia(9%) saturate(2940%) hue-rotate(122deg) brightness(94%) contrast(90%);
--img-filter-error: invert(16%) sepia(60%) saturate(3717%) hue-rotate(349deg) brightness(86%) contrast(120%);
--banner: url("../img/banner-tube-archivist-dark.png");
--logo: url("../img/logo-tube-archivist-dark.png");
}

View File

@ -9,4 +9,6 @@
--accent-font-light: #35b399;
--img-filter: invert(50%) sepia(9%) saturate(2940%) hue-rotate(122deg) brightness(94%) contrast(90%);
--img-filter-error: invert(16%) sepia(60%) saturate(3717%) hue-rotate(349deg) brightness(86%) contrast(120%);
--banner: url("../img/banner-tube-archivist-light.png");
--logo: url("../img/logo-tube-archivist-light.png");
}

View File

@ -0,0 +1,75 @@
:root {
--main-bg: #000000;
--highlight-bg: #080808;
--highlight-error: #880000;
--highlight-error-light: #aa0000;
--highlight-bg-transparent: #0c0c0caf;
--main-font: #00aa00;
--accent-font-dark: #007700;
--accent-font-light: #00aa00;
--img-filter: invert(50%) sepia(9%) saturate(2940%) hue-rotate(122deg) brightness(94%) contrast(90%);
--img-filter-error: invert(16%) sepia(60%) saturate(3717%) hue-rotate(349deg) brightness(86%) contrast(120%);
--banner: url("../img/banner-tube-archivist-dark.png");
--logo: url("../img/logo-tube-archivist-dark.png");
--outline: 1px solid green;
--filter: hue-rotate(310deg);
}
.settings-group {
outline: var(--outline);
}
.info-box-item {
outline: var(--outline);
}
.footer {
outline: var(--outline);
}
.nav-icons {
filter: var(--filter);
}
.view-icons {
filter: var(--filter);
}
.top-banner {
filter: var(--filter);
}
.icon-text {
outline: var(--outline);
}
.video-item {
outline: var(--outline);
}
.channel-banner {
outline: var(--outline);
}
.description-box {
outline: var(--outline);
}
.video-player {
outline: var(--outline);
}
#notification {
outline: var(--outline);
}
textarea {
background-color: var(--highlight-bg);
outline: var(--outline);
color: var(--main-font);
}
input {
background-color: var(--highlight-bg);
color: var(--main-font);
}

View File

@ -0,0 +1,14 @@
:root {
--main-bg: #000000;
--highlight-bg: #0c0c0c;
--highlight-error: #220000;
--highlight-error-light: #330000;
--highlight-bg-transparent: #0c0c0caf;
--main-font: #888888;
--accent-font-dark: #555555;
--accent-font-light: #999999;
--img-filter: invert(50%) sepia(9%) saturate(2940%) hue-rotate(122deg) brightness(94%) contrast(90%);
--img-filter-error: invert(16%) sepia(60%) saturate(3717%) hue-rotate(349deg) brightness(86%) contrast(120%);
--banner: url("../img/banner-tube-archivist-dark.png");
--logo: url("../img/logo-tube-archivist-dark.png");
}

View File

@ -165,12 +165,13 @@ button:hover {
.top-banner img {
width: 100%;
max-width: 700px;
content: var(--banner);
}
.footer {
margin: 0;
padding: 20px 0;
background-color: var(--accent-font-dark);
background-color: var(--highlight-bg);
grid-row-start: 2;
grid-row-end: 3;
}
@ -725,6 +726,7 @@ video:-webkit-full-screen {
max-width: 200px;
max-height: 200px;
margin-bottom: 40px;
content: var(--logo);
}
.login-page form {