consolidate carousel

master
howard 2021-04-29 20:29:02 -07:00
parent 525a13171c
commit bdcc41176f
5 changed files with 225 additions and 91 deletions

View File

@ -14,6 +14,8 @@ combine multiple solids to form the part you desire
uplaod your design to a 3d printer uplaod your design to a 3d printer
navigation tips
General Workflow for part creation General Workflow for part creation

View File

@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useReducer, useRef } from 'react';
import { MdArrowBack, MdArrowForward } from 'react-icons/md'
export function throttle(callback, limit) { export function throttle(callback, limit) {
let handler = null; // Initially, we're not waiting let handler = null; // Initially, we're not waiting
@ -26,101 +27,97 @@ const transTime = 200
const elastic = `transform ${transTime}ms cubic-bezier(0.4, 0.0, 0.2, 1)`; const elastic = `transform ${transTime}ms cubic-bezier(0.4, 0.0, 0.2, 1)`;
function reducer(state, action) {
switch (action.type) {
case 'set-rect':
return {
...state,
rect: action.rect
};
case 'resize':
return {
...state,
rect: action.rect,
dragLeft: state.pg * action.rect.width,
dragging: true
};
case 'move':
return {
...state,
pg: state.pg + action.del,
dragging: false
};
case 'drag-start':
return {
...state,
dragLeft: state.pg * state.rect.width,
dragging: true
};
case 'drag':
return {
...state,
dragLeft: state.dragLeft - action.move
};
case 'drag-end':
return {
...state,
pg: Math.round(state.dragLeft / state.rect.width),
dragging: false
};
default:
console.log('wtf')
console.error(action)
}
}
export const Carousel = () => { export const Carousel = () => {
const arr = [1, 2, 3] const arr = [1, 2, 3]
const ref = useRef(null) const ref = useRef(null)
const [dragging, setDragging] = useState(false) const [state, dispatch] = useReducer(reducer, { rect: {}, pg: 0, dragLeft: 0, dragging: false })
// const dragging = useRef(false)
const [rect, setRect] = useState({})
const [pg, setPg] = useState(0)
const [dragLeft, setDragLeft] = useState(0)
useEffect(() => { useEffect(() => {
setRect(ref.current.getBoundingClientRect()) dispatch({ type: 'set-rect', rect: ref.current.getBoundingClientRect() })
}, [ref]) }, [ref])
const updateSize = useCallback( const updateSize = useCallback(
debounce( debounce(
// throttle(
() => { () => {
setRect(ref.current.getBoundingClientRect()) dispatch({ type: 'resize', rect: ref.current.getBoundingClientRect() })
} }
, 200 , 200
) )
, [] , []
) )
// const updateSize = () => setRect(ref.current.getBoundingClientRect())
useEffect(() => {
// dragging.current = false
// console.log(dragging)
// setDragLeft(pg * rect.width)
// setDragging(false)
}, [rect])
useEffect(() => { useEffect(() => {
window.addEventListener('resize', updateSize) window.addEventListener('resize', updateSize)
return () => window.removeEventListener('resize', updateSize)
}, []) }, [])
return <> return <>
<div
className='select-none'
onClick={ <div className='bg-transparent h-full w-full'
() => setPg(pg + 1)
}>1</div>
<div
className='select-none'
onClick={
() => setPg(pg - 1)
}
>2</div>
<div
ref={ref} ref={ref}
className='relative overflow-visible bg-gray-200 h-full w-full'
> >
{rect.width && {state.rect.width &&
<div <div className='absolute top-0 overflow-visible bg-green-400 h-full'
className='absolute overflow-visible bg-green-400'
onMouseDown={() => { onMouseDown={() => dispatch({ type: 'drag-start' })}
setDragging(true) onMouseMove={(e) => e.buttons == 1 && dispatch({ type: 'drag', move: e.movementX })}
// dragging.current = true onMouseUp={() => dispatch({ type: 'drag-end' })}
setDragLeft(pg * rect.width)
}}
onMouseMove={(e) => {
if (e.buttons != 1) return
setDragLeft(state => state + e.movementX)
}}
onMouseUp={(e) => {
// dragging.current = false
setPg(Math.round(dragLeft / rect.width))
setDragging(false)
}}
style={{ style={{
height: '80%', width: 1 * state.rect.width,
width: 1 * rect.width, transform: `translateX(${state.dragging ? -state.dragLeft : -state.pg * state.rect.width}px)`,
top: 0, transition: state.dragging ? null : elastic
// left: dragging ? dragLeft : pg * rect.width, }}
left: 0, >
transform: `translateX(${dragging ? dragLeft : pg * rect.width}px)`,
transition: dragging ? null : elastic
}}>
{ {
arr.map((e, idx) => { arr.map((e, idx) => {
@ -132,6 +129,24 @@ export const Carousel = () => {
</div> </div>
} }
</div> </div>
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -left-24 fill-current bg-gray-100 rounded-full'
onClick={() => dispatch({ type: "move", del: -1 })}
>
<MdArrowBack className="w-full h-full text-gray-700 p-3" />
</div>
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -right-24 fill-current bg-gray-100 rounded-full'
onClick={() => dispatch({ type: "move", del: 1 })}
>
<MdArrowForward className="w-full h-full text-gray-700 p-3" />
</div>
<div className="flex w-full -bottom-8 absolute flex justify-center items-center">
{arr.map((ele, idx) => (
<div key={idx} className={`h-2 w-2 mx-1 rounded-full ${idx == state.pg ? 'bg-gray-50' : 'bg-gray-500'}`}></div>
))}
</div>
</> </>
} }

View File

@ -1,9 +1,10 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useReducer, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import { MdCancel, MdClose, MdHelpOutline } from 'react-icons/md' import { MdCancel, MdArrowBack, MdArrowForward } from 'react-icons/md'
import { Carousel } from './carousel' import { Carousel } from './carousel'
@ -34,54 +35,162 @@ const exportTS = [
10, 'result', 10, 'result',
] ]
function debounce(callback, delay) {
let handler = null;
return (...args) => {
clearTimeout(handler);
handler = setTimeout(() => callback(...args), delay);
}
}
function reducer(state, action) {
switch (action.type) {
case 'resize':
return {
...state,
rect: window.innerHeight * 0.6,
dragLeft: state.pg * window.innerHeight * 0.6,
dragging: true
};
case 'move':
return {
...state,
pg: state.pg + action.del,
dragging: false
};
case 'drag-start':
return {
...state,
dragLeft: state.pg * state.rect,
dragging: true
};
case 'drag':
return {
...state,
dragLeft: state.dragLeft - action.move
};
case 'drag-end':
return {
...state,
pg: Math.round(state.dragLeft / state.rect),
dragging: false
};
default:
console.error(action)
// throw new Error();
}
}
const transTime = 200
const elastic = `transform ${transTime}ms cubic-bezier(0.4, 0.0, 0.2, 1)`;
export const Help = () => { export const Help = () => {
const dispatch = useDispatch()
const status = useSelector(state => state.ui.help)
const handleClick = (e) => { const handleClick = (e) => {
/* if (!e.composedPath().includes(ref.current)
this handles inside click as well due to bubbling, ) {
sets the open/close state of drop down e.stopPropagation() // prevents mouse from immediately clicking nav button if over it
*/ dispatch({ type: 'set-help', status: false })
!e.composedPath().includes(ref.current) && dispatch({ type: 'set-help', status: false })
}
} }
const handleTimeUpdate = (e) => {
}
const ref = useRef()
const vidRef = useRef()
useEffect(() => { useEffect(() => {
if (!status) return
document.addEventListener( // handles click outside buttona & dropdown document.addEventListener( // handles click outside buttona & dropdown
'pointerdown', 'click',
handleClick handleClick
, ,
{ capture: true } // capture phase to allow for stopPropogation on others { capture: true } // capture phase to allow for stopPropogation on others
) )
return () => document.removeEventListener('pointerdown', handleClick) return () => {
document.removeEventListener('click', handleClick, { capture: true }) // important to include options if it was specified
}
}, [status])
const arr = [1, 2, 3]
const ref = useRef(null)
const [state, carouselDispatch] = useReducer(reducer, { rect: window.innerHeight * 0.6, pg: 0, dragLeft: 0, dragging: false })
const updateSize = useCallback(
debounce(
() => {
carouselDispatch({ type: 'resize' })
}
, 200
)
, []
)
useEffect(() => {
window.addEventListener('resize', updateSize)
}, []) }, [])
const dispatch = useDispatch()
const [open, setOpen] = useState(false)
const status = useSelector(state => state.ui.help)
if (status) { if (status) {
return <div className="absolute w-1/5 h-1/5 left-0 top-0 right-0 bottom-0 m-auto bg-green-200 return <div className="absolute h-3/5 left-0 top-0 right-0 bottom-0 m-auto bg-transparent
flex flex-col items-center flex flex-col items-center
" "
// return <div className="absolute w-full h-full bg-green-200" style={{
// onClick={handleInsideClick} width: 1 * state.rect,
}}
ref={ref} ref={ref}
> >
<MdCancel className="btn-green absolute h-7 w-auto right-4 top-4"/> <div className='absolute top-0 overflow-visible bg-green-400 h-full'
<Carousel />
onMouseDown={() => carouselDispatch({ type: 'drag-start' })}
onMouseMove={(e) => e.buttons == 1 && carouselDispatch({ type: 'drag', move: e.movementX })}
onMouseUp={() => carouselDispatch({ type: 'drag-end' })}
style={{
width: 1 * state.rect,
transform: `translateX(${state.dragging ? -state.dragLeft : -state.pg * state.rect}px)`,
transition: state.dragging ? null : elastic
}}
>
{
arr.map((e, idx) => {
return <div key={idx} style={{}}>
hi {e}
</div>
})
}
</div>
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -left-24 fill-current bg-gray-100 rounded-full'
onClick={() => carouselDispatch({ type: "move", del: -1 })}
>
<MdArrowBack className="w-full h-full text-gray-700 p-3" />
</div>
<div className='select-none absolute w-12 h-12 top-0 bottom-0 my-auto -right-24 fill-current bg-gray-100 rounded-full'
onClick={() => carouselDispatch({ type: "move", del: 1 })}
>
<MdArrowForward className="w-full h-full text-gray-700 p-3" />
</div>
<div className="flex w-full -bottom-8 absolute flex justify-center items-center">
{arr.map((ele, idx) => (
<div key={idx} className={`h-2 w-2 mx-1 rounded-full ${idx == state.pg ? 'bg-gray-50' : 'bg-gray-500'}`}></div>
))}
</div>
<MdCancel className="btn-green absolute h-7 w-auto right-4 top-4"
onClick={() => dispatch({ type: 'set-help', status: false })}
/>
</div > </div >
} else { } else {
return null return null

View File

@ -31,6 +31,7 @@ export const NavBar = () => {
const modified = useSelector(state => state.ui.modified) const modified = useSelector(state => state.ui.modified)
const fileName = useSelector(state => state.ui.fileName) const fileName = useSelector(state => state.ui.fileName)
const mode = useSelector(state => state.ui.mode) const mode = useSelector(state => state.ui.mode)
const help = useSelector(state => state.ui.help)
const boolOp = (code) => { const boolOp = (code) => {
if (sce.selected.length != 2 || !sce.selected.every(e => e.userData.type == 'mesh')) { if (sce.selected.length != 2 || !sce.selected.every(e => e.userData.type == 'mesh')) {
@ -194,7 +195,10 @@ export const NavBar = () => {
} }
</div> </div>
<div className='w-auto h-full flex-1 items-center justify-end flex-shrink-1 hidden md:flex'> <div className='w-auto h-full flex-1 items-center justify-end flex-shrink-1 hidden md:flex'>
<MdHelpOutline className="btn-green w-auto h-full p-3" onClick={()=>dispatch({type:'set-help', status:true})}/> <MdHelpOutline className="btn-green w-auto h-full p-3" onClick={() => {
dispatch({ type: 'set-help', status: true })
}
} />
<a href='https://github.com/twpride/three.cad' className='h-full w=auto'> <a href='https://github.com/twpride/three.cad' className='h-full w=auto'>
<FaGithub className="btn-green w-auto h-full p-3.5"></FaGithub> <FaGithub className="btn-green w-auto h-full p-3.5"></FaGithub>
</a> </a>

View File

@ -199,6 +199,10 @@ export function ui(state = defaultUIState, action) {
return update(state, { return update(state, {
help: { $set: action.status } help: { $set: action.status }
}) })
case 'toggle-help':
return update(state, {
help: { $set: !state.help }
})
default: default:
return state return state