Landscape orientation, redesigned web UI, rotation on/off + minutes, weather by city name

- Panel is mounted sideways: render landscape (600x400), rotate to the
  panel's native portrait orientation right before writing to hardware.
- Web UI: card-based layout, dark mode, active nav highlighting, save
  confirmation toasts, error banners.
- Rotation: separate enabled/disabled toggle (off pins to the first screen
  in the list) and the interval is now in minutes instead of raw seconds.
  Migrates existing config.json from the old interval_seconds field.
- Weather: type a city name instead of hunting down coordinates, resolved
  via Open-Meteo's free geocoding API. Manual lat/long still available as
  a fallback.
This commit is contained in:
Honey committed 2026-07-21 22:51:16 +02:00
1 parent 7c197e20a5
commit 61348be674
11 files changed
+393 -104

No files matched your search

+23 -13
View File
@@ -3,25 +3,35 @@
<h1>Rotation</h1>
<form method="post">
<div class="field">
<label>Navidrome takes over when music plays</label>
<div class="card">
<div class="section-label">Priority</div>
<label class="checkbox">
<input type="checkbox" name="navidrome_priority" {{ "checked" if navidrome_priority }}>
Show Navidrome immediately whenever something is playing, regardless of rotation
Navidrome takes over immediately whenever something is playing, regardless of rotation
</label>
</div>
<div class="field">
<label for="screens">Rotation order (used when Navidrome isn't playing, or if priority is off)</label>
<input type="text" id="screens" name="screens" value="{{ rotation.screens | join(', ') }}" placeholder="clock, weather">
<p style="font-size:0.8rem;color:#666">
Comma-separated, in order. Available: {{ screens.keys() | join(', ') }}.
<div class="card">
<div class="section-label">Rotation</div>
<label class="checkbox">
<input type="checkbox" name="rotation_enabled" {{ "checked" if rotation.enabled }}>
Enabled -- cycle through the screens below on a timer
</label>
<p class="hint" style="margin: 0.6rem 0 1.1rem;">
Off just pins to the first screen in the order below (still shown when
Navidrome priority is on but nothing's playing). "Show X now" buttons on
the Status page still work either way, they just don't stick past the
next check.
</p>
</div>
<div class="field">
<label for="interval_seconds">Rotation interval (seconds)</label>
<input type="number" id="interval_seconds" name="interval_seconds" value="{{ rotation.interval_seconds }}" min="10">
<div class="field">
<label for="screens">Order</label>
<input type="text" id="screens" name="screens" value="{{ rotation.screens | join(', ') }}" placeholder="clock, weather">
<p class="hint">Comma-separated, in order. Available: {{ screens.keys() | join(', ') }}.</p>
</div>
<div class="field">
<label for="interval_minutes">Switch every (minutes)</label>
<input type="number" id="interval_minutes" name="interval_minutes" value="{{ rotation.interval_minutes }}" min="1">
</div>
</div>
<button type="submit">Save</button>