update wave, cycle, damage type ...
This commit is contained in:
@@ -4,7 +4,7 @@ import useBattleDataStore from "@/stores/battleDataStore";
|
||||
import CharacterCard from "../card/characterCard";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState, useEffect } from "react";
|
||||
import { AvatarType } from "@/types";
|
||||
import { AvatarHakushiType } from "@/types";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import { getNameChar } from '@/helper/getNameChar';
|
||||
import SkillBarChart from "../chart/skillBarChart";
|
||||
@@ -13,19 +13,17 @@ import { motion } from "framer-motion";
|
||||
import { DamageLineForOne } from "../chart/damageLineForOne";
|
||||
import { DamagePerCycleForOne } from "../chart/damagePerCycleForOne";
|
||||
import { useCalcTotalDmgAvatar, useCalcTotalTurnAvatar } from "@/hooks/useCalcAvatarData";
|
||||
import Image from "next/image";
|
||||
// import ShowCaseInfo from "../card/showCaseCard";
|
||||
|
||||
export default function LineupBar() {
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<AvatarType | null>(null);
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<AvatarHakushiType | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const transI18n = useTranslations("DataAnalysisPage");
|
||||
const { lineup } = useBattleDataStore();
|
||||
const { lineup, turnHistory, dataAvatar } = useBattleDataStore();
|
||||
const { listAvatar } = useAvatarDataStore();
|
||||
const { locale } = useLocaleStore();
|
||||
const [modeBar, setModeBar] = useState<0 | 1 | 2>(1);
|
||||
const [modeLine, setModeLine] = useState<0 | 1>(1);
|
||||
|
||||
|
||||
const totalDamage = useCalcTotalDmgAvatar(selectedCharacter ? Number(selectedCharacter.id) : 0);
|
||||
const totalTurn = useCalcTotalTurnAvatar(selectedCharacter ? Number(selectedCharacter.id) : 0)
|
||||
|
||||
@@ -34,7 +32,7 @@ export default function LineupBar() {
|
||||
lineup.some(av => av.avatarId.toString() === item.id)
|
||||
);
|
||||
|
||||
const handleShow = (modalId: string, item: AvatarType) => {
|
||||
const handleShow = (modalId: string, item: AvatarHakushiType) => {
|
||||
const modal = document.getElementById(modalId) as HTMLDialogElement | null;
|
||||
if (modal) {
|
||||
setSelectedCharacter(item);
|
||||
@@ -76,62 +74,47 @@ export default function LineupBar() {
|
||||
{transI18n("lineupInfo")}
|
||||
</motion.h2>
|
||||
|
||||
<div className="relative h-full pt-2 max-h-[90vh] border-t-2 border-accent">
|
||||
<div className="flex justify-center mb-2">
|
||||
<div className="badge badge-accent gap-2 text-lg items-center px-4 py-2 whitespace-nowrap max-w-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 shrink-0">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M17.982 18.725A7.488 7.488 0 0 0 12 15.75a7.488 7.488 0 0 0-5.982 2.975m11.963 0a9 9 0 1 0-11.963 0m11.963 0A8.966 8.966 0 0 1 12 21a8.966 8.966 0 0 1-5.982-2.275M15 9.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
|
||||
<span className="text-sm truncate">{transI18n("lastTurn")}: {getNameChar(locale, listAvatar.find(it => it.id === turnHistory.findLast(i => i?.avatarId)?.avatarId?.toString()))}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="relative h-full pt-2 max-h-[90vh] lg:max-h-[80vh] border-t-2 border-accent">
|
||||
{lineupAvatars.length === 0 ? (
|
||||
<div className="h-full flex justify-center items-start">
|
||||
<p className="text-base-content opacity-50">{transI18n("noCharactersInLineup")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full w-full overflow-x-auto md:overflow-x-hidden md:overflow-y-auto custom-scrollbar rounded-lg">
|
||||
<style jsx>{`
|
||||
.custom-scrollbar {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: hsl(var(--p)) hsl(var(--b3));
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: hsl(var(--b3));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: hsl(var(--p));
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: hsl(var(--pf));
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
<div className="h-full w-full overflow-x-auto md:overflow-x-hidden md:overflow-y-auto rounded-lg">
|
||||
<div className="flex flex-nowrap md:grid md:grid-cols-1 w-fit md:w-full justify-items-center items-start gap-2">
|
||||
{lineupAvatars.map((item, index) => (
|
||||
<motion.div
|
||||
key={item.id}
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.1 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
className="cursor-pointer flex-shrink-0 md:w-full justify-items-center"
|
||||
onClick={() => handleShow("character_detail_modal", item)}
|
||||
>
|
||||
<CharacterCard data={item} />
|
||||
</motion.div>
|
||||
))}
|
||||
{lineupAvatars.map((item, index) => {
|
||||
const lastTurnAvatarId = turnHistory.findLast(i => i?.avatarId)?.avatarId || -1;
|
||||
const isLastTurn = item.id === lastTurnAvatarId.toString();
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={item.id}
|
||||
initial={{ opacity: 0, scale: 0.9 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.1 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
onClick={() => handleShow("character_detail_modal", item)}
|
||||
className={`cursor-pointer flex-shrink-0 justify-items-center ${isLastTurn ? "shadow-[inset_0_0_10px_2px_rgba(59,130,246,0.7),_0_0_20px_5px_rgba(59,130,246,0.3)]" : ""
|
||||
}`}
|
||||
>
|
||||
<CharacterCard data={item} />
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)}
|
||||
|
||||
{/* Character Detail Modal */}
|
||||
@@ -165,7 +148,7 @@ export default function LineupBar() {
|
||||
<h4 className="text-lg font-semibold mb-2 text-pink-500">{transI18n("characterInformation")}</h4>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2">
|
||||
<div className="flex flex-col space-y-2 relative">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 justify-items-start items-center gap-6">
|
||||
<p>
|
||||
{transI18n("id")}: <span className="font-bold">{selectedCharacter.id}</span>
|
||||
</p>
|
||||
@@ -173,11 +156,13 @@ export default function LineupBar() {
|
||||
<span>{transI18n("path")}:</span>
|
||||
<span className="font-bold">{transI18n(selectedCharacter.baseType.toLowerCase())}</span>
|
||||
{selectedCharacter.baseType && (
|
||||
<img
|
||||
loading="lazy"
|
||||
<Image
|
||||
|
||||
src={`https://api.hakush.in/hsr/UI/pathicon/${selectedCharacter.baseType.toLowerCase()}.webp`}
|
||||
className="w-6 h-6"
|
||||
alt={selectedCharacter.baseType.toLowerCase()}
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
@@ -186,31 +171,77 @@ export default function LineupBar() {
|
||||
</p>
|
||||
<p className="flex items-center space-x-2">
|
||||
<span>{transI18n("element")}:</span>
|
||||
<span className="font-bold">{transI18n(selectedCharacter.damageType.toLowerCase())}</span>
|
||||
{selectedCharacter.damageType && (
|
||||
<img
|
||||
loading="lazy"
|
||||
src={`https://api.hakush.in/hsr/UI/element/${selectedCharacter.damageType.toLowerCase()}.webp`}
|
||||
className="w-6 h-6"
|
||||
alt={selectedCharacter.damageType.toLowerCase()}
|
||||
/>
|
||||
)}
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/element/${selectedCharacter.damageType.toLowerCase()}.webp`}
|
||||
className="w-6 h-6"
|
||||
alt={selectedCharacter.damageType.toLowerCase()}
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
</p>
|
||||
|
||||
{(() => {
|
||||
const avatar = dataAvatar.find(it => it.avatar_id.toString() === selectedCharacter.id);
|
||||
if (!avatar) return null;
|
||||
const relicIds = avatar.relics.map(item => {
|
||||
const relicIdStr = item.relic_id.toString().slice(1);
|
||||
const slot = relicIdStr.slice(-1);
|
||||
return `${item.relic_set_id}_${slot}`;
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
{transI18n("level")}: <span className="font-bold">{avatar.level}</span>
|
||||
</p>
|
||||
<p>
|
||||
{transI18n("eidolons")}: <span className="font-bold">{avatar?.data?.rank}</span>
|
||||
</p>
|
||||
<p className="flex items-center space-x-2">
|
||||
<span>{transI18n("lightcones")}:</span>
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/lightconemediumicon/${avatar?.Lightcone?.item_id}.webp`}
|
||||
className="w-12 h-12"
|
||||
alt={avatar?.Lightcone?.item_id?.toString() || ""}
|
||||
width={200}
|
||||
height={200}
|
||||
/>
|
||||
</p>
|
||||
<p className="flex items-center space-x-2 w-full">
|
||||
<span>{transI18n("relics")}:</span>
|
||||
<div className="grid grid-cols-3 md:flex md:flex-row w-full">
|
||||
{relicIds.map(it => (
|
||||
<Image
|
||||
key={it}
|
||||
src={`https://api.hakush.in/hsr/UI/relicfigures/IconRelic_${it}.webp`}
|
||||
className="w-12 h-12"
|
||||
alt={avatar?.Lightcone?.item_id?.toString() || ""}
|
||||
width={200}
|
||||
height={200}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center items-center">
|
||||
{selectedCharacter && (
|
||||
<img
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${selectedCharacter.id}.webp`}
|
||||
alt={getNameChar(locale, selectedCharacter)}
|
||||
className="h-32 w-32 object-cover rounded-full border-2 border-purple-500"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${selectedCharacter.id}.webp`}
|
||||
alt={getNameChar(locale, selectedCharacter)}
|
||||
className="h-32 w-32 object-cover rounded-full border-2 border-purple-500"
|
||||
width={128}
|
||||
height={128}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="md:col-span-2 bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<h4 className="text-lg font-semibold mb-2 text-pink-500">{transI18n("characterInformation")}</h4>
|
||||
<ShowCaseInfo></ShowCaseInfo>
|
||||
</div> */}
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<p className="mt-2 font-bold text-lg text-cyan-500">{transI18n("totalTurn")}: <span className="text-base-content">{totalTurn.toFixed(2)}</span></p>
|
||||
</div>
|
||||
@@ -218,52 +249,30 @@ export default function LineupBar() {
|
||||
<h4 className="text-lg font-semibold mb-2 text-purple-500">{transI18n("totalDamage")}: <span className="text-base-content">{totalDamage.toFixed(2)}</span></h4>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md max-h-11/12">
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<h4 className="text-lg font-semibold mb-4 text-purple-500">{transI18n("skillDamageBreakdown")}</h4>
|
||||
<SkillBarChart avatarId={Number(selectedCharacter.id) ?? 0} />
|
||||
</div>
|
||||
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md max-h-11/12">
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h4 className="text-lg font-semibold mb-4 text-cyan-500">{transI18n("damageOverTime")}</h4>
|
||||
<div className="flex gap-2">
|
||||
{[0, 1].map((m) => (
|
||||
<button
|
||||
key={m}
|
||||
onClick={() => setModeLine(m as 0 | 1)}
|
||||
className={`btn btn-sm ${modeLine === m ? "btn-accent" : "btn-ghost"}`}
|
||||
>
|
||||
{transI18n("type")} {m}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<DamageLineForOne avatarId={Number(selectedCharacter.id) ?? 0} mode={modeLine} />
|
||||
<DamageLineForOne avatarId={Number(selectedCharacter.id) ?? 0} />
|
||||
</div>
|
||||
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md max-h-11/12">
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<h4 className="text-lg font-semibold mb-4 text-cyan-500">{transI18n("skillUsageDistribution")}</h4>
|
||||
<SkillPieChart avatarId={Number(selectedCharacter.id) ?? 0} />
|
||||
</div>
|
||||
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md max-h-11/12">
|
||||
<div className="bg-base-200 rounded-lg p-4 shadow-md">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h4 className="text-lg font-semibold text-purple-500">{transI18n("damagerPerCycle")}</h4>
|
||||
<div className="flex gap-2">
|
||||
{[0, 1, 2].map((m) => (
|
||||
<button
|
||||
key={m}
|
||||
onClick={() => setModeBar(m as 0 | 1 | 2)}
|
||||
className={`btn btn-sm ${modeBar === m ? "btn-accent" : "btn-ghost"}`}
|
||||
>
|
||||
{transI18n("type")} {m}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<h4 className="text-lg font-semibold text-purple-500">{transI18n("damagePerCycle")}</h4>
|
||||
</div>
|
||||
<DamagePerCycleForOne avatarId={Number(selectedCharacter.id) ?? 0} mode={modeBar} />
|
||||
<DamagePerCycleForOne avatarId={Number(selectedCharacter.id) ?? 0} />
|
||||
</div>
|
||||
|
||||
</motion.div>
|
||||
|
||||
Reference in New Issue
Block a user