diff --git a/components/TransportWidget.tsx b/components/TransportWidget.tsx index 1afa232..af39e15 100644 --- a/components/TransportWidget.tsx +++ b/components/TransportWidget.tsx @@ -1,7 +1,7 @@ 'use client' import { useEffect, useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' -import { ArrowRight, ArrowLeft, Accessibility, Train } from 'lucide-react' +import { ArrowRight, Train } from 'lucide-react' interface Arrival { route: string @@ -12,171 +12,88 @@ interface Arrival { interface Direction { stopId: string - title: string - subtitle: string - icon: 'right' | 'left' - accent: string - glow: string + short: string + sub: string } const DIRECTIONS: Direction[] = [ - { - stopId: '16226', - title: 'В центр', - subtitle: 'к м. Новочеркасская', - icon: 'right', - accent: 'linear-gradient(135deg, rgba(16,185,129,0.14), rgba(6,182,212,0.06))', - glow: 'rgba(16,185,129,0.35)', - }, - { - stopId: '16354', - title: 'Из центра', - subtitle: 'к пр. Большевиков', - icon: 'left', - accent: 'linear-gradient(135deg, rgba(236,72,153,0.14), rgba(245,158,11,0.06))', - glow: 'rgba(236,72,153,0.35)', - }, + { stopId: '16226', short: 'Лента', sub: 'в центр' }, + { stopId: '16354', short: 'Дыбенко', sub: 'от центра' }, ] -const ALLOWED_ROUTES = new Set(['23', '27', '39']) +const ROUTES: { num: string; color: string; bg: string }[] = [ + { num: '23', color: '#60a5fa', bg: 'linear-gradient(135deg, #3b82f6, #2563eb)' }, + { num: '27', color: '#fbbf24', bg: 'linear-gradient(135deg, #f59e0b, #d97706)' }, + { num: '39', color: '#c084fc', bg: 'linear-gradient(135deg, #a855f7, #7c3aed)' }, +] -const ROUTE_STYLE: Record = { - '23': { color: '#60a5fa', bg: 'linear-gradient(135deg, #3b82f6, #2563eb)' }, - '27': { color: '#fbbf24', bg: 'linear-gradient(135deg, #f59e0b, #d97706)' }, - '39': { color: '#c084fc', bg: 'linear-gradient(135deg, #a855f7, #7c3aed)' }, +function formatMinutes(m: number): string { + if (m <= 0) return 'сейчас' + return `${m} мин` } -function formatMinutes(m: number): { big: string; unit: string } { - if (m <= 0) return { big: 'сейчас', unit: '' } - if (m === 1) return { big: '1', unit: 'мин' } - return { big: String(m), unit: 'мин' } -} - -function DirectionCard({ dir, arrivals, loading }: { dir: Direction; arrivals: Arrival[]; loading: boolean }) { +function Cell({ arrivals, color }: { arrivals: Arrival[]; color: string }) { const sorted = [...arrivals].sort((a, b) => a.minutes - b.minutes).slice(0, 3) - const ArrowIcon = dir.icon === 'right' ? ArrowRight : ArrowLeft - + if (sorted.length === 0) { + return ( +
+ ) + } + const [first, ...rest] = sorted + const imminent = first.minutes <= 2 return (
- {/* Glow */} -
- - {/* Header */} -
+ {/* Primary time */} +
- + {first.minutes <= 0 ? 'сейчас' : first.minutes}
-
-
- {dir.title} -
-
- {dir.subtitle} -
-
-
- - {/* Arrivals */} -
- {loading && arrivals.length === 0 ? ( -
- Загрузка... -
- ) : sorted.length === 0 ? ( -
- -
Пока нет данных
-
- ) : ( - - {sorted.map((arr, idx) => { - const style = ROUTE_STYLE[arr.route] || { color: '#9ca3af', bg: 'linear-gradient(135deg, #6b7280, #4b5563)' } - const time = formatMinutes(arr.minutes) - const isImminent = arr.minutes <= 2 - return ( - - {/* Route badge */} -
- {arr.route} -
- - {/* Label */} -
-
- Трамвай -
-
- №{arr.park} -
-
- - {/* Time */} -
-
- {time.big} -
- {time.unit && ( -
- {time.unit} -
- )} -
- - {/* Wheelchair */} - {arr.wheelchair && ( - - )} -
- ) - })} -
+ {first.minutes > 0 && ( +
мин
)}
+ + {/* Divider */} + {rest.length > 0 && ( +
+ )} + + {/* Next arrivals */} + {rest.length > 0 && ( +
+
+ затем +
+
+ {rest.map(r => formatMinutes(r.minutes)).join(' · ')} +
+
+ )}
) } @@ -199,9 +116,7 @@ export default function TransportWidget() { ) if (cancelled) return const map: Record = {} - for (const r of results) { - map[r.stopId] = r.arrivals.filter(a => ALLOWED_ROUTES.has(a.route)) - } + for (const r of results) map[r.stopId] = r.arrivals setData(map) } finally { if (!cancelled) setLoading(false) @@ -213,15 +128,112 @@ export default function TransportWidget() { }, []) return ( -
- {DIRECTIONS.map(d => ( - - ))} +
+ {/* Glow */} +
+ + {/* Header */} +
+
+ +
+
+
+ Трамвай +
+
+ Ул. Антонова-Овсеенко +
+
+
+ + {/* Column headers */} +
+
+ {DIRECTIONS.map(d => ( +
+ +
+
+ {d.short} +
+
+ {d.sub} +
+
+
+ ))} +
+ + {/* Rows: one per route */} +
+ {ROUTES.map(route => ( +
+ {/* Route badge */} +
+ {route.num} +
+ + {DIRECTIONS.map(d => { + const arrivals = (data[d.stopId] || []).filter(a => a.route === route.num) + return ( + + a.minutes).join(',')}`} + initial={{ opacity: 0, y: 4 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.2 }} + > + + + + ) + })} +
+ ))} +
+ + {loading && Object.keys(data).length === 0 && ( +
+ Загрузка расписания... +
+ )}
) }