From a6ec0e52ecb33915cc4c4b22df1d2512ab9b0111 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:44:50 +0100 Subject: PWA: use standalone display mode and disable scroll on modal sheets (#82) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com> --- src/frontend/app/routes/estimates-$id.tsx | 4 +--- src/frontend/app/routes/map.tsx | 2 +- src/frontend/app/routes/settings.tsx | 11 +++++++-- src/frontend/app/routes/stops-$id.tsx | 40 ++++++++++++++++++++----------- src/frontend/app/routes/timetable-$id.tsx | 35 +++++++++++++++++---------- 5 files changed, 59 insertions(+), 33 deletions(-) (limited to 'src/frontend/app/routes') diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx index 81c83ea..84d25c1 100644 --- a/src/frontend/app/routes/estimates-$id.tsx +++ b/src/frontend/app/routes/estimates-$id.tsx @@ -299,9 +299,7 @@ export default function Estimates() { {stopData && stopData.lines && stopData.lines.length > 0 && ( -
+
{stopData.lines.map((line) => (
diff --git a/src/frontend/app/routes/map.tsx b/src/frontend/app/routes/map.tsx index e8b3cf3..40be174 100644 --- a/src/frontend/app/routes/map.tsx +++ b/src/frontend/app/routes/map.tsx @@ -144,7 +144,7 @@ export default function StopMap() { longitude: getLongitude(mapState.center), zoom: mapState.zoom, }} - attributionControl={{compact: false}} + attributionControl={{ compact: false }} maxBounds={ REGIONS[region].bounds ? [REGIONS[region].bounds!.sw, REGIONS[region].bounds!.ne] diff --git a/src/frontend/app/routes/settings.tsx b/src/frontend/app/routes/settings.tsx index c916877..85ec5a1 100644 --- a/src/frontend/app/routes/settings.tsx +++ b/src/frontend/app/routes/settings.tsx @@ -123,12 +123,19 @@ export default function Settings() { className="form-select-inline" value={tableStyle} onChange={(e) => - setTableStyle(e.target.value as "regular" | "grouped" | "experimental_consolidated") + setTableStyle( + e.target.value as + | "regular" + | "grouped" + | "experimental_consolidated", + ) } > - +
diff --git a/src/frontend/app/routes/stops-$id.tsx b/src/frontend/app/routes/stops-$id.tsx index ea60da7..7d533a5 100644 --- a/src/frontend/app/routes/stops-$id.tsx +++ b/src/frontend/app/routes/stops-$id.tsx @@ -27,7 +27,6 @@ export interface ConsolidatedCirculation { }; } - interface ErrorInfo { type: "network" | "server" | "unknown"; status?: number; @@ -39,11 +38,14 @@ const loadConsolidatedData = async ( stopId: string, ): Promise => { const regionConfig = getRegionConfig(region); - const resp = await fetch(`${regionConfig.consolidatedCirculationsEndpoint}?stopId=${stopId}`, { - headers: { - Accept: "application/json", + const resp = await fetch( + `${regionConfig.consolidatedCirculationsEndpoint}?stopId=${stopId}`, + { + headers: { + Accept: "application/json", + }, }, - }); + ); if (!resp.ok) { throw new Error(`HTTP ${resp.status}: ${resp.statusText}`); @@ -232,9 +234,7 @@ export default function Estimates() {
{stopData && stopData.lines && stopData.lines.length > 0 && ( -
+
{stopData.lines.map((line) => (
@@ -244,18 +244,30 @@ export default function Estimates() { )}
- {t("estimates.experimental_feature", "Experimental feature")} -

{t("estimates.experimental_description", "This view uses consolidated data from multiple real-time sources. This feature is experimental and may not be completely accurate.")}

+ + {t("estimates.experimental_feature", "Experimental feature")} + +

+ {t( + "estimates.experimental_description", + "This view uses consolidated data from multiple real-time sources. This feature is experimental and may not be completely accurate.", + )} +

{stopData && }
- {data ? (<> - - ) : null} + {data ? ( + <> + + + ) : null}
-
); diff --git a/src/frontend/app/routes/timetable-$id.tsx b/src/frontend/app/routes/timetable-$id.tsx index df77372..da7a2e7 100644 --- a/src/frontend/app/routes/timetable-$id.tsx +++ b/src/frontend/app/routes/timetable-$id.tsx @@ -450,7 +450,7 @@ const ScrollFabManager: React.FC<{ const style = getComputedStyle(el); const hasScroll = el.scrollHeight > el.clientHeight + 8; const overflowY = style.overflowY; - if (hasScroll && (overflowY === 'auto' || overflowY === 'scroll')) { + if (hasScroll && (overflowY === "auto" || overflowY === "scroll")) { return el; } el = el.parentElement; @@ -465,12 +465,14 @@ const ScrollFabManager: React.FC<{ const handleScroll = () => { const scrollTop = useWindowScroll - ? (window.scrollY || document.documentElement.scrollTop || 0) + ? window.scrollY || document.documentElement.scrollTop || 0 : scrollEl!.scrollTop; const scrollHeight = useWindowScroll ? document.documentElement.scrollHeight : scrollEl!.scrollHeight; - const clientHeight = useWindowScroll ? window.innerHeight : scrollEl!.clientHeight; + const clientHeight = useWindowScroll + ? window.innerHeight + : scrollEl!.clientHeight; const scrollBottom = scrollHeight - scrollTop - clientHeight; const threshold = 80; // slightly smaller threshold for responsiveness @@ -479,39 +481,46 @@ const ScrollFabManager: React.FC<{ if (nextEntryRef.current) { const rect = nextEntryRef.current.getBoundingClientRect(); - const isNextVisible = rect.top >= 0 && rect.bottom <= window.innerHeight; + const isNextVisible = + rect.top >= 0 && rect.bottom <= window.innerHeight; setShowGoToNow(!isNextVisible); } }; const target: any = useWindowScroll ? window : scrollEl!; - target.addEventListener('scroll', handleScroll, { passive: true }); - window.addEventListener('resize', handleScroll); + target.addEventListener("scroll", handleScroll, { passive: true }); + window.addEventListener("resize", handleScroll); handleScroll(); return () => { - target.removeEventListener('scroll', handleScroll); - window.removeEventListener('resize', handleScroll); + target.removeEventListener("scroll", handleScroll); + window.removeEventListener("resize", handleScroll); }; }, [containerRef, nextEntryRef, disabled, data, currentTime]); const scrollToTop = () => { const scrollEl = getScrollContainer(); if (!scrollEl) { - window.scrollTo({ top: 0, behavior: 'smooth' }); + window.scrollTo({ top: 0, behavior: "smooth" }); } else { - scrollEl.scrollTo({ top: 0, behavior: 'smooth' }); + scrollEl.scrollTo({ top: 0, behavior: "smooth" }); } }; const scrollToBottom = () => { const scrollEl = getScrollContainer(); if (!scrollEl) { - window.scrollTo({ top: document.documentElement.scrollHeight, behavior: 'smooth' }); + window.scrollTo({ + top: document.documentElement.scrollHeight, + behavior: "smooth", + }); } else { - scrollEl.scrollTo({ top: scrollEl.scrollHeight, behavior: 'smooth' }); + scrollEl.scrollTo({ top: scrollEl.scrollHeight, behavior: "smooth" }); } }; const scrollToNow = () => { - nextEntryRef.current?.scrollIntoView({ behavior: "smooth", block: "center" }); + nextEntryRef.current?.scrollIntoView({ + behavior: "smooth", + block: "center", + }); }; if (disabled) return null; -- cgit v1.3