This commit is contained in:
Michael Zhang 2024-01-09 11:09:47 -06:00
parent edcb715de8
commit 5f5cd6e1d9
13 changed files with 168 additions and 20 deletions

1
.rsw/rsw.crates Normal file
View file

@ -0,0 +1 @@
common :~> common/pkg

View file

@ -47,6 +47,7 @@
"sass": "^1.69.6", "sass": "^1.69.6",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^5.0.8", "vite": "^5.0.8",
"vite-plugin-rsw": "^2.0.11",
"vite-plugin-top-level-await": "^1.4.1", "vite-plugin-top-level-await": "^1.4.1",
"vite-plugin-wasm": "^3.3.0" "vite-plugin-wasm": "^3.3.0"
} }

View file

@ -103,6 +103,9 @@ devDependencies:
vite: vite:
specifier: ^5.0.8 specifier: ^5.0.8
version: 5.0.10(sass@1.69.6) version: 5.0.10(sass@1.69.6)
vite-plugin-rsw:
specifier: ^2.0.11
version: 2.0.11(vite@5.0.10)
vite-plugin-top-level-await: vite-plugin-top-level-await:
specifier: ^1.4.1 specifier: ^1.4.1
version: 1.4.1(vite@5.0.10) version: 1.4.1(vite@5.0.10)
@ -3286,6 +3289,14 @@ packages:
resolution: {integrity: sha512-LdabyT4OffkyXFCe9UT+uMkxNBs5rcTVuZClvxQr08D5TUgo1OFKkoT65qYRCsiKBl/usHjpXvP4hHMzzDRj3A==} resolution: {integrity: sha512-LdabyT4OffkyXFCe9UT+uMkxNBs5rcTVuZClvxQr08D5TUgo1OFKkoT65qYRCsiKBl/usHjpXvP4hHMzzDRj3A==}
dev: false dev: false
/vite-plugin-rsw@2.0.11(vite@5.0.10):
resolution: {integrity: sha512-OqbGAtdDfK88gDoxA9wVdGowCmlzLSXEyRvD8CgTu9IP5O7tx8Tg2CtIzKOyOWZtHHZPhtdYiN+5Il6rTZCkzw==}
peerDependencies:
vite: '>2.8.0-0'
dependencies:
vite: 5.0.10(sass@1.69.6)
dev: true
/vite-plugin-top-level-await@1.4.1(vite@5.0.10): /vite-plugin-top-level-await@1.4.1(vite@5.0.10):
resolution: {integrity: sha512-hogbZ6yT7+AqBaV6lK9JRNvJDn4/IJvHLu6ET06arNfo0t2IsyCaon7el9Xa8OumH+ESuq//SDf8xscZFE0rWw==} resolution: {integrity: sha512-hogbZ6yT7+AqBaV6lK9JRNvJDn4/IJvHLu6ET06arNfo0t2IsyCaon7el9Xa8OumH+ESuq//SDf8xscZFE0rWw==}
peerDependencies: peerDependencies:

View file

@ -4,6 +4,7 @@ import "./App.css";
import routes from "./routes"; import routes from "./routes";
import { Provider as ReduxProvider } from "react-redux"; import { Provider as ReduxProvider } from "react-redux";
import { store } from "./store"; import { store } from "./store";
import { HotkeysProvider } from "@blueprintjs/core";
const router = createBrowserRouter(routes); const router = createBrowserRouter(routes);
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@ -12,7 +13,9 @@ function App() {
return ( return (
<ReduxProvider store={store}> <ReduxProvider store={store}>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<RouterProvider router={router} /> <HotkeysProvider>
<RouterProvider router={router} />
</HotkeysProvider>
</QueryClientProvider> </QueryClientProvider>
</ReduxProvider> </ReduxProvider>
); );

View file

@ -6,9 +6,13 @@ import "normalize.css";
import "@blueprintjs/core/lib/css/blueprint.css"; import "@blueprintjs/core/lib/css/blueprint.css";
import "@blueprintjs/icons/lib/css/blueprint-icons.css"; import "@blueprintjs/icons/lib/css/blueprint-icons.css";
import init from "common";
// biome-ignore lint/style/noNonNullAssertion: <explanation> // biome-ignore lint/style/noNonNullAssertion: <explanation>
const el = document.getElementById("root")!; const el = document.getElementById("root")!;
init();
ReactDOM.createRoot(el).render( ReactDOM.createRoot(el).render(
<React.StrictMode> <React.StrictMode>
<App /> <App />

View file

@ -1,16 +1,23 @@
import { useRef, useState } from "react"; import { useCallback, useState, type MouseEvent } from "react";
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import { Canvas, type MeshProps, useLoader } from "@react-three/fiber"; import { Canvas, type MeshProps, useLoader } from "@react-three/fiber";
import styles from "./MapView.module.scss"; import styles from "./MapView.module.css";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { MapControls, Text } from "@react-three/drei"; import { MapControls, Text } from "@react-three/drei";
import { ColorRepresentation, DoubleSide, TextureLoader } from "three"; import { ColorRepresentation, DoubleSide, TextureLoader } from "three";
import { Bloom, EffectComposer } from "@react-three/postprocessing"; import { Bloom, EffectComposer } from "@react-three/postprocessing";
import { useAppDispatch } from "../store"; import { useAppDispatch } from "../store";
import { addWindow } from "../store/someShit"; import { setWindow } from "../store/someShit";
import { DragDropContext } from "react-beautiful-dnd"; import { DragDropContext } from "react-beautiful-dnd";
import {
Menu,
MenuDivider,
MenuItem,
showContextMenu,
} from "@blueprintjs/core";
import StatusWindow from "./StatusWindow";
export default function MapView({}) { export default function MapView() {
const { universeId } = useParams(); const { universeId } = useParams();
const { isLoading, data: mapData } = useQuery( const { isLoading, data: mapData } = useQuery(
`universe ${universeId} points`, `universe ${universeId} points`,
@ -74,6 +81,8 @@ export default function MapView({}) {
); );
})} })}
</Canvas> </Canvas>
<StatusWindow />
</DragDropContext> </DragDropContext>
</main> </main>
); );
@ -100,6 +109,36 @@ function StarSystem({
color = parseInt(owner.color, 16); color = parseInt(owner.color, 16);
} }
const menu = (
<Menu>
<MenuItem
icon="cross-circle"
intent="danger"
text="Click me to close"
// onClick={handleClose}
/>
<MenuItem icon="search-around" text="Search around..." />
<MenuItem icon="search" text="Object viewer" />
<MenuItem icon="graph-remove" text="Remove" />
<MenuItem icon="group-objects" text="Group" />
<MenuDivider />
<MenuItem disabled={true} text="Clicked on node" />
</Menu>
);
const handleContextMenu = useCallback((event: MouseEvent<HTMLElement>) => {
event.preventDefault();
showContextMenu({
content: menu,
// onClose: handleClose,
targetOffset: {
left: event.clientX,
top: event.clientY,
},
});
// setIsOpen(true);
}, []);
return ( return (
<> <>
<mesh {...props} position={[x, 0, y]} scale={active ? 1.5 : 1}> <mesh {...props} position={[x, 0, y]} scale={active ? 1.5 : 1}>
@ -115,7 +154,12 @@ function StarSystem({
{...props} {...props}
position={[x, 0, y]} position={[x, 0, y]}
onClick={(event) => { onClick={(event) => {
dispatch(addWindow(["planet", { type: "planet" }])); dispatch(setWindow(["planet", { type: "planet" }]));
event.stopPropagation();
}}
onContextMenu={(event) => {
console.log("Hellosu", event);
handleContextMenu(event.nativeEvent);
event.stopPropagation(); event.stopPropagation();
}} }}
onPointerOver={(event) => { onPointerOver={(event) => {

View file

@ -0,0 +1,60 @@
import { HotkeyConfig, useHotkeys } from "@blueprintjs/core";
import { useCallback, useMemo } from "react";
export default function StatusWindow() {
const handleEscape = useCallback(() => {
console.log("helloge");
}, []);
const hotkeys: HotkeyConfig[] = useMemo(
() => [
{
combo: "1",
global: true,
label: "Escape",
onkeydown: handleEscape,
},
],
[handleEscape],
);
const { handleKeyDown, handleKeyUp } = useHotkeys(hotkeys);
return (
<div
className="bp5-dialog"
onKeyDown={handleKeyDown}
onKeyUp={handleKeyUp}
style={{
position: "absolute",
bottom: "10px",
left: "10px",
margin: "0",
}}
>
<div className="bp5-dialog-header">
<span className="bp5-icon-large bp5-icon-inbox" />
<h5 className="bp5-heading">Dialog header</h5>
<button
type="button"
aria-label="Close"
className="bp5-dialog-close-button bp5-button bp5-minimal bp5-icon-cross"
/>
</div>
<div className="bp5-dialog-body">
This dialog hasn't been wired up with any open or close interactions.
It's just an example of markup and styles.
</div>
<div className="bp5-dialog-footer">
<div className="bp5-dialog-footer-actions">
<button type="button" className="bp5-button">
Secondary button
</button>
<button type="submit" className="bp5-button bp5-intent-primary">
Primary button
</button>
</div>
</div>
</div>
);
}

View file

@ -1,20 +1,18 @@
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit"; import type { PayloadAction } from "@reduxjs/toolkit";
type WindowDef = { type WindowDef = { type: string } & object;
type: "planet";
};
// Define a type for the slice state // Define a type for the slice state
interface SomeShitState { interface SomeShitState {
activeEmpireId: number | null; activeEmpireId: number | null;
windows: { [_: string]: WindowDef }; activeWindow: WindowDef | null;
} }
// Define the initial state using that type // Define the initial state using that type
const initialState: SomeShitState = { const initialState: SomeShitState = {
activeEmpireId: null, activeEmpireId: null,
windows: {}, activeWindow: null,
}; };
export const someShitSlice = createSlice({ export const someShitSlice = createSlice({
@ -25,18 +23,17 @@ export const someShitSlice = createSlice({
state.activeEmpireId = action.payload; state.activeEmpireId = action.payload;
}, },
addWindow: (state, action: PayloadAction<[string, WindowDef]>) => { setWindow: (state, action: PayloadAction<WindowDef>) => {
const [name, def] = action.payload; state.activeWindow = action.payload;
state.windows = { ...state.windows, [name]: def };
}, },
closeWindow: (state, action: PayloadAction<string>) => { closeWindow: (state) => {
delete state.windows[action.payload]; state.activeWindow = null;
}, },
}, },
}); });
export const { changeActiveEmpire, addWindow, closeWindow } = export const { changeActiveEmpire, setWindow, closeWindow } =
someShitSlice.actions; someShitSlice.actions;
export default someShitSlice.reducer; export default someShitSlice.reducer;

View file

@ -1,12 +1,19 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import reactPlugin from "@vitejs/plugin-react-swc"; import reactPlugin from "@vitejs/plugin-react-swc";
import wasmPlugin from "vite-plugin-wasm"; // import wasmPlugin from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await"; // import topLevelAwait from "vite-plugin-top-level-await";
import { ViteRsw } from "vite-plugin-rsw";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [reactPlugin(), wasmPlugin(), topLevelAwait()], plugins: [
// wasmPlugin(["./common"], []),
// topLevelAwait(),
// ViteRsw(),
reactPlugin(),
],
server: { server: {
fs: { allow: [".."] },
proxy: { proxy: {
"/api": { "/api": {
target: "http://localhost:1440", target: "http://localhost:1440",

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"common": "link:/Users/michael/Projects/openstellaris/common/pkg"
}
}

10
pnpm-lock.yaml Normal file
View file

@ -0,0 +1,10 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
common:
specifier: link:/Users/michael/Projects/openstellaris/common/pkg
version: link:common/pkg

5
rsw.toml Normal file
View file

@ -0,0 +1,5 @@
cli = "pnpm"
[[crates]]
name = "common"
link = true