lost css
parent
c6a3803b8d
commit
b54b871fa3
|
@ -0,0 +1,185 @@
|
|||
/* @tailwind base; */
|
||||
|
||||
.bg-gray-50 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.justify-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.75rem;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.p-1 {
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
* {
|
||||
--tw-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
* {
|
||||
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgba(59, 130, 246, 0.5);
|
||||
--tw-ring-offset-shadow: 0 0 #0000;
|
||||
--tw-ring-shadow: 0 0 #0000;
|
||||
}
|
||||
|
||||
.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ping {
|
||||
75%, 100% {
|
||||
transform: scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
50% {
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% {
|
||||
transform: translateY(-25%);
|
||||
animation-timing-function: cubic-bezier(0.8,0,1,1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: none;
|
||||
animation-timing-function: cubic-bezier(0,0,0.2,1);
|
||||
}
|
||||
}
|
||||
|
||||
/* html, */
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
overflow: hidden;
|
||||
--topNavH: 36px;
|
||||
--sideNavW: 200px;
|
||||
}
|
||||
|
||||
#c {
|
||||
position: absolute;
|
||||
width: calc(100% - var(--sideNavW));
|
||||
height: calc(100% - var(--topNavH));
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.topNav {
|
||||
position: absolute;
|
||||
height: var(--topNavH);
|
||||
left:0;
|
||||
right:0;
|
||||
top:0;
|
||||
}
|
||||
|
||||
.sideNav {
|
||||
position: absolute;
|
||||
top: var(--topNavH);
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: var(--sideNavW);
|
||||
}
|
||||
|
||||
#labels > div {
|
||||
position: absolute;
|
||||
border: solid 1px black;
|
||||
}
|
||||
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgba(243, 244, 246, var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgba(229, 231, 235, var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.btn {
|
||||
fill: currentColor;
|
||||
--tw-text-opacity: 1;
|
||||
color: rgba(5, 150, 105, var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgba(4, 120, 87, var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<div id="react"></div>
|
||||
<div id="labels"></div>
|
||||
<div id="stats"></div>
|
||||
<script src="index.bundle.js"></script>
|
||||
<script src="app.bundle.js"></script>
|
||||
<script src="scene.bundle.js"></script>
|
||||
<script src="solver.js"></script>
|
||||
<script src="lz-string.min.js"></script>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
import * as THREE from '../node_modules/three/src/Three';
|
||||
|
||||
import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEvents'
|
||||
import { onHover, onDrag, onDragDim, onPick, onRelease } from './mouseEvents'
|
||||
import { addDimension, setCoincident } from './constraintEvents'
|
||||
import { get3PtArc } from './drawArc'
|
||||
import { _vec2, _vec3, raycaster, awaitPts } from './shared'
|
||||
|
||||
import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEvents'
|
||||
import { onHover, onDrag, onPick, onRelease } from './mouseEvents'
|
||||
import { setCoincident } from './constraintEvents'
|
||||
import { get3PtArc } from './drawArc'
|
||||
import { replacer, reviver } from './utils'
|
||||
import { AxesHelper } from './sketchAxes'
|
||||
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
||||
|
|
40
src/app.css
40
src/app.css
|
@ -1,38 +1,36 @@
|
|||
/* @tailwind base; */
|
||||
@tailwind utilities;
|
||||
|
||||
html,
|
||||
/* html, */
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
overflow: hidden;
|
||||
--topNavH: 36px;
|
||||
--sideNavW: 200px;
|
||||
}
|
||||
|
||||
#c {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
width: calc(100% - var(--sideNavW));
|
||||
height: calc(100% - var(--topNavH));
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#react > div {
|
||||
|
||||
.topNav {
|
||||
position: absolute;
|
||||
height: var(--topNavH);
|
||||
left:0;
|
||||
right:0;
|
||||
top:0;
|
||||
}
|
||||
|
||||
.btn-red {
|
||||
cursor: pointer;
|
||||
@apply bg-red-500 hover:bg-red-600 text-gray-50;
|
||||
}
|
||||
|
||||
.btn-grn {
|
||||
cursor: pointer;
|
||||
@apply bg-green-500 hover:bg-green-600 text-gray-50;
|
||||
}
|
||||
|
||||
.btn-blu {
|
||||
cursor: pointer;
|
||||
@apply bg-blue-500 hover:bg-blue-600 text-gray-50;
|
||||
.sideNav {
|
||||
position: absolute;
|
||||
top: var(--topNavH);
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: var(--sideNavW);
|
||||
}
|
||||
|
||||
|
||||
|
|
221
src/app.jsx
221
src/app.jsx
|
@ -1,214 +1,31 @@
|
|||
|
||||
import ReactDOM from 'react-dom'
|
||||
import React from 'react'
|
||||
|
||||
import { createStore, applyMiddleware} from 'redux'
|
||||
import { Provider } from 'react-redux'
|
||||
import logger from 'redux-logger'
|
||||
|
||||
|
||||
import { Tree } from './treeEntry'
|
||||
import { NavBar } from './navBar'
|
||||
import { reducer, preloadedState } from './reducer'
|
||||
|
||||
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
||||
import './app.css'
|
||||
|
||||
import { Provider, useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
import { FaCube, FaEdit } from 'react-icons/fa'
|
||||
import { MdEdit, MdDone, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
||||
import * as Icon from "./icons";
|
||||
// import { color } from './shared'
|
||||
window.store = createStore(reducer, preloadedState, applyMiddleware(logger))
|
||||
|
||||
export const Root = ({ store }) => (
|
||||
|
||||
const App = ({ store }) => (
|
||||
<Provider store={store}>
|
||||
<App></App>
|
||||
<NavBar />
|
||||
<Tree />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
const App = () => {
|
||||
const dispatch = useDispatch()
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeSketchId) {
|
||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
||||
return () => {
|
||||
sc.canvas.removeEventListener('pointermove', sc.onHover)
|
||||
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
||||
}
|
||||
}
|
||||
}, [activeSketchId])
|
||||
|
||||
|
||||
const btnz = [
|
||||
activeSketchId ?
|
||||
[MdDone, () => {
|
||||
treeEntries.byId[activeSketchId].deactivate()
|
||||
sc.activeSketch = null
|
||||
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
||||
}, 'Finish'] :
|
||||
[FaEdit, sc.addSketch, 'Sketch']
|
||||
,
|
||||
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
||||
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
||||
[Icon.Subtract, () => {
|
||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
||||
// console.log('here')
|
||||
const [m1, m2] = sc.selected
|
||||
const mesh = subtract(m1, m2)
|
||||
|
||||
console.log(mesh, 'meshres')
|
||||
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}, 'Subtract'],
|
||||
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
||||
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension'],
|
||||
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line'],
|
||||
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc'],
|
||||
]
|
||||
|
||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||
|
||||
return <>
|
||||
<div className='absolute flex ml-auto mr-auto left-0 right-0 justify-center'>
|
||||
{/* <div className='absolute flex justify-center'> */}
|
||||
{
|
||||
btnz.map(([Icon, fcn, txt], idx) => (
|
||||
<div className="btn flex items-center justify-start p-1 text-lg" key={idx}
|
||||
onClick={fcn}
|
||||
>
|
||||
<Icon className="w-6 h-6" />
|
||||
<div className="ml-2">{txt}</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className='absolute left-0 top-36 w-40 flex flex-col'>
|
||||
{treeEntries.allIds.map((entId, idx) => (
|
||||
<TreeEntry key={idx} entId={entId} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
</>
|
||||
|
||||
}
|
||||
|
||||
const TreeEntry = ({ entId }) => {
|
||||
|
||||
const treeEntries = useSelector(state => state.treeEntries.byId)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||
|
||||
let obj3d, entry;
|
||||
|
||||
entry = treeEntries[entId]
|
||||
|
||||
if (entId[0] == "s") {
|
||||
obj3d = treeEntries[entId].obj3d
|
||||
} else {
|
||||
obj3d = treeEntries[entId]
|
||||
}
|
||||
|
||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||
|
||||
const vis = obj3d.visible
|
||||
|
||||
return <div className='bg-gray-50 flex justify-between w-full'>
|
||||
<div className="btn"
|
||||
onPointerEnter={() => {
|
||||
if (entId[0] == 'm') {
|
||||
// entry.material.color.set(color.hover)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
onPointerLeave={() => {
|
||||
const obj = entry
|
||||
if (entId[0] == 'm' && !sc.selected.includes(obj)) {
|
||||
// obj.material.color.set(color.mesh)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
onPointerDown={() => {
|
||||
if (entId[0] == 'm') {
|
||||
sc.selected.push(
|
||||
entry
|
||||
)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{entId}
|
||||
</div>
|
||||
<div className='flex'>
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
activeSketchId && treeEntries[activeSketchId].deactivate()
|
||||
entry.activate()
|
||||
sc.clearSelection()
|
||||
sc.activeSketch = entry;
|
||||
}}
|
||||
>
|
||||
<MdEdit />
|
||||
</div>
|
||||
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
dispatch({ type: 'delete-node', id: entId })
|
||||
}}
|
||||
>
|
||||
<MdDelete />
|
||||
</div>
|
||||
{
|
||||
vis ?
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
obj3d.visible = false;
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}}
|
||||
>
|
||||
<MdVisibility />
|
||||
</div>
|
||||
:
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
obj3d.visible = true;
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}}
|
||||
>
|
||||
<MdVisibilityOff />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
const subtract = (m1, m2) => {
|
||||
// //Create a bsp tree from each of the meshes
|
||||
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
||||
|
||||
|
||||
let bspA = BoolOp.fromMesh(m1)
|
||||
let bspB = BoolOp.fromMesh(m2)
|
||||
m1.visible = false
|
||||
m2.visible = false
|
||||
|
||||
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
||||
|
||||
let bspResult = bspA.subtract(bspB)
|
||||
|
||||
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
||||
|
||||
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
||||
meshResult.userData.type = 'mesh'
|
||||
meshResult.name = `${m1.name}-${m2.name}`
|
||||
|
||||
sc.obj3d.add(meshResult)
|
||||
|
||||
return meshResult
|
||||
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
ReactDOM.render(<App store={store} />, document.getElementById('react'));
|
||||
});
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ export function onHover(e) {
|
|||
|
||||
if (hoverPts.length) {
|
||||
|
||||
console.log(hoverPts)
|
||||
// for (let i = 0; i < hoverPts.length; i++) {
|
||||
// const obj = hoverPts[i].object
|
||||
// if (['point', 'plane'].includes(obj.userData.type)) {
|
||||
|
@ -50,7 +51,6 @@ export function onHover(e) {
|
|||
// break;
|
||||
// }
|
||||
// }
|
||||
// console.log(hoverPts)
|
||||
|
||||
|
||||
let minDist = Infinity;
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
|
||||
import React, { useEffect, useReducer} from 'react';
|
||||
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
import { FaCube, FaEdit } from 'react-icons/fa'
|
||||
import { MdDone } from 'react-icons/md'
|
||||
import * as Icon from "./icons";
|
||||
|
||||
|
||||
|
||||
export const NavBar = () => {
|
||||
const dispatch = useDispatch()
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeSketchId) {
|
||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||
sc.canvas.addEventListener('pointerdown', sc.onPick)
|
||||
return () => {
|
||||
sc.canvas.removeEventListener('pointermove', sc.onHover)
|
||||
sc.canvas.removeEventListener('pointerdown', sc.onPick)
|
||||
}
|
||||
}
|
||||
}, [activeSketchId])
|
||||
|
||||
|
||||
const btnz = [
|
||||
activeSketchId ?
|
||||
[MdDone, () => {
|
||||
treeEntries.byId[activeSketchId].deactivate()
|
||||
sc.activeSketch = null
|
||||
// sc.activeDim = this.activeSketch.obj3d.children[1].children
|
||||
}, 'Finish'] :
|
||||
[FaEdit, sc.addSketch, 'Sketch']
|
||||
,
|
||||
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude'],
|
||||
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
||||
[Icon.Subtract, () => {
|
||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
||||
// console.log('here')
|
||||
const [m1, m2] = sc.selected
|
||||
const mesh = subtract(m1, m2)
|
||||
|
||||
console.log(mesh, 'meshres')
|
||||
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}, 'Subtract'],
|
||||
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
||||
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension'],
|
||||
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line'],
|
||||
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc'],
|
||||
]
|
||||
|
||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||
|
||||
return <div className='topNav flex justify-center'>
|
||||
{
|
||||
btnz.map(([Icon, fcn, txt], idx) => (
|
||||
<div className="btn flex items-center justify-start p-1 text-lg" key={idx}
|
||||
onClick={fcn}
|
||||
>
|
||||
<Icon className="w-6 h-6" />
|
||||
<div className="ml-2" tooltip="wtf">{txt}</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
const subtract = (m1, m2) => {
|
||||
// //Create a bsp tree from each of the meshes
|
||||
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
|
||||
|
||||
|
||||
let bspA = BoolOp.fromMesh(m1)
|
||||
let bspB = BoolOp.fromMesh(m2)
|
||||
m1.visible = false
|
||||
m2.visible = false
|
||||
|
||||
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
||||
|
||||
let bspResult = bspA.subtract(bspB)
|
||||
|
||||
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
||||
|
||||
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
|
||||
meshResult.userData.type = 'mesh'
|
||||
meshResult.name = `${m1.name}-${m2.name}`
|
||||
|
||||
sc.obj3d.add(meshResult)
|
||||
|
||||
return meshResult
|
||||
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
|
||||
import ReactDOM from 'react-dom'
|
||||
import React from 'react'
|
||||
import { Root } from './app.jsx'
|
||||
import update from 'immutability-helper';
|
||||
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import logger from 'redux-logger'
|
||||
|
||||
import { DepTree } from './depTree.mjs'
|
||||
import update from 'immutability-helper'
|
||||
|
||||
|
||||
export const preloadedState = {
|
||||
treeEntries: {
|
||||
byId: {},
|
||||
allIds: [],
|
||||
tree: {},
|
||||
order: {},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
function reducer(state = {}, action) {
|
||||
export function reducer(state = {}, action) {
|
||||
switch (action.type) {
|
||||
case 'rx-sketch':
|
||||
return update(state, {
|
||||
|
@ -84,21 +85,3 @@ function reducer(state = {}, action) {
|
|||
|
||||
|
||||
|
||||
const preloadedState = {
|
||||
treeEntries: {
|
||||
byId: {},
|
||||
allIds: [],
|
||||
tree: {},
|
||||
order: {},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
window.store = createStore(reducer, preloadedState, applyMiddleware(logger))
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
ReactDOM.render(<Root store={store} />, document.getElementById('react'));
|
||||
});
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
|
||||
import React, { useReducer } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { MdEdit, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
|
||||
|
||||
|
||||
export const Tree = () => {
|
||||
const treeEntries = useSelector(state => state.treeEntries)
|
||||
|
||||
return <div className='sideNav flex flex-col'>
|
||||
{treeEntries.allIds.map((entId, idx) => (
|
||||
<TreeEntry key={idx} entId={entId} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
|
||||
const TreeEntry = ({ entId }) => {
|
||||
|
||||
const treeEntries = useSelector(state => state.treeEntries.byId)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const activeSketchId = useSelector(state => state.activeSketchId)
|
||||
|
||||
let obj3d, entry;
|
||||
|
||||
entry = treeEntries[entId]
|
||||
|
||||
if (entId[0] == "s") {
|
||||
obj3d = treeEntries[entId].obj3d
|
||||
} else {
|
||||
obj3d = treeEntries[entId]
|
||||
}
|
||||
|
||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||
|
||||
const vis = obj3d.visible
|
||||
|
||||
return <div className='bg-gray-50 flex justify-between w-full'>
|
||||
<div className="btn"
|
||||
onPointerEnter={() => {
|
||||
if (entId[0] == 'm') {
|
||||
// entry.material.color.set(color.hover)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
onPointerLeave={() => {
|
||||
const obj = entry
|
||||
if (entId[0] == 'm' && !sc.selected.includes(obj)) {
|
||||
// obj.material.color.set(color.mesh)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
onPointerDown={() => {
|
||||
if (entId[0] == 'm') {
|
||||
sc.selected.push(
|
||||
entry
|
||||
)
|
||||
sc.render()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{entId}
|
||||
</div>
|
||||
<div className='flex'>
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
activeSketchId && treeEntries[activeSketchId].deactivate()
|
||||
entry.activate()
|
||||
sc.clearSelection()
|
||||
sc.activeSketch = entry;
|
||||
}}
|
||||
>
|
||||
<MdEdit />
|
||||
</div>
|
||||
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
dispatch({ type: 'delete-node', id: entId })
|
||||
}}
|
||||
>
|
||||
<MdDelete />
|
||||
</div>
|
||||
{
|
||||
vis ?
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
obj3d.visible = false;
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}}
|
||||
>
|
||||
<MdVisibility />
|
||||
</div>
|
||||
:
|
||||
<div className='btn'
|
||||
onClick={() => {
|
||||
obj3d.visible = true;
|
||||
sc.render()
|
||||
forceUpdate()
|
||||
}}
|
||||
>
|
||||
<MdVisibilityOff />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@ const tailwindcss = require('tailwindcss')
|
|||
|
||||
module.exports = {
|
||||
entry: {
|
||||
index: './src/index.jsx',
|
||||
app: './src/app.jsx',
|
||||
scene: './src/Scene.js',
|
||||
},
|
||||
output: {
|
||||
|
|
Loading…
Reference in New Issue