[react] fix: Various fixes for the measurement view and editor (#233)
Various fixes for the measurement view and editor: - Translate measurements in the measurement set view and align the measurements table properly - Display a question mark next to the measurements that links to the corresponding docs page This fixes a part of #226 Reviewed-on: https://codeberg.org/freesewing/freesewing/pulls/233 Reviewed-by: Joost De Cock <joostdecock@noreply.codeberg.org> Co-authored-by: Jonathan Haas <haasjona@gmail.com> Co-committed-by: Jonathan Haas <haasjona@gmail.com>
This commit is contained in:
parent
c5b0daf390
commit
36da79afb6
10 changed files with 49 additions and 19 deletions
|
@ -76,8 +76,9 @@ const t = (input) => {
|
||||||
* @param {number} id - The ID of the measurements set to load
|
* @param {number} id - The ID of the measurements set to load
|
||||||
* @param {bool} publicOnly - FIXME
|
* @param {bool} publicOnly - FIXME
|
||||||
* @param {function} Link - An optional framework-specific Link component to use for client-side routing
|
* @param {function} Link - An optional framework-specific Link component to use for client-side routing
|
||||||
|
* @param {object} measurementHelpProvider - A function that returns a url or action to show help for a specific measurement
|
||||||
*/
|
*/
|
||||||
export const Set = ({ id, publicOnly = false, Link = false }) => {
|
export const Set = ({ id, publicOnly = false, Link = false, measurementHelpProvider = false }) => {
|
||||||
if (!Link) Link = WebLink
|
if (!Link) Link = WebLink
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
|
@ -459,7 +460,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
||||||
title={<MeasurementValue {...{ m, val, imperial: !displayAsMetric }} />}
|
title={<MeasurementValue {...{ m, val, imperial: !displayAsMetric }} />}
|
||||||
key={m}
|
key={m}
|
||||||
>
|
>
|
||||||
<span className="tw-font-medium">{m}</span>
|
<span className="tw-font-medium">{measurementTranslations[m]}</span>
|
||||||
</DisplayRow>
|
</DisplayRow>
|
||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
|
@ -491,6 +492,7 @@ export const Set = ({ id, publicOnly = false, Link = false }) => {
|
||||||
current={mset.measies[m]}
|
current={mset.measies[m]}
|
||||||
original={mset.measies[m]}
|
original={mset.measies[m]}
|
||||||
update={updateMeasies}
|
update={updateMeasies}
|
||||||
|
helpProvider={measurementHelpProvider}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
/*
|
/*
|
||||||
* A component to display a row of data
|
* A component to display a row of data
|
||||||
*/
|
*/
|
||||||
export const DisplayRow = ({ title, children, keyWidth = 'w-24' }) => (
|
export const DisplayRow = ({ title, children, keyWidth = 'tw-w-24' }) => (
|
||||||
<div className="tw-flex tw-flex-row tw-flex-wrap tw-items-center lg:tw-gap-4 tw-my-2 tw-w-full">
|
<div className="tw-flex tw-flex-row tw-flex-wrap tw-items-center lg:tw-gap-4 tw-my-2 tw-w-full">
|
||||||
<div
|
<div
|
||||||
className={`${keyWidth} tw-text-left md:tw-text-right tw-block md:tw-inline tw-font-bold tw-pr-4 tw-shrink-0`}
|
className={`${keyWidth} tw-text-left md:tw-text-right tw-block md:tw-inline tw-font-bold tw-pr-4 tw-shrink-0`}
|
||||||
|
|
|
@ -9,9 +9,10 @@ import { MeasurementInput } from '@freesewing/react/components/Input'
|
||||||
* @param {object} props.state - The ViewWrapper state object
|
* @param {object} props.state - The ViewWrapper state object
|
||||||
* @param {object} props.state.settings - The current settings
|
* @param {object} props.state.settings - The current settings
|
||||||
* @param {object} props.update - Helper object for updating the ViewWrapper state
|
* @param {object} props.update - Helper object for updating the ViewWrapper state
|
||||||
|
* @param {object} props.helpProvider - A function that takes a measurement and returns a url or action to show help for that measurement
|
||||||
* @return {function} MeasurementsEditor - React component
|
* @return {function} MeasurementsEditor - React component
|
||||||
*/
|
*/
|
||||||
export const MeasurementsEditor = ({ Design, update, state }) => {
|
export const MeasurementsEditor = ({ Design, update, state, helpProvider = false }) => {
|
||||||
/*
|
/*
|
||||||
* Helper method to handle state updates for measurements
|
* Helper method to handle state updates for measurements
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +35,7 @@ export const MeasurementsEditor = ({ Design, update, state }) => {
|
||||||
original={state.settings.measurements?.[m]}
|
original={state.settings.measurements?.[m]}
|
||||||
update={(m, newVal) => onUpdate(m, newVal)}
|
update={(m, newVal) => onUpdate(m, newVal)}
|
||||||
id={`edit-${m}`}
|
id={`edit-${m}`}
|
||||||
|
helpProvider={helpProvider}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -37,6 +37,7 @@ const iconClasses = {
|
||||||
* @param {Array} props.missingMeasurements - List of missing measurements for the current design
|
* @param {Array} props.missingMeasurements - List of missing measurements for the current design
|
||||||
* @param {Object} props.state - The editor state object
|
* @param {Object} props.state - The editor state object
|
||||||
* @param {Object} props.update - Helper object for updating the editor state
|
* @param {Object} props.update - Helper object for updating the editor state
|
||||||
|
* @param {object} props.helpProvider - A function that takes a measurement and returns a url or action to show help for that measurement
|
||||||
* @return {Function} MeasurementsView - React component
|
* @return {Function} MeasurementsView - React component
|
||||||
*/
|
*/
|
||||||
export const MeasurementsView = ({
|
export const MeasurementsView = ({
|
||||||
|
@ -46,6 +47,7 @@ export const MeasurementsView = ({
|
||||||
state,
|
state,
|
||||||
update,
|
update,
|
||||||
design,
|
design,
|
||||||
|
measurementHelpProvider = false,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
* If there is no view set, completing measurements will switch to the view picker
|
* If there is no view set, completing measurements will switch to the view picker
|
||||||
|
@ -168,7 +170,10 @@ export const MeasurementsView = ({
|
||||||
</div>
|
</div>
|
||||||
<p className="tw-text-left">You can manually set or override measurements below.</p>
|
<p className="tw-text-left">You can manually set or override measurements below.</p>
|
||||||
</Fragment>,
|
</Fragment>,
|
||||||
<MeasurementsEditor key={2} {...{ Design, config, update, state }} />,
|
<MeasurementsEditor
|
||||||
|
key={2}
|
||||||
|
{...{ Design, config, update, state, helpProvider: measurementHelpProvider }}
|
||||||
|
/>,
|
||||||
'edit',
|
'edit',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ export const Editor = ({
|
||||||
preload = {},
|
preload = {},
|
||||||
setTitle = false,
|
setTitle = false,
|
||||||
localDesigns = {},
|
localDesigns = {},
|
||||||
|
measurementHelpProvider = false,
|
||||||
}) => {
|
}) => {
|
||||||
/*
|
/*
|
||||||
* Bundle all designs
|
* Bundle all designs
|
||||||
|
@ -144,6 +145,7 @@ export const Editor = ({
|
||||||
{...extraProps}
|
{...extraProps}
|
||||||
{...{ view, update, designs, config: editorConfig }}
|
{...{ view, update, designs, config: editorConfig }}
|
||||||
state={passDownState}
|
state={passDownState}
|
||||||
|
measurementHelpProvider={measurementHelpProvider}
|
||||||
/>
|
/>
|
||||||
</LoadingStatusContextProvider>
|
</LoadingStatusContextProvider>
|
||||||
</ModalContextProvider>
|
</ModalContextProvider>
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { useDropzone } from 'react-dropzone'
|
||||||
import { useBackend } from '@freesewing/react/hooks/useBackend'
|
import { useBackend } from '@freesewing/react/hooks/useBackend'
|
||||||
// Components
|
// Components
|
||||||
import { Link as WebLink } from '@freesewing/react/components/Link'
|
import { Link as WebLink } from '@freesewing/react/components/Link'
|
||||||
import { TrashIcon, ResetIcon, UploadIcon } from '@freesewing/react/components/Icon'
|
import { TrashIcon, ResetIcon, UploadIcon, HelpIcon } from '@freesewing/react/components/Icon'
|
||||||
import { ModalWrapper } from '@freesewing/react/components/Modal'
|
import { ModalWrapper } from '@freesewing/react/components/Modal'
|
||||||
import { isDegreeMeasurement } from '@freesewing/config'
|
import { isDegreeMeasurement } from '@freesewing/config'
|
||||||
import { Tabs, Tab } from '@freesewing/react/components/Tab'
|
import { Tabs, Tab } from '@freesewing/react/components/Tab'
|
||||||
|
@ -49,17 +49,17 @@ export const _Tab = ({
|
||||||
const HelpLink = ({ help, Link = false }) => {
|
const HelpLink = ({ help, Link = false }) => {
|
||||||
if (!Link) Link = WebLink
|
if (!Link) Link = WebLink
|
||||||
|
|
||||||
if (typeof helpLink === 'function')
|
if (typeof help === 'function')
|
||||||
return (
|
return (
|
||||||
<button onClick={() => help} title="Show help">
|
<button onClick={() => help} title="Show help">
|
||||||
<QuestionIcon className="tw-w-5 tw-h-5" />
|
<HelpIcon className="tw-w-5 tw-h-5" />
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (typeof helpLink === 'string')
|
if (typeof help === 'string')
|
||||||
return (
|
return (
|
||||||
<Link href={help} target="_BLANK" rel="nofollow" title="Show help">
|
<Link href={help} target="_BLANK" rel="nofollow" title="Show help">
|
||||||
<QuestionIcon className="tw-w-5 tw-h-5" />
|
<HelpIcon className="tw-w-5 tw-h-5" />
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,14 +77,14 @@ export const FormControl = ({
|
||||||
labelBR = false, // Optional bottom-right label
|
labelBR = false, // Optional bottom-right label
|
||||||
forId = false, // ID of the for element we are wrapping
|
forId = false, // ID of the for element we are wrapping
|
||||||
help = false, // An optional URL/method to link/show help/docs
|
help = false, // An optional URL/method to link/show help/docs
|
||||||
Link = false, // An optionan framework-specific link components
|
Link = false, // An optional framework-specific link components
|
||||||
}) => {
|
}) => {
|
||||||
if (labelBR && !labelBL) labelBL = <span></span>
|
if (labelBR && !labelBL) labelBL = <span></span>
|
||||||
|
|
||||||
const topLabelChildren = (
|
const topLabelChildren = (
|
||||||
<>
|
<>
|
||||||
{label ? (
|
{label ? (
|
||||||
<span className="tw-daisy-label-text tw-text-sm lg:tw-text-base tw-font-bold tw-mb-1 tw-text-inherit">
|
<span className="tw-daisy-label-text tw-text-sm lg:tw-text-base tw-font-bold tw-mb-1 tw-text-inherit tw-inline-flex tw-items-center tw-gap-1">
|
||||||
{label} <HelpLink {...{ help, Link }} />
|
{label} <HelpLink {...{ help, Link }} />
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
|
@ -541,6 +541,7 @@ export const MeasurementInput = ({
|
||||||
update, // The onChange handler
|
update, // The onChange handler
|
||||||
placeholder, // The placeholder content
|
placeholder, // The placeholder content
|
||||||
id = '', // An id to tie the input to the label
|
id = '', // An id to tie the input to the label
|
||||||
|
helpProvider = false, // a function that provides a url or an action to display help for a measurement
|
||||||
}) => {
|
}) => {
|
||||||
const isDegree = isDegreeMeasurement(m)
|
const isDegree = isDegreeMeasurement(m)
|
||||||
const units = imperial ? 'imperial' : 'metric'
|
const units = imperial ? 'imperial' : 'metric'
|
||||||
|
@ -604,6 +605,7 @@ export const MeasurementInput = ({
|
||||||
<FormControl
|
<FormControl
|
||||||
label={measurementsTranslations[m] + (isDegree ? ' (°)' : '')}
|
label={measurementsTranslations[m] + (isDegree ? ' (°)' : '')}
|
||||||
forId={id}
|
forId={id}
|
||||||
|
help={typeof helpProvider === 'function' ? helpProvider(m) : helpProvider}
|
||||||
labelBL={bottomLeftLabel}
|
labelBL={bottomLeftLabel}
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
|
|
|
@ -25,8 +25,15 @@ export const AnchorLink = ({ children, id = '', title = false }) => (
|
||||||
* @param {string} props.className - Any non-default CSS classes to apply
|
* @param {string} props.className - Any non-default CSS classes to apply
|
||||||
* @param {string} props.style - Any non-default styles to apply
|
* @param {string} props.style - Any non-default styles to apply
|
||||||
*/
|
*/
|
||||||
export const Link = ({ href, title = false, children, className = linkClasses, style = {} }) => (
|
export const Link = ({
|
||||||
<a href={href} className={className} title={title ? title : ''} style={style}>
|
href,
|
||||||
|
title = false,
|
||||||
|
children,
|
||||||
|
className = linkClasses,
|
||||||
|
target,
|
||||||
|
style = {},
|
||||||
|
}) => (
|
||||||
|
<a href={href} target={target} className={className} title={title ? title : ''} style={style}>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,6 +11,10 @@ import Link from '@docusaurus/Link'
|
||||||
|
|
||||||
<DocusaurusDoc>
|
<DocusaurusDoc>
|
||||||
<RoleBlock user>
|
<RoleBlock user>
|
||||||
<Set Link={Link} id={getSearchParam('id')} />
|
<Set
|
||||||
|
Link={Link}
|
||||||
|
id={getSearchParam('id')}
|
||||||
|
measurementHelpProvider={(m) => `/docs/measurements/${m.toLowerCase()}`}
|
||||||
|
/>
|
||||||
</RoleBlock>
|
</RoleBlock>
|
||||||
</DocusaurusDoc>
|
</DocusaurusDoc>
|
||||||
|
|
|
@ -18,7 +18,10 @@ const EditorPage = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BareLayout title={title}>
|
<BareLayout title={title}>
|
||||||
<Editor setTitle={setTitle} />
|
<Editor
|
||||||
|
setTitle={setTitle}
|
||||||
|
measurementHelpProvider={(m) => `/docs/measurements/${m.toLowerCase()}`}
|
||||||
|
/>
|
||||||
</BareLayout>
|
</BareLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,10 @@ export const MeasurementImage = (props) => {
|
||||||
.split('/')
|
.split('/')
|
||||||
.filter((dir) => dir)
|
.filter((dir) => dir)
|
||||||
.pop()
|
.pop()
|
||||||
if (!m || !measurements[caseMap[m]])
|
.toLowerCase()
|
||||||
|
// look up the internal measurement key case-insensitively
|
||||||
|
const mappedMeasurement = measurements[caseMap[m]]
|
||||||
|
if (!m || !mappedMeasurement)
|
||||||
return <p>Unable to match the input {m} to MeasurementImage to a measurement name</p>
|
return <p>Unable to match the input {m} to MeasurementImage to a measurement name</p>
|
||||||
|
|
||||||
const pose = seated.includes(m) ? 'seated' : 'standing'
|
const pose = seated.includes(m) ? 'seated' : 'standing'
|
||||||
|
@ -50,7 +53,7 @@ export const MeasurementImage = (props) => {
|
||||||
height={sarahImages[m].height}
|
height={sarahImages[m].height}
|
||||||
width={sarahImages[m].width}
|
width={sarahImages[m].width}
|
||||||
src={sarahImages[m]}
|
src={sarahImages[m]}
|
||||||
alt={measurements[caseMap[m]]}
|
alt={mappedMeasurement}
|
||||||
style={{ ...style, backgroundImage: `url(/img/sarah-${pose}.jpg)` }}
|
style={{ ...style, backgroundImage: `url(/img/sarah-${pose}.jpg)` }}
|
||||||
/>
|
/>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
@ -59,7 +62,7 @@ export const MeasurementImage = (props) => {
|
||||||
height={timImages[m].height}
|
height={timImages[m].height}
|
||||||
width={timImages[m].width}
|
width={timImages[m].width}
|
||||||
src={timImages[m]}
|
src={timImages[m]}
|
||||||
alt={measurements[caseMap[m]]}
|
alt={mappedMeasurement}
|
||||||
style={{ ...style, backgroundImage: `url(/img/tim-${pose}.jpg)` }}
|
style={{ ...style, backgroundImage: `url(/img/tim-${pose}.jpg)` }}
|
||||||
/>
|
/>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue