Extract slide-over script to shared component
Creates slide_over_script() in shared_scripts.py that generates JavaScript for slide-over panels with open/close functions. EventSlideOverScript and SidebarScript now use this shared function, reducing duplicated JS logic. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ from starlette.requests import Request
|
||||
|
||||
from animaltrack.models.reference import UserRole
|
||||
from animaltrack.web.templates.nav import BottomNav, BottomNavStyles
|
||||
from animaltrack.web.templates.shared_scripts import slide_over_script
|
||||
from animaltrack.web.templates.sidebar import (
|
||||
MenuDrawer,
|
||||
Sidebar,
|
||||
@@ -79,29 +80,13 @@ def EventSlideOverStyles(): # noqa: N802
|
||||
|
||||
def EventSlideOverScript(): # noqa: N802
|
||||
"""JavaScript for event slide-over panel open/close behavior."""
|
||||
return Script("""
|
||||
function openEventPanel() {
|
||||
document.getElementById('event-slide-over').classList.add('open');
|
||||
document.getElementById('event-backdrop').classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
// Focus the panel for keyboard events
|
||||
document.getElementById('event-slide-over').focus();
|
||||
}
|
||||
|
||||
function closeEventPanel() {
|
||||
document.getElementById('event-slide-over').classList.remove('open');
|
||||
document.getElementById('event-backdrop').classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// HTMX event: after loading event content, open the panel
|
||||
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
||||
if (evt.detail.target.id === 'event-slide-over' ||
|
||||
evt.detail.target.id === 'event-panel-content') {
|
||||
openEventPanel();
|
||||
}
|
||||
});
|
||||
""")
|
||||
return slide_over_script(
|
||||
panel_id="event-slide-over",
|
||||
backdrop_id="event-backdrop",
|
||||
open_fn_name="openEventPanel",
|
||||
close_fn_name="closeEventPanel",
|
||||
htmx_auto_open_targets=["event-slide-over", "event-panel-content"],
|
||||
)
|
||||
|
||||
|
||||
def CsrfHeaderScript(): # noqa: N802
|
||||
|
||||
58
src/animaltrack/web/templates/shared_scripts.py
Normal file
58
src/animaltrack/web/templates/shared_scripts.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# ABOUTME: Shared JavaScript script generators for AnimalTrack templates.
|
||||
# ABOUTME: Provides reusable script components to reduce code duplication.
|
||||
|
||||
from fasthtml.common import Script
|
||||
|
||||
|
||||
def slide_over_script(
|
||||
panel_id: str,
|
||||
backdrop_id: str,
|
||||
open_fn_name: str,
|
||||
close_fn_name: str,
|
||||
htmx_auto_open_targets: list[str] | None = None,
|
||||
) -> Script:
|
||||
"""Generate JavaScript for slide-over panel open/close behavior.
|
||||
|
||||
Creates global functions for opening and closing a slide-over panel with
|
||||
backdrop. Optionally auto-opens when HTMX swaps content into specified targets.
|
||||
|
||||
Args:
|
||||
panel_id: DOM ID of the slide-over panel element.
|
||||
backdrop_id: DOM ID of the backdrop overlay element.
|
||||
open_fn_name: Name of the global function to open the panel.
|
||||
close_fn_name: Name of the global function to close the panel.
|
||||
htmx_auto_open_targets: List of target element IDs that trigger auto-open
|
||||
when HTMX swaps content into them.
|
||||
|
||||
Returns:
|
||||
Script element containing the JavaScript code.
|
||||
"""
|
||||
# Build HTMX auto-open listener if targets specified
|
||||
htmx_listener = ""
|
||||
if htmx_auto_open_targets:
|
||||
conditions = " ||\n ".join(
|
||||
f"evt.detail.target.id === '{target}'" for target in htmx_auto_open_targets
|
||||
)
|
||||
htmx_listener = f"""
|
||||
// HTMX event: after loading content, open the panel
|
||||
document.body.addEventListener('htmx:afterSwap', function(evt) {{
|
||||
if ({conditions}) {{
|
||||
{open_fn_name}();
|
||||
}}
|
||||
}});"""
|
||||
|
||||
return Script(f"""
|
||||
function {open_fn_name}() {{
|
||||
document.getElementById('{panel_id}').classList.add('open');
|
||||
document.getElementById('{backdrop_id}').classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
// Focus the panel for keyboard events
|
||||
document.getElementById('{panel_id}').focus();
|
||||
}}
|
||||
|
||||
function {close_fn_name}() {{
|
||||
document.getElementById('{panel_id}').classList.remove('open');
|
||||
document.getElementById('{backdrop_id}').classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
}}{htmx_listener}
|
||||
""")
|
||||
@@ -1,12 +1,13 @@
|
||||
# ABOUTME: Responsive sidebar and menu drawer components for AnimalTrack.
|
||||
# ABOUTME: Desktop shows persistent sidebar, mobile shows slide-out drawer.
|
||||
|
||||
from fasthtml.common import A, Button, Div, Nav, Script, Span, Style
|
||||
from fasthtml.common import A, Button, Div, Nav, Span, Style
|
||||
from fasthtml.svg import Path, Svg
|
||||
|
||||
from animaltrack.build_info import get_build_info
|
||||
from animaltrack.models.reference import UserRole
|
||||
from animaltrack.web.templates.icons import EggIcon, FeedIcon, MoveIcon
|
||||
from animaltrack.web.templates.shared_scripts import slide_over_script
|
||||
|
||||
|
||||
def SidebarStyles(): # noqa: N802
|
||||
@@ -73,21 +74,12 @@ def SidebarStyles(): # noqa: N802
|
||||
|
||||
def SidebarScript(): # noqa: N802
|
||||
"""JavaScript for menu drawer open/close behavior."""
|
||||
return Script("""
|
||||
function openMenuDrawer() {
|
||||
document.getElementById('menu-drawer').classList.add('open');
|
||||
document.getElementById('menu-backdrop').classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
// Focus the drawer for keyboard events
|
||||
document.getElementById('menu-drawer').focus();
|
||||
}
|
||||
|
||||
function closeMenuDrawer() {
|
||||
document.getElementById('menu-drawer').classList.remove('open');
|
||||
document.getElementById('menu-backdrop').classList.remove('open');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
""")
|
||||
return slide_over_script(
|
||||
panel_id="menu-drawer",
|
||||
backdrop_id="menu-backdrop",
|
||||
open_fn_name="openMenuDrawer",
|
||||
close_fn_name="closeMenuDrawer",
|
||||
)
|
||||
|
||||
|
||||
def _primary_nav_item(label: str, href: str, icon_fn, is_active: bool):
|
||||
|
||||
Reference in New Issue
Block a user