color picker floating above viewer
This commit is contained in:
parent
c95616210b
commit
2ae038020b
9 changed files with 41 additions and 11 deletions
|
|
@ -22,12 +22,14 @@ Licenses: see [LICENSES](./LICENSE).
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- Add tests!
|
- Add tests!
|
||||||
|
- Better names for downloads (matching source)
|
||||||
- Model /home fs in shared state. have two clear paths: /libraries for builtins, and /home for user data. State pointing to /libraries paths needs not store the data except if there's overrides (flagged as modifications in the file picker)
|
- Model /home fs in shared state. have two clear paths: /libraries for builtins, and /home for user data. State pointing to /libraries paths needs not store the data except if there's overrides (flagged as modifications in the file picker)
|
||||||
- Setup [OPENSCADPATH](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Setting_OPENSCADPATH) env var w/ Emscripten to ensure examples will run fine.
|
- Setup [OPENSCADPATH](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Libraries#Setting_OPENSCADPATH) env var w/ Emscripten to ensure examples will run fine.
|
||||||
- Bundle some official demos and more examples from each library!
|
- Bundle some official demos and more examples from each library!
|
||||||
- Ask users to contribute recipes to include more libraries, and cool examples that work in the environment
|
- Ask users to contribute recipes to include more libraries, and cool examples that work in the environment
|
||||||
- Drag and drop of files (SCAD, STL, etc) and Zip archives. For assets, auto insert the corresponding import.
|
- Drag and drop of files (SCAD, STL, etc) and Zip archives. For assets, auto insert the corresponding import.
|
||||||
- Proper PWA w/ File opening / association to *.scad files
|
- Proper PWA w/ File opening / association to *.scad files
|
||||||
|
- Animation rendering (And other formats than STL)
|
||||||
- Compress URL fragment
|
- Compress URL fragment
|
||||||
- Customizer support. Probably by adding --export-json or --export-format=customizer-json to OpenSCAD.
|
- Customizer support. Probably by adding --export-json or --export-format=customizer-json to OpenSCAD.
|
||||||
- Mobile (iOS) editing support: switch to https://www.npmjs.com/package/react-codemirror ?
|
- Mobile (iOS) editing support: switch to https://www.npmjs.com/package/react-codemirror ?
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ export default function Footer({style}: {style?: CSSProperties}) {
|
||||||
|
|
||||||
{state.output && (
|
{state.output && (
|
||||||
<Button icon='pi pi-download'
|
<Button icon='pi pi-download'
|
||||||
title={`Download ${state.output.isPreview ? "preview.stl" : "render.stl"} (${state.output.formattedStlFileSize})`}
|
title={`Download ${state.output.isPreview ? "preview.stl" : "render.stl"} (${state.output.formattedStlFileSize})\nGenerated in ${state.output.formattedElapsedMillis}`}
|
||||||
severity="secondary"
|
severity="secondary"
|
||||||
text
|
text
|
||||||
// label={state.output.isPreview ? "preview.stl" : "render.stl"}
|
// label={state.output.isPreview ? "preview.stl" : "render.stl"}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ export default function PanelSwitcher() {
|
||||||
}
|
}
|
||||||
<SettingsMenu style={{
|
<SettingsMenu style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
marginTop: '5px',
|
|
||||||
right: 0,
|
right: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
}} />
|
}} />
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
import { CSSProperties, forwardRef, useContext, useEffect, useRef, useState } from 'react';
|
import { CSSProperties, forwardRef, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { ModelContext } from './contexts';
|
import { ModelContext } from './contexts';
|
||||||
import { StlViewer} from "react-stl-viewer";
|
import { StlViewer} from "react-stl-viewer";
|
||||||
|
import { ColorPicker } from 'primereact/colorpicker';
|
||||||
|
import { defaultModelColor } from '../state/initial-state';
|
||||||
|
|
||||||
export default function ViewerPanel({className, style}: {className?: string, style?: CSSProperties}) {
|
export default function ViewerPanel({className, style}: {className?: string, style?: CSSProperties}) {
|
||||||
const model = useContext(ModelContext);
|
const model = useContext(ModelContext);
|
||||||
|
|
@ -21,8 +23,10 @@ export default function ViewerPanel({className, style}: {className?: string, sty
|
||||||
}}>
|
}}>
|
||||||
{state.output?.stlFileURL &&
|
{state.output?.stlFileURL &&
|
||||||
<StlViewer
|
<StlViewer
|
||||||
|
className='absolute-fill'
|
||||||
style={{
|
style={{
|
||||||
flex: 1
|
zIndex: 0,
|
||||||
|
// flex: 1,
|
||||||
// width: '100%'
|
// width: '100%'
|
||||||
}}
|
}}
|
||||||
// ref={stlModelRef}
|
// ref={stlModelRef}
|
||||||
|
|
@ -30,12 +34,22 @@ export default function ViewerPanel({className, style}: {className?: string, sty
|
||||||
orbitControls
|
orbitControls
|
||||||
shadows={state.view.showShadows}
|
shadows={state.view.showShadows}
|
||||||
modelProps={{
|
modelProps={{
|
||||||
color: '#f9d72c',
|
color: model.state.view.color,
|
||||||
|
|
||||||
}}
|
}}
|
||||||
url={state.output?.stlFileURL ?? ''}
|
url={state.output?.stlFileURL ?? ''}
|
||||||
/>
|
/>}
|
||||||
}
|
|
||||||
|
<ColorPicker
|
||||||
|
className={`opacity-animated ${!model.isComponentFullyVisible('viewer') ? 'opacity-0' : ''}`}
|
||||||
|
value={model.state.view.color}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '12px',
|
||||||
|
left: '12px',
|
||||||
|
// pointerEvents: model.isComponentFullyVisible('viewer') ? undefined : 'none',
|
||||||
|
}}
|
||||||
|
onChange={(e) => model.mutate(s => s.view.color = `#${e.value ?? defaultModelColor}`)} />
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ export interface State {
|
||||||
mode: 'multi',
|
mode: 'multi',
|
||||||
} & { [K in MultiLayoutComponentId]: boolean })
|
} & { [K in MultiLayoutComponentId]: boolean })
|
||||||
|
|
||||||
|
color: string,
|
||||||
showAxes?: boolean,
|
showAxes?: boolean,
|
||||||
showShadows?: boolean,
|
showShadows?: boolean,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { State } from "./app-state";
|
import { State } from "./app-state";
|
||||||
import { validateArray, validateBoolean, validateString, validateStringEnum } from "../utils";
|
import { validateArray, validateBoolean, validateString, validateStringEnum } from "../utils";
|
||||||
|
import { defaultModelColor } from "./initial-state";
|
||||||
|
|
||||||
export function buildUrlForStateParams(state: State) {//partialState: {params: State['params'], view: State['view']}) {
|
export function buildUrlForStateParams(state: State) {//partialState: {params: State['params'], view: State['view']}) {
|
||||||
return `${location.protocol}//${location.host}${location.pathname}#${encodeStateParamsAsFragment(state)}`;
|
return `${location.protocol}//${location.host}${location.pathname}#${encodeStateParamsAsFragment(state)}`;
|
||||||
|
|
@ -33,6 +34,7 @@ export function readStateFromFragment(): State | null {
|
||||||
viewer: validateBoolean(view?.layout['viewer']),
|
viewer: validateBoolean(view?.layout['viewer']),
|
||||||
customizer: validateBoolean(view?.layout['customizer']),
|
customizer: validateBoolean(view?.layout['customizer']),
|
||||||
},
|
},
|
||||||
|
color: validateString(view?.color, () => defaultModelColor),
|
||||||
showAxes: validateBoolean(view?.layout?.showAxis),
|
showAxes: validateBoolean(view?.layout?.showAxis),
|
||||||
showShadows: validateBoolean(view?.layout?.showShadow),
|
showShadows: validateBoolean(view?.layout?.showShadow),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import defaultScad from './default-scad';
|
||||||
import { State } from './app-state';
|
import { State } from './app-state';
|
||||||
|
|
||||||
export const defaultSourcePath = '/playground.scad';
|
export const defaultSourcePath = '/playground.scad';
|
||||||
|
export const defaultModelColor = '#f9d72c';
|
||||||
|
|
||||||
export const blankProjectState: State = {
|
export const blankProjectState: State = {
|
||||||
params: {
|
params: {
|
||||||
|
|
@ -12,6 +13,7 @@ export const blankProjectState: State = {
|
||||||
features: [],
|
features: [],
|
||||||
},
|
},
|
||||||
view: {
|
view: {
|
||||||
|
color: defaultModelColor,
|
||||||
layout: {
|
layout: {
|
||||||
mode: 'single',
|
mode: 'single',
|
||||||
focus: 'editor'
|
focus: 'editor'
|
||||||
|
|
@ -37,7 +39,9 @@ export function createInitialState(fs: any, state: State | null) {
|
||||||
editor: true,
|
editor: true,
|
||||||
viewer: true,
|
viewer: true,
|
||||||
customizer: false,
|
customizer: false,
|
||||||
} as any
|
} as any,
|
||||||
|
|
||||||
|
color: defaultModelColor,
|
||||||
},
|
},
|
||||||
...(state ?? {})
|
...(state ?? {})
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,14 @@ export class Model {
|
||||||
this.mutate(s => s.view.logs = value);
|
this.mutate(s => s.view.logs = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isComponentFullyVisible(id: SingleLayoutComponentId) {
|
||||||
|
if (this.state.view.layout.mode === 'multi') {
|
||||||
|
return this.state.view.layout[id];
|
||||||
|
} else {
|
||||||
|
return this.state.view.layout.focus === id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changeLayout(mode: 'multi' | 'single') {
|
changeLayout(mode: 'multi' | 'single') {
|
||||||
if (this.state.view.layout.mode === mode) return;
|
if (this.state.view.layout.mode === mode) return;
|
||||||
this.mutate(s => {
|
this.mutate(s => {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ export function formatBytes(n: number) {
|
||||||
|
|
||||||
export function formatMillis(n: number) {
|
export function formatMillis(n: number) {
|
||||||
if (n < 1000)
|
if (n < 1000)
|
||||||
return `${Math.floor(n)} millis`;
|
return `${Math.floor(n)}ms`;
|
||||||
|
|
||||||
return `${Math.floor(n / 100) / 10}sec`;
|
return `${Math.floor(n / 100) / 10}sec`;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue