diff --git a/web/src/Routes.js b/web/src/Routes.js index eeadbf6..1528bd1 100644 --- a/web/src/Routes.js +++ b/web/src/Routes.js @@ -47,6 +47,7 @@ const Routes = () => { {/* End ownership enforced routes */} + diff --git a/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js b/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js index 59bd46a..f97c1c9 100644 --- a/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js +++ b/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js @@ -1,26 +1,47 @@ import { useAuth } from '@redwoodjs/auth' -import { Link, routes } from '@redwoodjs/router' import CascadeController from 'src/helpers/cascadeController' import IdeToolbar from 'src/components/IdeToolbar' import { useEffect, useState } from 'react' +const defaultExampleCode = `// Welcome to Cascade Studio! Here are some useful functions: +// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection() +// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon() +// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(), +// FilletEdges(), ChamferEdges(), +// Slider(), Button(), Checkbox() + +let holeRadius = Slider("Radius", 30 , 20 , 40); + +let sphere = Sphere(50); +let cylinderZ = Cylinder(holeRadius, 200, true); +let cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true)); +let cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true)); + +Translate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ])); + +Translate([-130, 0, 100], Text3D("Start Hacking")); + +// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!` + const IdeCascadeStudio = ({ part, saveCode, loading }) => { - const [code, setCode] = useState(part.code) + const isDraft = !part + const [code, setCode] = useState(isDraft ? defaultExampleCode : part.code) const { currentUser } = useAuth() const canEdit = currentUser?.sub === part?.user?.id useEffect(() => { // Cascade studio attaches "cascade-container" a div outside the react app in 'web/src/index.html', and so we are // "opening" and "closing" it for the ide part of the app by displaying none or block. Which is why this useEffect // returns a clean up function that hides the div again. + setCode(part?.code || '') const onCodeChange = (code) => setCode(code) - CascadeController.initialise(onCodeChange, part.code) + CascadeController.initialise(onCodeChange, code || '') const element = document.getElementById('cascade-container') element.setAttribute('style', 'display: block; opacity: 100%; overflow: hidden; height: calc(100vh - 8rem)') // eslint-disable-line return () => { element.setAttribute('style', 'display: none; overflow: hidden; height: calc(100vh - 8rem)') // eslint-disable-line } - }, [part.code]) - const isChanges = code !== part.code + }, [part?.code]) + const isChanges = code !== part?.code return ( <> @@ -28,6 +49,8 @@ const IdeCascadeStudio = ({ part, saveCode, loading }) => { { saveCode({ input: { @@ -42,8 +65,8 @@ const IdeCascadeStudio = ({ part, saveCode, loading }) => { }} onExport={(type) => threejsViewport[`saveShape${type}`]()} userNamePart={{ - userName: part.user.userName, - partTitle: part.title, + userName: part?.user?.userName, + partTitle: part?.title, image: part?.user?.image, }} /> diff --git a/web/src/components/IdePartCell/IdePartCell.js b/web/src/components/IdePartCell/IdePartCell.js index 6bbffcf..bc91be8 100644 --- a/web/src/components/IdePartCell/IdePartCell.js +++ b/web/src/components/IdePartCell/IdePartCell.js @@ -27,7 +27,7 @@ const UPDATE_PART_MUTATION = gql` } } ` -const FORK_PART_MUTATION = gql` +export const FORK_PART_MUTATION = gql` mutation ForkPartMutation($input: CreatePartInput!) { forkPart(input: $input) { id @@ -62,9 +62,9 @@ export const Success = ({ part, refetch }) => { }, }) - const saveCode = ({ input, id, isFork }) => { + const saveCode = async ({ input, id, isFork }) => { if (!isFork) { - updatePart({ variables: { id, input } }) + await updatePart({ variables: { id, input } }) refetch() return } diff --git a/web/src/components/IdeToolbar/IdeToolbar.js b/web/src/components/IdeToolbar/IdeToolbar.js index 8c5d452..c9fd12c 100644 --- a/web/src/components/IdeToolbar/IdeToolbar.js +++ b/web/src/components/IdeToolbar/IdeToolbar.js @@ -4,17 +4,43 @@ import OutBound from 'src/components/OutBound' import ReactGA from 'react-ga' import { Link, routes, navigate } from '@redwoodjs/router' import { useAuth } from '@redwoodjs/auth' +import { useMutation, useFlash } from '@redwoodjs/web' import Button from 'src/components/Button' import ImageUploader from 'src/components/ImageUploader' import Svg from '../Svg/Svg' -import LoginModal from '../LoginModal/LoginModal' +import LoginModal from 'src/components/LoginModal' +import { FORK_PART_MUTATION } from 'src/components/IdePartCell' -const IdeToolbar = ({ canEdit, isChanges, onSave, onExport, userNamePart }) => { +const IdeToolbar = ({ + canEdit, + isChanges, + onSave, + onExport, + userNamePart, + isDraft, + code, +}) => { const [anchorEl, setAnchorEl] = useState(null) const [whichPopup, setWhichPopup] = useState(null) const [isLoginModalOpen, setIsLoginModalOpen] = useState(false) - const { isAuthenticated } = useAuth() + const { isAuthenticated, currentUser } = useAuth() + const showForkButton = !(canEdit || isDraft) + + const { addMessage } = useFlash() + const [forkPart] = useMutation(FORK_PART_MUTATION, { + onCompleted: ({ forkPart }) => { + navigate( + routes.ide({ + userName: forkPart?.user?.userName, + partTitle: forkPart?.title, + }) + ) + addMessage(`Part created with title: ${forkPart?.title}.`, { + classes: 'rw-flash-success', + }) + }, + }) const handleClick = ({ event, whichPopup }) => { setAnchorEl(event.currentTarget) @@ -27,7 +53,17 @@ const IdeToolbar = ({ canEdit, isChanges, onSave, onExport, userNamePart }) => { } const handleSave = () => { - if (isAuthenticated) onSave() + if (isDraft && isAuthenticated) + forkPart({ + variables: { + input: { + userId: currentUser.sub, + title: 'draft', + code, + }, + }, + }) + else if (isAuthenticated) onSave() else recordedLogin() } @@ -55,39 +91,43 @@ const IdeToolbar = ({ canEdit, isChanges, onSave, onExport, userNamePart }) => { id="cadhub-ide-toolbar" className="flex bg-gradient-to-r from-gray-900 to-indigo-900 pt-1" > -
-
- -
-
- - {userNamePart?.userName} - -
-
+ {!isDraft && ( + <> +
+
+ +
+
+ + {userNamePart?.userName} + +
+
+ + + )} -