Files
karate_halloween/components/screens/StyleScreen.tsx
T

114 lines
4.4 KiB
TypeScript
Raw Normal View History

"use client";
import React, { useState } from "react";
import { Check, ArrowLeft, Wand2 } from "lucide-react";
import { BoothConfig, BoothStyle } from "@/types/booth";
import { useI18n } from "@/lib/i18n";
import { MascotGuide } from "@/components/MascotGuide";
interface StyleScreenProps {
config: BoothConfig;
styles: BoothStyle[];
onStyleSelected: (style: BoothStyle) => void;
onBack: () => void;
}
export const StyleScreen: React.FC<StyleScreenProps> = ({
config,
styles,
onStyleSelected,
onBack,
}) => {
const { t } = useI18n();
const [selectedId, setSelectedId] = useState<string>(styles[0]?.id || "");
const handleConfirm = () => {
const chosen = styles.find((s) => s.id === selectedId) || styles[0];
if (chosen) {
onStyleSelected(chosen);
}
};
const currentStyle = styles.find((s) => s.id === selectedId);
return (
<div className="relative flex-1 flex flex-col justify-between p-3 sm:p-4 overflow-hidden select-none">
{/* Top Header - Back on left, Confirm on right */}
<div className="w-full flex items-center justify-between px-1 mb-1 z-30 min-h-[40px]">
<button
onClick={onBack}
className="p-2 px-3 game-btn-dark flex items-center space-x-1 font-bold text-xs shrink-0 cursor-pointer shadow-md"
title="Back"
>
<ArrowLeft size={16} className="stroke-[2.5]" />
<span>{t(config.labels.backButton)}</span>
</button>
{/* Top-Right Confirm / Transform Button - Clean text, no icon */}
<button
onClick={handleConfirm}
className="py-2 px-3.5 game-btn-gold font-extrabold text-xs tracking-wider flex items-center justify-center uppercase font-cinzel shadow-lg active:scale-95 cursor-pointer"
>
<span>{t(config.labels.confirmStyleButton)}</span>
</button>
</div>
{/* Main Styles Grid (2x2) with Game Stone/Wood Frame Card Styling - Moved down with spacing */}
<div className="w-full max-w-sm mx-auto grid grid-cols-2 gap-3 z-20 mt-3 mb-auto py-1">
{styles.map((style) => {
const isSelected = selectedId === style.id;
const styleName = t(style.name);
return (
<div
key={style.id}
onClick={() => setSelectedId(style.id)}
className={`relative flex flex-col items-center p-2.5 rounded-2xl cursor-pointer transition-all duration-200 ${
isSelected
? "game-panel-amber ring-2 ring-amber-400 scale-[1.03] shadow-[0_8px_25px_rgba(249,115,22,0.6)]"
: "game-panel opacity-85 hover:opacity-100 hover:border-purple-400/80"
}`}
>
{isSelected && (
<div className="absolute -top-2.5 -right-2.5 w-7 h-7 rounded-full bg-gradient-to-r from-amber-400 to-orange-500 border-2 border-black flex items-center justify-center text-black z-30 shadow-[0_2px_8px_rgba(0,0,0,0.8)]">
<Check size={16} className="stroke-[3.5]" />
</div>
)}
{/* Artwork Thumbnail */}
<div className="relative w-full aspect-square rounded-xl overflow-hidden bg-black/80 border-2 border-[#3d1e6d] shadow-inner">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={style.thumbnail}
alt={styleName}
className="w-full h-full object-cover select-none"
loading="lazy"
/>
</div>
{/* Title & Tag */}
<div className="mt-2 text-center w-full px-1">
<span className="block text-xs font-bold text-amber-100 truncate drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]">
{styleName}
</span>
</div>
</div>
);
})}
</div>
{/* Selected Style Description Card & Mascot Comic Guide - Lifted up to slightly overlay bottom of style cards */}
<div className="w-full max-w-sm mx-auto z-30 flex items-center justify-start gap-1 px-1 -mt-5 sm:-mt-6 pb-2 pointer-events-none">
<MascotGuide
pose="punch"
size="md"
speechPosition="right"
speechText={{
en: "Choose your legendary martial transformation!",
zh: "挑选你专属的万圣节武道变身奥义!",
}}
/>
</div>
</div>
);
};