Update theme switcher
This commit is contained in:
parent
42fbd6eeea
commit
026f6ab02e
|
|
@ -1 +1 @@
|
|||
0.1.0-alpha.2
|
||||
0.1.0-alpha.3
|
||||
20
messages.pot
20
messages.pot
|
|
@ -6,16 +6,16 @@
|
|||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Starfall 0.1.0-alpha.2\n"
|
||||
"Project-Id-Version: Starfall 0.1.0-alpha.3\n"
|
||||
"Report-Msgid-Bugs-To: flare@theflare.at\n"
|
||||
"POT-Creation-Date: 2026-03-09 01:32+0100\n"
|
||||
"POT-Creation-Date: 2026-03-09 09:57+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.10.3\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
|
||||
#: web/templates/base.jinja:6
|
||||
msgid "base.meta.title.empty"
|
||||
|
|
@ -41,19 +41,23 @@ msgstr ""
|
|||
msgid "base.label.toggle_nav"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/base.jinja:50
|
||||
#: web/templates/base.jinja:47
|
||||
msgid "base.label.theme.btn"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/base.jinja:52
|
||||
msgid "base.label.theme.light"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/base.jinja:53
|
||||
#: web/templates/base.jinja:55
|
||||
msgid "base.label.theme.dark"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/base.jinja:56
|
||||
#: web/templates/base.jinja:58
|
||||
msgid "base.label.theme.auto"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/base.jinja:82
|
||||
#: web/templates/base.jinja:84
|
||||
msgid "base.label.copy"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -113,7 +117,7 @@ msgstr ""
|
|||
msgid "error.404.title"
|
||||
msgstr ""
|
||||
|
||||
#: web/templates/errors/not_found.jinja:10
|
||||
#: web/templates/errors/not_found.jinja:9
|
||||
msgid "error.404.body"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from inspect import isclass
|
|||
from pkgutil import iter_modules
|
||||
from typing import final
|
||||
|
||||
from flask import Blueprint, Flask, g, request
|
||||
from flask import Blueprint, Flask, request
|
||||
from flask_assets import Bundle, Environment
|
||||
from flask_babel import Babel
|
||||
from livereload import Server
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -7,17 +7,16 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Starfall 0.1.0-alpha.2\n"
|
||||
"Report-Msgid-Bugs-To: flare@theflare.at\n"
|
||||
"POT-Creation-Date: 2026-03-09 01:32+0100\n"
|
||||
"POT-Creation-Date: 2026-03-09 09:57+0100\n"
|
||||
"PO-Revision-Date: 2026-03-09 01:34+0100\n"
|
||||
"Last-Translator: Flare Starfall <flare@theflare.at>\n"
|
||||
"Language-Team: en <LL@li.org>\n"
|
||||
"Language: en\n"
|
||||
"Language-Team: en <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Generated-By: Babel 2.10.3\n"
|
||||
"X-Generator: Poedit 3.8\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
|
||||
#: web/templates/base.jinja:6
|
||||
msgid "base.meta.title.empty"
|
||||
|
|
@ -43,19 +42,23 @@ msgstr "Starfall - Logo"
|
|||
msgid "base.label.toggle_nav"
|
||||
msgstr "Open menu"
|
||||
|
||||
#: web/templates/base.jinja:50
|
||||
#: web/templates/base.jinja:47
|
||||
msgid "base.label.theme.btn"
|
||||
msgstr "Theme"
|
||||
|
||||
#: web/templates/base.jinja:52
|
||||
msgid "base.label.theme.light"
|
||||
msgstr "Light"
|
||||
|
||||
#: web/templates/base.jinja:53
|
||||
#: web/templates/base.jinja:55
|
||||
msgid "base.label.theme.dark"
|
||||
msgstr "Dark"
|
||||
|
||||
#: web/templates/base.jinja:56
|
||||
#: web/templates/base.jinja:58
|
||||
msgid "base.label.theme.auto"
|
||||
msgstr "Auto"
|
||||
|
||||
#: web/templates/base.jinja:82
|
||||
#: web/templates/base.jinja:84
|
||||
msgid "base.label.copy"
|
||||
msgstr "© Team Starfall"
|
||||
|
||||
|
|
@ -126,8 +129,8 @@ msgstr ""
|
|||
"<p>The following privacy policy is intended to inform you in particular "
|
||||
"about the type, scope, purpose, duration, and legal basis for the "
|
||||
"processing of such data either under our own control or in conjunction "
|
||||
"with others. We also inform you below about the third-party components "
|
||||
"we use to optimize our website and improve the user experience which may "
|
||||
"with others. We also inform you below about the third-party components we"
|
||||
" use to optimize our website and improve the user experience which may "
|
||||
"result in said third parties also processing data they collect and "
|
||||
"control.</p>\n"
|
||||
"<p>Our privacy policy is structured as follows:</p>\n"
|
||||
|
|
@ -138,9 +141,9 @@ msgstr ""
|
|||
#: web/templates/imprint.jinja:36
|
||||
msgid "page.imprint.sec2.body"
|
||||
msgstr ""
|
||||
"<p>The party responsible for this website (the „controller“) for "
|
||||
"purposes of data protection law is:<br>Robert Bäs-Fischlmair a.k.a. "
|
||||
"Flare Starfall<br>Phone: +43 (0) 677 62890651<br>Email: <a "
|
||||
"<p>The party responsible for this website (the „controller“) for purposes"
|
||||
" of data protection law is:<br>Robert Bäs-Fischlmair a.k.a. Flare "
|
||||
"Starfall<br>Phone: +43 (0) 677 62890651<br>Email: <a "
|
||||
"href=\"mailto:flare@theflare.at\">flare@theflare.at</a></p>"
|
||||
|
||||
#: web/templates/imprint.jinja:37
|
||||
|
|
@ -150,20 +153,20 @@ msgstr ""
|
|||
"below, users and data subjects have the right</p>\n"
|
||||
"<ul>\n"
|
||||
"<li>to confirmation of whether data concerning them is being processed, "
|
||||
"information about the data being processed, further information about "
|
||||
"the nature of the data processing, and copies of the data (cf. also Art. "
|
||||
"15 GDPR);</li>\n"
|
||||
"<li>to correct or complete incorrect or incomplete data (cf. also Art. "
|
||||
"16 GDPR);</li>\n"
|
||||
"information about the data being processed, further information about the"
|
||||
" nature of the data processing, and copies of the data (cf. also Art. 15 "
|
||||
"GDPR);</li>\n"
|
||||
"<li>to correct or complete incorrect or incomplete data (cf. also Art. 16"
|
||||
" GDPR);</li>\n"
|
||||
"<li>to the immediate deletion of data concerning them (cf. also Art. 17 "
|
||||
"DSGVO), or, alternatively, if further processing is necessary as "
|
||||
"stipulated in Art. 17 Para. 3 GDPR, to restrict said processing per Art. "
|
||||
"18 GDPR; </li> <li>to receive copies of the data concerning them and/or "
|
||||
"provided by them and to have the same transmitted to other providers/"
|
||||
"controllers (cf. also Art. 20 GDPR);</li> <li>to file complaints with "
|
||||
"the supervisory authority if they believe that data concerning them is "
|
||||
"being processed by the controller in breach of data protection "
|
||||
"provisions (see also Art. 77 GDPR).</li>\n"
|
||||
"provided by them and to have the same transmitted to other "
|
||||
"providers/controllers (cf. also Art. 20 GDPR);</li> <li>to file "
|
||||
"complaints with the supervisory authority if they believe that data "
|
||||
"concerning them is being processed by the controller in breach of data "
|
||||
"protection provisions (see also Art. 77 GDPR).</li>\n"
|
||||
"</ul>\n"
|
||||
"<p>In addition, the controller is obliged to inform all recipients to "
|
||||
"whom it discloses data of any such corrections, deletions, or "
|
||||
|
|
@ -171,10 +174,10 @@ msgstr ""
|
|||
"GDPR. However, this obligation does not apply if such notification is "
|
||||
"impossible or involves a disproportionate effort. Nevertheless, users "
|
||||
"have a right to information about these recipients.</p>\n"
|
||||
"<p><strong>Likewise, under Art. 21 GDPR, users and data subjects have "
|
||||
"the right to object to the controller's future processing of their "
|
||||
"data pursuant to Art. 6 Para. 1 lit. f) GDPR. In particular, an "
|
||||
"objection to data processing for the purpose of direct advertising is "
|
||||
"<p><strong>Likewise, under Art. 21 GDPR, users and data subjects have the"
|
||||
" right to object to the controller's future processing of their data"
|
||||
" pursuant to Art. 6 Para. 1 lit. f) GDPR. In particular, an objection to "
|
||||
"data processing for the purpose of direct advertising is "
|
||||
"permissible.</strong></p>"
|
||||
|
||||
#: web/templates/imprint.jinja:38
|
||||
|
|
@ -190,8 +193,8 @@ msgstr ""
|
|||
"ensure a secure and stable website: These server log files record the "
|
||||
"type and version of your browser, operating system, the webpages on our "
|
||||
"site visited, and the date and time of your visit. The IP address from "
|
||||
"which you visited our site is additionally recorded if an error occurs.</"
|
||||
"p>\n"
|
||||
"which you visited our site is additionally recorded if an error "
|
||||
"occurs.</p>\n"
|
||||
"<p>The data thus collected will be temporarily stored, but not in "
|
||||
"association with any other of your data.</p>\n"
|
||||
"<p>The basis for this storage is Art. 6 Para. 1 lit. f) GDPR. Our "
|
||||
|
|
@ -206,8 +209,9 @@ msgstr ""
|
|||
msgid "error.404.title"
|
||||
msgstr "404 Not Found"
|
||||
|
||||
#: web/templates/errors/not_found.jinja:10
|
||||
#: web/templates/errors/not_found.jinja:9
|
||||
msgid "error.404.body"
|
||||
msgstr ""
|
||||
"<p>Whatever you were looking for cannot be found here.<br>You may want "
|
||||
"to <a href=\"/\">start over</a>.</p>"
|
||||
"<p>Whatever you were looking for cannot be found here.<br>You may want to"
|
||||
" <a href=\"/\">start over</a>.</p>"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
/*!
|
||||
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors
|
||||
* Licensed under the Creative Commons Attribution 3.0 Unported License.
|
||||
*/
|
||||
|
||||
(() => {
|
||||
'use strict'
|
||||
|
||||
const getStoredTheme = () => localStorage.getItem('theme')
|
||||
const setStoredTheme = theme => localStorage.setItem('theme', theme)
|
||||
|
||||
const getPreferredTheme = () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme) {
|
||||
return storedTheme
|
||||
}
|
||||
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
const setTheme = theme => {
|
||||
if (theme === 'auto') {
|
||||
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(getPreferredTheme())
|
||||
|
||||
const showActiveTheme = (theme, focus = false) => {
|
||||
const themeSwitcher = document.querySelector('#bd-theme')
|
||||
|
||||
if (!themeSwitcher) {
|
||||
return
|
||||
}
|
||||
|
||||
const themeSwitcherText = document.querySelector('#bd-theme-text')
|
||||
const activeThemeIcon = document.querySelector('.theme-icon-active use')
|
||||
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
|
||||
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
|
||||
element.classList.remove('active')
|
||||
element.setAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
btnToActive.classList.add('active')
|
||||
btnToActive.setAttribute('aria-pressed', 'true')
|
||||
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
|
||||
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
|
||||
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
|
||||
|
||||
if (focus) {
|
||||
themeSwitcher.focus()
|
||||
}
|
||||
}
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme !== 'light' && storedTheme !== 'dark') {
|
||||
setTheme(getPreferredTheme())
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
showActiveTheme(getPreferredTheme())
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]')
|
||||
.forEach(toggle => {
|
||||
toggle.addEventListener('click', () => {
|
||||
const theme = toggle.getAttribute('data-bs-theme-value')
|
||||
setStoredTheme(theme)
|
||||
setTheme(theme)
|
||||
showActiveTheme(theme, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})()
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
"use strict";
|
||||
|
||||
class S_ThemeSwitcher {
|
||||
static attach() {
|
||||
window.S_ThemeSwitcher = new S_ThemeSwitcher();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.setTheme(this.getStoredTheme() || this.getPreferredTheme());
|
||||
this.showActiveTheme();
|
||||
|
||||
document.querySelectorAll("[data-bs-theme-value]").forEach(function (button) {
|
||||
button.addEventListener("click", () => this.manageThemeClick(button, true));
|
||||
}, this);
|
||||
|
||||
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
||||
const storedTheme = this.getStoredTheme();
|
||||
if (storedTheme !== "light" && storedTheme !== "dark") {
|
||||
const theme = this.getColorTheme();
|
||||
const themeButton = document.querySelector("[data-bs-theme-value=\"" + theme + "\"]");
|
||||
this.manageThemeClick(themeButton);
|
||||
}
|
||||
});
|
||||
|
||||
const breakpointMd = window.getComputedStyle(document.body).getPropertyValue("--bs-breakpoint-md");
|
||||
const matchMd = window.matchMedia("(min-width: " + breakpointMd + ")");
|
||||
this.manageThemeText(matchMd.matches);
|
||||
matchMd.addEventListener("change", (ev) => this.manageThemeText(ev.matches));
|
||||
}
|
||||
|
||||
getStoredTheme() {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
|
||||
setStoredTheme(theme) {
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
|
||||
getPreferredTheme() {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
||||
}
|
||||
|
||||
getColorTheme() {
|
||||
const theme = this.getStoredTheme();
|
||||
return ('auto' === theme) ? this.getPreferredTheme() : theme;
|
||||
}
|
||||
|
||||
setTheme(theme) {
|
||||
document.documentElement.setAttribute("data-bs-theme", ("auto" === theme) ? this.getPreferredTheme() : theme);
|
||||
}
|
||||
|
||||
showActiveTheme(focus = false) {
|
||||
const themeSwitcher = document.querySelector("#theme");
|
||||
if (!themeSwitcher) { return; }
|
||||
|
||||
const themeSwitcherIcon = themeSwitcher.querySelector("i");
|
||||
|
||||
const activeTheme = this.getColorTheme();
|
||||
const activeThemeButton = document.querySelector("[data-bs-theme-value=\"" + activeTheme + "\"]");
|
||||
const activeThemeButtonIcon = activeThemeButton.querySelector("i");
|
||||
|
||||
themeSwitcherIcon.classList = activeThemeButtonIcon.classList;
|
||||
|
||||
if (focus) {
|
||||
themeSwitcher.focus();
|
||||
}
|
||||
}
|
||||
|
||||
manageThemeClick(button, focus = false) {
|
||||
const theme = button.getAttribute("data-bs-theme-value");
|
||||
this.setStoredTheme(theme);
|
||||
this.setTheme(theme);
|
||||
this.showActiveTheme(focus);
|
||||
}
|
||||
|
||||
manageThemeText(matches) {
|
||||
const themeSwitcher = document.querySelector("#theme");
|
||||
if (!themeSwitcher) { return; }
|
||||
|
||||
const themeSwitcherText = themeSwitcher.querySelector("span");
|
||||
themeSwitcherText.classList.toggle("visually-hidden", matches);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState !== "loading") {
|
||||
S_ThemeSwitcher.attach();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", S_ThemeSwitcher.attach);
|
||||
}
|
||||
|
|
@ -1,12 +1,2 @@
|
|||
$font-family-sans-serif: 'Overpass', system-ui, -apple-system, sans-serif;
|
||||
$font-size-base: 18px;
|
||||
|
||||
[data-bs-theme="light"] {
|
||||
--site-background: linear-gradient(to bottom right, rgb(80, 160, 220), rgb(114, 165, 255));
|
||||
--nav-background: rgba(211, 164, 255, 0.3);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] {
|
||||
--site-background: linear-gradient(to bottom right, rgb(70, 81, 110), rgb(16, 20, 60));
|
||||
--nav-background: rgba(28, 29, 54, 0.4);
|
||||
}
|
||||
$font-size-base: 18px;
|
||||
|
|
@ -1,3 +1,13 @@
|
|||
[data-bs-theme="light"] {
|
||||
--site-background: linear-gradient(to bottom right, rgb(220, 230, 255), rgb(210, 240, 255));
|
||||
--nav-background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
[data-bs-theme="dark"] {
|
||||
--site-background: linear-gradient(to bottom right, rgb(70, 81, 110), rgb(16, 20, 60));
|
||||
--nav-background: rgba(28, 29, 54, 0.4);
|
||||
}
|
||||
|
||||
@mixin site-backgrounds(){
|
||||
background: var(--site-background);
|
||||
background-repeat: no-repeat;
|
||||
|
|
|
|||
|
|
@ -22,29 +22,30 @@
|
|||
|
||||
<header class="sticky-top">
|
||||
<nav class="navbar navbar-expand-md">
|
||||
<div class="container-fluid">
|
||||
<div class="container-fluid mx-2">
|
||||
<a class="navbar-brand" href="/">
|
||||
<img src="{{url_for('static', filename='img/logo.png')}}" alt="{{_('base.label.logo_alt')}}" />
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
<button class="me-auto navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="{{_('base.label.toggle_nav')}}">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
|
||||
<div class="collapse navbar-collapse d-md-flex flex-row justify-content-between" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav">
|
||||
{# %block title: Page title. #}
|
||||
{%block navLinks%}
|
||||
{%include 'components/nav_public.jinja'%}
|
||||
{%endblock%}
|
||||
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-menu dropdown">
|
||||
<button id="theme" class="btn btn-link nav-link dropdown-toggle" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-circle-half"></i>
|
||||
<span class="visually-hidden">{{_('base.label.theme.btn')}}</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<button class="dropdown-item" type="button" data-bs-theme-value="light">
|
||||
<i class="bi bi-brightness-high-fill"></i> {{_('base.label.theme.light')}}
|
||||
|
|
@ -78,17 +79,17 @@
|
|||
|
||||
<footer class="fixed-bottom">
|
||||
<nav class="navbar">
|
||||
<div class="container-fluid">
|
||||
<small>{{_('base.label.copy')}} {{bp.date.year}}</small>
|
||||
<ul class="navbar-nav">
|
||||
<div class="container-fluid mx-2 row">
|
||||
<small class="col">{{_('base.label.copy')}} {{bp.date.year}}</small>
|
||||
<ul class="col navbar-nav d-flex flex-row justify-content-end">
|
||||
{%include 'components/nav_foot.jinja'%}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
<script type="text/javascript" src="{{url_for('static', filename='js/bootstrap.bundle.min.js')}}"></script>
|
||||
<script type="text/javascript" src="{{url_for('static', filename='js/color-switcher.js')}}"></script>
|
||||
<script type="text/javascript" src="{{url_for('static', filename='js/bootstrap.bundle.min.js')}}" defer></script>
|
||||
<script type="text/javascript" src="{{url_for('static', filename='js/theme-switcher.js')}}" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,9 +1 @@
|
|||
{%extends 'base.jinja'%}
|
||||
|
||||
{%block body%}
|
||||
<div class="container" id="content">
|
||||
<div class="d-flex flex-column">
|
||||
<h1>Starfall</h1>
|
||||
</div>
|
||||
</div>
|
||||
{%endblock%}
|
||||
{%extends 'base.jinja'%}
|
||||
Loading…
Reference in New Issue