1
0
Fork 0

add reset_all and undo buttons to error boundary. no styling

This commit is contained in:
Enoch Riese 2022-07-12 17:32:47 -05:00
parent 00953e9189
commit 9bcfa4f39b
10 changed files with 93 additions and 28 deletions

View file

@ -1,9 +1,5 @@
--- ---
title: Dart position title: "Dart position"
--- ---
Controls whether to split at the shoulder or armhole The **Dart position** option controls whether to create the princess seam at the shoulder or armhole.
## Effect of this option on the pattern
![This image shows the effect of this option by superimposing several variants that have a different value for this option](noble_dartposition_sample.svg "Effect of this option on the pattern")

View file

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import ResetButtons from './reset-buttons'
class ErrorBoundary extends React.Component { class ErrorBoundary extends React.Component {
constructor(props) { constructor(props) {
@ -25,7 +26,11 @@ class ErrorBoundary extends React.Component {
render() { render() {
if (this.state.hasError) { if (this.state.hasError) {
// You can render any custom fallback UI // You can render any custom fallback UI
return this.props.errorView || (<h1>Something went wrong.</h1>); return (<div>
{this.props.errorView || (<h1>Something went wrong.</h1>)}
<ResetButtons undoGist={this.props.undoGist} resetGist={this.props.resetGist} />
</div>)
return ;
} }
try { try {

View file

@ -0,0 +1,10 @@
import { useTranslation } from 'next-i18next'
export default function ({resetGist, undoGist}) {
const {t} = useTranslation(['app'])
return (<>
<button className="btn btn-primary" onClick={undoGist}>{t('undo')}</button>
<button className="btn btn-primary" onClick={resetGist}>{t('reset_all')}</button>
</>
)}

View file

@ -18,14 +18,14 @@ const Draft = props => {
...patternProps.autoLayout, ...patternProps.autoLayout,
width: patternProps.width, width: patternProps.width,
height: patternProps.height height: patternProps.height
}) }, false, false)
} }
}, [layout]) }, [layout])
if (!patternProps || !layout) return null if (!patternProps || !layout) return null
// Helper method to update part layout and re-calculate width * height // Helper method to update part layout and re-calculate width * height
const updateLayout = (name, config) => { const updateLayout = (name, config, history=true) => {
// Start creating new layout // Start creating new layout
const newLayout = {...layout} const newLayout = {...layout}
newLayout.parts[name] = config newLayout.parts[name] = config
@ -49,7 +49,7 @@ const Draft = props => {
newLayout.height = bottomRight.y - topLeft.y newLayout.height = bottomRight.y - topLeft.y
newLayout.bottomRight = bottomRight newLayout.bottomRight = bottomRight
newLayout.topLeft = topLeft newLayout.topLeft = topLeft
updateGist(['layout'], newLayout) updateGist(['layout'], newLayout, false, history)
} }

View file

@ -94,7 +94,7 @@ const Part = props => {
// update the layout on mount // update the layout on mount
useEffect(() => { useEffect(() => {
if (partRef.current) updateLayout() if (partRef.current) updateLayout(false)
}, [partRef]) }, [partRef])
// Initialize drag handler // Initialize drag handler
@ -168,7 +168,7 @@ const Part = props => {
updateLayout() updateLayout()
setRotate(!rotate) setRotate(!rotate)
} }
const updateLayout = () => { const updateLayout = (history=true) => {
const partRect = partRef.current.getBoundingClientRect(); const partRect = partRef.current.getBoundingClientRect();
const matrix = partRef.current.ownerSVGElement.getScreenCTM().inverse(); const matrix = partRef.current.ownerSVGElement.getScreenCTM().inverse();
@ -188,7 +188,7 @@ const Part = props => {
flipY, flipY,
tl, tl,
br br
}) }, history)
} }
// Method to flip (mirror) the part along the X or Y axis // Method to flip (mirror) the part along the X or Y axis

View file

