Skip to content

Specification: Kiosk Leaderboard Dashboard (Live-Sync)

1. Layout & Architecture

  • Structure: Use a single-page h-screen overflow-hidden layout using Tailwind CSS.
  • Layers:
    • Top (5vh): Integration of the existing Cyclist Ticker (Live-Active Cyclists).
    • Header (15vh): School Banner showing the Top 3 Schools (aggregated mileage).
    • Main (75vh): Flexible Auto-Grid for Group Tiles.
    • Footer (5vh): Global statistics (Total KM) and Live Activity Counter.
  • Floating Element: A 'Daily Record' Trophy Badge in the top-right corner, tilted 12 degrees.

2. Grid Logic (Group Tiles)

  • Flexibility: Use grid-cols-[repeat(auto-fit,minmax(220px,1fr))].
  • States (Focus-Dimming):
    • Active (<30s): Green ring, pulse animation, scale-105, z-20, opacity-100.
    • Idle (<10m): Standard appearance, opacity-100.
    • Dormant (>10m): opacity-40, grayscale, scale-95. Use transition-all duration-1000.
  • Ranking: - Rank 1: Gold gradient + Crown Icon + Shadow Glow.
    • Rank 2/3: Silver/Bronze gradients.
    • Others: Dark Slate cards with high-contrast text.

3. Data & Sync (Django + HTMX)

  • Optimization: Use a single view-level calculation for active_group_ids and recent_group_ids to avoid N+1 queries.
  • Live Counter: Display a pulsing red dot next to the text "[X] Groups currently pedaling".
  • Daily Record: Calculate the highest mileage achieved since 00:00 today and display the holder's name and value.
  • Updates: Trigger a full HTMX swap for the Leaderboard section every 20 seconds using hx-trigger="every 20s".
  • Page Rotation: - Implement a 60-second rotation between the 'Map View' and the 'Leaderboard View'.
    • Use HTMX or a simple setTimeout Javascript logic to toggle a hidden class or swap the content.
    • Add a visual 'Next swap in X seconds' progress bar at the very bottom to inform viewers.
    • Ensure the OSM map is not re-initialized every time to save performance; hide/show is preferred over re-loading.

4. Map Integration (OSM)

  • Context: The dashboard must coexist with the existing OSM map showing travel tracks and milestones.
  • Toggle/Overlay: Propose a way to either:
    • Side-by-side: 50% Map / 50% Leaderboard.
    • Overlay: The Leaderboard as a semi-transparent sidebar on the left/right of the map.
  • Requirement: Ensure the Leaderboard logic (Active Glow) can trigger interactions on the map (e.g., center map on an active group's last milestone).

5. Coding Standards (Strict)

  • Language: All code, comments, and docstrings must be in English.
  • Type Hints: Use full Python type hinting for all new methods and views.
  • Naming: Follow Django best practices; use gettext_lazy for any German UI strings.

6. View Rotation & Manual Override

  • Auto-Rotation: Toggle between #map-view and #leaderboard-view every 60 seconds.
  • Progress Indicator: Display a 2px high progress bar at the bottom (bg-blue-600) that resets every 60s.
  • Manual Control:
    • Spacebar / Right Arrow: Immediately skip to the next view and reset the 60s timer.
    • 'P' Key: Pause/Resume the auto-rotation (show a small 'Paused' icon in a corner).
  • Persistence: Ensure the OSM map is only initialized once and hidden using CSS display: none to preserve zoom levels and markers.

7. Group Tile Content & Hierarchy

  • Primary Label: Display group.get_kiosk_label (the short name like '1a') in a very large, bold font.
  • Subtitle: Display group.school_name directly below the primary label in a smaller, semi-transparent font (e.g., text-sm opacity-70).
  • Mileage: The total kilometers (distance_total) should be the most prominent numerical element on the tile.
  • Layout: Use a vertical stack inside the tile: School Name (top) -> Short Name (center) -> KM (bottom).