Files
Firefly_Srtools/src/components/card/relicCard.tsx
T
Kain344 2a36904b43
Gitea Auto Deploy / Deploy-Container (push) Failing after 13m19s
Refactor TypeScript interfaces and types for improved readability and consistency
- Reformatted interfaces in changelog.ts, enka.ts, extraData.ts, global.d.ts, index.ts, lightconeDetail.ts, metaData.ts, mics.ts, mocDetail.ts, modelConfig.ts, monsterDetail.ts, peakDetail.ts, pfDetail.ts, psConnect.ts, relicDetail.ts, showcase.ts, srtools.ts, and zod/index.ts for consistent indentation and spacing.
- Added missing imports and interfaces where necessary, such as Invasion in mocDetail.ts and peakDetail.ts.
- Ensured all interfaces are properly structured and maintain a consistent style across the codebase.
2026-08-27 00:38:15 +07:00

135 lines
5.9 KiB
TypeScript

"use client";
import useRelicMakerStore from "@/stores/relicMakerStore";
import useUserDataStore from "@/stores/userDataStore";
import { useShallow } from "zustand/react/shallow";
import Image from "next/image";
import { useMemo } from "react";
interface RelicCardProps {
slot: string
avatarId: string
}
const getRarityColor = (rarity: string) => {
switch (rarity) {
case '6':
return 'border-amber-400/90 shadow-[0_0_16px_rgba(251,191,36,0.4)] bg-linear-to-br from-amber-600 via-amber-400 to-amber-500';
case '5':
return 'border-purple-400/90 shadow-[0_0_16px_rgba(192,132,252,0.4)] bg-linear-to-br from-purple-700 via-purple-400 to-purple-500';
case '4':
return 'border-sky-400/90 shadow-[0_0_16px_rgba(56,189,248,0.4)] bg-linear-to-br from-blue-700 via-blue-400 to-sky-500';
case '3':
return 'border-emerald-400/90 shadow-[0_0_16px_rgba(52,211,153,0.4)] bg-linear-to-br from-emerald-700 via-emerald-400 to-emerald-500';
default:
return 'border-base-content/20 bg-base-300';
}
};
const getSlotIconAndName = (slot: string) => {
const slotMap: Record<string, { icon: string; name: string }> = {
'1': { icon: '/relics/HEAD.png', name: 'Head' },
'2': { icon: '/relics/HAND.png', name: 'Hands' },
'3': { icon: '/relics/BODY.png', name: 'Body' },
'4': { icon: '/relics/FOOT.png', name: 'Feet' },
'5': { icon: '/relics/NECK.png', name: 'Planar Sphere' },
'6': { icon: '/relics/OBJECT.png', name: 'Link Rope' },
};
const current = slotMap[slot];
if (!current) return null;
return (
<div className="flex items-center gap-1.5 justify-center mt-2.5">
<Image
unoptimized
crossOrigin="anonymous"
src={current.icon}
alt={current.name}
width={18}
height={18}
className="w-4 h-4 object-contain theme-stat-icon opacity-85"
/>
<span className="text-xs font-bold text-base-content">{current.name}</span>
</div>
);
};
export default function RelicCard({ slot, avatarId }: RelicCardProps) {
const { avatars } = useUserDataStore(
useShallow((state) => ({ avatars: state.avatars }))
)
const { selectedRelicSlot } = useRelicMakerStore(
useShallow((state) => ({ selectedRelicSlot: state.selectedRelicSlot }))
)
const relicDetail = useMemo(() => {
const avatar = avatars[avatarId];
if (avatar) {
const profile = avatar.profileList?.[avatar.profileSelect] ?? avatar.profileList?.[0];
return profile?.relics?.[slot] || null;
}
return null;
}, [avatars, avatarId, slot]);
const isSelected = selectedRelicSlot === slot;
return (
<div className="flex flex-col items-center select-none group cursor-pointer">
{relicDetail ? (
<div className="flex flex-col items-center">
<div
className={`
relative w-22 h-22 sm:w-24 sm:h-24 rounded-full border-3
${getRarityColor(relicDetail.relic_id.toString()[0])}
flex items-center justify-center
transition-all duration-200
${isSelected ? 'ring-2 ring-primary/70 shadow-md ring-offset-2 ring-offset-base-100' : 'hover:border-primary/60'}
`}
>
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/spriteoutput/relicfigures/IconRelic_${relicDetail.relic_set_id}_${slot}.png`}
alt="Relic"
width={124}
height={124}
className="w-14 h-14 sm:w-16 sm:h-16 object-contain drop-shadow-md"
/>
{/* Level Badge */}
<div className="absolute -bottom-2 bg-base-100 border border-base-content/15 shadow-md rounded-full px-2 py-0.5">
<span className="text-xs font-mono font-bold text-primary">+{relicDetail.level}</span>
</div>
</div>
{getSlotIconAndName(slot)}
</div>
) : (
<div className="flex flex-col items-center">
<div
className={`
relative w-22 h-22 sm:w-24 sm:h-24 rounded-full border-2 border-dashed border-base-content/20
bg-base-200/60 flex items-center justify-center
transition-all duration-200 group-hover:border-primary/60
${isSelected ? 'ring-2 ring-primary/70 border-solid bg-primary/10 ring-offset-2 ring-offset-base-100' : ''}
`}
>
<div className="flex flex-col items-center justify-center gap-1 text-base-content/40 group-hover:text-primary transition-colors">
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</div>
{/* Level Badge */}
<div className="absolute -bottom-2 bg-base-100 border border-base-content/15 shadow-md rounded-full px-2 py-0.5">
<span className="text-xs font-mono font-bold text-base-content/40">+0</span>
</div>
</div>
{getSlotIconAndName(slot)}
</div>
)}
</div>
)
}