@ -4,7 +4,6 @@ import DesignOptions from './design-options'
import CoreSettings from './core-settings' import CoreSettings from './core-settings'
import Xray from './xray' import Xray from './xray'
import TestDesignOptions from './test-design-options' import TestDesignOptions from './test-design-options'
import ErrorBoundary from 'shared/components/error-boundary'
export const Ul = props => <ul className="pl-5 list-inside">{props.children}</ul> export const Ul = props => <ul className="pl-5 list-inside">{props.children}</ul>
export const Li = props => ( export const Li = props => (
@ -87,7 +86,6 @@ const WorkbenchMenu = props => {
return ( return (
<nav className="grow mb-12"> <nav className="grow mb-12">
<ViewMenu {...props} /> <ViewMenu {...props} />
<ErrorBoundary>
{props.gist?._state?.view === 'draft' && ( {props.gist?._state?.view === 'draft' && (
<> <>
<DesignOptions {...props} /> <DesignOptions {...props} />
@ -96,7 +94,6 @@ const WorkbenchMenu = props => {
</> </>
)} )}
{props.gist?._state?.view === 'test' && <TestDesignOptions {...props} />} {props.gist?._state?.view === 'test' && <TestDesignOptions {...props} />}
</ErrorBoundary>
</nav> </nav>
) )
} }

View file

@ -18,7 +18,7 @@ import DraftEvents from 'shared/components/workbench/events.js'
import CutLayout from 'shared/components/workbench/layout/cut' import CutLayout from 'shared/components/workbench/layout/cut'
import PrintLayout from 'shared/components/workbench/layout/print' import PrintLayout from 'shared/components/workbench/layout/print'
import ErrorBoundary from 'shared/components/error-boundary'; import ErrorBoundary from 'shared/components/error/error-boundary';
const views = { const views = {
measurements: Measurements, measurements: Measurements,
@ -57,7 +57,7 @@ const doPreload = async (preload, from, design, gist, setGist, setPreloaded) =>
const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false }) => { const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false }) => {
// State for gist // State for gist
const {gist, setGist, unsetGist, updateGist, gistReady} = useGist(design, app); const {gist, setGist, unsetGist, updateGist, gistReady, undoGist, resetGist} = useGist(design, app);
const [messages, setMessages] = useState([]) const [messages, setMessages] = useState([])
const [popup, setPopup] = useState(false) const [popup, setPopup] = useState(false)
const [preloaded, setPreloaded] = useState(false) const [preloaded, setPreloaded] = useState(false)
@ -87,8 +87,8 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
}, [preload, preloaded, from, design]) }, [preload, preloaded, from, design])
// Helper methods to manage the gist state // Helper methods to manage the gist state
const updateWBGist = useMemo(() => (path, value, closeNav=false) => { const updateWBGist = useMemo(() => (path, value, closeNav=false, addToHistory=true) => {
updateGist(path, value) updateGist(path, value, addToHistory)
// Force close of menu on mobile if it is open // Force close of menu on mobile if it is open
if (closeNav && app.primaryMenu) app.setPrimaryMenu(false) if (closeNav && app.primaryMenu) app.setPrimaryMenu(false)
}, [app]) }, [app])
@ -142,6 +142,12 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
showInfo: setPopup, showInfo: setPopup,
} }
const errorProps = {
undoGist,
resetGist,
gist
}
// Layout to use // Layout to use
const LayoutComponent = layout const LayoutComponent = layout
? layout ? layout
@ -153,7 +159,7 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
return <LayoutComponent {...layoutProps}> return <LayoutComponent {...layoutProps}>
{messages} {messages}
<ErrorBoundary gist={gist}> <ErrorBoundary {...errorProps}>
<Component {...componentProps} /> <Component {...componentProps} />
{popup && <Modal cancel={() => setPopup(false)}>{popup}</Modal>} {popup && <Modal cancel={() => setPopup(false)}>{popup}</Modal>}
</ErrorBoundary> </ErrorBoundary>

