Skip to content

Commit

Permalink
replace preact app with react app from the rust side
Browse files Browse the repository at this point in the history
  • Loading branch information
noxware committed Oct 12, 2024
1 parent 42aa976 commit 00caa76
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 178 deletions.
151 changes: 131 additions & 20 deletions companion/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,138 @@
import { useState } from "react";
import React, { useState, useEffect } from "react";

function Area({ area, interactive }) {
return (
<foreignObject
key={area.id}
x={area.x}
y={area.y}
width={area.width}
height={area.height}
style={{ overflow: "hidden" }}
>
<div
style={{
width: "100%",
height: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "lightblue",
visibility: area.visible ? "visible" : "hidden",
pointerEvents: interactive ? "auto" : "none",
}}
onMouseEnter={() => {
console.log("Mouse entered");
}}
dangerouslySetInnerHTML={{
__html: area.content,
}}
/>
</foreignObject>
);
}

function MaskRect({ id, x, y, width, height, kind }) {
return (
<rect
key={id}
x={x}
y={y}
width={width}
height={height}
// TODO: This roundness looks good for egui windows but should not be hardcoded.
// In the future, a canvas area may not be a window.
rx={kind === "canvas" ? 7 : 0}
fill={kind === "canvas" ? "black" : "white"}
/>
);
}

function App() {
const [count, setCount] = useState(0);
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [windowHeight, setWindowHeight] = useState(window.innerHeight);
const [mouseX, setMouseX] = useState(0);
const [mouseY, setMouseY] = useState(0);
const [areas, setAreas] = useState([]);
window.setAreas = setAreas;

useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
setWindowHeight(window.innerHeight);
};

window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);

useEffect(() => {
const handleMouseMove = (event) => {
setMouseX(event.clientX);
setMouseY(event.clientY);
};

// Because of the svg having no pointer events, only the canvas can read mousemove, document, window and body can't, idk why.
// And this will not trigger if canvas is not receiving mousemove events.
document
.getElementById("the_canvas_id")
.addEventListener("mousemove", handleMouseMove);

// When the canvas does not receive mousemove, maybe other elements are capturing it and window should receive it.
window.addEventListener("mousemove", handleMouseMove);

return () => {
document
.getElementById("the_canvas_id")
.removeEventListener("mousemove", handleMouseMove);

window.removeEventListener("mousemove", handleMouseMove);
};
}, []);

const hoveredArea = areas
.slice()
.reverse()
.find((area) => {
return (
area.x <= mouseX &&
mouseX <= area.x + area.width &&
area.y <= mouseY &&
mouseY <= area.y + area.height
);
});

console.log(mouseX, mouseY);
console.log(hoveredArea);

return (
<>
<div>
<a href="https://vitejs.dev" target="_blank"></a>
<a href="https://react.dev" target="_blank"></a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
<svg
width={windowWidth}
height={windowHeight}
style={{
position: "absolute",
top: 0,
left: 0,
mask: "url(#mask)",
zIndex: 1000,
// Issue: This causes window mousemove events to be ignored.
pointerEvents: "none",
}}
>
<defs>
<mask id="mask">
{areas.map((area) => (
<MaskRect key={area.id} {...area} />
))}
</mask>
</defs>

{areas
.filter((area) => area.kind === "html")
.map((area) => (
<Area key={area.id} area={area} interactive={area === hoveredArea} />
))}
</svg>
);
}

Expand Down
21 changes: 20 additions & 1 deletion companion/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,29 @@ import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";

export function run(root) {
export function run() {
window.hframeDebug = {};

const root = document.createElement("div");
root.style.display = "contents";
document.body.appendChild(root);

createRoot(root).render(
<StrictMode>
<App />
</StrictMode>
);
}

export function set_areas(areas) {
if (window.setAreas) {
window.hframeDebug.areas = areas;
window.setAreas(areas);
} else {
console.error("set_areas function not available");
}
}

export function log(message) {
console.log(message);
}
3 changes: 3 additions & 0 deletions companion/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ export default defineConfig({
// external: ['react', 'react-dom'],
},
},
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
});
156 changes: 0 additions & 156 deletions src/js/companion.js

This file was deleted.

2 changes: 1 addition & 1 deletion src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod js {
use serde::{de::DeserializeOwned, Serialize};
use wasm_bindgen::prelude::*;

#[wasm_bindgen(module = "/src/js/companion.js")]
#[wasm_bindgen(module = "/companion/dist/companion.js")]

Check failure on line 8 in src/web.rs

View workflow job for this annotation

GitHub Actions / Check

failed to read file `/home/runner/work/hframe/hframe/companion/dist/companion.js`: No such file or directory (os error 2)

Check failure on line 8 in src/web.rs

View workflow job for this annotation

GitHub Actions / Clippy

failed to read file `/home/runner/work/hframe/hframe/companion/dist/companion.js`: No such file or directory (os error 2)
extern "C" {
pub(crate) fn set_areas(areas: JsValue);
pub(crate) fn run();
Expand Down

0 comments on commit 00caa76

Please sign in to comment.