UPDATE: add more ui for showcase card, fix some bug
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 2m1s
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 2m1s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect } from "react"
|
||||||
import CharacterCard from "../card/characterCard"
|
import CharacterCard from "../card/characterCard"
|
||||||
import useLocaleStore from "@/stores/localeStore"
|
import useLocaleStore from "@/stores/localeStore"
|
||||||
import useAvatarStore from "@/stores/avatarStore"
|
import useAvatarStore from "@/stores/avatarStore"
|
||||||
@@ -8,9 +8,17 @@ import { useTranslations } from "next-intl"
|
|||||||
|
|
||||||
|
|
||||||
export default function AvatarBar({ onClose }: { onClose?: () => void }) {
|
export default function AvatarBar({ onClose }: { onClose?: () => void }) {
|
||||||
const [listElement, setListElement] = useState<Record<string, boolean>>({ "fire": false, "ice": false, "imaginary": false, "physical": false, "quantum": false, "thunder": false, "wind": false })
|
const {
|
||||||
const [listPath, setListPath] = useState<Record<string, boolean>>({ "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false })
|
listAvatar,
|
||||||
const { listAvatar, setAvatarSelected, setSkillSelected, setFilter, filter } = useAvatarStore()
|
setAvatarSelected,
|
||||||
|
setSkillSelected,
|
||||||
|
setFilter,
|
||||||
|
filter,
|
||||||
|
listElement,
|
||||||
|
listPath,
|
||||||
|
setListElement,
|
||||||
|
setListPath
|
||||||
|
} = useAvatarStore()
|
||||||
const transI18n = useTranslations("DataPage")
|
const transI18n = useTranslations("DataPage")
|
||||||
const { locale } = useLocaleStore()
|
const { locale } = useLocaleStore()
|
||||||
|
|
||||||
@@ -40,7 +48,7 @@ export default function AvatarBar({ onClose }: { onClose?: () => void }) {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListElement((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListElement({ ...listElement, [key]: !listElement[key] })
|
||||||
}}
|
}}
|
||||||
className="hover:bg-gray-600 grid items-center justify-items-center cursor-pointer rounded-md shadow-lg"
|
className="hover:bg-gray-600 grid items-center justify-items-center cursor-pointer rounded-md shadow-lg"
|
||||||
style={{
|
style={{
|
||||||
@@ -60,7 +68,7 @@ export default function AvatarBar({ onClose }: { onClose?: () => void }) {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListPath((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListPath({ ...listPath, [key]: !listPath[key] })
|
||||||
}}
|
}}
|
||||||
className="hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-lg cursor-pointer"
|
className="hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-lg cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import SelectCustomImage from "../select/customSelectImage";
|
|||||||
|
|
||||||
export default function CopyImport() {
|
export default function CopyImport() {
|
||||||
const { avatars, setAvatar } = useUserDataStore();
|
const { avatars, setAvatar } = useUserDataStore();
|
||||||
const {avatarSelected} = useListAvatarStore()
|
const { avatarSelected } = useListAvatarStore()
|
||||||
const { locale } = useLocaleStore()
|
const { locale } = useLocaleStore()
|
||||||
const {
|
const {
|
||||||
selectedProfiles,
|
selectedProfiles,
|
||||||
@@ -22,12 +22,16 @@ export default function CopyImport() {
|
|||||||
setSelectedProfiles,
|
setSelectedProfiles,
|
||||||
filterCopy,
|
filterCopy,
|
||||||
setFilterCopy,
|
setFilterCopy,
|
||||||
setAvatarCopySelected
|
setAvatarCopySelected,
|
||||||
|
listElement,
|
||||||
|
listPath,
|
||||||
|
listRank,
|
||||||
|
setListElement,
|
||||||
|
setListPath,
|
||||||
|
setListRank
|
||||||
} = useCopyProfileStore()
|
} = useCopyProfileStore()
|
||||||
const transI18n = useTranslations("DataPage")
|
const transI18n = useTranslations("DataPage")
|
||||||
const [listPath, setListPath] = useState<Record<string, boolean>>({ "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false })
|
|
||||||
const [listElement, setListElement] = useState<Record<string, boolean>>({ "fire": false, "ice": false, "imaginary": false, "physical": false, "quantum": false, "thunder": false, "wind": false })
|
|
||||||
const [listRank, setListRank] = useState<Record<string, boolean>>({ "4": false, "5": false })
|
|
||||||
const [message, setMessage] = useState({
|
const [message, setMessage] = useState({
|
||||||
type: "",
|
type: "",
|
||||||
text: ""
|
text: ""
|
||||||
@@ -49,8 +53,9 @@ export default function CopyImport() {
|
|||||||
element: Object.keys(listElement).filter((key) => listElement[key]),
|
element: Object.keys(listElement).filter((key) => listElement[key]),
|
||||||
rarity: Object.keys(listRank).filter((key) => listRank[key])
|
rarity: Object.keys(listRank).filter((key) => listRank[key])
|
||||||
})
|
})
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [listPath, listRank, locale])
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [listPath, listRank, listElement, locale, setFilterCopy])
|
||||||
|
|
||||||
const clearSelection = () => {
|
const clearSelection = () => {
|
||||||
setSelectedProfiles([]);
|
setSelectedProfiles([]);
|
||||||
@@ -142,7 +147,7 @@ export default function CopyImport() {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListPath((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListPath({ ...listPath, [key]: !listPath[key] })
|
||||||
}}
|
}}
|
||||||
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
@@ -167,7 +172,7 @@ export default function CopyImport() {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListElement((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListElement({ ...listElement, [key]: !listElement[key] })
|
||||||
}}
|
}}
|
||||||
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
@@ -192,7 +197,7 @@ export default function CopyImport() {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListRank((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListRank({ ...listRank, [key]: !listRank[key] })
|
||||||
}}
|
}}
|
||||||
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
className="w-[50px] h-[50px] hover:bg-gray-600 grid items-center justify-items-center rounded-md shadow-md cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
@@ -207,9 +212,10 @@ export default function CopyImport() {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 gap-2">
|
<div className="grid grid-cols-1 gap-2">
|
||||||
<div>
|
|
||||||
<div>{transI18n("characterName")}</div>
|
{listCopyAvatar.length > 0 && (
|
||||||
{listCopyAvatar.length > 0 && (
|
<div>
|
||||||
|
<div>{transI18n("characterName")}</div>
|
||||||
<SelectCustomImage
|
<SelectCustomImage
|
||||||
customSet={listCopyAvatar.map((avatar) => ({
|
customSet={listCopyAvatar.map((avatar) => ({
|
||||||
value: avatar.id.toString(),
|
value: avatar.id.toString(),
|
||||||
@@ -221,8 +227,9 @@ export default function CopyImport() {
|
|||||||
placeholder="Character Select"
|
placeholder="Character Select"
|
||||||
setSelectedCustomSet={(value) => setAvatarCopySelected(listCopyAvatar.find((avatar) => avatar.id.toString() === value) || null)}
|
setSelectedCustomSet={(value) => setAvatarCopySelected(listCopyAvatar.find((avatar) => avatar.id.toString() === value) || null)}
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect } from "react"
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import useLocaleStore from "@/stores/localeStore"
|
import useLocaleStore from "@/stores/localeStore"
|
||||||
import useLightconeStore from "@/stores/lightconeStore";
|
import useLightconeStore from "@/stores/lightconeStore";
|
||||||
@@ -11,10 +11,17 @@ import useModelStore from "@/stores/modelStore";
|
|||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
export default function LightconeBar() {
|
export default function LightconeBar() {
|
||||||
const [listPath, setListPath] = useState<Record<string, boolean>>({ "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false })
|
|
||||||
const [listRank, setListRank] = useState<Record<string, boolean>>({ "3": false, "4": false, "5": false })
|
|
||||||
const { locale } = useLocaleStore()
|
const { locale } = useLocaleStore()
|
||||||
const { listLightcone, filter, setFilter, defaultFilter } = useLightconeStore()
|
const {
|
||||||
|
listLightcone,
|
||||||
|
filter,
|
||||||
|
setFilter,
|
||||||
|
defaultFilter,
|
||||||
|
listPath,
|
||||||
|
listRank,
|
||||||
|
setListPath,
|
||||||
|
setListRank
|
||||||
|
} = useLightconeStore()
|
||||||
const { setAvatar, avatars } = useUserDataStore()
|
const { setAvatar, avatars } = useUserDataStore()
|
||||||
const { avatarSelected } = useAvatarStore()
|
const { avatarSelected } = useAvatarStore()
|
||||||
const { setIsOpenLightcone } = useModelStore()
|
const { setIsOpenLightcone } = useModelStore()
|
||||||
@@ -35,7 +42,7 @@ export default function LightconeBar() {
|
|||||||
}
|
}
|
||||||
setListPath(newListPath)
|
setListPath(newListPath)
|
||||||
setListRank(newListRank)
|
setListRank(newListRank)
|
||||||
}, [defaultFilter])
|
}, [defaultFilter, setListPath, setListRank])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFilter({
|
setFilter({
|
||||||
@@ -72,7 +79,7 @@ export default function LightconeBar() {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListPath((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListPath({ ...listPath, [key]: !listPath[key] })
|
||||||
}}
|
}}
|
||||||
className="h-[38px] w-[38px] md:h-[50px] md:w-[50px] hover:bg-gray-600 grid place-items-center rounded-md shadow-lg cursor-pointer"
|
className="h-[38px] w-[38px] md:h-[50px] md:w-[50px] hover:bg-gray-600 grid place-items-center rounded-md shadow-lg cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
@@ -96,7 +103,7 @@ export default function LightconeBar() {
|
|||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setListRank((prev) => ({ ...prev, [key]: !prev[key] }))
|
setListRank({ ...listRank, [key]: !listRank[key] })
|
||||||
}}
|
}}
|
||||||
className="h-[38px] w-[38px] md:h-[50px] md:w-[50px] hover:bg-gray-600 grid place-items-center rounded-md shadow-lg cursor-pointer"
|
className="h-[38px] w-[38px] md:h-[50px] md:w-[50px] hover:bg-gray-600 grid place-items-center rounded-md shadow-lg cursor-pointer"
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useMemo } from "react";
|
|||||||
import useAvatarStore from "@/stores/avatarStore";
|
import useAvatarStore from "@/stores/avatarStore";
|
||||||
import { calcAffixBonus, calcBaseStatRaw, calcBonusStatRaw, calcMainAffixBonus, calcMainAffixBonusRaw, calcPromotion, calcSubAffixBonusRaw, replaceByParam } from "@/helper";
|
import { calcAffixBonus, calcBaseStatRaw, calcBonusStatRaw, calcMainAffixBonus, calcMainAffixBonusRaw, calcPromotion, calcSubAffixBonusRaw, replaceByParam } from "@/helper";
|
||||||
import { mappingStats } from "@/constant/constant";
|
import { mappingStats } from "@/constant/constant";
|
||||||
|
import RelicShowcase from "../showcaseCard/relicShowcase";
|
||||||
export default function QuickView() {
|
export default function QuickView() {
|
||||||
const { avatarSelected, mapAvatarInfo } = useAvatarStore()
|
const { avatarSelected, mapAvatarInfo } = useAvatarStore()
|
||||||
const { mapLightconeInfo } = useLightconeStore()
|
const { mapLightconeInfo } = useLightconeStore()
|
||||||
@@ -80,7 +81,9 @@ export default function QuickView() {
|
|||||||
return {
|
return {
|
||||||
property: subAffixMap?.[subValue?.sub_affix_id]?.property,
|
property: subAffixMap?.[subValue?.sub_affix_id]?.property,
|
||||||
valueAffix: calcAffixBonus(subAffixMap?.[subValue?.sub_affix_id], subValue?.step, subValue?.count),
|
valueAffix: calcAffixBonus(subAffixMap?.[subValue?.sub_affix_id], subValue?.step, subValue?.count),
|
||||||
detail: mappingStats?.[subAffixMap?.[subValue?.sub_affix_id]?.property]
|
detail: mappingStats?.[subAffixMap?.[subValue?.sub_affix_id]?.property],
|
||||||
|
step: subValue?.step,
|
||||||
|
count: subValue?.count
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -398,7 +401,7 @@ export default function QuickView() {
|
|||||||
<div key={index} className="flex flex-row items-center justify-between">
|
<div key={index} className="flex flex-row items-center justify-between">
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<NextImage src={stat?.icon || ""} alt="Stat Icon" width={40} height={40} className="h-auto w-10 p-1 mx-1 bg-black/20 rounded-full" />
|
<NextImage src={stat?.icon || ""} alt="Stat Icon" width={40} height={40} className="h-auto w-10 p-1 mx-1 bg-black/20 rounded-full" />
|
||||||
<span className="font-bold">{stat.name}</span>
|
<div className="font-bold">{stat.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 mr-3 flex-grow border rounded opacity-50" />
|
<div className="ml-3 mr-3 flex-grow border rounded opacity-50" />
|
||||||
<div className="flex cursor-default flex-col text-right font-bold">{
|
<div className="flex cursor-default flex-col text-right font-bold">{
|
||||||
@@ -439,63 +442,79 @@ export default function QuickView() {
|
|||||||
|
|
||||||
<div className="grid grid-cols-1 gap-2 justify-between py-3 text-lg">
|
<div className="grid grid-cols-1 gap-2 justify-between py-3 text-lg">
|
||||||
|
|
||||||
{relicStats?.map((relic, index) => {
|
{relicStats?.map((relic, index) => {
|
||||||
if (!relic) return null
|
if (!relic) return null
|
||||||
return (
|
return (
|
||||||
<div key={index} className="black-blur relative flex flex-row items-center rounded-lg border-2 p-1 border-yellow-600">
|
<div
|
||||||
<div className="flex">
|
key={index}
|
||||||
<NextImage src={relic?.img || ""} width={80} height={80} alt="Relic Icon" className="h-auto w-20" />
|
className="relative w-full flex flex-row items-center rounded-s-lg border-l-2 p-1 border-yellow-600/60 bg-gradient-to-r from-yellow-600/20 to-transparent"
|
||||||
|
>
|
||||||
|
{/* Subtle glow overlay */}
|
||||||
|
<div className="absolute inset-0 rounded-s-lg pointer-events-none"></div>
|
||||||
|
|
||||||
<div
|
<div className="flex relative">
|
||||||
className="absolute text-yellow-500 font-bold z-10"
|
<div className="absolute inset-0 rounded-lg blur-lg -z-10"></div>
|
||||||
style={{
|
<NextImage
|
||||||
left: '0.7rem',
|
src={relic?.img || ""}
|
||||||
bottom: '-0.5rem',
|
width={78}
|
||||||
fontSize: '1.1rem',
|
height={78}
|
||||||
letterSpacing: '-0.1em',
|
alt="Relic Icon"
|
||||||
textShadow: `
|
className="h-auto w-[78px] rounded-lg"
|
||||||
0 0 0.2em #f59e0b,
|
/>
|
||||||
0 0 0.4em #f59e0b,
|
|
||||||
0 0 0.8em #f59e0b,
|
<div
|
||||||
-0.05em -0.05em 0.05em rgba(0,0,0,0.7),
|
className="absolute text-yellow-400 font-bold z-10 drop-shadow-[0_0_6px_rgba(251,191,36,0.8)]"
|
||||||
0.05em 0.05em 0.05em rgba(0,0,0,0.7)
|
style={{
|
||||||
`
|
left: '0.65rem',
|
||||||
}}
|
bottom: '-0.45rem',
|
||||||
>
|
fontSize: '1.05rem',
|
||||||
✦✦✦✦✦
|
letterSpacing: '-0.1em',
|
||||||
</div>
|
}}
|
||||||
</div>
|
>
|
||||||
<div className="mx-1 flex w-1/6 flex-col items-center justify-center">
|
✦✦✦✦✦
|
||||||
<NextImage src={relic?.mainAffix?.detail?.icon || ""} width={36} height={36} alt="Main Affix Icon" className="h-auto w-9 bg-black/20 rounded-full" />
|
</div>
|
||||||
<span className="text-base text-[#f1a23c]">{relic?.mainAffix?.valueAffix + relic?.mainAffix?.detail?.unit}</span>
|
|
||||||
<span className="black-blur rounded px-1 text-xs">+{relic?.mainAffix?.level}</span>
|
|
||||||
</div>
|
|
||||||
<div style={{ opacity: 0.5, height: '80px', borderLeftWidth: '1px' }}></div>
|
|
||||||
<div className="m-auto grid w-1/2 grid-cols-2 gap-2">
|
|
||||||
{relic?.subAffix?.map((subAffix, index) => {
|
|
||||||
if (!subAffix) return null
|
|
||||||
return (
|
|
||||||
<div key={index} className="flex flex-col">
|
|
||||||
<div className="flex flex-row items-center">
|
|
||||||
{subAffix?.detail?.icon ? (
|
|
||||||
<NextImage src={subAffix?.detail?.icon || ""} width={36} height={36} alt="Sub Affix Icon" className="h-auto w-9 bg-black/20 rounded-full" />
|
|
||||||
) : (
|
|
||||||
<div className="h-9 w-9 bg-black/20 rounded flex items-center justify-center">
|
|
||||||
<span className="text-xs text-white">?</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span className="text-sm">+{subAffix?.valueAffix + subAffix?.detail?.unit}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className=" flex w-1/6 flex-col items-center justify-center">
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-0 bg-yellow-500/15 rounded-full blur-md -z-10"></div>
|
||||||
|
<NextImage
|
||||||
|
src={relic?.mainAffix?.detail?.icon || ""}
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
alt="Main Affix Icon"
|
||||||
|
className="h-auto w-[35px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="text-base text-yellow-400 font-semibold drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]">
|
||||||
|
{relic?.mainAffix?.valueAffix + relic?.mainAffix?.detail?.unit}
|
||||||
|
</span>
|
||||||
|
<span className="bg-black/20 backdrop-blur-sm rounded px-1.5 py-0.5 text-xs border border-white/10">
|
||||||
|
+{relic?.mainAffix?.level}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ opacity: 0.3, height: '78px', borderLeftWidth: '1px' }}></div>
|
||||||
|
|
||||||
|
<div className="grid w-[65%] m-2 grid-cols-2 gap-1">
|
||||||
|
{relic?.subAffix?.map((subAffix, index) => {
|
||||||
|
if (!subAffix) return null
|
||||||
|
return (
|
||||||
|
<RelicShowcase key={index} relic={relic} />
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{(!relicStats || !relicStats?.length) && <div className="flex flex-col items-center justify-center ">
|
|
||||||
<span className="text-lg">{transI18n("noRelicEquipped")}</span>
|
{(!relicStats || !relicStats?.length) && (
|
||||||
</div>}
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<div className="text-center p-6 rounded-lg bg-black/40 backdrop-blur-sm border border-white/10">
|
||||||
|
<span className="text-lg text-gray-400">{transI18n("noRelicEquipped")}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import { useTranslations } from 'next-intl';
|
|||||||
import useAffixStore from '@/stores/affixStore';
|
import useAffixStore from '@/stores/affixStore';
|
||||||
import useRelicStore from '@/stores/relicStore';
|
import useRelicStore from '@/stores/relicStore';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import RelicShowcase from './relicShowcase';
|
||||||
|
|
||||||
|
|
||||||
export default function ShowCaseInfo() {
|
export default function ShowCaseInfo() {
|
||||||
const { avatarSelected, mapAvatarInfo } = useAvatarStore()
|
const { avatarSelected, mapAvatarInfo } = useAvatarStore()
|
||||||
@@ -162,7 +164,9 @@ export default function ShowCaseInfo() {
|
|||||||
return {
|
return {
|
||||||
property: subAffixMap?.[subValue?.sub_affix_id]?.property,
|
property: subAffixMap?.[subValue?.sub_affix_id]?.property,
|
||||||
valueAffix: calcAffixBonus(subAffixMap?.[subValue?.sub_affix_id], subValue?.step, subValue?.count),
|
valueAffix: calcAffixBonus(subAffixMap?.[subValue?.sub_affix_id], subValue?.step, subValue?.count),
|
||||||
detail: mappingStats?.[subAffixMap?.[subValue?.sub_affix_id]?.property]
|
detail: mappingStats?.[subAffixMap?.[subValue?.sub_affix_id]?.property],
|
||||||
|
step: subValue?.step,
|
||||||
|
count: subValue?.count
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -495,7 +499,7 @@ export default function ShowCaseInfo() {
|
|||||||
}, [avatarSelected])
|
}, [avatarSelected])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-start m-2 text-white">
|
<div className="flex flex-col justify-start m-1 text-white">
|
||||||
<div className="flex items-center justify-start mt-4 mb-4">
|
<div className="flex items-center justify-start mt-4 mb-4">
|
||||||
<button className="btn btn-success w-24 text-sm" onClick={handleSaveImage}>Save Img</button>
|
<button className="btn btn-success w-24 text-sm" onClick={handleSaveImage}>Save Img</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -503,7 +507,7 @@ export default function ShowCaseInfo() {
|
|||||||
<div className="overflow-auto">
|
<div className="overflow-auto">
|
||||||
<div
|
<div
|
||||||
ref={cardRef}
|
ref={cardRef}
|
||||||
className=" relative min-h-[650px] w-[1400px] rounded-3xl transition-all duration-500"
|
className=" relative min-h-[650px] w-[1600px] rounded-3xl transition-all duration-500 overflow-hidden"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: `${applyBrightness(avgColor, 0.3)}`,
|
backgroundColor: `${applyBrightness(avgColor, 0.3)}`,
|
||||||
backdropFilter: "blur(50px)",
|
backdropFilter: "blur(50px)",
|
||||||
@@ -522,7 +526,7 @@ export default function ShowCaseInfo() {
|
|||||||
<NextImage
|
<NextImage
|
||||||
ref={imgRef}
|
ref={imgRef}
|
||||||
src={`https://api.hakush.in/hsr/UI/avatardrawcard/${avatarSelected?.id}.webp`}
|
src={`https://api.hakush.in/hsr/UI/avatardrawcard/${avatarSelected?.id}.webp`}
|
||||||
className="object-cover scale-[2]"
|
className="object-cover scale-[2] overflow-hidden"
|
||||||
alt="Character Preview"
|
alt="Character Preview"
|
||||||
width={1024}
|
width={1024}
|
||||||
height={1024}
|
height={1024}
|
||||||
@@ -607,7 +611,6 @@ export default function ShowCaseInfo() {
|
|||||||
{avatarData && avatarInfo && avatarSkillTree && traceShowCaseMap[avatarSelected?.baseType || ""]
|
{avatarData && avatarInfo && avatarSkillTree && traceShowCaseMap[avatarSelected?.baseType || ""]
|
||||||
&& Object.values(traceShowCaseMap[avatarSelected?.baseType || ""] || []).map((item, index) => {
|
&& Object.values(traceShowCaseMap[avatarSelected?.baseType || ""] || []).map((item, index) => {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`row-${index}`} className="flex flex-row items-center">
|
<div key={`row-${index}`} className="flex flex-row items-center">
|
||||||
{item.map((btn, idx) => {
|
{item.map((btn, idx) => {
|
||||||
@@ -803,7 +806,6 @@ export default function ShowCaseInfo() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Chỉ số */}
|
|
||||||
<div className="flex justify-center items-center flex-col gap-1 mt-1 ">
|
<div className="flex justify-center items-center flex-col gap-1 mt-1 ">
|
||||||
<div className="flex gap-1 text-sm ">
|
<div className="flex gap-1 text-sm ">
|
||||||
<div className="flex items-center gap-1 rounded bg-black/30 px-1 w-fit py-1">
|
<div className="flex items-center gap-1 rounded bg-black/30 px-1 w-fit py-1">
|
||||||
@@ -872,7 +874,7 @@ export default function ShowCaseInfo() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<span className="black-blur bg-black/50 flex w-5 justify-center rounded px-1.5 py-0.5">{setEffect.count}</span>
|
<span className="black-blur bg-black/30 flex w-5 justify-center rounded px-1.5 py-0.5">{setEffect.count}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -881,65 +883,22 @@ export default function ShowCaseInfo() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-1/3 z-10">
|
<div className="w-1/3 z-10">
|
||||||
<div className="flex h-[650px] flex-col justify-between py-3 text-lg">
|
<div className="flex h-[650px] flex-col justify-between py-3 mr-1 text-lg w-full" >
|
||||||
|
|
||||||
{relicStats?.map((relic, index) => {
|
{relicStats?.map((relic, index) => {
|
||||||
if (!relic) return null
|
if (!relic) return null
|
||||||
return (
|
return (
|
||||||
<div key={index} className="black-blur relative flex flex-row items-center rounded-s-lg border-l-2 p-1 border-yellow-600">
|
<RelicShowcase key={index} relic={relic} />
|
||||||
<div className="flex">
|
|
||||||
<NextImage src={relic?.img || ""} width={80} height={80} alt="Relic Icon" className="h-auto w-20" />
|
|
||||||
|
|
||||||
<div
|
|
||||||
className="absolute text-yellow-500 font-bold z-10"
|
|
||||||
style={{
|
|
||||||
left: '0.7rem',
|
|
||||||
bottom: '-0.5rem',
|
|
||||||
fontSize: '1.1rem',
|
|
||||||
letterSpacing: '-0.1em',
|
|
||||||
textShadow: `
|
|
||||||
0 0 0.2em #f59e0b,
|
|
||||||
0 0 0.4em #f59e0b,
|
|
||||||
0 0 0.8em #f59e0b,
|
|
||||||
-0.05em -0.05em 0.05em rgba(0,0,0,0.7),
|
|
||||||
0.05em 0.05em 0.05em rgba(0,0,0,0.7)
|
|
||||||
`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
✦✦✦✦✦
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mx-1 flex w-1/6 flex-col items-center justify-center">
|
|
||||||
<NextImage src={relic?.mainAffix?.detail?.icon || ""} width={36} height={36} alt="Main Affix Icon" className="h-auto w-9" />
|
|
||||||
<span className="text-base text-[#f1a23c]">{relic?.mainAffix?.valueAffix + relic?.mainAffix?.detail?.unit}</span>
|
|
||||||
<span className="black-blur rounded px-1 text-xs">+{relic?.mainAffix?.level}</span>
|
|
||||||
</div>
|
|
||||||
<div style={{ opacity: 0.5, height: '80px', borderLeftWidth: '1px' }}></div>
|
|
||||||
<div className="m-auto grid w-1/2 grid-cols-2 gap-2">
|
|
||||||
{relic?.subAffix?.map((subAffix, index) => {
|
|
||||||
if (!subAffix) return null
|
|
||||||
return (
|
|
||||||
<div key={index} className="flex flex-col">
|
|
||||||
<div className="flex flex-row items-center">
|
|
||||||
{subAffix?.detail?.icon ? (
|
|
||||||
<NextImage src={subAffix?.detail?.icon || ""} width={36} height={36} alt="Sub Affix Icon" className="h-auto w-9" />
|
|
||||||
) : (
|
|
||||||
<div className="h-9 w-9 bg-black/50 rounded flex items-center justify-center">
|
|
||||||
<span className="text-xs text-white">?</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span className="text-sm">+{subAffix?.valueAffix + subAffix?.detail?.unit}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{(!relicStats || !relicStats?.length) && <div className="flex flex-col items-center justify-center ">
|
|
||||||
<span className="text-lg">{transI18n("noRelicEquipped")}</span>
|
{(!relicStats || !relicStats?.length) && (
|
||||||
</div>}
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<div className="text-center p-6">
|
||||||
|
<span className="text-lg text-white">{transI18n("noRelicEquipped")}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
99
src/components/showcaseCard/relicShowcase.tsx
Normal file
99
src/components/showcaseCard/relicShowcase.tsx
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import NextImage from "next/image"
|
||||||
|
import { RelicShowcaseType } from "@/types";
|
||||||
|
|
||||||
|
export default function RelicShowcase({
|
||||||
|
relic,
|
||||||
|
}: {
|
||||||
|
relic: RelicShowcaseType;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="relative w-full flex flex-row items-center rounded-s-lg border-l-2 p-1 border-yellow-600/60 bg-gradient-to-r from-yellow-600/20 to-transparent"
|
||||||
|
>
|
||||||
|
{/* Subtle glow overlay */}
|
||||||
|
<div className="absolute inset-0 rounded-s-lg pointer-events-none"></div>
|
||||||
|
|
||||||
|
<div className="flex relative">
|
||||||
|
<div className="absolute inset-0 rounded-lg blur-lg -z-10"></div>
|
||||||
|
<NextImage
|
||||||
|
src={relic?.img || ""}
|
||||||
|
width={78}
|
||||||
|
height={78}
|
||||||
|
alt="Relic Icon"
|
||||||
|
className="h-auto w-[78px] rounded-lg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="absolute text-yellow-400 font-bold z-10 drop-shadow-[0_0_6px_rgba(251,191,36,0.8)]"
|
||||||
|
style={{
|
||||||
|
left: '0.65rem',
|
||||||
|
bottom: '-0.45rem',
|
||||||
|
fontSize: '1.05rem',
|
||||||
|
letterSpacing: '-0.1em',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
✦✦✦✦✦
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className=" flex w-1/6 flex-col items-center justify-center">
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute inset-0 bg-yellow-500/15 rounded-full blur-md -z-10"></div>
|
||||||
|
<NextImage
|
||||||
|
src={relic?.mainAffix?.detail?.icon || ""}
|
||||||
|
width={35}
|
||||||
|
height={35}
|
||||||
|
alt="Main Affix Icon"
|
||||||
|
className="h-auto w-[35px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="text-base text-yellow-400 font-semibold drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]">
|
||||||
|
{relic?.mainAffix?.valueAffix + relic?.mainAffix?.detail?.unit}
|
||||||
|
</span>
|
||||||
|
<span className="bg-black/20 backdrop-blur-sm rounded px-1.5 py-0.5 text-xs border border-white/10">
|
||||||
|
+{relic?.mainAffix?.level}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ opacity: 0.3, height: '78px', borderLeftWidth: '1px' }}></div>
|
||||||
|
|
||||||
|
<div className="grid w-[65%] m-2 grid-cols-2 gap-1">
|
||||||
|
{relic?.subAffix?.map((subAffix, index) => {
|
||||||
|
if (!subAffix) return null
|
||||||
|
return (
|
||||||
|
<div key={index} className="flex flex-col">
|
||||||
|
<div className="relative flex flex-row items-center bg-black/20 backdrop-blur-sm rounded-md p-1 border border-white/5 min-w-0">
|
||||||
|
{subAffix?.detail?.icon ? (
|
||||||
|
<NextImage
|
||||||
|
src={subAffix?.detail?.icon || ""}
|
||||||
|
width={32}
|
||||||
|
height={32}
|
||||||
|
alt="Sub Affix Icon"
|
||||||
|
className="h-auto w-6 flex-shrink-0"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="h-6 w-6 bg-black/60 rounded flex items-center justify-center border border-white/10 flex-shrink-0">
|
||||||
|
<span className="text-xs text-white/50">?</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<span className="text-xs text-gray-200 ml-0.5 truncate flex-1 min-w-0">
|
||||||
|
+{subAffix?.valueAffix + subAffix?.detail?.unit}
|
||||||
|
</span>
|
||||||
|
{subAffix.step > 1 && (
|
||||||
|
<span className="ml-1 bg-yellow-600/20 text-yellow-400 rounded-full px-1 py-0.5 text-[10px] font-semibold border border-yellow-600/30 flex-shrink-0 leading-none">
|
||||||
|
{subAffix?.step}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -9,6 +9,10 @@ interface AvatarState {
|
|||||||
avatarSelected: CharacterBasic | null;
|
avatarSelected: CharacterBasic | null;
|
||||||
mapAvatarInfo: Record<string, CharacterDetail>;
|
mapAvatarInfo: Record<string, CharacterDetail>;
|
||||||
skillSelected: string | null;
|
skillSelected: string | null;
|
||||||
|
listElement: Record<string, boolean>;
|
||||||
|
listPath: Record<string, boolean>;
|
||||||
|
setListElement: (newListElement: Record<string, boolean>) => void;
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => void;
|
||||||
setListAvatar: (newListAvatar: CharacterBasic[]) => void;
|
setListAvatar: (newListAvatar: CharacterBasic[]) => void;
|
||||||
setAvatarSelected: (newAvatarSelected: CharacterBasic) => void;
|
setAvatarSelected: (newAvatarSelected: CharacterBasic) => void;
|
||||||
setFilter: (newFilter: FilterAvatarType) => void;
|
setFilter: (newFilter: FilterAvatarType) => void;
|
||||||
@@ -30,6 +34,10 @@ const useAvatarStore = create<AvatarState>((set, get) => ({
|
|||||||
avatarSelected: null,
|
avatarSelected: null,
|
||||||
skillSelected: null,
|
skillSelected: null,
|
||||||
mapAvatarInfo: {},
|
mapAvatarInfo: {},
|
||||||
|
listElement: { "fire": false, "ice": false, "imaginary": false, "physical": false, "quantum": false, "thunder": false, "wind": false },
|
||||||
|
listPath: { "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false },
|
||||||
|
setListElement: (newListElement: Record<string, boolean>) => set({ listElement: newListElement }),
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => set({ listPath: newListPath }),
|
||||||
setSkillSelected: (newSkillSelected: string | null) => set({ skillSelected: newSkillSelected }),
|
setSkillSelected: (newSkillSelected: string | null) => set({ skillSelected: newSkillSelected }),
|
||||||
setListAvatar: (newListAvatar: CharacterBasic[]) => set({ listAvatar: newListAvatar, listRawAvatar: newListAvatar }),
|
setListAvatar: (newListAvatar: CharacterBasic[]) => set({ listAvatar: newListAvatar, listRawAvatar: newListAvatar }),
|
||||||
setAvatarSelected: (newAvatarSelected: CharacterBasic) => set({ avatarSelected: newAvatarSelected }),
|
setAvatarSelected: (newAvatarSelected: CharacterBasic) => set({ avatarSelected: newAvatarSelected }),
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ interface CopyProfileState {
|
|||||||
listRawCopyAvatar: CharacterBasic[];
|
listRawCopyAvatar: CharacterBasic[];
|
||||||
filterCopy: FilterAvatarType;
|
filterCopy: FilterAvatarType;
|
||||||
avatarCopySelected: CharacterBasic | null;
|
avatarCopySelected: CharacterBasic | null;
|
||||||
|
listElement: Record<string, boolean>;
|
||||||
|
listPath: Record<string, boolean>;
|
||||||
|
listRank: Record<string, boolean>;
|
||||||
|
setListElement: (newListElement: Record<string, boolean>) => void;
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => void;
|
||||||
|
setListRank: (newListRank: Record<string, boolean>) => void;
|
||||||
setSelectedProfiles: (newListAvatar: AvatarProfileCardType[]) => void;
|
setSelectedProfiles: (newListAvatar: AvatarProfileCardType[]) => void;
|
||||||
setAvatarCopySelected: (newAvatarSelected: CharacterBasic | null) => void;
|
setAvatarCopySelected: (newAvatarSelected: CharacterBasic | null) => void;
|
||||||
setFilterCopy: (newFilter: FilterAvatarType) => void;
|
setFilterCopy: (newFilter: FilterAvatarType) => void;
|
||||||
@@ -25,6 +31,12 @@ const useCopyProfileStore = create<CopyProfileState>((set, get) => ({
|
|||||||
locale: "",
|
locale: "",
|
||||||
},
|
},
|
||||||
avatarCopySelected: null,
|
avatarCopySelected: null,
|
||||||
|
listElement: { "fire": false, "ice": false, "imaginary": false, "physical": false, "quantum": false, "thunder": false, "wind": false },
|
||||||
|
listPath: { "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false },
|
||||||
|
listRank: { "4": false, "5": false },
|
||||||
|
setListElement: (newListElement: Record<string, boolean>) => set({ listElement: newListElement }),
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => set({ listPath: newListPath }),
|
||||||
|
setListRank: (newListRank: Record<string, boolean>) => set({ listRank: newListRank }),
|
||||||
setListCopyAvatar: (newListAvatar: CharacterBasic[]) => set({ listCopyAvatar: newListAvatar, listRawCopyAvatar: newListAvatar }),
|
setListCopyAvatar: (newListAvatar: CharacterBasic[]) => set({ listCopyAvatar: newListAvatar, listRawCopyAvatar: newListAvatar }),
|
||||||
setAvatarCopySelected: (newAvatarSelected: CharacterBasic | null) => set({ avatarCopySelected: newAvatarSelected }),
|
setAvatarCopySelected: (newAvatarSelected: CharacterBasic | null) => set({ avatarCopySelected: newAvatarSelected }),
|
||||||
setFilterCopy: (newFilter: FilterAvatarType) => {
|
setFilterCopy: (newFilter: FilterAvatarType) => {
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ import { create } from 'zustand'
|
|||||||
interface LightconeState {
|
interface LightconeState {
|
||||||
listLightcone: LightConeBasic[];
|
listLightcone: LightConeBasic[];
|
||||||
listRawLightcone: LightConeBasic[];
|
listRawLightcone: LightConeBasic[];
|
||||||
|
listPath: Record<string, boolean>;
|
||||||
|
listRank: Record<string, boolean>;
|
||||||
filter: FilterLightconeType;
|
filter: FilterLightconeType;
|
||||||
defaultFilter: { path: string[], rarity: string[] };
|
defaultFilter: { path: string[], rarity: string[] };
|
||||||
mapLightconeInfo: Record<string, LightConeDetail>;
|
mapLightconeInfo: Record<string, LightConeDetail>;
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => void;
|
||||||
|
setListRank: (newListRank: Record<string, boolean>) => void;
|
||||||
setDefaultFilter: (newDefaultFilter: { path: string[], rarity: string[] }) => void;
|
setDefaultFilter: (newDefaultFilter: { path: string[], rarity: string[] }) => void;
|
||||||
setListLightcone: (newListLightcone: LightConeBasic[]) => void;
|
setListLightcone: (newListLightcone: LightConeBasic[]) => void;
|
||||||
setFilter: (newFilter: FilterLightconeType) => void;
|
setFilter: (newFilter: FilterLightconeType) => void;
|
||||||
@@ -18,6 +22,7 @@ const useLightconeStore = create<LightconeState>((set, get) => ({
|
|||||||
listLightcone: [],
|
listLightcone: [],
|
||||||
listRawLightcone: [],
|
listRawLightcone: [],
|
||||||
mapLightconeInfo: {},
|
mapLightconeInfo: {},
|
||||||
|
|
||||||
filter: {
|
filter: {
|
||||||
name: "",
|
name: "",
|
||||||
path: [],
|
path: [],
|
||||||
@@ -25,6 +30,10 @@ const useLightconeStore = create<LightconeState>((set, get) => ({
|
|||||||
rarity: [],
|
rarity: [],
|
||||||
},
|
},
|
||||||
defaultFilter: { path: [], rarity: [] },
|
defaultFilter: { path: [], rarity: [] },
|
||||||
|
listPath: { "knight": false, "mage": false, "priest": false, "rogue": false, "shaman": false, "warlock": false, "warrior": false, "memory": false },
|
||||||
|
listRank: { "3": false, "4": false, "5": false },
|
||||||
|
setListPath: (newListPath: Record<string, boolean>) => set({ listPath: newListPath }),
|
||||||
|
setListRank: (newListRank: Record<string, boolean>) => set({ listRank: newListRank }),
|
||||||
setDefaultFilter: (newDefaultFilter: { path: string[], rarity: string[] }) => set({ defaultFilter: newDefaultFilter }),
|
setDefaultFilter: (newDefaultFilter: { path: string[], rarity: string[] }) => set({ defaultFilter: newDefaultFilter }),
|
||||||
setListLightcone: (newListLightcone: LightConeBasic[]) => set({ listLightcone: newListLightcone, listRawLightcone: newListLightcone }),
|
setListLightcone: (newListLightcone: LightConeBasic[]) => set({ listLightcone: newListLightcone, listRawLightcone: newListLightcone }),
|
||||||
setFilter: (newFilter: FilterLightconeType) => {
|
setFilter: (newFilter: FilterLightconeType) => {
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ export * from "./monsterValue"
|
|||||||
export * from "./peakDetail"
|
export * from "./peakDetail"
|
||||||
export * from "./monsterDetail"
|
export * from "./monsterDetail"
|
||||||
export * from "./extraData"
|
export * from "./extraData"
|
||||||
|
export * from "./showcase"
|
||||||
|
|||||||
26
src/types/showcase.tsx
Normal file
26
src/types/showcase.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
export type RelicShowcaseType = {
|
||||||
|
img: string;
|
||||||
|
mainAffix: {
|
||||||
|
property: string;
|
||||||
|
level: number;
|
||||||
|
valueAffix: string;
|
||||||
|
detail: {
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
unit: string;
|
||||||
|
baseStat: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
subAffix: {
|
||||||
|
property: string;
|
||||||
|
valueAffix: string;
|
||||||
|
detail: {
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
unit: string;
|
||||||
|
baseStat: string;
|
||||||
|
};
|
||||||
|
step: number;
|
||||||
|
count: number;
|
||||||
|
}[]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user