diff --git a/.gitmodules b/.gitmodules index b5c356217..a74aee594 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "docs/wiki"] path = docs/wiki url = https://github.com/Grasscutters/Grasscutter.wiki.git +[submodule "src/handbook/data/assets"] + path = src/handbook/data/assets + url = https://github.com/genshitters/gm-handbook-assets.git diff --git a/README.md b/README.md index 560e73b9a..cd56b9837 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Grasscutter uses Gradle to handle dependencies & building. ##### Windows ```shell -git clone https://github.com/Grasscutters/Grasscutter.git +git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git cd Grasscutter .\gradlew.bat # Setting up environments .\gradlew jar # Compile @@ -89,7 +89,7 @@ cd Grasscutter ##### Linux (GNU) ```bash -git clone https://github.com/Grasscutters/Grasscutter.git +git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git cd Grasscutter chmod +x gradlew ./gradlew jar # Compile diff --git a/src/handbook/.gitignore b/src/handbook/.gitignore index c74de08b8..e1c33ad6e 100644 --- a/src/handbook/.gitignore +++ b/src/handbook/.gitignore @@ -24,4 +24,4 @@ dist-ssr *.sw? # Handbook data -data/ +data/ \ No newline at end of file diff --git a/src/handbook/data/assets b/src/handbook/data/assets new file mode 160000 index 000000000..4b823697f --- /dev/null +++ b/src/handbook/data/assets @@ -0,0 +1 @@ +Subproject commit 4b823697f5a31312a03e20eb057a1a58e374df78 diff --git a/src/handbook/src/backend/files.d.ts b/src/handbook/src/backend/files.d.ts index 205989139..ac11472da 100644 --- a/src/handbook/src/backend/files.d.ts +++ b/src/handbook/src/backend/files.d.ts @@ -2,6 +2,11 @@ declare module "*.svg" { export const ReactComponent: React.FunctionComponent>; } +declare module "*.webp" { + const ref: string; + export default ref; +} + declare module "*.csv" { const content: any[]; export default content; diff --git a/src/handbook/src/css/App.scss b/src/handbook/src/css/App.scss index 668df9cef..ba120df98 100644 --- a/src/handbook/src/css/App.scss +++ b/src/handbook/src/css/App.scss @@ -1,3 +1,8 @@ +@font-face { + font-family: 'Poppins'; + src: url('/data/assets/Poppins-Regular.ttf') +} + html { --background-color: #346b77; --secondary-color: #418493; @@ -17,6 +22,7 @@ body { height: 100vh; width: 100%; overflow: hidden; + background-color: var(--background-color); #root { height: 100%; diff --git a/src/handbook/src/css/pages/AvatarsPage.scss b/src/handbook/src/css/pages/AvatarsPage.scss index 77ce01e18..810f66729 100644 --- a/src/handbook/src/css/pages/AvatarsPage.scss +++ b/src/handbook/src/css/pages/AvatarsPage.scss @@ -1,12 +1,13 @@ .AvatarsPage { display: flex; - height: 100%; - width: 100%; + width: calc(100% - 352px); background-color: var(--background-color); flex-direction: column; padding: 24px; + + overflow-y: scroll; } .AvatarsPage_Title { @@ -21,13 +22,10 @@ } .AvatarsPage_List { - display: grid; - gap: 15px 15px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 15px; max-width: 90%; - - grid-template-columns: repeat(12, 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 79b21f1e1..bd21b4adf 100644 --- a/src/handbook/src/css/pages/HomePage.scss +++ b/src/handbook/src/css/pages/HomePage.scss @@ -1,11 +1,15 @@ .HomePage { - display: flex; height: 100%; width: 100%; + overflow-y: scroll; + padding: 0; - background-color: var(--background-color); + display:flex; flex-direction: column; justify-content: space-between; + gap: 50px; + + background-color: var(--background-color); div { display: flex; @@ -15,7 +19,6 @@ .HomePage_Top { display: flex; width: 100%; - height: 80%; flex-direction: column; align-items: center; @@ -30,10 +33,8 @@ .HomePage_Buttons { width: 100%; - height: 40%; max-width: 1376px; - max-height: 256px; gap: 24px; justify-content: center; @@ -42,11 +43,9 @@ .HomePage_Bottom { display: flex; - - height: 50%; - max-height: 125px; flex-direction: row; justify-content: space-between; + margin-bottom: 50px; } .HomePage_Box { @@ -57,13 +56,11 @@ .HomePage_Disclaimer { display: flex; flex-direction: row; - justify-content: space-between; + gap: 30px; background-color: var(--secondary-color); - width: 50%; - height: 100%; - max-width: 630px; - max-height: 93px; + height: 100px; + align-self: end; margin: 0 0 0 60px; border-radius: 10px; @@ -71,29 +68,15 @@ box-sizing: border-box; padding: 11px; - :nth-child(1) { - font-size: 24px; - max-height: 30px; - - display: flex; - flex-direction: column; - } - p { - font-size: 18px; - max-height: 40px; + font-size: 16px; } } .HomePage_Discord { - display: flex; - flex-direction: row; - border-radius: 10px; - - max-height: 40px; max-width: 150px; - height: 100%; - width: 100%; + padding: 10px; + border-radius: 10px; gap: 8px; align-self: center; @@ -104,34 +87,26 @@ height: 100%; max-width: 44px; max-height: 30px; - - fill: #5865F2; } p { font-size: 16px; - max-width: 90px; } -} -.HomePage_Discord:hover { - cursor: pointer; - align-items: center; - justify-content: center; - - max-height: 50px; - max-width: 160px; - - background-color: #5865F2; + &:hover { + cursor: pointer; + background-color: #5865F2; + box-shadow: 0 0 10px 0 rgba(0,0,0,0.75); + } } .HomePage_Text { display: flex; flex-direction: column; + gap: 10px; background-color: var(--secondary-color); max-width: 300px; - max-height: 80px; margin: 13px 60px 0 0; border-radius: 10px; @@ -145,9 +120,6 @@ flex-direction: row; gap: 5px; - max-height: 18px; - padding-bottom: 5px; - :nth-child(1) { font-size: 18px; font-weight: bold; @@ -161,11 +133,15 @@ .HomePage_Links { display: flex; - flex-wrap: wrap; + flex-direction: column; a { color: var(--text-primary-color); text-decoration: none; padding-right: 10px; + + &:hover { + text-decoration: underline; + } } } diff --git a/src/handbook/src/css/pages/ItemsPage.scss b/src/handbook/src/css/pages/ItemsPage.scss index 3ef443681..2a4d77de5 100644 --- a/src/handbook/src/css/pages/ItemsPage.scss +++ b/src/handbook/src/css/pages/ItemsPage.scss @@ -72,11 +72,6 @@ } .ItemsPage_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/ScenesPage.scss b/src/handbook/src/css/pages/ScenesPage.scss index a40273722..1b3d63097 100644 --- a/src/handbook/src/css/pages/ScenesPage.scss +++ b/src/handbook/src/css/pages/ScenesPage.scss @@ -43,8 +43,14 @@ background-color: var(--background-color); user-select: none; + + transition: 0.1s ease-in-out all; } .ScenesPage_Button:hover { cursor: pointer; } + +.ScenesPage_Button:active { + scale: 0.9; +} diff --git a/src/handbook/src/css/views/SideBar.scss b/src/handbook/src/css/views/SideBar.scss index 5a383939a..1c810663d 100644 --- a/src/handbook/src/css/views/SideBar.scss +++ b/src/handbook/src/css/views/SideBar.scss @@ -32,7 +32,6 @@ display: flex; flex-direction: column; - padding-left: 27px; gap: 15px; user-select: none; diff --git a/src/handbook/src/css/widgets/Card.scss b/src/handbook/src/css/widgets/Card.scss index 538b55f05..d68683797 100644 --- a/src/handbook/src/css/widgets/Card.scss +++ b/src/handbook/src/css/widgets/Card.scss @@ -5,7 +5,6 @@ width: 100%; max-width: 1510px; - max-height: 100px; border-radius: 15px; padding: 10px; @@ -42,9 +41,7 @@ .Card_Description { color: var(--text-primary-color); - - overflow-y: scroll; - max-height: 24px; + padding-bottom: 5px; } .Card_Button { diff --git a/src/handbook/src/css/widgets/Character.scss b/src/handbook/src/css/widgets/Character.scss index 975bd4d2e..323612b7b 100644 --- a/src/handbook/src/css/widgets/Character.scss +++ b/src/handbook/src/css/widgets/Character.scss @@ -3,7 +3,7 @@ flex-direction: column; max-width: 96px; - max-height: 125px; + max-height: 135px; border-radius: 15px; height: 100%; @@ -11,6 +11,12 @@ overflow: hidden; box-sizing: border-box; + + &:hover { + cursor: pointer; + transition: 0.1s ease-in-out all; + box-shadow: 0 0 10px 5px var(--accent-color); + } } .Character :hover { @@ -18,11 +24,8 @@ } .Character_Icon { - width: 100%; - height: 100%; - - max-width: 96px; - max-height: 96px; + width: 96px; + height: 96px; align-self: center; } @@ -35,7 +38,7 @@ background-color: var(--secondary-color); max-width: 100px; - height: 30px; + height: 40px; p { text-align: center; diff --git a/src/handbook/src/css/widgets/HomeButton.scss b/src/handbook/src/css/widgets/HomeButton.scss index 0b85cdfa6..4b64fcd93 100644 --- a/src/handbook/src/css/widgets/HomeButton.scss +++ b/src/handbook/src/css/widgets/HomeButton.scss @@ -1,11 +1,10 @@ .HomeButton { display: flex; flex-direction: column; + padding: 20px; - width: 100%; - height: 100%; - max-width: 256px; - max-height: 256px; + width: 196px; + height: 196px; background-color: var(--secondary-color); @@ -15,10 +14,24 @@ border-radius: 10px; user-select: none; + + &:hover { + cursor: pointer; + transition: 0.1s ease-in-out all; + box-shadow: 0 0 10px 5px var(--accent-color); + scale: 1.01; + } } .HomeButton:hover { cursor: pointer; + transition: 0.1s ease-in-out all; + + &:hover { + cursor: pointer; + box-shadow: 0 0 10px 5px var(--accent-color); + scale: 1.01; + } } .HomeButton_Icon { @@ -27,8 +40,6 @@ } .HomeButton_Label { - font-size: 34px; - line-height: 44px; + font-size: 30px; text-align: center; - font-style: normal; } diff --git a/src/handbook/src/css/widgets/MiniCard.scss b/src/handbook/src/css/widgets/MiniCard.scss index 80c6c6fe6..06199c5a2 100644 --- a/src/handbook/src/css/widgets/MiniCard.scss +++ b/src/handbook/src/css/widgets/MiniCard.scss @@ -6,6 +6,13 @@ overflow: hidden; justify-content: center; + + transition: 0.1s ease-in-out all; + + &:hover { + cursor: pointer; + filter: brightness(0.9); + } } .MiniCard_Background { diff --git a/src/handbook/src/css/widgets/ObjectCard.scss b/src/handbook/src/css/widgets/ObjectCard.scss index 98c41d71e..334d2132f 100644 --- a/src/handbook/src/css/widgets/ObjectCard.scss +++ b/src/handbook/src/css/widgets/ObjectCard.scss @@ -147,8 +147,14 @@ background-color: var(--secondary-color); user-select: none; + transition: 0.1s ease-in-out all; } .ObjectCard_Submit:hover { cursor: pointer; + scale: 1.05; +} + +.ObjectCard_Submit:active { + scale: 0.9; } diff --git a/src/handbook/src/css/widgets/SideBarButton.scss b/src/handbook/src/css/widgets/SideBarButton.scss index 7b43a5777..ef13c3cb3 100644 --- a/src/handbook/src/css/widgets/SideBarButton.scss +++ b/src/handbook/src/css/widgets/SideBarButton.scss @@ -3,14 +3,17 @@ flex-direction: row; gap: 15px; + padding-left: 27px; - width: 100%; height: 64px; - max-width: 300px; - max-height: 64px; align-items: center; - cursor: pointer; + + &:hover { + cursor: pointer; + transition: 0.1s ease-in-out all; + backdrop-filter: brightness(0.9); + } } .SideBarButton_Icon { diff --git a/src/handbook/src/ui/components/TextState.tsx b/src/handbook/src/ui/components/TextState.tsx index b0d50af42..4bc0b32c6 100644 --- a/src/handbook/src/ui/components/TextState.tsx +++ b/src/handbook/src/ui/components/TextState.tsx @@ -3,6 +3,7 @@ import React from "react"; import emitter from "@backend/events"; interface IProps { + initial: boolean; event: string; text1: string; text2: string; diff --git a/src/handbook/src/ui/components/VirtualizedGrid.tsx b/src/handbook/src/ui/components/VirtualizedGrid.tsx index 631c53fc9..c1c07d438 100644 --- a/src/handbook/src/ui/components/VirtualizedGrid.tsx +++ b/src/handbook/src/ui/components/VirtualizedGrid.tsx @@ -21,6 +21,7 @@ interface IProps { interface IState { scrollTop: number; + itemsPerRow: number; } class VirtualizedGrid extends React.Component, IState> { @@ -28,7 +29,8 @@ class VirtualizedGrid extends React.Component, IState> { super(props); this.state = { - scrollTop: 0 + scrollTop: 0, + itemsPerRow: 10 }; } @@ -39,7 +41,7 @@ class VirtualizedGrid extends React.Component, IState> { const items: React.ReactNode[] = []; // Calculate the items to render. - const perRow = this.props.itemsPerRow ?? 10; + const perRow = this.state.itemsPerRow ?? 10; for (let i = 0; i < perRow; i++) { const itemIndex = props.index * perRow + i; if (itemIndex < this.props.list.length) { @@ -64,8 +66,20 @@ class VirtualizedGrid extends React.Component, IState> { ); } + componentDidMount() { + this.setState({ + itemsPerRow: Math.floor((window.innerWidth - 650) / (this.props.itemHeight + (this.props.gap ?? 0))) + }); + + window.addEventListener("resize", () => { + this.setState({ + itemsPerRow: Math.floor((window.innerWidth - 650) / (this.props.itemHeight + (this.props.gap ?? 0))) + }); + }); + } + render() { - const { list, itemHeight, itemsPerRow } = this.props; + const { list, itemHeight } = this.props; return ( @@ -74,7 +88,7 @@ class VirtualizedGrid extends React.Component, IState> { height={height - 150} width={width} rowHeight={itemHeight + (this.props.gap ?? 0)} - rowCount={Math.ceil(list.length / (itemsPerRow ?? 10))} + rowCount={Math.ceil(list.length / (this.state.itemsPerRow ?? 10))} rowRenderer={this.rowRender.bind(this)} scrollTop={this.state.scrollTop} onScroll={(e) => this.setState({ scrollTop: e.scrollTop })} diff --git a/src/handbook/src/ui/pages/CommandsPage.tsx b/src/handbook/src/ui/pages/CommandsPage.tsx index 6c5416ace..b63a0c2b4 100644 --- a/src/handbook/src/ui/pages/CommandsPage.tsx +++ b/src/handbook/src/ui/pages/CommandsPage.tsx @@ -21,7 +21,6 @@ class CommandsPage extends React.PureComponent { command.name.length == 1 ? undefined : `(aka /${command.name.slice(1).join(", /")})` } description={command.description} - height={75} /> ))} diff --git a/src/handbook/src/ui/pages/HomePage.tsx b/src/handbook/src/ui/pages/HomePage.tsx index 069ec32ae..6bf3625bf 100644 --- a/src/handbook/src/ui/pages/HomePage.tsx +++ b/src/handbook/src/ui/pages/HomePage.tsx @@ -4,6 +4,14 @@ import HomeButton from "@widgets/HomeButton"; import { ReactComponent as DiscordLogo } from "@icons/discord.svg"; +import Icon_Version_Highlights from "@assets/Icon_Version_Highlights.webp"; +import Icon_Character_Lumine from "@assets/Icon_Character_Lumine.webp"; +import Icon_Inventory from "@assets/Icon_Inventory.webp"; +import Icon_Tutorial_Monster from "@assets/Icon_Tutorial_Monster.webp"; +import Icon_Map from "@assets/Icon_Map.webp"; +import Icon_Quests from "@assets/Icon_Quests.webp"; +import Icon_Achievements from "@assets/Icon_Achievements.webp"; + import { openUrl } from "@app/utils"; import "@css/pages/HomePage.scss"; @@ -20,26 +28,25 @@ class HomePage extends React.Component {

