Gm handbook lmao (#2149)

* Fix font issue

* Fix avatars

* Fix text overflow in commands

* Fix virtualized lists and items page 😭😭

* magix why 💀

* use hover style in all minicards

* button

* remove console.log

* lint

* Add icons

* magix asked

* Fix overflow padding issue

* Fix achievement text overflow

* remove icons from repo

* Change command icon

* Add the wiki page as a submodule

* total magix moment

* fix text overflow in commands

* Fix discord button

* Make text scale on Minicard

* import icons and font from another source

* Add hover effects to siebar buttons

* move font and readme to submodule repo

* Make data folder a submodule

* import icons and font from data submodule

* Update README.md

* total magix moment

* magix moment v2

* submodule change

* Import `.webp` files

* Resize `HomeButton`

* Fix 'Copy Command' reappearing after changing pages

---------

Co-authored-by: KingRainbow44 <kobedo11@gmail.com>
This commit is contained in:
Scald 2023-05-15 13:25:44 +05:30 committed by GitHub
parent 964cc8143b
commit 4647d528e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 208 additions and 125 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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

View File

@ -24,4 +24,4 @@ dist-ssr
*.sw?
# Handbook data
data/
data/

@ -0,0 +1 @@
Subproject commit 4b823697f5a31312a03e20eb057a1a58e374df78

View File

@ -2,6 +2,11 @@ declare module "*.svg" {
export const ReactComponent: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
}
declare module "*.webp" {
const ref: string;
export default ref;
}
declare module "*.csv" {
const content: any[];
export default content;

View File

@ -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%;

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -72,11 +72,6 @@
}
.ItemsPage_List {
display: grid;
gap: 15px 15px;
grid-template-columns: repeat(15, 100px);
margin-bottom: 28px;
overflow-y: scroll;
}

View File

@ -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;
}

View File

@ -32,7 +32,6 @@
display: flex;
flex-direction: column;
padding-left: 27px;
gap: 15px;
user-select: none;

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -3,6 +3,7 @@ import React from "react";
import emitter from "@backend/events";
interface IProps {
initial: boolean;
event: string;
text1: string;
text2: string;

View File

@ -21,6 +21,7 @@ interface IProps<T> {
interface IState {
scrollTop: number;
itemsPerRow: number;
}
class VirtualizedGrid<T> extends React.Component<IProps<T>, IState> {
@ -28,7 +29,8 @@ class VirtualizedGrid<T> extends React.Component<IProps<T>, IState> {
super(props);
this.state = {
scrollTop: 0
scrollTop: 0,
itemsPerRow: 10
};
}
@ -39,7 +41,7 @@ class VirtualizedGrid<T> extends React.Component<IProps<T>, 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<T> extends React.Component<IProps<T>, 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 (
<AutoSizer>
@ -74,7 +88,7 @@ class VirtualizedGrid<T> extends React.Component<IProps<T>, 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 })}

View File

@ -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}
/>
))}
</div>

View File

@ -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<any, any> {
<h1 className={"HomePage_Title"}>Welcome back, Traveler~</h1>
<div className={"HomePage_Buttons"}>
<HomeButton name={"Commands"} anchor={"Commands"} />
<HomeButton name={"Characters"} anchor={"Avatars"} />
<HomeButton name={"Items"} anchor={"Items"} />
<HomeButton name={"Entities"} anchor={"Entities"} />
<HomeButton name={"Scenes"} anchor={"Scenes"} />
</div>
<div className={"HomePage_Buttons"}>
<HomeButton name={"Quests"} anchor={"Home"} />
<HomeButton name={"Achievements"} anchor={"Home"} />
<HomeButton name={"Commands"} anchor={"Commands"} icon={Icon_Version_Highlights} />
<HomeButton name={"Characters"} anchor={"Avatars"} icon={Icon_Character_Lumine} />
<HomeButton name={"Items"} anchor={"Items"} icon={Icon_Inventory} />
<HomeButton name={"Entities"} anchor={"Entities"} icon={Icon_Tutorial_Monster} />
<HomeButton name={"Scenes"} anchor={"Scenes"} icon={Icon_Map} />
<HomeButton name={"Quests"} anchor={"Home"} icon={Icon_Quests} />
<HomeButton name={"Achievements"} anchor={"Home"} icon={Icon_Achievements} />
</div>
</div>
<div className={"HomePage_Bottom"}>
<div className={"HomePage_Box HomePage_Disclaimer"}>
<div>
<p>This tool is not affiliated with HoYoverse.</p>
<p>Genshin Impact, game content and materials are</p>
<p>trademarks and copyrights of HoYoverse.</p>
</div>
<p>
<b>This tool is not affiliated with HoYoverse.</b>
<br />
Genshin Impact, game content and materials are
<br />
trademarks and copyrights of HoYoverse.
</p>
<div className={"HomePage_Discord"} onClick={() => openUrl("https://discord.gg/grasscutter")}>
<DiscordLogo />

View File

@ -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> {
}}
>
<div className={"SideBar_Buttons"}>
<SideBarButton name={"Commands"} anchor={"Commands"} />
<SideBarButton name={"Characters"} anchor={"Avatars"} />
<SideBarButton name={"Items"} anchor={"Items"} />
<SideBarButton name={"Entities"} anchor={"Entities"} />
<SideBarButton name={"Scenes"} anchor={"Scenes"} />
<SideBarButton name={"Quests"} anchor={"Home"} />
<SideBarButton name={"Achievements"} anchor={"Home"} />
<SideBarButton name={"Commands"} anchor={"Commands"} icon={Icon_Version_Highlights} />
<SideBarButton name={"Characters"} anchor={"Avatars"} icon={Icon_Character_Lumine} />
<SideBarButton name={"Items"} anchor={"Items"} icon={Icon_Inventory} />
<SideBarButton name={"Entities"} anchor={"Entities"} icon={Icon_Tutorial_Monster} />
<SideBarButton name={"Scenes"} anchor={"Scenes"} icon={Icon_Map} />
<SideBarButton name={"Quests"} anchor={"Home"} icon={Icon_Quests} />
<SideBarButton name={"Achievements"} anchor={"Home"} icon={Icon_Achievements} />
</div>
<div className={"SideBar_Enter"}>

