diff options
Diffstat (limited to 'Biz')
| -rw-r--r-- | Biz/PodcastItLater/Web.py | 148 |
1 files changed, 126 insertions, 22 deletions
diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py index 2032746..39e2240 100644 --- a/Biz/PodcastItLater/Web.py +++ b/Biz/PodcastItLater/Web.py @@ -52,6 +52,60 @@ from typing import override logger = Log.setup() + +def create_theme_switcher_script() -> html.script: + """Create JavaScript for theme switching with localStorage persistence.""" + return html.script( + """ + // Theme switcher with localStorage persistence + (function() { + 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 => { + document.documentElement.setAttribute('data-bs-theme', theme); + const icon = document.getElementById('theme-icon'); + if (icon) { + icon.className = theme === 'dark' + ? 'bi bi-sun-fill' + : 'bi bi-moon-fill'; + } + }; + + // Set theme on page load + setTheme(getPreferredTheme()); + + // Theme toggle button handler + window.toggleTheme = () => { + const currentTheme = document.documentElement + .getAttribute('data-bs-theme'); + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; + setTheme(newTheme); + setStoredTheme(newTheme); + }; + + // Listen for system theme changes + window.matchMedia('(prefers-color-scheme: dark)') + .addEventListener('change', e => { + if (!getStoredTheme()) { + setTheme(e.matches ? 'dark' : 'light'); + } + }); + })(); + """, + ) + + # Configuration area = App.from_env() BASE_URL = os.getenv("BASE_URL", "http://localhost:8000") @@ -649,24 +703,49 @@ class BillingPage(Component[AnyChildren, BillingPageAttrs]): ), html.div( html.div( - html.h1( - html.i(classes=["bi", "bi-credit-card", "me-2"]), - "Billing & Usage", - classes=["mb-4"], - ), html.div( - html.a( - html.i(classes=["bi", "bi-arrow-left", "me-1"]), - "Back to Dashboard", - href="/", - classes=[ - "btn", - "btn-outline-secondary", - "mb-4", - ], + html.h1( + html.i( + classes=["bi", "bi-credit-card", "me-2"], + ), + "Billing & Usage", + classes=["mb-4"], + ), + html.div( + html.a( + html.i( + classes=["bi", "bi-arrow-left", "me-1"], + ), + "Back to Dashboard", + href="/", + classes=[ + "btn", + "btn-outline-secondary", + "mb-4", + ], + ), + ), + classes=["flex-grow-1"], + ), + html.button( + html.i( + id="theme-icon", + classes=["bi", "bi-moon-fill"], ), + on_click="toggleTheme()", + classes=[ + "btn", + "btn-outline-secondary", + "position-absolute", + "top-0", + "end-0", + "mt-3", + "me-3", + ], + title="Toggle dark mode", + type="button", ), - classes=["mb-4"], + classes=["position-relative", "mb-4"], ), # Success/Error alerts html.div( @@ -803,6 +882,8 @@ class BillingPage(Component[AnyChildren, BillingPageAttrs]): integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL", crossorigin="anonymous", ), + # Theme switcher script + create_theme_switcher_script(), ), ) @@ -936,15 +1017,36 @@ class HomePage(Component[AnyChildren, HomePageAttrs]): html.div( # Header html.div( - html.h1( - "PodcastItLater", - classes=["display-4", "mb-2"], + html.div( + html.h1( + "PodcastItLater", + classes=["display-4", "mb-2"], + ), + html.p( + "Convert web articles to podcast episodes", + classes=["lead", "text-muted"], + ), + classes=["text-center", "flex-grow-1"], ), - html.p( - "Convert web articles to podcast episodes", - classes=["lead", "text-muted"], + html.button( + html.i( + id="theme-icon", + classes=["bi", "bi-moon-fill"], + ), + on_click="toggleTheme()", + classes=[ + "btn", + "btn-outline-secondary", + "position-absolute", + "top-0", + "end-0", + "mt-3", + "me-3", + ], + title="Toggle dark mode", + type="button", ), - classes=["text-center", "mb-4", "pt-4"], + classes=["position-relative", "mb-4", "pt-4"], ), # Error alert html.div( @@ -1078,6 +1180,8 @@ class HomePage(Component[AnyChildren, HomePageAttrs]): integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL", crossorigin="anonymous", ), + # Theme switcher script + create_theme_switcher_script(), ), ) |
