diff --git a/public/ff-sranalysis.ico b/public/ff-sranalysis.ico new file mode 100644 index 0000000..ba78eb0 Binary files /dev/null and b/public/ff-sranalysis.ico differ diff --git a/public/ff-sranalysis.png b/public/ff-sranalysis.png new file mode 100644 index 0000000..2fd9142 Binary files /dev/null and b/public/ff-sranalysis.png differ diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index b8133f5..0000000 Binary files a/src/app/favicon.ico and /dev/null differ diff --git a/src/app/icon.png b/src/app/icon.png deleted file mode 100644 index 02ef1c8..0000000 Binary files a/src/app/icon.png and /dev/null differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0af71de..cd71a6f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -21,7 +21,34 @@ const geistMono = Geist_Mono({ export const metadata: Metadata = { title: "Firefly Analytics", description: "Analytics tool for Veritas", -}; + icons: { + icon: "/ff-sranalysis.png", + shortcut: "/ff-sranalysis.ico", + apple: "/ff-sranalysis.png", + }, + openGraph: { + title: "Firefly Analytics", + description: "Analytics tool for Veritas", + url: "https://sranalysis.kain.id.vn", + siteName: "Firefly Analytics", + images: [ + { + url: "https://sranalysis.kain.id.vn/ff-sranalysis.png", + width: 1200, + height: 630, + alt: "Firefly Analytics Logo", + }, + ], + locale: "en_US", + type: "website", + }, + twitter: { + card: "summary_large_image", + title: "Firefly Analytics", + description: "Analytics tool for Veritas", + images: ["https://sranalysis.kain.id.vn/ff-sranalysis.png"], + }, + }; export default async function RootLayout({ children, diff --git a/src/app/page.tsx b/src/app/page.tsx index 4e71dfd..2af7d74 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,7 +3,7 @@ import { useTranslations } from "next-intl"; import { useEffect, useState } from "react"; import ActionBar from "@/components/actionbar"; import useAvatarDataStore from "@/stores/avatarDataStore"; -import { getCharacterListApi } from "@/lib/api"; +import { getCharacterListApi, getEnemyListApi } from "@/lib/api"; import LineupBar from "@/components/lineupbar"; import useBattleDataStore from "@/stores/battleDataStore"; import DamagePerAvatarForAll from "@/components/chart/damagePerAvatarForAll"; @@ -14,7 +14,7 @@ import EnemyBar from "@/components/enemybar"; export default function Home() { const transI18n = useTranslations("DataAnalysisPage"); - const { setListAvatar } = useAvatarDataStore(); + const { setListAvatar, setListEnemy } = useAvatarDataStore(); const { totalAV, totalDamage, @@ -36,9 +36,11 @@ export default function Home() { const fetchData = async () => { const data = await getCharacterListApi(); setListAvatar(data); + const enemyData = await getEnemyListApi(); + setListEnemy(enemyData); }; fetchData(); - }, [setListAvatar]); + }, [setListAvatar, setListEnemy]); useEffect(() => { window.dispatchEvent(new Event('resize')); diff --git a/src/components/enemybar/index.tsx b/src/components/enemybar/index.tsx index 61c6ea9..4945eae 100644 --- a/src/components/enemybar/index.tsx +++ b/src/components/enemybar/index.tsx @@ -2,15 +2,16 @@ import useBattleDataStore from "@/stores/battleDataStore"; import Image from "next/image"; +import useAvatarDataStore from "@/stores/avatarDataStore"; +import { getNameEnemy } from "@/helper/getNameChar"; -function formatEnemyIdForURL(id?: number): string { - const n = id ?? 0; - const adjusted = n.toString().length === 9 ? n / 100 : n; - return adjusted.toFixed(0); -} +import useLocaleStore from "@/stores/localeStore"; +import NameAvatar from "../nameAvatar"; export default function EnemyBar() { const { enemyDetail } = useBattleDataStore() + const { listEnemy } = useAvatarDataStore() + const { locale } = useLocaleStore() return (
@@ -21,16 +22,18 @@ export default function EnemyBar() {
monster.child.includes(enemy.id))?.icon?.split("/")?.pop()?.replace(".png", "")}.webp`} alt={enemy.name} width={40} height={40} className="object-cover w-10 h-10 rounded-lg" />
-

- {enemy.name} -

+ monster.child.includes(enemy.id)))} + locale={locale} + className="text-base font-semibold leading-tight truncate overflow-hidden" + />

Level {enemy.level || 1}

diff --git a/src/components/header/index.tsx b/src/components/header/index.tsx index c3d877e..3d43936 100644 --- a/src/components/header/index.tsx +++ b/src/components/header/index.tsx @@ -12,6 +12,7 @@ import { useTranslations } from "next-intl"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; +import Image from "next/image"; const themes = [ { label: "Winter" }, @@ -211,23 +212,28 @@ export default function Header() { {/* Logo */} -

- Firefly Analy - - sis - -

-

For Veritas

+
+ Logo +
+

+ Firefly Analy + + sis + +

+

For Veritas

+
+
{version && ( -
-
-
-
- {version} -
-
-
+
+
+
+
+ {version} +
+
+
)}
diff --git a/src/helper/getNameChar.ts b/src/helper/getNameChar.ts index 843038a..3cf0789 100644 --- a/src/helper/getNameChar.ts +++ b/src/helper/getNameChar.ts @@ -1,5 +1,5 @@ import { listCurrentLanguage } from "@/lib/constant"; -import { AvatarHakushiType } from "@/types"; +import { AvatarHakushiType, EnemyHakushiType } from "@/types"; export function getNameChar(locale: string, data: AvatarHakushiType | undefined): string { @@ -22,6 +22,21 @@ export function getNameChar(locale: string, data: AvatarHakushiType | undefined) return text } +export function getNameEnemy(locale: string, data: EnemyHakushiType | undefined): string { + if (!data) { + return "" + } + if (!listCurrentLanguage.hasOwnProperty(locale)) { + return "" + } + + let text = data.lang.get(listCurrentLanguage[locale as keyof typeof listCurrentLanguage].toLowerCase()) ?? ""; + if (!text) { + text = data.lang.get("en") ?? ""; + } + return text +} + export function parseRuby(text: string): string { const rubyRegex = /\{RUBY_B#(.*?)\}(.*?)\{RUBY_E#\}/gs; return text.replace(rubyRegex, (_match, furigana, kanji) => { diff --git a/src/lib/api.ts b/src/lib/api.ts index b854297..eb4baab 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -1,4 +1,5 @@ import useSocketStore from "@/stores/socketSettingStore"; +import { EnemyHakushiRawType, EnemyHakushiType } from "@/types"; import { AvatarHakushiType, AvatarHakushiRawType } from "@/types/avatar"; import axios from 'axios'; @@ -46,6 +47,29 @@ export async function getCharacterListApi(): Promise { } } +export async function getEnemyListApi(): Promise { + try { + const res = await axios.get>( + 'https://api.hakush.in/hsr/data/monster.json', + { + headers: { + 'Content-Type': 'application/json', + }, + } + ); + + const data = new Map(Object.entries(res.data)); + + return Array.from(data.entries()).map(([id, it]) => convertMonster(id, it)); + } catch (error: unknown) { + if (axios.isAxiosError(error)) { + console.log(`Error: ${error.response?.status} - ${error.message}`); + } else { + console.log(`Unexpected error: ${String(error)}`); + } + return []; + } +} function convertAvatar(id: string, item: AvatarHakushiRawType): AvatarHakushiType { const lang = new Map([ @@ -66,5 +90,26 @@ function convertAvatar(id: string, item: AvatarHakushiRawType): AvatarHakushiTyp id: id }; + return result; +} + +export function convertMonster(id: string, item: EnemyHakushiRawType): EnemyHakushiType { + const lang = new Map([ + ['en', item.en], + ['kr', item.kr], + ['cn', item.cn], + ['jp', item.jp] + ]); + const result: EnemyHakushiType = { + id: id, + rank: item.rank, + camp: item.camp, + icon: item.icon, + child: item.child, + weak: item.weak, + desc: item.desc, + lang: lang + }; + return result; } \ No newline at end of file diff --git a/src/stores/avatarDataStore.ts b/src/stores/avatarDataStore.ts index d5711e7..c643557 100644 --- a/src/stores/avatarDataStore.ts +++ b/src/stores/avatarDataStore.ts @@ -1,16 +1,19 @@ -import { AvatarHakushiType } from '@/types'; +import { AvatarHakushiType, EnemyHakushiType } from '@/types'; import { create } from 'zustand' interface AvatarDataState { listAvatar: AvatarHakushiType[]; + listEnemy: EnemyHakushiType[]; setListAvatar: (list: AvatarHakushiType[]) => void; + setListEnemy: (list: EnemyHakushiType[]) => void; } const useAvatarDataStore = create((set) => ({ listAvatar: [], + listEnemy: [], setListAvatar: (list: AvatarHakushiType[]) => set({ listAvatar: list }), - + setListEnemy: (list: EnemyHakushiType[]) => set({ listEnemy: list }), })); export default useAvatarDataStore; \ No newline at end of file diff --git a/src/stores/battleDataStore.ts b/src/stores/battleDataStore.ts index 56e9256..6bb4923 100644 --- a/src/stores/battleDataStore.ts +++ b/src/stores/battleDataStore.ts @@ -1,4 +1,4 @@ -import { DamageType, AvatarAnalysisJson, UseSkillType, BattleBeginType, BattleEndType, DamageDetailType, EntityDefeatedType, SetBattleLineupType, TurnBeginType, TurnEndType, UpdateCycleType, UpdateWaveType, VersionType, StatType, StatChangeType, UpdateTeamFormationType } from '@/types'; +import { DamageType, AvatarAnalysisJson, UseSkillType, BattleBeginType, BattleEndType, DamageDetailType, EntityDefeatedType, SetBattleLineupType, TurnBeginType, TurnEndType, UpdateCycleType, UpdateWaveType, VersionType, StatChangeType, UpdateTeamFormationType } from '@/types'; import { InitializeEnemyType } from '@/types/enemy'; import { AvatarBattleInfo, AvatarInfo, BattleDataStateJson, EnemyInfo, SkillBattleInfo, TurnBattleInfo } from '@/types/mics'; import { create } from 'zustand' diff --git a/src/types/enemy.ts b/src/types/enemy.ts index 785d2a5..49383bb 100644 --- a/src/types/enemy.ts +++ b/src/types/enemy.ts @@ -9,4 +9,28 @@ export interface EnemyType { export interface InitializeEnemyType { enemy: EnemyType -} \ No newline at end of file +} + +export interface EnemyHakushiRawType { + rank: string; + camp: string | null; + icon: string; + child: number[]; + weak: string[]; + en: string; + desc: string; + kr: string; + cn: string; + jp: string; +} + +export interface EnemyHakushiType { + id: string; + rank: string; + camp: string | null; + icon: string; + child: number[]; + weak: string[]; + desc: string; + lang: Map; +} diff --git a/src/types/index.ts b/src/types/index.ts index dbc8c09..f8674a5 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -9,3 +9,4 @@ export * from "./srtools" export * from "./version" export * from "./entity" export * from "./stat" +export * from "./enemy"