diff --git a/requirements.txt b/requirements.txt index a1c7a40..ee057d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ django django-cors-headers requests +cariosvg diff --git a/tcommon/static/css/base.css b/tcommon/static/css/base.css index a5457fa..b60460f 100644 --- a/tcommon/static/css/base.css +++ b/tcommon/static/css/base.css @@ -24,6 +24,11 @@ body { font-size: 18px; } +::selection { + background-color: var(--accent); + color: var(--base); +} + code, pre { font-family: "Ubuntu Mono" } @@ -71,15 +76,20 @@ button { color: var(--text); font-family: "DejaVu Sans"; outline: 1px solid var(--surface0); - padding: 4px 8px; + padding: 4px 6px; min-width: 75px; border: none; margin: 2px 0; - border-radius: 8px; + border-radius: 99999px; cursor: pointer; transition: outline-color 0.25s, background-color 0.25s; } +ul, +ol { + padding-left: 15px; +} + input[type="submit"]:focus, button:focus { outline-color: var(--accent); diff --git a/tcommon/static/js/theme.js b/tcommon/static/js/theme.js index e0fd755..13f6375 100644 --- a/tcommon/static/js/theme.js +++ b/tcommon/static/js/theme.js @@ -1,16 +1,6 @@ let _themeMM = matchMedia("(prefers-color-scheme: light)"); let light, useAutoTheme; -// {% if theme == "auto" %} - light = _themeMM.matches; - useAutoTheme = true; -// {% else %} - // {% if theme == "light" %} - light = true; - // {% else %} - light = false; - // {% endif %} - useAutoTheme = false; -// {% endif %} +light = _themeMM.matches; function setTheme() { if (light) { @@ -21,10 +11,8 @@ function setTheme() { } _themeMM.addEventListener("change", function() { - if (useAutoTheme) { - light = _themeMM.matches; - setTheme(); - } + light = _themeMM.matches; + setTheme(); }); setTheme(); diff --git a/tcommon/urls.py b/tcommon/urls.py index deebf4d..fa28644 100644 --- a/tcommon/urls.py +++ b/tcommon/urls.py @@ -1,8 +1,9 @@ from django.urls import include, path -from .views import initialize +from .views import generate_favicon, initialize urlpatterns = [ path("api/initialize/", initialize), + path("favicon///", generate_favicon), path("static/", include("tcommon.views.static")) ] diff --git a/tcommon/views/__init__.py b/tcommon/views/__init__.py index f3ad99a..310570c 100644 --- a/tcommon/views/__init__.py +++ b/tcommon/views/__init__.py @@ -1 +1,2 @@ from .api import initialize # noqa: F401 +from .favicon import generate_favicon # noqa: F401 diff --git a/tcommon/views/api.py b/tcommon/views/api.py index aaf043c..081ae1c 100644 --- a/tcommon/views/api.py +++ b/tcommon/views/api.py @@ -21,6 +21,7 @@ def initialize(request: WSGIRequest) -> HttpResponse: resp = { "debug": DEBUG, "version": list(VERSION), + "version_str": ".".join([str(i) for i in VERSION]), "success": True, "services": { "common": { diff --git a/tcommon/views/favicon.py b/tcommon/views/favicon.py new file mode 100644 index 0000000..331e7cb --- /dev/null +++ b/tcommon/views/favicon.py @@ -0,0 +1,62 @@ +from cairosvg import svg2png +from django.http import HttpResponse, HttpResponseServerError +from django.views.decorators.cache import cache_page + +favicon = """ + + +""" + +colors = { + "base": { + "light": "#eff1f5", + "dark": "#1e1e2e" + }, + "accent": { + "light": { + "rosewater": "#dc8a78", + "flamingo": "#dd7878", + "pink": "#ea76cb", + "mauve": "#8839ef", + "red": "#d20f39", + "maroon": "#e64553", + "peach": "#fe640b", + "yellow": "#df8e1d", + "green": "#40a02b", + "teal": "#179299", + "sky": "#04a5e5", + "sapphire": "#209fb5", + "blue": "#1e66f5", + "lavender": "#7287fd" + }, + "dark": { + "rosewater": "#f5e0dc", + "flamingo": "#f2cdcd", + "pink": "#f5c2e7", + "mauve": "#cba6f7", + "red": "#f38ba8", + "maroon": "#eba0ac", + "peach": "#fab387", + "yellow": "#f9e2af", + "green": "#a6e3a1", + "teal": "#94e2d5", + "sky": "#89dceb", + "sapphire": "#74c7ec", + "blue": "#89b4fa", + "lavender": "#b4befe" + } + } +} + +@cache_page(60 * 60 * 2) +def generate_favicon(request, theme, accent) -> HttpResponse | HttpResponseServerError: + png_data: bytes | None = svg2png( + favicon.replace("{{ BASE }}", colors["base"][theme]).replace("{{ ACCENT }}", colors["accent"][theme][accent]), + output_width=64, + output_height=64 + ) + + if not isinstance(png_data, bytes): + return HttpResponseServerError("500 Internal Server Error") + + return HttpResponse(png_data, content_type="image/png") diff --git a/tcommon/views/static.py b/tcommon/views/static.py index 05da5f7..9214ee0 100644 --- a/tcommon/views/static.py +++ b/tcommon/views/static.py @@ -1,6 +1,6 @@ from django.http import HttpResponse from django.urls import path -from django.views.decorators.cache import cache_page +from django.views.decorators.cache import cache_control from tcommon.settings import STATIC_DIR @@ -21,7 +21,7 @@ file_associations = { "ttf": "font/ttf" } -urlpatterns = [path(i, cache_page(60 * 60 * 24 * 30)(get_static_serve(i, file_associations[i.split(".")[-1]]))) for i in [ +urlpatterns = [path(i, cache_control(**{"max-age": 60 * 60 * 24 * 30})(get_static_serve(i, file_associations[i.split(".")[-1]]))) for i in [ "css/base.css", "js/theme.js", "font/DejaVuSans-Bold.ttf",