color picker floating above viewer

This commit is contained in:
ochafik 2023-03-27 01:08:45 +01:00
commit 2ae038020b
9 changed files with 41 additions and 11 deletions

View file

@ -22,12 +22,14 @@ Licenses: see [LICENSES](./LICENSE).
## Roadmap
- 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)
- 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!
- 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.
- Proper PWA w/ File opening / association to *.scad files
- Animation rendering (And other formats than STL)
- Compress URL fragment
- 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 ?

View file

@ -113,7 +113,7 @@ export default function Footer({style}: {style?: CSSProperties}) {
{state.output && (
<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"
text
// label={state.output.isPreview ? "preview.stl" : "render.stl"}

View file

@ -64,7 +64,6 @@ export default function PanelSwitcher() {
}
<SettingsMenu style={{
position: 'absolute',
marginTop: '5px',
right: 0,
top: 0,
}} />

View file

@ -3,6 +3,8 @@
import { CSSProperties, forwardRef, useContext, useEffect, useRef, useState } from 'react';
import { ModelContext } from './contexts';
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}) {
const model = useContext(ModelContext);
@ -21,8 +23,10 @@ export default function ViewerPanel({className, style}: {className?: string, sty
}}>
{state.output?.stlFileURL &&
<StlViewer
className='absolute-fill'
style={{
flex: 1
zIndex: 0,
// flex: 1,
// width: '100%'
}}
// ref={stlModelRef}
@ -30,12 +34,22 @@ export default function ViewerPanel({className, style}: {className?: string, sty
orbitControls
shadows={state.view.showShadows}
modelProps={{
color: '#f9d72c',
color: model.state.view.color,
}}
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>
)

View file

@ -21,6 +21,7 @@ export interface State {
mode: 'multi',
} & { [K in MultiLayoutComponentId]: boolean })
color: string,
showAxes?: boolean,
showShadows?: boolean,
}

View file

@ -2,6 +2,7 @@
import { State } from "./app-state";
import { validateArray, validateBoolean, validateString, validateStringEnum } from "../utils";
import { defaultModelColor } from "./initial-state";
export function buildUrlForStateParams(state: State) {//partialState: {params: State['params'], view: State['view']}) {
return `${location.protocol}//${location.host}${location.pathname}#${encodeStateParamsAsFragment(state)}`;
@ -33,6 +34,7 @@ export function readStateFromFragment(): State | null {
viewer: validateBoolean(view?.layout['viewer']),
customizer: validateBoolean(view?.layout['customizer']),
},
color: validateString(view?.color, () => defaultModelColor),
showAxes: validateBoolean(view?.layout?.showAxis),
showShadows: validateBoolean(view?.layout?.showShadow),
}

View file

@ -4,6 +4,7 @@ import defaultScad from './default-scad';
import { State } from './app-state';
export const defaultSourcePath = '/playground.scad';
export const defaultModelColor = '#f9d72c';
export const blankProjectState: State = {
params: {
@ -12,6 +13,7 @@ export const blankProjectState: State = {
features: [],
},
view: {
color: defaultModelColor,
layout: {
mode: 'single',
focus: 'editor'
@ -37,7 +39,9 @@ export function createInitialState(fs: any, state: State | null) {
editor: true,
viewer: true,
customizer: false,
} as any
} as any,
color: defaultModelColor,
},
...(state ?? {})
};

View file

@ -51,6 +51,14 @@ export class Model {
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') {
if (this.state.view.layout.mode === mode) return;
this.mutate(s => {

View file

@ -83,7 +83,7 @@ export function formatBytes(n: number) {
export function formatMillis(n: number) {
if (n < 1000)
return `${Math.floor(n)} millis`;
return `${Math.floor(n)}ms`;
return `${Math.floor(n / 100) / 10}sec`;
}