diff --git a/index.html b/index.html index d37cc60..1d4d89f 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,8 @@ href="https://fonts.googleapis.com/css2?family=Recursive:slnt,wght,CASL,CRSV,MONO@-15..0,300..1000,0..1,0..1,0..1&display=swap" rel="stylesheet"> - + +
\ No newline at end of file diff --git a/package.json b/package.json index 3556c24..a236846 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,9 @@ "dependencies": { "@dimforge/rapier2d": "latest", "@tldraw/tldraw": "2.0.2", - "@types/react-helmet": "^6.1.11", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-helmet": "^6.1.0" + "react-helmet-async": "^2.0.4" }, "devDependencies": { "@biomejs/biome": "1.4.1", @@ -32,4 +31,4 @@ "vite-plugin-top-level-await": "^1.3.1", "vite-plugin-wasm": "^3.2.2" } -} +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 6ec1d08..cff4c4f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,30 +1,119 @@ -import { createTLUser, setUserPreferences, Tldraw, track, useEditor } from "@tldraw/tldraw"; +import { atom, createShapeId, createTLUser, setUserPreferences, StoreSnapshot, Tldraw, TLGeoShape, TLInstance, TLRecord, TLShape, TLUiComponents, TLUnknownShape, TLUserPreferences, track, useEditor } from "@tldraw/tldraw"; import "@tldraw/tldraw/tldraw.css"; import { SimControls } from "./physics/ui/PhysicsControls"; import { uiOverrides } from "./physics/ui/overrides"; -import { Helmet } from "react-helmet"; -import React, { useEffect, useState } from "react"; +import { Helmet, HelmetProvider } from "react-helmet-async"; +import React, { Suspense, useEffect, useState } from "react"; import ReactDOM from "react-dom/client"; ReactDOM.createRoot(document.getElementById("root")!).render(); +const components: TLUiComponents = { + HelpMenu: null, + StylePanel: null, + PageMenu: null, + NavigationPanel: null, + DebugMenu: null, + MenuPanel: null, + // ContextMenu: null, + // ActionsMenu: null, + // ZoomMenu: null, + // MainMenu: null, + // Minimap: null, + // Toolbar: null, + // KeyboardShortcutsDialog: null, + // QuickActions: null, + // HelperButtons: null, + // SharePanel: null, + // TopPanel: null, +} + function App() { const [isPhysicsEnabled, setIsPhysicsEnabled] = useState(false); + const [elementsInfo, setElementsInfo] = useState([]); useEffect(() => { - const togglePhysics = () => setIsPhysicsEnabled(prev => !prev); + const togglePhysics = async () => { + if (!isPhysicsEnabled) { + const info = await gatherElementsInfo(); + setElementsInfo(info); + setIsPhysicsEnabled(true); // Enable physics only after gathering info + } else { + setIsPhysicsEnabled(false); + setElementsInfo([]); // Reset elements info when disabling physics + } + }; window.addEventListener('togglePhysicsEvent', togglePhysics); return () => { window.removeEventListener('togglePhysicsEvent', togglePhysics); }; - }, []); + }, [isPhysicsEnabled]); + + // Function to gather elements info asynchronously + async function gatherElementsInfo() { + const rootElement = document.getElementById('root'); + const info: any[] = []; + if (rootElement) { + for (const child of rootElement.children) { + const rect = child.getBoundingClientRect(); + let w = rect.width + if (!['P', 'UL'].includes(child.tagName)) { + w = measureElementTextWidth(child); + } + console.log(w) + info.push({ + tagName: child.tagName, + position: { x: rect.left, y: rect.top }, + dimensions: { width: w, height: rect.height }, + }); + }; + } + // Example usage + // const element = document.getElementById('yourElementId'); // Replace 'yourElementId' with the actual ID + // if (element) { + // console.log(`Text width: ${textWidth}px`); + // } + // console.log(info.length); + // console.log(info); + + return info; + } + + const shapes: TLGeoShape[] = elementsInfo.map((element, index) => ({ + id: createShapeId(), + type: 'geo', + x: element.position.x, + y: element.position.y, + props: { + geo: "rectangle", + w: element.dimensions.width, + h: element.dimensions.height, + fill: 'solid', + color: 'green' + } + })) + + shapes.push({ + id: createShapeId(), + type: 'geo', + x: 0, + y: window.innerHeight, + props: { + geo: "rectangle", + w: window.innerWidth, + h: 20, + fill: 'solid' + } + }) return ( - - {isPhysicsEnabled ? : } + + + {isPhysicsEnabled && elementsInfo.length > 0 ? : } + ); }; @@ -56,10 +145,8 @@ function Default() {

My work

- Alongside my independent work I am a researcher at - Block Science building - knowledge organisation infrastructure and at - ECSA working on + Alongside my independent work I am a researcher at Block Science building + knowledge organisation infrastructure and at ECSA working on computational media. I am also part of the nascent Liberatory Computing collective and a co-organiser of the OCWG.

@@ -92,7 +179,7 @@ function Default() { ); } -function Canvas() { +function Canvas({ shapes }: { shapes: TLShape[] }) { return (
@@ -101,13 +188,9 @@ function Canvas() { - {/* */} - {/* {()=> { - setUserPreferences({id: 'orion', isDarkMode: true }) - }} */} - +
); @@ -126,3 +209,42 @@ function Toggle() { ); } +function Contact() { + return ( +
+

Contact

+

Twitter: @OrionReedOne

+

Mastodon: orion@hci.social

+

Email: me@orionreed.com

+

GitHub: OrionReed

+
+ + ) +} + +function measureElementTextWidth(element: Element) { + // Create a temporary span element + const tempElement = document.createElement('span'); + // Get the text content from the passed element + tempElement.textContent = element.textContent || element.innerText; + // Get the computed style of the passed element + const computedStyle = window.getComputedStyle(element); + // Apply relevant styles to the temporary element + tempElement.style.font = computedStyle.font; + tempElement.style.fontWeight = computedStyle.fontWeight; + tempElement.style.fontSize = computedStyle.fontSize; + tempElement.style.fontFamily = computedStyle.fontFamily; + tempElement.style.letterSpacing = computedStyle.letterSpacing; + // Ensure the temporary element is not visible in the viewport + tempElement.style.position = 'absolute'; + tempElement.style.visibility = 'hidden'; + tempElement.style.whiteSpace = 'nowrap'; // Prevent text from wrapping + // Append to the body to make measurements possible + document.body.appendChild(tempElement); + // Measure the width + const width = tempElement.getBoundingClientRect().width; + // Remove the temporary element from the document + document.body.removeChild(tempElement); + // Return the measured width + return width === 0 ? 10 : width; +} \ No newline at end of file diff --git a/src/card/contact.html b/src/card/contact.html deleted file mode 100644 index f157b8c..0000000 --- a/src/card/contact.html +++ /dev/null @@ -1,7 +0,0 @@ -
-

Contact

-

Twitter: @OrionReedOne

-

Mastodon: orion@hci.social

-

Email: me@orionreed.com

-

GitHub: OrionReed

-
diff --git a/src/css/tldraw.css b/src/css/tldraw.css index 6b5cb6e..b938a37 100644 --- a/src/css/tldraw.css +++ b/src/css/tldraw.css @@ -26,5 +26,9 @@ html, } .tl-background { - background-color: transparent !important; + background-color: transparent; +} + +.tlui-debug-panel { + display: none; } diff --git a/src/physics/simulation.ts b/src/physics/simulation.ts index f6ec6b8..3829d2d 100644 --- a/src/physics/simulation.ts +++ b/src/physics/simulation.ts @@ -28,7 +28,7 @@ export class PhysicsWorld { public start() { this.world = new RAPIER.World(GRAVITY); - this.addShapes(this.editor.getSelectedShapes()); + this.addShapes(this.editor.getCurrentPageShapes()); const simLoop = () => { this.world.step(); diff --git a/src/physics/ui/PhysicsControls.tsx b/src/physics/ui/PhysicsControls.tsx index 477e264..e15fbb5 100644 --- a/src/physics/ui/PhysicsControls.tsx +++ b/src/physics/ui/PhysicsControls.tsx @@ -1,47 +1,17 @@ -import { track, useEditor } from "@tldraw/tldraw"; -import { useEffect, useState } from "react"; +import { TLUnknownShape, useEditor } from "@tldraw/tldraw"; +import { useEffect } from "react"; import { usePhysicsSimulation } from "../simulation"; -// import "../../css/physics-ui.css"; -export const SimControls = track(() => { +export const SimControls = ({ shapes }: { shapes: TLUnknownShape[] }) => { const editor = useEditor(); - const [physicsEnabled, setPhysics] = useState(false); useEffect(() => { - const togglePhysics = () => { - setPhysics(prev => !prev); - }; - - window.addEventListener('togglePhysicsEvent', togglePhysics); - - return () => { - window.removeEventListener('togglePhysicsEvent', togglePhysics); - }; + editor.createShapes(shapes) + return () => { editor.deleteShapes(editor.getCurrentPageShapes()) } }, []); - const { addShapes } = usePhysicsSimulation(editor, physicsEnabled); - return ( -
-
- - -
-
- ); -}); + const { addShapes } = usePhysicsSimulation(editor, true); + + return (<>); +};