Skip to content

Commit

Permalink
Updated to the latest version of openjscad-react, added more complete…
Browse files Browse the repository at this point in the history
… example
  • Loading branch information
aeksco committed Dec 21, 2020
1 parent 0cb68be commit 6521543
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 118 deletions.
83 changes: 81 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,82 @@
# openjscad-react-next-starter
<h1 align="center">openjscad-react-next-starter</h1>

A web starter project with OpenJSCAD, React, Next.js, TypeScript, and Netlify. Built with [openjscad-react](https://github.com/aeksco/openjscad-react).
<div align="center">
<strong>A React.js + Next.js starter kit for building apps with <a href="https://aeksco.github.io/openjscad-react">openjscad-react</a></strong>
</div>

<br />

<div align="center">
Write an <code>OpenJSCAD</code> script and wire it up to some inputs to start exporting user-customizable designs
</div>

<br />

<div align="center">
<!-- GitHub Stars -->
<img src="https://img.shields.io/github/stars/aeksco/openjscad-react-next-starter.svg?style=social&label=Star" alt="GitHub Stars" />

<!-- MIT License -->
<img src="https://img.shields.io/apm/l/atomic-design-ui.svg" alt="MIT License" />

<!-- Hit Count -->
<img src="http://hits.dwyl.com/aeksco/openjscad-react-next-starter.svg" alt="Hit Count" />

<!-- PRs Welcome -->
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="Hit Count" />
</div>

<div align="center">
<h3>
<a href="https://aeksco.github.io/openjscad-react">
Website
</a>
<span> | </span>
<a href="https://aeksco.github.io/openjscad-react">
Documentation
</a>
</h3>
</div>

![Demo Example](https://i.imgur.com/9NijaGj.png "Demo Example")

<hr/>

## Developing

- Install dependencies:

```
yarn install
```

- Build the Next.js project and start the development server:

```
yarn build && yarn start
```

- Export the Next.js app:

```
yarn build && yarn export
```

## Built with

- [React](https://reactjs.org)
- [TypeScript](https://www.typescriptlang.org/)
- [Tailwind CSS](https://tailwindcss.com)

## Misc. References

- [openjscad-react](https://github.com/aeksco/openjscad-react)
- [OpenJSCAD Homepage](https://openjscad.org)
- [OpenJSCAD API Reference](https://openjscad.org/dokuwiki/doku.php)
- [JSCAD User Group](https://openjscad.nodebb.com/)

### License

Open source under the [MIT License](https://github.com/aeksco/openjscad-react/blob/main/LICENSE). Built with&nbsp;:heart:&nbsp; by [@aeksco](https://github.com/aeksco)

[![Tweet](https://img.shields.io/twitter/url/https/github.com/aeksco/openjscad-react.svg?style=social)](https://twitter.com/intent/tweet?text=https://github.com/aeksco/openjscad-react)
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
"author": "Alexander Schwartzberg",
"license": "MIT",
"dependencies": {
"@types/downloadjs": "^1.4.2",
"downloadjs": "^1.4.7",
"lodash.debounce": "^4.0.8",
"next": "^9.0.1",
"openjscad-react": "^0.0.1-canary-04",
"openjscad-react": "^0.0.1-canary-06",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"tailwindcss": "^1.8.10"
},
"devDependencies": {
"@types/downloadjs": "^1.4.2",
"@types/lodash.debounce": "^4.0.6",
"@types/node": "^12.6.2",
"@types/react": "^16.8.23",
Expand Down
6 changes: 3 additions & 3 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { PageHeader } from "../src/PageHeader";
import { Navbar } from "../src/Navbar";
import App from "next/app";
import "../styles/index.css";

Expand All @@ -8,8 +8,8 @@ export default class extends App {
const { Component, pageProps } = this.props;
return (
<React.Fragment>
<PageHeader />
<div className="container mx-auto">
<Navbar />
<div className="container mx-auto pt-10">
<Component {...pageProps} />
</div>
</React.Fragment>
Expand Down
2 changes: 1 addition & 1 deletion pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class MyDocument extends Document {
<Head>
<title>OpenJSCAD React Next.js Starter</title>
</Head>
<body className="bg-gray-200">
<body className="bg-gray-100">
<Main />
<NextScript />
</body>
Expand Down
225 changes: 165 additions & 60 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,81 +1,186 @@
import React from "react";
import dynamic from "next/dynamic";
import { OpenJSCADProps } from "openjscad-react/dist/types";

const STLB_FORMAT = {
name: "stlb",
displayName: "STL (Binary)",
description: "STereoLithography, Binary",
extension: "stl",
mimetype: "application/sla",
convertCSG: true,
convertCAG: false
};
import { OpenJSCADProps } from "openjscad-react/dist";
import { FormGroup } from "../src/FormGroup";

// Dynamic import
const OpenJSCAD: React.ComponentType<OpenJSCADProps> = dynamic(
() => import("openjscad-react/dist").then(mod => mod.OpenJSCAD),
{ ssr: false }
);
const OpenJSCAD: React.ComponentType<
OpenJSCADProps
> = dynamic(() => import("openjscad-react/dist").then((mod) => mod.OpenJSCAD), {
ssr: false,
});

// // // //

export const DEFAULT_SCRIPT = `
function main () {
return union(
difference(
cube({size: 3, center: true}),
sphere({r: 2, center: true})
),
intersection(
sphere({r: 1.3, center: true}),
cube({size: 2.1, center: true})
)
).translate([0, 0, 1.5]).scale(10);
}
function getSign(props: { name?: string; height?: number; padding?: number }) {
let { name = "Hello, OpenJSCAD!" } = props;
const { height = 4, padding = 2 } = props;

// Removes all double quotes and back-slashes (prevents issues when interpolating below)
name = name.replace(/[\"/s]/gi, "").replace(/[/\/s]/gi, "");

// Renders sign JSCAD script
const signJscad = `
function main (param) {
var o = []; // our stack of objects
var l = []; // our stack of line segments (when rendering vector text)
var p = []; // our stack of extruded line segments
var name = "${name}";
var thickness = ${String(height)};
// -- render name & extrude
l = vector_text(0, 0, name);
l.forEach(function (s) {
p.push(rectangular_extrude(s, {w: 4, h: 4}));
});
o.push(union(p).setColor([0.3, 0.3, 0.3]).scale([1 / 3, 1 / 3, 1 / 3]).center([true, true, false]).translate([0, 0, thickness]));
var b = o[0].getBounds();
var m = ${padding};
var w = b[1].x - b[0].x + m * 2;
var h = b[1].y - b[0].y + m * 2;
o.push(cube({size: [w, h, thickness], round: true, radius: 0.5}).translate([b[0].x - m, b[0].y - m, 0]).setColor([0.8, 0.8, 0.8]));
return union(o);
}
`;

return signJscad;
}

// // // //

const Index = () => {
if (typeof window == "undefined" || typeof document == "undefined") {
return null;
}

const DEFAULT_NAME = "Hello, OpenJSCAD!";
const [name, setName] = React.useState<string>(DEFAULT_NAME);
const [height, setHeight] = React.useState<number>(4);
const [padding, setPadding] = React.useState<number>(6);

return (
<OpenJSCAD
className="grid grid-cols-1 mt-5"
jscadScript={DEFAULT_SCRIPT}
viewerOptions={{}}
// defaultOutputFileFormat="stl"
outputFileExport="stla"
viewerOptions={{
camera: {
angle: { x: -30, y: 0, z: 0 },
},
}}
jscadScript={getSign({
name,
height,
padding,
})}
loadingPlaceholder={() => {
return (
<div
className="card flex justify-center items-center"
style={{ minHeight: "32rem" }}
>
<p>Resizing...</p>
</div>
);
}}
>
{({ viewerElement, outputFile }) => {
// NOTE - processor is null, must be fixed
// if (processor !== null) {
// // setTimeout(() => {
// // processor.generateOutputFile(STLB_FORMAT);
// // }, 3000);
// }

{(childProps) => {
return (
<div>
{viewerElement}
{/* <button
className="btn btn-blue"
onClick={() => {
processor.generateOutputFile(STLB_FORMAT);
}}
>
Download STL
</button> */}
{outputFile !== null && (
<a
href={outputFile.data}
download="stl-export.stl"
className="btn btn-blue"
>
Download STL
</a>
)}
<pre>{JSON.stringify({ outputFile }, null, 4)}</pre>
<div className="card">
<div className="grid grid-cols-1 lg:grid-cols-3 w-full">
<div className="lg:pr-2 pl-0 flex flex-col justify-between col-span-2 lg:col-span-1">
<div>
<h2 className="text-center text-xl mb-3">
Customize 3D Model
</h2>
<hr />

<FormGroup label="Text">
<input
className="bg-white shadow rounded p-3 w-full border border-gray-200"
placeholder="Enter a name"
value={name}
onChange={(e) => {
const updatedName = e.currentTarget.value;
setName(updatedName);
}}
/>
</FormGroup>

<FormGroup label="Height">
<input
type="range"
className="focus:outline-none rounded-xl overflow-hidden appearance-none bg-gray-400 h-5 w-full"
step={1}
min={2}
max={15}
value={height}
onChange={(e) => {
const updatedHeight = Number(e.currentTarget.value);
setHeight(updatedHeight);
}}
/>
</FormGroup>

<FormGroup label="Padding">
<input
type="range"
className="focus:outline-none rounded-xl overflow-hidden appearance-none bg-gray-400 h-5 w-full"
step={1}
min={0}
max={15}
value={padding}
onChange={(e) => {
const updatedPadding = Number(e.currentTarget.value);
setPadding(updatedPadding);
}}
/>
</FormGroup>
</div>

{childProps.outputFile === null ||
(childProps.status === "rendering" && (
<button
className="btn w-full flex justify-center text-center mt-3"
disabled
>
Download and 3D Print
</button>
))}

{childProps.outputFile !== null && (
<a
className="btn w-full flex justify-center text-center mt-3"
download="openjscad-react-export.stl"
href={childProps.outputFile.data}
>
Download and 3D Print
</a>
)}
</div>

<div className="col-span-2 lg:pl-2 sm:pl-0 mt-3 lg:mt-0 rounded-xl">
{/* Example using refs directly */}
<div
ref={childProps.refs.viewerContext}
className="rounded-xl bg-white overflow-hidden"
>
<div ref={childProps.refs.viewerDiv} />
</div>

{/* Don't forget parametersTable! */}
<table ref={childProps.refs.parametersTable} />

<canvas
style={{
width: "100%",
height: "480px",
}}
ref={childProps.refs.viewerCanvas}
/>
</div>
</div>
</div>
);
}}
Expand Down
12 changes: 12 additions & 0 deletions src/FormGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from "react";

// // // //

export function FormGroup(props: { label: string; children: React.ReactNode }) {
return (
<div className="mt-5">
<p className="font-semibold mb-2">{props.label}</p>
{props.children}
</div>
);
}
Loading

0 comments on commit 6521543

Please sign in to comment.