View File

@ -28,7 +28,10 @@ class Card extends React.PureComponent<IProps> {
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
}}
>
<div className={"Card_Content"}>
<div className={"Card_Header"}>

View File

@ -49,7 +49,7 @@ class Character extends React.PureComponent<IProps> {
/>
<div className={"Character_Label"}>
<p style={{ fontSize: characterName.length >= 12 ? 13 : 17 }}>{characterName}</p>
<p style={{ fontSize: characterName.length >= 10 ? 13 : 17 }}>{characterName}</p>
</div>
</div>
);

View File

@ -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<IProps> {
render() {
return (
<div className={"HomeButton"} onClick={() => this.redirect()}>
<img className={"HomeButton_Icon"} src={"https://dummyimage.com/128x128"} alt={this.props.name} />
<img className={"HomeButton_Icon"} src={this.props.icon} alt={this.props.name} />
<p className={"HomeButton_Label"}>{this.props.name}</p>
</div>

View File

@ -163,7 +163,7 @@ class ItemCard extends React.Component<IProps, IState> {
</div>
<button className={"ObjectCard_Submit"} onClick={this.addToInventory.bind(this)}>
<TextState event={"connected"} text1={"Copy Command"} text2={"Add to Inventory"} />
<TextState initial={connected} event={"connected"} text1={"Copy Command"} text2={"Add to Inventory"} />
</button>
</div>
</div>

View File

@ -19,6 +19,9 @@ interface IState {
class MiniCard extends React.Component<IProps, IState> {
loading: number | any;
containerRef: React.RefObject<HTMLDivElement>;
textRef: React.RefObject<HTMLDivElement>;
constructor(props: IProps) {
super(props);
@ -28,6 +31,9 @@ class MiniCard extends React.Component<IProps, IState> {
icon: true,
loaded: false
};
this.containerRef = React.createRef();
this.textRef = React.createRef();
}
/**
@ -42,8 +48,34 @@ class MiniCard extends React.Component<IProps, IState> {
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<IProps, IState> {
render() {
return (
<div className={"MiniCard"} onClick={this.props.onClick}>
<div className={"MiniCard_Background"}>
<div className={"MiniCard_Background"} ref={this.containerRef}>
{this.state.icon && (
<img
className={"MiniCard_Icon"}
@ -66,7 +98,7 @@ class MiniCard extends React.Component<IProps, IState> {
)}
{(!this.state.loaded || !this.state.icon) && (
<p className={"MiniCard_Label"}>{this.props.data.name}</p>
<p className={"MiniCard_Label"} ref={this.textRef}>{this.props.data.name}</p>
)}
</div>
</div>

View File

@ -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<IProps> {
render() {
return (
<div className={"SideBarButton"} onClick={() => this.redirect()}>
<img className={"SideBarButton_Icon"} src={"https://dummyimage.com/128x128"} alt={this.props.name} />
<img className={"SideBarButton_Icon"} src={this.props.icon} alt={this.props.name} />
<p className={"SideBarButton_Label"}>{this.props.name}</p>
</div>

View File

@ -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"],