add reset_all and undo buttons to error boundary. no styling
This commit is contained in:
parent
00953e9189
commit
9bcfa4f39b
10 changed files with 93 additions and 28 deletions
|
@ -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
|
|
||||||

|
|
||||||
|
|
|
@ -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 {
|
10
sites/shared/components/error/reset-buttons.js
Normal file
10
sites/shared/components/error/reset-buttons.js
Normal 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>
|
||||||
|
</>
|
||||||
|
)}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue