diff --git a/.editorconfig b/.editorconfig index dcc46b748..1c7bcce3d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,5 +10,5 @@ max_line_length = 120 tab_width = 4 trim_trailing_whitespace = true -[{*.json,*.xml}] +[{*.json,*.xml,*.yml}] indent_size = 2 diff --git a/.github/workflows/handbook.yml b/.github/workflows/handbook.yml new file mode 100644 index 000000000..4497545fd --- /dev/null +++ b/.github/workflows/handbook.yml @@ -0,0 +1,82 @@ +name: "Handbook" + +on: + workflow_dispatch: ~ + push: + paths: + - "src/handbook/**.tsx" + branches: + - "development" + - "unstable" + pull_request: + paths: + - "src/handbook/**.tsx" + types: + - opened + - synchronize + - reopened + +jobs: + Lint-Code: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '17' + - name: Cache node modules + uses: actions/cache@v2 + with: + path: | + ~/.npm + ~/.cache + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Install dependencies + working-directory: src/handbook + run: npm install --force + - name: Run linter + working-directory: src/handbook + run: npm run lint + + - run: git config --global user.name "github-actions" + - run: git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + - name: Commit changes + if: ${{ github.event_name == 'push' }} + run: git add -u && git commit -m "Lint Code [skip actions]" || true + - name: Push changes + if: ${{ github.event_name == 'push' }} + run: git push --set-upstream --force origin ${{ github.ref }} + + Build-Handbook: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: '17' + - name: Cache node modules + uses: actions/cache@v2 + with: + path: | + ~/.npm + ~/.cache + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Install dependencies + working-directory: src/handbook + run: npm install --force + - name: Build handbook + working-directory: src/handbook + run: npm run build + - name: Upload build + uses: actions/upload-artifact@v3 + with: + name: Handbook + path: src/handbook/dist/*.html diff --git a/.gitignore b/.gitignore index eaf307905..0a2881741 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,9 @@ mongod.exe gacha-mapping.js mappings.js BuildConfig.java +data/hk4e/announcement/ + +src/main/resources/handbook.html # lombok /.apt_generated/ @@ -80,7 +83,6 @@ BuildConfig.java # macOS .DS_Store .directory -data/hk4e/announcement/ # Hotswap Agent hotswap-agent.properties diff --git a/src/handbook/.gitignore b/src/handbook/.gitignore new file mode 100644 index 000000000..c74de08b8 --- /dev/null +++ b/src/handbook/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Handbook data +data/ diff --git a/src/handbook/.prettierrc b/src/handbook/.prettierrc new file mode 100644 index 000000000..a370e477a --- /dev/null +++ b/src/handbook/.prettierrc @@ -0,0 +1,12 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "lf", + "jsxSingleQuote": false, + "jsxBracketSameLine": false, + "semi": true, + "singleQuote": false, + "tabWidth": 4, + "trailingComma": "none", + "useTabs": false +} \ No newline at end of file diff --git a/src/handbook/cfg/postcss.config.js b/src/handbook/cfg/postcss.config.js new file mode 100644 index 000000000..1962ca60c --- /dev/null +++ b/src/handbook/cfg/postcss.config.js @@ -0,0 +1,25 @@ +import tailwind from "tailwindcss"; +import autoprefixer from "autoprefixer"; +import cssnanoPlugin from "cssnano"; + +import tailwindConfig from "./tailwind.config.js"; +const mode = process.env.NODE_ENV; +const dev = mode === "development"; + +export default { + plugins: (() => { + let plugins = [ + // Some plugins, like TailwindCSS/Nesting, need to run before Tailwind. + tailwind(tailwindConfig), + + // But others, like autoprefixer, need to run after. + autoprefixer() + ]; + + !dev && cssnanoPlugin({ + preset: "default" + }); + + return plugins; + })() +} diff --git a/src/handbook/cfg/tailwind.config.js b/src/handbook/cfg/tailwind.config.js new file mode 100644 index 000000000..6a004f99f --- /dev/null +++ b/src/handbook/cfg/tailwind.config.js @@ -0,0 +1,9 @@ +export default { + content: ["./src/**/*.{html,js,tsx,ts}"], + mode: "jit", + theme: { + extend: {} + }, + darkMode: "class", + plugins: [] +}; diff --git a/src/handbook/data/README.md b/src/handbook/data/README.md new file mode 100644 index 000000000..cb7adf9eb --- /dev/null +++ b/src/handbook/data/README.md @@ -0,0 +1,32 @@ +# Handbook Data +Use Grasscutter's dumpers to generate the data to put here. + +## Files Required +- `commands.json` +- `entities.csv` +- `avatars.csv` +- `scenes.csv` +- `items.csv` + +# Item Icon Notes +- Artifacts: `https://bbs.hoyolab.com/hoyowiki/picture/reliquary/(name)/(piece)_icon.png` + - Alternate source: `https://api.ambr.top/assets/UI/reliquary/UI_RelicIcon_(set)_(piece).png` + - `xxxx4` - `flower_of_life` + - `xxxx5` - `sands_of_eon` + - `xxxx3` - `circlet_of_logos`/`plume_of_death` + - Use `circlet_of_logos` with a complete set + - Use `plume_of_death` with part of a set. + - `xxxx2` - `plume_of_death` + - `xxxx1` - `goblet_of_eonothem` +- Miscellaneous Items: `https://bbs.hoyolab.com/hoyowiki/picture/object/(name)_icon.png` + - Includes: materials, quest items, food, etc. + - Alternate source: `https://api.ambr.top/assets/UI/UI_ItemIcon_(id).png` +- Avatars/Avatar Items: `https://bbs.hoyolab.com/hoyowiki/picture/character/(name)_icon.png` + - Avatar Items are between ranges `1001` and `1099`. +- Weapons: `https://api.ambr.top/assets/UI/UI_EquipIcon_(type)_(name).png` +- Furniture: `https://api.ambr.top/assets/UI/furniture/UI_Homeworld_(location)_(name).png` +- Monsters: `https://api.ambr.top/assets/UI/monster/UI_MonsterIcon_(type)_(variant).png` + +# Credits +- [`...List.json` files](https://raw.githubusercontent.com/Dituon/grasscutter-command-helper/main/data/en-US) - Grasscutter Command Helper +- [Internal Asset API](https://ambr.top) - Project Amber diff --git a/src/handbook/index.html b/src/handbook/index.html new file mode 100644 index 000000000..4e84c88f2 --- /dev/null +++ b/src/handbook/index.html @@ -0,0 +1,12 @@ + + + + + + GM Handbook + + +
+ + + diff --git a/src/handbook/package-lock.json b/src/handbook/package-lock.json new file mode 100644 index 000000000..12186b8f7 --- /dev/null +++ b/src/handbook/package-lock.json @@ -0,0 +1,5847 @@ +{ + "name": "handbook", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "handbook", + "version": "0.1.0", + "hasInstallScript": true, + "dependencies": { + "events": "^3.3.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-virtualized": "^9.22.3" + }, + "devDependencies": { + "@rollup/plugin-dsv": "^3.0.2", + "@types/events": "^3.0.0", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-virtualized": "^9.21.21", + "@vitejs/plugin-react-swc": "^3.0.0", + "autoprefixer": "^10.4.13", + "cssnano": "^5.1.15", + "patch-package": "^6.5.1", + "postcss": "^8.4.21", + "postcss-font-magician": "^3.0.0", + "postcss-load-config": "^4.0.1", + "prettier": "^2.8.7", + "sass": "^1.58.3", + "tailwindcss": "^3.2.7", + "typescript": "^4.9.3", + "vite": "^4.2.0", + "vite-plugin-singlefile": "^0.13.5", + "vite-plugin-svgr": "^2.4.0", + "vite-tsconfig-paths": "^4.0.7" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.4", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.4", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.21.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.21.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.15", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-dsv": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/d3-dsv": "^3.0.0", + "d3-dsv": "2.0.0", + "tosource": "^2.0.0-alpha.3" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast/node_modules/entities": { + "version": "4.4.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "^6.0.0" + } + }, + "node_modules/@swc/core": { + "version": "1.3.44", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/events": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "dev": true, + "optional": true, + "peer": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.0.33", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-virtualized": { + "version": "9.21.21", + "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.21.tgz", + "integrity": "sha512-Exx6I7p4Qn+BBA1SRyj/UwQlZ0I0Pq7g7uhAp0QQ4JWzZunqEqNBGTmCmMmS/3N9wFgAGWuBD16ap7k8Y14VPA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/react": "^17" + } + }, + "node_modules/@types/react-virtualized/node_modules/@types/react": { + "version": "17.0.56", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.56.tgz", + "integrity": "sha512-Z13f9Qz7Hg8f2g2NsBjiJSVWmON2b3K8RIqFK8mMKCIgvD0CD0ZChTukz87H3lI28X3ukXoNFGzo3ZW1ICTtPA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.3.35" + }, + "peerDependencies": { + "vite": "^4" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/amdefine": { + "version": "1.0.1", + "dev": true, + "license": "BSD-3-Clause OR MIT", + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/b3b": { + "version": "0.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/bootstrap-fonts-complete": { + "version": "1.0.0", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "postcss": "^4.1.16" + } + }, + "node_modules/bootstrap-fonts-complete/node_modules/postcss": { + "version": "4.1.16", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "~2.3.0", + "js-base64": "~2.1.8", + "source-map": "~0.4.2" + } + }, + "node_modules/bootstrap-fonts-complete/node_modules/source-map": { + "version": "0.4.4", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brotli": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001473", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.4.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "dev": true, + "license": "MIT", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "license": "MIT" + }, + "node_modules/d3-dsv": { + "version": "2.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json", + "csv2tsv": "bin/dsv2dsv", + "dsv2dsv": "bin/dsv2dsv", + "dsv2json": "bin/dsv2json", + "json2csv": "bin/json2dsv", + "json2dsv": "bin/json2dsv", + "json2tsv": "bin/json2dsv", + "tsv2csv": "bin/dsv2dsv", + "tsv2json": "bin/dsv2json" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/directory-fonts-complete": { + "version": "1.2.0", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "brotli": "^1.3.2", + "is-eot": "^1.0.0", + "is-otf": "^0.1.1", + "is-ttf": "^0.2.1", + "is-woff": "^1.0.1", + "is-woff2": "^1.0.0" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.349", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "2.2.0", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es6-promise": { + "version": "2.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.17.15", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.15", + "@esbuild/android-arm64": "0.17.15", + "@esbuild/android-x64": "0.17.15", + "@esbuild/darwin-arm64": "0.17.15", + "@esbuild/darwin-x64": "0.17.15", + "@esbuild/freebsd-arm64": "0.17.15", + "@esbuild/freebsd-x64": "0.17.15", + "@esbuild/linux-arm": "0.17.15", + "@esbuild/linux-arm64": "0.17.15", + "@esbuild/linux-ia32": "0.17.15", + "@esbuild/linux-loong64": "0.17.15", + "@esbuild/linux-mips64el": "0.17.15", + "@esbuild/linux-ppc64": "0.17.15", + "@esbuild/linux-riscv64": "0.17.15", + "@esbuild/linux-s390x": "0.17.15", + "@esbuild/linux-x64": "0.17.15", + "@esbuild/netbsd-x64": "0.17.15", + "@esbuild/openbsd-x64": "0.17.15", + "@esbuild/sunos-x64": "0.17.15", + "@esbuild/win32-arm64": "0.17.15", + "@esbuild/win32-ia32": "0.17.15", + "@esbuild/win32-x64": "0.17.15" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/google-fonts-complete": { + "version": "2.1.1", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "postcss": "^7.0.18" + } + }, + "node_modules/google-fonts-complete/node_modules/picocolors": { + "version": "0.2.1", + "dev": true, + "license": "ISC" + }, + "node_modules/google-fonts-complete/node_modules/postcss": { + "version": "7.0.39", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-eot": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-otf": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "b3b": "0.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-ttf": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "b3b": "0.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-woff": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-woff2": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jiti": { + "version": "1.18.2", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-base64": { + "version": "2.1.9", + "dev": true, + "license": "BSD" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/mdn-data": { + "version": "2.0.14", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", + "dev": true, + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "cross-spawn": "^6.0.5", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "is-ci": "^2.0.0", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^5.6.0", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^1.10.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=10", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/patch-package/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/patch-package/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-font-magician": { + "version": "3.0.0", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "bootstrap-fonts-complete": "^1.0.0", + "directory-fonts-complete": "^1.2.0", + "google-fonts-complete": "^2.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.2.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier": { + "version": "2.8.7", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-virtualized": { + "version": "9.22.3", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", + "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha", + "react-dom": "^15.3.0 || ^16.0.0-alpha" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rollup": { + "version": "3.20.2", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.60.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/sucrase": { + "version": "3.31.0", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/svgo": { + "version": "2.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tosource": { + "version": "2.0.0-alpha.3", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsconfck": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^14.13.1 || ^16 || >=18" + }, + "peerDependencies": { + "typescript": "^4.3.5 || ^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "4.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.18.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-singlefile": { + "version": "0.13.5", + "dev": true, + "license": "MIT", + "dependencies": { + "micromatch": "^4.0.5" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "rollup": ">=2.79.0", + "vite": ">=3.2.0" + } + }, + "node_modules/vite-plugin-svgr": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.2", + "@svgr/core": "^6.5.1" + }, + "peerDependencies": { + "vite": "^2.6.0 || 3 || 4" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^2.1.0" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.21.4", + "dev": true + }, + "@babel/core": { + "version": "7.21.4", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.4", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/types": "^7.21.4", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.21.0", + "dev": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-imports": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/types": "^7.21.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.21.2", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" + } + }, + "@babel/helper-simple-access": { + "version": "7.20.2", + "dev": true, + "requires": { + "@babel/types": "^7.20.2" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.21.0", + "dev": true + }, + "@babel/helpers": { + "version": "7.21.0", + "dev": true, + "requires": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.21.4", + "dev": true + }, + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/template": { + "version": "7.20.7", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + } + }, + "@babel/traverse": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.21.4", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@esbuild/win32-x64": { + "version": "0.17.15", + "dev": true, + "optional": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-dsv": { + "version": "3.0.2", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/d3-dsv": "^3.0.0", + "d3-dsv": "2.0.0", + "tosource": "^2.0.0-alpha.3" + } + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, + "@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-attribute": { + "version": "7.0.0", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "7.0.0", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "dev": true, + "requires": {} + }, + "@svgr/babel-preset": { + "version": "6.5.1", + "dev": true, + "requires": { + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + } + }, + "@svgr/core": { + "version": "6.5.1", + "dev": true, + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + } + }, + "@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "dev": true, + "requires": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "dependencies": { + "entities": { + "version": "4.4.0", + "dev": true + } + } + }, + "@svgr/plugin-jsx": { + "version": "6.5.1", + "dev": true, + "requires": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + } + }, + "@swc/core": { + "version": "1.3.44", + "dev": true, + "requires": { + "@swc/core-darwin-arm64": "1.3.44", + "@swc/core-darwin-x64": "1.3.44", + "@swc/core-linux-arm-gnueabihf": "1.3.44", + "@swc/core-linux-arm64-gnu": "1.3.44", + "@swc/core-linux-arm64-musl": "1.3.44", + "@swc/core-linux-x64-gnu": "1.3.44", + "@swc/core-linux-x64-musl": "1.3.44", + "@swc/core-win32-arm64-msvc": "1.3.44", + "@swc/core-win32-ia32-msvc": "1.3.44", + "@swc/core-win32-x64-msvc": "1.3.44" + } + }, + "@swc/core-win32-x64-msvc": { + "version": "1.3.44", + "dev": true, + "optional": true + }, + "@trysound/sax": { + "version": "0.2.0", + "dev": true + }, + "@types/d3-dsv": { + "version": "3.0.1", + "dev": true + }, + "@types/estree": { + "version": "1.0.0", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "dev": true + }, + "@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "dev": true, + "optional": true, + "peer": true + }, + "@types/parse-json": { + "version": "4.0.0", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.5", + "dev": true + }, + "@types/react": { + "version": "18.0.33", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.11", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-virtualized": { + "version": "9.21.21", + "resolved": "https://registry.npmjs.org/@types/react-virtualized/-/react-virtualized-9.21.21.tgz", + "integrity": "sha512-Exx6I7p4Qn+BBA1SRyj/UwQlZ0I0Pq7g7uhAp0QQ4JWzZunqEqNBGTmCmMmS/3N9wFgAGWuBD16ap7k8Y14VPA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/react": "^17" + }, + "dependencies": { + "@types/react": { + "version": "17.0.56", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.56.tgz", + "integrity": "sha512-Z13f9Qz7Hg8f2g2NsBjiJSVWmON2b3K8RIqFK8mMKCIgvD0CD0ZChTukz87H3lI28X3ukXoNFGzo3ZW1ICTtPA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + } + } + }, + "@types/scheduler": { + "version": "0.16.3", + "dev": true + }, + "@vitejs/plugin-react-swc": { + "version": "3.2.0", + "dev": true, + "requires": { + "@swc/core": "^1.3.35" + } + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.2", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.14", + "dev": true, + "requires": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "b3b": { + "version": "0.0.1", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "dev": true + }, + "bootstrap-fonts-complete": { + "version": "1.0.0", + "dev": true, + "requires": { + "postcss": "^4.1.16" + }, + "dependencies": { + "postcss": { + "version": "4.1.16", + "dev": true, + "requires": { + "es6-promise": "~2.3.0", + "js-base64": "~2.1.8", + "source-map": "~0.4.2" + } + }, + "source-map": { + "version": "0.4.4", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brotli": { + "version": "1.3.3", + "dev": true, + "requires": { + "base64-js": "^1.1.2" + } + }, + "browserslist": { + "version": "4.21.5", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, + "callsites": { + "version": "3.1.0", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "dev": true + }, + "caniuse-api": { + "version": "3.0.0", + "dev": true, + "requires": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001473", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chokidar": { + "version": "3.5.3", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, + "color-convert": { + "version": "1.9.3", + "dev": true, + "requires": { + "color-name": "1.1.3" + }, + "dependencies": { + "color-name": { + "version": "1.1.3", + "dev": true + } + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "colord": { + "version": "2.9.3", + "dev": true + }, + "commander": { + "version": "7.2.0", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "dev": true + }, + "convert-source-map": { + "version": "1.9.0", + "dev": true + }, + "cosmiconfig": { + "version": "7.1.0", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "css-declaration-sorter": { + "version": "6.4.0", + "dev": true, + "requires": {} + }, + "css-select": { + "version": "4.3.0", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-tree": { + "version": "1.1.3", + "dev": true, + "requires": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + } + }, + "css-what": { + "version": "6.1.0", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "dev": true + }, + "cssnano": { + "version": "5.1.15", + "dev": true, + "requires": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + } + }, + "cssnano-preset-default": { + "version": "5.2.14", + "dev": true, + "requires": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + } + }, + "cssnano-utils": { + "version": "3.1.0", + "dev": true, + "requires": {} + }, + "csso": { + "version": "4.2.0", + "dev": true, + "requires": { + "css-tree": "^1.1.2" + } + }, + "csstype": { + "version": "3.1.2" + }, + "d3-dsv": { + "version": "2.0.0", + "dev": true, + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "didyoumean": { + "version": "1.2.2", + "dev": true + }, + "directory-fonts-complete": { + "version": "1.2.0", + "dev": true, + "requires": { + "brotli": "^1.3.2", + "is-eot": "^1.0.0", + "is-otf": "^0.1.1", + "is-ttf": "^0.2.1", + "is-woff": "^1.0.1", + "is-woff2": "^1.0.0" + } + }, + "dlv": { + "version": "1.1.3", + "dev": true + }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "1.4.1", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "electron-to-chromium": { + "version": "1.4.349", + "dev": true + }, + "entities": { + "version": "2.2.0", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-promise": { + "version": "2.3.0", + "dev": true + }, + "esbuild": { + "version": "0.17.15", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.17.15", + "@esbuild/android-arm64": "0.17.15", + "@esbuild/android-x64": "0.17.15", + "@esbuild/darwin-arm64": "0.17.15", + "@esbuild/darwin-x64": "0.17.15", + "@esbuild/freebsd-arm64": "0.17.15", + "@esbuild/freebsd-x64": "0.17.15", + "@esbuild/linux-arm": "0.17.15", + "@esbuild/linux-arm64": "0.17.15", + "@esbuild/linux-ia32": "0.17.15", + "@esbuild/linux-loong64": "0.17.15", + "@esbuild/linux-mips64el": "0.17.15", + "@esbuild/linux-ppc64": "0.17.15", + "@esbuild/linux-riscv64": "0.17.15", + "@esbuild/linux-s390x": "0.17.15", + "@esbuild/linux-x64": "0.17.15", + "@esbuild/netbsd-x64": "0.17.15", + "@esbuild/openbsd-x64": "0.17.15", + "@esbuild/sunos-x64": "0.17.15", + "@esbuild/win32-arm64": "0.17.15", + "@esbuild/win32-ia32": "0.17.15", + "@esbuild/win32-x64": "0.17.15" + } + }, + "escalade": { + "version": "3.1.1", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "dev": true + }, + "events": { + "version": "3.3.0" + }, + "fast-glob": { + "version": "3.2.12", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fastq": { + "version": "1.15.0", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "requires": { + "micromatch": "^4.0.2" + } + }, + "fraction.js": { + "version": "4.2.0", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "dev": true + }, + "glob": { + "version": "7.1.6", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "dev": true + }, + "globrex": { + "version": "0.1.2", + "dev": true + }, + "google-fonts-complete": { + "version": "2.1.1", + "dev": true, + "requires": { + "postcss": "^7.0.18" + }, + "dependencies": { + "picocolors": { + "version": "0.2.1", + "dev": true + }, + "postcss": { + "version": "7.0.39", + "dev": true, + "requires": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + } + } + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "immutable": { + "version": "4.3.0", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.11.0", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-eot": { + "version": "1.0.0", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "dev": true + }, + "is-otf": { + "version": "0.1.2", + "dev": true, + "requires": { + "b3b": "0.0.1" + } + }, + "is-ttf": { + "version": "0.2.2", + "dev": true, + "requires": { + "b3b": "0.0.1" + } + }, + "is-woff": { + "version": "1.0.3", + "dev": true + }, + "is-woff2": { + "version": "1.0.0", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jiti": { + "version": "1.18.2", + "dev": true + }, + "js-base64": { + "version": "2.1.9", + "dev": true + }, + "js-tokens": { + "version": "4.0.0" + }, + "jsesc": { + "version": "2.5.2", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true + }, + "json5": { + "version": "2.2.3", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11" + } + }, + "lilconfig": { + "version": "2.1.0", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "mdn-data": { + "version": "2.0.14", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "mz": { + "version": "2.7.0", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nanoid": { + "version": "3.3.6", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-releases": { + "version": "2.0.10", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1" + }, + "object-hash": { + "version": "3.0.0", + "dev": true + }, + "once": { + "version": "1.4.0", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "patch-package": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", + "dev": true, + "requires": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "cross-spawn": "^6.0.5", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "is-ci": "^2.0.0", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^5.6.0", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^1.10.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "dev": true + }, + "pify": { + "version": "2.3.0", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "dev": true + }, + "postcss": { + "version": "8.4.21", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-calc": { + "version": "8.2.4", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-colormin": { + "version": "5.3.1", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-convert-values": { + "version": "5.1.3", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-discard-comments": { + "version": "5.1.2", + "dev": true, + "requires": {} + }, + "postcss-discard-duplicates": { + "version": "5.1.0", + "dev": true, + "requires": {} + }, + "postcss-discard-empty": { + "version": "5.1.1", + "dev": true, + "requires": {} + }, + "postcss-discard-overridden": { + "version": "5.1.0", + "dev": true, + "requires": {} + }, + "postcss-font-magician": { + "version": "3.0.0", + "dev": true, + "requires": { + "bootstrap-fonts-complete": "^1.0.0", + "directory-fonts-complete": "^1.2.0", + "google-fonts-complete": "^2.1.1" + } + }, + "postcss-import": { + "version": "14.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-js": { + "version": "4.0.1", + "dev": true, + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "4.0.1", + "dev": true, + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "dependencies": { + "yaml": { + "version": "2.2.1", + "dev": true + } + } + }, + "postcss-merge-longhand": { + "version": "5.1.7", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + } + }, + "postcss-merge-rules": { + "version": "5.1.4", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-minify-font-values": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-gradients": { + "version": "5.1.1", + "dev": true, + "requires": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-params": { + "version": "5.1.4", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-minify-selectors": { + "version": "5.2.1", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-nested": { + "version": "6.0.0", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-normalize-charset": { + "version": "5.1.0", + "dev": true, + "requires": {} + }, + "postcss-normalize-display-values": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-positions": { + "version": "5.1.1", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-repeat-style": { + "version": "5.1.1", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-string": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-timing-functions": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-unicode": { + "version": "5.1.1", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-url": { + "version": "5.1.0", + "dev": true, + "requires": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-normalize-whitespace": { + "version": "5.1.1", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-ordered-values": { + "version": "5.1.3", + "dev": true, + "requires": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-reduce-initial": { + "version": "5.1.2", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + } + }, + "postcss-reduce-transforms": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.11", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-svgo": { + "version": "5.1.0", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + } + }, + "postcss-unique-selectors": { + "version": "5.1.1", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.5" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "dev": true + }, + "prettier": { + "version": "2.8.7", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "queue-microtask": { + "version": "1.2.3", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "dev": true + }, + "react": { + "version": "18.2.0", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-is": { + "version": "16.13.1" + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-virtualized": { + "version": "9.22.3", + "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.3.tgz", + "integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==", + "requires": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "read-cache": { + "version": "1.0.0", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "3.6.0", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "resolve": { + "version": "1.22.1", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "3.20.2", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rw": { + "version": "1.3.3", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "dev": true + }, + "sass": { + "version": "1.60.0", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "scheduler": { + "version": "0.23.0", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "6.3.0", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "dev": true + }, + "stable": { + "version": "0.1.8", + "dev": true + }, + "stylehacks": { + "version": "5.1.1", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + } + }, + "sucrase": { + "version": "3.31.0", + "dev": true, + "requires": { + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "dev": true + } + } + }, + "supports-color": { + "version": "5.5.0", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, + "svg-parser": { + "version": "2.0.4", + "dev": true + }, + "svgo": { + "version": "2.8.0", + "dev": true, + "requires": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + } + }, + "tailwindcss": { + "version": "3.3.1", + "dev": true, + "requires": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1", + "sucrase": "^3.29.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "postcss-load-config": { + "version": "3.1.4", + "dev": true, + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + } + } + } + }, + "thenify": { + "version": "3.3.1", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tosource": { + "version": "2.0.0-alpha.3", + "dev": true + }, + "ts-interface-checker": { + "version": "0.1.13", + "dev": true + }, + "tsconfck": { + "version": "2.1.1", + "dev": true, + "requires": {} + }, + "typescript": { + "version": "4.9.5", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.10", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "dev": true + }, + "vite": { + "version": "4.2.1", + "dev": true, + "requires": { + "esbuild": "^0.17.5", + "fsevents": "~2.3.2", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.18.0" + } + }, + "vite-plugin-singlefile": { + "version": "0.13.5", + "dev": true, + "requires": { + "micromatch": "^4.0.5" + } + }, + "vite-plugin-svgr": { + "version": "2.4.0", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.2", + "@svgr/core": "^6.5.1" + } + }, + "vite-tsconfig-paths": { + "version": "4.0.8", + "dev": true, + "requires": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^2.1.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "dev": true + } + } +} diff --git a/src/handbook/package.json b/src/handbook/package.json new file mode 100644 index 000000000..94073bf07 --- /dev/null +++ b/src/handbook/package.json @@ -0,0 +1,50 @@ +{ + "name": "handbook", + "description": "The ultimate anime game handbook!", + "version": "0.1.0", + "private": true, + + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + + "postinstall": "npx patch-package", + "lint": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md}\"" + }, + + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-virtualized": "^9.22.3", + + "events": "^3.3.0" + }, + "devDependencies": { + "typescript": "^4.9.3", + "@types/react": "^18.0.28", + "@types/react-dom": "^18.0.11", + "@types/react-virtualized": "^9.21.21", + "@types/events": "^3.0.0", + + "vite": "^4.2.0", + "vite-plugin-svgr": "^2.4.0", + "vite-tsconfig-paths": "^4.0.7", + "vite-plugin-singlefile": "^0.13.5", + "@vitejs/plugin-react-swc": "^3.0.0", + "@rollup/plugin-dsv": "^3.0.2", + + "sass": "^1.58.3", + "cssnano": "^5.1.15", + "tailwindcss": "^3.2.7", + "autoprefixer": "^10.4.13", + + "postcss": "^8.4.21", + "postcss-load-config": "^4.0.1", + "postcss-font-magician": "^3.0.0", + + "prettier": "^2.8.7", + "patch-package": "^6.5.1" + } +} diff --git a/src/handbook/patches/react-virtualized+9.22.3.patch b/src/handbook/patches/react-virtualized+9.22.3.patch new file mode 100644 index 000000000..d40d28db9 --- /dev/null +++ b/src/handbook/patches/react-virtualized+9.22.3.patch @@ -0,0 +1,10 @@ +diff --git a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js +index d00f0f1..42456dc 100644 +--- a/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js ++++ b/node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js +@@ -71,4 +71,3 @@ export function unregisterScrollListener(component, element) { + } + } + } +-import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js"; +\ No newline at end of file diff --git a/src/handbook/src/backend/data.ts b/src/handbook/src/backend/data.ts new file mode 100644 index 000000000..72238d0b9 --- /dev/null +++ b/src/handbook/src/backend/data.ts @@ -0,0 +1,146 @@ +import commands from "@data/commands.json"; +import entities from "@data/entities.csv"; +import avatars from "@data/avatars.csv"; +import scenes from "@data/scenes.csv"; +import items from "@data/items.csv"; + +import { Quality, ItemType, ItemCategory, SceneType } from "@backend/types"; +import type { Command, Avatar, Item, Scene, Entity } from "@backend/types"; + +import { inRange } from "@app/utils"; + +type AvatarDump = { [key: number]: Avatar }; +type CommandDump = { [key: string]: Command }; +type TaggedItems = { [key: number]: Item[] }; + +/** + * @see {@file src/handbook/data/README.md} + */ + +export const sortedItems: TaggedItems = { + [ItemCategory.Constellation]: [], // Range: 1102 - 11xx + [ItemCategory.Avatar]: [], // Range: 1002 - 10xx + [ItemCategory.Weapon]: [], + [ItemCategory.Artifact]: [], + [ItemCategory.Furniture]: [], + [ItemCategory.Material]: [], + [ItemCategory.Miscellaneous]: [] +}; + +/** + * Setup function for this file. + * Sorts all items into their respective categories. + */ +export function setup(): void { + getItems().forEach((item) => { + switch (item.type) { + case ItemType.Weapon: + sortedItems[ItemCategory.Weapon].push(item); + break; + case ItemType.Material: + sortedItems[ItemCategory.Material].push(item); + break; + case ItemType.Furniture: + sortedItems[ItemCategory.Furniture].push(item); + break; + case ItemType.Reliquary: + sortedItems[ItemCategory.Artifact].push(item); + break; + } + + // Sort constellations. + if (inRange(item.id, 1102, 1199)) { + sortedItems[ItemCategory.Constellation].push(item); + } + // Sort avatars. + if (inRange(item.id, 1002, 1099)) { + sortedItems[ItemCategory.Avatar].push(item); + } + }); +} + +/** + * Fetches and casts all commands in the file. + */ +export function getCommands(): CommandDump { + return commands as CommandDump; +} + +/** + * Fetches and lists all the commands in the file. + */ +export function listCommands(): Command[] { + return Object.values(getCommands()); +} + +/** + * Fetches and casts all entities in the file. + */ +export function getEntities(): Entity[] { + return entities.map((entry) => { + const values = Object.values(entry) as string[]; + const id = parseInt(values[0]); + return { + id, + name: values[1], + internal: values[2] + }; + }); +} + +/** + * Fetches and casts all avatars in the file. + */ +export function getAvatars(): AvatarDump { + const map: AvatarDump = {}; + avatars.forEach((avatar) => { + const values = Object.values(avatar) as [string, string, string]; + const id = parseInt(values[0]); + map[id] = { + id, + name: values[1], + quality: values[2] as Quality + }; + }); + + return map; +} + +/** + * Fetches and lists all the avatars in the file. + */ +export function listAvatars(): Avatar[] { + return Object.values(getAvatars()); +} + +/** + * Fetches and casts all scenes in the file. + */ +export function getScenes(): Scene[] { + return scenes.map((entry) => { + const values = Object.values(entry) as string[]; + const id = parseInt(values[0]); + return { + id, + identifier: values[1], + type: values[2] as SceneType + }; + }); +} + +/** + * Fetches and casts all items in the file. + */ +export function getItems(): Item[] { + return items.map((entry) => { + const values = Object.values(entry) as string[]; + const id = parseInt(values[0]); + return { + id, + name: values[1], + type: values[3] as ItemType, + quality: values[2] as Quality, + icon: values[4] + }; + }); +} diff --git a/src/handbook/src/backend/events.ts b/src/handbook/src/backend/events.ts new file mode 100644 index 000000000..8904b8c2b --- /dev/null +++ b/src/handbook/src/backend/events.ts @@ -0,0 +1,100 @@ +import { EventEmitter } from "events"; + +import type { Page } from "@backend/types"; +import { isPage } from "@backend/types"; + +const emitter = new EventEmitter(); +const navigation = new EventEmitter(); + +let navStack: Page[] = []; +let currentPage: number | null = -1; + +/** + * Sets up the event system. + */ +export function setup(): void { + window.onpopstate = (event) => { + navigate(event.state, false); + }; + + setTimeout(() => { + // Check if the window's href is a page. + const page = window.location.href.split("/").pop(); + if (page == undefined || page == "") return; + + // Convert the page to a Page type. + const pageName = page.charAt(0).toUpperCase() + page.slice(1); + const pageType = pageName as Page; + + // Navigate to the page. + isPage(page) && navigate(pageType, false); + }, 3e2); +} + +/** + * Adds a navigation listener. + * + * @param listener The listener to add. + */ +export function addNavListener(listener: (page: Page) => void) { + navigation.on("navigate", listener); +} + +/** + * Removes a navigation listener. + * + * @param listener The listener to remove. + */ +export function removeNavListener(listener: (page: Page) => void) { + navigation.off("navigate", listener); +} + +/** + * Navigates to a page. + * Returns the last page. + * + * @param page The page to navigate to. + * @param update Whether to update the state or not. + */ +export function navigate(page: Page, update: boolean = true): Page | null { + // Navigate to the new page. + const lastPage = currentPage; + navigation.emit("navigate", page); + + if (update) { + // Set the current page. + navStack.push(page); + currentPage = navStack.length - 1; + // Add the page to the window history. + window.history.pushState(page, page, "/" + page.toLowerCase()); + } + + return lastPage ? navStack[lastPage] : null; +} + +/** + * Goes back or forward in the navigation stack. + * + * @param forward Whether to go forward or not. + */ +export function go(forward: boolean): void { + if (currentPage == undefined) return; + + // Get the new page. + const newPage = forward ? currentPage + 1 : currentPage - 1; + if (newPage < 0 || newPage >= navStack.length) return; + + // Navigate to the new page. + currentPage = newPage; + navigation.emit("navigate", navStack[newPage]); + + // Update the window history. + window.history.pushState(navStack[newPage], navStack[newPage], "/" + navStack[newPage].toLowerCase()); +} + +// This is the global event system. +export default emitter; +// @ts-ignore +window["emitter"] = emitter; +// @ts-ignore +window["navigate"] = navigate; diff --git a/src/handbook/src/backend/files.d.ts b/src/handbook/src/backend/files.d.ts new file mode 100644 index 000000000..205989139 --- /dev/null +++ b/src/handbook/src/backend/files.d.ts @@ -0,0 +1,8 @@ +declare module "*.svg" { + export const ReactComponent: React.FunctionComponent>; +} + +declare module "*.csv" { + const content: any[]; + export default content; +} diff --git a/src/handbook/src/backend/server.ts b/src/handbook/src/backend/server.ts new file mode 100644 index 000000000..f317e73b5 --- /dev/null +++ b/src/handbook/src/backend/server.ts @@ -0,0 +1,74 @@ +import type { CommandResponse } from "@backend/types"; + +let targetPlayer = 0; // The UID of the target player. + +/** + * Sets the target player. + * + * @param player The UID of the target player. + */ +export function setTargetPlayer(player: number): void { + targetPlayer = player; + console.log(`Target Player is now: ${targetPlayer}`); +} + +/** + * Validates a number. + * + * @param value The number to validate. + */ +function invalid(value: number): boolean { + return isNaN(value) || value < 0; +} + +/** + * Grants an avatar to a player. + * + * @param avatar The avatar's ID. + * @param level The avatar's level. + * @param constellations The avatar's unlocked constellations. + * @param talents The level for the avatar's talents. + */ +export async function grantAvatar( + avatar: number, + level = 90, + constellations = 6, + talents = 6 +): Promise { + // Validate the numbers. + if (invalid(avatar) || invalid(level) || invalid(constellations) || invalid(talents)) + return { status: -1, message: "Invalid arguments." }; + + return await fetch(`https://localhost:443/handbook/avatar`, { + method: "POST", + body: JSON.stringify({ + player: targetPlayer.toString(), + avatar: avatar.toString(), + level, + constellations, + talentLevels: talents + }) + }).then((res) => res.json()); +} + +/** + * Gives an item to the player. + * This does not support weapons. + * This does not support relics. + * + * @param item The item's ID. + * @param amount The amount of the item to give. + */ +export async function giveItem(item: number, amount = 1): Promise { + // Validate the number. + if (isNaN(amount) || amount < 1) return { status: -1, message: "Invalid amount." }; + + return await fetch(`https://localhost:443/handbook/item`, { + method: "POST", + body: JSON.stringify({ + player: targetPlayer.toString(), + item: item.toString(), + amount + }) + }).then((res) => res.json()); +} diff --git a/src/handbook/src/backend/types.ts b/src/handbook/src/backend/types.ts new file mode 100644 index 000000000..857f1aebb --- /dev/null +++ b/src/handbook/src/backend/types.ts @@ -0,0 +1,159 @@ +export type Page = "Home" | "Commands" | "Avatars" | "Items" | "Entities" | "Scenes"; +export type Days = "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday"; + +export type Command = { + name: string[]; + description: string; + usage: string[]; + permission: string[]; + target: Target; +}; + +export type Avatar = { + name: string; + quality: Quality; + id: number; +}; + +export type Scene = { + identifier: string; + type: SceneType; + id: number; +}; + +export type Item = { + id: number; + name: string; + quality: Quality; + type: ItemType; + icon: string; +}; + +export type Entity = { + id: number; + name: string; + internal: string; +}; + +// Exported from Project Amber. +export type ItemInfo = { + response: number | 200 | 404; + data: { + name: string; + description: string; + type: string; + recipe: boolean; + mapMark: boolean; + source: { + name: string; + type: string | "domain"; + days: Days; + }[]; + icon: string; + rank: 1 | 2 | 3 | 4 | 5; + route: string; + }; +}; + +// Exported from Project Amber. +export type EntityInfo = { + response: number | 200 | 404; + data: { + id: number; + name: string; + type: string; + icon: string; + route: string; + title: string; + specialName: string; + description: string; + entries: any[]; + tips: null; + }; +}; + +export enum Target { + None = "NONE", + Offline = "OFFLINE", + Player = "PLAYER", + Online = "ONLINE" +} + +export enum Quality { + Legendary = "LEGENDARY", + Epic = "EPIC", + Rare = "RARE", + Uncommon = "UNCOMMON", + Common = "COMMON", + Unknown = "UNKNOWN" +} + +export enum ItemType { + None = "ITEM_NONE", + Virtual = "ITEM_VIRTUAL", + Material = "ITEM_MATERIAL", + Reliquary = "ITEM_RELIQUARY", + Weapon = "ITEM_WEAPON", + Display = "ITEM_DISPLAY", + Furniture = "ITEM_FURNITURE" +} + +export enum SceneType { + None = "SCENE_NONE", + World = "SCENE_WORLD", + Dungeon = "SCENE_DUNGEON", + Room = "SCENE_ROOM", + HomeWorld = "SCENE_HOME_WORLD", + HomeRoom = "SCENE_HOME_ROOM", + Activity = "SCENE_ACTIVITY" +} + +export enum ItemCategory { + Constellation, + Avatar, + Weapon, + Artifact, + Furniture, + Material, + Miscellaneous +} + +export type CommandResponse = { + status: number | 200 | 500; + message: string; +}; + +/** + * Checks if a string is a page. + * + * @param page The string to check. + */ +export function isPage(page: string): page is Page { + return ["Home", "Commands", "Avatars", "Items", "Entities", "Scenes"].includes(page); +} + +/** + * Converts an item type to a string. + * + * @param type The item type to convert. + */ +export function itemTypeToString(type: ItemType): string { + switch (type) { + default: + return "Unknown"; + case ItemType.None: + return "None"; + case ItemType.Virtual: + return "Virtual"; + case ItemType.Material: + return "Material"; + case ItemType.Reliquary: + return "Reliquary"; + case ItemType.Weapon: + return "Weapon"; + case ItemType.Display: + return "Display"; + case ItemType.Furniture: + return "Furniture"; + } +} diff --git a/src/handbook/src/css/App.scss b/src/handbook/src/css/App.scss new file mode 100644 index 000000000..668df9cef --- /dev/null +++ b/src/handbook/src/css/App.scss @@ -0,0 +1,54 @@ +html { + --background-color: #346b77; + --secondary-color: #418493; + --accent-color: #5abcb9; + + --text-primary-color: #FFFFFF; + + --legendary-color: #926d45; + --epic-color: #7b5c90; + + overflow: hidden; +} + +body { + margin: 0; + padding: 0; + height: 100vh; + width: 100%; + overflow: hidden; + + #root { + height: 100%; + width: 100%; + } + + * { + font-family: 'SDK_SC_Web', 'SDK_JP_Web', 'Poppins', sans-serif; + } + + svg:focus { + outline: none; + } +} + +.App { + display: flex; + flex-direction: row; + + width: 100%; + height: 100%; +} + +::-webkit-scrollbar { + width: 5px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--accent-color); + border-radius: 10px; +} diff --git a/src/handbook/src/css/Text.scss b/src/handbook/src/css/Text.scss new file mode 100644 index 000000000..5eae1e523 --- /dev/null +++ b/src/handbook/src/css/Text.scss @@ -0,0 +1,28 @@ +p { + color: var(--text-primary-color); + margin: 0; +} + +h1 { + color: var(--text-primary-color); + font-style: normal; + font-weight: normal; + font-size: 48px; + margin: 0; +} + +h2 { + color: var(--text-primary-color); + font-style: normal; + font-weight: 600; + font-size: 24px; + margin: 0; +} + +h3 { + color: var(--text-primary-color); + font-style: normal; + font-weight: 600; + font-size: 18px; + margin: 0; +} diff --git a/src/handbook/src/css/components/VirtualizedGrid.scss b/src/handbook/src/css/components/VirtualizedGrid.scss new file mode 100644 index 000000000..44b569499 --- /dev/null +++ b/src/handbook/src/css/components/VirtualizedGrid.scss @@ -0,0 +1,4 @@ +.GridRow { + display: flex; + flex-direction: row; +} diff --git a/src/handbook/src/css/pages/AvatarsPage.scss b/src/handbook/src/css/pages/AvatarsPage.scss new file mode 100644 index 000000000..77ce01e18 --- /dev/null +++ b/src/handbook/src/css/pages/AvatarsPage.scss @@ -0,0 +1,33 @@ +.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; + + max-width: 90%; + + grid-template-columns: repeat(12, 100px); + + margin-bottom: 28px; + overflow-y: scroll; +} diff --git a/src/handbook/src/css/pages/CommandsPage.scss b/src/handbook/src/css/pages/CommandsPage.scss new file mode 100644 index 000000000..147a20b1a --- /dev/null +++ b/src/handbook/src/css/pages/CommandsPage.scss @@ -0,0 +1,30 @@ +.CommandsPage { + display: flex; + height: 100%; + width: 100%; + + background-color: var(--background-color); + flex-direction: column; + + padding: 24px; +} + +.CommandsPage_Title { + max-width: 275px; + max-height: 60px; + + font-size: 48px; + font-weight: bold; + text-align: center; + + margin-bottom: 30px; +} + +.CommandsPage_List { + display: flex; + flex-direction: column; + + gap: 15px; + margin-bottom: 28px; + overflow-y: scroll; +} diff --git a/src/handbook/src/css/pages/EntitiesPage.scss b/src/handbook/src/css/pages/EntitiesPage.scss new file mode 100644 index 000000000..3da203659 --- /dev/null +++ b/src/handbook/src/css/pages/EntitiesPage.scss @@ -0,0 +1,93 @@ +.EntitiesPage { + display: flex; + height: 100%; + width: 100%; + + flex-direction: row; + justify-content: space-between; + background-color: var(--background-color); + + padding: 24px; +} + +.EntitiesPage_Content { + display: flex; + flex-direction: column; + + width: 80%; +} + +.EntitiesPage_Header { + display: flex; + flex-direction: row; + + gap: 30px; + align-content: center; + + margin-bottom: 30px; +} + +.EntitiesPage_Title { + max-width: 230px; + max-height: 60px; + + font-size: 48px; + font-weight: bold; + text-align: center; + justify-content: center; +} + +.EntitiesPage_Search { + display: flex; + + width: 100%; + height: 100%; + max-width: 465px; + max-height: 60px; + + box-sizing: border-box; + align-items: center; + border-radius: 10px; + + background-color: var(--secondary-color); +} + +.EntitiesPage_Input { + background-color: transparent; + border: none; + + color: var(--text-primary-color); + font-size: 20px; + width: 100%; + padding: 11px; + + &:focus, &:active { + outline: none; + } +} + +.EntitiesPage_Input::placeholder { + color: var(--text-secondary-color); + opacity: 1; +} + +.EntitiesPage_List { + display: grid; + gap: 15px 15px; + + grid-template-columns: repeat(15, 100px); + + margin-bottom: 28px; + overflow-y: scroll; +} + +.EntitiesPage_Card { + display: flex; + + width: 100%; + max-width: 300px; + min-height: 300px; + max-height: 700px; + + align-self: center; +} diff --git a/src/handbook/src/css/pages/HomePage.scss b/src/handbook/src/css/pages/HomePage.scss new file mode 100644 index 000000000..ee2afacdc --- /dev/null +++ b/src/handbook/src/css/pages/HomePage.scss @@ -0,0 +1,151 @@ +.HomePage { + display: flex; + height: 100%; + width: 100%; + + background-color: var(--background-color); + flex-direction: column; + justify-content: space-between; + + div { + display: flex; + } +} + +.HomePage_Top { + display: flex; + width: 100%; + height: 80%; + + flex-direction: column; + align-items: center; + + gap: 24px; +} + +.HomePage_Title { + margin-top: 31px; + margin-bottom: 15px; +} + +.HomePage_Buttons { + width: 100%; + height: 40%; + + max-width: 1376px; + max-height: 256px; + + gap: 24px; + justify-content: center; + flex-wrap: wrap; +} + +.HomePage_Bottom { + display: flex; + + height: 50%; + max-height: 125px; + flex-direction: row; + justify-content: space-between; +} + +.HomePage_Box { + display: flex; + background-color: var(--secondary-color); +} + +.HomePage_Disclaimer { + display: flex; + flex-direction: row; + justify-content: space-between; + background-color: var(--secondary-color); + + width: 50%; + height: 100%; + max-width: 630px; + max-height: 93px; + + margin: 0 0 0 60px; + border-radius: 10px; + + 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; + } +} + +.HomePage_Discord { + max-height: 40px; + max-width: 150px; + + gap: 8px; + align-self: center; + align-items: center; + + svg { + width: 100%; + height: 100%; + max-width: 44px; + max-height: 30px; + } + + p { + font-size: 16px; + } +} + +.HomePage_Text { + display: flex; + flex-direction: column; + background-color: var(--secondary-color); + + max-width: 300px; + max-height: 80px; + + margin: 13px 60px 0 0; + border-radius: 10px; + + box-sizing: border-box; + padding: 11px; +} + +.HomePage_Credits { + display: flex; + flex-direction: row; + gap: 5px; + + max-height: 18px; + padding-bottom: 5px; + + :nth-child(1) { + font-size: 18px; + font-weight: bold; + } + + :nth-child(2) { + font-size: 10px; + align-self: center; + } +} + +.HomePage_Links { + display: flex; + flex-wrap: wrap; + + a { + color: var(--text-primary-color); + text-decoration: none; + padding-right: 10px; + } +} diff --git a/src/handbook/src/css/pages/ItemsPage.scss b/src/handbook/src/css/pages/ItemsPage.scss new file mode 100644 index 000000000..3ef443681 --- /dev/null +++ b/src/handbook/src/css/pages/ItemsPage.scss @@ -0,0 +1,93 @@ +.ItemsPage { + display: flex; + height: 100%; + width: 100%; + + flex-direction: row; + justify-content: space-between; + background-color: var(--background-color); + + padding: 24px; +} + +.ItemsPage_Content { + display: flex; + flex-direction: column; + + width: 80%; +} + +.ItemsPage_Header { + display: flex; + flex-direction: row; + + gap: 30px; + align-content: center; + + margin-bottom: 30px; +} + +.ItemsPage_Title { + max-width: 130px; + max-height: 60px; + + font-size: 48px; + font-weight: bold; + text-align: center; + justify-content: center; +} + +.ItemsPage_Search { + display: flex; + + width: 100%; + height: 100%; + max-width: 465px; + max-height: 60px; + + box-sizing: border-box; + align-items: center; + border-radius: 10px; + + background-color: var(--secondary-color); +} + +.ItemsPage_Input { + background-color: transparent; + border: none; + + color: var(--text-primary-color); + font-size: 20px; + width: 100%; + padding: 11px; + + &:focus, &:active { + outline: none; + } +} + +.ItemsPage_Input::placeholder { + color: var(--text-secondary-color); + opacity: 1; +} + +.ItemsPage_List { + display: grid; + gap: 15px 15px; + + grid-template-columns: repeat(15, 100px); + + margin-bottom: 28px; + overflow-y: scroll; +} + +.ItemsPage_Card { + display: flex; + + width: 100%; + max-width: 300px; + min-height: 300px; + max-height: 700px; + + align-self: center; +} diff --git a/src/handbook/src/css/pages/ScenesPage.scss b/src/handbook/src/css/pages/ScenesPage.scss new file mode 100644 index 000000000..8762741d4 --- /dev/null +++ b/src/handbook/src/css/pages/ScenesPage.scss @@ -0,0 +1,44 @@ +.ScenesPage { + display: flex; + height: 100%; + width: 100%; + + background-color: var(--background-color); + flex-direction: column; + + padding: 24px; +} + +.ScenesPage_Title { + max-width: 180px; + max-height: 60px; + + font-size: 48px; + font-weight: bold; + text-align: center; + + margin-bottom: 30px; +} + +.ScenesPage_List { + display: flex; + flex-direction: column; + + gap: 15px; + margin-bottom: 28px; + overflow-y: scroll; +} + +.ScenesPage_Button { + width: 94px; + height: 34px; + + margin: 0; + border-radius: 10px; + border: transparent; + + font-size: 20px; + + color: var(--text-primary-color); + background-color: var(--background-color); +} diff --git a/src/handbook/src/css/views/Content.scss b/src/handbook/src/css/views/Content.scss new file mode 100644 index 000000000..2a2abba8b --- /dev/null +++ b/src/handbook/src/css/views/Content.scss @@ -0,0 +1,4 @@ +.Content { + width: 100%; + height: 100%; +} diff --git a/src/handbook/src/css/views/SideBar.scss b/src/handbook/src/css/views/SideBar.scss new file mode 100644 index 000000000..52c2ef5ce --- /dev/null +++ b/src/handbook/src/css/views/SideBar.scss @@ -0,0 +1,67 @@ +.SideBar { + display: flex; + flex-direction: column; + + height: 100%; + width: 100%; + max-width: 300px; + + background-color: var(--secondary-color); + + gap: 40px; +} + +.SideBar_Title { + margin-top: 42px; + line-height: 41px; + font-size: 34px; + + max-width: 256px; + max-height: 128px; + text-align: center; + align-self: center; +} + +.SideBar_Buttons { + display: flex; + flex-direction: column; + + padding-left: 27px; + gap: 15px; +} + +.SideBar_Enter { + display: flex; + + width: 100%; + height: 100%; + max-width: 250px; + max-height: 50px; + margin-bottom: 24px; + + box-sizing: border-box; + align-self: center; + align-items: center; + border-radius: 10px; + + background-color: var(--background-color); +} + +.SideBar_Input { + background-color: transparent; + border: none; + + color: var(--text-primary-color); + font-size: 20px; + width: 100%; + padding: 11px; + + &:focus, &:active { + outline: none; + } +} + +.SideBar_Input::placeholder { + color: var(--text-secondary-color); + opacity: 1; +} diff --git a/src/handbook/src/css/widgets/Card.scss b/src/handbook/src/css/widgets/Card.scss new file mode 100644 index 000000000..538b55f05 --- /dev/null +++ b/src/handbook/src/css/widgets/Card.scss @@ -0,0 +1,56 @@ +.Card { + display: flex; + flex-direction: row; + justify-content: space-between; + + width: 100%; + max-width: 1510px; + max-height: 100px; + + border-radius: 15px; + padding: 10px; + box-sizing: border-box; + + background-color: var(--secondary-color); +} + +.Card_Content { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.Card_Header { + display: flex; + flex-direction: row; + + width: 100%; + height: 100%; + + gap: 15px; + align-items: center; +} + +.Card_Title { + font-size: 32px; + font-weight: bold; +} + +.Card_Alternate { + font-size: 24px; +} + +.Card_Description { + color: var(--text-primary-color); + + overflow-y: scroll; + max-height: 24px; +} + +.Card_Button { + display: flex; + margin-right: 13px; + + align-self: center; + justify-content: center; +} diff --git a/src/handbook/src/css/widgets/Character.scss b/src/handbook/src/css/widgets/Character.scss new file mode 100644 index 000000000..5d161d3ee --- /dev/null +++ b/src/handbook/src/css/widgets/Character.scss @@ -0,0 +1,36 @@ +.Character { + display: flex; + flex-direction: column; + + max-width: 100px; + max-height: 125px; + border-radius: 15px; + + height: 100%; + + overflow: hidden; +} + +.Character_Icon { + width: 100%; + height: 100%; + + max-width: 96px; + max-height: 96px; +} + +.Character_Label { + display: flex; + justify-content: center; + align-items: center; + + background-color: var(--secondary-color); + + max-width: 100px; + height: 30px; + + p { + font-size: 18px; + text-align: center; + } +} diff --git a/src/handbook/src/css/widgets/HomeButton.scss b/src/handbook/src/css/widgets/HomeButton.scss new file mode 100644 index 000000000..6f05ebe07 --- /dev/null +++ b/src/handbook/src/css/widgets/HomeButton.scss @@ -0,0 +1,29 @@ +.HomeButton { + display: flex; + flex-direction: column; + + width: 100%; + height: 100%; + max-width: 256px; + max-height: 256px; + + background-color: var(--secondary-color); + + align-items: center; + justify-content: center; + gap: 20px; + + border-radius: 10px; +} + +.HomeButton_Icon { + max-width: 128px; + max-height: 128px; +} + +.HomeButton_Label { + font-size: 34px; + line-height: 44px; + text-align: center; + font-style: normal; +} diff --git a/src/handbook/src/css/widgets/ItemCard.scss b/src/handbook/src/css/widgets/ItemCard.scss new file mode 100644 index 000000000..3578447c5 --- /dev/null +++ b/src/handbook/src/css/widgets/ItemCard.scss @@ -0,0 +1,143 @@ +.ItemCard { + display: flex; + flex-direction: column; + justify-content: space-between; + + width: 100%; + height: 100%; + max-width: 300px; + min-height: 300px; + max-height: 700px; + + padding: 20px; + box-sizing: border-box; + + border-radius: 10px; + background-color: var(--accent-color); +} + +.ItemCard_Content { + display: flex; + gap: 10px; + + flex-direction: column; +} + +.ItemCard_Header { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.ItemCard_Info { + display: flex; + flex-direction: column; + gap: 10px; + + :nth-child(1) { + font-weight: bold; + font-size: 20px; + + max-width: 170px; + max-height: 60px; + + color: var(--text-primary-color); + } + + :nth-child(2) { + font-size: 16px; + + color: var(--text-primary-color); + } +} + +.ItemCard_Icon { + width: 64px; + height: 64px +} + +.ItemCard_Description { + display: flex; + flex-direction: column; + + max-width: 250px; + max-height: 460px; + + p { + font-size: 14px; + + color: var(--text-primary-color); + } +} + +.ItemCard_Actions { + display: flex; + flex-direction: column; + + gap: 5px; + padding-top: 10px; +} + +.ItemCard_Counter { + display: flex; + flex-direction: row; + justify-content: space-between; + + width: 100%; + height: 100%; + max-width: 260px; + max-height: 46px; + + border-radius: 10px; + padding: 0 13px 0 13px; + box-sizing: border-box; + + align-items: center; + background-color: var(--secondary-color); +} + +.ItemCard_Operation { + user-select: none; + display: flex; + + width: 30px; + height: 20px; + + font-size: 24px; + align-items: center; + justify-content: center; + color: var(--text-primary-color); + + background-color: var(--background-color); +} + +.ItemCard_Count { + max-width: 105px; + height: 48px; + + font-size: 24px; + text-align: center; + background-color: transparent; + color: var(--text-primary-color); + border: transparent; +} + +.ItemCard_Count:focus { + outline: none; +} + +.ItemCard_Submit { + width: 100%; + height: 46px; + max-width: 260px; + + border-radius: 10px; + text-align: center; + justify-content: center; + + border: transparent; + font-size: 24px; + + color: var(--text-primary-color); + background-color: var(--secondary-color); +} diff --git a/src/handbook/src/css/widgets/MiniCard.scss b/src/handbook/src/css/widgets/MiniCard.scss new file mode 100644 index 000000000..80c6c6fe6 --- /dev/null +++ b/src/handbook/src/css/widgets/MiniCard.scss @@ -0,0 +1,40 @@ +.MiniCard { + display: flex; + + width: 64px; + height: 64px; + + overflow: hidden; + justify-content: center; +} + +.MiniCard_Background { + display: flex; + align-items: center; + + max-width: 64px; + max-height: 64px; + + border-radius: 10px; + background-color: var(--secondary-color); +} + +.MiniCard_Icon { + max-width: 64px; + max-height: 64px; + object-fit: scale-down; + border-radius: 10px; +} + +.MiniCard_Label { + width: 64px; + max-height: 64px; + text-align: center; + font-size: 12px; + color: var(--text-primary-color); +} + +.MiniCard_Info { + position: absolute; + display: flex; +} diff --git a/src/handbook/src/css/widgets/SideBarButton.scss b/src/handbook/src/css/widgets/SideBarButton.scss new file mode 100644 index 000000000..805ad7513 --- /dev/null +++ b/src/handbook/src/css/widgets/SideBarButton.scss @@ -0,0 +1,26 @@ +.SideBarButton { + display: flex; + flex-direction: row; + + gap: 15px; + + width: 100%; + height: 64px; + max-width: 300px; + max-height: 64px; + + align-items: center; +} + +.SideBarButton_Icon { + max-width: 64px; + max-height: 64px; +} + +.SideBarButton_Label { + font-size: 22px; + line-height: 29px; + font-style: normal; + + max-width: 220px; +} diff --git a/src/handbook/src/icons/discord.svg b/src/handbook/src/icons/discord.svg new file mode 100644 index 000000000..22ee27ba2 --- /dev/null +++ b/src/handbook/src/icons/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/handbook/src/main.tsx b/src/handbook/src/main.tsx new file mode 100644 index 000000000..f80fd024a --- /dev/null +++ b/src/handbook/src/main.tsx @@ -0,0 +1,18 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; + +import * as data from "@backend/data"; +import * as events from "@backend/events"; + +import App from "@ui/App"; + +// Call initial setup functions. +data.setup(); +events.setup(); + +// Render the application. +createRoot(document.getElementById("root") as HTMLElement).render( + + + +); diff --git a/src/handbook/src/ui/App.tsx b/src/handbook/src/ui/App.tsx new file mode 100644 index 000000000..eba12dc40 --- /dev/null +++ b/src/handbook/src/ui/App.tsx @@ -0,0 +1,50 @@ +import React from "react"; + +import SideBar from "@views/SideBar"; +import Content from "@views/Content"; + +import type { Page } from "@backend/types"; +import { isPage } from "@backend/types"; + +import "@css/App.scss"; +import "@css/Text.scss"; + +// Based on the design at: https://www.figma.com/file/PDeAVDkTDF5vvUGGdaIZ39/GM-Handbook. +// Currently designed by: Magix. + +interface IState { + initial: Page | null; +} + +class App extends React.Component<{}, IState> { + constructor(props: any) { + super(props); + + // Check if the window's href is a page. + let targetPage = null; + const page = window.location.href.split("/").pop(); + console.log(page); + + if (page != undefined && page != "") { + // Convert the page to a Page type. + const pageName = page.charAt(0).toUpperCase() + page.slice(1); + // Check if the page is a valid page. + if (isPage(pageName)) targetPage = pageName as Page; + } + + this.state = { + initial: targetPage as Page | null + }; + } + + render() { + return ( +
+ + +
+ ); + } +} + +export default App; diff --git a/src/handbook/src/ui/components/VirtualizedGrid.tsx b/src/handbook/src/ui/components/VirtualizedGrid.tsx new file mode 100644 index 000000000..631c53fc9 --- /dev/null +++ b/src/handbook/src/ui/components/VirtualizedGrid.tsx @@ -0,0 +1,88 @@ +import React from "react"; + +import { List as _List, ListProps, ListRowProps } from "react-virtualized/dist/es/List"; +import { AutoSizer as _AutoSizer, AutoSizerProps } from "react-virtualized/dist/es/AutoSizer"; + +const List = _List as unknown as React.FC; +const AutoSizer = _AutoSizer as unknown as React.FC; + +import "@css/components/VirtualizedGrid.scss"; + +interface IProps { + list: T[]; + render: (item: T) => React.ReactNode; + + itemHeight: number; + itemsPerRow?: number; + + gap?: number; + itemGap?: number; +} + +interface IState { + scrollTop: number; +} + +class VirtualizedGrid extends React.Component, IState> { + constructor(props: IProps) { + super(props); + + this.state = { + scrollTop: 0 + }; + } + + /** + * Renders a row of items. + */ + private rowRender(props: ListRowProps): React.ReactNode { + const items: React.ReactNode[] = []; + + // Calculate the items to render. + const perRow = this.props.itemsPerRow ?? 10; + for (let i = 0; i < perRow; i++) { + const itemIndex = props.index * perRow + i; + if (itemIndex < this.props.list.length) { + items.push(this.props.render(this.props.list[itemIndex])); + } + } + + return ( +
+ {items.map((item, index) => ( +
{item}
+ ))} +
+
+ ); + } + + render() { + const { list, itemHeight, itemsPerRow } = this.props; + + return ( + + {({ height, width }) => ( + this.setState({ scrollTop: e.scrollTop })} + /> + )} + + ); + } +} + +export default VirtualizedGrid; diff --git a/src/handbook/src/ui/pages/AvatarsPage.tsx b/src/handbook/src/ui/pages/AvatarsPage.tsx new file mode 100644 index 000000000..fe97e3a6d --- /dev/null +++ b/src/handbook/src/ui/pages/AvatarsPage.tsx @@ -0,0 +1,39 @@ +import React from "react"; + +import Character from "@app/ui/widgets/Character"; + +import type { Avatar } from "@backend/types"; +import { listAvatars } from "@backend/data"; +import { grantAvatar } from "@backend/server"; + +import "@css/pages/AvatarsPage.scss"; + +class AvatarsPage extends React.PureComponent { + /** + * Grants the avatar to the user. + * + * @param avatar The avatar to grant. + * @private + */ + private async grantAvatar(avatar: Avatar): Promise { + console.log(await grantAvatar(avatar.id)); + } + + 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 new file mode 100644 index 000000000..6c5416ace --- /dev/null +++ b/src/handbook/src/ui/pages/CommandsPage.tsx @@ -0,0 +1,33 @@ +import React from "react"; + +import Card from "@widgets/Card"; + +import { listCommands } from "@backend/data"; + +import "@css/pages/CommandsPage.scss"; + +class CommandsPage extends React.PureComponent { + render() { + return ( +
+

Commands

+ +
+ {listCommands().map((command) => ( + + ))} +
+
+ ); + } +} + +export default CommandsPage; diff --git a/src/handbook/src/ui/pages/EntitiesPage.tsx b/src/handbook/src/ui/pages/EntitiesPage.tsx new file mode 100644 index 000000000..f0dbe96da --- /dev/null +++ b/src/handbook/src/ui/pages/EntitiesPage.tsx @@ -0,0 +1,153 @@ +import React, { ChangeEvent } from "react"; + +import MiniCard from "@widgets/MiniCard"; +import VirtualizedGrid from "@components/VirtualizedGrid"; + +import { Entity, ItemCategory } from "@backend/types"; +import type { Entity as EntityType, EntityInfo } from "@backend/types"; +import { getEntities } from "@backend/data"; +import { entityIcon, fetchEntityData } from "@app/utils"; + +import "@css/pages/EntitiesPage.scss"; +import EntityCard from "@widgets/EntityCard"; + +interface IState { + filters: ItemCategory[]; + search: string; + + selected: EntityType | null; + selectedInfo: EntityInfo | null; +} + +class EntitiesPage extends React.Component<{}, IState> { + constructor(props: {}) { + super(props); + + this.state = { + filters: [], + search: "", + + selected: null, + selectedInfo: null + }; + } + + /** + * Should the entity be shown? + * + * @param entity The entity. + * @private + */ + private showEntity(entity: Entity): boolean { + // Check if the entity's name starts with N/A. + if (entity.name.includes("[N/A]")) return false; + + return entity.id > 0; + } + + /** + * Gets the items to render. + * @private + */ + private getEntities(): EntityType[] { + let entities: EntityType[] = []; + + // Add items based on filters. + const filters = this.state.filters; + if (filters.length == 0) { + entities = getEntities(); + } else { + for (const filter of filters) { + // Remove duplicate items. + entities = entities.filter((item, index) => { + return entities.indexOf(item) == index; + }); + } + } + + // Filter out items that don't match the search. + const search = this.state.search.toLowerCase(); + if (search != "") { + entities = entities.filter((item) => { + return item.name.toLowerCase().includes(search); + }); + } + + return entities; + } + + /** + * Invoked when the search input changes. + * + * @param event The event. + * @private + */ + private onChange(event: ChangeEvent): void { + this.setState({ search: event.target.value }); + } + + /** + * Sets the selected entity. + * + * @param entity The entity. + * @private + */ + private async setSelectedItem(entity: EntityType): Promise { + let data: EntityInfo | null = null; + try { + data = await fetchEntityData(entity); + } catch {} + + this.setState({ + selected: entity, + selectedInfo: data + }); + } + + render() { + const entities = this.getEntities(); + + return ( +
+
+
+

Monsters

+ +
+ +
+
+ + {entities.length > 0 ? ( + this.showEntity(entity))} + itemHeight={64} + itemsPerRow={18} + gap={5} + itemGap={5} + render={(entity) => ( + this.setSelectedItem(entity)} + /> + )} + /> + ) : undefined} +
+ +
+ +
+
+ ); + } +} + +export default EntitiesPage; diff --git a/src/handbook/src/ui/pages/HomePage.tsx b/src/handbook/src/ui/pages/HomePage.tsx new file mode 100644 index 000000000..d25bfe4d6 --- /dev/null +++ b/src/handbook/src/ui/pages/HomePage.tsx @@ -0,0 +1,66 @@ +import React from "react"; + +import HomeButton from "@widgets/HomeButton"; + +import { ReactComponent as DiscordLogo } from "@icons/discord.svg"; + +import "@css/pages/HomePage.scss"; + +class HomePage extends React.Component { + constructor(props: any) { + super(props); + } + + render() { + return ( +
+
+

Welcome back, Traveler~

+ +
+ + + + + +
+ +
+ + +
+
+ +
+
+
+

This tool is not affiliated with HoYoverse.

+

Genshin Impact, game content and materials are

+

trademarks and copyrights of HoYoverse.

+
+ +
+ +

Join the Community!

+
+
+ +
+
+

Credits

+

(hover to see info)

+
+ + +
+
+
+ ); + } +} + +export default HomePage; diff --git a/src/handbook/src/ui/pages/ItemsPage.tsx b/src/handbook/src/ui/pages/ItemsPage.tsx new file mode 100644 index 000000000..1f4096737 --- /dev/null +++ b/src/handbook/src/ui/pages/ItemsPage.tsx @@ -0,0 +1,157 @@ +import React, { ChangeEvent } from "react"; + +import MiniCard from "@widgets/MiniCard"; +import ItemCard from "@widgets/ItemCard"; +import VirtualizedGrid from "@components/VirtualizedGrid"; + +import { ItemCategory } from "@backend/types"; +import type { Item as ItemType, ItemInfo } from "@backend/types"; +import { getItems, sortedItems } from "@backend/data"; +import { fetchItemData, itemIcon } from "@app/utils"; + +import "@css/pages/ItemsPage.scss"; + +interface IState { + filters: ItemCategory[]; + search: string; + + selected: ItemType | null; + selectedInfo: ItemInfo | null; +} + +class ItemsPage extends React.Component<{}, IState> { + constructor(props: {}) { + super(props); + + this.state = { + filters: [], + search: "", + + selected: null, + selectedInfo: null + }; + } + + /** + * Gets the items to render. + * @private + */ + private getItems(): ItemType[] { + let items: ItemType[] = []; + + // Add items based on filters. + const filters = this.state.filters; + if (filters.length == 0) { + items = getItems(); + } else { + for (const filter of filters) { + // Add items from the category. + items = items.concat(sortedItems[filter]); + // Remove duplicate items. + items = items.filter((item, index) => { + return items.indexOf(item) == index; + }); + } + } + + // Filter out items that don't match the search. + const search = this.state.search.toLowerCase(); + if (search != "") { + items = items.filter((item) => { + return item.name.toLowerCase().includes(search); + }); + } + + return items; + } + + /** + * Invoked when the search input changes. + * + * @param event The event. + * @private + */ + private onChange(event: ChangeEvent): void { + this.setState({ search: event.target.value }); + } + + /** + * Should the item be showed? + * + * @param item The item. + * @private + */ + private showItem(item: ItemType): boolean { + // Check if the item has an icon. + if (item.icon.length == 0) return false; + // Check if the item is a TCG card. + if (item.icon.includes("Gcg")) return false; + + return item.id > 0; + } + + /** + * Sets the selected item. + * + * @param item The item. + * @private + */ + private async setSelectedItem(item: ItemType): Promise { + let data: ItemInfo | null = null; + try { + data = await fetchItemData(item); + } catch {} + + this.setState({ + selected: item, + selectedInfo: data + }); + } + + render() { + const items = this.getItems(); + + return ( +
+
+
+

Items

+ +
+ +
+
+ + {items.length > 0 ? ( + this.showItem(item))} + itemHeight={64} + itemsPerRow={18} + gap={5} + itemGap={5} + render={(item) => ( + this.setSelectedItem(item)} + /> + )} + /> + ) : undefined} +
+ +
+ +
+
+ ); + } +} + +export default ItemsPage; diff --git a/src/handbook/src/ui/pages/ScenesPage.tsx b/src/handbook/src/ui/pages/ScenesPage.tsx new file mode 100644 index 000000000..4d8686128 --- /dev/null +++ b/src/handbook/src/ui/pages/ScenesPage.tsx @@ -0,0 +1,71 @@ +import React from "react"; + +import Card from "@widgets/Card"; + +import { SceneType } from "@backend/types"; +import { getScenes } from "@backend/data"; + +import "@css/pages/ScenesPage.scss"; + +/** + * Converts a scene type to a string. + * + * @param type The scene type. + */ +function sceneTypeToString(type: SceneType): string { + switch (type) { + default: + return "Unknown"; + case SceneType.None: + return "None"; + case SceneType.World: + return "World"; + case SceneType.Activity: + return "Activity"; + case SceneType.Dungeon: + return "Dungeon"; + case SceneType.Room: + return "Room"; + case SceneType.HomeRoom: + return "Home Room"; + case SceneType.HomeWorld: + return "Home World"; + } +} + +class ScenesPage extends React.PureComponent { + /** + * Teleports the player to the specified scene. + * @private + */ + private async teleport(): Promise { + // TODO: Implement teleporting. + } + + render() { + return ( +
+

Scenes

+ +
+ {getScenes().map((command) => ( + + Teleport + + } + rightOffset={13} + height={75} + /> + ))} +
+
+ ); + } +} + +export default ScenesPage; diff --git a/src/handbook/src/ui/views/Content.tsx b/src/handbook/src/ui/views/Content.tsx new file mode 100644 index 000000000..eaa4ececa --- /dev/null +++ b/src/handbook/src/ui/views/Content.tsx @@ -0,0 +1,70 @@ +import React from "react"; + +import HomePage from "@pages/HomePage"; +import CommandsPage from "@pages/CommandsPage"; +import AvatarsPage from "@pages/AvatarsPage"; +import ItemsPage from "@pages/ItemsPage"; +import EntitiesPage from "@pages/EntitiesPage"; +import ScenesPage from "@pages/ScenesPage"; + +import type { Page } from "@backend/types"; +import { addNavListener, removeNavListener } from "@backend/events"; + +import "@css/views/Content.scss"; + +interface IProps { + initial?: Page | null; +} + +interface IState { + current: Page; +} + +class Content extends React.Component { + constructor(props: IProps) { + super(props); + + this.state = { + current: props.initial ?? "Home" + }; + } + + /** + * Navigates to the specified page. + * + * @param page The page to navigate to. + * @private + */ + private navigate(page: Page): void { + this.setState({ current: page }); + } + + componentDidMount() { + addNavListener(this.navigate.bind(this)); + } + + componentWillUnmount() { + removeNavListener(this.navigate.bind(this)); + } + + render() { + switch (this.state.current) { + default: + return undefined; + case "Home": + return ; + case "Commands": + return ; + case "Avatars": + return ; + case "Items": + return ; + case "Entities": + return ; + case "Scenes": + return ; + } + } +} + +export default Content; diff --git a/src/handbook/src/ui/views/SideBar.tsx b/src/handbook/src/ui/views/SideBar.tsx new file mode 100644 index 000000000..7181acd92 --- /dev/null +++ b/src/handbook/src/ui/views/SideBar.tsx @@ -0,0 +1,78 @@ +import React, { ChangeEvent } from "react"; + +import SideBarButton from "@app/ui/widgets/SideBarButton"; + +import { navigate } from "@app/backend/events"; + +import "@css/views/SideBar.scss"; +import { setTargetPlayer } from "@backend/server"; + +interface IState { + uid: string | null; +} + +class SideBar extends React.Component<{}, IState> { + constructor(props: {}) { + super(props); + + this.state = { + uid: null + }; + } + + /** + * Invoked when the UID input changes. + * + * @param event The event. + * @private + */ + private onChange(event: ChangeEvent): void { + const input = event.target.value; + const uid = input == "" ? null : input; + if (uid && uid.length > 10) return; + + this.setState({ uid }); + setTargetPlayer(parseInt(uid ?? "0")); + } + + render() { + return ( +
+

navigate("Home")}> + The Ultimate Anime Game Handbook +

+ +
+
+ + + + + + + +
+ +
+ +
+
+
+ ); + } +} + +export default SideBar; diff --git a/src/handbook/src/ui/widgets/Card.tsx b/src/handbook/src/ui/widgets/Card.tsx new file mode 100644 index 000000000..c8308bbcd --- /dev/null +++ b/src/handbook/src/ui/widgets/Card.tsx @@ -0,0 +1,64 @@ +import React from "react"; + +import "@css/widgets/Card.scss"; + +interface IProps { + title: string; + alternate?: string; + description?: string | string[]; + + height?: number | string; + button?: React.ReactNode; + rightOffset?: number; + + onClick?: () => void; + onOver?: () => void; + onOut?: () => void; +} + +class Card extends React.PureComponent { + constructor(props: IProps) { + super(props); + } + + render() { + return ( +
+
+
+

{this.props.title}

+ {this.props.alternate &&

{this.props.alternate}

} +
+ +
+ {this.props.description ? ( + Array.isArray(this.props.description) ? ( + this.props.description.map((line, index) => ( +

+ {line} +

+ )) + ) : ( +

{this.props.description}

+ ) + ) : undefined} +
+
+ + {this.props.button ? ( +
+ {this.props.button} +
+ ) : undefined} +
+ ); + } +} + +export default Card; diff --git a/src/handbook/src/ui/widgets/Character.tsx b/src/handbook/src/ui/widgets/Character.tsx new file mode 100644 index 000000000..c2b2a8fa1 --- /dev/null +++ b/src/handbook/src/ui/widgets/Character.tsx @@ -0,0 +1,57 @@ +import React from "react"; + +import type { Avatar } from "@backend/types"; +import { colorFor, formatAvatarName } from "@app/utils"; + +import "@css/widgets/Character.scss"; + +// Image base URL: https://paimon.moe/images/characters/(name).png + +const ignored = [ + 10000001 // Kate +]; + +const nameSwitch: { [key: number]: string } = { + 10000005: "Lumine", + 10000007: "Aether" +}; + +interface IProps { + data: Avatar; + + onClick?: () => void; +} + +class Character extends React.PureComponent { + constructor(props: IProps) { + super(props); + } + + 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 ( +
+ {name} + +
+

{nameSwitch[id] ?? name}

+
+
+ ); + } +} + +export default Character; diff --git a/src/handbook/src/ui/widgets/EntityCard.tsx b/src/handbook/src/ui/widgets/EntityCard.tsx new file mode 100644 index 000000000..0e3829a45 --- /dev/null +++ b/src/handbook/src/ui/widgets/EntityCard.tsx @@ -0,0 +1,162 @@ +import React from "react"; + +import type { Entity as EntityType, EntityInfo } from "@backend/types"; +import { entityIcon } from "@app/utils"; + +import "@css/widgets/ItemCard.scss"; + +/** + * Converts a description string into a list of paragraphs. + * + * @param description The description to convert. + */ +function toDescription(description: string | undefined): JSX.Element[] { + if (!description) return []; + + return description.split("\\n").map((line, index) => { + return

{line}

; + }); +} + +interface IProps { + entity: EntityType | null; + info: EntityInfo | null; +} + +interface IState { + icon: boolean; + count: number | string; +} + +const defaultState = { + icon: true, + count: 1 +}; + +class EntityCard extends React.Component { + constructor(props: IProps) { + super(props); + + this.state = defaultState; + } + + /** + * Updates the count of the item. + * + * @param event The change event. + * @private + */ + private updateCount(event: React.ChangeEvent) { + const value = event.target.value; + if (isNaN(parseInt(value)) && value.length > 1) return; + + this.setState({ count: value }); + } + + /** + * Adds to the count of the entity. + * + * @param positive Is the count being added or subtracted? + * @param multiple Is the count being multiplied by 10? + * @private + */ + private addCount(positive: boolean, multiple: boolean) { + let { count } = this.state; + if (count === "") count = 1; + if (typeof count == "string") count = parseInt(count); + if (count < 1) count = 1; + + let increment = 1; + if (!positive) increment = -1; + if (multiple) increment *= 10; + + count = Math.max(1, count + increment); + + this.setState({ count }); + } + + /** + * Summons the entity at the connected player's position. + * @private + */ + private async summonAtPlayer(): Promise { + // TODO: Implement server access. + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any) { + if (this.props.entity != prevProps.entity) { + this.setState(defaultState); + } + } + + render() { + const { entity, info } = this.props; + const data = info?.data; + + return entity ? ( +
+
+
+
+

{data?.name ?? entity.name}

+

{data?.type ?? ""}

+
+ + {this.state.icon && ( + {entity.name} this.setState({ icon: false })} + /> + )} +
+ +
{toDescription(data?.description)}
+
+ +
+
+
this.addCount(false, false)} + onContextMenu={(e) => { + e.preventDefault(); + this.addCount(false, true); + }} + className={"ItemCard_Operation"} + > + - +
+ { + if (this.state.count == "") { + this.setState({ count: 1 }); + } + }} + /> +
this.addCount(true, false)} + onContextMenu={(e) => { + e.preventDefault(); + this.addCount(true, true); + }} + className={"ItemCard_Operation"} + > + + +
+
+ + +
+
+ ) : undefined; + } +} + +export default EntityCard; diff --git a/src/handbook/src/ui/widgets/HomeButton.tsx b/src/handbook/src/ui/widgets/HomeButton.tsx new file mode 100644 index 000000000..dabc31563 --- /dev/null +++ b/src/handbook/src/ui/widgets/HomeButton.tsx @@ -0,0 +1,37 @@ +import React from "react"; + +import type { Page } from "@backend/types"; +import { navigate } from "@backend/events"; + +import "@css/widgets/HomeButton.scss"; + +interface IProps { + name: string; + anchor: Page; +} + +class HomeButton extends React.PureComponent { + constructor(props: IProps) { + super(props); + } + + /** + * Redirects the user to the specified anchor. + * @private + */ + private redirect(): void { + navigate(this.props.anchor); + } + + render() { + return ( +
this.redirect()}> + {this.props.name} + +

{this.props.name}

+
+ ); + } +} + +export default HomeButton; diff --git a/src/handbook/src/ui/widgets/ItemCard.tsx b/src/handbook/src/ui/widgets/ItemCard.tsx new file mode 100644 index 000000000..af42dd7fe --- /dev/null +++ b/src/handbook/src/ui/widgets/ItemCard.tsx @@ -0,0 +1,167 @@ +import React from "react"; + +import type { Item as ItemType, ItemInfo } from "@backend/types"; +import { itemTypeToString } from "@backend/types"; +import { itemIcon } from "@app/utils"; +import { giveItem } from "@backend/server"; + +import "@css/widgets/ItemCard.scss"; + +/** + * Converts a description string into a list of paragraphs. + * + * @param description The description to convert. + */ +function toDescription(description: string | undefined): JSX.Element[] { + if (!description) return []; + + return description.split("\\n").map((line, index) => { + return

{line}

; + }); +} + +interface IProps { + item: ItemType | null; + info: ItemInfo | null; +} + +interface IState { + icon: boolean; + count: number | string; +} + +const defaultState = { + icon: true, + count: 1 +}; + +class ItemCard extends React.Component { + constructor(props: IProps) { + super(props); + + this.state = defaultState; + } + + /** + * Updates the count of the item. + * + * @param event The change event. + * @private + */ + private updateCount(event: React.ChangeEvent) { + const value = event.target.value; + if (isNaN(parseInt(value)) && value.length > 1) return; + + this.setState({ count: value }); + } + + /** + * Adds to the count of the item. + * + * @param positive Is the count being added or subtracted? + * @param multiple Is the count being multiplied by 10? + * @private + */ + private addCount(positive: boolean, multiple: boolean) { + let { count } = this.state; + if (count === "") count = 1; + if (typeof count == "string") count = parseInt(count); + if (count < 1) count = 1; + + let increment = 1; + if (!positive) increment = -1; + if (multiple) increment *= 10; + + count = Math.max(1, count + increment); + + this.setState({ count }); + } + + /** + * Adds the item to the player's connected inventory. + * @private + */ + private async addToInventory(): Promise { + await giveItem( + this.props.item?.id ?? 102, + typeof this.state.count == "string" ? parseInt(this.state.count) : this.state.count + ); + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any) { + if (this.props.item != prevProps.item) { + this.setState(defaultState); + } + } + + render() { + const { item, info } = this.props; + const data = info?.data; + + return item ? ( +
+
+
+
+

{data?.name ?? item.name}

+

{data?.type ?? itemTypeToString(item.type)}

+
+ + {this.state.icon && ( + {item.name} this.setState({ icon: false })} + /> + )} +
+ +
{toDescription(data?.description)}
+
+ +
+
+
this.addCount(false, false)} + onContextMenu={(e) => { + e.preventDefault(); + this.addCount(false, true); + }} + className={"ItemCard_Operation"} + > + - +
+ { + if (this.state.count == "") { + this.setState({ count: 1 }); + } + }} + /> +
this.addCount(true, false)} + onContextMenu={(e) => { + e.preventDefault(); + this.addCount(true, true); + }} + className={"ItemCard_Operation"} + > + + +
+
+ + +
+
+ ) : undefined; + } +} + +export default ItemCard; diff --git a/src/handbook/src/ui/widgets/MiniCard.tsx b/src/handbook/src/ui/widgets/MiniCard.tsx new file mode 100644 index 000000000..a286e1530 --- /dev/null +++ b/src/handbook/src/ui/widgets/MiniCard.tsx @@ -0,0 +1,77 @@ +import React from "react"; + +import { itemIcon } from "@app/utils"; + +import "@css/widgets/MiniCard.scss"; + +interface IProps { + data: { name: string }; + icon: string; + + onClick?: () => void; +} + +interface IState { + popout: boolean; + icon: boolean; + loaded: boolean; +} + +class MiniCard extends React.Component { + loading: number | any; + + constructor(props: IProps) { + super(props); + + this.state = { + popout: false, + icon: true, + loaded: false + }; + } + + /** + * Replaces the icon with the item's name. + * @private + */ + private replaceIcon(): void { + this.setState({ icon: false, loaded: false }); + } + + private forceReplace(): void { + if (!this.state.loaded) this.replaceIcon(); + } + + componentDidMount() { + this.loading = setTimeout(this.forceReplace.bind(this), 1e3); + } + + componentWillUnmount() { + clearTimeout(this.loading); + this.loading = null; + } + + render() { + return ( +
+
+ {this.state.icon && ( + {this.props.data.name} this.setState({ loaded: true })} + /> + )} + + {(!this.state.loaded || !this.state.icon) && ( +

{this.props.data.name}

+ )} +
+
+ ); + } +} + +export default MiniCard; diff --git a/src/handbook/src/ui/widgets/SideBarButton.tsx b/src/handbook/src/ui/widgets/SideBarButton.tsx new file mode 100644 index 000000000..5a16af4c5 --- /dev/null +++ b/src/handbook/src/ui/widgets/SideBarButton.tsx @@ -0,0 +1,37 @@ +import React from "react"; + +import type { Page } from "@backend/types"; +import { navigate } from "@backend/events"; + +import "@css/widgets/SideBarButton.scss"; + +interface IProps { + name: string; + anchor: Page; +} + +class SideBarButton extends React.PureComponent { + constructor(props: IProps) { + super(props); + } + + /** + * Redirects the user to the specified anchor. + * @private + */ + private redirect(): void { + navigate(this.props.anchor); + } + + render() { + return ( +
this.redirect()}> + {this.props.name} + +

{this.props.name}

+
+ ); + } +} + +export default SideBarButton; diff --git a/src/handbook/src/utils.ts b/src/handbook/src/utils.ts new file mode 100644 index 000000000..5ec928217 --- /dev/null +++ b/src/handbook/src/utils.ts @@ -0,0 +1,136 @@ +import type { Entity, Item, EntityInfo, ItemInfo } from "@backend/types"; +import { ItemType, 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"; + } +} + +/** + * Checks if a value is between two numbers. + * + * @param value The value to check. + * @param min The minimum value. + * @param max The maximum value. + */ +export function inRange(value: number, min: number, max: number): boolean { + return value >= min && value <= max; +} + +/** + * Gets the path to the icon for an item. + * Uses the Project Amber API to get the icon. + * + * @param item The item to get the icon for. + */ +export function itemIcon(item: Item): string { + // Check if the item matches a special case. + if (inRange(item.id, 1001, 1099)) { + return `https://paimon.moe/images/characters/${formatAvatarName(item.name, item.id)}.png`; + } + + switch (item.type) { + default: + return `https://api.ambr.top/assets/UI/UI_${item.icon}.png`; + case ItemType.Furniture: + return `https://api.ambr.top/assets/UI/furniture/UI_${item.icon}.png`; + case ItemType.Reliquary: + return `https://api.ambr.top/assets/UI/reliquary/UI_${item.icon}.png`; + } +} + +/** + * Gets the path to the icon for an entity. + * Uses the Project Amber API to get the icon. + * + * @param entity The entity to get the icon for. Project Amber data required. + */ +export function entityIcon(entity: Entity): string { + return `https://api.ambr.top/assets/UI/monster/UI_MonsterIcon_${entity.internal}.png`; +} + +/** + * Formats a character's name to fit with the reference name. + * Example: Hu Tao -> hu_tao + * + * @param name The character's name. + * @param id The character's ID. + */ +export function formatAvatarName(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 refSwitch: { [key: number]: string } = { + 10000005: "traveler_anemo", + 10000007: "traveler_geo" +}; + +/** + * Gets the route for an item type. + * + * @param type The type of the item. + */ +export function typeToRoute(type: ItemType): string { + switch (type) { + default: + return "material"; + case ItemType.Furniture: + return "furniture"; + case ItemType.Reliquary: + return "reliquary"; + case ItemType.Weapon: + return "weapon"; + } +} + +/** + * Fetches the data for an item. + * Uses the Project Amber API to get the data. + * + * @route GET https://api.ambr.top/v2/EN/{type}/{id} + * @param item The item to fetch the data for. + */ +export async function fetchItemData(item: Item): Promise { + let url = `https://api.ambr.top/v2/EN/(type)/(id)`; + + // Replace the type and ID in the URL. + url = url.replace("(type)", typeToRoute(item.type)); + url = url.replace("(id)", item.id.toString()); + + // Fetch the data. + return fetch(url) + .then((res) => res.json()) + .catch(() => {}); +} + +/** + * Fetches the data for an entity. + * Uses the Project Amber API to get the data. + * + * @route GET https://api.ambr.top/v2/en/monster/{id} + * @param entity The entity to fetch the data for. + */ +export async function fetchEntityData(entity: Entity): Promise { + return fetch(`https://api.ambr.top/v2/en/monster/${entity.id}`) + .then((res) => res.json()) + .catch(() => {}); +} diff --git a/src/handbook/tsconfig.json b/src/handbook/tsconfig.json new file mode 100644 index 000000000..f08be7441 --- /dev/null +++ b/src/handbook/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + "baseUrl": ".", + "paths": { + "@app/*": ["src/*"], + "@backend/*": ["src/backend/*"], + "@css/*": ["src/css/*"], + "@ui/*": ["src/ui/*"], + "@icons/*": ["src/icons/*"], + "@views/*": ["src/ui/views/*"], + "@pages/*": ["src/ui/pages/*"], + "@widgets/*": ["src/ui/widgets/*"], + "@components/*": ["src/ui/components/*"], + "@data/*": ["data/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/src/handbook/tsconfig.node.json b/src/handbook/tsconfig.node.json new file mode 100644 index 000000000..b8afcc8fa --- /dev/null +++ b/src/handbook/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": [ + "vite.config.ts" + ] +} diff --git a/src/handbook/vite.config.ts b/src/handbook/vite.config.ts new file mode 100644 index 000000000..48079b4bd --- /dev/null +++ b/src/handbook/vite.config.ts @@ -0,0 +1,25 @@ +// noinspection JSUnusedGlobalSymbols + +import { defineConfig } from "vite"; + +import react from "@vitejs/plugin-react-swc"; +import tsconfigPaths from "vite-tsconfig-paths"; + +import dsv from "@rollup/plugin-dsv"; +import viteSvgr from "vite-plugin-svgr"; +import { viteSingleFile } from "vite-plugin-singlefile"; + +import postcss from "./cfg/postcss.config.js"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ react(), tsconfigPaths(), dsv(), + viteSvgr(), viteSingleFile() ], + css: { postcss }, + + optimizeDeps: { + exclude: [ + "react-virtualization" + ] + } +}); diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index edef16b7d..1768e94bf 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -1,10 +1,14 @@ package emu.grasscutter; import emu.grasscutter.utils.Position; +import emu.grasscutter.utils.SparseSet; import emu.grasscutter.utils.Utils; import java.util.Arrays; public final class GameConstants { + public static String VERSION = "3.6.0"; + public static final boolean DEBUG = true; + public static final int DEFAULT_TEAMS = 4; public static final int MAX_TEAMS = 10; public static final int MAIN_CHARACTER_MALE = 10000005; @@ -28,9 +32,19 @@ public final class GameConstants { "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener" }; + public static final SparseSet ILLEGAL_WEAPONS = new SparseSet(""" + 10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509, + 13503, 13506, 14411, 14503, 14505, 14508, 15504-15506 + """); + public static final SparseSet ILLEGAL_RELICS = new SparseSet(""" + 20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554 + """); + public static final SparseSet ILLEGAL_ITEMS = new SparseSet(""" + 100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000, + 105001, 105004, 106000-107000, 107011, 108000, 109000-110000, + 115000-130000, 200200-200899, 220050, 220054 + """); public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default"); - public static String VERSION = "3.6.0"; - public static final boolean DEBUG = true; } diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index c05a7d2c3..4fae4a872 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -21,6 +21,7 @@ import emu.grasscutter.server.http.HttpServer; import emu.grasscutter.server.http.dispatch.DispatchHandler; import emu.grasscutter.server.http.dispatch.RegionHandler; import emu.grasscutter.server.http.documentation.DocumentationServerHandler; +import emu.grasscutter.server.http.documentation.HandbookHandler; import emu.grasscutter.server.http.handlers.AnnouncementsHandler; import emu.grasscutter.server.http.handlers.GachaHandler; import emu.grasscutter.server.http.handlers.GenericHandler; @@ -136,6 +137,7 @@ public final class Grasscutter { httpServer.addRouter(DispatchHandler.class); httpServer.addRouter(GachaHandler.class); httpServer.addRouter(DocumentationServerHandler.class); + httpServer.addRouter(HandbookHandler.class); // Start servers. var runMode = Grasscutter.getRunMode(); diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java index 7dc1b928f..bd79a3c0d 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.function.BiConsumer; import java.util.regex.Pattern; +import static emu.grasscutter.GameConstants.*; import static emu.grasscutter.command.CommandHelpers.*; @Command( @@ -42,18 +43,6 @@ public final class GiveCommand implements CommandHandler { Map.entry(constellationRegex, GiveItemParameters::setConstellation), Map.entry(skillLevelRegex, GiveItemParameters::setSkillLevel) ); - private static final SparseSet illegalWeaponIds = new SparseSet(""" - 10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509, - 13503, 13506, 14411, 14503, 14505, 14508, 15504-15506 - """); - private static final SparseSet illegalRelicIds = new SparseSet(""" - 20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554 - """); - private static final SparseSet illegalItemIds = new SparseSet(""" - 100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000, - 105001, 105004, 106000-107000, 107011, 108000, 109000-110000, - 115000-130000, 200200-200899, 220050, 220054 - """); private static Avatar makeAvatar(GiveItemParameters param) { return makeAvatar(param.avatarData, param.lvl, Avatar.getMinPromoteLevel(param.lvl), param.constellation, param.skillLevel); @@ -231,7 +220,7 @@ public final class GiveCommand implements CommandHandler { for (ItemData itemdata : GameData.getItemDataMap().values()) { int id = itemdata.getId(); if (id < 100_000) continue; // Nothing meaningful below this - if (illegalItemIds.contains(id)) continue; + if (ILLEGAL_ITEMS.contains(id)) continue; if (itemdata.isEquip()) continue; GameItem item = new GameItem(itemdata); @@ -251,7 +240,7 @@ public final class GiveCommand implements CommandHandler { for (ItemData itemdata : GameData.getItemDataMap().values()) { int id = itemdata.getId(); if (id < 11100 || id > 16000) continue; // All extant weapons are within this range - if (illegalWeaponIds.contains(id)) continue; + if (ILLEGAL_WEAPONS.contains(id)) continue; if (!itemdata.isEquip()) continue; if (itemdata.getItemType() != ItemType.ITEM_WEAPON) continue; @@ -333,7 +322,7 @@ public final class GiveCommand implements CommandHandler { if (param.lvl < 0) param.lvl = 0; if (param.lvl > 20) param.lvl = 20; param.lvl += 1; - if (illegalRelicIds.contains(param.id)) + if (ILLEGAL_RELICS.contains(param.id)) CommandHandler.sendTranslatedMessage(sender, "commands.give.illegal_relic"); } else { // Suitable for Avatars and Weapons diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java index 195554cdf..4ffa17a7e 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java @@ -10,6 +10,8 @@ import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.world.Scene; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp; @@ -43,11 +45,11 @@ public class DungeonSystem extends BaseGameSystem { var handlerClasses = reflections.getSubTypesOf(clazz); for (var obj : handlerClasses) { - this.registerPacketHandler(map, obj); + this.registerHandler(map, obj); } } - public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { + public void registerHandler(Int2ObjectMap map, Class handlerClass) { try { DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class); @@ -178,5 +180,6 @@ public class DungeonSystem extends BaseGameSystem { // Transfer player back to world player.getWorld().transferPlayerToScene(player, prevScene, prevPos); + player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); } } diff --git a/src/main/java/emu/grasscutter/server/http/documentation/HandbookHandler.java b/src/main/java/emu/grasscutter/server/http/documentation/HandbookHandler.java new file mode 100644 index 000000000..29a49f562 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/http/documentation/HandbookHandler.java @@ -0,0 +1,173 @@ +package emu.grasscutter.server.http.documentation; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.Grasscutter.ServerRunMode; +import emu.grasscutter.data.GameData; +import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.server.http.Router; +import emu.grasscutter.utils.FileUtils; +import emu.grasscutter.utils.objects.HandbookBody; +import io.javalin.Javalin; +import io.javalin.http.Context; + +import static emu.grasscutter.config.Configuration.HANDBOOK; + +/** Handles requests for the new GM Handbook. */ +public final class HandbookHandler implements Router { + private final byte[] handbook; + private final boolean serve; + + /** + * Constructor for the handbook router. + * Enables serving the handbook if the handbook file is found. + */ + public HandbookHandler() { + this.handbook = FileUtils.readResource("/handbook.html"); + this.serve = HANDBOOK.enable && this.handbook.length > 0; + } + + @Override + public void applyRoutes(Javalin javalin) { + if (!this.serve) return; + + // The handbook content. (built from src/handbook) + javalin.get("/handbook", this::serveHandbook); + + // Handbook control routes. + javalin.post("/handbook/avatar", this::grantAvatar); + javalin.post("/handbook/item", this::giveItem); + } + + /** + * @return True if the server can execute handbook commands. + */ + private boolean controlSupported() { + return HANDBOOK.enable && + Grasscutter.getRunMode() == ServerRunMode.HYBRID; + } + + /** + * Serves the handbook if it is found. + * + * @route GET /handbook + * @param ctx The Javalin request context. + */ + private void serveHandbook(Context ctx) { + if (!this.serve) { + ctx.status(500).result("Handbook not found."); + } else { + ctx.contentType("text/html").result(this.handbook); + } + } + + /** + * Grants the avatar to the user. + * + * @route POST /handbook/avatar + * @param ctx The Javalin request context. + */ + private void grantAvatar(Context ctx) { + if (!this.controlSupported()) { + ctx.status(500).result("Handbook control not supported."); + return; + } + + // Parse the request body into a class. + var request = ctx.bodyAsClass(HandbookBody.GrantAvatar.class); + // Validate the request. + if (request.getPlayer() == null || request.getAvatar() == null) { + ctx.status(400).result("Invalid request."); + return; + } + + try { + // Parse the requested player. + var playerId = Integer.parseInt(request.getPlayer()); + var player = Grasscutter.getGameServer().getPlayerByUid(playerId); + + // Parse the requested avatar. + var avatarId = Integer.parseInt(request.getAvatar()); + var avatarData = GameData.getAvatarDataMap().get(avatarId); + + // Validate the request. + if (player == null || avatarData == null) { + ctx.status(400).result("Invalid player UID or avatar ID."); + return; + } + + // Create the new avatar. + var avatar = new Avatar(avatarData); + avatar.setLevel(request.getLevel()); + avatar.setPromoteLevel(Avatar.getMinPromoteLevel(avatar.getLevel())); + avatar.getSkillDepot().getSkillsAndEnergySkill().forEach(id -> + avatar.setSkillLevel(id, request.getTalentLevels())); + avatar.forceConstellationLevel(request.getConstellations()); + avatar.recalcStats(true); avatar.save(); + + player.addAvatar(avatar); // Add the avatar. + ctx.json(HandbookBody.Response.builder() + .status(200) + .message("Avatar granted.") + .build()); + } catch (NumberFormatException ignored) { + ctx.status(500).result("Invalid player UID or avatar ID."); + } catch (Exception exception) { + ctx.status(500).result("An error occurred while granting the avatar."); + Grasscutter.getLogger().debug("A handbook command error occurred.", exception); + } + } + + /** + * Gives an item to the user. + * + * @route POST /handbook/item + * @param ctx The Javalin request context. + */ + private void giveItem(Context ctx) { + if (!this.controlSupported()) { + ctx.status(500).result("Handbook control not supported."); + return; + } + + // Parse the request body into a class. + var request = ctx.bodyAsClass(HandbookBody.GiveItem.class); + // Validate the request. + if (request.getPlayer() == null || request.getItem() == null) { + ctx.status(400).result("Invalid request."); + return; + } + + try { + // Parse the requested player. + var playerId = Integer.parseInt(request.getPlayer()); + var player = Grasscutter.getGameServer().getPlayerByUid(playerId); + + // Parse the requested item. + var itemId = Integer.parseInt(request.getItem()); + var itemData = GameData.getItemDataMap().get(itemId); + + // Validate the request. + if (player == null || itemData == null) { + ctx.status(400).result("Invalid player UID or item ID."); + return; + } + + // Create the new item stack. + var itemStack = new GameItem(itemData, request.getAmount()); + // Add the item to the inventory. + player.getInventory().addItem(itemStack, ActionReason.Gm); + + ctx.json(HandbookBody.Response.builder() + .status(200) + .message("Item granted.") + .build()); + } catch (NumberFormatException ignored) { + ctx.status(500).result("Invalid player UID or item ID."); + } catch (Exception exception) { + ctx.status(500).result("An error occurred while granting the item."); + Grasscutter.getLogger().debug("A handbook command error occurred.", exception); + } + } +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketWindSeedClientNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketWindSeedClientNotify.java new file mode 100644 index 000000000..aa7439145 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketWindSeedClientNotify.java @@ -0,0 +1,18 @@ +package emu.grasscutter.server.packet.send; + +import com.google.protobuf.ByteString; +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.WindSeedClientNotifyOuterClass.WindSeedClientNotify; +import emu.grasscutter.net.proto.WindSeedClientNotifyOuterClass.WindSeedClientNotify.AreaNotify; + +public final class PacketWindSeedClientNotify extends BasePacket { + public PacketWindSeedClientNotify(byte[] compiledLua) { + super(PacketOpcodes.WindSeedClientNotify); + + this.setData(WindSeedClientNotify.newBuilder() + .setAreaNotify(AreaNotify.newBuilder() + .setAreaId(1).setAreaType(1) + .setAreaCode(ByteString.copyFrom(compiledLua)))); + } +} diff --git a/src/main/java/emu/grasscutter/tools/Dumpers.java b/src/main/java/emu/grasscutter/tools/Dumpers.java index 75df3b17e..c7e3bf752 100644 --- a/src/main/java/emu/grasscutter/tools/Dumpers.java +++ b/src/main/java/emu/grasscutter/tools/Dumpers.java @@ -1,16 +1,325 @@ package emu.grasscutter.tools; -import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp; -import emu.grasscutter.net.proto.GetShopRspOuterClass.GetShopRsp; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.Command.TargetRequirement; +import emu.grasscutter.command.CommandMap; +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.ResourceLoader; +import emu.grasscutter.game.inventory.ItemType; +import emu.grasscutter.game.props.SceneType; +import emu.grasscutter.utils.JsonUtils; +import emu.grasscutter.utils.Language; +import lombok.AllArgsConstructor; -public final class Dumpers { - public static void extractBanner(byte[] data) throws Exception { - GetGachaInfoRsp proto = GetGachaInfoRsp.parseFrom(data); - System.out.println(proto); +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public interface Dumpers { + // See `src/handbook/data/README.md` for attributions. + + /** + * Fetches the description of a command. + * + * @param locale The locale to use. + * @param command The command to get the description of. + * @return The description of the command. + */ + private static String commandDescription(String locale, Command command) { + try { + // Get the language by the locale. + var language = Language.getLanguage(locale); + if (language == null) throw new IllegalArgumentException("Invalid language."); + + return language.get("commands." + command.label() + ".description"); + } catch (IllegalArgumentException ignored) { + return command.label(); + } } - public static void extractShop(byte[] data) throws Exception { - GetShopRsp proto = GetShopRsp.parseFrom(data); - System.out.println(proto); + /** + * Encodes the dump into comma separated values. + * + * @param dump The dump to encode. + * @return The encoded dump. + */ + private static String miniEncode(Map dump) { + return dump.entrySet().stream() + .map(entry -> entry.getKey() + "," + entry.getValue().toString()) + .collect(Collectors.joining("\n")); + } + + /** + * Dumps all commands to a JSON file. + * + * @param locale The language to dump the commands in. + */ + static void dumpCommands(String locale) { + // Check that commands are registered. + var commandMap = CommandMap.getInstance(); + if (commandMap == null) commandMap = new CommandMap(true); + + // Convert all registered commands to an info map. + var dump = new HashMap(); + commandMap.getAnnotationsAsList().forEach(command -> { + var description = Dumpers.commandDescription(locale, command); + var labels = new ArrayList(){{ + this.add(command.label()); + this.addAll(List.of(command.aliases())); + }}; + + // Add the command info to the list. + dump.put(command.label(), new CommandInfo( + labels, description, List.of(command.usage()), List.of( + command.permission(), command.permissionTargeted()), + command.targetRequirement())); + }); + + try { + // Create a file for the dump. + var file = new File("commands.json"); + if (file.exists() && !file.delete()) + throw new RuntimeException("Failed to delete file."); + if (!file.exists() && !file.createNewFile()) + throw new RuntimeException("Failed to create file."); + + // Write the dump to the file. + Files.writeString(file.toPath(), JsonUtils.encode(dump)); + } catch (IOException ignored) { + throw new RuntimeException("Failed to write to file."); + } + } + + /** + * Dumps all avatars to a JSON file. + * + * @param locale The language to dump the avatars in. + */ + static void dumpAvatars(String locale) { + // Reload resources. + ResourceLoader.loadAll(); + Language.loadTextMaps(); + + // Convert all known avatars to an avatar map. + var dump = new HashMap(); + GameData.getAvatarDataMap().forEach((id, avatar) -> { + var langHash = avatar.getNameTextMapHash(); + dump.put(id, new AvatarInfo( + langHash == 0 ? avatar.getName() : Language.getTextMapKey(langHash).get(locale), + avatar.getQualityType().equals("QUALITY_PURPLE") ? Quality.EPIC : Quality.LEGENDARY + )); + }); + + try { + // Create a file for the dump. + var file = new File("avatars.csv"); + if (file.exists() && !file.delete()) + throw new RuntimeException("Failed to delete file."); + if (!file.exists() && !file.createNewFile()) + throw new RuntimeException("Failed to create file."); + + // Write the dump to the file. + Files.writeString(file.toPath(), Dumpers.miniEncode(dump)); + } catch (IOException ignored) { + throw new RuntimeException("Failed to write to file."); + } + } + + /** + * Dumps all items to a JSON file. + * + * @param locale The language to dump the items in. + */ + static void dumpItems(String locale) { + // Reload resources. + ResourceLoader.loadAll(); + Language.loadTextMaps(); + + // Convert all known items to an item map. + var originalDump = new ArrayList(); + GameData.getItemDataMap().forEach((id, item) -> originalDump.add(new ItemInfo(id, + Language.getTextMapKey(item.getNameTextMapHash()).get(locale), + Quality.from(item.getRankLevel()), item.getItemType(), + item.getIcon().length() > 0 ? item.getIcon().substring(3) : "" + ))); + + // Create a new dump with filtered duplicates. + var names = new ArrayList(); + var dump = new HashMap(); + originalDump.forEach(item -> { + // Validate the item. + if (item.name.contains("[CHS]")) return; + if (names.contains(item.name)) return; + if (dump.containsKey(item.id)) return; + // Add the item to the dump. + names.add(item.name); + dump.put(item.id, item); + }); + + try { + // Create a file for the dump. + var file = new File("items.csv"); + if (file.exists() && !file.delete()) + throw new RuntimeException("Failed to delete file."); + if (!file.exists() && !file.createNewFile()) + throw new RuntimeException("Failed to create file."); + + // Write the dump to the file. + Files.writeString(file.toPath(), Dumpers.miniEncode(dump)); + } catch (IOException ignored) { + throw new RuntimeException("Failed to write to file."); + } + } + + /** + * Dumps all scenes to a JSON file. + */ + static void dumpScenes() { + // Reload resources. + ResourceLoader.loadAll(); + Language.loadTextMaps(); + + // Convert all known scenes to a scene map. + var dump = new HashMap(); + GameData.getSceneDataMap().forEach((id, scene) -> + dump.put(id, new SceneInfo(scene.getScriptData(), scene.getSceneType()))); + + try { + // Create a file for the dump. + var file = new File("scenes.csv"); + if (file.exists() && !file.delete()) + throw new RuntimeException("Failed to delete file."); + if (!file.exists() && !file.createNewFile()) + throw new RuntimeException("Failed to create file."); + + // Write the dump to the file. + Files.writeString(file.toPath(), Dumpers.miniEncode(dump)); + } catch (IOException ignored) { + throw new RuntimeException("Failed to write to file."); + } + } + + /** + * Dumps all entities to a JSON file. + * + * @param locale The language to dump the entities in. + */ + static void dumpEntities(String locale) { + // Reload resources. + ResourceLoader.loadAll(); + Language.loadTextMaps(); + + // Convert all known avatars to an avatar map. + var dump = new HashMap(); + GameData.getMonsterDataMap().forEach((id, monster) -> { + var langHash = monster.getNameTextMapHash(); + dump.put(id, new EntityInfo( + langHash == 0 ? monster.getMonsterName() : + Language.getTextMapKey(langHash).get(locale), + monster.getMonsterName() + )); + }); + + try { + // Create a file for the dump. + var file = new File("entities.csv"); + if (file.exists() && !file.delete()) + throw new RuntimeException("Failed to delete file."); + if (!file.exists() && !file.createNewFile()) + throw new RuntimeException("Failed to create file."); + + // Write the dump to the file. + Files.writeString(file.toPath(), Dumpers.miniEncode(dump)); + } catch (IOException ignored) { + throw new RuntimeException("Failed to write to file."); + } + } + + @AllArgsConstructor + class CommandInfo { + public List name; + public String description; + public List usage; + public List permission; + public TargetRequirement target; + } + + @AllArgsConstructor + class AvatarInfo { + public String name; + public Quality quality; + + @Override + public String toString() { + return this.name + "," + + this.quality; + } + } + + @AllArgsConstructor + class ItemInfo { + public Integer id; + public String name; + public Quality quality; + public ItemType type; + public String icon; + + @Override + public String toString() { + return this.name + "," + + this.quality + "," + + this.type + "," + + this.icon; + } + } + + @AllArgsConstructor + class SceneInfo { + public String identifier; + public SceneType type; + + @Override + public String toString() { + return this.identifier + "," + + this.type; + } + } + + @AllArgsConstructor + class EntityInfo { + public String name; + public String internal; + + @Override + public String toString() { + return this.name + "," + + this.internal; + } + } + + enum Quality { + LEGENDARY, EPIC, RARE, UNCOMMON, COMMON, UNKNOWN; + + /** + * Convert a rank level to a quality. + * + * @param rankLevel The rank level to convert. + * @return The quality. + */ + static Quality from(int rankLevel) { + return switch (rankLevel) { + case 0 -> UNKNOWN; + case 1 -> COMMON; + case 2 -> UNCOMMON; + case 3 -> RARE; + case 4 -> EPIC; + default -> LEGENDARY; + }; + } } } diff --git a/src/main/java/emu/grasscutter/utils/FileUtils.java b/src/main/java/emu/grasscutter/utils/FileUtils.java index 4c7897042..efde279cd 100644 --- a/src/main/java/emu/grasscutter/utils/FileUtils.java +++ b/src/main/java/emu/grasscutter/utils/FileUtils.java @@ -209,7 +209,7 @@ public final class FileUtils { return is.readAllBytes(); } catch (Exception exception) { Grasscutter.getLogger().warn("Failed to read resource: " + resourcePath); - exception.printStackTrace(); + Grasscutter.getLogger().debug("Failed to load resource: " + resourcePath, exception); } return new byte[0]; diff --git a/src/main/java/emu/grasscutter/utils/StartupArguments.java b/src/main/java/emu/grasscutter/utils/StartupArguments.java index c15cf1006..13392fd36 100644 --- a/src/main/java/emu/grasscutter/utils/StartupArguments.java +++ b/src/main/java/emu/grasscutter/utils/StartupArguments.java @@ -10,6 +10,8 @@ import emu.grasscutter.Grasscutter.ServerRunMode; import emu.grasscutter.net.packet.PacketOpcodesUtils; import java.util.Map; import java.util.function.Function; + +import emu.grasscutter.tools.Dumpers; import org.slf4j.LoggerFactory; /** A parser for start-up arguments. */ @@ -47,6 +49,7 @@ public final class StartupArguments { SERVER.http.encryption.useEncryption = false; return false; }, + "-dump", StartupArguments::dump, // Aliases. "-v", StartupArguments::printVersion, @@ -124,4 +127,38 @@ public final class StartupArguments { Grasscutter.getLogger().debug("The logger is now running in debug mode."); return false; } + + /** + * Dumps the specified information. + * + * @param parameter The parameter to dump. + * @return True to exit early. + */ + private static boolean dump(String parameter) { + // Parse the parameter. + if (!parameter.contains(",")) { + Grasscutter.getLogger().error("Dumper usage: -dump=,"); + return true; + } + + var split = parameter.split(","); + var content = split[0]; + var language = split[1]; + + try { + switch (content.toLowerCase()) { + case "commands" -> Dumpers.dumpCommands(language); + case "avatars" -> Dumpers.dumpAvatars(language); + case "items" -> Dumpers.dumpItems(language); + case "scenes" -> Dumpers.dumpScenes(); + case "entities" -> Dumpers.dumpEntities(language); + } + + Grasscutter.getLogger().info("Finished dumping."); + } catch (Exception exception) { + Grasscutter.getLogger().error("Unable to complete dump.", exception); + } + + return true; + } } diff --git a/src/main/java/emu/grasscutter/utils/objects/HandbookBody.java b/src/main/java/emu/grasscutter/utils/objects/HandbookBody.java new file mode 100644 index 000000000..f0f76a161 --- /dev/null +++ b/src/main/java/emu/grasscutter/utils/objects/HandbookBody.java @@ -0,0 +1,32 @@ +package emu.grasscutter.utils.objects; + +import lombok.Builder; +import lombok.Getter; + +/** HTTP request object for handbook controls. */ +@SuppressWarnings("FieldMayBeFinal") +public interface HandbookBody { + @Builder + class Response { + private int status; + private String message; + } + + @Getter + class GrantAvatar { + private String player; // Parse into online player ID. + private String avatar; // Parse into avatar ID. + + private int level = 90; // Range between 1 - 90. + private int constellations = 6; // Range between 0 - 6. + private int talentLevels = 10; // Range between 1 - 15. + } + + @Getter + class GiveItem { + private String player; // Parse into online player ID. + private String item; // Parse into item ID. + + private int amount = 1; // Range between 1 - Long.MAX_VALUE. + } +}