Files
web-tools/src/components/rt-guide/mtr-board-form.tsx
Snowykami 330cd84beb
Some checks failed
Build and Push Container Image, Deploy to Host / build-and-push-and-deploy (push) Has been cancelled
feat: add MTR display board and train info components
- Implemented MtrDisplayBoard component to show train schedules with weather information.
- Created MtrTrainInfo component to manage state and render MtrDisplayBoard.
- Added ScreenshotTaker component for downloading screenshots of the display board.
- Introduced theme toggle functionality with ThemeToggle component.
- Developed various UI components including Button, Card, ColorPicker, DropdownMenu, Input, Label, Popover, Select, Separator, Switch, Tabs, and Textarea.
- Added utility functions for class name merging and tool definitions.
2025-08-14 01:31:45 +08:00

287 lines
11 KiB
TypeScript

"use client";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ColorPicker } from "@/components/ui/color-picker";
import { Separator } from "@/components/ui/separator";
import { Switch } from "@/components/ui/switch";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { BoardData, TrainType } from "@/app/rt-guide/types";
interface MtrBoardFormProps {
data: BoardData;
setData: (data: BoardData) => void;
}
export function MtrBoardForm({ data, setData }: MtrBoardFormProps) {
const handleStatusBarChange = (field: string, value: string) => {
setData({ ...data, statusBar: { ...data.statusBar, [field]: value } });
};
const handleTrainChange = (index: number, field: string, value: any) => {
const newTrains = [...data.trains];
const trainToUpdate = { ...newTrains[index] };
if (field === "destination.en" || field === "destination.cn") {
const [, subkey] = field.split(".");
(trainToUpdate.destination as any)[subkey] = value;
} else {
(trainToUpdate as any)[field] = value;
}
newTrains[index] = trainToUpdate;
setData({ ...data, trains: newTrains });
};
const handleThemeChange = (field: string, value: any) => {
setData({ ...data, theme: { ...data.theme, [field]: value } });
};
const handleLangChange = (checked: boolean) => {
setData({ ...data, lang: checked ? "cn" : "en" });
};
return (
<Card className="w-full max-w-2xl">
<CardHeader>
<CardTitle>Board Configuration</CardTitle>
</CardHeader>
<CardContent>
<Tabs defaultValue="statusbar">
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="statusbar">Status Bar</TabsTrigger>
<TabsTrigger value="trains">Train Info</TabsTrigger>
<TabsTrigger value="theme">Theme</TabsTrigger>
</TabsList>
{/* Status Bar Tab */}
<TabsContent value="statusbar" className="mt-4">
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="weather">Weather</Label>
<Select
value={data.statusBar.weather}
onValueChange={(value) =>
handleStatusBarChange("weather", value)
}
>
<SelectTrigger id="weather">
<SelectValue placeholder="Select weather" />
</SelectTrigger>
<SelectContent>
<SelectItem value="sunny">Sunny</SelectItem>
<SelectItem value="cloudy">Cloudy</SelectItem>
<SelectItem value="rainy">Rainy</SelectItem>
<SelectItem value="stormy">Stormy</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="temperature">Temperature (°C)</Label>
<Input
id="temperature"
type="number"
value={data.statusBar.temperature}
onChange={(e) =>
handleStatusBarChange("temperature", e.target.value)
}
/>
</div>
</div>
<div>
<Label htmlFor="time">Time</Label>
<Input
id="time"
type="text"
value={data.statusBar.time}
onChange={(e) => handleStatusBarChange("time", e.target.value)}
/>
</div>
</div>
</TabsContent>
{/* Trains Tab */}
<TabsContent value="trains" className="mt-4">
<div className="space-y-6">
{data.trains.map((train, index) => (
<div key={index}>
<Label className="text-lg font-semibold">
Train {index + 1}
</Label>
<div className="grid grid-cols-2 gap-4 mt-2">
<div>
<Label htmlFor={`dest-en-${index}`}>
Destination (EN)
</Label>
<Input
id={`dest-en-${index}`}
value={train.destination.en}
onChange={(e) =>
handleTrainChange(
index,
"destination.en",
e.target.value
)
}
/>
</div>
<div>
<Label htmlFor={`dest-cn-${index}`}>
Destination (CN)
</Label>
<Input
id={`dest-cn-${index}`}
value={train.destination.cn}
onChange={(e) =>
handleTrainChange(
index,
"destination.cn",
e.target.value
)
}
/>
</div>
<div>
<Label htmlFor={`platform-${index}`}>Platform</Label>
<Input
id={`platform-${index}`}
value={train.platform}
onChange={(e) =>
handleTrainChange(index, "platform", e.target.value)
}
/>
</div>
<div>
<Label htmlFor={`arrival-${index}`}>Arrival</Label>
<Input
id={`arrival-${index}`}
value={train.arrival}
onChange={(e) =>
handleTrainChange(index, "arrival", e.target.value)
}
/>
</div>
<div>
<Label htmlFor={`type-${index}`}>Type</Label>
<Select
value={train.type}
onValueChange={(value: TrainType) =>
handleTrainChange(index, "type", value)
}
>
<SelectTrigger id={`type-${index}`}>
<SelectValue placeholder="Select type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="normal">Normal</SelectItem>
<SelectItem value="rapid">Rapid</SelectItem>
<SelectItem value="express">Express</SelectItem>
<SelectItem value="through">Through</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{index < data.trains.length - 1 && (
<Separator className="mt-6" />
)}
</div>
))}
</div>
</TabsContent>
{/* Theme Tab */}
<TabsContent value="theme" className="mt-4">
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<ColorPicker
label="状态栏颜色"
value={data.theme.statusBarColor}
onChange={(value) => handleThemeChange("statusBarColor", value)}
/>
<ColorPicker
label="状态栏文本颜色"
value={data.theme.statusBarTextColor}
onChange={(value) => handleThemeChange("statusBarTextColor", value)}
/>
<ColorPicker
label="奇数行颜色"
value={data.theme.oddRowColor}
onChange={(value) => handleThemeChange("oddRowColor", value)}
/>
<ColorPicker
label="偶数行颜色"
value={data.theme.evenRowColor}
onChange={(value) => handleThemeChange("evenRowColor", value)}
/>
<ColorPicker
label="行文本颜色"
value={data.theme.textColor}
onChange={(value) => handleThemeChange("textColor", value)}
/>
<ColorPicker
label="月台背景颜色"
value={data.theme.platformBackgroundColor}
onChange={(value) => handleThemeChange("platformBackgroundColor", value)}
/>
<ColorPicker
label="月台文本颜色"
value={data.theme.platformTextColor}
onChange={(value) => handleThemeChange("platformTextColor", value)}
/>
</div>
<Separator className="my-4" />
<Label className="text-lg font-semibold">Train Type Colors</Label>
<div className="grid grid-cols-2 gap-4">
{(Object.keys(data.theme.trainTypeColors) as TrainType[]).map(
(type) => (
<ColorPicker
key={type}
label={type === "local" ? "普通" :
type === "express" ? "特快" :
type === "rapid" ? "快速" :
type === "through" ? "直通" : type}
value={data.theme.trainTypeColors[type]}
onChange={(value) => {
const newColors = {
...data.theme.trainTypeColors,
[type]: value,
};
handleThemeChange("trainTypeColors", newColors);
}}
/>
)
)}
</div>
<Separator className="my-4" />
<div className="flex items-center space-x-2 mt-4">
<Switch
id="language-switch"
checked={data.lang === "cn"}
onCheckedChange={handleLangChange}
/>
<Label htmlFor="language-switch">
Display Chinese ()
</Label>
</div>
</div>
</TabsContent>
</Tabs>
</CardContent>
</Card>
);
}