diff options
| author | Copilot <198982749+Copilot@users.noreply.github.com> | 2025-11-06 20:34:36 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-06 20:34:36 +0100 |
| commit | a24639e17b63c5ebb9b2bb26af18e17302e9360b (patch) | |
| tree | 3301a4f8f278cab61696b2cd0212cb71e0676363 /src/frontend/app | |
| parent | 9a2e46b6e8f0decbd1995c14d34b0b8c0d663b49 (diff) | |
Add manual stop creation and override alerts with alternate stop codes (#74)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: arielcostas <94913521+arielcostas@users.noreply.github.com>
Co-authored-by: Ariel Costas Guerrero <ariel@costas.dev>
Diffstat (limited to 'src/frontend/app')
| -rw-r--r-- | src/frontend/app/components/StopAlert.css | 89 | ||||
| -rw-r--r-- | src/frontend/app/components/StopAlert.tsx | 36 | ||||
| -rw-r--r-- | src/frontend/app/components/StopSheet.tsx | 3 | ||||
| -rw-r--r-- | src/frontend/app/data/StopDataProvider.ts | 5 | ||||
| -rw-r--r-- | src/frontend/app/routes/estimates-$id.tsx | 3 |
5 files changed, 136 insertions, 0 deletions
diff --git a/src/frontend/app/components/StopAlert.css b/src/frontend/app/components/StopAlert.css new file mode 100644 index 0000000..0032d09 --- /dev/null +++ b/src/frontend/app/components/StopAlert.css @@ -0,0 +1,89 @@ +.stop-alert { + display: flex; + align-items: flex-start; + gap: 0.75rem; + padding: 0.75rem; + border-radius: 0.5rem; + margin: 0.75rem 0; + border: 1px solid; +} + +.stop-alert-info { + background-color: rgba(59, 130, 246, 0.1); + border-color: rgba(59, 130, 246, 0.3); + color: #1e40af; +} + +.stop-alert-error { + background-color: rgba(239, 68, 68, 0.1); + border-color: rgba(239, 68, 68, 0.3); + color: #991b1b; +} + +.stop-alert-compact { + padding: 0.5rem; + margin: 0.5rem 0; + font-size: 0.875rem; +} + +.stop-alert-icon { + flex-shrink: 0; + width: 1.25rem; + height: 1.25rem; +} + +.stop-alert-compact .stop-alert-icon { + width: 1rem; + height: 1rem; +} + +.stop-alert-content { + flex: 1; + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.stop-alert-title { + font-weight: 600; + font-size: 0.95rem; +} + +.stop-alert-compact .stop-alert-title { + font-size: 0.85rem; +} + +.stop-alert-message { + font-size: 0.9rem; + opacity: 0.9; +} + +.stop-alert-compact .stop-alert-message { + font-size: 0.8rem; +} + +.stop-alert-alternate-codes { + font-size: 0.85rem; + margin-top: 0.25rem; + font-style: italic; + opacity: 0.8; +} + +.stop-alert-compact .stop-alert-alternate-codes { + font-size: 0.75rem; +} + +/* Dark mode support */ +@media (prefers-color-scheme: dark) { + .stop-alert-info { + background-color: rgba(59, 130, 246, 0.15); + border-color: rgba(59, 130, 246, 0.4); + color: #93c5fd; + } + + .stop-alert-error { + background-color: rgba(239, 68, 68, 0.15); + border-color: rgba(239, 68, 68, 0.4); + color: #fca5a5; + } +} diff --git a/src/frontend/app/components/StopAlert.tsx b/src/frontend/app/components/StopAlert.tsx new file mode 100644 index 0000000..69ecc22 --- /dev/null +++ b/src/frontend/app/components/StopAlert.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { AlertCircle, Info } from "lucide-react"; +import type { Stop } from "~/data/StopDataProvider"; +import "./StopAlert.css"; + +interface StopAlertProps { + stop: Stop; + compact?: boolean; +} + +export const StopAlert: React.FC<StopAlertProps> = ({ stop, compact = false }) => { + // Don't render anything if there's no alert content + const hasContent = stop.title || stop.message; + if (!hasContent) { + return null; + } + + const isError = stop.cancelled === true; + + return ( + <div className={`stop-alert ${isError ? 'stop-alert-error' : 'stop-alert-info'} ${compact ? 'stop-alert-compact' : ''}`}> + <div className="stop-alert-icon"> + {isError ? <AlertCircle /> : <Info />} + </div> + <div className="stop-alert-content"> + {stop.title && <div className="stop-alert-title">{stop.title}</div>} + {stop.message && <div className="stop-alert-message">{stop.message}</div>} + {stop.alternateCodes && stop.alternateCodes.length > 0 && ( + <div className="stop-alert-alternate-codes"> + Alternative stops: {stop.alternateCodes.join(", ")} + </div> + )} + </div> + </div> + ); +}; diff --git a/src/frontend/app/components/StopSheet.tsx b/src/frontend/app/components/StopSheet.tsx index afa530b..695b18e 100644 --- a/src/frontend/app/components/StopSheet.tsx +++ b/src/frontend/app/components/StopSheet.tsx @@ -6,6 +6,7 @@ import { Clock, RefreshCw } from "lucide-react"; import LineIcon from "./LineIcon"; import { StopSheetSkeleton } from "./StopSheetSkeleton"; import { ErrorDisplay } from "./ErrorDisplay"; +import { StopAlert } from "./StopAlert"; import { type Estimate } from "../routes/estimates-$id"; import { REGIONS, type RegionId, getRegionConfig } from "../data/RegionConfig"; import { useApp } from "../AppContext"; @@ -144,6 +145,8 @@ export const StopSheet: React.FC<StopSheetProps> = ({ ))} </div> + <StopAlert stop={stop} compact /> + {loading ? ( <StopSheetSkeleton /> ) : error ? ( diff --git a/src/frontend/app/data/StopDataProvider.ts b/src/frontend/app/data/StopDataProvider.ts index e49faaa..25a617b 100644 --- a/src/frontend/app/data/StopDataProvider.ts +++ b/src/frontend/app/data/StopDataProvider.ts @@ -17,6 +17,11 @@ export interface Stop { longitude?: number; lines: string[]; favourite?: boolean; + amenities?: string[]; + cancelled?: boolean; + title?: string; + message?: string; + alternateCodes?: string[]; } // In-memory cache and lookup map per region diff --git a/src/frontend/app/routes/estimates-$id.tsx b/src/frontend/app/routes/estimates-$id.tsx index f213105..21186fb 100644 --- a/src/frontend/app/routes/estimates-$id.tsx +++ b/src/frontend/app/routes/estimates-$id.tsx @@ -14,6 +14,7 @@ import { ErrorDisplay } from "~/components/ErrorDisplay"; import { PullToRefresh } from "~/components/PullToRefresh"; import { useAutoRefresh } from "~/hooks/useAutoRefresh"; import { type RegionId, getRegionConfig } from "~/data/RegionConfig"; +import { StopAlert } from "~/components/StopAlert"; export interface Estimate { line: string; @@ -276,6 +277,8 @@ export default function Estimates() { </button> </div> + {stopData && <StopAlert stop={stopData} />} + <div className="table-responsive"> {estimatesLoading ? ( tableStyle === "grouped" ? ( |
