feat: redesign passenger cards with vintage train station aesthetic

Redesign passenger information cards to match classic Grand Central
Terminal style with compact, elegant vintage design.

- Vintage color scheme: sepia, gold accents, dark backgrounds
- Courier New monospace font for mechanical board feel
- Compact layout with FROM/TO route information
- Shows origin station (was missing before)
- Status badges: WAIT, BOARD, DLVRD
- Color-coded by state (waiting/aboard/urgent/delivered)
- Art Deco gold borders and styling
- Much smaller footprint while showing more info

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-10-01 08:52:25 -05:00
parent 8ad3144d2d
commit 651bc21583

View File

@@ -4,110 +4,206 @@ import type { Passenger, Station } from '../lib/gameTypes'
interface PassengerCardProps {
passenger: Passenger
originStation: Station | undefined
destinationStation: Station | undefined
}
export function PassengerCard({ passenger, destinationStation }: PassengerCardProps) {
if (!destinationStation) return null
export function PassengerCard({ passenger, originStation, destinationStation }: PassengerCardProps) {
if (!destinationStation || !originStation) return null
// Vintage train station colors
const bgColor = passenger.isDelivered
? '#1a3a1a' // Dark green for delivered
: !passenger.isBoarded
? '#2a2419' // Dark brown/sepia for waiting
: passenger.isUrgent
? '#3a2419' // Dark red-brown for urgent
: '#1a2a3a' // Dark blue for aboard
const accentColor = passenger.isDelivered
? '#4ade80' // Green
: !passenger.isBoarded
? '#d4af37' // Gold for waiting
: passenger.isUrgent
? '#ff6b35' // Orange-red for urgent
: '#60a5fa' // Blue for aboard
const borderColor = passenger.isUrgent && passenger.isBoarded && !passenger.isDelivered
? '#ff6b35'
: '#d4af37'
return (
<div
style={{
background: passenger.isDelivered
? 'linear-gradient(135deg, #10b981 0%, #059669 100%)'
: !passenger.isBoarded
? 'linear-gradient(135deg, #9ca3af 0%, #6b7280 100%)' // Gray for waiting
: passenger.isUrgent
? 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)'
: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)',
color: 'white',
padding: '12px 16px',
borderRadius: '12px',
background: bgColor,
border: `2px solid ${borderColor}`,
borderRadius: '4px',
padding: '8px 10px',
minWidth: '220px',
maxWidth: '280px',
boxShadow: passenger.isUrgent && !passenger.isDelivered && passenger.isBoarded
? '0 0 20px rgba(245, 158, 11, 0.6)'
: '0 2px 8px rgba(0, 0, 0, 0.2)',
minWidth: '180px',
? '0 0 16px rgba(255, 107, 53, 0.5)'
: '0 4px 12px rgba(0, 0, 0, 0.4)',
position: 'relative',
opacity: passenger.isDelivered ? 0.6 : !passenger.isBoarded ? 0.8 : 1,
animation: passenger.isUrgent && !passenger.isDelivered && passenger.isBoarded ? 'urgentPulse 1.5s ease-in-out infinite' : 'none',
fontFamily: '"Courier New", Courier, monospace',
animation: passenger.isUrgent && !passenger.isDelivered && passenger.isBoarded
? 'urgentFlicker 1.5s ease-in-out infinite'
: 'none',
transition: 'all 0.3s ease'
}}
>
{/* Passenger icon and name */}
{/* Top row: Passenger info and status */}
<div style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
marginBottom: '8px'
alignItems: 'flex-start',
justifyContent: 'space-between',
marginBottom: '6px',
borderBottom: `1px solid ${accentColor}33`,
paddingBottom: '4px',
paddingRight: '42px' // Make room for points badge
}}>
<div style={{ fontSize: '32px' }}>
{passenger.isDelivered ? '✅' : passenger.avatar}
</div>
<div style={{ flex: 1 }}>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '6px',
flex: 1
}}>
<div style={{ fontSize: '20px', lineHeight: '1' }}>
{passenger.isDelivered ? '✅' : passenger.avatar}
</div>
<div style={{
fontSize: '11px',
fontWeight: 'bold',
fontSize: '16px'
color: accentColor,
letterSpacing: '0.5px',
textTransform: 'uppercase'
}}>
{passenger.name}
</div>
{/* Status badge */}
{!passenger.isDelivered && (
<div style={{
fontSize: '10px',
marginTop: '2px',
opacity: 0.9,
fontWeight: '600'
}}>
{passenger.isBoarded ? '🚂 ABOARD' : '⏳ WAITING'}
</div>
)}
</div>
{passenger.isUrgent && !passenger.isDelivered && passenger.isBoarded && (
<div style={{
fontSize: '16px',
animation: 'urgentBlink 0.8s ease-in-out infinite'
}}>
</div>
)}
{/* Status indicator */}
<div style={{
fontSize: '9px',
color: accentColor,
fontWeight: 'bold',
letterSpacing: '0.5px',
background: `${accentColor}22`,
padding: '2px 6px',
borderRadius: '2px',
border: `1px solid ${accentColor}66`,
whiteSpace: 'nowrap',
marginTop: '0'
}}>
{passenger.isDelivered ? 'DLVRD' : passenger.isBoarded ? 'BOARD' : 'WAIT'}
</div>
</div>
{/* Destination */}
{/* Route information */}
<div style={{
display: 'flex',
alignItems: 'center',
gap: '6px',
fontSize: '14px',
opacity: 0.95
flexDirection: 'column',
gap: '3px',
fontSize: '10px',
color: '#e8d4a0'
}}>
<span></span>
<span>{destinationStation.icon}</span>
<span style={{ fontWeight: '600' }}>{destinationStation.name}</span>
{/* From station */}
<div style={{
display: 'flex',
alignItems: 'center',
gap: '6px'
}}>
<span style={{
color: accentColor,
fontSize: '8px',
fontWeight: 'bold',
width: '28px',
letterSpacing: '0.3px'
}}>
FROM:
</span>
<span style={{ fontSize: '14px', lineHeight: '1' }}>
{originStation.icon}
</span>
<span style={{
fontWeight: '600',
fontSize: '10px',
letterSpacing: '0.3px'
}}>
{originStation.name}
</span>
</div>
{/* To station */}
<div style={{
display: 'flex',
alignItems: 'center',
gap: '6px'
}}>
<span style={{
color: accentColor,
fontSize: '8px',
fontWeight: 'bold',
width: '28px',
letterSpacing: '0.3px'
}}>
TO:
</span>
<span style={{ fontSize: '14px', lineHeight: '1' }}>
{destinationStation.icon}
</span>
<span style={{
fontWeight: '600',
fontSize: '10px',
letterSpacing: '0.3px'
}}>
{destinationStation.name}
</span>
</div>
</div>
{/* Points indicator */}
{/* Points badge */}
{!passenger.isDelivered && (
<div style={{
position: 'absolute',
top: '8px',
right: '8px',
background: 'rgba(255, 255, 255, 0.3)',
borderRadius: '8px',
padding: '2px 8px',
fontSize: '12px',
fontWeight: 'bold'
top: '6px',
right: '6px',
background: `${accentColor}33`,
border: `1px solid ${accentColor}`,
borderRadius: '2px',
padding: '2px 6px',
fontSize: '10px',
fontWeight: 'bold',
color: accentColor,
letterSpacing: '0.5px'
}}>
{passenger.isUrgent ? '+20' : '+10'}
</div>
)}
{/* Urgent indicator */}
{passenger.isUrgent && !passenger.isDelivered && passenger.isBoarded && (
<div style={{
position: 'absolute',
left: '8px',
bottom: '6px',
fontSize: '10px',
animation: 'urgentBlink 0.8s ease-in-out infinite',
filter: 'drop-shadow(0 0 4px rgba(255, 107, 53, 0.8))'
}}>
</div>
)}
<style>{`
@keyframes urgentPulse {
@keyframes urgentFlicker {
0%, 100% {
box-shadow: 0 0 20px rgba(245, 158, 11, 0.6);
box-shadow: 0 0 16px rgba(255, 107, 53, 0.5);
border-color: #ff6b35;
}
50% {
box-shadow: 0 0 30px rgba(245, 158, 11, 0.9);
box-shadow: 0 0 24px rgba(255, 107, 53, 0.8);
border-color: #ffaa35;
}
}
@@ -122,4 +218,4 @@ export function PassengerCard({ passenger, destinationStation }: PassengerCardPr
`}</style>
</div>
)
}
}