UPDATE: Responsive for mobile
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 1m54s

This commit is contained in:
2025-09-30 15:15:51 +07:00
parent 6908e3971f
commit 91ce8320d1
10 changed files with 437 additions and 412 deletions

View File

@@ -197,6 +197,7 @@
"selectPFEvent": "Chọn sự kiện PF", "selectPFEvent": "Chọn sự kiện PF",
"selectASEvent": "Chọn sự kiện AS", "selectASEvent": "Chọn sự kiện AS",
"selectCEEvent": "Chọn sự kiện CE", "selectCEEvent": "Chọn sự kiện CE",
"selectPEAKEvent": "Chọn sự kiện PEAK",
"selectEvent": "Chọn sự kiện", "selectEvent": "Chọn sự kiện",
"selectFloor": "Chọn tầng", "selectFloor": "Chọn tầng",
"selectSide": "Chọn nửa trận", "selectSide": "Chọn nửa trận",
@@ -237,10 +238,9 @@
"maxAllSuccess": "Đã thiết lập cấp độ kỹ năng tối đa thành công.", "maxAllSuccess": "Đã thiết lập cấp độ kỹ năng tối đa thành công.",
"maxAllFailed": "Thiết lập cấp độ kỹ năng tối đa thất bại.", "maxAllFailed": "Thiết lập cấp độ kỹ năng tối đa thất bại.",
"noRelicEquipped": "Không có di vật", "noRelicEquipped": "Không có di vật",
"anomalyArbitration": "Phán Quyết Dị Thường", "anomalyArbitration": "Trọng tài dị tướng",
"normalMode": "Chế độ thường", "normalMode": "Chế độ thường",
"hardMode": "Chế độ khó", "hardMode": "Chế độ khó",
"selectPEAKEvent": "Chọn sự kiện",
"mode": "Chế độ", "mode": "Chế độ",
"selectMode": "Chọn chế độ", "selectMode": "Chọn chế độ",
"rollBack": "Quay lại bước trước", "rollBack": "Quay lại bước trước",

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -74,7 +74,7 @@ export default function AsBar() {
newBattleConfig.monsters = [] newBattleConfig.monsters = []
newBattleConfig.stage_id = 0 newBattleConfig.stage_id = 0
if ((as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower") if ((as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower")
&& challengeSelected.EventIDList1.length > 0) { && challengeSelected.EventIDList1.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventIDList1[0].StageID newBattleConfig.stage_id = challengeSelected.EventIDList1[0].StageID
for (const wave of challengeSelected.EventIDList1[0].MonsterList) { for (const wave of challengeSelected.EventIDList1[0].MonsterList) {
@@ -89,7 +89,7 @@ export default function AsBar() {
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} }
if ((as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper") if ((as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper")
&& challengeSelected.EventIDList2.length > 0) { && challengeSelected.EventIDList2.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventIDList2[0].StageID newBattleConfig.stage_id = challengeSelected.EventIDList2[0].StageID
for (const wave of challengeSelected.EventIDList2[0].MonsterList) { for (const wave of challengeSelected.EventIDList2[0].MonsterList) {
@@ -104,7 +104,7 @@ export default function AsBar() {
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} }
if (as_config.floor_side === "Lower -> Upper" if (as_config.floor_side === "Lower -> Upper"
&& challengeSelected.EventIDList1.length > 0) { && challengeSelected.EventIDList1.length > 0) {
for (const wave of challengeSelected.EventIDList1[0].MonsterList) { for (const wave of challengeSelected.EventIDList1[0].MonsterList) {
const newWave: MonsterStore[] = [] const newWave: MonsterStore[] = []
@@ -117,7 +117,7 @@ export default function AsBar() {
} }
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} else if (as_config.floor_side === "Upper -> Lower" } else if (as_config.floor_side === "Upper -> Lower"
&& challengeSelected.EventIDList2.length > 0) { && challengeSelected.EventIDList2.length > 0) {
for (const wave of challengeSelected.EventIDList2[0].MonsterList) { for (const wave of challengeSelected.EventIDList2[0].MonsterList) {
const newWave: MonsterStore[] = [] const newWave: MonsterStore[] = []
@@ -146,7 +146,7 @@ export default function AsBar() {
if (!ASEvent) return null if (!ASEvent) return null
return ( return (
<div className="container mx-auto px-4 py-8 relative"> <div className="py-8 relative">
{/* Title Card */} {/* Title Card */}
<div className="rounded-xl p-4 mb-2 border border-warning"> <div className="rounded-xl p-4 mb-2 border border-warning">
@@ -160,11 +160,11 @@ export default function AsBar() {
excludeSet={[]} excludeSet={[]}
selectedCustomSet={as_config.event_id.toString()} selectedCustomSet={as_config.event_id.toString()}
placeholder={transI18n("selectASEvent")} placeholder={transI18n("selectASEvent")}
setSelectedCustomSet={(id) => setAsConfig({ setSelectedCustomSet={(id) => setAsConfig({
...as_config, ...as_config,
event_id: Number(id), event_id: Number(id),
challenge_id: mapASInfo[Number(id)]?.Level.slice(-1)[0]?.Id || 0, challenge_id: mapASInfo[Number(id)]?.Level.slice(-1)[0]?.Id || 0,
buff_id: 0 buff_id: 0
})} })}
/> />
</div> </div>
@@ -243,106 +243,109 @@ export default function AsBar() {
</div> </div>
{/* Enemy Waves */} {/* Enemy Waves */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> {(as_config?.challenge_id ?? 0) !== 0 && (
{/* First Half */} <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div className="rounded-xl p-4 mt-2 border border-warning"> {/* First Half */}
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2> <div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventIDList1?.length > 0 && challengeSelected?.EventIDList1[0].MonsterList.map((wave, waveIndex) => ( {challengeSelected && challengeSelected?.EventIDList1?.length > 0 && challengeSelected?.EventIDList1[0].MonsterList.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6"> <div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Object.values(wave).map((waveValue, enemyIndex) => ( {Object.values(wave).map((waveValue, enemyIndex) => (
<div <div
key={enemyIndex} key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image {listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon" alt="Enemy Icon"
width={376} width={376}
height={512} height={512}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/>} />}
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1"> <div className="flex items-center space-x-1 mt-1">
{listMonster {listMonster
.find((monster) => monster.child.includes(waveValue)) .find((monster) => monster.child.includes(waveValue))
?.weak?.map((icon, iconIndex) => ( ?.weak?.map((icon, iconIndex) => (
<Image <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon} alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200} width={200}
height={200} height={200}
key={iconIndex} key={iconIndex}
/> />
))} ))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div>
{/* Second Half */} {/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning"> <div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2> <h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventIDList2?.length > 0 && challengeSelected?.EventIDList2[0].MonsterList.map((wave, waveIndex) => ( {challengeSelected && challengeSelected?.EventIDList2?.length > 0 && challengeSelected?.EventIDList2[0].MonsterList.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6"> <div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Object.values(wave).map((waveValue, enemyIndex) => ( {Object.values(wave).map((waveValue, enemyIndex) => (
<div <div
key={enemyIndex} key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image {listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon" alt="Enemy Icon"
width={376} width={376}
height={512} height={512}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/>} />}
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1"> <div className="flex items-center space-x-1 mt-1">
{listMonster {listMonster
.find((monster) => monster.child.includes(waveValue)) .find((monster) => monster.child.includes(waveValue))
?.weak?.map((icon, iconIndex) => ( ?.weak?.map((icon, iconIndex) => (
<Image <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon} alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200} width={200}
height={200} height={200}
key={iconIndex} key={iconIndex}
/> />
))} ))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> )}
</div> </div>
) )
} }

View File

@@ -111,7 +111,7 @@ export default function CeBar() {
}, [stageSearchTerm]) }, [stageSearchTerm])
return ( return (
<div className="p-6 z-4 h-full w-full" onClick={() => { <div className="z-4 py-8 h-full w-full" onClick={() => {
setShowSearchWaveId(null) setShowSearchWaveId(null)
setShowSearchStage(false) setShowSearchStage(false)
@@ -217,7 +217,7 @@ export default function CeBar() {
{ce_config.monsters.map((wave, waveIndex) => ( {ce_config.monsters.map((wave, waveIndex) => (
<div key={waveIndex} className="card border border-slate-700/50 "> <div key={waveIndex} className="card border border-slate-700/50 ">
<div className="card-body p-6"> <div className="card-body p-6">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center flex-wrap justify-between mb-4">
<h2 className="text-xl font-bold text-white">{transI18n("wave")} {waveIndex + 1}</h2> <h2 className="text-xl font-bold text-white">{transI18n("wave")} {waveIndex + 1}</h2>
<div className="flex gap-2"> <div className="flex gap-2">
<button <button
@@ -286,7 +286,7 @@ export default function CeBar() {
<div className="card border hover:border-slate-500 transition-colors w-full h-full"> <div className="card border hover:border-slate-500 transition-colors w-full h-full">
<div className="card-body p-4"> <div className="card-body p-4">
<button <button
className="btn btn-xs btn-success absolute -top-2 right-5 opacity-50 group-hover:opacity-100 transition-opacity" className="btn btn-xs btn-success absolute -top-2 right-12 opacity-50 group-hover:opacity-100 transition-opacity"
onClick={() => { onClick={() => {
const newCeConfig = cloneDeep(ce_config) const newCeConfig = cloneDeep(ce_config)
@@ -301,7 +301,7 @@ export default function CeBar() {
<CopyPlus className="w-3 h-3" /> <CopyPlus className="w-3 h-3" />
</button> </button>
<button <button
className="btn btn-xs btn-error absolute -top-2 -right-4 opacity-50 group-hover:opacity-100 transition-opacity" className="btn btn-xs btn-error absolute -top-2 right-2 opacity-50 group-hover:opacity-100 transition-opacity"
onClick={() => { onClick={() => {
const newCeConfig = cloneDeep(ce_config) const newCeConfig = cloneDeep(ce_config)
newCeConfig.monsters[waveIndex].splice(memberIndex, 1) newCeConfig.monsters[waveIndex].splice(memberIndex, 1)

View File

@@ -15,56 +15,64 @@ export default function MonsterBar() {
{ name: transI18n("memoryOfChaos"), icon: 'AbyssIcon01', value: 'MOC' }, { name: transI18n("memoryOfChaos"), icon: 'AbyssIcon01', value: 'MOC' },
{ name: transI18n("pureFiction"), icon: 'ChallengeStory', value: 'PF' }, { name: transI18n("pureFiction"), icon: 'ChallengeStory', value: 'PF' },
{ name: transI18n("apocalypticShadow"), icon: 'ChallengeBoss', value: 'AS' }, { name: transI18n("apocalypticShadow"), icon: 'ChallengeBoss', value: 'AS' },
{ name: transI18n("anomalyArbitration"), icon: 'AbyssIcon02', value: 'PEAK' }, { name: transI18n("anomalyArbitration"), icon: 'ChallengePeakIcon', value: 'PEAK' },
{ name: transI18n("customEnemy"), icon: 'MonsterIcon', value: 'CE' }, { name: transI18n("customEnemy"), icon: 'MonsterIcon', value: 'CE' },
{ name: transI18n("simulatedUniverse"), icon: 'SimulatedUniverse', value: 'SU' }, { name: transI18n("simulatedUniverse"), icon: 'SimulatedUniverse', value: 'SU' },
]; ];
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
{/* Header Navigation */} {/* Header Navigation */}
<nav className="border-b border-warning/30 relative"> <nav className="border-b border-warning/30 relative pb-2">
<div className="container mx-auto px-4"> <div className="flex items-center justify-center">
<div className="flex items-center justify-center"> {/* Mobile Select */}
{/* Navigation Tabs */} <div className="block md:hidden w-full">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-1"> <select
className="select select-bordered w-full"
value={battle_type.toUpperCase()}
onChange={(e) => setBattleType(e.target.value.toUpperCase())}
>
{navItems.map((item) => ( {navItems.map((item) => (
<button <option key={item.name} value={item.value.toUpperCase()}>
key={item.name} {item.name}
onClick={() => setBattleType(item.value.toUpperCase())} </option>
className={`px-4 py-2 rounded-lg transition-all cursor-pointer duration-300 flex items-center space-x-2 ${battle_type.toUpperCase() === item.value.toUpperCase()
? 'bg-success/30 shadow-lg'
: 'bg-base-200/20 hover:bg-base-200/40 '
}`}
>
<span
style={
battle_type.toUpperCase() === item.value.toUpperCase()
? {
filter:
'brightness(0) saturate(100%) invert(63%) sepia(78%) saturate(643%) hue-rotate(1deg) brightness(93%) contrast(89%)',
}
: undefined
}
>
<Image src={`/icon/${item.icon}.webp`} alt={item.name} width={24} height={24} />
</span>
<span
style={
battle_type.toUpperCase() === item.value.toUpperCase()
? {
filter:
'brightness(0) saturate(100%) invert(63%) sepia(78%) saturate(643%) hue-rotate(1deg) brightness(93%) contrast(89%)',
}
: undefined
}
>
<span className="font-medium">{item.name}</span>
</span>
</button>
))} ))}
</div> </select>
</div>
{/* Desktop Tabs */}
<div className="hidden md:grid grid-cols-3 lg:grid-cols-6 gap-1">
{navItems.map((item) => (
<button
key={item.name}
onClick={() => setBattleType(item.value.toUpperCase())}
className={`px-4 py-2 rounded-lg transition-all cursor-pointer duration-300 flex items-center space-x-2 ${battle_type.toUpperCase() === item.value.toUpperCase()
? 'bg-success/30 shadow-lg'
: 'bg-base-200/20 hover:bg-base-200/40 '
}`}
>
<span
style={
battle_type.toUpperCase() === item.value.toUpperCase()
? {
filter:
'brightness(0) saturate(100%) invert(63%) sepia(78%) saturate(643%) hue-rotate(1deg) brightness(93%) contrast(89%)',
}
: undefined
}
>
<Image
src={`/icon/${item.icon}.webp`}
alt={item.name}
width={24}
height={24}
/>
</span>
<span>{item.name}</span>
</button>
))}
</div> </div>
</div> </div>
</nav> </nav>
@@ -81,7 +89,7 @@ export default function MonsterBar() {
{battle_type.toUpperCase() === 'PEAK' && <PeakBar />} {battle_type.toUpperCase() === 'PEAK' && <PeakBar />}
{battle_type.toUpperCase() === 'SU' && ( {battle_type.toUpperCase() === 'SU' && (
<div className="container mx-auto px-4 py-8 text-center font-bold text-3xl"> <div className="container mx-auto px-4 py-8 text-center font-bold text-3xl">
{transI18n("comingSoon")} {transI18n("comingSoon")}
</div> </div>
)} )}

View File

@@ -113,7 +113,7 @@ export default function MocBar() {
]) ])
if (!MOCEvent) return null if (!MOCEvent) return null
return ( return (
<div className="container mx-auto px-4 py-8 relative"> <div className="py-8 relative">
{/* Title Card */} {/* Title Card */}
<div className="rounded-xl p-4 mb-2 border border-warning"> <div className="rounded-xl p-4 mb-2 border border-warning">
@@ -127,10 +127,10 @@ export default function MocBar() {
excludeSet={[]} excludeSet={[]}
selectedCustomSet={moc_config.event_id.toString()} selectedCustomSet={moc_config.event_id.toString()}
placeholder={transI18n("selectMOCEvent")} placeholder={transI18n("selectMOCEvent")}
setSelectedCustomSet={(id) => setMocConfig({ setSelectedCustomSet={(id) => setMocConfig({
...moc_config, ...moc_config,
event_id: Number(id), event_id: Number(id),
challenge_id: mapMOCInfo[Number(id)]?.slice(-1)[0]?.Id || 0, challenge_id: mapMOCInfo[Number(id)]?.slice(-1)[0]?.Id || 0,
})} })}
/> />
</div> </div>
@@ -144,9 +144,9 @@ export default function MocBar() {
<select <select
value={moc_config.challenge_id} value={moc_config.challenge_id}
className="select select-success" className="select select-success"
onChange={(e) => setMocConfig({ onChange={(e) => setMocConfig({
...moc_config, ...moc_config,
challenge_id: Number(e.target.value) challenge_id: Number(e.target.value)
})} })}
> >
<option value={0} disabled={true}>Select a Floor</option> <option value={0} disabled={true}>Select a Floor</option>
@@ -223,106 +223,109 @@ export default function MocBar() {
</div> </div>
{/* Enemy Waves */} {/* Enemy Waves */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> {(moc_config?.challenge_id ?? 0) !== 0 && (
{/* First Half */} <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div className="rounded-xl p-4 mt-2 border border-warning"> {/* First Half */}
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2> <div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventIDList1?.length > 0 && challengeSelected?.EventIDList1[0].MonsterList.map((wave, waveIndex) => ( {challengeSelected && challengeSelected?.EventIDList1?.length > 0 && challengeSelected?.EventIDList1[0].MonsterList.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6"> <div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Object.values(wave).map((waveValue, enemyIndex) => ( {Object.values(wave).map((waveValue, enemyIndex) => (
<div <div
key={enemyIndex} key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image {listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon" alt="Enemy Icon"
width={376} width={376}
height={512} height={512}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/>} />}
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1"> <div className="flex items-center space-x-1 mt-1">
{listMonster {listMonster
.find((monster) => monster.child.includes(waveValue)) .find((monster) => monster.child.includes(waveValue))
?.weak?.map((icon, iconIndex) => ( ?.weak?.map((icon, iconIndex) => (
<Image <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon} alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200} width={200}
height={200} height={200}
key={iconIndex} key={iconIndex}
/> />
))} ))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div>
{/* Second Half */} {/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning"> <div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2> <h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventIDList2?.length > 0 && challengeSelected?.EventIDList2[0].MonsterList.map((wave, waveIndex) => ( {challengeSelected && challengeSelected?.EventIDList2?.length > 0 && challengeSelected?.EventIDList2[0].MonsterList.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6"> <div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Object.values(wave).map((waveValue, enemyIndex) => ( {Object.values(wave).map((waveValue, enemyIndex) => (
<div <div
key={enemyIndex} key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image {listMonster.find((monster) => monster.child.includes(waveValue))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(waveValue))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon" alt="Enemy Icon"
width={376} width={376}
height={512} height={512}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/>} />}
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1"> <div className="flex items-center space-x-1 mt-1">
{listMonster {listMonster
.find((monster) => monster.child.includes(waveValue)) .find((monster) => monster.child.includes(waveValue))
?.weak?.map((icon, iconIndex) => ( ?.weak?.map((icon, iconIndex) => (
<Image <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon} alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200} width={200}
height={200} height={200}
key={iconIndex} key={iconIndex}
/> />
))} ))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> )}
</div> </div>
) )
} }

View File

@@ -55,53 +55,53 @@ export default function PeakBar() {
}, [peak_config, listFloor, mapPEAKInfo, bossConfig]) }, [peak_config, listFloor, mapPEAKInfo, bossConfig])
useEffect(() => { useEffect(() => {
if (!challengeSelected) return if (!challengeSelected) return
if (peak_config.event_id !== 0 && peak_config.challenge_id !== 0 && challengeSelected) { if (peak_config.event_id !== 0 && peak_config.challenge_id !== 0 && challengeSelected) {
const newBattleConfig = cloneDeep(peak_config) const newBattleConfig = cloneDeep(peak_config)
newBattleConfig.cycle_count = 6 newBattleConfig.cycle_count = 6
newBattleConfig.blessings = [] newBattleConfig.blessings = []
for (const value of challengeSelected.TagList) { for (const value of challengeSelected.TagList) {
newBattleConfig.blessings.push({ newBattleConfig.blessings.push({
id: Number(value.Id), id: Number(value.Id),
level: 1 level: 1
}) })
}
if (peak_config.buff_id !== 0) {
newBattleConfig.blessings.push({
id: peak_config.buff_id,
level: 1
})
}
newBattleConfig.monsters = []
newBattleConfig.stage_id = challengeSelected.EventIDList[0].StageID
for (const wave of challengeSelected.EventIDList[0].MonsterList) {
if (!wave) continue
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
if (!value) continue
newWave.push({
monster_id: Number(value),
level: challengeSelected.EventIDList[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
setPeakConfig(newBattleConfig)
} }
if (peak_config.buff_id !== 0) {
newBattleConfig.blessings.push({
id: peak_config.buff_id,
level: 1
})
}
newBattleConfig.monsters = []
newBattleConfig.stage_id = challengeSelected.EventIDList[0].StageID
for (const wave of challengeSelected.EventIDList[0].MonsterList) {
if (!wave) continue
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
if (!value) continue
newWave.push({
monster_id: Number(value),
level: challengeSelected.EventIDList[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
setPeakConfig(newBattleConfig)
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
peak_config.event_id, peak_config.event_id,
peak_config.challenge_id, peak_config.challenge_id,
peak_config.buff_id, peak_config.buff_id,
mapPEAKInfo, mapPEAKInfo,
]) ])
if (!PEAKEvent) return null if (!PEAKEvent) return null
return ( return (
<div className="container mx-auto px-4 py-8 relative"> <div className="py-8 relative">
{/* Title Card */} {/* Title Card */}
<div className="rounded-xl p-4 mb-2 border border-warning"> <div className="rounded-xl p-4 mb-2 border border-warning">
@@ -113,7 +113,7 @@ export default function PeakBar() {
}))} }))}
excludeSet={[]} excludeSet={[]}
selectedCustomSet={peak_config.event_id.toString()} selectedCustomSet={peak_config.event_id.toString()}
placeholder={transI18n("selectASEvent")} placeholder={transI18n("selectPEAKEvent")}
setSelectedCustomSet={(id) => setPeakConfig({ ...peak_config, event_id: Number(id), challenge_id: 0, buff_id: 0 })} setSelectedCustomSet={(id) => setPeakConfig({ ...peak_config, event_id: Number(id), challenge_id: 0, buff_id: 0 })}
/> />
</div> </div>
@@ -216,57 +216,61 @@ export default function PeakBar() {
</div> </div>
{/* Enemy Waves */} {/* Enemy Waves */}
<div className="grid grid-cols-1 gap-4">
<div className="rounded-xl p-4 mt-2 border border-warning"> {(peak_config?.challenge_id ?? 0) !== 0 && (
<h2 className="text-2xl font-bold mb-6 text-info">{challengeSelected?.Name}</h2> <div className="grid grid-cols-1 gap-4">
{challengeSelected && Object.values(challengeSelected.InfiniteList).map((waveValue, waveIndex) => ( <div className="rounded-xl p-4 mt-2 border border-warning">
<div key={waveIndex} className="mb-6"> <h2 className="text-2xl font-bold mb-6 text-info">{challengeSelected?.Name}</h2>
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => (
<div
key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
>
<div className="flex items-center space-x-3"> {challengeSelected && Object.values(challengeSelected.InfiniteList).map((waveValue, waveIndex) => (
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div key={waveIndex} className="mb-6">
{listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
alt="Enemy Icon" {Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => (
width={376} <div
height={512} key={enemyIndex}
className="w-full h-full object-cover" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
/>} >
</div>
<div className="flex flex-col"> <div className="flex items-center space-x-3">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList[0].Level}</div> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
<div className="flex items-center space-x-1 mt-1"> {listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image
{listMonster src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
.find((monster) => monster.child.includes(monsterId)) alt="Enemy Icon"
?.weak?.map((icon, iconIndex) => ( width={376}
<Image height={512}
src={`/icon/${icon.toLowerCase()}.webp`} className="w-full h-full object-cover"
alt={icon} />}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" </div>
width={200}
height={200} <div className="flex flex-col">
key={iconIndex} <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList[0].Level}</div>
/> <div className="flex items-center space-x-1 mt-1">
))} {listMonster
.find((monster) => monster.child.includes(monsterId))
?.weak?.map((icon, iconIndex) => (
<Image
src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200}
height={200}
key={iconIndex}
/>
))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> )}
</div> </div>
) )
} }

View File

@@ -120,7 +120,7 @@ export default function PfBar() {
if (!PFEvent) return null if (!PFEvent) return null
return ( return (
<div className="container mx-auto px-4 py-8 relative"> <div className="py-8 relative">
{/* Title Card */} {/* Title Card */}
<div className="rounded-xl p-4 mb-2 border border-warning"> <div className="rounded-xl p-4 mb-2 border border-warning">
@@ -134,11 +134,12 @@ export default function PfBar() {
excludeSet={[]} excludeSet={[]}
selectedCustomSet={pf_config.event_id.toString()} selectedCustomSet={pf_config.event_id.toString()}
placeholder={transI18n("selectPFEvent")} placeholder={transI18n("selectPFEvent")}
setSelectedCustomSet={(id) => setPfConfig({ setSelectedCustomSet={(id) => setPfConfig({
...pf_config, ...pf_config,
event_id: Number(id), event_id: Number(id),
challenge_id: mapPFInfo[Number(id)]?.Level.slice(-1)[0]?.Id || 0, challenge_id: mapPFInfo[Number(id)]?.Level.slice(-1)[0]?.Id || 0,
buff_id: 0 })} buff_id: 0
})}
/> />
</div> </div>
{/* Settings */} {/* Settings */}
@@ -229,107 +230,111 @@ export default function PfBar() {
</div> </div>
{/* Enemy Waves */} {/* Enemy Waves */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* First Half */}
<div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
{challengeSelected && Object.values(challengeSelected.InfiniteList1).map((waveValue, waveIndex) => ( {(pf_config?.challenge_id ?? 0) !== 0 && (
<div key={waveIndex} className="mb-6"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> {/* First Half */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="rounded-xl p-4 mt-2 border border-warning">
{Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => ( <h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
<div {challengeSelected && Object.values(challengeSelected.InfiniteList1).map((waveValue, waveIndex) => (
key={enemyIndex} <div key={waveIndex} className="mb-6">
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="flex items-center space-x-3"> {Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => (
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon"
width={376}
height={512}
className="w-full h-full object-cover"
/>}
</div>
<div className="flex flex-col"> <div
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> key={enemyIndex}
<div className="flex items-center space-x-1 mt-1"> className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
{listMonster >
.find((monster) => monster.child.includes(monsterId)) <div className="flex items-center space-x-3">
?.weak?.map((icon, iconIndex) => ( <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
<Image {listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt={icon} alt="Enemy Icon"
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" width={376}
width={200} height={512}
height={200} className="w-full h-full object-cover"
key={iconIndex} />}
/> </div>
))}
<div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1">
{listMonster
.find((monster) => monster.child.includes(monsterId))
?.weak?.map((icon, iconIndex) => (
<Image
src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200}
height={200}
key={iconIndex}
/>
))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div>
{/* Second Half */} {/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning"> <div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2> <h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && Object.values(challengeSelected?.InfiniteList2).map((waveValue, waveIndex) => ( {challengeSelected && Object.values(challengeSelected?.InfiniteList2).map((waveValue, waveIndex) => (
<div key={waveIndex} className="mb-6"> <div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3> <h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => ( {Array.from(new Set(waveValue.MonsterGroupIDList)).map((monsterId, enemyIndex) => (
<div <div
key={enemyIndex} key={enemyIndex}
className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition" className="rounded-xl p-2 border border-white/10 shadow-md hover:border-white/20 hover:shadow-lg transition"
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm"> <div className="relative w-20 h-20 rounded-full overflow-hidden flex-shrink-0 border border-white/10 shadow-sm">
{listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image {listMonster.find((monster) => monster.child.includes(monsterId))?.icon && <Image
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listMonster.find((monster) => monster.child.includes(monsterId))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
alt="Enemy Icon" alt="Enemy Icon"
width={376} width={376}
height={512} height={512}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/>} />}
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div> <div className="text-sm font-semibold">Lv. {challengeSelected?.EventIDList1[0].Level}</div>
<div className="flex items-center space-x-1 mt-1"> <div className="flex items-center space-x-1 mt-1">
{listMonster {listMonster
.find((monster) => monster.child.includes(monsterId)) .find((monster) => monster.child.includes(monsterId))
?.weak?.map((icon, iconIndex) => ( ?.weak?.map((icon, iconIndex) => (
<Image <Image
src={`/icon/${icon.toLowerCase()}.webp`} src={`/icon/${icon.toLowerCase()}.webp`}
alt={icon} alt={icon}
className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm" className="h-[28px] w-[28px] 2xl:h-[40px] 2xl:w-[40px] object-contain rounded-md border border-white/20 shadow-sm"
width={200} width={200}
height={200} height={200}
key={iconIndex} key={iconIndex}
/> />
))} ))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> ))}
))} </div>
</div> </div>
</div> )}
</div> </div>
) )
} }

View File

@@ -174,6 +174,7 @@ export default function RelicsInfo() {
} else { } else {
setSelectedRelicSlot(item) setSelectedRelicSlot(item)
} }
handlerChangeRelic(item)
}} }}
className="cursor-pointer" className="cursor-pointer"
> >

View File

@@ -189,9 +189,10 @@ export default function SkillsInfo() {
setSkillSelected(btn.id === skillSelected ? null : btn.id) setSkillSelected(btn.id === skillSelected ? null : btn.id)
}} }}
style={{ style={{
left: `calc(${btn.left} - var(--size-${btn.size}) / 2)`, left: btn.left,
top: `calc(${btn.top} - var(--size-${btn.size}) / 2)`, top: btn.top,
}} transform: "translate(-50%, -50%)",
}}
> >
<Image <Image
src={getImageSkill(avatarInfo?.SkillTrees?.[btn.id]?.["1"]?.Icon, avatarSkillTree?.[btn.id]?.["1"]?.StatusAddList[0]) || ""} src={getImageSkill(avatarInfo?.SkillTrees?.[btn.id]?.["1"]?.Icon, avatarSkillTree?.[btn.id]?.["1"]?.StatusAddList[0]) || ""}