View file

@ -1,7 +1,9 @@
import useLocalStorage from './useLocalStorage'; import useLocalStorage from './useLocalStorage';
import set from 'lodash.set' import set from 'lodash.set'
import unset from 'lodash.unset' import unset from 'lodash.unset'
import cloneDeep from 'lodash.clonedeep'
import defaultSettings from 'shared/components/workbench/default-settings.js' import defaultSettings from 'shared/components/workbench/default-settings.js'
import {useState, useEffect} from 'react'
// Generates a default design gist to start from // Generates a default design gist to start from
export const defaultGist = (design, locale='en') => { export const defaultGist = (design, locale='en') => {
@ -19,25 +21,68 @@ export const defaultGist = (design, locale='en') => {
// generate the gist state and its handlers // generate the gist state and its handlers
export function useGist(design, app) { export function useGist(design, app) {
// get the localstorage state and setter // get the localstorage state and setter
const [gist, setGist, gistReady] = useLocalStorage(`${design.config.name}_gist`, defaultGist(design, app.locale)); const [gist, _setGist, gistReady] = useLocalStorage(`${design.config.name}_gist`, defaultGist(design, app.locale));
const [gistHistory, setGistHistory] = useState([]);
const [gistFuture, setGistFuture] = useState([]);
const setGist = (newGist, addToHistory=true) => {
let oldGist
_setGist((gistState) => {
// have to clone it or nested objects will be referenced instead of copied, which defeats the purpose
oldGist = cloneDeep(gistState);
return typeof newGist === 'function' ? newGist(cloneDeep(gistState)) : newGist
})
if (addToHistory) {
setGistHistory((history) => {
return [...history, oldGist]
})
setGistFuture([])
}
}
/** update a single gist value */ /** update a single gist value */
const updateGist = (path, value) => { const updateGist = (path, value, addToHistory=true) => {
setGist((gistState) => { setGist((gistState) => {
const newGist = {...gistState}; const newGist = {...gistState};
set(newGist, path, value); set(newGist, path, value);
return newGist; return newGist;
}) }, addToHistory)
} }
/** unset a single gist value */ /** unset a single gist value */
const unsetGist = (path) => { const unsetGist = (path, addToHistory=true) => {
setGist((gistState) => { setGist((gistState) => {
const newGist = {... gistState}; const newGist = {...gistState};
unset(newGist, path); unset(newGist, path);
return newGist; return newGist;
}) }, addToHistory)
} }
return {gist, setGist, unsetGist, gistReady, updateGist}; const undoGist = () => {
_setGist((gistState) => {
let prevGist;
setGistHistory((history) => {
const newHistory = [...history]
prevGist = newHistory.pop() || defaultGist(design, app.locale);
return newHistory;
})
setGistFuture((future) => [gistState, ...future]);
return {...prevGist}
})
}
const redoGist = () => {
const newHistory = [...gistHistory, gist]
const newFuture = [...gistFuture]
const newGist = newFuture.shift()
setGistHistory(newHistory)
setGistFuture(newFuture)
_setGist(newGist)
}
const resetGist = () => setGist(defaultGist(design, app.locale))
return {gist, setGist, unsetGist, gistReady, updateGist, undoGist, redoGist, resetGist};
} }

View file

@ -23,6 +23,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"front-matter": "^4.0.2", "front-matter": "^4.0.2",
"highlight.js": "^11.4.0", "highlight.js": "^11.4.0",
"lodash.clonedeep": "^4.5.0",
"lodash.orderby": "^4.6.0", "lodash.orderby": "^4.6.0",
"lodash.unset": "^4.5.2", "lodash.unset": "^4.5.2",
"mdast-util-toc": "^6.1.0", "mdast-util-toc": "^6.1.0",

View file

@ -13805,6 +13805,11 @@ lodash.castarray@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115"
integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU=
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
lodash.debounce@^4.0.8: lodash.debounce@^4.0.8:
version "4.0.8" version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"