diff options
Diffstat (limited to 'src/frontend/app/components/Stops')
| -rw-r--r-- | src/frontend/app/components/Stops/ArrivalCard.css | 17 | ||||
| -rw-r--r-- | src/frontend/app/components/Stops/ArrivalCard.tsx | 72 | ||||
| -rw-r--r-- | src/frontend/app/components/Stops/ArrivalList.tsx | 25 |
3 files changed, 114 insertions, 0 deletions
diff --git a/src/frontend/app/components/Stops/ArrivalCard.css b/src/frontend/app/components/Stops/ArrivalCard.css new file mode 100644 index 0000000..5835352 --- /dev/null +++ b/src/frontend/app/components/Stops/ArrivalCard.css @@ -0,0 +1,17 @@ +@import "../../tailwind.css"; + +.time-running { + @apply bg-green-600/20 dark:bg-green-600/25 text-[#1a9e56] dark:text-[#22c55e]; +} + +.time-delayed { + @apply bg-orange-600/20 dark:bg-orange-600/25 text-[#d06100] dark:text-[#fb923c]; +} + +.time-past { + @apply bg-gray-600/20 dark:bg-gray-600/25 text-gray-600 dark:text-gray-400; +} + +.time-scheduled { + @apply bg-blue-900/20 dark:bg-blue-600/25 text-[#0b3d91] dark:text-[#93c5fd]; +} diff --git a/src/frontend/app/components/Stops/ArrivalCard.tsx b/src/frontend/app/components/Stops/ArrivalCard.tsx new file mode 100644 index 0000000..96d0af0 --- /dev/null +++ b/src/frontend/app/components/Stops/ArrivalCard.tsx @@ -0,0 +1,72 @@ +import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import LineIcon from "~/components/LineIcon"; +import { type Arrival } from "../../api/schema"; +import "./ArrivalCard.css"; + +interface ArrivalCardProps { + arrival: Arrival; + reduced?: boolean; +} + +export const ArrivalCard: React.FC<ArrivalCardProps> = ({ + arrival, + reduced, +}) => { + const { t } = useTranslation(); + const { route, headsign, estimate } = arrival; + + const etaValue = Math.max(0, Math.round(estimate.minutes)).toString(); + const etaUnit = t("estimates.minutes", "min"); + + const timeClass = useMemo(() => { + switch (estimate.precission) { + case "confident": + return "time-running"; + case "unsure": + return "time-delayed"; + case "past": + return "time-past"; + default: + return "time-scheduled"; + } + }, [estimate.precission]); + + return ( + <div + className={` + flex-none flex items-center gap-2.5 min-h-12 + bg-(--message-background-color) border border-(--border-color) + rounded-xl px-3 py-2.5 transition-all + ${reduced ? "reduced" : ""} + `.trim()} + > + <div className="shrink-0 min-w-[7ch]"> + <LineIcon + line={route.shortName} + colour={route.colour} + textColour={route.textColour} + mode="pill" + /> + </div> + <div className="flex-1 min-w-0 flex flex-col gap-1"> + <strong className="text-base text-(--text-color) overflow-hidden text-ellipsis line-clamp-2 leading-tight"> + {headsign.destination} + </strong> + </div> + <div + className={` + inline-flex items-center justify-center px-2 py-1.5 rounded-xl shrink-0 + ${timeClass} + `.trim()} + > + <div className="flex flex-col items-center leading-none"> + <span className="text-lg font-bold leading-none">{etaValue}</span> + <span className="text-[0.65rem] uppercase tracking-wider mt-0.5 opacity-90"> + {etaUnit} + </span> + </div> + </div> + </div> + ); +}; diff --git a/src/frontend/app/components/Stops/ArrivalList.tsx b/src/frontend/app/components/Stops/ArrivalList.tsx new file mode 100644 index 0000000..a1210d5 --- /dev/null +++ b/src/frontend/app/components/Stops/ArrivalList.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { type Arrival } from "../../api/schema"; +import { ArrivalCard } from "./ArrivalCard"; + +interface ArrivalListProps { + arrivals: Arrival[]; + reduced?: boolean; +} + +export const ArrivalList: React.FC<ArrivalListProps> = ({ + arrivals, + reduced, +}) => { + return ( + <div className="flex flex-col gap-3"> + {arrivals.map((arrival, index) => ( + <ArrivalCard + key={`${arrival.route.shortName}-${index}`} + arrival={arrival} + reduced={reduced} + /> + ))} + </div> + ); +}; |
