aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/app/routes
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-11-14 18:24:43 +0100
committerAriel Costas Guerrero <ariel@costas.dev>2025-11-14 18:24:53 +0100
commitd285093900ff6f8e3d5dba394999bb413f5d00f3 (patch)
tree88b9127d031177b8e3787d4e263ae7cb7d9a461f /src/frontend/app/routes
parent80f6263516e307bcc6d887f6f91757bc73ae63f2 (diff)
Enhance stop map functionality with new styles and components for better user experience
Diffstat (limited to 'src/frontend/app/routes')
-rw-r--r--src/frontend/app/routes/estimates-$id.css53
-rw-r--r--src/frontend/app/routes/stops-$id.tsx79
2 files changed, 103 insertions, 29 deletions
diff --git a/src/frontend/app/routes/estimates-$id.css b/src/frontend/app/routes/estimates-$id.css
index 81fba1d..ff09f82 100644
--- a/src/frontend/app/routes/estimates-$id.css
+++ b/src/frontend/app/routes/estimates-$id.css
@@ -1,6 +1,20 @@
+.estimates-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ min-height: 0;
+ flex: 1;
+}
+
+.estimates-list-container {
+ overflow-y: auto;
+ flex: 1;
+ min-height: 0;
+ border-radius: 0.5rem;
+}
+
.table-responsive {
overflow-x: auto;
- margin-bottom: 1.5rem;
}
.table {
@@ -29,12 +43,20 @@
}
/* Estimates page specific styles */
+.estimates-page {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ overflow: hidden;
+}
+
.estimates-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 1rem;
gap: 1rem;
+ flex-shrink: 0;
}
.manual-refresh-button {
@@ -63,6 +85,32 @@
transform: none;
}
+.toggle-map-button {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ background: var(--primary-color);
+ border: none;
+ border-radius: 0.375rem;
+ font-size: 0.875rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ min-width: max-content;
+}
+
+.toggle-map-button:hover:not(:disabled) {
+ background: var(--primary-color-hover);
+ transform: translateY(-1px);
+}
+
+.toggle-map-button:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none;
+}
+
.refresh-icon {
width: 1.5rem;
height: 1.5rem;
@@ -215,6 +263,7 @@
gap: 0.5rem;
flex-wrap: wrap;
margin-bottom: 1rem;
+ flex-shrink: 0;
}
.estimates-lines-container.scrollable {
@@ -245,6 +294,7 @@
padding: 1rem;
margin-bottom: 1rem;
color: #856404;
+ flex-shrink: 0;
}
.experimental-notice strong {
@@ -282,6 +332,7 @@
color: var(--primary-color);
font-size: 0.9rem;
font-weight: 500;
+ flex-shrink: 0;
}
.refresh-status .refresh-icon {
diff --git a/src/frontend/app/routes/stops-$id.tsx b/src/frontend/app/routes/stops-$id.tsx
index 86e74d9..efe2867 100644
--- a/src/frontend/app/routes/stops-$id.tsx
+++ b/src/frontend/app/routes/stops-$id.tsx
@@ -1,18 +1,19 @@
-import { useEffect, useState, useCallback } from "react";
-import { useParams, Link } from "react-router";
-import StopDataProvider, { type Stop } from "../data/StopDataProvider";
-import { Star, Edit2, ExternalLink, RefreshCw } from "lucide-react";
-import "./estimates-$id.css";
-import { useApp } from "../AppContext";
+import { Edit2, RefreshCw, Star } from "lucide-react";
+import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
+import { useParams } from "react-router";
+import { ErrorDisplay } from "~/components/ErrorDisplay";
+import LineIcon from "~/components/LineIcon";
import { PullToRefresh } from "~/components/PullToRefresh";
-import { useAutoRefresh } from "~/hooks/useAutoRefresh";
-import { type RegionId, getRegionConfig } from "~/data/RegionConfig";
import { StopAlert } from "~/components/StopAlert";
-import LineIcon from "~/components/LineIcon";
+import { StopMap } from "~/components/StopMapSheet";
import { ConsolidatedCirculationList } from "~/components/Stops/ConsolidatedCirculationList";
import { ConsolidatedCirculationListSkeleton } from "~/components/Stops/ConsolidatedCirculationListSkeleton";
-import { ErrorDisplay } from "~/components/ErrorDisplay";
+import { type RegionId, getRegionConfig } from "~/data/RegionConfig";
+import { useAutoRefresh } from "~/hooks/useAutoRefresh";
+import { useApp } from "../AppContext";
+import StopDataProvider, { type Stop } from "../data/StopDataProvider";
+import "./estimates-$id.css";
export interface ConsolidatedCirculation {
line: string;
@@ -27,6 +28,11 @@ export interface ConsolidatedCirculation {
minutes: number;
distance: number;
};
+ currentPosition?: {
+ latitude: number;
+ longitude: number;
+ orientationDegrees: number;
+ };
}
interface ErrorInfo {
@@ -266,25 +272,42 @@ export default function Estimates() {
{stopData && <StopAlert stop={stopData} />}
- <div className="table-responsive">
- {dataLoading ? (
- <ConsolidatedCirculationListSkeleton />
- ) : dataError ? (
- <ErrorDisplay
- error={dataError}
- onRetry={loadData}
- title={t(
- "errors.estimates_title",
- "Error al cargar estimaciones",
- )}
- />
- ) : data ? (
- <ConsolidatedCirculationList
- data={data}
- dataDate={dataDate}
- regionConfig={regionConfig}
+ <div className="estimates-content-wrapper">
+ <div className="estimates-list-container">
+ <div className="table-responsive">
+ {dataLoading ? (
+ <ConsolidatedCirculationListSkeleton />
+ ) : dataError ? (
+ <ErrorDisplay
+ error={dataError}
+ onRetry={loadData}
+ title={t(
+ "errors.estimates_title",
+ "Error al cargar estimaciones",
+ )}
+ />
+ ) : data ? (
+ <ConsolidatedCirculationList
+ data={data}
+ dataDate={dataDate}
+ regionConfig={regionConfig}
+ />
+ ) : null}
+ </div>
+ </div>
+
+ {/* Map showing stop and bus positions */}
+ {stopData && (
+ <StopMap
+ stop={stopData}
+ region={region}
+ circulations={(data ?? []).map((c) => ({
+ line: c.line,
+ route: c.route,
+ currentPosition: c.currentPosition,
+ }))}
/>
- ) : null}
+ )}
</div>
</div>
</PullToRefresh>