This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import useAvatarDataStore from "@/stores/avatarDataStore";
|
||||
import useBattleDataStore from "@/stores/battleDataStore";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import {attackTypeToString, AvatarHakushiType} from "@/types";
|
||||
import { attackTypeToString, CharacterBasic } from "@/types";
|
||||
import { SkillBattleInfo } from "@/types/mics";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
@@ -13,7 +13,7 @@ import NameAvatar from "../nameAvatar";
|
||||
|
||||
export default function ActionBar() {
|
||||
const [selectTurn, setSelectTurn] = useState<SkillBattleInfo | null>(null);
|
||||
const [selectAvatar, setSelectAvatar] = useState<AvatarHakushiType | null>(null);
|
||||
const [selectAvatar, setSelectAvatar] = useState<CharacterBasic | null>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const { skillHistory, turnHistory, cycleIndex, waveIndex, maxWave } = useBattleDataStore();
|
||||
const { listAvatar } = useAvatarDataStore();
|
||||
@@ -29,7 +29,7 @@ export default function ActionBar() {
|
||||
alignItems: 'center',
|
||||
};
|
||||
|
||||
const handleShow = (modalId: string, avatar: AvatarHakushiType, turn: SkillBattleInfo) => {
|
||||
const handleShow = (modalId: string, avatar: CharacterBasic, turn: SkillBattleInfo) => {
|
||||
const modal = document.getElementById(modalId) as HTMLDialogElement | null;
|
||||
if (modal) {
|
||||
setSelectAvatar(avatar);
|
||||
@@ -105,13 +105,13 @@ export default function ActionBar() {
|
||||
skillHistory.map((turn, index) => {
|
||||
const data = listAvatar.find(it => it.id === turn.avatarId.toString());
|
||||
if (!data) return null;
|
||||
const text = getNameChar(locale, data);
|
||||
const text = getNameChar(locale, transI18n, data);
|
||||
|
||||
return (
|
||||
<div key={index} className="h-full md:w-full">
|
||||
<div
|
||||
onClick={() => handleShow("action_detail_modal", data, turn)}
|
||||
className="h-full grid grid-cols-2 gap-2 border bg-base-100 w-full hover:bg-base-200 transition-colors duration-200 border-cyan-400 border-l-4 cursor-pointer min-w-[200px] sm:min-w-[250px] md:min-w-0"
|
||||
className="h-full grid grid-cols-2 gap-2 border bg-base-100 w-full hover:bg-base-200 transition-colors duration-200 border-cyan-400 border-l-4 cursor-pointer min-w-50 sm:min-w-62.5 md:min-w-0"
|
||||
>
|
||||
<div
|
||||
style={contentStyle}
|
||||
@@ -119,21 +119,23 @@ export default function ActionBar() {
|
||||
>
|
||||
<div className="avatar">
|
||||
<div className="w-12 h-12 rounded-full border-2 flex items-center justify-center bg-base-300 border-cyan-400 border-l-4">
|
||||
|
||||
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${data.id}.webp`}
|
||||
src={`${process.env.CDN_URL}/${data.icon}`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
alt={text}
|
||||
width={32}
|
||||
height={32}
|
||||
width={125}
|
||||
height={125}
|
||||
className="w-8 h-8 object-contain"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, data)}
|
||||
text={getNameChar(locale, transI18n, data)}
|
||||
className="text-base-content text-center text-sm mt-1 font-medium"
|
||||
/>
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 justify-center gap-2 py-2 w-full">
|
||||
<div className="bg-local text-primary text-xs max-w-full">
|
||||
@@ -195,15 +197,17 @@ export default function ActionBar() {
|
||||
<span className="font-medium text-base-content/70">{transI18n("character")}:</span>
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, selectAvatar)}
|
||||
text={getNameChar(locale, transI18n, selectAvatar)}
|
||||
className="font-bold"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-center items-center">
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${selectAvatar.id}.webp`}
|
||||
alt={getNameChar(locale, selectAvatar)}
|
||||
src={`${process.env.CDN_URL}/${selectAvatar?.icon}`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
alt={getNameChar(locale, transI18n, selectAvatar)}
|
||||
width={80}
|
||||
height={80}
|
||||
className="h-20 w-20 object-cover rounded-full border-2 border-purple-500 shadow-lg shadow-purple-500/20"
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
|
||||
import { getNameChar } from '@/helper';
|
||||
import useLocaleStore from '@/stores/localeStore';
|
||||
import { AvatarHakushiType } from '@/types';
|
||||
import { CharacterBasic } from '@/types';
|
||||
import NameAvatar from '../nameAvatar';
|
||||
import useBattleDataStore from '@/stores/battleDataStore';
|
||||
import Image from 'next/image';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
interface CharacterCardProps {
|
||||
data: AvatarHakushiType
|
||||
data: CharacterBasic
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function CharacterCard({ data }: CharacterCardProps) {
|
||||
const { locale } = useLocaleStore();
|
||||
const text = getNameChar(locale, data)
|
||||
const { avatarDetail } = useBattleDataStore()
|
||||
const transI18n = useTranslations("DataAnalysisPage");
|
||||
const text = getNameChar(locale, transI18n, data)
|
||||
|
||||
return (
|
||||
<li className="z-10 flex flex-col w-28 items-center p-1 rounded-md shadow-lg bg-linear-to-b from-customStart to-customEnd transform transition-transform duration-300 hover:scale-105 m-1">
|
||||
@@ -31,21 +31,27 @@ export default function CharacterCard({ data }: CharacterCardProps) {
|
||||
<Image
|
||||
width={376}
|
||||
height={512}
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${data.id}.webp`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${data.icon}`}
|
||||
className="w-full h-full rounded-md object-cover"
|
||||
alt="ALT"
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
height={48}
|
||||
src={`https://api.hakush.in/hsr/UI/element/${data.damageType.toLowerCase()}.webp`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`/icon/${data.damageType.toLowerCase()}.webp`}
|
||||
className="absolute top-0 left-0 w-6 h-6"
|
||||
alt={data.damageType.toLowerCase()}
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
height={48}
|
||||
src={`https://api.hakush.in/hsr/UI/pathicon/${data.baseType.toLowerCase()}.webp`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`/icon/${data.baseType.toLowerCase()}.webp`}
|
||||
className="absolute top-0 right-0 w-6 h-6"
|
||||
alt={data.baseType.toLowerCase()}
|
||||
/>
|
||||
|
||||
@@ -24,14 +24,13 @@ export default function MultiCharLineChart() {
|
||||
const [mode, setMode] = useState<1 | 2>(2);
|
||||
const dataByAvatar = useDamageLinesForAll(mode);
|
||||
const avatarIds = Object.keys(dataByAvatar).map(Number);
|
||||
const { listAvatar } = useAvatarDataStore()
|
||||
const { mapAvatar } = useAvatarDataStore()
|
||||
const { locale } = useLocaleStore();
|
||||
const transI18n = useTranslations("DataAnalysisPage")
|
||||
|
||||
|
||||
const data = {
|
||||
datasets: avatarIds.map((id, idx) => ({
|
||||
label: getNameChar(locale, listAvatar.find(it => it.id == id.toString())),
|
||||
label: getNameChar(locale, transI18n, mapAvatar?.[id.toString()]),
|
||||
data: dataByAvatar[id].map(({ x, y }: { x: number; y: number }) => {
|
||||
return {
|
||||
x: x.toFixed(2),
|
||||
|
||||
@@ -48,17 +48,16 @@ const borderPalette = colorPalette.map((c) => c.replace('0.6', '1'));
|
||||
export default function DamagePerAvatarForAll() {
|
||||
const transI18n = useTranslations("DataAnalysisPage");
|
||||
const { lineup, skillHistory } = useBattleDataStore();
|
||||
const { listAvatar } = useAvatarDataStore();
|
||||
const { mapAvatar } = useAvatarDataStore();
|
||||
const { locale } = useLocaleStore();
|
||||
|
||||
const [mode, setMode] = useState<number>(2);
|
||||
|
||||
const avatarMap = lineup.map((avatar) => {
|
||||
const char = listAvatar.find(it => it.id === avatar.avatarId.toString());
|
||||
if (!char) return undefined;
|
||||
if (!mapAvatar?.[avatar.avatarId.toString()]) return undefined;
|
||||
return {
|
||||
avatarId: avatar.avatarId,
|
||||
avatarName: getNameChar(locale, char)
|
||||
avatarName: getNameChar(locale, transI18n, mapAvatar?.[avatar.avatarId.toString()])
|
||||
};
|
||||
}).filter(Boolean) as { avatarId: number, avatarName: string }[];
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@ export default function DamagePercentChartForAll() {
|
||||
const [mode, setMode] = useState<1 | 2>(1);
|
||||
const damageByAvatar = useDamagePercentPerAvatar();
|
||||
const damageByType = useDamagePercentByType();
|
||||
const { listAvatar } = useAvatarDataStore();
|
||||
const { mapAvatar } = useAvatarDataStore();
|
||||
const { locale } = useLocaleStore();
|
||||
const transI18n = useTranslations("DataAnalysisPage");
|
||||
|
||||
const chartData = {
|
||||
labels: (mode === 1
|
||||
? damageByAvatar.map(d =>
|
||||
getNameChar(locale, listAvatar.find(it => it.id == d.avatarId.toString()))
|
||||
getNameChar(locale, transI18n, mapAvatar?.[d.avatarId.toString()])
|
||||
)
|
||||
: damageByType.map(d => transI18n(d.type.toLowerCase()))
|
||||
),
|
||||
|
||||
@@ -10,7 +10,7 @@ import NameAvatar from "../nameAvatar";
|
||||
|
||||
export default function EnemyBar() {
|
||||
const { enemyDetail } = useBattleDataStore()
|
||||
const { listEnemy } = useAvatarDataStore()
|
||||
const { mapEnemy } = useAvatarDataStore()
|
||||
const { locale } = useLocaleStore()
|
||||
|
||||
return (
|
||||
@@ -21,10 +21,12 @@ export default function EnemyBar() {
|
||||
<div key={uid} className="bg-base-200 rounded-lg p-3 border border-gray-700 w-52 shrink-0">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
{listEnemy.find((monster) => monster.child.includes(enemy.id))?.icon?.split("/")?.pop()?.replace(".png", "") && (
|
||||
{mapEnemy?.[enemy.id.toString()]?.icon && (
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/monstermiddleicon/${listEnemy.find((monster) => monster.child.includes(enemy.id))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`}
|
||||
src={`${process.env.CDN_URL}/${mapEnemy?.[enemy.id.toString()]?.icon}`}
|
||||
alt={enemy.name}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
width={40}
|
||||
height={40}
|
||||
className="object-cover w-10 h-10 rounded-lg"
|
||||
@@ -33,7 +35,7 @@ export default function EnemyBar() {
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<NameAvatar
|
||||
text={getNameEnemy(locale, listEnemy.find((monster) => monster.child.includes(enemy.id)))}
|
||||
text={getNameEnemy(locale, mapEnemy?.[enemy.id.toString()])}
|
||||
locale={locale}
|
||||
className="text-base font-semibold leading-tight truncate overflow-hidden"
|
||||
/>
|
||||
|
||||
@@ -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 { AvatarHakushiType } from "@/types";
|
||||
import { CharacterBasic } from "@/types";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import { getNameChar } from '@/helper/getNameChar';
|
||||
import SkillBarChart from "../chart/skillBarChart";
|
||||
@@ -18,12 +18,12 @@ import NameAvatar from "../nameAvatar";
|
||||
// import ShowCaseInfo from "../card/showCaseCard";
|
||||
|
||||
export default function LineupBar() {
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<AvatarHakushiType | undefined>(undefined);
|
||||
const [selectedCharacter, setSelectedCharacter] = useState<CharacterBasic | undefined>(undefined);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const transI18n = useTranslations("DataAnalysisPage");
|
||||
const { lineup, turnHistory, dataAvatar } = useBattleDataStore();
|
||||
const { listAvatar } = useAvatarDataStore();
|
||||
const { listAvatar, mapAvatar } = useAvatarDataStore();
|
||||
const { locale } = useLocaleStore();
|
||||
const totalDamage = useCalcTotalDmgAvatar(selectedCharacter ? Number(selectedCharacter.id) : 0);
|
||||
const totalTurn = useCalcTotalTurnAvatar(selectedCharacter ? Number(selectedCharacter.id) : 0)
|
||||
@@ -33,7 +33,7 @@ export default function LineupBar() {
|
||||
lineup.some(av => av.avatarId.toString() === item.id)
|
||||
);
|
||||
|
||||
const handleShow = (modalId: string, item: AvatarHakushiType) => {
|
||||
const handleShow = (modalId: string, item: CharacterBasic) => {
|
||||
const modal = document.getElementById(modalId) as HTMLDialogElement | null;
|
||||
if (modal) {
|
||||
setSelectedCharacter(item);
|
||||
@@ -81,16 +81,16 @@ export default function LineupBar() {
|
||||
<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 flex flex-row">
|
||||
<div>
|
||||
{transI18n("lastTurn")}:
|
||||
</div>
|
||||
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, listAvatar.find(it => it.id === turnHistory.findLast(i => i?.avatarId)?.avatarId?.toString()))}
|
||||
/>
|
||||
</span>
|
||||
<span className="text-sm truncate flex flex-row">
|
||||
<div>
|
||||
{transI18n("lastTurn")}:
|
||||
</div>
|
||||
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, transI18n, mapAvatar?.[turnHistory.findLast(i => i?.avatarId)?.avatarId?.toString() || ""])}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -142,10 +142,10 @@ export default function LineupBar() {
|
||||
</div>
|
||||
|
||||
<div className="border-b border-purple-500/30 px-6 py-4 mb-4">
|
||||
|
||||
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, selectedCharacter).toUpperCase()}
|
||||
text={getNameChar(locale, transI18n, selectedCharacter).toUpperCase()}
|
||||
className={"font-bold text-2xl text-transparent bg-clip-text bg-linear-to-r from-pink-400 to-cyan-400"}
|
||||
/>
|
||||
</div>
|
||||
@@ -170,8 +170,9 @@ export default function LineupBar() {
|
||||
<span className="font-bold">{transI18n(selectedCharacter.baseType.toLowerCase())}</span>
|
||||
{selectedCharacter.baseType && (
|
||||
<Image
|
||||
|
||||
src={`https://api.hakush.in/hsr/UI/pathicon/${selectedCharacter.baseType.toLowerCase()}.webp`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`/icon/${selectedCharacter.baseType.toLowerCase()}.webp`}
|
||||
className="w-6 h-6"
|
||||
alt={selectedCharacter.baseType.toLowerCase()}
|
||||
width={24}
|
||||
@@ -185,7 +186,9 @@ export default function LineupBar() {
|
||||
<p className="flex items-center space-x-2">
|
||||
<span>{transI18n("element")}:</span>
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/element/${selectedCharacter.damageType.toLowerCase()}.webp`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`/icon/${selectedCharacter.damageType.toLowerCase()}.webp`}
|
||||
className="w-6 h-6"
|
||||
alt={selectedCharacter.damageType.toLowerCase()}
|
||||
width={24}
|
||||
@@ -212,7 +215,9 @@ export default function LineupBar() {
|
||||
<div 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`}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/spriteoutput/lightconemediumicon/${avatar?.Lightcone?.item_id}.png`}
|
||||
className="w-12 h-12"
|
||||
alt={avatar?.Lightcone?.item_id?.toString() || ""}
|
||||
width={200}
|
||||
@@ -224,8 +229,10 @@ export default function LineupBar() {
|
||||
<div className="grid grid-cols-3 md:flex md:flex-row w-full">
|
||||
{relicIds.map(it => (
|
||||
<Image
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
key={it}
|
||||
src={`https://api.hakush.in/hsr/UI/relicfigures/IconRelic_${it}.webp`}
|
||||
src={`${process.env.CDN_URL}/spriteoutput/relicfigures/IconRelic_${it}.png`}
|
||||
className="w-12 h-12"
|
||||
alt={avatar?.Lightcone?.item_id?.toString() || ""}
|
||||
width={200}
|
||||
@@ -243,8 +250,10 @@ export default function LineupBar() {
|
||||
|
||||
</div>
|
||||
<Image
|
||||
src={`https://api.hakush.in/hsr/UI/avatarshopicon/${selectedCharacter.id}.webp`}
|
||||
alt={getNameChar(locale, selectedCharacter)}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${selectedCharacter.icon}`}
|
||||
alt={getNameChar(locale, transI18n, selectedCharacter)}
|
||||
className="h-32 w-32 object-cover rounded-full border-2 border-purple-500"
|
||||
width={128}
|
||||
height={128}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
import { createContext, PropsWithChildren, useEffect, useState } from "react";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import { createContext, PropsWithChildren, useEffect } from "react";
|
||||
|
||||
interface ThemeContextType {
|
||||
theme?: string;
|
||||
@@ -8,7 +9,7 @@ interface ThemeContextType {
|
||||
export const ThemeContext = createContext<ThemeContextType>({});
|
||||
|
||||
export const ThemeProvider = ({ children }: PropsWithChildren) => {
|
||||
const [theme, setTheme] = useState<string>("light");
|
||||
const { theme, setTheme } = useLocaleStore()
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -19,14 +20,13 @@ export const ThemeProvider = ({ children }: PropsWithChildren) => {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const changeTheme = (nextTheme: string | null) => {
|
||||
console.log(nextTheme)
|
||||
if (nextTheme) {
|
||||
setTheme(nextTheme);
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("theme", nextTheme);
|
||||
}
|
||||
} else {
|
||||
setTheme((prev) => (prev === "light" ? "night" : "light"));
|
||||
setTheme(theme === "winter" ? "night" : "winter");
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user