210 lines
7.2 KiB
TypeScript
210 lines
7.2 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { Planet, Starship } from "@/types/swapi";
|
|
import { t, LocaleType } from "@/content/locales";
|
|
import { getPlanetTheme } from "@/utils/getPlanetTheme";
|
|
|
|
interface ActionPanelProps {
|
|
planet?: Planet | null;
|
|
enemy?: Starship | null;
|
|
onAction: () => void;
|
|
onEscape?: () => void;
|
|
onRepair?: () => void;
|
|
isLoading?: boolean;
|
|
isCurrentLocation?: boolean;
|
|
currentHp: number;
|
|
}
|
|
|
|
export default function ActionPanel({
|
|
planet,
|
|
enemy,
|
|
onAction,
|
|
onEscape,
|
|
onRepair,
|
|
isLoading,
|
|
isCurrentLocation,
|
|
currentHp,
|
|
}: ActionPanelProps) {
|
|
const isCombat = !!enemy;
|
|
|
|
const planetVisual = getPlanetTheme(
|
|
planet?.terrain,
|
|
planet?.climate,
|
|
t as LocaleType,
|
|
);
|
|
|
|
const uiTheme = isCombat
|
|
? {
|
|
color: "text-red-500",
|
|
border: "border-red-600",
|
|
glow: "shadow-[0_0_30px_#dc2626]",
|
|
label: t.ACTION_PANEL.MODES.HOSTILE,
|
|
borderAlpha: "border-red-900/30",
|
|
labelAlpha: "text-red-500/50",
|
|
}
|
|
: {
|
|
color: "text-yellow-500",
|
|
border: "border-yellow-300",
|
|
glow: "shadow-[0_0_20px_rgba(234,179,8,0.2)]",
|
|
label: "NEUTRAL SYSTEM",
|
|
borderAlpha: "border-yellow-500/10",
|
|
labelAlpha: "text-yellow-500/50",
|
|
};
|
|
|
|
const stats = isCombat
|
|
? [
|
|
{
|
|
label: t.ACTION_PANEL.LABELS.MANUFACTURER,
|
|
value: enemy.manufacturer,
|
|
},
|
|
{
|
|
label: t.ACTION_PANEL.LABELS.COST,
|
|
value: `${enemy.cost_in_credits} Cr`,
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
label: t.ACTION_PANEL.LABELS.POPULATION,
|
|
value: planet?.population.toLocaleString(),
|
|
},
|
|
{ label: t.ACTION_PANEL.LABELS.GRAVITY, value: planet?.gravity },
|
|
];
|
|
|
|
return (
|
|
<div
|
|
className={`w-full max-w-4xl mt-6 bg-black/90 backdrop-blur-md border-2 rounded-lg p-6 shadow-2xl relative overflow-hidden transition-all duration-500 ${uiTheme.border}`}
|
|
>
|
|
<div
|
|
className={`absolute inset-0 bg-[linear-gradient(transparent_0%,${isCombat ? "rgba(220,38,38,0.1)" : "rgba(234,179,8,0.05)"}_50%,transparent_100%)] bg-[length:100%_4px] animate-pulse pointer-events-none`}
|
|
/>
|
|
|
|
<div className="flex flex-col md:flex-row gap-8 items-center relative z-10">
|
|
{/* VISUAL UNIT */}
|
|
<div className="relative shrink-0">
|
|
<div
|
|
className={`w-32 h-32 rounded-full flex items-center justify-center bg-black overflow-hidden relative shadow-inner transition-all duration-500 ${
|
|
isCombat
|
|
? `border-4 ${uiTheme.border} ${uiTheme.glow}`
|
|
: `border-1 ${planetVisual.border} shadow-[0_0_15px_${planetVisual.hex}44]`
|
|
}`}
|
|
>
|
|
{isCombat ? (
|
|
<div className="text-red-600 animate-pulse font-black text-6xl">
|
|
!
|
|
</div>
|
|
) : (
|
|
<div
|
|
className="w-full h-full transition-all duration-1000"
|
|
style={{
|
|
background: `radial-gradient(circle at 30% 30%, ${planetVisual.hex}, #000)`,
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
<div
|
|
className={`absolute -top-2 -right-2 bg-black border px-2 py-0.5 text-[8px] uppercase tracking-widest ${uiTheme.color} ${uiTheme.border}`}
|
|
>
|
|
{isCurrentLocation && !isCombat
|
|
? "CURRENT LOCATION"
|
|
: uiTheme.label}
|
|
</div>
|
|
</div>
|
|
|
|
{/* INFO SECTION */}
|
|
<div className="flex-1 text-center md:text-left space-y-4">
|
|
<div>
|
|
<div className="flex flex-col md:flex-row items-baseline gap-3">
|
|
<h3
|
|
className={`text-3xl font-black tracking-widest uppercase ${isCombat ? "text-red-600" : "text-white"}`}
|
|
>
|
|
{isCombat ? enemy.name : planet?.name}
|
|
</h3>
|
|
{isCombat && (
|
|
<div className="flex items-center gap-2">
|
|
<span className="px-2 py-0.5 border border-red-500 text-red-500 font-mono text-xs">
|
|
DS {enemy.ds}
|
|
</span>
|
|
<div className="flex gap-1 ml-2">
|
|
{[...Array(enemy.hp)].map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className="w-4 h-2 bg-red-600 shadow-[0_0_8px_#dc2626] border border-red-400/50"
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<p
|
|
className={`${uiTheme.color} text-[10px] font-bold uppercase tracking-[0.2em] opacity-80 mt-1`}
|
|
>
|
|
{isCombat
|
|
? `${t.ACTION_PANEL.LABELS.CLASS}: ${enemy.starship_class}`
|
|
: `${t.ACTION_PANEL.LABELS.SECTOR}: ${planet?.terrain}`}
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
className={`grid grid-cols-2 gap-4 border-t border-b py-3 ${uiTheme.borderAlpha}`}
|
|
>
|
|
{stats.map((stat, idx) => (
|
|
<div key={idx} className="text-[10px] uppercase">
|
|
<span className={uiTheme.labelAlpha}>{stat.label}</span>
|
|
<p className="text-white font-mono truncate">{stat.value}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* BUTTONS */}
|
|
<div className="flex flex-col gap-3 shrink-0 w-full md:w-auto">
|
|
{isCurrentLocation && !isCombat ? (
|
|
<button
|
|
onClick={onRepair}
|
|
disabled={currentHp >= 10 || isLoading}
|
|
className={`w-full md:w-auto px-10 py-5 border-2 font-black uppercase tracking-[0.3em] transition-all
|
|
${
|
|
currentHp < 10
|
|
? "border-blue-500 text-blue-500 hover:bg-blue-500 hover:text-white shadow-[0_0_20px_rgba(59,130,246,0.3)]"
|
|
: "border-gray-600 text-gray-600 opacity-50 cursor-not-allowed"
|
|
}`}
|
|
>
|
|
{currentHp < 10
|
|
? t.ACTION_PANEL.BUTTONS.REPAIR((10 - currentHp) * 20)
|
|
: t.ACTION_PANEL.BUTTONS.HULL_INTACT}
|
|
</button>
|
|
) : (
|
|
<button
|
|
onClick={onAction}
|
|
disabled={isLoading}
|
|
className={`w-full md:w-auto px-10 py-5 border-2 font-black uppercase tracking-[0.3em] transition-all
|
|
${
|
|
isCombat
|
|
? "border-red-600 text-red-600 hover:bg-red-600 hover:text-white"
|
|
: "border-yellow-500 text-yellow-500 hover:bg-yellow-500 hover:text-black"
|
|
}
|
|
${isLoading ? "opacity-50" : ""}`}
|
|
>
|
|
{isLoading
|
|
? t.ACTION_PANEL.STATUS.ENGAGING
|
|
: isCombat
|
|
? t.ACTION_PANEL.BUTTONS.FIRE
|
|
: t.ACTION_PANEL.BUTTONS.JUMP}
|
|
</button>
|
|
)}
|
|
|
|
{isCombat && (
|
|
<button
|
|
onClick={onEscape}
|
|
className="px-10 py-2 border border-white/40 text-white/80 text-[10px] uppercase tracking-widest hover:bg-white/5 hover:text-white transition-colors"
|
|
>
|
|
{t.ACTION_PANEL.BUTTONS.ESCAPE}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|