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:
2026-01-09 12:20:18 +00:00
parent fc4c2a8e40
commit 4e78b79745
3 changed files with 74 additions and 39 deletions

View File

@@ -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

View 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}
""")

View File

@@ -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):