2023-08-02 16:23:17 -07:00
|
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
|
|
import { useStore } from '../useStore'
|
|
|
|
import { faXmark } from '@fortawesome/free-solid-svg-icons'
|
|
|
|
import { ActionButton } from './ActionButton'
|
|
|
|
import Modal from 'react-modal'
|
|
|
|
import React from 'react'
|
|
|
|
import { useFormik } from 'formik'
|
|
|
|
import { Models } from '@kittycad/lib'
|
|
|
|
|
|
|
|
type OutputFormat = Models['OutputFormat_type']
|
|
|
|
|
|
|
|
export const ExportButton = () => {
|
|
|
|
const { engineCommandManager } = useStore((s) => ({
|
|
|
|
engineCommandManager: s.engineCommandManager,
|
|
|
|
}))
|
|
|
|
|
|
|
|
const [modalIsOpen, setIsOpen] = React.useState(false)
|
|
|
|
|
|
|
|
const defaultType = 'gltf'
|
|
|
|
const [type, setType] = React.useState(defaultType)
|
|
|
|
|
|
|
|
const customModalStyles = {
|
|
|
|
content: {
|
|
|
|
top: '50%',
|
|
|
|
left: '50%',
|
|
|
|
right: 'auto',
|
|
|
|
bottom: 'auto',
|
|
|
|
marginRight: '-50%',
|
|
|
|
transform: 'translate(-50%, -50%)',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
function openModal() {
|
|
|
|
setIsOpen(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
function closeModal() {
|
|
|
|
setIsOpen(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default to gltf and embedded.
|
|
|
|
const initialValues: OutputFormat = {
|
|
|
|
type: defaultType,
|
|
|
|
storage: 'embedded',
|
|
|
|
}
|
|
|
|
const formik = useFormik({
|
|
|
|
initialValues,
|
|
|
|
onSubmit: (values: OutputFormat) => {
|
|
|
|
// Set the default coords.
|
|
|
|
if (
|
|
|
|
values.type === 'obj' ||
|
|
|
|
values.type === 'ply' ||
|
|
|
|
values.type === 'step' ||
|
|
|
|
values.type === 'stl'
|
|
|
|
) {
|
|
|
|
// Set the default coords.
|
|
|
|
// In the future we can make this configurable.
|
|
|
|
// But for now, its probably best to keep it consistent with the
|
|
|
|
// UI.
|
|
|
|
values.coords = {
|
|
|
|
forward: {
|
|
|
|
axis: 'y',
|
|
|
|
direction: 'negative',
|
|
|
|
},
|
|
|
|
up: {
|
|
|
|
axis: 'z',
|
|
|
|
direction: 'positive',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
engineCommandManager?.sendSceneCommand({
|
|
|
|
type: 'modeling_cmd_req',
|
|
|
|
cmd: {
|
|
|
|
type: 'export',
|
|
|
|
// By default let's leave this blank to export the whole scene.
|
|
|
|
// In the future we might want to let the user choose which entities
|
|
|
|
// in the scene to export. In that case, you'd pass the IDs thru here.
|
|
|
|
entity_ids: [],
|
|
|
|
format: values,
|
|
|
|
},
|
|
|
|
cmd_id: uuidv4(),
|
|
|
|
file_id: uuidv4(),
|
|
|
|
})
|
|
|
|
|
|
|
|
closeModal()
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<button onClick={openModal}>Export</button>
|
|
|
|
<Modal
|
|
|
|
isOpen={modalIsOpen}
|
|
|
|
onRequestClose={closeModal}
|
|
|
|
contentLabel="Export"
|
|
|
|
style={customModalStyles}
|
|
|
|
>
|
|
|
|
<div className="text-black">
|
|
|
|
<h1 className="text-2xl font-bold">Export your design</h1>
|
|
|
|
<form onSubmit={formik.handleSubmit}>
|
|
|
|
<p>
|
|
|
|
<label htmlFor="type">Type</label>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<select
|
|
|
|
id="type"
|
|
|
|
name="type"
|
|
|
|
onChange={(e) => {
|
|
|
|
setType(e.target.value)
|
|
|
|
formik.handleChange(e)
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<option value="gltf">gltf</option>
|
|
|
|
<option value="obj">obj</option>
|
|
|
|
<option value="ply">ply</option>
|
|
|
|
<option value="step">step</option>
|
|
|
|
<option value="stl">stl</option>
|
|
|
|
</select>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
{(type === 'gltf' || type === 'ply' || type === 'stl') && (
|
|
|
|
<>
|
|
|
|
<p>
|
|
|
|
{' '}
|
|
|
|
<label htmlFor="storage">Storage</label>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<select
|
|
|
|
id="storage"
|
|
|
|
name="storage"
|
|
|
|
onChange={formik.handleChange}
|
|
|
|
value={formik.values.storage}
|
|
|
|
>
|
|
|
|
{type === 'gltf' && (
|
|
|
|
<>
|
|
|
|
<option value="embedded">embedded</option>
|
|
|
|
<option value="binary">binary</option>
|
|
|
|
<option value="standard">standard</option>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
{type === 'ply' && (
|
|
|
|
<>
|
|
|
|
<option value="ascii">ascii</option>
|
|
|
|
<option value="binary">binary</option>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
{type === 'stl' && (
|
|
|
|
<>
|
|
|
|
<option value="ascii">ascii</option>
|
|
|
|
<option value="binary_little_endian">
|
|
|
|
binary_little_endian
|
|
|
|
</option>
|
|
|
|
<option value="binary_big_endian">
|
|
|
|
binary_big_endian
|
|
|
|
</option>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</select>
|
|
|
|
</p>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<div className="flex justify-between mt-6">
|
|
|
|
<button type="submit">Submit</button>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
<div className="flex justify-between mt-6">
|
|
|
|
<ActionButton
|
2023-08-15 21:56:24 -04:00
|
|
|
Element="button"
|
2023-08-02 16:23:17 -07:00
|
|
|
onClick={closeModal}
|
|
|
|
icon={{
|
|
|
|
icon: faXmark,
|
|
|
|
bgClassName: 'bg-destroy-80',
|
|
|
|
iconClassName:
|
|
|
|
'text-destroy-20 group-hover:text-destroy-10 hover:text-destroy-10',
|
|
|
|
}}
|
|
|
|
className="hover:border-destroy-40"
|
|
|
|
>
|
|
|
|
Close
|
|
|
|
</ActionButton>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</Modal>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|