Add a Locus Pro-style toolbar readout: DMS coords + sunrise/sunset

The topbar's coordinate display was plain decimal degrees ("48.14611,
17.17722") — switched to DMS (48°08'46"N 17°10'38"E), the more
GPS-unit-like format Locus Pro itself uses, and made it click-to-copy
(plain decimal, since that's what pastes cleanly into another map/GPS
app — not the DMS text actually shown).

Added sunrise/sunset + a countdown to whichever's next, for the same
map-center point the coordinates already describe. Vendored SunCalc
(BSD-2-Clause, github.com/mourner/suncalc) rather than hand-rolling
the astronomical math — small, dependency-free, and correctness here
has real pitfalls (equation of time, refraction, polar day/night) a
first-pass reimplementation would risk getting subtly wrong.

Also added a test asserting every public/js/*.js module has a
versioned importmap entry in layout.erb — caught that overlays.js
(from the previous commit) was missing one, which would have quietly
skipped ASSET_VERSION's cache-busting for that file after every
deploy.
This commit is contained in:
randy committed 2026-09-10 21:08:02 +02:00
1 parent c5b4a9ffb2
commit dce5fd87da
8 files changed
+696 -3

No files matched your search

+16
View File
@@ -18,6 +18,22 @@ class AppTest < Minitest::Test
assert_includes response.body, "livetrack-panel"
end
# Every public/js/*.js module map.js (or something it imports) can reach
# needs its own versioned importmap entry (views/layout.erb) or it skips
# ASSET_VERSION's whole cache-busting story — easy to forget when adding a
# new module, since the app still works fine locally either way (a plain
# unmapped import just resolves straight to the unversioned file).
# map.js itself is excluded: it's the one entry point loaded directly by
# its own <script> tag, not imported by anything, so it has no importmap
# entry of its own by design.
def test_every_own_js_module_has_a_versioned_importmap_entry
response = request.get("/")
modules = Dir.glob(File.join(__dir__, "..", "public", "js", "*.js")).map { |path| File.basename(path) } - ["map.js"]
modules.each do |name|
assert_match(%r{"/js/#{Regexp.escape(name)}":\s*"/js/#{Regexp.escape(name)}\?v=\d+"}, response.body, "#{name} is missing from the importmap")
end
end
def test_offline_tiles_reports_unavailable_when_no_pmtiles_present
response = request.get("/api/offline-tiles")
assert_equal({ "available" => false }, json_body(response))