aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-11-19 12:40:48 +0100
committerAriel Costas Guerrero <ariel@costas.dev>2025-11-19 12:40:48 +0100
commitd434204860fc0409ad6343e815d0057b97ce3573 (patch)
tree37d349fb3a39e727150134a32e745c64a7312571 /src
parentd6a28db658487bab63067499c3c7dbe6165e18c1 (diff)
Some UI tweaks
Diffstat (limited to 'src')
-rw-r--r--src/frontend/app/components/StopMapSheet.css11
-rw-r--r--src/frontend/app/components/StopMapSheet.tsx37
-rw-r--r--src/frontend/app/components/StopSheet.css1
-rw-r--r--src/frontend/app/root.css5
-rw-r--r--src/frontend/app/routes/home.css2
-rw-r--r--src/frontend/app/routes/map.tsx42
-rw-r--r--src/frontend/app/routes/stops-$id.css3
-rw-r--r--src/frontend/app/routes/stops-$id.tsx19
-rw-r--r--src/frontend/public/maps/styles/openfreemap-dark.json28
-rw-r--r--src/frontend/public/maps/styles/openfreemap-light.json78
-rw-r--r--src/frontend/public/pwa-worker.js6
11 files changed, 152 insertions, 80 deletions
diff --git a/src/frontend/app/components/StopMapSheet.css b/src/frontend/app/components/StopMapSheet.css
index 4b0f528..2b28a13 100644
--- a/src/frontend/app/components/StopMapSheet.css
+++ b/src/frontend/app/components/StopMapSheet.css
@@ -76,6 +76,17 @@
animation: userPulse 1.8s ease-out infinite;
}
+.stop-map-container small {
+ position: absolute;
+ bottom: 4px;
+ left: 4px;
+ font-size: 12px;
+ color: var(--text-secondary);
+ background-color: rgba(255, 255, 255, 0.7);
+ padding: 2px 4px;
+ border-radius: 4px;
+}
+
@keyframes userPulse {
0% {
transform: scale(0.6);
diff --git a/src/frontend/app/components/StopMapSheet.tsx b/src/frontend/app/components/StopMapSheet.tsx
index b3a1666..8bdcfa9 100644
--- a/src/frontend/app/components/StopMapSheet.tsx
+++ b/src/frontend/app/components/StopMapSheet.tsx
@@ -1,9 +1,9 @@
import maplibregl from "maplibre-gl";
import React, { useEffect, useMemo, useRef, useState } from "react";
import Map, {
- AttributionControl,
- Marker,
- type MapRef,
+ AttributionControl,
+ Marker,
+ type MapRef,
} from "react-map-gl/maplibre";
import { useApp } from "~/AppContext";
import { getLineColor } from "~/data/LineColors";
@@ -184,8 +184,26 @@ export const StopMap: React.FC<StopMapProps> = ({
useEffect(() => {
if (!styleSpec || !mapRef.current || hasFitBounds.current) return;
+ const map = mapRef.current.getMap();
+
+ // Handle missing sprite images to suppress console warnings
+ const handleStyleImageMissing = (e: any) => {
+ if (!map || map.hasImage(e.id)) return;
+ // Add a transparent 1x1 placeholder
+ map.addImage(e.id, {
+ width: 1,
+ height: 1,
+ data: new Uint8Array(4),
+ });
+ };
+
+ map.on("styleimagemissing", handleStyleImageMissing);
+
const points = computeFocusPoints();
- if (points.length === 0) return;
+ if (points.length === 0) {
+ map.off("styleimagemissing", handleStyleImageMissing);
+ return;
+ }
let minLat = points[0].lat,
maxLat = points[0].lat,
@@ -223,6 +241,15 @@ export const StopMap: React.FC<StopMapProps> = ({
}
hasFitBounds.current = true;
} catch {}
+
+ return () => {
+ if (mapRef.current) {
+ const map = mapRef.current.getMap();
+ if (map) {
+ map.off("styleimagemissing", handleStyleImageMissing);
+ }
+ }
+ };
}, [styleSpec, stop.latitude, stop.longitude, busPositions, userPosition]);
const handleCenter = () => {
@@ -435,7 +462,7 @@ export const StopMap: React.FC<StopMapProps> = ({
})()}
</Map>
)}
- {/* Floating controls */}
+
<div className="map-floating-controls">
<button
type="button"
diff --git a/src/frontend/app/components/StopSheet.css b/src/frontend/app/components/StopSheet.css
index 31770a1..a34d730 100644
--- a/src/frontend/app/components/StopSheet.css
+++ b/src/frontend/app/components/StopSheet.css
@@ -177,6 +177,7 @@
gap: 0.75rem;
margin: 0.75rem 0 1rem 0;
padding-top: 0.75rem;
+ padding-inline: 16px;
}
.stop-sheet-timestamp {
diff --git a/src/frontend/app/root.css b/src/frontend/app/root.css
index 6331140..6c3dd99 100644
--- a/src/frontend/app/root.css
+++ b/src/frontend/app/root.css
@@ -144,9 +144,8 @@ body {
}
.navigation-bar__link svg {
- width: 1.5rem;
- height: 1.5rem;
- margin-bottom: 5px;
+ width: 1.375rem;
+ height: 1.375rem;
fill: none;
stroke-width: 2;
}
diff --git a/src/frontend/app/routes/home.css b/src/frontend/app/routes/home.css
index 253c0ab..3d5ba3a 100644
--- a/src/frontend/app/routes/home.css
+++ b/src/frontend/app/routes/home.css
@@ -1,6 +1,6 @@
/* Common page styles */
.page-title {
- font-size: 1.8rem;
+ font-size: 1.4rem;
margin-bottom: 1rem;
font-weight: 600;
color: var(--text-color);
diff --git a/src/frontend/app/routes/map.tsx b/src/frontend/app/routes/map.tsx
index 5a8c7a2..b8fb881 100644
--- a/src/frontend/app/routes/map.tsx
+++ b/src/frontend/app/routes/map.tsx
@@ -1,22 +1,21 @@
import StopDataProvider, { type Stop } from "../data/StopDataProvider";
import "./map.css";
+import { loadStyle } from "app/maps/styleloader";
+import type { Feature as GeoJsonFeature, Point } from "geojson";
import { useEffect, useRef, useState } from "react";
-import { useApp } from "~/AppContext";
+import { useTranslation } from "react-i18next";
import Map, {
- AttributionControl,
- GeolocateControl,
- Layer,
- NavigationControl,
- Source,
- type MapRef,
- type MapLayerMouseEvent,
- type StyleSpecification,
+ GeolocateControl,
+ Layer,
+ NavigationControl,
+ Source,
+ type MapLayerMouseEvent,
+ type MapRef,
+ type StyleSpecification
} from "react-map-gl/maplibre";
-import { loadStyle } from "app/maps/styleloader";
-import type { Feature as GeoJsonFeature, Point } from "geojson";
+import { useApp } from "~/AppContext";
import { StopSheet } from "~/components/StopSheet";
-import { useTranslation } from "react-i18next";
import { REGIONS } from "~/data/RegionConfig";
// Default minimal fallback style before dynamic loading
@@ -96,10 +95,26 @@ export default function StopMap() {
updateMapState([center.lat, center.lng], zoom);
};
+ const handleStyleImageMissing = (e: any) => {
+ // Suppress warnings for missing sprite images from base style
+ // This prevents console noise from OpenFreeMap's missing icons
+ if (!mapRef.current) return;
+ const map = mapRef.current.getMap();
+ if (!map || map.hasImage(e.id)) return;
+
+ // Add a transparent 1x1 placeholder to prevent repeated warnings
+ map.addImage(e.id, {
+ width: 1,
+ height: 1,
+ data: new Uint8Array(4),
+ });
+ };
+
if (mapRef.current) {
const map = mapRef.current.getMap();
if (map) {
map.on("moveend", handleMapChange);
+ map.on("styleimagemissing", handleStyleImageMissing);
}
}
@@ -108,6 +123,7 @@ export default function StopMap() {
const map = mapRef.current.getMap();
if (map) {
map.off("moveend", handleMapChange);
+ map.off("styleimagemissing", handleStyleImageMissing);
}
}
};
@@ -168,7 +184,7 @@ export default function StopMap() {
layout={{
"icon-image": [
"case",
- ["boolean", ["get", "cancelled"], false],
+ ["coalesce", ["get", "cancelled"], false],
`stop-${region}-cancelled`,
`stop-${region}`,
],
diff --git a/src/frontend/app/routes/stops-$id.css b/src/frontend/app/routes/stops-$id.css
index 7df3af2..c515435 100644
--- a/src/frontend/app/routes/stops-$id.css
+++ b/src/frontend/app/routes/stops-$id.css
@@ -1,5 +1,6 @@
.page-title {
margin-block: 0;
+ font-size: 1.5rem;
}
.estimates-content-wrapper {
@@ -269,7 +270,7 @@
background-color: #fff3cd;
border: 1px solid #ffc107;
border-radius: 8px;
- padding: 1rem;
+ padding: 0.5rem 1rem;
color: #856404;
flex-shrink: 0;
}
diff --git a/src/frontend/app/routes/stops-$id.tsx b/src/frontend/app/routes/stops-$id.tsx
index ac41250..372582b 100644
--- a/src/frontend/app/routes/stops-$id.tsx
+++ b/src/frontend/app/routes/stops-$id.tsx
@@ -191,14 +191,19 @@ export default function Estimates() {
<>
<div className="page-container stops-page">
<div className="stops-header">
+ <div>
+ <Star
+ className={`star-icon ${favourited ? "active" : ""}`}
+ onClick={toggleFavourite}
+ width={20}
+ />
+ <Edit2
+ className="edit-icon"
+ onClick={handleRename}
+ width={20} />
+ </div>
<h1 className="page-title">
- <Star
- className={`star-icon ${favourited ? "active" : ""}`}
- onClick={toggleFavourite}
- />
- <Edit2 className="edit-icon" onClick={handleRename} />
- {getStopDisplayName()}{" "}
- <span className="estimates-stop-id">({stopIdNum})</span>
+ {getStopDisplayName()}
</h1>
<button
diff --git a/src/frontend/public/maps/styles/openfreemap-dark.json b/src/frontend/public/maps/styles/openfreemap-dark.json
index 2803f1a..eb9cd25 100644
--- a/src/frontend/public/maps/styles/openfreemap-dark.json
+++ b/src/frontend/public/maps/styles/openfreemap-dark.json
@@ -3344,13 +3344,22 @@
"paint": {
"line-opacity": [
"interpolate",
- ["linear"],
- ["get", "zoom"],
- 0, 1,
- 14, 1,
- 16, 0.8,
- 18, 0.6,
- 22, 0.6
+ [
+ "linear"
+ ],
+ [
+ "zoom"
+ ],
+ 0,
+ 1,
+ 14,
+ 1,
+ 16,
+ 0.8,
+ 18,
+ 0.6,
+ 22,
+ 0.6
],
"line-color": [
"match",
@@ -3360,19 +3369,14 @@
],
"#CONGESTION",
"hsl(70.7 100% 38%)",
-
"#MUYDENSO",
"hsl(36.49 100% 50%)",
-
"#DENSO",
"hsl(47.61 100% 49%)",
-
"#FLUIDO",
"hsl(83.9 100% 40%)",
-
"#MUYFLUIDO",
"hsl(161.25 100% 42%)",
-
"hsl(0.0 0% 0%)"
],
"line-width": [
diff --git a/src/frontend/public/maps/styles/openfreemap-light.json b/src/frontend/public/maps/styles/openfreemap-light.json
index d616fe7..535659f 100644
--- a/src/frontend/public/maps/styles/openfreemap-light.json
+++ b/src/frontend/public/maps/styles/openfreemap-light.json
@@ -5287,10 +5287,14 @@
false
],
[
- "\u003E=",
+ ">=",
[
- "get",
- "rank"
+ "coalesce",
+ [
+ "get",
+ "rank"
+ ],
+ 0
],
20
]
@@ -5392,7 +5396,7 @@
"bus"
],
[
- "\u003E=",
+ ">=",
[
"get",
"rank"
@@ -5400,10 +5404,14 @@
7
],
[
- "\u003C",
+ "<",
[
- "get",
- "rank"
+ "coalesce",
+ [
+ "get",
+ "rank"
+ ],
+ 0
],
20
]
@@ -5505,26 +5513,26 @@
"bus"
],
[
- "!=",
+ ">=",
[
- "get",
- "class"
- ],
- "bus"
- ],
- [
- "\u003E=",
- [
- "get",
- "rank"
+ "coalesce",
+ [
+ "get",
+ "rank"
+ ],
+ 1
],
1
],
[
- "\u003C",
+ "<",
[
- "get",
- "rank"
+ "coalesce",
+ [
+ "get",
+ "rank"
+ ],
+ 0
],
7
]
@@ -6993,13 +7001,22 @@
"paint": {
"line-opacity": [
"interpolate",
- ["linear"],
- ["get", "zoom"],
- 0, 1,
- 14, 1,
- 16, 0.8,
- 18, 0.6,
- 22, 0.6
+ [
+ "linear"
+ ],
+ [
+ "zoom"
+ ],
+ 0,
+ 1,
+ 14,
+ 1,
+ 16,
+ 0.8,
+ 18,
+ 0.6,
+ 22,
+ 0.6
],
"line-color": [
"match",
@@ -7009,19 +7026,14 @@
],
"#CONGESTION",
"hsl(70.7 100% 38%)",
-
"#MUYDENSO",
"hsl(36.49 100% 50%)",
-
"#DENSO",
"hsl(47.61 100% 49%)",
-
"#FLUIDO",
"hsl(83.9 100% 40%)",
-
"#MUYFLUIDO",
"hsl(161.25 100% 42%)",
-
"hsl(0.0 0% 0%)"
],
"line-width": [
diff --git a/src/frontend/public/pwa-worker.js b/src/frontend/public/pwa-worker.js
index eb69b84..649a161 100644
--- a/src/frontend/public/pwa-worker.js
+++ b/src/frontend/public/pwa-worker.js
@@ -1,4 +1,4 @@
-const CACHE_VERSION = "20251107a";
+const CACHE_VERSION = "20251118a";
const STATIC_CACHE_NAME = `static-cache-${CACHE_VERSION}`;
const STATIC_CACHE_ASSETS = ["/favicon.ico", "/logo-256.png", "/logo-512.jpg"];
@@ -9,7 +9,6 @@ const ESTIMATES_MIN_AGE = 15 * 1000;
const ESTIMATES_MAX_AGE = 30 * 1000;
self.addEventListener("install", (event) => {
- console.log("SW: Install event in progress. Cache version: ", CACHE_VERSION);
event.waitUntil(
caches
.open(STATIC_CACHE_NAME)
@@ -67,17 +66,14 @@ async function handleStaticRequest(request) {
const cache = await caches.open(STATIC_CACHE_NAME);
const cachedResponse = await cache.match(request);
if (cachedResponse) {
- console.log("SW handleStaticRequest: HIT for ", request.url);
return cachedResponse;
}
try {
const netResponse = await fetch(request);
if (netResponse.ok) cache.put(request, netResponse.clone());
- console.log("SW handleStaticRequest: MISS for ", request.url);
return netResponse;
} catch (err) {
- console.error("SW handleStaticRequest: FAIL for ", request.url, err);
return null;
}
}