That's a spicy meatball mammamia
This commit is contained in:
parent
1ec48eaf65
commit
efb127dedd
29 changed files with 536 additions and 34 deletions
33
.eslintrc.js
Normal file
33
.eslintrc.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2020: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
"airbnb-base",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
],
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
plugins: ["@typescript-eslint", "prettier", "react-hooks"],
|
||||||
|
rules: {
|
||||||
|
"prettier/prettier": "error",
|
||||||
|
"one-var": "off", // WHO CARES?????
|
||||||
|
"no-use-before-define": "off", // YOU ARE WRONG
|
||||||
|
"import/extensions": "off",
|
||||||
|
"import/no-unresolved": "off",
|
||||||
|
"no-param-reassign": "off",
|
||||||
|
"no-alert": "off",
|
||||||
|
"no-console": "off",
|
||||||
|
"func-names": "off",
|
||||||
|
"dot-notation": ["error", { allowPattern: "^[A-Z][a-z]+$" }],
|
||||||
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"ts-expect-error": "allow-with-description",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"react-hooks/rules-of-hooks": "error",
|
||||||
|
"react-hooks/exhaustive-deps": "warn",
|
||||||
|
},
|
||||||
|
};
|
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"singleQuote": false,
|
||||||
|
"endOfLine": "auto"
|
||||||
|
}
|
17
assets/images/logos/logo.svg
Normal file
17
assets/images/logos/logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 14 KiB |
1
assets/images/logos/spinner.svg
Normal file
1
assets/images/logos/spinner.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.1 KiB |
|
@ -5,16 +5,22 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inlet/react-pixi": "^5.1.4",
|
"@inlet/react-pixi": "^5.1.4",
|
||||||
|
"@reduxjs/toolkit": "^1.4.0",
|
||||||
"@types/howler": "^2.2.1",
|
"@types/howler": "^2.2.1",
|
||||||
"@types/react": "^16.9.49",
|
"@types/react": "^16.9.49",
|
||||||
"@types/react-dom": "^16.9.8",
|
"@types/react-dom": "^16.9.8",
|
||||||
|
"@types/react-redux": "^7.1.9",
|
||||||
"animejs": "^3.2.0",
|
"animejs": "^3.2.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.1.2",
|
||||||
"hotkeys-js": "^3.8.1",
|
"hotkeys-js": "^3.8.1",
|
||||||
"howler": "^2.2.0",
|
"howler": "^2.2.0",
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
"pixi.js": "^5.3.3",
|
"pixi.js": "^5.3.3",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
"react-redux": "^7.2.1",
|
||||||
|
"redux": "^4.0.5",
|
||||||
|
"redux-devtools-extension": "^2.13.8",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
29
src/game/lib/loader.tsx
Normal file
29
src/game/lib/loader.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { Loader, ILoaderOptions } from "pixi.js";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export type ResourceList = Record<
|
||||||
|
string,
|
||||||
|
string | { name: string; options: ILoaderOptions }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export default function useLoader(resources: ResourceList) {
|
||||||
|
const loader = new Loader();
|
||||||
|
|
||||||
|
const [state, setState] = useState({ loaded: false, resources: null });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
for (const res in resources) {
|
||||||
|
const param = resources[res];
|
||||||
|
if (typeof param === "string") {
|
||||||
|
loader.add(res, param);
|
||||||
|
} else {
|
||||||
|
loader.add(res, param.name, param.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loader.load((loader, resources) => {
|
||||||
|
setState({ loaded: true, resources });
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
32
src/game/scenes/Game.tsx
Normal file
32
src/game/scenes/Game.tsx
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import React, { Fragment } from "react";
|
||||||
|
import useLoader from "~game/lib/Loader";
|
||||||
|
import InGameSpaceBG from "./backgrounds/InGameSpaceBG";
|
||||||
|
|
||||||
|
// Resources, this will make TS go crazy!
|
||||||
|
|
||||||
|
//@ts-expect-error Image resource
|
||||||
|
import NoiseSpaceFine from "~/../assets/images/noise/space_fine.png";
|
||||||
|
//@ts-expect-error Image resource
|
||||||
|
import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png";
|
||||||
|
|
||||||
|
export default function Game() {
|
||||||
|
const { loaded, resources } = useLoader({
|
||||||
|
bg_fine: NoiseSpaceFine,
|
||||||
|
bg_sparse: NoiseSpaceSparse,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
return <Fragment></Fragment>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<InGameSpaceBG
|
||||||
|
textures={{
|
||||||
|
noise_fine: resources.bg_fine,
|
||||||
|
noise_sparse: resources.bg_sparse,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
5
src/game/scenes/LoadingScreen.tsx
Normal file
5
src/game/scenes/LoadingScreen.tsx
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import React, { Fragment } from "react";
|
||||||
|
|
||||||
|
export default function LoadingScreen() {
|
||||||
|
return <Fragment></Fragment>;
|
||||||
|
}
|
35
src/game/scenes/MapEditor.tsx
Normal file
35
src/game/scenes/MapEditor.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { Fragment } from "react";
|
||||||
|
import useLoader from "~game/lib/Loader";
|
||||||
|
import InGameSpaceBG from "./backgrounds/InGameSpaceBG";
|
||||||
|
|
||||||
|
// Resources, this will make TS go crazy!
|
||||||
|
|
||||||
|
//@ts-expect-error Image resource
|
||||||
|
import NoiseSpaceFine from "~/../assets/images/noise/space_fine.png";
|
||||||
|
//@ts-expect-error Image resource
|
||||||
|
import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png";
|
||||||
|
import LoadingScreen from "./LoadingScreen";
|
||||||
|
import useUILayer from "~ui/utils/useLayer";
|
||||||
|
|
||||||
|
export default function MapEditor() {
|
||||||
|
const { loaded, resources } = useLoader({
|
||||||
|
bg_fine: NoiseSpaceFine,
|
||||||
|
bg_sparse: NoiseSpaceSparse,
|
||||||
|
});
|
||||||
|
const id = useUILayer({ type: "MapEditor" }, loaded);
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
return <LoadingScreen />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<InGameSpaceBG
|
||||||
|
textures={{
|
||||||
|
noise_fine: resources.bg_fine,
|
||||||
|
noise_sparse: resources.bg_sparse,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
10
src/game/scenes/TitleScreen.tsx
Normal file
10
src/game/scenes/TitleScreen.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import React, { Fragment } from "react";
|
||||||
|
import MenuBackground from "./backgrounds/MenuBackground";
|
||||||
|
|
||||||
|
export default function TitleScreen() {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<MenuBackground />
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
30
src/game/scenes/backgrounds/InGameSpaceBG.tsx
Normal file
30
src/game/scenes/backgrounds/InGameSpaceBG.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { Sprite, useApp, useTick } from "@inlet/react-pixi";
|
||||||
|
import InGameSpace, { SpaceTextures } from "~graphics/filters/InGameSpace";
|
||||||
|
|
||||||
|
export interface InGameSpaceBGProps {
|
||||||
|
textures: SpaceTextures;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function InGameSpaceBG({ textures }: InGameSpaceBGProps) {
|
||||||
|
const app = useApp();
|
||||||
|
const scale = 1;
|
||||||
|
const menubg = new InGameSpace(app.renderer, scale, textures);
|
||||||
|
|
||||||
|
useTick((delta) => {
|
||||||
|
menubg.update(delta);
|
||||||
|
menubg.render();
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
menubg.rescale(scale);
|
||||||
|
};
|
||||||
|
app.renderer.on("resize", handleResize);
|
||||||
|
return () => {
|
||||||
|
app.renderer.off("resize", handleResize);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Sprite texture={menubg.texture} scale={{ x: scale, y: scale }} />;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from "react";
|
import React, { useEffect } from "react";
|
||||||
import MenuBackgroundFilter from "../graphics/filters/MenuBackground";
|
import MenuBackgroundFilter from "~graphics/filters/MenuBackground";
|
||||||
import { Sprite, useApp, useTick } from "@inlet/react-pixi";
|
import { Sprite, useApp, useTick } from "@inlet/react-pixi";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
|
@ -12,8 +12,14 @@ export default function () {
|
||||||
menubg.render();
|
menubg.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
useEffect(() => {
|
||||||
menubg.rescale(scale);
|
const handleResize = () => {
|
||||||
|
menubg.rescale(scale);
|
||||||
|
};
|
||||||
|
app.renderer.on("resize", handleResize);
|
||||||
|
return () => {
|
||||||
|
app.renderer.off("resize", handleResize);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return <Sprite texture={menubg.texture} scale={{ x: scale, y: scale }} />;
|
return <Sprite texture={menubg.texture} scale={{ x: scale, y: scale }} />;
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { Filter, Renderer, Texture, WRAP_MODES } from "pixi.js";
|
||||||
|
import RTTShader from "../utils/RTTShader";
|
||||||
|
|
||||||
|
//@ts-expect-error Frag file
|
||||||
|
import filter_src from "./frag/InGameSpace.frag";
|
||||||
|
|
||||||
|
export interface SpaceTextures {
|
||||||
|
noise_sparse;
|
||||||
|
noise_fine;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class InGameSpaceFilter extends RTTShader {
|
||||||
|
private elapsed: number;
|
||||||
|
private filter: Filter;
|
||||||
|
|
||||||
|
constructor(renderer: Renderer, scale: number, textures: SpaceTextures) {
|
||||||
|
const noise_sparse = textures.noise_sparse.texture as Texture;
|
||||||
|
const noise_fine = textures.noise_fine.texture as Texture;
|
||||||
|
|
||||||
|
noise_sparse.baseTexture.wrapMode = WRAP_MODES.REPEAT;
|
||||||
|
noise_fine.baseTexture.wrapMode = WRAP_MODES.REPEAT;
|
||||||
|
|
||||||
|
const filter = new Filter(null, filter_src, {
|
||||||
|
time: 0,
|
||||||
|
ires: [renderer.width / scale, renderer.height / scale],
|
||||||
|
noise_sparse,
|
||||||
|
noise_fine,
|
||||||
|
scroll_speed: 0,
|
||||||
|
warp_boost: 0,
|
||||||
|
warp_opacity: 0,
|
||||||
|
});
|
||||||
|
super(renderer, filter, scale);
|
||||||
|
this.elapsed = 0;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
rescale(scale: number) {
|
||||||
|
super.rescale(scale);
|
||||||
|
this.filter.uniforms.ires = [
|
||||||
|
this.renderer.width / scale,
|
||||||
|
this.renderer.height / scale,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
update(delta: number) {
|
||||||
|
this.filter.uniforms.time = this.elapsed;
|
||||||
|
this.elapsed += delta / 60;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import * as PIXI from "pixi.js";
|
import { Filter, Renderer } from "pixi.js";
|
||||||
import RTTShader from "../utils/RTTShader";
|
import RTTShader from "../utils/RTTShader";
|
||||||
|
|
||||||
//@ts-expect-error Frag file
|
//@ts-expect-error Frag file
|
||||||
|
@ -6,10 +6,10 @@ import filter_src from "./frag/MenuBackground.frag";
|
||||||
|
|
||||||
export default class MenuBackgroundFilter extends RTTShader {
|
export default class MenuBackgroundFilter extends RTTShader {
|
||||||
private elapsed: number;
|
private elapsed: number;
|
||||||
private filter: PIXI.Filter;
|
private filter: Filter;
|
||||||
|
|
||||||
constructor(renderer: PIXI.Renderer, scale: number) {
|
constructor(renderer: Renderer, scale: number) {
|
||||||
const filter = new PIXI.Filter(null, filter_src, {
|
const filter = new Filter(null, filter_src, {
|
||||||
iTime: 0,
|
iTime: 0,
|
||||||
iResolution: [renderer.width / scale, renderer.height / scale],
|
iResolution: [renderer.width / scale, renderer.height / scale],
|
||||||
});
|
});
|
|
@ -3,26 +3,26 @@ precision mediump float;
|
||||||
uniform sampler2D noise_sparse;
|
uniform sampler2D noise_sparse;
|
||||||
uniform sampler2D noise_fine;
|
uniform sampler2D noise_fine;
|
||||||
|
|
||||||
uniform vec2 iResolution;
|
uniform vec2 ires;
|
||||||
uniform float scroll_speed;
|
uniform float scroll_speed;
|
||||||
uniform float warp_boost;
|
uniform float warp_boost;
|
||||||
uniform float warp_opacity;
|
uniform float warp_opacity;
|
||||||
uniform float time;
|
uniform float time;
|
||||||
|
|
||||||
const float noise_sparse_scale = 0.0007;
|
const float noise_sparse_scale = 0.0007;
|
||||||
const float noise_fine_scale = 0.003;
|
const float noise_fine_scale = 0.004;
|
||||||
const float warp_clouds_scale = 0.0003;
|
const float warp_clouds_scale = 0.0003;
|
||||||
const vec2 scroll_dir = vec2(1,0);
|
const vec2 scroll_dir = vec2(1,0);
|
||||||
const vec2 blink_scroll = vec2(50.0, 0);
|
const vec2 blink_scroll = vec2(50.0, 0);
|
||||||
const float PI = 3.1415;
|
const float PI = 3.1415;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv=gl_FragCoord.xy/iResolution.xy;
|
vec2 uv=gl_FragCoord.xy/ires.xy;
|
||||||
float scroll = scroll_speed * time;
|
float scroll = scroll_speed * time;
|
||||||
float sparse = texture2D(noise_sparse, (gl_FragCoord.xy + scroll_dir * scroll)*noise_sparse_scale).r;
|
float sparse = texture2D(noise_sparse, (gl_FragCoord.xy + scroll_dir * scroll)*noise_sparse_scale).r;
|
||||||
sparse = ((sparse * sparse) - 0.2) * 1.2;
|
sparse = ((sparse * sparse) - 0.2) * 1.2;
|
||||||
float fine = texture2D(noise_fine, (gl_FragCoord.xy + scroll_dir * scroll)*noise_fine_scale).r;
|
float fine = texture2D(noise_fine, (gl_FragCoord.xy + scroll_dir * scroll)*noise_fine_scale).r;
|
||||||
fine = fine - 0.6;
|
fine = fine - 0.62;
|
||||||
if (fine > 0.) {
|
if (fine > 0.) {
|
||||||
fine = fine * 10.0;
|
fine = fine * 10.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import * as PIXI from "pixi.js";
|
import { RenderTexture, Container, Renderer, Filter } from "pixi.js";
|
||||||
|
|
||||||
export default class RTTShader {
|
export default class RTTShader {
|
||||||
readonly texture: PIXI.RenderTexture;
|
readonly texture: RenderTexture;
|
||||||
readonly container: PIXI.Container;
|
readonly container: Container;
|
||||||
readonly renderer: PIXI.Renderer;
|
readonly renderer: Renderer;
|
||||||
|
|
||||||
constructor(renderer: PIXI.Renderer, filter: PIXI.Filter, scale: number = 2) {
|
constructor(renderer: Renderer, filter: Filter, scale: number = 2) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.texture = PIXI.RenderTexture.create({
|
this.texture = RenderTexture.create({
|
||||||
width: this.renderer.width / scale,
|
width: this.renderer.width / scale,
|
||||||
height: this.renderer.height / scale,
|
height: this.renderer.height / scale,
|
||||||
});
|
});
|
||||||
this.container = new PIXI.Container();
|
this.container = new Container();
|
||||||
this.container.filterArea = this.texture.frame;
|
this.container.filterArea = this.texture.frame;
|
||||||
this.container.filters = [filter];
|
this.container.filters = [filter];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import * as React from "react";
|
|
||||||
import * as PIXI from "pixi.js";
|
import * as PIXI from "pixi.js";
|
||||||
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { Stage, useApp } from "@inlet/react-pixi";
|
import { Provider } from "react-redux";
|
||||||
import MenuBackground from "./game/MenuBackground";
|
import { Stage } from "@inlet/react-pixi";
|
||||||
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
|
import UI from "~ui/UI";
|
||||||
|
import reducer from "~store/reducer";
|
||||||
|
import MapEditor from "~game/scenes/MapEditor";
|
||||||
|
|
||||||
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
|
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
|
||||||
|
|
||||||
|
@ -13,14 +17,18 @@ const mounted = (app: PIXI.Application) => {
|
||||||
app.queueResize();
|
app.queueResize();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const store = configureStore({ reducer });
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Stage options={{ resolution: 1, resizeTo: window }} onMount={mounted}>
|
<Stage options={{ resolution: 1, resizeTo: window }} onMount={mounted}>
|
||||||
<MenuBackground />
|
<Provider store={store}>
|
||||||
|
<MapEditor />
|
||||||
|
</Provider>
|
||||||
</Stage>
|
</Stage>
|
||||||
<div id="ui">
|
<Provider store={store}>
|
||||||
<p>Hello!</p>
|
<UI />
|
||||||
</div>
|
</Provider>
|
||||||
</React.Fragment>,
|
</React.Fragment>,
|
||||||
document.getElementById("app")
|
document.getElementById("app")
|
||||||
);
|
);
|
||||||
|
|
6
src/store/reducer.ts
Normal file
6
src/store/reducer.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { combineReducers } from "@reduxjs/toolkit";
|
||||||
|
import uiReducer from "./ui/reducer";
|
||||||
|
|
||||||
|
const reducer = combineReducers({ ui: uiReducer });
|
||||||
|
|
||||||
|
export default reducer;
|
5
src/store/state.ts
Normal file
5
src/store/state.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import UIStore from "./ui/state";
|
||||||
|
|
||||||
|
export interface GameStore {
|
||||||
|
ui: UIStore;
|
||||||
|
}
|
56
src/store/ui/reducer.ts
Normal file
56
src/store/ui/reducer.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import { UILayer } from "~ui/UI";
|
||||||
|
import UIStore from "./state";
|
||||||
|
|
||||||
|
const initialState: UIStore = {
|
||||||
|
layers: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AddLayerPayload {
|
||||||
|
id: string;
|
||||||
|
data: UILayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LayerActionPayload {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uiSlice = createSlice({
|
||||||
|
name: "ui",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
addLayer(state, action: PayloadAction<AddLayerPayload>) {
|
||||||
|
state.layers.push({ ...action.payload, visible: false });
|
||||||
|
},
|
||||||
|
removeLayer(state, action: PayloadAction<LayerActionPayload>) {
|
||||||
|
const index = state.layers.findIndex(
|
||||||
|
(layer) => layer.id == action.payload.id
|
||||||
|
);
|
||||||
|
if (index < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.layers.splice(index, 1);
|
||||||
|
},
|
||||||
|
showLayer(state, action: PayloadAction<LayerActionPayload>) {
|
||||||
|
const index = state.layers.findIndex(
|
||||||
|
(layer) => layer.id == action.payload.id
|
||||||
|
);
|
||||||
|
if (index < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.layers[index].visible = true;
|
||||||
|
},
|
||||||
|
hideLayer(state, action: PayloadAction<LayerActionPayload>) {
|
||||||
|
const index = state.layers.findIndex(
|
||||||
|
(layer) => layer.id == action.payload.id
|
||||||
|
);
|
||||||
|
if (index < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.layers[index].visible = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { addLayer, removeLayer, showLayer, hideLayer } = uiSlice.actions;
|
||||||
|
export default uiSlice.reducer;
|
5
src/store/ui/state.ts
Normal file
5
src/store/ui/state.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { LayerList } from "~ui/UI";
|
||||||
|
|
||||||
|
export default interface UIStore {
|
||||||
|
layers: LayerList;
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
import * as React from "react";
|
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
|
|
||||||
ReactDOM.render(<p>Hello</p>, document.getElementById("ui"));
|
|
13
src/ui/MapEditor.tsx
Normal file
13
src/ui/MapEditor.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export interface MapEditorLayer {
|
||||||
|
type: "MapEditor";
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MapEditor() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>HEY HEY</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
import * as React from "react";
|
|
28
src/ui/UI.tsx
Normal file
28
src/ui/UI.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { GameStore } from "~store/state";
|
||||||
|
import MapEditor, { MapEditorLayer } from "./MapEditor";
|
||||||
|
|
||||||
|
export type UILayer = MapEditorLayer;
|
||||||
|
|
||||||
|
export type LayerList = { id: string; data: UILayer; visible: boolean }[];
|
||||||
|
|
||||||
|
function renderLayer(data: UILayer) {
|
||||||
|
switch (data.type) {
|
||||||
|
case "MapEditor":
|
||||||
|
return <MapEditor />;
|
||||||
|
default:
|
||||||
|
throw new Error("unknown or invalid ui layer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function UI() {
|
||||||
|
const layers = useSelector<GameStore, LayerList>((state) => state.ui.layers);
|
||||||
|
return (
|
||||||
|
<div id="ui">
|
||||||
|
{layers.map(({ id, data }) => (
|
||||||
|
<div key={id}>{renderLayer(data)}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
32
src/ui/utils/useLayer.ts
Normal file
32
src/ui/utils/useLayer.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { UILayer } from "~ui/UI";
|
||||||
|
import { addLayer, removeLayer, showLayer, hideLayer } from "~store/ui/reducer";
|
||||||
|
|
||||||
|
export default function useUILayer(data: UILayer, show: boolean) {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const id = data.type + "-" + Math.random().toString(32).slice(2);
|
||||||
|
|
||||||
|
const [visible, setVisible] = useState(show);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(addLayer({ id, data }));
|
||||||
|
return () => {
|
||||||
|
dispatch(removeLayer({ id }));
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
dispatch(showLayer({ id }));
|
||||||
|
} else {
|
||||||
|
dispatch(hideLayer({ id }));
|
||||||
|
}
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
if (show != visible) {
|
||||||
|
setVisible(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"~*": ["./src/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
yarn.lock
90
yarn.lock
|
@ -837,7 +837,7 @@
|
||||||
"@babel/types" "^7.4.4"
|
"@babel/types" "^7.4.4"
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
"@babel/runtime@^7.4.4", "@babel/runtime@^7.8.4":
|
"@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
|
||||||
version "7.11.2"
|
version "7.11.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||||
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||||
|
@ -1263,6 +1263,24 @@
|
||||||
eventemitter3 "^3.1.0"
|
eventemitter3 "^3.1.0"
|
||||||
url "^0.11.0"
|
url "^0.11.0"
|
||||||
|
|
||||||
|
"@reduxjs/toolkit@^1.4.0":
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.4.0.tgz#ee2e2384cc3d1d76780d844b9c2da3580d32710d"
|
||||||
|
integrity sha512-hkxQwVx4BNVRsYdxjNF6cAseRmtrkpSlcgJRr3kLUcHPIAMZAmMJkXmHh/eUEGTMqPzsYpJLM7NN2w9fxQDuGw==
|
||||||
|
dependencies:
|
||||||
|
immer "^7.0.3"
|
||||||
|
redux "^4.0.0"
|
||||||
|
redux-thunk "^2.3.0"
|
||||||
|
reselect "^4.0.0"
|
||||||
|
|
||||||
|
"@types/hoist-non-react-statics@^3.3.0":
|
||||||
|
version "3.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||||
|
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
|
||||||
|
dependencies:
|
||||||
|
"@types/react" "*"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
|
||||||
"@types/howler@^2.2.1":
|
"@types/howler@^2.2.1":
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/howler/-/howler-2.2.1.tgz#c95314724a8e970b1b29a731861975f39987b9ca"
|
resolved "https://registry.yarnpkg.com/@types/howler/-/howler-2.2.1.tgz#c95314724a8e970b1b29a731861975f39987b9ca"
|
||||||
|
@ -1285,6 +1303,16 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/react-redux@^7.1.9":
|
||||||
|
version "7.1.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3"
|
||||||
|
integrity sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w==
|
||||||
|
dependencies:
|
||||||
|
"@types/hoist-non-react-statics" "^3.3.0"
|
||||||
|
"@types/react" "*"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
redux "^4.0.0"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^16.9.49":
|
"@types/react@*", "@types/react@^16.9.49":
|
||||||
version "16.9.49"
|
version "16.9.49"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872"
|
||||||
|
@ -2586,6 +2614,11 @@ escodegen@~1.9.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
|
eslint-plugin-react-hooks@^4.1.2:
|
||||||
|
version "4.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e"
|
||||||
|
integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg==
|
||||||
|
|
||||||
esprima@^3.1.3:
|
esprima@^3.1.3:
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
|
||||||
|
@ -3101,6 +3134,13 @@ hmac-drbg@^1.0.0:
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
minimalistic-crypto-utils "^1.0.1"
|
minimalistic-crypto-utils "^1.0.1"
|
||||||
|
|
||||||
|
hoist-non-react-statics@^3.3.0:
|
||||||
|
version "3.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||||
|
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||||
|
dependencies:
|
||||||
|
react-is "^16.7.0"
|
||||||
|
|
||||||
hotkeys-js@^3.8.1:
|
hotkeys-js@^3.8.1:
|
||||||
version "3.8.1"
|
version "3.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.1.tgz#fa7051f73bf1dc92a8b8d580a40b247f91966376"
|
resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.8.1.tgz#fa7051f73bf1dc92a8b8d580a40b247f91966376"
|
||||||
|
@ -3206,6 +3246,11 @@ ieee754@^1.1.4:
|
||||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
||||||
integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
|
integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
|
||||||
|
|
||||||
|
immer@^7.0.3:
|
||||||
|
version "7.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.9.tgz#28e7552c21d39dd76feccd2b800b7bc86ee4a62e"
|
||||||
|
integrity sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==
|
||||||
|
|
||||||
import-fresh@^2.0.0:
|
import-fresh@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
|
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
|
||||||
|
@ -4733,7 +4778,7 @@ process@^0.11.10:
|
||||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||||
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
||||||
|
|
||||||
prop-types@^15.6.2:
|
prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
|
@ -4843,7 +4888,7 @@ react-dom@^16.13.1:
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.19.1"
|
scheduler "^0.19.1"
|
||||||
|
|
||||||
react-is@^16.8.1:
|
react-is@^16.7.0, react-is@^16.8.1, react-is@^16.9.0:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||||
|
@ -4858,6 +4903,17 @@ react-reconciler@0.25.1:
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
scheduler "^0.19.1"
|
scheduler "^0.19.1"
|
||||||
|
|
||||||
|
react-redux@^7.2.1:
|
||||||
|
version "7.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985"
|
||||||
|
integrity sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.5.5"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
prop-types "^15.7.2"
|
||||||
|
react-is "^16.9.0"
|
||||||
|
|
||||||
react@^16.13.1:
|
react@^16.13.1:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
|
resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
|
||||||
|
@ -4915,6 +4971,24 @@ readdirp@~3.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.2.1"
|
picomatch "^2.2.1"
|
||||||
|
|
||||||
|
redux-devtools-extension@^2.13.8:
|
||||||
|
version "2.13.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1"
|
||||||
|
integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==
|
||||||
|
|
||||||
|
redux-thunk@^2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||||
|
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
|
||||||
|
|
||||||
|
redux@^4.0.0, redux@^4.0.5:
|
||||||
|
version "4.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
|
||||||
|
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
symbol-observable "^1.2.0"
|
||||||
|
|
||||||
regenerate-unicode-properties@^8.2.0:
|
regenerate-unicode-properties@^8.2.0:
|
||||||
version "8.2.0"
|
version "8.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
|
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
|
||||||
|
@ -5033,6 +5107,11 @@ request@^2.88.0:
|
||||||
tunnel-agent "^0.6.0"
|
tunnel-agent "^0.6.0"
|
||||||
uuid "^3.3.2"
|
uuid "^3.3.2"
|
||||||
|
|
||||||
|
reselect@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
|
||||||
|
integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
|
||||||
|
|
||||||
resolve-from@^3.0.0:
|
resolve-from@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
|
||||||
|
@ -5521,6 +5600,11 @@ svgo@^1.0.0, svgo@^1.3.2:
|
||||||
unquote "~1.1.1"
|
unquote "~1.1.1"
|
||||||
util.promisify "~1.0.0"
|
util.promisify "~1.0.0"
|
||||||
|
|
||||||
|
symbol-observable@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||||
|
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||||
|
|
||||||
symbol-tree@^3.2.2:
|
symbol-tree@^3.2.2:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||||
|
|
Reference in a new issue