diff options
Diffstat (limited to 'src/frontend/app/components/Stops')
3 files changed, 224 insertions, 242 deletions
diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css new file mode 100644 index 0000000..8a442c3 --- /dev/null +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.css @@ -0,0 +1,214 @@ +@reference "../../root.css"; + +.consolidated-circulation-card { + all: unset; + flex: 0 0 auto; + display: flex; + flex-direction: column; + gap: 0.5rem; + background-color: var(--message-background-color); + border-radius: 12px; + border: 1px solid var(--border-color); + padding: 0.65rem 0.85rem; + transition: all 0.2s ease; +} + +.consolidated-circulation-card.has-gps { + cursor: pointer; +} + +.consolidated-circulation-card.no-gps { + cursor: not-allowed; + opacity: 0.7; +} + +.consolidated-circulation-card.has-gps:hover { + box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08); + border-color: var(--button-background-color); + background-color: color-mix( + in oklab, + var(--button-background-color) 5%, + var(--message-background-color) + ); +} + +.consolidated-circulation-card.has-gps:active { + transform: scale(0.98); +} + +.consolidated-circulation-card:disabled { + pointer-events: none; +} + + +.consolidated-circulation-card .card-row { + display: flex; + align-items: center; + gap: 0.65rem; +} + +.consolidated-circulation-card .card-row.main { + min-height: 48px; +} + +.consolidated-circulation-card .line-info { + flex-shrink: 0; +} + +.consolidated-circulation-card .route-info { + flex: 1; + min-width: 0; +} + +.consolidated-circulation-card .route-info strong { + font-size: 1rem; + color: var(--text-color); + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; + line-height: 1.25; +} + +.consolidated-circulation-card .eta-badge { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.3rem 0.45rem; + border-radius: 12px; +} + +.consolidated-circulation-card .eta-text { + display: flex; + flex-direction: column; + align-items: center; + line-height: 1; +} + +.consolidated-circulation-card .eta-value { + font-size: 1.15rem; + font-weight: 700; +} + +.consolidated-circulation-card .eta-unit { + font-size: 0.65rem; + text-transform: uppercase; + letter-spacing: 0.08em; +} + +.consolidated-circulation-card .eta-badge.time-running { + background: rgba(34, 197, 94, 0.12); + color: #1a9e56; +} + +.consolidated-circulation-card .eta-badge.time-delayed { + background: rgba(255, 106, 0, 0.12); + color: #d06100; +} + +.consolidated-circulation-card .eta-badge.time-scheduled { + background: rgba(11, 61, 145, 0.12); + color: #0b3d91; +} + +[data-theme="dark"] .consolidated-circulation-card .eta-badge.time-scheduled { + color: #8fb4ff; +} + +.consolidated-circulation-card .card-row.meta { + flex-wrap: wrap; + justify-content: flex-start; + gap: 0.4rem; +} + +.meta-chip { + font-size: 0.75rem; + padding: 0.2rem 0.55rem; + border-radius: 999px; + background: rgba(0, 0, 0, 0.03); + + @apply flex items-center justify-center gap-1 flex-shrink-0 bg-gray-200/30 dark:bg-gray-600/30; +} + +.meta-chip.delay-ok { + @apply bg-green-400/30 dark:bg-green-600/30 border-green-500 dark:border-green-700 text-green-800 dark:text-green-200; +} + +.meta-chip.delay-warn { + @apply bg-yellow-400/30 dark:bg-yellow-600/30 border-yellow-500 dark:border-yellow-700 text-yellow-800 dark:text-yellow-200; +} + +.meta-chip.delay-critical { + @apply bg-red-400/30 dark:bg-red-600/30 border-red-500 dark:border-red-700 text-white; +} + +.meta-chip.delay-early { + @apply bg-blue-400/30 dark:bg-blue-600/30 border-blue-500 dark:border-blue-700 text-blue-800 dark:text-blue-200; +} + +/* GPS Indicator */ +.gps-indicator { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + flex-shrink: 0; + position: relative; +} + +.gps-pulse { + position: absolute; + width: 8px; + height: 8px; + background: #22c55e; + border-radius: 50%; + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + animation: gpsPulse 2s ease-in-out infinite; +} + +.gps-pulse.previous-trip { + background: #ff9800; + box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); + animation: gpsPulseOrange 2s ease-in-out infinite; +} + +@keyframes gpsPulse { + 0% { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + } + 50% { + box-shadow: 0 0 0 6px rgba(34, 197, 94, 0.1); + } + 100% { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + } +} + +@keyframes gpsPulseOrange { + 0% { + box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); + } + 50% { + box-shadow: 0 0 0 6px rgba(255, 152, 0, 0.1); + } + 100% { + box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); + } +} + +@media (max-width: 480px) { + .consolidated-circulation-card { + padding: 0.65rem 0.75rem; + } + + .consolidated-circulation-card .card-row { + gap: 0.5rem; + } + + .consolidated-circulation-card .eta-badge { + padding: 0.25rem 0.4rem; + } +} diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx index 707ecce..0b97c11 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationCard.tsx @@ -4,7 +4,7 @@ import { type RegionConfig } from "~/config/RegionConfig"; import LineIcon from "~components/LineIcon"; import { type ConsolidatedCirculation } from "~routes/stops-$id"; -import "./ConsolidatedCirculationList.css"; +import "./ConsolidatedCirculationCard.css"; interface ConsolidatedCirculationCardProps { estimate: ConsolidatedCirculation; @@ -75,18 +75,6 @@ export const ConsolidatedCirculationCard: React.FC< > = ({ estimate, regionConfig, onMapClick, readonly }) => { const { t } = useTranslation(); - const absoluteArrivalTime = (minutes: number) => { - const now = new Date(); - const arrival = new Date(now.getTime() + minutes * 60000); - return Intl.DateTimeFormat( - typeof navigator !== "undefined" ? navigator.language : "en", - { - hour: "2-digit", - minute: "2-digit", - } - ).format(arrival); - }; - const formatDistance = (meters: number) => { if (meters > 1024) { return `${(meters / 1000).toFixed(1)} km`; @@ -123,9 +111,12 @@ export const ConsolidatedCirculationCard: React.FC< return null; } - const delta = Math.round(estimate.realTime.minutes - estimate.schedule.minutes); + const delta = Math.round( + estimate.realTime.minutes - estimate.schedule.minutes + ); const absDelta = Math.abs(delta); + // On time if (delta === 0) { return { label: t("estimates.delay_on_time", "En hora (0 min)"), @@ -133,8 +124,10 @@ export const ConsolidatedCirculationCard: React.FC< } as const; } + // Delayed if (delta > 0) { - const tone = delta <= 2 ? "delay-ok" : delta <= 10 ? "delay-warn" : "delay-critical"; + const tone = + delta <= 2 ? "delay-ok" : delta <= 10 ? "delay-warn" : "delay-critical"; return { label: t("estimates.delay_positive", "Retraso de {{minutes}} min", { minutes: delta, @@ -143,6 +136,7 @@ export const ConsolidatedCirculationCard: React.FC< } as const; } + // Early const tone = absDelta <= 2 ? "delay-ok" : "delay-early"; return { label: t("estimates.delay_negative", "Adelanto de {{minutes}} min", { @@ -200,7 +194,7 @@ export const ConsolidatedCirculationCard: React.FC< > <div className="card-row main"> <div className="line-info"> - <LineIcon line={estimate.line} region={regionConfig.id} rounded /> + <LineIcon line={estimate.line} region={regionConfig.id} mode="pill" /> </div> <div className="route-info"> <strong>{estimate.route}</strong> diff --git a/src/frontend/app/components/Stops/ConsolidatedCirculationList.css b/src/frontend/app/components/Stops/ConsolidatedCirculationList.css index 5afdeaa..044b4a3 100644 --- a/src/frontend/app/components/Stops/ConsolidatedCirculationList.css +++ b/src/frontend/app/components/Stops/ConsolidatedCirculationList.css @@ -11,229 +11,3 @@ color: var(--subtitle-color); font-size: 0.95rem; } - -.consolidated-circulation-card { - all: unset; - flex: 0 0 auto; - display: flex; - flex-direction: column; - gap: 0.5rem; - background-color: var(--message-background-color); - border-radius: 12px; - border: 1px solid var(--border-color); - padding: 0.65rem 0.85rem; - transition: all 0.2s ease; -} - -.consolidated-circulation-card.has-gps { - cursor: pointer; -} - -.consolidated-circulation-card.no-gps { - cursor: not-allowed; - opacity: 0.7; -} - -.consolidated-circulation-card.has-gps:hover { - box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08); - border-color: var(--button-background-color); - background-color: color-mix( - in oklab, - var(--button-background-color) 5%, - var(--message-background-color) - ); -} - -.consolidated-circulation-card.has-gps:active { - transform: scale(0.98); -} - -.consolidated-circulation-card:disabled { - pointer-events: none; -} - - -.consolidated-circulation-card .card-row { - display: flex; - align-items: center; - gap: 0.65rem; -} - -.consolidated-circulation-card .card-row.main { - min-height: 48px; -} - -.consolidated-circulation-card .line-info { - flex-shrink: 0; -} - -.consolidated-circulation-card .route-info { - flex: 1; - min-width: 0; -} - -.consolidated-circulation-card .route-info strong { - font-size: 1rem; - color: var(--text-color); - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - line-height: 1.25; -} - -.consolidated-circulation-card .eta-badge { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.3rem 0.45rem; - border-radius: 12px; -} - -.consolidated-circulation-card .eta-text { - display: flex; - flex-direction: column; - align-items: center; - line-height: 1; -} - -.consolidated-circulation-card .eta-value { - font-size: 1.15rem; - font-weight: 700; -} - -.consolidated-circulation-card .eta-unit { - font-size: 0.65rem; - text-transform: uppercase; - letter-spacing: 0.08em; -} - -.consolidated-circulation-card .eta-badge.time-running { - background: rgba(34, 197, 94, 0.12); - color: #1a9e56; -} - -.consolidated-circulation-card .eta-badge.time-delayed { - background: rgba(255, 106, 0, 0.12); - color: #d06100; -} - -.consolidated-circulation-card .eta-badge.time-scheduled { - background: rgba(11, 61, 145, 0.12); - color: #0b3d91; -} - -[data-theme="dark"] .consolidated-circulation-card .eta-badge.time-scheduled { - color: #8fb4ff; -} - -.consolidated-circulation-card .card-row.meta { - flex-wrap: wrap; - justify-content: flex-start; - gap: 0.4rem; -} - -.meta-chip { - font-size: 0.75rem; - padding: 0.2rem 0.55rem; - border-radius: 999px; - background: rgba(0, 0, 0, 0.03); - color: var(--subtitle-color); - border: 1px solid var(--border-color); -} - -@media (prefers-color-scheme: dark) { - .meta-chip { - background: rgba(255, 255, 255, 0.05); - } -} - -.meta-chip.delay-ok { - background: hsla(142, 71%, 45%, 0.15); - border-color: hsla(142, 71%, 45%, 0.5); - color: #1a9e56; -} - -.meta-chip.delay-warn { - background: hsla(43, 96%, 56%, 0.25); - border-color: hsla(43, 96%, 56%, 0.6); - color: hsl(43, 96%, 40%); -} - -.meta-chip.delay-critical { - background: hsla(0, 84%, 60%, 0.2); - border-color: hsla(0, 84%, 60%, 0.35); - color: hsl(0, 74%, 42%); -} - -.meta-chip.delay-early { - background: hsla(217, 91%, 60%, 0.17); - border-color: hsla(217, 91%, 60%, 0.3); - color: hsl(224, 90%, 50%); -} - -/* GPS Indicator */ -.gps-indicator { - display: flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - flex-shrink: 0; - position: relative; -} - -.gps-pulse { - position: absolute; - width: 8px; - height: 8px; - background: #22c55e; - border-radius: 50%; - box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); - animation: gpsPulse 2s ease-in-out infinite; -} - -.gps-pulse.previous-trip { - background: #ff9800; - box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); - animation: gpsPulseOrange 2s ease-in-out infinite; -} - -@keyframes gpsPulse { - 0% { - box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); - } - 50% { - box-shadow: 0 0 0 6px rgba(34, 197, 94, 0.1); - } - 100% { - box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); - } -} - -@keyframes gpsPulseOrange { - 0% { - box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); - } - 50% { - box-shadow: 0 0 0 6px rgba(255, 152, 0, 0.1); - } - 100% { - box-shadow: 0 0 0 2px rgba(255, 152, 0, 0.2); - } -} - -@media (max-width: 480px) { - .consolidated-circulation-card { - padding: 0.65rem 0.75rem; - } - - .consolidated-circulation-card .card-row { - gap: 0.5rem; - } - - .consolidated-circulation-card .eta-badge { - padding: 0.25rem 0.4rem; - } -} |
