From 757d682cd68e04e006bacadddf4aa7fa9acb16cc Mon Sep 17 00:00:00 2001 From: KingRainbow44 Date: Thu, 6 Apr 2023 23:54:15 -0400 Subject: [PATCH] Implement avatars/characters page Handle edge-cases for avatar image rendering --- src/handbook/src/backend/data.ts | 7 ++++ src/handbook/src/backend/types.ts | 2 +- src/handbook/src/css/App.scss | 4 -- src/handbook/src/css/pages/AvatarsPage.scss | 31 +++++++++++++++ src/handbook/src/css/pages/HomePage.scss | 4 ++ src/handbook/src/css/widgets/Character.scss | 12 +++--- src/handbook/src/ui/pages/AvatarsPage.tsx | 28 ++++++++++++++ src/handbook/src/ui/pages/CommandsPage.tsx | 1 + src/handbook/src/ui/pages/HomePage.tsx | 2 +- src/handbook/src/ui/views/Content.tsx | 4 +- src/handbook/src/ui/views/SideBar.tsx | 2 +- src/handbook/src/ui/widgets/Character.tsx | 42 ++++++++++++++++++--- src/handbook/src/utils.ts | 17 +++++++++ 13 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 src/handbook/src/css/pages/AvatarsPage.scss create mode 100644 src/handbook/src/ui/pages/AvatarsPage.tsx create mode 100644 src/handbook/src/utils.ts diff --git a/src/handbook/src/backend/data.ts b/src/handbook/src/backend/data.ts index 0d4597e53..90d3a8bfb 100644 --- a/src/handbook/src/backend/data.ts +++ b/src/handbook/src/backend/data.ts @@ -40,6 +40,13 @@ export function getAvatars(): AvatarDump { return map; } +/** + * Fetches and lists all the avatars in the file. + */ +export function listAvatars(): Avatar[] { + return Object.values(getAvatars()); +} + /** * Fetches and casts all items in the file. */ diff --git a/src/handbook/src/backend/types.ts b/src/handbook/src/backend/types.ts index 35b9bc9c0..4ded0f43e 100644 --- a/src/handbook/src/backend/types.ts +++ b/src/handbook/src/backend/types.ts @@ -1,4 +1,4 @@ -export type Page = "Home" | "Commands"; +export type Page = "Home" | "Commands" | "Avatars"; export type Command = { name: string[]; diff --git a/src/handbook/src/css/App.scss b/src/handbook/src/css/App.scss index 9256bf764..668df9cef 100644 --- a/src/handbook/src/css/App.scss +++ b/src/handbook/src/css/App.scss @@ -38,10 +38,6 @@ body { width: 100%; height: 100%; - - div { - display: flex; - } } ::-webkit-scrollbar { diff --git a/src/handbook/src/css/pages/AvatarsPage.scss b/src/handbook/src/css/pages/AvatarsPage.scss new file mode 100644 index 000000000..a172e1cdf --- /dev/null +++ b/src/handbook/src/css/pages/AvatarsPage.scss @@ -0,0 +1,31 @@ +.AvatarsPage { + display: flex; + height: 100%; + width: 100%; + + background-color: var(--background-color); + flex-direction: column; + + padding: 24px; +} + +.AvatarsPage_Title { + max-width: 275px; + max-height: 60px; + + font-size: 48px; + font-weight: bold; + text-align: center; + + margin-bottom: 30px; +} + +.AvatarsPage_List { + display: grid; + gap: 15px 15px; + + grid-template-columns: repeat(15, 100px); + + margin-bottom: 28px; + overflow-y: scroll; +} diff --git a/src/handbook/src/css/pages/HomePage.scss b/src/handbook/src/css/pages/HomePage.scss index 0edc9ce17..ee2afacdc 100644 --- a/src/handbook/src/css/pages/HomePage.scss +++ b/src/handbook/src/css/pages/HomePage.scss @@ -6,6 +6,10 @@ background-color: var(--background-color); flex-direction: column; justify-content: space-between; + + div { + display: flex; + } } .HomePage_Top { diff --git a/src/handbook/src/css/widgets/Character.scss b/src/handbook/src/css/widgets/Character.scss index de1e75337..1a30cb049 100644 --- a/src/handbook/src/css/widgets/Character.scss +++ b/src/handbook/src/css/widgets/Character.scss @@ -2,12 +2,12 @@ display: flex; flex-direction: column; - background-color: var(--legendary-color); - max-width: 100px; - max-height: 125px; + max-height: 150px; border-radius: 15px; + height: 100%; + overflow: hidden; } @@ -20,15 +20,17 @@ } .Character_Label { + display: flex; align-items: center; justify-content: center; background-color: var(--secondary-color); max-width: 100px; - height: 25px; + height: 50px; p { - color: var(--text-primary-color); font-size: 18px; + text-align: center; + height: 100%; } } diff --git a/src/handbook/src/ui/pages/AvatarsPage.tsx b/src/handbook/src/ui/pages/AvatarsPage.tsx new file mode 100644 index 000000000..19445f951 --- /dev/null +++ b/src/handbook/src/ui/pages/AvatarsPage.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +import Character from "@app/ui/widgets/Character"; + +import { listAvatars } from "@backend/data"; + +import "@css/pages/AvatarsPage.scss"; + +class AvatarsPage extends React.PureComponent { + render() { + return ( +
+

Characters

+ +
+ { + listAvatars().map(avatar => ( + avatar.id > 11000000 ? undefined : + + )) + } +
+
+ ); + } +} + +export default AvatarsPage; diff --git a/src/handbook/src/ui/pages/CommandsPage.tsx b/src/handbook/src/ui/pages/CommandsPage.tsx index 78fcc9191..7901cd1dc 100644 --- a/src/handbook/src/ui/pages/CommandsPage.tsx +++ b/src/handbook/src/ui/pages/CommandsPage.tsx @@ -16,6 +16,7 @@ class CommandsPage extends React.PureComponent { { listCommands().map(command => ( {
- + diff --git a/src/handbook/src/ui/views/Content.tsx b/src/handbook/src/ui/views/Content.tsx index 3bf00b3a8..866ffa558 100644 --- a/src/handbook/src/ui/views/Content.tsx +++ b/src/handbook/src/ui/views/Content.tsx @@ -2,11 +2,12 @@ import React from "react"; import HomePage from "@pages/HomePage"; import CommandsPage from "@pages/CommandsPage"; +import AvatarsPage from "@pages/AvatarsPage"; import type { Page } from "@backend/types"; +import { addNavListener, removeNavListener } from "@backend/events"; import "@css/views/Content.scss"; -import { addNavListener, removeNavListener } from "@backend/events"; interface IProps { initial?: Page | null; @@ -48,6 +49,7 @@ class Content extends React.Component { default: return undefined; case "Home": return ; case "Commands": return ; + case "Avatars": return ; } } } diff --git a/src/handbook/src/ui/views/SideBar.tsx b/src/handbook/src/ui/views/SideBar.tsx index b1db7df7b..3b69f53f9 100644 --- a/src/handbook/src/ui/views/SideBar.tsx +++ b/src/handbook/src/ui/views/SideBar.tsx @@ -23,7 +23,7 @@ class SideBar extends React.Component {
- + diff --git a/src/handbook/src/ui/widgets/Character.tsx b/src/handbook/src/ui/widgets/Character.tsx index ae4da9a6b..92dc7500d 100644 --- a/src/handbook/src/ui/widgets/Character.tsx +++ b/src/handbook/src/ui/widgets/Character.tsx @@ -1,5 +1,8 @@ import React from "react"; +import type { Avatar } from "@backend/types"; +import { colorFor } from "@app/utils"; + import "@css/widgets/Character.scss"; // Image base URL: https://paimon.moe/images/characters/(name).png @@ -9,13 +12,30 @@ import "@css/widgets/Character.scss"; * Example: Hu Tao -> hu_tao * * @param name The character's name. + * @param id The character's ID. */ -function formatName(name: string): string { +function formatName(name: string, id: number): string { + // Check if a different name is used for the character. + if (refSwitch[id]) name = refSwitch[id]; return name.toLowerCase().replace(" ", "_"); } +const ignored = [ + 10000001 // Kate +]; + +const refSwitch: { [key: number]: string } = { + 10000005: "traveler_anemo", + 10000007: "traveler_geo", +}; + +const nameSwitch: { [key: number]: string } = { + 10000005: "Lumine", + 10000007: "Aether", +}; + interface IProps { - name: string; // paimon.moe reference name. + data: Avatar; } class Character extends React.PureComponent { @@ -24,16 +44,26 @@ class Character extends React.PureComponent { } render() { + const { name, quality, id } = this.props.data; + const qualityColor = colorFor(quality); + + // Check if the avatar is blacklisted. + if (ignored.includes(id)) + return undefined; + return ( -
+
{this.props.name}
-

{this.props.name}

+

{nameSwitch[id] ?? name}

); diff --git a/src/handbook/src/utils.ts b/src/handbook/src/utils.ts new file mode 100644 index 000000000..821538017 --- /dev/null +++ b/src/handbook/src/utils.ts @@ -0,0 +1,17 @@ +import { Quality } from "@backend/types"; + +/** + * Fetches the name of the CSS variable for the quality. + * + * @param quality The quality of the item. + */ +export function colorFor(quality: Quality): string { + switch (quality) { + default: return "--legendary-color"; + case "EPIC": return "--epic-color"; + case "RARE": return "--rare-color"; + case "UNCOMMON": return "--uncommon-color"; + case "COMMON": return "--common-color"; + case "UNKNOWN": return "--unknown-color"; + } +}