diff --git a/package-lock.json b/package-lock.json
index 33af3c1..57c2cd3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
+ "@radix-ui/react-form": "^0.0.3",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-menubar": "^1.0.3",
"@radix-ui/react-popover": "^1.0.6",
@@ -1320,6 +1321,34 @@
}
}
},
+ "node_modules/@radix-ui/react-form": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.0.3.tgz",
+ "integrity": "sha512-kgE+Z/haV6fxE5WqIXj05KkaXa3OkZASoTDy25yX2EIp/x0c54rOH/vFr5nOZTg7n7T1z8bSyXmiVIFP9bbhPQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-label": "2.0.2",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-icons": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
@@ -1346,6 +1375,29 @@
}
}
},
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
+ "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-menu": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.5.tgz",
@@ -6473,6 +6525,20 @@
"@radix-ui/react-use-callback-ref": "1.0.1"
}
},
+ "@radix-ui/react-form": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.0.3.tgz",
+ "integrity": "sha512-kgE+Z/haV6fxE5WqIXj05KkaXa3OkZASoTDy25yX2EIp/x0c54rOH/vFr5nOZTg7n7T1z8bSyXmiVIFP9bbhPQ==",
+ "requires": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-label": "2.0.2",
+ "@radix-ui/react-primitive": "1.0.3"
+ }
+ },
"@radix-ui/react-icons": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
@@ -6488,6 +6554,15 @@
"@radix-ui/react-use-layout-effect": "1.0.1"
}
},
+ "@radix-ui/react-label": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
+ "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
+ "requires": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ }
+ },
"@radix-ui/react-menu": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.5.tgz",
diff --git a/package.json b/package.json
index 6b78567..82360c4 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
+ "@radix-ui/react-form": "^0.0.3",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-menubar": "^1.0.3",
"@radix-ui/react-popover": "^1.0.6",
diff --git a/src/App.jsx b/src/App.jsx
index 63e47f5..55c76b9 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,29 +1,41 @@
+/* eslint-disable react/prop-types */
import "./App.css";
-import { useEffect, useRef } from "react";
+import { useEffect, useState } from "react";
import { LegoRoom } from "./components/3D";
import { useStore } from "./store";
import { Loader } from "./components/UI/Loader";
+import { JoinRoomScreen } from "./components/UI/JoinRoomForm";
const CONNECTED = "connected";
-function App() {
+const Lobby = ({ roomId }) => {
const enterRoom = useStore((state) => state.liveblocks.enterRoom);
const leaveRoom = useStore((state) => state.liveblocks.leaveRoom);
const status = useStore((state) => state.liveblocks.status);
useEffect(() => {
- enterRoom("lego-test-room");
+ enterRoom(roomId);
- return () => leaveRoom("lego-test-room", { bricks: [] });
- }, [enterRoom, leaveRoom]);
+ return () => leaveRoom(roomId, { bricks: [] });
+ }, [enterRoom, leaveRoom, roomId]);
if (status !== CONNECTED) {
return ;
}
+ return ;
+};
+
+function App() {
+ const [roomId, setRoomId] = useState(null);
+
return (
-
+ {roomId ? (
+
+ ) : (
+
+ )}
);
}
diff --git a/src/components/3D/LegoRoom.jsx b/src/components/3D/LegoRoom.jsx
index 3f88eb5..9e70191 100644
--- a/src/components/3D/LegoRoom.jsx
+++ b/src/components/3D/LegoRoom.jsx
@@ -4,43 +4,56 @@
/* eslint-disable react/display-name */
import { Canvas } from "@react-three/fiber";
import React, { Suspense } from "react";
-import { LinearToneMapping } from "three";
+// import { LinearToneMapping } from "three";
import { ControlsWrapper, Scene } from ".";
import { DialogBox } from "../UI";
-import { Perf } from "r3f-perf";
+// import { Perf } from "r3f-perf";
import { ModeToggleBar } from "../UI/ModeToggleBar";
import { Panel } from "../UI/Panel";
import { BottomBar } from "../UI/BottomBar";
-export const LegoRoom = () => {
+const UI = () => {
return (
<>
-
+ >
+ );
+};
+
+const ThreeD = () => {
+ return (
+
+ );
+};
+
+export const LegoRoom = () => {
+ return (
+ <>
+
+
>
);
};
diff --git a/src/components/UI/JoinRoomForm/index.jsx b/src/components/UI/JoinRoomForm/index.jsx
new file mode 100644
index 0000000..874fc20
--- /dev/null
+++ b/src/components/UI/JoinRoomForm/index.jsx
@@ -0,0 +1,98 @@
+/* eslint-disable react/prop-types */
+import * as Form from "@radix-ui/react-form";
+import "./styles.css";
+import { useRef } from "react";
+import { useStore } from "../../../store";
+
+const JoinRoomForm = ({ setRoomId }) => {
+ const form = useRef();
+
+ const name = useRef();
+ const room = useRef();
+
+ const setSelfName = useStore((state) => state.setSelfName);
+
+ const submit = (e) => {
+ e.preventDefault();
+ setSelfName(name.current);
+ setRoomId(room.current);
+ };
+
+ return (
+
+
+
+
Name
+
+ Please enter your Name
+
+
+
+ {
+ name.current = e.target.value;
+ }}
+ />
+
+
+
+
+
Room ID
+
+ Please enter a room ID
+
+
+
+ {
+ room.current = e.target.value;
+ }}
+ />
+
+
+
+
+
+
+ );
+};
+
+export const JoinRoomScreen = ({ setRoomId }) => {
+ return (
+
+
+
+ );
+};
diff --git a/src/components/UI/JoinRoomForm/styles.css b/src/components/UI/JoinRoomForm/styles.css
new file mode 100644
index 0000000..0503f00
--- /dev/null
+++ b/src/components/UI/JoinRoomForm/styles.css
@@ -0,0 +1,95 @@
+@import "@radix-ui/colors/black-alpha.css";
+@import "@radix-ui/colors/violet.css";
+@import "@radix-ui/colors/mauve.css";
+
+/* reset */
+input,
+textarea,
+button {
+ all: unset;
+ box-sizing: border-box;
+}
+
+.FormRoot {
+ width: 260px;
+}
+
+.FormField {
+ display: grid;
+ margin-bottom: 10px;
+}
+
+.FormLabel {
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 35px;
+ color: white;
+}
+
+.FormMessage {
+ font-size: 13px;
+ color: white;
+ opacity: 0.8;
+}
+
+.Input,
+.Textarea {
+ width: 100%;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+
+ font-size: 15px;
+ color: white;
+ background-color: gray;
+ box-shadow: 0 0 0 1px var(--black-a9);
+}
+.Input:hover,
+.Textarea:hover {
+ box-shadow: 0 0 0 1px white;
+}
+.Input:focus,
+.Textarea:focus {
+ box-shadow: 0 0 0 2px white;
+}
+.Input::selection,
+.Textarea::selection {
+ background-color: var(--black-a9);
+ color: white;
+}
+
+.Input {
+ padding: 0 10px;
+ height: 35px;
+ line-height: 1;
+}
+
+.Textarea {
+ resize: none;
+ padding: 10px;
+}
+
+.FormButton {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ padding: 0 15px;
+ font-size: 15px;
+ line-height: 1;
+ font-weight: 500;
+ height: 35px;
+ width: 100%;
+
+ background-color: white;
+ color: black;
+ box-shadow: 0 2px 10px var(--black-a7);
+}
+.FormButton:hover {
+ background-color: var(--mauve-3);
+ cursor: pointer;
+}
+.FormButton:focus {
+ box-shadow: 0 0 0 2px black;
+}
diff --git a/src/components/UI/PeopleList/index.jsx b/src/components/UI/PeopleList/index.jsx
index d84a633..0d2539c 100644
--- a/src/components/UI/PeopleList/index.jsx
+++ b/src/components/UI/PeopleList/index.jsx
@@ -40,8 +40,8 @@ const PeopleList = () => {
return user.presence?.self ? (
) : null;
})}
diff --git a/src/store/index.js b/src/store/index.js
index e4e4eac..3b0b15f 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -13,59 +13,6 @@ const client = createClient({
publicApiKey: import.meta.env.VITE_LIVEBLOCKS_API_KEY,
});
-// export const useStore = create((set) => ({
-// mode: CREATE_MODE,
-// setMode: (newMode) => set({ mode: newMode }),
-
-// width: defaultWidth,
-// setWidth: (newWidth) => set({ width: newWidth }),
-
-// depth: defaultWidth,
-// setDepth: (newDepth) => set({ depth: newDepth }),
-
-// anchorX: defaultAnchor,
-// setAnchorX: (newAnchorPoint) => set({ anchorX: newAnchorPoint }),
-
-// anchorZ: defaultAnchor,
-// setAnchorZ: (newAnchorPoint) => set({ anchorZ: newAnchorPoint }),
-
-// rotate: false,
-// setRotate: (bool) => set({ rotate: bool }),
-
-// color: "#ff0000",
-// setColor: (newColor) => set({ color: newColor }),
-
-// selectedBricks: [],
-// setSelectedBricks: ({ object, shift }) =>
-// set((state) => {
-// if (object === undefined) return { selectedBricks: [] };
-// else if (Array.isArray(object)) return { selectedBricks: object };
-// else if (!shift)
-// return state.selectedBricks[0] === object
-// ? { selectedBricks: [] }
-// : { selectedBricks: [object] };
-// else if (state.selectedBricks.includes(object))
-// return {
-// selectedBricks: state.selectedBricks.filter((o) => o !== object),
-// };
-// else return { selectedBricks: [object, ...state.selectedBricks] };
-// }),
-
-// bricks: [],
-// setBricks: (getBricks) =>
-// set((state) => ({ bricks: getBricks(state.bricks) })),
-// clearBricks: () => set({ bricks: [] }),
-
-// cursor: {
-// x: 0,
-// z: 0,
-// w: 0,
-// d: 0,
-// },
-
-// setCursor: (newState) => set({ cursor: newState }),
-// }));
-
const id = uID();
const color = generateSoftColors();
@@ -115,6 +62,8 @@ export const useStore = create(
clearBricks: () => set({ bricks: [] }),
self: { id: id, color: color },
+ setSelfName: (name) =>
+ set((state) => ({ self: { ...state.self, name: name } })),
cursorColors: {},
setCursorColors: (newCursorColor) =>
diff --git a/src/utils/helpers.js b/src/utils/helpers.js
index f34db0e..6bfba2e 100644
--- a/src/utils/helpers.js
+++ b/src/utils/helpers.js
@@ -127,3 +127,7 @@ export function generateSoftColors() {
return hexColor;
}
+
+export function isBlank(str) {
+ return !str || /^\s*$/.test(str);
+}