mirror of
https://github.com/exzork/gc-tools.git
synced 2024-11-27 01:55:48 +00:00
first
This commit is contained in:
parent
23d6ba1a11
commit
8c8e00b687
2
.gitignore
vendored
2
.gitignore
vendored
@ -11,6 +11,8 @@
|
|||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.env.local
|
.env.local
|
||||||
|
5
.idea/.gitignore
vendored
Normal file
5
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
7
.idea/discord.xml
Normal file
7
.idea/discord.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
12
.idea/gc-tools.iml
Normal file
12
.idea/gc-tools.iml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/gc-tools.iml" filepath="$PROJECT_DIR$/.idea/gc-tools.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
FROM node:16-slim
|
||||||
|
ADD . /booklist-react
|
||||||
|
WORKDIR /booklist-react
|
||||||
|
RUN npm install
|
||||||
|
RUN npm install -g serve
|
||||||
|
RUN npm run build
|
||||||
|
CMD ["npm","install","-g","serve"]
|
||||||
|
CMD ["serve", "-s", "build"]
|
||||||
|
EXPOSE 3000
|
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
exzork_booklist_react:
|
||||||
|
container_name: exzork_booklist_react
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- .:/booklist-react
|
||||||
|
- /booklist-react/node_modules
|
||||||
|
- /booklist-react/build
|
||||||
|
environment:
|
||||||
|
- VIRTUAL_HOST=booklist-react.exzork.me
|
||||||
|
- LETSENCRYPT_HOST=booklist-react.exzork.me
|
||||||
|
- LETSENCRYPT_EMAIL=muhammadeko.if@gmail.com
|
||||||
|
networks:
|
||||||
|
default :
|
||||||
|
name: nginx-proxy
|
888
package-lock.json
generated
888
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@ -3,6 +3,10 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.9.0",
|
||||||
|
"@emotion/styled": "^11.8.1",
|
||||||
|
"@mui/material": "^5.6.3",
|
||||||
|
"@tailwindcss/forms": "^0.5.0",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.1.1",
|
"@testing-library/react": "^13.1.1",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
@ -10,9 +14,17 @@
|
|||||||
"@types/node": "^16.11.32",
|
"@types/node": "^16.11.32",
|
||||||
"@types/react": "^18.0.8",
|
"@types/react": "^18.0.8",
|
||||||
"@types/react-dom": "^18.0.3",
|
"@types/react-dom": "^18.0.3",
|
||||||
|
"autoprefixer": "^10.4.5",
|
||||||
|
"axios": "^0.27.2",
|
||||||
|
"fs": "^0.0.1-security",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"postcss": "^8.4.12",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"react-select-search": "^3.0.9",
|
||||||
|
"tailwindcss": "^3.0.24",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
@ -39,5 +51,8 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.14.182"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
62
src/App.tsx
62
src/App.tsx
@ -1,26 +1,46 @@
|
|||||||
import React from 'react';
|
import React, {Component} from 'react';
|
||||||
import logo from './logo.svg';
|
import logo from './logo.svg';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
import Main from "./components/Main";
|
||||||
|
import {BrowserRouter} from "react-router-dom";
|
||||||
|
import Navbar from "./components/Navbar";
|
||||||
|
import Header from "./components/Header";
|
||||||
|
|
||||||
function App() {
|
interface IState{
|
||||||
return (
|
headerTitle: string;
|
||||||
<div className="App">
|
|
||||||
<header className="App-header">
|
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.tsx</code> and save to reload.
|
|
||||||
</p>
|
|
||||||
<a
|
|
||||||
className="App-link"
|
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Learn React
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default class App extends Component<{},IState>{
|
||||||
|
constructor(props:{}) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
headerTitle: 'Hello World'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHeaderTitleChange = (headerTitle:string) =>{
|
||||||
|
this.setState({
|
||||||
|
headerTitle: headerTitle
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const NavbarProps = {
|
||||||
|
headerTitle: this.state.headerTitle,
|
||||||
|
handleHeaderTitleChange: this.handleHeaderTitleChange
|
||||||
|
}
|
||||||
|
const HeaderProps = {
|
||||||
|
name: this.state.headerTitle,
|
||||||
|
}
|
||||||
|
const MainProps = {
|
||||||
|
handleHeaderTitleChange: this.handleHeaderTitleChange
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<BrowserRouter>
|
||||||
|
<Navbar {...NavbarProps}/>
|
||||||
|
<Header {...HeaderProps}/>
|
||||||
|
<Main {...MainProps}/>
|
||||||
|
</BrowserRouter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
11
src/components/Header.tsx
Normal file
11
src/components/Header.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export default function Header(props:{name:string}){
|
||||||
|
return (
|
||||||
|
<header className="bg-white shadow">
|
||||||
|
<div className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="text-xl md:text-3xl font-bold text-gray-900">{props.name}</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
19
src/components/Main.tsx
Normal file
19
src/components/Main.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from "react";
|
||||||
|
import RouteMenu from "./RouteMenu";
|
||||||
|
import {RouteProps} from "react-router-dom";
|
||||||
|
|
||||||
|
interface Props extends RouteProps{
|
||||||
|
handleHeaderTitleChange: (title: string) => void;
|
||||||
|
}
|
||||||
|
export default function Main(props: Props) {
|
||||||
|
const RouteMenuProps = {
|
||||||
|
handleHeaderTitleChange: props.handleHeaderTitleChange
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<main className="bg-gray-100 min-h-full">
|
||||||
|
<div className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8 ">
|
||||||
|
<RouteMenu {...RouteMenuProps}/>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
25
src/components/MenuDesktop.tsx
Normal file
25
src/components/MenuDesktop.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {useLocation, Link, useNavigate} from "react-router-dom"
|
||||||
|
export default function MenuDesktop(props:{handleHeaderTitleChange: (title:string) => void}) {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const {handleHeaderTitleChange} = props;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
{location.pathname === "/" ? (
|
||||||
|
<Link to="/" className="menu-item bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">Home</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/" onClick={() => handleHeaderTitleChange("Home")} className="menu-item text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Home</Link>
|
||||||
|
)}
|
||||||
|
*/
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{location.pathname === "/artifact" ? (
|
||||||
|
<Link to="/artifact" className="menu-item bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">Artifact</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/artifact" onClick={() => handleHeaderTitleChange("Artifact Command Generator")} className="menu-item text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Artifact</Link>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
25
src/components/MenuMobile.tsx
Normal file
25
src/components/MenuMobile.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {useLocation, Link} from "react-router-dom";
|
||||||
|
|
||||||
|
export default function MenuMobile(props: any) {
|
||||||
|
const location = useLocation();
|
||||||
|
const {handleHeaderTitleChange} = props;
|
||||||
|
|
||||||
|
/*
|
||||||
|
{location.pathname === "/" ? (
|
||||||
|
<Link to="/" className="menu-item block bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">Home</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/" onClick={() => handleHeaderTitleChange("Home")} className="menu-item block text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Home</Link>
|
||||||
|
)}
|
||||||
|
*/
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
{location.pathname === "/artifact" ? (
|
||||||
|
<Link to="/artifact" className="menu-item block bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium">Artifact</Link>
|
||||||
|
) : (
|
||||||
|
<Link to="/artifact" onClick={() => handleHeaderTitleChange("Artifact Command Generator")} className="menu-item block text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Artifact</Link>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
77
src/components/Navbar.tsx
Normal file
77
src/components/Navbar.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import React from "react";
|
||||||
|
import MenuDesktop from "./MenuDesktop";
|
||||||
|
import MenuMobile from "./MenuMobile";
|
||||||
|
|
||||||
|
class Navbar extends React.Component {
|
||||||
|
handleHeaderTitleChange;
|
||||||
|
toggleMobileMenu = () => {
|
||||||
|
const menuShow = document.querySelector(".menu-show");
|
||||||
|
const menuHide = document.querySelector(".menu-hide");
|
||||||
|
const mobileMenu = document.querySelector("#mobile-menu");
|
||||||
|
if (mobileMenu && menuHide && menuShow){
|
||||||
|
if (menuShow.classList.contains("block")) {
|
||||||
|
menuShow.classList.remove("block");
|
||||||
|
menuShow.classList.add("hidden");
|
||||||
|
menuHide.classList.remove("hidden");
|
||||||
|
menuHide.classList.add("block");
|
||||||
|
mobileMenu.classList.remove("hidden");
|
||||||
|
} else {
|
||||||
|
menuShow.classList.remove("hidden");
|
||||||
|
menuShow.classList.add("block");
|
||||||
|
menuHide.classList.remove("block");
|
||||||
|
menuHide.classList.add("hidden");
|
||||||
|
mobileMenu.classList.add("hidden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props:{handleHeaderTitleChange: (title:string) => void}) {
|
||||||
|
super(props);
|
||||||
|
const {handleHeaderTitleChange} = props;
|
||||||
|
|
||||||
|
this.handleHeaderTitleChange = handleHeaderTitleChange;
|
||||||
|
const pathname =window.location.pathname;
|
||||||
|
|
||||||
|
if(pathname==="/") handleHeaderTitleChange("Home")
|
||||||
|
else if(pathname==="/artifact") handleHeaderTitleChange("Artifact Command Generator")
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return(
|
||||||
|
<nav className="bg-gray-800">
|
||||||
|
<div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
|
||||||
|
<div className="relative flex items-center justify-between h-16">
|
||||||
|
<div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
|
||||||
|
{/* Mobile menu button */}
|
||||||
|
<button onClick={this.toggleMobileMenu} className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:bg-gray-700 focus:text-white transition duration-150 ease-in-out">
|
||||||
|
<svg className="menu-show block h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16"/>
|
||||||
|
</svg>
|
||||||
|
<svg className="menu-hide hidden h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
|
||||||
|
<div className="flex-shrink-0 flex items-center text-white text-lg">
|
||||||
|
Grasscutter Tools
|
||||||
|
</div>
|
||||||
|
<div className="hidden sm:block sm:ml-6 w-full">
|
||||||
|
<div className="flex w-full">
|
||||||
|
<MenuDesktop handleHeaderTitleChange={this.handleHeaderTitleChange}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="hidden sm:hidden" id="mobile-menu">
|
||||||
|
<div className="px-2 pt2 pb-3 space-y-1">
|
||||||
|
<MenuMobile handleHeaderTitleChange={this.handleHeaderTitleChange}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Navbar;
|
22
src/components/RouteMenu.tsx
Normal file
22
src/components/RouteMenu.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import {Routes, Route, RouteProps} from "react-router-dom";
|
||||||
|
import React from "react";
|
||||||
|
import Artifacts from "./pages/Artifacts";
|
||||||
|
|
||||||
|
interface RouteMenuProps extends RouteProps{
|
||||||
|
handleHeaderTitleChange: (title: string) => void;
|
||||||
|
}
|
||||||
|
export default function RouteMenu(props: RouteMenuProps) {
|
||||||
|
const defaultProps = {
|
||||||
|
handleHeaderTitleChange: props.handleHeaderTitleChange
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={
|
||||||
|
<div>Nothing Here</div>
|
||||||
|
}/>
|
||||||
|
<Route path="/artifact" element={
|
||||||
|
<Artifacts/>
|
||||||
|
}/>
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
}
|
189
src/components/pages/Artifacts.tsx
Normal file
189
src/components/pages/Artifacts.tsx
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import {ChangeEvent, useEffect, useState} from "react";
|
||||||
|
import ReliquaryDataProvider, {IReliquaryAffix, IReliquaryMain} from "../providers/ReliquaryDataProvider";
|
||||||
|
import {Autocomplete, Chip, createFilterOptions, TextField} from "@mui/material";
|
||||||
|
//@ts-ignore
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
interface IArtifact {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Artifacts() {
|
||||||
|
const [reliquaryMains, setReliquaryMains] = useState<IReliquaryMain[]>([]);
|
||||||
|
const [reliquaryAffixes, setReliquaryAffixes] = useState<IReliquaryAffix[]>([]);
|
||||||
|
const [uid, setUid] = useState(0);
|
||||||
|
const [selectedArtifact, setSelectedArtifact] = useState(0);
|
||||||
|
const [selectedMainStat, setSelectedMainStat] = useState(0);
|
||||||
|
const [selectedAffixes, setSelectedAffixes] = useState<number[]>([]);
|
||||||
|
const [selectedAffixesAmount, setSelectedAffixesAmount] = useState<Record<number, number>>({});
|
||||||
|
|
||||||
|
|
||||||
|
const [artifactData, setArtifactData] = useState<IArtifact[]>([]);
|
||||||
|
const [generatedArtifact, setGeneratedArtifact] = useState("/giveart ");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const dataArtifact: IArtifact[] = [];
|
||||||
|
const initReliquaryData = async () => {
|
||||||
|
await ReliquaryDataProvider.init();
|
||||||
|
setReliquaryMains(ReliquaryDataProvider.getReliquaryMains());
|
||||||
|
setReliquaryAffixes(ReliquaryDataProvider.getReliquaryAffixes());
|
||||||
|
};
|
||||||
|
fetch("https://gist.githubusercontent.com/exzork/0c5ab10f35f6aa718735380d8ce585db/raw/bc14a3f87f3a49aa053a43db999d04a8f09dcd71/GM%2520Handbook.txt")
|
||||||
|
.then(res => res.text())
|
||||||
|
.then(text => {
|
||||||
|
const lines = text.split("\n");
|
||||||
|
lines.forEach(line => {
|
||||||
|
const lineSplit = line.split(" : ");
|
||||||
|
if (lineSplit.length === 2) {
|
||||||
|
const id = parseInt(lineSplit[0]);
|
||||||
|
const name = lineSplit[1];
|
||||||
|
if ((id >= 23341 && id <= 30000) || (id >= 51110 && id <= 99554)) {
|
||||||
|
if (dataArtifact.filter((x) => x.name === lineSplit[1]).length === 0) {
|
||||||
|
dataArtifact.push({id: id, name: name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setArtifactData(dataArtifact);
|
||||||
|
initReliquaryData();
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleGeneratedArtifact()
|
||||||
|
}, [uid, selectedArtifact, selectedMainStat, selectedAffixes, selectedAffixesAmount]);
|
||||||
|
|
||||||
|
const handleArtifactChange = (event: any, value: any) => {
|
||||||
|
if (value !== null) {
|
||||||
|
setSelectedArtifact(value.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMainStatChange = (event: any, value: any) => {
|
||||||
|
if (value !== null) {
|
||||||
|
setSelectedMainStat(value.Id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAffixSelected = (event: ChangeEvent<HTMLInputElement>, amount = false, affixId=0) => {
|
||||||
|
let newSelectedAffixes = [...selectedAffixes];
|
||||||
|
let newSelectedAffixesAmount = {...selectedAffixesAmount};
|
||||||
|
if (amount) {
|
||||||
|
newSelectedAffixesAmount[affixId]=Number(event.target.value);
|
||||||
|
} else {
|
||||||
|
if (newSelectedAffixes.indexOf(Number(event.currentTarget.value)) === -1) {
|
||||||
|
newSelectedAffixes.push(Number(event.currentTarget.value));
|
||||||
|
newSelectedAffixesAmount[Number(event.currentTarget.value)] = 1;
|
||||||
|
} else {
|
||||||
|
newSelectedAffixes.splice(newSelectedAffixes.indexOf(Number(event.currentTarget.value)), 1);
|
||||||
|
newSelectedAffixesAmount[Number(event.currentTarget.value)] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSelectedAffixes(newSelectedAffixes);
|
||||||
|
setSelectedAffixesAmount(newSelectedAffixesAmount);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPercent = (affix:IReliquaryAffix)=>{
|
||||||
|
if (affix.PropType.indexOf("PERCENT") !== -1 || affix.PropType.indexOf("CRITICAL") !== -1 || affix.PropType.indexOf("EFFICIENCY") !== -1 || affix.PropType.indexOf("HURT") !== -1) {
|
||||||
|
return parseFloat(String(affix.PropValue*100)).toPrecision(3) + "%";
|
||||||
|
}
|
||||||
|
return parseInt(String(affix.PropValue));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleGeneratedArtifact = () => {
|
||||||
|
let selectedAffixesCombine: (string | number)[] = [];
|
||||||
|
if (selectedAffixes.length > 0) {
|
||||||
|
selectedAffixesCombine = selectedAffixes.map(x => {
|
||||||
|
if (selectedAffixesAmount[x] > 1) {
|
||||||
|
return x + "," + selectedAffixesAmount[x];
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const generated = "/giveart "+uid+" "+selectedArtifact+" "+selectedMainStat+" "+selectedAffixesCombine.join(" ")+" 21";
|
||||||
|
setGeneratedArtifact(generated);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form method="POST" className="space-y-8 divide-y divide-gray-200 bg-white p-10">
|
||||||
|
<div className="space-y-8 divide-y divide-gray-200 sm:space-y-5">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p className="mt-1 max-w-2xl text-sm text-gray-500">Please fill artifact details</p>
|
||||||
|
</div>
|
||||||
|
<div className="mt-6 sm:mt-5 space-y-6 sm:space-y-5">
|
||||||
|
<div
|
||||||
|
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||||
|
<label htmlFor="name"
|
||||||
|
className="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
|
||||||
|
UID
|
||||||
|
</label>
|
||||||
|
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||||
|
<input type="text" aria-label="UID" name="uid" id="uid" className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(event) => setUid(parseInt(event.target.value))}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||||
|
<label htmlFor="description"
|
||||||
|
className="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
|
||||||
|
Artifact Name
|
||||||
|
</label>
|
||||||
|
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||||
|
<Autocomplete
|
||||||
|
aria-label="Artifact Name" id="ArtifactName"
|
||||||
|
className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"
|
||||||
|
options={artifactData}
|
||||||
|
getOptionLabel={(option) => option.name}
|
||||||
|
onChange={handleArtifactChange}
|
||||||
|
renderInput={(params) => <TextField {...params} label="Artifact Name" variant="outlined"/>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||||
|
<label htmlFor="image"
|
||||||
|
className="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
|
||||||
|
Main Stats
|
||||||
|
</label>
|
||||||
|
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||||
|
<div
|
||||||
|
className="relative h-10 rounded-lg flex justify-center items-center">
|
||||||
|
<Autocomplete
|
||||||
|
aria-label="Artifact Main Stats" id="ArtifactMainStats"
|
||||||
|
className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md"
|
||||||
|
options={reliquaryMains}
|
||||||
|
getOptionLabel={(option) => option.PropType}
|
||||||
|
onChange={handleMainStatChange}
|
||||||
|
renderInput={(params) => <TextField {...params} label="Main Stats" variant="outlined"/>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||||
|
<label htmlFor="start_date"
|
||||||
|
className="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
|
||||||
|
Artifact Sub Stats
|
||||||
|
</label>
|
||||||
|
<div className="mt-1 sm:mt-0 sm:col-span-2 h-48 overflow-auto">
|
||||||
|
{reliquaryAffixes.map((affix, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} className="flex">
|
||||||
|
<input type="checkbox" className="mr-4 ml-4 focus:ring-indigo-500 h-4 w-4 mt-1 text-indigo-600 border-gray-300 rounded" value={affix.Id} id={"select-"+affix.Id} onChange={(e)=>handleAffixSelected(e,false,0)}/>
|
||||||
|
<label className="flex-grow" htmlFor={"select-"+affix.Id}>{affix.PropType +" - "+getPercent(affix)}</label>
|
||||||
|
<input type="number" defaultValue="1" min="1" className="flex-none block shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" onChange={(e)=>handleAffixSelected(e,true, affix.Id)}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="block sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
|
||||||
|
<input type="text" onClick={(e)=>{navigator.clipboard.writeText(e.currentTarget.value)}} className="block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm border-gray-300 rounded-md" value={generatedArtifact} readOnly/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
46
src/components/providers/ReliquaryDataProvider.ts
Normal file
46
src/components/providers/ReliquaryDataProvider.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
export interface IReliquaryMain {
|
||||||
|
Id: number;
|
||||||
|
PropDepotId: number;
|
||||||
|
PropType:string;
|
||||||
|
AffixName:string;
|
||||||
|
}
|
||||||
|
export interface IReliquaryAffix {
|
||||||
|
Id: number;
|
||||||
|
DepotId: number;
|
||||||
|
GroupId: number;
|
||||||
|
PropType:string;
|
||||||
|
PropValue:number;
|
||||||
|
}
|
||||||
|
export default class ReliquaryDataProvider {
|
||||||
|
private static reliquaryMains:IReliquaryMain[] = [];
|
||||||
|
private static reliquaryAffixes:IReliquaryAffix[] = [];
|
||||||
|
|
||||||
|
public static async init(){
|
||||||
|
await this.loadReliquaryMain();
|
||||||
|
await this.loadReliquaryAffixes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async loadReliquaryMain(){
|
||||||
|
let data = await fetch("https://raw.githubusercontent.com/Dimbreath/GenshinData/master/ExcelBinOutput/ReliquaryMainPropExcelConfigData.json");
|
||||||
|
let json:IReliquaryMain[] = await data.json();
|
||||||
|
this.reliquaryMains = [];
|
||||||
|
json.forEach(element => {
|
||||||
|
if (this.reliquaryMains.filter(x => x.PropType === element.PropType).length === 0)
|
||||||
|
this.reliquaryMains.push(element)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async loadReliquaryAffixes(){
|
||||||
|
let data = await fetch("https://raw.githubusercontent.com/Dimbreath/GenshinData/master/ExcelBinOutput/ReliquaryAffixExcelConfigData.json");
|
||||||
|
let json = await data.json();
|
||||||
|
this.reliquaryAffixes = json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getReliquaryMains():IReliquaryMain[]{
|
||||||
|
return this.reliquaryMains;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getReliquaryAffixes():IReliquaryAffix[]{
|
||||||
|
return this.reliquaryAffixes;
|
||||||
|
}
|
||||||
|
}
|
@ -11,3 +11,6 @@ code {
|
|||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./src/**/*.{js,jsx,ts,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/forms')
|
||||||
|
],
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user