diff --git a/demo/left-click.svg b/demo/left-click.svg new file mode 100644 index 0000000..67c7578 --- /dev/null +++ b/demo/left-click.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/demo/middle-click.svg b/demo/middle-click.svg new file mode 100644 index 0000000..7f0e4ea --- /dev/null +++ b/demo/middle-click.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/demo/mouse.original.svg b/demo/mouse.original.svg new file mode 100644 index 0000000..3947979 --- /dev/null +++ b/demo/mouse.original.svg @@ -0,0 +1,262 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/mouse.svg b/demo/mouse.svg new file mode 100644 index 0000000..10321b3 --- /dev/null +++ b/demo/mouse.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/demo/right-click.svg b/demo/right-click.svg new file mode 100644 index 0000000..0ebfdc6 --- /dev/null +++ b/demo/right-click.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/demo/scroll.svg b/demo/scroll.svg new file mode 100644 index 0000000..564ab54 --- /dev/null +++ b/demo/scroll.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/demo/user-guide.md b/demo/user-guide.md index 60be946..dba4bcf 100644 --- a/demo/user-guide.md +++ b/demo/user-guide.md @@ -6,15 +6,18 @@ -Draw a two outline using lines and arcs -Extrude the ouline into a 3d solid +s -combine multiple solids to form the part you desire +Turn the shapes you drew into 3D solids + +Combine multiple solids to form more complex solids uplaod your design to a 3d printer -navigation tips +navigation tip + +offer to watch three video demos diff --git a/dist/export-to-3dprint.mp4 b/dist/export-to-3dprint.mp4 new file mode 100644 index 0000000..1184fdf Binary files /dev/null and b/dist/export-to-3dprint.mp4 differ diff --git a/dist/load-file-and-edit.mp4 b/dist/load-file-and-edit.mp4 new file mode 100644 index 0000000..93300b6 Binary files /dev/null and b/dist/load-file-and-edit.mp4 differ diff --git a/icon/svgr_raw/mouseLeft.svg b/icon/svgr_raw/mouseLeft.svg new file mode 100644 index 0000000..67c7578 --- /dev/null +++ b/icon/svgr_raw/mouseLeft.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/icon/svgr_raw/mouseMiddle.svg b/icon/svgr_raw/mouseMiddle.svg new file mode 100644 index 0000000..7f0e4ea --- /dev/null +++ b/icon/svgr_raw/mouseMiddle.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/icon/svgr_raw/mouseRight.svg b/icon/svgr_raw/mouseRight.svg new file mode 100644 index 0000000..0ebfdc6 --- /dev/null +++ b/icon/svgr_raw/mouseRight.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/icon/svgr_raw/mouseScroll.svg b/icon/svgr_raw/mouseScroll.svg new file mode 100644 index 0000000..564ab54 --- /dev/null +++ b/icon/svgr_raw/mouseScroll.svg @@ -0,0 +1,170 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/icon/svgr_raw/pan.svg b/icon/svgr_raw/pan.svg new file mode 100644 index 0000000..c8b1fd4 --- /dev/null +++ b/icon/svgr_raw/pan.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/icon/svgr_raw/rotate.svg b/icon/svgr_raw/rotate.svg new file mode 100644 index 0000000..d4347e2 --- /dev/null +++ b/icon/svgr_raw/rotate.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/icon/svgr_raw/select.svg b/icon/svgr_raw/select.svg new file mode 100644 index 0000000..7d95d75 --- /dev/null +++ b/icon/svgr_raw/select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/react/app.css b/src/react/app.css index db568ee..f3d4d7f 100644 --- a/src/react/app.css +++ b/src/react/app.css @@ -5,6 +5,8 @@ box-sizing: border-box; scrollbar-color: lightgray #262626; scrollbar-width: thin; + border-width: 0; + border-style: solid; } body { diff --git a/src/react/app.jsx b/src/react/app.jsx index c8836b6..5860df4 100644 --- a/src/react/app.jsx +++ b/src/react/app.jsx @@ -27,7 +27,6 @@ const App = ({ store }) => { - } diff --git a/src/react/clip.jsx b/src/react/clip.jsx new file mode 100644 index 0000000..1dc33cb --- /dev/null +++ b/src/react/clip.jsx @@ -0,0 +1,51 @@ +import React, { useState, useEffect, useRef, useCallback, useReducer } from "react" +import { MdCancel} from 'react-icons/md' + + +export const Clip = ({ setClip, clip }) => { + + const width = window.innerWidth * 0.9 + const top = (window.innerHeight - (width / 1.6)) / 2 + + return ( +
+
+
+ {clip[1]} +
+ setClip(null)} + /> +
+
+ ) +} + +const basicWorkflowTS = [ + 10, 'Sketching on a plane', + 10, 'Extruding a sketch to a solid', + 10, 'Sketch on a face of a solid', + 10, 'Peforming boolean operation between solids', +] + +const editWorkflowTS = [ + 10, 'opening a file from disk', + 10, 'editing an existing sketch', + 10, 'accepting the edit and exiting', +] + +const exportTS = [ + 10, 'selecting a body for export', + 10, 'initiate export', + 10, 'loading exported stl into 3dprint slicer', + 10, 'result', +] diff --git a/src/react/help.jsx b/src/react/help.jsx index be5182e..6297046 100644 --- a/src/react/help.jsx +++ b/src/react/help.jsx @@ -1,13 +1,12 @@ -import React, { useCallback, useEffect, useReducer, useRef } from 'react'; +import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux' -import { MdCancel, MdArrowBack, MdArrowForward } from 'react-icons/md' - -import { Carousel } from './carousel' +import { MdArrowBack, MdArrowForward } from 'react-icons/md' +import { QuickStart } from './quickStart' // 10, 'Use the line tool', // 10, 'Adding dimensions', @@ -15,26 +14,6 @@ import { Carousel } from './carousel' // 10, 'Drawing an arc', // 10, 'Adding coincident constraints', -const basicWorkflowTS = [ - 10, 'Sketching on a plane', - 10, 'Extruding a sketch to a solid', - 10, 'Sketch on a face of a solid', - 10, 'Peforming boolean operation between solids', -] - -const editWorkflowTS = [ - 10, 'opening a file from disk', - 10, 'editing an existing sketch', - 10, 'accepting the edit and exiting', -] - -const exportTS = [ - 10, 'selecting a body for export', - 10, 'initiate export', - 10, 'loading exported stl into 3dprint slicer', - 10, 'result', -] - function debounce(callback, delay) { let handler = null; return (...args) => { @@ -46,10 +25,12 @@ function debounce(callback, delay) { function reducer(state, action) { switch (action.type) { case 'resize': + + const rect = Math.min(Math.min(window.innerHeight * 0.8, window.innerWidth * 0.7),800) return { ...state, - rect: window.innerHeight * 0.6, - dragLeft: state.pg * window.innerHeight * 0.6, + rect, + dragLeft: state.pg * rect, dragging: true }; case 'move': @@ -81,47 +62,52 @@ function reducer(state, action) { } } -const transTime = 200 +const transTime = 300 const elastic = `transform ${transTime}ms cubic-bezier(0.4, 0.0, 0.2, 1)`; -export const Help = () => { +const arr = [ + ['Sketch out your ideas in 2D outlines.', 'link'], + ['Transform the sketched shapes into 3D solids.', 'link'], + ['Combine multiple solids to form more complex ones.', 'link'], + ['Export your design to a 3D printer and turn into reality.', 'link'], +] + + + + + + + + +export const Help = ({ setModal }) => { const dispatch = useDispatch() const status = useSelector(state => state.ui.help) - const handleClick = (e) => { - if (!e.composedPath().includes(ref.current) - ) { - e.stopPropagation() // prevents mouse from immediately clicking nav button if over it - dispatch({ type: 'set-help', status: false }) - - } - } - - useEffect(() => { - if (!status) return - - document.addEventListener( // handles click outside buttona & dropdown - 'click', - handleClick - , - { capture: true } // capture phase to allow for stopPropogation on others - ) - - return () => { - document.removeEventListener('click', handleClick, { capture: true }) // important to include options if it was specified - } - - }, [status]) + // useEffect(() => { + // if (!status) return + + // document.addEventListener( // handles click outside buttona & dropdown + // 'click', + // handleClick + // , + // { capture: true } // capture phase to allow for stopPropogation on others + // ) + + // 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 rect = Math.min(Math.min(window.innerHeight * 0.8, window.innerWidth * 0.7),800) + const [state, carouselDispatch] = useReducer(reducer, { rect, pg: 0, dragLeft: 0, dragging: false }) @@ -137,62 +123,96 @@ export const Help = () => { ) + const handleMouseDown = () => carouselDispatch({ type: 'drag-start' }) + const handleMouseMove = (e) => e.buttons == 1 && carouselDispatch({ type: 'drag', move: e.movementX }) + const handleMouseUp = () => carouselDispatch({ type: 'drag-end' }) + useEffect(() => { window.addEventListener('resize', updateSize) + document.addEventListener('mousedown', handleMouseDown) + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('mouseup', handleMouseUp) }, []) - if (status) { - return
-
- onMouseDown={() => carouselDispatch({ type: 'drag-start' })} - onMouseMove={(e) => e.buttons == 1 && carouselDispatch({ type: 'drag', move: e.movementX })} - onMouseUp={() => carouselDispatch({ type: 'drag-end' })} +
+
{ - arr.map((e, idx) => { - - return
- hi {e} + arr.map( + (e, idx) =>
+
+
+ {e[0]} +
- }) + ) } + + +
+ +
-
carouselDispatch({ type: "move", del: -1 })} - > - -
-
carouselDispatch({ type: "move", del: 1 })} - > - -
-
- {arr.map((ele, idx) => ( -
- ))} -
- dispatch({ type: 'set-help', status: false })} - /> -
- } else { - return null - } +
+ +
setModal(false)} + > + Get Started +
+ +
carouselDispatch({ type: "move", del: -1 })} + > + +
+
carouselDispatch({ type: "move", del: 1 })} + > + +
+ +
+ {Array(arr.length + 1).fill().map((ele, idx) => ( +
+ ))} +
+ +
+ // } else { + // return null + // } } \ No newline at end of file diff --git a/src/react/icons.jsx b/src/react/icons.jsx index a804641..ed29f3f 100644 --- a/src/react/icons.jsx +++ b/src/react/icons.jsx @@ -314,6 +314,227 @@ function Logo(props) { ); } +function MouseLeft(props) { + return ( + + + + + ); +} + +function MouseMiddle(props) { + return ( + + + + + ); +} + +function MouseRight(props) { + return ( + + + + + ); +} + +function MouseScroll(props) { + return ( + + + + + ); +} + +function Pan(props) { + return ( + + + + ); +} + +function Rotate(props) { + return ( + + + + ); +} + +function Select(props) { + return ( + + + + + ); +} + function Stl(props) { return ( ); } -export { Arc, Coincident, Dimension, Extrude, Flip, Horizontal, Intersect, Line, Logo, Stl, Subtract, Tangent, Union, Vertical }; \ No newline at end of file +export { Arc, Coincident, Dimension, Extrude, Flip, Horizontal, Intersect, Line, Logo, MouseLeft, MouseMiddle, MouseRight, MouseScroll, Pan, Rotate, Select, Stl, Subtract, Tangent, Union, Vertical }; \ No newline at end of file diff --git a/src/react/modal.jsx b/src/react/modal.jsx new file mode 100644 index 0000000..e65138d --- /dev/null +++ b/src/react/modal.jsx @@ -0,0 +1,22 @@ +import ReactDOM from 'react-dom' +import React from 'react' +const modalRoot = document.getElementById('react'); + +export class Modal extends React.Component { + constructor(props) { + super(props); + this.el = document.createElement('div'); + } + + componentDidMount() { + modalRoot.appendChild(this.el); + } + + componentWillUnmount() { + modalRoot.removeChild(this.el); + } + + render() { + return ReactDOM.createPortal(this.props.children, this.el); + } +} \ No newline at end of file diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index 0ab5eba..2bae73b 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -1,17 +1,18 @@ -import React, { useEffect, useReducer } from 'react'; +import React, { useEffect, useReducer, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { FaEdit, FaLinkedin, FaGithub } from 'react-icons/fa' import { MdSave, MdFolder, MdInsertDriveFile, MdHelpOutline } from 'react-icons/md' - import * as Icon from "./icons"; + import { Dialog } from './dialog' -import { DropDown } from './dropDown' import { Help } from './help' +import { Modal } from './modal' import { STLExport, saveFile, openFile } from './fileHelpers' +import { DropDown} from './dropDown' const buttonIdx = { 'line': 1, @@ -171,10 +172,12 @@ export const NavBar = () => { const [_, forceUpdate] = useReducer(x => x + 1, 0); - return
+ const [modal, setModal] = useState(false) -
-
+ return
+ +
+
three.cad
@@ -194,11 +197,15 @@ export const NavBar = () => { )) }
-
+
+ { - dispatch({ type: 'set-help', status: true }) + setModal(true) } } /> + + {/* */} + @@ -206,6 +213,11 @@ export const NavBar = () => {
+ { + modal && + + + }
} diff --git a/src/react/quickStart.jsx b/src/react/quickStart.jsx new file mode 100644 index 0000000..e54d5dd --- /dev/null +++ b/src/react/quickStart.jsx @@ -0,0 +1,139 @@ +import React, { useState, useEffect, useRef, useCallback, useReducer } from "react" +import { useDispatch, useSelector } from "react-redux" + +import { Clip } from './clip' +import { Modal } from './modal' + +import { MdZoomIn, MdSave, MdFolder, MdInsertDriveFile, MdHelpOutline } from 'react-icons/md' +import { FaRegPlayCircle, FaEdit, FaLinkedin, FaGithub } from 'react-icons/fa' + +import * as Icon from "./icons"; + + + +const clipArr = [ + ['basic-workflow.mp4', 'Basic model creation workflow'], + ['load-file-and-edit.mp4', 'Loading and editing models'], + ['export-to-3dprint.mp4', 'Exporting model for 3D printing'], +] + +const navArr = [ + 'Mouse Navigation', + [Icon.Select, 'Select', [ + Icon.MouseLeft, '+ drag' + ]], + [Icon.Rotate, 'Rotate', [ + Icon.MouseRight + ]], + [MdZoomIn, 'Zoom', [ + Icon.MouseScroll + ]], + [Icon.Pan, 'Pan', [ + Icon.MouseMiddle, '(or', () =>
Ctrl
, ' + ', Icon.MouseRight, ') + drag' + ]], + '\u00A0', + 'Model Toolbar', + [FaEdit, 'Sketch', ['Initiates a new sketch based on the the user must first select a plane, or three points on existing extrusions.']], + [Icon.Extrude, 'Extrude', ['Intiates new extrusion dialog. before clickin gthis button. The user must firs select a sketch to extrude from']], + [Icon.Union, 'Union', ['Creates a new solid that is a boolean union or two selected solids.']], + [Icon.Subtract, 'Substract', ['Creates a new solid that is a boolean subtraction of the second selected solid from the first selected solid']], + [Icon.Intersect, 'Intersect', ['Creates a new solid that is a boolean intersection or two selected solids.']], + [MdInsertDriveFile, 'New Document', ['Wipes the current workspace and starts a fresh document']], + [MdSave, 'Save', ['saves current document. on the inital save the user can specify save location and file name']], + [MdFolder, 'Open', ['loads an existing document from the local disk.']], + [Icon.Stl, 'Export to STL', ['Exports selected solid to 3d print friendly stl format']], + + '\u00A0', + 'Sketch Toolbar', + [Icon.Extrude, 'Extrude', ['Creates a new extrusion from the current sketch']], + [Icon.Line, 'Line', ['Subsequent clicks on the canvas define the vertices of the line segment chain.']], + [Icon.Arc, 'Arc', ['In the 3 subsequent mouse clicks, the first sets the start point, the seconds the endpoint, and the third the radius.']], + [Icon.Dimension, 'Dimension', ['Adds a distance when 2 points, or 1 point and 1 line are selected. Adds an angle when two lines are selected.']], + [Icon.Coincident, 'Coincident', ['Adds a coincident contraint between two points, or a line and a point.']], + [Icon.Vertical, 'Vertical', ['Aligns the the selected line, or two selected points with the y-axis']], + [Icon.Horizontal, 'Horizontal', ['Aligns the the selected line, or two selected points with the x-axis']], + [Icon.Tangent, 'Tangent', ['Adds a tangent constraint between selected two arcs, or a line and a arc. Entities must first be coincident']], + + +] + +export const QuickStart = () => { + + + const [clip, setClip] = useState(null) + return
+ +
+ +
+ Common workflow walkthoughs +
+ + { + clipArr.map((ele, idx) => ( +
setClip(ele)} + key={idx} + > + + {ele[1]} +
+ )) + } + +
+ { + navArr.map((row, i) => ( + typeof row === 'string' ? +
+ {row} +
+ : + +
+ {row[1]} + {React.createElement(row[0], + { + className: "fill-current text-gray-100 flex-shrink-0", + width: '2.5em', height: '2.5em', size: '2.5em', + style: { padding: '0.5em' } + } + )} +
+ +
+ { + row[2].map( + (Col, key) => typeof Col === 'string' ? + Col + : + + ) + } +
+
+ )) + } + +
+ + + + { + clip && + + + } +
+ + +
+ + +} \ No newline at end of file diff --git a/src/react/reducer.js b/src/react/reducer.js index 57eb7cf..a7bde75 100644 --- a/src/react/reducer.js +++ b/src/react/reducer.js @@ -195,15 +195,6 @@ export function ui(state = defaultUIState, action) { mode: { $set: action.mode } }) - case 'set-help': - return update(state, { - help: { $set: action.status } - }) - case 'toggle-help': - return update(state, { - help: { $set: !state.help } - }) - default: return state } diff --git a/tailwind.config.js b/tailwind.config.js index 5e98c0e..9cd4d9b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -14,7 +14,7 @@ module.exports = { gray: colors.trueGray, green: colors.emerald, red: colors.red, - } + }, }, variants: { extend: {},