mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-09 12:32:56 +08:00
Add quest widgets
This commit is contained in:
parent
b6b9d3d744
commit
900d7fa200
@ -16,6 +16,9 @@
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.8.0",
|
||||
"react-d3-tree": "^3.6.1",
|
||||
"react-collapsible": "^2.10.0",
|
||||
"react-virtualized": "^9.22.3",
|
||||
|
||||
"events": "^3.3.0"
|
||||
|
@ -6,6 +6,8 @@ import scenes from "@data/scenes.csv";
|
||||
import quests from "@data/quests.csv";
|
||||
import items from "@data/items.csv";
|
||||
|
||||
import type { RawNodeDatum } from "react-d3-tree";
|
||||
|
||||
import { Quality, ItemType, ItemCategory, SceneType } from "@backend/types";
|
||||
import type { MainQuest, Command, Avatar, Item, Scene, Entity, Quest } from "@backend/types";
|
||||
|
||||
@ -209,3 +211,41 @@ export function listMainQuests(): MainQuestDump[] {
|
||||
export function getMainQuestFor(quest: Quest): MainQuest {
|
||||
return allMainQuests[quest.mainId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all quests for a main quest.
|
||||
*
|
||||
* @param mainQuest The main quest to fetch quests for.
|
||||
*/
|
||||
export function listSubQuestsFor(mainQuest: MainQuest): Quest[] {
|
||||
return listQuests()
|
||||
.filter((quest) => quest.mainId == mainQuest.id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tree conversion methods.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a quest to a tree.
|
||||
*
|
||||
* @param mainQuest The main quest to convert.
|
||||
*/
|
||||
export function questToTree(mainQuest: MainQuest): RawNodeDatum {
|
||||
return {
|
||||
name: mainQuest.title,
|
||||
attributes: {
|
||||
id: mainQuest.id
|
||||
},
|
||||
children: listSubQuestsFor(mainQuest)
|
||||
.map((quest) => {
|
||||
return {
|
||||
name: quest.id.toString(),
|
||||
attributes: {
|
||||
description: quest.description
|
||||
},
|
||||
children: []
|
||||
} as RawNodeDatum;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
54
src/handbook/src/css/widgets/quest/NormalQuest.scss
Normal file
54
src/handbook/src/css/widgets/quest/NormalQuest.scss
Normal file
@ -0,0 +1,54 @@
|
||||
.NormalQuest {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 431px;
|
||||
height: 100%;
|
||||
|
||||
min-width: 100px;
|
||||
min-height: 25px;
|
||||
max-height: 53px;
|
||||
|
||||
background-color: var(--quest-unselected);
|
||||
padding: 11px 20px 11px 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
p {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.NormalQuest[datatype="right"] {
|
||||
margin-left: auto;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.NormalQuest:hover {
|
||||
background-color: var(--quest-selected);
|
||||
|
||||
p {
|
||||
color: var(--qt-selected);
|
||||
}
|
||||
}
|
||||
|
||||
.NormalQuest_Info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:nth-child(1) {
|
||||
font-size: 16px;
|
||||
color: var(--qt-unselected);
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
font-size: 13px;
|
||||
color: var(--qt2-unselected);
|
||||
}
|
||||
}
|
||||
|
||||
.NormalQuest_Icon {
|
||||
font-size: 16px;
|
||||
color: var(--quest-accent);
|
||||
}
|
65
src/handbook/src/css/widgets/quest/PrimaryQuest.scss
Normal file
65
src/handbook/src/css/widgets/quest/PrimaryQuest.scss
Normal file
@ -0,0 +1,65 @@
|
||||
.PrimaryQuest {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: min-content;
|
||||
}
|
||||
|
||||
.PrimaryQuest_List {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
width: 97%;
|
||||
margin-left: auto;
|
||||
margin-right: 5px;
|
||||
|
||||
gap: 8px;
|
||||
padding: 8px 8px 8px 8px;
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
/* Trigger related CSS. */
|
||||
|
||||
.Trigger {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
gap: 10px;
|
||||
padding: 10px 10px 10px 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
width: 461px;
|
||||
height: 100%;
|
||||
min-width: 100px;
|
||||
min-height: 25px;
|
||||
max-height: 60px;
|
||||
|
||||
background-color: var(--pq-bg);
|
||||
|
||||
p {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.Trigger_Icon {
|
||||
font-size: 20px;
|
||||
padding-top: 5px;
|
||||
|
||||
color: var(--pq-text);
|
||||
}
|
||||
|
||||
.Trigger_Info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:nth-child(1) {
|
||||
font-size: 16px;
|
||||
color: var(--pq-text);
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
font-size: 14px;
|
||||
color: var(--pq-text2);
|
||||
}
|
||||
}
|
38
src/handbook/src/ui/widgets/quest/NormalQuest.tsx
Normal file
38
src/handbook/src/ui/widgets/quest/NormalQuest.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
|
||||
import { IoLocationSharp } from "react-icons/io5"
|
||||
|
||||
import type { Quest } from "@backend/types";
|
||||
|
||||
import "@css/widgets/quest/NormalQuest.scss";
|
||||
|
||||
interface IProps {
|
||||
quest: Quest;
|
||||
right?: boolean;
|
||||
}
|
||||
|
||||
class NormalQuest extends React.PureComponent<IProps> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { quest } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={"NormalQuest"}
|
||||
datatype={this.props.right ? "right" : "left"}
|
||||
>
|
||||
<div className={"NormalQuest_Info"}>
|
||||
<p className={"font-bold"}>{quest.description}</p>
|
||||
<p>ID: {quest.id} | Main: {quest.mainId}</p>
|
||||
</div>
|
||||
|
||||
<IoLocationSharp className={"NormalQuest_Icon"} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NormalQuest;
|
54
src/handbook/src/ui/widgets/quest/PrimaryQuest.tsx
Normal file
54
src/handbook/src/ui/widgets/quest/PrimaryQuest.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
|
||||
import { GiSupersonicArrow } from "react-icons/gi";
|
||||
|
||||
import Collapsible from "react-collapsible";
|
||||
import NormalQuest from "@widgets/quest/NormalQuest";
|
||||
|
||||
import type { MainQuest } from "@backend/types";
|
||||
import { listSubQuestsFor } from "@backend/data";
|
||||
|
||||
import "@css/widgets/quest/PrimaryQuest.scss";
|
||||
|
||||
interface IProps {
|
||||
quest: MainQuest;
|
||||
}
|
||||
|
||||
function Trigger(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<div className={"Trigger"}>
|
||||
<GiSupersonicArrow className={"Trigger_Icon"} />
|
||||
<div className={"Trigger_Info"}>
|
||||
<p className={"font-bold"}>{props.quest.title}</p>
|
||||
<p>ID: {props.quest.id}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
class PrimaryQuest extends React.PureComponent<IProps> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Collapsible
|
||||
className={"PrimaryQuest"}
|
||||
openedClassName={"PrimaryQuest"}
|
||||
trigger={<Trigger quest={this.props.quest} />}
|
||||
transitionTime={50}
|
||||
>
|
||||
<div className={"PrimaryQuest_List"}>
|
||||
{
|
||||
listSubQuestsFor(this.props.quest)
|
||||
.map((quest) => <NormalQuest
|
||||
key={quest.id} quest={quest} right />)
|
||||
}
|
||||
</div>
|
||||
</Collapsible>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PrimaryQuest;
|
Loading…
Reference in New Issue
Block a user