updates UI

This commit is contained in:
bhushan6
2023-08-13 14:25:42 +05:30
parent 14852144f1
commit 48d4ffaf91
24 changed files with 770 additions and 215 deletions
+343 -9
View File
@@ -1,16 +1,19 @@
{
"name": "new",
"name": "lego-builder",
"version": "0.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new",
"name": "lego-builder",
"version": "0.0.0",
"dependencies": {
"@radix-ui/colors": "^0.1.8",
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.0.4",
"@react-three/drei": "^9.80.2",
"@react-three/fiber": "^8.13.6",
"framer-motion": "^10.15.1",
@@ -18,6 +21,7 @@
"leva": "^0.9.35",
"r3f-perf": "^7.1.2",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"three": "^0.155.0",
"use-keyboard-shortcut": "^1.1.6",
@@ -1017,9 +1021,17 @@
}
},
"node_modules/@radix-ui/colors": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-0.1.8.tgz",
"integrity": "sha512-jwRMXYwC0hUo0mv6wGpuw254Pd9p/R6Td5xsRpOmaWkUHlooNWqVcadgyzlRumMq3xfOTXwJReU0Jv+EIy4Jbw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.0.1.tgz",
"integrity": "sha512-EhWky2oSIf5y+BDfrAY+Rykrkh7m2/M/bgCVRr3M+Hnr4JOh+mtFZLHUS1j/WzaPw1uvd0vwhK3cbxsR0QnCgw=="
},
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
"integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==",
"dependencies": {
"@babel/runtime": "^7.13.10"
}
},
"node_modules/@radix-ui/primitive": {
"version": "1.0.1",
@@ -1052,6 +1064,62 @@
}
}
},
"node_modules/@radix-ui/react-checkbox": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz",
"integrity": "sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==",
"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-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
},
"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-collection": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
"integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2"
},
"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-compose-refs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
@@ -1122,6 +1190,23 @@
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
"integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz",
@@ -1319,6 +1404,70 @@
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
"integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"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-slider": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz",
"integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/number": "1.0.1",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
},
"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-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
@@ -1337,6 +1486,60 @@
}
}
},
"node_modules/@radix-ui/react-toggle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
"integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"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-toggle-group": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz",
"integrity": "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-toggle": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
},
"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-tooltip": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.6.tgz",
@@ -1441,6 +1644,23 @@
}
}
},
"node_modules/@radix-ui/react-use-previous": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz",
"integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==",
"dependencies": {
"@babel/runtime": "^7.13.10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-rect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz",
@@ -5902,9 +6122,17 @@
}
},
"@radix-ui/colors": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-0.1.8.tgz",
"integrity": "sha512-jwRMXYwC0hUo0mv6wGpuw254Pd9p/R6Td5xsRpOmaWkUHlooNWqVcadgyzlRumMq3xfOTXwJReU0Jv+EIy4Jbw=="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-2.0.1.tgz",
"integrity": "sha512-EhWky2oSIf5y+BDfrAY+Rykrkh7m2/M/bgCVRr3M+Hnr4JOh+mtFZLHUS1j/WzaPw1uvd0vwhK3cbxsR0QnCgw=="
},
"@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
"integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/primitive": {
"version": "1.0.1",
@@ -5923,6 +6151,34 @@
"@radix-ui/react-primitive": "1.0.3"
}
},
"@radix-ui/react-checkbox": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz",
"integrity": "sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==",
"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-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
}
},
"@radix-ui/react-collection": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
"integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2"
}
},
"@radix-ui/react-compose-refs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
@@ -5961,6 +6217,14 @@
"react-remove-scroll": "2.5.5"
}
},
"@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
"integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-dismissable-layer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz",
@@ -6054,6 +6318,42 @@
"@radix-ui/react-slot": "1.0.2"
}
},
"@radix-ui/react-roving-focus": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
"integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-callback-ref": "1.0.1",
"@radix-ui/react-use-controllable-state": "1.0.1"
}
},
"@radix-ui/react-slider": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz",
"integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/number": "1.0.1",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-collection": "1.0.3",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1",
"@radix-ui/react-use-previous": "1.0.1",
"@radix-ui/react-use-size": "1.0.1"
}
},
"@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
@@ -6063,6 +6363,32 @@
"@radix-ui/react-compose-refs": "1.0.1"
}
},
"@radix-ui/react-toggle": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
"integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
}
},
"@radix-ui/react-toggle-group": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz",
"integrity": "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-direction": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-roving-focus": "1.0.4",
"@radix-ui/react-toggle": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1"
}
},
"@radix-ui/react-tooltip": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.6.tgz",
@@ -6117,6 +6443,14 @@
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-use-previous": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz",
"integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==",
"requires": {
"@babel/runtime": "^7.13.10"
}
},
"@radix-ui/react-use-rect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz",
+6 -2
View File
@@ -1,5 +1,5 @@
{
"name": "new",
"name": "lego-builder",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -10,9 +10,12 @@
"preview": "vite preview"
},
"dependencies": {
"@radix-ui/colors": "^0.1.8",
"@radix-ui/colors": "^2.0.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-toggle-group": "^1.0.4",
"@react-three/drei": "^9.80.2",
"@react-three/fiber": "^8.13.6",
"framer-motion": "^10.15.1",
@@ -20,6 +23,7 @@
"leva": "^0.9.35",
"r3f-perf": "^7.1.2",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-dom": "^18.2.0",
"three": "^0.155.0",
"use-keyboard-shortcut": "^1.1.6",
+6 -2
View File
@@ -4,7 +4,8 @@
/* eslint-disable react/display-name */
import React, { forwardRef, useMemo } from "react";
import { Vector3 } from "three";
import { getMeasurementsFromDimensions, base } from "../../utils";
import { getMeasurementsFromDimensions, base, CREATE_MODE } from "../../utils";
import { useStore } from "../../store";
export const BrickCursor = forwardRef(
(
@@ -16,10 +17,13 @@ export const BrickCursor = forwardRef(
dimensions = { x: 1, z: 1 },
rotation = 0,
translation = { x: 0, z: 0 },
visible = true,
},
ref
) => {
const mode = useStore((state) => state.mode);
const visible = mode === CREATE_MODE;
const { height, width, depth } = getMeasurementsFromDimensions(dimensions);
const position = useMemo(() => {
+2 -20
View File
@@ -8,18 +8,7 @@ import { useControls } from "leva";
import { OrbitControls } from "@react-three/drei";
export const ControlsWrapper = () => {
const { setEvents, camera } = useThree();
const [{ MultiSelect }, set] = useControls(() => ({
MultiSelect: false,
}));
useEffect(() => {
if (MultiSelect) {
camera.position.set(0, 1000, 0);
camera.lookAt(0, 0, 0);
}
}, [MultiSelect, camera]);
const { setEvents } = useThree();
const startTimeoutID = useRef();
const endTimeoutID = useRef();
@@ -37,12 +26,5 @@ export const ControlsWrapper = () => {
endTimeoutID.current = setTimeout(() => setEvents({ enabled: true }), 500);
};
return (
<OrbitControls
enabled={!MultiSelect}
makeDefault
onEnd={onEnd}
onStart={onStart}
/>
);
return <OrbitControls makeDefault onEnd={onEnd} onStart={onStart} />;
};
+6 -2
View File
@@ -8,10 +8,15 @@ import { LinearToneMapping } from "three";
import { ControlsWrapper, Scene } from ".";
import { DialogBox } from "../UI";
import { Perf } from "r3f-perf";
import { ModeToggleBar } from "../UI/ModeToggleBar";
import { Panel } from "../UI/Panel";
export const LegoRoom = () => {
return (
<>
<DialogBox />
<ModeToggleBar />
<Panel />
<Canvas
gl={{
alpha: false,
@@ -32,9 +37,8 @@ export const LegoRoom = () => {
<Scene />
<ControlsWrapper />
</Suspense>
<Perf position="bottom-left" />
{/* <Perf position="bottom-left" matrixUpdate={true} /> */}
</Canvas>
<DialogBox />
</>
);
};
+16 -84
View File
@@ -18,58 +18,29 @@ import {
base,
useAnchorShorcuts,
minWorkSpaceSize,
EDIT_MODE,
} from "../../utils";
import { button, useControls } from "leva";
import { ChangeColor } from "./ChangeColor";
import { useStore } from "../../store";
export const Scene = () => {
const [bricks, setBricks] = useState([]);
const minWorkSpaceSizeRef = useRef(minWorkSpaceSize);
const [workspaceSize, setWorkspaceSize] = useState(minWorkSpaceSize);
const bricksBoundBox = useRef([]);
const brickCursorRef = useRef();
const box = useMemo(() => new Box3(), []);
const mode = useStore((state) => state.mode);
const [{ width, depth, rotate, color, anchorX, anchorZ, Edit }, set] =
useControls(() => ({
width: {
value: 1,
min: 1,
max: 5,
step: 1,
},
depth: {
value: 1,
min: 1,
max: 5,
step: 1,
},
rotate: false,
color: "#ff0",
anchorX: {
value: 0,
min: -2,
max: 2,
step: 1,
},
anchorZ: {
value: 0,
min: -2,
max: 2,
step: 1,
},
Undo: button((get) => {
undoAddedBrick();
}),
Edit: false,
}));
const isEditMode = mode === EDIT_MODE;
useAnchorShorcuts(anchorX, anchorZ, set);
const width = useStore((state) => state.width);
const depth = useStore((state) => state.depth);
const anchorX = useStore((state) => state.anchorX);
const anchorZ = useStore((state) => state.anchorZ);
const rotate = useStore((state) => state.rotate);
const color = useStore((state) => state.color);
// useAnchorShorcuts(anchorX, anchorZ, set);
const setSelection = useSetSelection();
@@ -84,7 +55,7 @@ export const Scene = () => {
const addBrick = (e) => {
e.stopPropagation();
if (Edit) return;
if (isEditMode) return;
if (!e.face?.normal || !e.point) return;
@@ -99,26 +70,6 @@ export const Scene = () => {
brickCursorRef.current
);
const maxMax = Math.max(
Math.abs(boundingBoxOfBrickToBeAdded.max.x * 2),
Math.abs(boundingBoxOfBrickToBeAdded.max.z * 2)
);
const maxMin = Math.max(
Math.abs(boundingBoxOfBrickToBeAdded.min.x * 2),
Math.abs(boundingBoxOfBrickToBeAdded.min.z * 2)
);
const max = Math.max(maxMax, maxMin);
minWorkSpaceSizeRef.current = Math.max(max, minWorkSpaceSizeRef.current);
setWorkspaceSize((currentSize) => {
if (currentSize <= max) {
return max;
}
return currentSize;
});
let canCreate = true;
for (let index = 0; index < bricksBoundBox.current.length; index++) {
@@ -165,9 +116,8 @@ export const Scene = () => {
const setBrickCursorPosition = (e) => {
e.stopPropagation();
if (Edit) return;
if (isEditMode) return;
if (!brickCursorRef.current) return;
const { height } = getMeasurementsFromDimensions({
x: width,
z: depth,
@@ -191,27 +141,10 @@ export const Scene = () => {
evenDepth ? base : base / 2
)
);
const bb = box.setFromObject(brickCursorRef.current);
const max = bb.max.multiplyScalar(1 / base);
const min = bb.min.multiplyScalar(1 / base);
const brickXEnd = brickCursorRef.current.position.x > 0 ? max.x : min.x;
const brickZEnd = brickCursorRef.current.position.z > 0 ? max.z : min.z;
setWorkspaceSize((currentSize) => {
const sizeDiff = Math.max(
Math.abs(brickXEnd + anchorX) * base * 2 - currentSize,
Math.abs(brickZEnd + anchorZ) * base * 2 - currentSize
);
if (sizeDiff > 0 || currentSize > minWorkSpaceSizeRef.current) {
return currentSize + sizeDiff;
}
return currentSize;
});
};
const onClick = (e) => {
if (!Edit) addBrick(e);
if (!isEditMode) addBrick(e);
};
const mouseMove = (e) => {
@@ -245,7 +178,7 @@ export const Scene = () => {
return (
<>
<color attach="background" args={["#202025"]} />
<Select enable={Edit} box multiple onChange={console.log}>
<Select box multiple onChange={console.log}>
{bricks.map((b, i) => {
return (
<Brick
@@ -265,10 +198,9 @@ export const Scene = () => {
<Workspace
onClick={onClick}
mouseMove={mouseMove}
workspaceSize={workspaceSize}
workspaceSize={minWorkSpaceSize}
/>
<BrickCursor
visible={Edit ? false : true}
ref={brickCursorRef}
rotation={rotate ? Math.PI / 2 : 0}
dimensions={{ x: width, z: depth }}
+5 -17
View File
@@ -6,21 +6,8 @@ import * as THREE from "three";
import { SelectionBox } from "three-stdlib";
import { useThree } from "@react-three/fiber";
import { shallow } from "zustand/shallow";
import { useControls } from "leva";
const useEventControl = () => {
const { setEvents } = useThree();
const [{ events }, set] = useControls(() => ({
events: true,
}));
React.useEffect(() => {
setEvents({ enabled: events });
}, [events, setEvents]);
return null;
};
import { useStore } from "../../../store";
import { EDIT_MODE } from "../../../utils";
const context = React.createContext([]);
const dispatchContext = React.createContext(() => {});
@@ -34,13 +21,14 @@ export function Select({
border = "1px solid #55aaff",
backgroundColor = "rgba(75, 160, 255, 0.1)",
filter: customFilter = (item) => item,
enable,
...props
}) {
const [downed, down] = React.useState(false);
const { setEvents, camera, raycaster, gl, controls, size, get } = useThree();
useEventControl();
const mode = useStore((state) => state.mode);
const enable = mode === EDIT_MODE;
const [active, dispatch] = React.useReducer((state, { object, shift }) => {
if (object === undefined) return [];
+36
View File
@@ -0,0 +1,36 @@
/* eslint-disable no-unused-vars */
import React from "react";
import * as ToggleGroup from "@radix-ui/react-toggle-group";
import "./styles.css";
import { CREATE_MODE, EDIT_MODE } from "../../../utils";
import { useStore } from "../../../store";
export const ModeToggleBar = () => {
const setMode = useStore((state) => state.setMode);
return (
<ToggleGroup.Root
className="ToggleGroup"
type="single"
defaultValue={CREATE_MODE}
aria-label="Text alignment"
>
<ToggleGroup.Item
className="ToggleGroupItem"
value={CREATE_MODE}
aria-label={CREATE_MODE}
onClick={() => setMode(CREATE_MODE)}
>
{CREATE_MODE}
</ToggleGroup.Item>
<ToggleGroup.Item
className="ToggleGroupItem"
value={EDIT_MODE}
aria-label={EDIT_MODE}
onClick={() => setMode(EDIT_MODE)}
>
{EDIT_MODE}
</ToggleGroup.Item>
</ToggleGroup.Root>
);
};
@@ -0,0 +1,47 @@
@import "@radix-ui/colors/black-alpha.css";
@import "@radix-ui/colors/mauve.css";
@import "@radix-ui/colors/violet.css";
/* reset */
button {
all: unset;
}
.ToggleGroup {
display: inline-flex;
background-color: white;
border-radius: 4px;
box-shadow: 0 2px 10px var(--black-a7);
position: fixed;
left: 50%;
top: 15px;
transform: translateX(-50%);
z-index: 1000;
}
.ToggleGroupItem {
background-color: white;
color: var(--mauve-11);
height: 35px;
display: flex;
font-size: 15px;
line-height: 1;
align-items: center;
justify-content: center;
margin: 6px;
padding: 0 4px;
border-radius: 4px;
}
.ToggleGroupItem:hover {
background-color: var(--violet-3);
cursor: pointer;
}
.ToggleGroupItem[data-state="on"] {
background-color: var(--violet-5);
color: var(--violet-11);
}
.ToggleGroupItem:focus {
position: relative;
box-shadow: 0 0 0 2px black;
}
@@ -0,0 +1,39 @@
/* eslint-disable react/prop-types */
/* eslint-disable no-unused-vars */
import React from "react";
import * as CheckboxRadix from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons";
import "./styles.css";
import { useStore } from "../../../../store";
const stateMap = {
rotate: "rotate",
};
const setterMap = {
rotate: "setRotate",
};
export const Checkbox = ({ label = "rotate" }) => {
const setValue = useStore((state) => state[setterMap[label]]);
return (
<div
className="SliderInputContainer"
style={{ display: "flex", alignItems: "center" }}
>
<label className="SliderLabel" htmlFor={label}>
{label}
</label>
<CheckboxRadix.Root
className="CheckboxRoot"
id={label}
onCheckedChange={(bool) => setValue(bool)}
>
<CheckboxRadix.Indicator className="CheckboxIndicator">
<CheckIcon />
</CheckboxRadix.Indicator>
</CheckboxRadix.Root>
</div>
);
};
@@ -0,0 +1,28 @@
@import "@radix-ui/colors/black-alpha.css";
@import "@radix-ui/colors/violet.css";
/* reset */
button {
all: unset;
}
.CheckboxRoot {
background-color: var(--black-a7);
width: 20px;
height: 20px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 10px var(--black-a7);
}
.CheckboxRoot:hover {
cursor: pointer;
}
.CheckboxRoot:focus {
box-shadow: 0 0 0 2px black;
}
.CheckboxIndicator {
color: var(--violet-11);
}
@@ -0,0 +1,16 @@
/* eslint-disable no-unused-vars */
import React from "react";
import { HexColorPicker } from "react-colorful";
import "./styles.css";
import { useStore } from "../../../../store";
export const ColorInput = () => {
const setColor = useStore((state) => state.setColor);
return (
<div className="SliderInputContainer">
<label className="SliderLabel">Color</label>
<HexColorPicker color="#000000" onChange={(color) => setColor(color)} />
</div>
);
};
@@ -0,0 +1,31 @@
@import "@radix-ui/colors/black-alpha.css";
.SliderInputContainer .react-colorful__saturation-pointer {
width: 10px;
height: 10px;
}
.SliderInputContainer .react-colorful__saturation {
border-bottom: none;
margin: 10px 0;
border-radius: 4px;
}
.SliderInputContainer .react-colorful__hue-pointer {
width: 10px;
height: 10px;
}
.SliderInputContainer .react-colorful__hue {
height: 8px;
/* padding: 8px; */
border-radius: 2px;
}
.SliderInputContainer .react-colorful {
width: 150px;
height: 150px;
border-radius: 4px;
padding: 8px;
background-color: var(--black-a7);
}
+51
View File
@@ -0,0 +1,51 @@
/* eslint-disable react/prop-types */
/* eslint-disable no-unused-vars */
import React, { useState } from "react";
import * as Slider from "@radix-ui/react-slider";
import "./styles.css";
import { useStore } from "../../../../store";
const stateMap = {
width: "width",
depth: "depth",
"anchor X": "anchorX",
"anchor Z": "anchorZ",
};
const setterMap = {
width: "setWidth",
depth: "setDepth",
"anchor X": "setAnchorX",
"anchor Z": "setAnchorZ",
};
export const SliderWithLabel = ({
label = "width",
defaultValue = 1,
...props
}) => {
const value = useStore((state) => state[stateMap[label]]);
const setValue = useStore((state) => state[setterMap[label]]);
return (
<div className="SliderInputContainer">
<label className="SliderLabel">{label}</label>
<Slider.Root
className="SliderRoot"
defaultValue={[defaultValue]}
max={4}
step={1}
min={1}
onValueChange={(newVal) => setValue(newVal)}
{...props}
>
<Slider.Track className="SliderTrack">
<Slider.Range className="SliderRange" />
</Slider.Track>
<Slider.Thumb className="SliderThumb" aria-label={label}>
{value}
</Slider.Thumb>
</Slider.Root>
</div>
);
};
+68
View File
@@ -0,0 +1,68 @@
@import "@radix-ui/colors/black-alpha.css";
@import "@radix-ui/colors/violet.css";
.SliderInputContainer {
display: flex;
align-items: center;
gap: 8px;
margin: 14px 0;
padding: 8px;
}
.SliderRoot {
position: relative;
display: flex;
align-items: center;
user-select: none;
touch-action: none;
width: 150px;
height: 20px;
}
.SliderTrack {
background-color: var(--black-a7);
position: relative;
flex-grow: 1;
border-radius: 9999px;
height: 3px;
}
.SliderRange {
position: absolute;
background-color: var(--black-a12);
border-radius: 9999px;
height: 100%;
}
.SliderThumb {
display: block;
width: 20px;
height: 20px;
background-color: black;
box-shadow: 0 2px 10px var(--black-a7);
border-radius: 10px;
color: white;
display: flex;
justify-content: center;
align-items: center;
font-size: 10px;
}
.SliderThumb:hover {
cursor: pointer;
}
.SliderThumb:focus {
outline: none;
box-shadow: 0 0 0 5px var(--black-a8);
}
.SliderLabel {
font-size: 15px;
font-weight: 500;
line-height: 35px;
color: var(--black-a12);
text-transform: capitalize;
font-weight: 600;
min-width: 75px;
font-size: 14px;
}
+20
View File
@@ -0,0 +1,20 @@
/* eslint-disable react/prop-types */
/* eslint-disable no-unused-vars */
import React from "react";
import "./styles.css";
import { SliderWithLabel } from "./Slider";
import { Checkbox } from "./Checkbox";
import { ColorInput } from "./ColorInput";
export const Panel = () => {
return (
<div className="Panel">
<SliderWithLabel label="width" />
<SliderWithLabel label="depth" />
<SliderWithLabel label="anchor X" min={-2} defaultValue={0} max={2} />
<SliderWithLabel label="anchor Z" min={-2} defaultValue={0} max={2} />
<Checkbox />
<ColorInput />
</div>
);
};
+10
View File
@@ -0,0 +1,10 @@
.Panel {
position: fixed;
left: 20px;
top: 50%;
transform: translateY(-50%);
z-index: 10000;
background: white;
border-radius: 4px;
padding: 10px;
}
-69
View File
@@ -1,69 +0,0 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
+6 -7
View File
@@ -1,10 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
ReactDOM.createRoot(document.getElementById('root')).render(
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
</React.StrictMode>
);
+25
View File
@@ -0,0 +1,25 @@
import { create } from "zustand";
import { CREATE_MODE, defaultAnchor, defaultWidth } from "../utils";
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 }),
}));
+7 -1
View File
@@ -1,7 +1,13 @@
export const base = 25;
export const knobSize = 7;
export const outlineWidth = 1.3;
export const minWorkSpaceSize = 500;
export const minWorkSpaceSize = 1000;
export const CREATE_MODE = "Create Mode";
export const EDIT_MODE = "Edit Mode";
export const defaultWidth = 1;
export const defaultAnchor = 0;
export const bricks = [
{ x: 1, z: 1 },
+2 -2
View File
@@ -9,7 +9,7 @@ export function CSSToHex(cssColor) {
export function getMeasurementsFromDimensions({ x, y, z }) {
return {
width: base * x,
height: base * y || (base * 2) / 1.5,
height: base * y || base,
depth: base * z,
};
}
@@ -34,7 +34,7 @@ export function createGeometry({
for (let j = 0; j < dimensions.z; j++) {
const cylinder = new CylinderGeometry(knobDim, knobDim, knobDim, 20);
const x = base * i - ((dimensions.x - 1) * base) / 2;
const y = base / 1.5;
const y = base - 12.5;
const z = base * j - ((dimensions.z - 1) * base) / 2;
cylinder.translate(x, y, z);
geometries.push(cylinder);