Welcome back, Traveler~

- - - - - -
- -
- - + + + + + + +
-
-

This tool is not affiliated with HoYoverse.

-

Genshin Impact, game content and materials are

-

trademarks and copyrights of HoYoverse.

-
+

+ This tool is not affiliated with HoYoverse. +
+ Genshin Impact, game content and materials are +
+ trademarks and copyrights of HoYoverse. +

openUrl("https://discord.gg/grasscutter")}> diff --git a/src/handbook/src/ui/views/SideBar.tsx b/src/handbook/src/ui/views/SideBar.tsx index 7181acd92..565bea6e7 100644 --- a/src/handbook/src/ui/views/SideBar.tsx +++ b/src/handbook/src/ui/views/SideBar.tsx @@ -2,10 +2,18 @@ import React, { ChangeEvent } from "react"; import SideBarButton from "@app/ui/widgets/SideBarButton"; -import { navigate } from "@app/backend/events"; +import Icon_Version_Highlights from "@assets/Icon_Version_Highlights.webp"; +import Icon_Character_Lumine from "@assets/Icon_Character_Lumine.webp"; +import Icon_Inventory from "@assets/Icon_Inventory.webp"; +import Icon_Tutorial_Monster from "@assets/Icon_Tutorial_Monster.webp"; +import Icon_Map from "@assets/Icon_Map.webp"; +import Icon_Quests from "@assets/Icon_Quests.webp"; +import Icon_Achievements from "@assets/Icon_Achievements.webp"; + +import { navigate } from "@backend/events"; +import { setTargetPlayer } from "@backend/server"; import "@css/views/SideBar.scss"; -import { setTargetPlayer } from "@backend/server"; interface IState { uid: string | null; @@ -51,13 +59,13 @@ class SideBar extends React.Component<{}, IState> { }} >
- - - - - - - + + + + + + +
diff --git a/src/handbook/src/ui/widgets/Card.tsx b/src/handbook/src/ui/widgets/Card.tsx index c8308bbcd..4043215ba 100644 --- a/src/handbook/src/ui/widgets/Card.tsx +++ b/src/handbook/src/ui/widgets/Card.tsx @@ -28,7 +28,10 @@ class Card extends React.PureComponent { onClick={this.props.onClick} onMouseOver={this.props.onOver} onMouseOut={this.props.onOut} - style={{ height: this.props.height }} + style={{ + height: this.props.height, + cursor: this.props.onClick ? "pointer" : undefined + }} >
diff --git a/src/handbook/src/ui/widgets/Character.tsx b/src/handbook/src/ui/widgets/Character.tsx index 80784e1c7..7cb70250a 100644 --- a/src/handbook/src/ui/widgets/Character.tsx +++ b/src/handbook/src/ui/widgets/Character.tsx @@ -49,7 +49,7 @@ class Character extends React.PureComponent { />
-

= 12 ? 13 : 17 }}>{characterName}

