fix(planner): wrap-safe mobile itinerary text — platform below the stop, minutes-first walks

This commit is contained in:
Maurice
2026-07-03 10:55:57 +02:00
committed by Maurice
parent 132ddcad16
commit 452360683c
3 changed files with 20 additions and 7 deletions
@@ -241,7 +241,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
{(transit.legs as TransitLegMeta[]).map((leg, i) => {
if (leg.mode === 'WALK') return <TransitWalkDivider key={i} leg={leg} t={t} />
if (leg.mode === 'WALK') return <TransitWalkDivider key={i} leg={leg} t={t} size={isMobile ? 'sm' : 'md'} />
const mins = leg.duration ? Math.round(leg.duration / 60) : null
if (isMobile) {
// The wide from → to line plus the chip row doesn't fit a
@@ -253,10 +253,18 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
leg.stops ? t('transit.stops', { count: leg.stops }) : null,
leg.agency || null,
].filter(Boolean).join(' · ')
// Names wrap instead of clipping; the platform gets its
// own quiet line below so it never pushes the name out.
const stopName = (stop: TransitLegMeta['from']) => (
<div className="text-content" style={{ fontSize: 'calc(12.5px * var(--fs-scale-body, 1))', fontWeight: 600, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{stop?.name}
{stop?.track && <span className="text-content-faint" style={{ fontWeight: 500 }}> · {t('transit.platform', { track: stop.track })}</span>}
<div style={{ minWidth: 0 }}>
<div className="text-content" style={{ fontSize: 'calc(12px * var(--fs-scale-body, 1))', fontWeight: 600, lineHeight: 1.35, overflowWrap: 'anywhere' }}>
{stop?.name}
</div>
{stop?.track && (
<div className="text-content-faint" style={{ fontSize: 'calc(10.5px * var(--fs-scale-caption, 1))', fontWeight: 500, marginTop: 1 }}>
{t('transit.platform', { track: stop.track })}
</div>
)}
</div>
)
const timeCell = (time?: string | null) => (
@@ -478,7 +478,7 @@ export default function TransitSearchPanel({ day, days, places, accommodations =
const tzTo = to ? tzAt(to.lat, to.lng) : tzFrom
const segBtn = (active: boolean): React.CSSProperties => ({
padding: '6px 11px', fontSize: 'calc(12px * var(--fs-scale-body, 1))', borderRadius: 7, fontWeight: 500,
padding: isMobile ? '6px 5px' : '6px 11px', fontSize: isMobile ? 'calc(11px * var(--fs-scale-body, 1))' : 'calc(12px * var(--fs-scale-body, 1))', borderRadius: 7, fontWeight: 500,
border: 0, cursor: 'pointer', fontFamily: 'inherit', whiteSpace: 'nowrap',
background: active ? 'var(--bg-card)' : 'transparent', color: active ? 'var(--text-primary)' : 'var(--text-muted)',
boxShadow: active ? '0 1px 4px rgba(0,0,0,0.08)' : 'none',
@@ -32,18 +32,23 @@ export function TransitWalkDivider({ leg, t, size = 'md' }: {
size?: 'sm' | 'md'
}) {
const mins = leg.duration ? Math.round(leg.duration / 60) : null
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768
// Hairlines that fade towards the outer edges — strongest next to the text.
const rule = (dir: 'left' | 'right'): React.CSSProperties => ({
flex: 1, height: 1, minWidth: 12, borderRadius: 1,
background: `linear-gradient(to ${dir}, var(--text-faint), transparent)`,
opacity: 0.55,
})
// On phones the minutes lead so a long stop name only ever clips the name.
const text = isMobile
? `${mins ? `${t('transit.min', { count: mins })} · ` : ''}${t('transit.walkTo', { name: leg.to?.name || '' })}`
: `${t('transit.walkTo', { name: leg.to?.name || '' })}${mins ? ` · ${t('transit.min', { count: mins })}` : ''}`
return (
<div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: size === 'sm' ? '1px 0' : '2px 0' }}>
<span style={rule('left')} />
<span className="text-content-faint" style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: size === 'sm' ? 'calc(10px * var(--fs-scale-caption, 1))' : 'calc(11.5px * var(--fs-scale-caption, 1))', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '75%' }}>
<span className="text-content-faint" style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: size === 'sm' ? 'calc(10px * var(--fs-scale-caption, 1))' : 'calc(11.5px * var(--fs-scale-caption, 1))', fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: isMobile ? '85%' : '75%' }}>
<Footprints size={size === 'sm' ? 11 : 12} style={{ flexShrink: 0 }} />
{t('transit.walkTo', { name: leg.to?.name || '' })}{mins ? ` · ${t('transit.min', { count: mins })}` : ''}
{text}
</span>
<span style={rule('right')} />
</div>