99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import React, { ComponentProps, FC } from "react";
|
|
import { Image, TouchableOpacity, View } from "react-native";
|
|
import { Ionicons } from "@expo/vector-icons";
|
|
import type { TrainIconEntry } from "@/lib/trainIconEntries";
|
|
|
|
type StackVariant = "header" | "list";
|
|
type StatusIcon = ComponentProps<typeof Ionicons>;
|
|
|
|
type Props = {
|
|
entries: TrainIconEntry[];
|
|
direction?: boolean;
|
|
hidden?: boolean;
|
|
onPressEntry?: (entry: TrainIconEntry, index: number) => void;
|
|
statusIcon?: StatusIcon;
|
|
variant?: StackVariant;
|
|
};
|
|
|
|
const iconSize = {
|
|
header: {
|
|
width: 24,
|
|
height: 30,
|
|
stackedWidth: 12,
|
|
stackedHeight: 15,
|
|
marginRight: 5,
|
|
stackedMarginLeft: -10,
|
|
stackedMarginTop: 10,
|
|
statusSize: 24,
|
|
},
|
|
list: {
|
|
width: 20,
|
|
height: 22,
|
|
stackedWidth: 10,
|
|
stackedHeight: 12,
|
|
marginRight: 2,
|
|
stackedMarginLeft: -8,
|
|
stackedMarginTop: 8,
|
|
statusSize: 18,
|
|
},
|
|
} as const;
|
|
|
|
export const TrainIconStack: FC<Props> = ({
|
|
entries,
|
|
direction,
|
|
hidden = false,
|
|
onPressEntry,
|
|
statusIcon,
|
|
variant = "header",
|
|
}) => {
|
|
const size = iconSize[variant];
|
|
|
|
return (
|
|
<View style={{ flexDirection: "row", alignItems: "flex-start" }}>
|
|
{entries.map((entry, index) => {
|
|
const trainIcon = direction
|
|
? entry.vehicle_info_img
|
|
: entry.vehicle_info_right_img || entry.vehicle_info_img;
|
|
if (!trainIcon) return null;
|
|
|
|
const content = (
|
|
<View>
|
|
<View style={{ opacity: hidden ? 0 : 1 }}>
|
|
<Image
|
|
source={{ uri: trainIcon }}
|
|
style={{
|
|
height: index > 0 ? size.stackedHeight : size.height,
|
|
width: index > 0 ? size.stackedWidth : size.width,
|
|
marginRight: size.marginRight,
|
|
marginLeft: index > 0 ? size.stackedMarginLeft : 0,
|
|
marginTop: index > 0 ? size.stackedMarginTop : 0,
|
|
}}
|
|
resizeMethod="resize"
|
|
/>
|
|
</View>
|
|
{statusIcon && hidden && (
|
|
<View style={{ position: "absolute", top: 0, left: 0 }}>
|
|
<Ionicons {...statusIcon} size={size.statusSize} />
|
|
</View>
|
|
)}
|
|
</View>
|
|
);
|
|
|
|
if (!onPressEntry) {
|
|
return <View key={`${trainIcon}-${index}`}>{content}</View>;
|
|
}
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
key={`${trainIcon}-${index}`}
|
|
onPress={() => onPressEntry(entry, index)}
|
|
disabled={!entry.vehicle_info_url}
|
|
>
|
|
{content}
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
};
|