+

= 10 ? 13 : 17 }}>{characterName}

); diff --git a/src/handbook/src/ui/widgets/HomeButton.tsx b/src/handbook/src/ui/widgets/HomeButton.tsx index dabc31563..3c07ecda8 100644 --- a/src/handbook/src/ui/widgets/HomeButton.tsx +++ b/src/handbook/src/ui/widgets/HomeButton.tsx @@ -7,6 +7,7 @@ import "@css/widgets/HomeButton.scss"; interface IProps { name: string; + icon: string; anchor: Page; } @@ -26,7 +27,7 @@ class HomeButton extends React.PureComponent { render() { return (
this.redirect()}> - {this.props.name} + {this.props.name}

{this.props.name}

diff --git a/src/handbook/src/ui/widgets/ItemCard.tsx b/src/handbook/src/ui/widgets/ItemCard.tsx index c54e7a226..3f7604c64 100644 --- a/src/handbook/src/ui/widgets/ItemCard.tsx +++ b/src/handbook/src/ui/widgets/ItemCard.tsx @@ -163,7 +163,7 @@ class ItemCard extends React.Component {
diff --git a/src/handbook/src/ui/widgets/MiniCard.tsx b/src/handbook/src/ui/widgets/MiniCard.tsx index a286e1530..1afda7a8a 100644 --- a/src/handbook/src/ui/widgets/MiniCard.tsx +++ b/src/handbook/src/ui/widgets/MiniCard.tsx @@ -19,6 +19,9 @@ interface IState { class MiniCard extends React.Component { loading: number | any; + + containerRef: React.RefObject; + textRef: React.RefObject; constructor(props: IProps) { super(props); @@ -28,6 +31,9 @@ class MiniCard extends React.Component { icon: true, loaded: false }; + + this.containerRef = React.createRef(); + this.textRef = React.createRef(); } /** @@ -42,8 +48,34 @@ class MiniCard extends React.Component { if (!this.state.loaded) this.replaceIcon(); } + /** + * Adjusts the font size of the text to fit the container. + * @private + */ + private adjustFontSize() { + const container = this.containerRef.current; + const text = this.textRef.current; + + if (!container || !text) { + return; + } + + const containerWidth = container.offsetWidth; + const textWidth = text.scrollWidth; + + const fontSize = parseFloat(window.getComputedStyle(text).fontSize); + const availableWidth = containerWidth - 10; + const scaleFactor = availableWidth / textWidth; + + if (scaleFactor < 1) { + const newFontSize = fontSize * scaleFactor; + text.style.fontSize = newFontSize + 'px'; + } + } + componentDidMount() { this.loading = setTimeout(this.forceReplace.bind(this), 1e3); + this.adjustFontSize(); } componentWillUnmount() { @@ -54,7 +86,7 @@ class MiniCard extends React.Component { render() { return (
-
+
{this.state.icon && ( { )} {(!this.state.loaded || !this.state.icon) && ( -

{this.props.data.name}

+

{this.props.data.name}

)}
diff --git a/src/handbook/src/ui/widgets/SideBarButton.tsx b/src/handbook/src/ui/widgets/SideBarButton.tsx index 5a16af4c5..9af875558 100644 --- a/src/handbook/src/ui/widgets/SideBarButton.tsx +++ b/src/handbook/src/ui/widgets/SideBarButton.tsx @@ -7,6 +7,7 @@ import "@css/widgets/SideBarButton.scss"; interface IProps { name: string; + icon: string; anchor: Page; } @@ -26,7 +27,7 @@ class SideBarButton extends React.PureComponent { render() { return (
this.redirect()}> - {this.props.name} + {this.props.name}

{this.props.name}

diff --git a/src/handbook/tsconfig.json b/src/handbook/tsconfig.json index f08be7441..f2c27fcd0 100644 --- a/src/handbook/tsconfig.json +++ b/src/handbook/tsconfig.json @@ -27,7 +27,8 @@ "@pages/*": ["src/ui/pages/*"], "@widgets/*": ["src/ui/widgets/*"], "@components/*": ["src/ui/components/*"], - "@data/*": ["data/*"] + "@data/*": ["data/*"], + "@assets/*": ["data/assets/*"] } }, "include": ["src"],