1
0
Fork 0

feat: Migrate from helpProvider to Help components

This commit is contained in:
joostdecock 2025-05-30 15:04:10 +02:00
parent f69093b0dc
commit 74d4f05d94
8 changed files with 107 additions and 20 deletions

View file

@ -83,6 +83,7 @@ packageJson:
"./components/Echart": "./components/Echart/index.mjs" "./components/Echart": "./components/Echart/index.mjs"
"./components/Editor": "./components/Editor/index.mjs" "./components/Editor": "./components/Editor/index.mjs"
"./components/Heading": "./components/Heading/index.mjs" "./components/Heading": "./components/Heading/index.mjs"
"./components/Help": "./components/Help/index.mjs"
"./components/Highlight": "./components/Highlight/index.mjs" "./components/Highlight": "./components/Highlight/index.mjs"
"./components/Icon": "./components/Icon/index.mjs" "./components/Icon": "./components/Icon/index.mjs"
"./components/Input": "./components/Input/index.mjs" "./components/Input": "./components/Input/index.mjs"
@ -124,6 +125,7 @@ packageJson:
"./hooks/useControl": "./hooks/useControl/index.mjs" "./hooks/useControl": "./hooks/useControl/index.mjs"
"./hooks/useDesign": "./hooks/useDesign/index.mjs" "./hooks/useDesign": "./hooks/useDesign/index.mjs"
"./hooks/useDesignTranslation": "./hooks/useDesignTranslation/index.mjs" "./hooks/useDesignTranslation": "./hooks/useDesignTranslation/index.mjs"
"./hooks/useFilter": "./hooks/useFilter/index.mjs"
"./hooks/useSelection": "./hooks/useSelection/index.mjs" "./hooks/useSelection": "./hooks/useSelection/index.mjs"
"./hooks/useStateObject": "./hooks/useStateObject/index.mjs" "./hooks/useStateObject": "./hooks/useStateObject/index.mjs"
# Lib # Lib

View file

@ -57,6 +57,7 @@ import { Popout } from '@freesewing/react/components/Popout'
import { bundlePatternTranslations, draft, flattenFlags } from '../Editor/lib/index.mjs' import { bundlePatternTranslations, draft, flattenFlags } from '../Editor/lib/index.mjs'
import { Bonny } from '@freesewing/bonny' import { Bonny } from '@freesewing/bonny'
import { MiniNote, MiniTip } from '../Mini/index.mjs' import { MiniNote, MiniTip } from '../Mini/index.mjs'
import { modalMeasurementHelp } from '@freesewing/react/components/Help'
/** /**
* Component to show an individual measurements set * Component to show an individual measurements set
@ -66,9 +67,8 @@ import { MiniNote, MiniTip } from '../Mini/index.mjs'
* @param {number} props.id - The ID of the measurements set to load * @param {number} props.id - The ID of the measurements set to load
* @param {bool} [props.publicOnly = false] - If the set should be used with the backend.getPublicSet method * @param {bool} [props.publicOnly = false] - If the set should be used with the backend.getPublicSet method
* @param {function} [props.Link = false] - An optional framework-specific Link component to use for client-side routing * @param {function} [props.Link = false] - An optional framework-specific Link component to use for client-side routing
* @param {function} [measurementHelpProvider = false] - A function that returns a url or action to show help for a specific measurement
*/ */
export const Set = ({ id, publicOnly = false, Link = false, measurementHelpProvider = false }) => { export const Set = ({ id, publicOnly = false, Link = false }) => {
if (!Link) Link = WebLink if (!Link) Link = WebLink
// Hooks // Hooks
@ -486,7 +486,7 @@ export const Set = ({ id, publicOnly = false, Link = false, measurementHelpProvi
current={mset.measies[m]} current={mset.measies[m]}
original={mset.measies[m]} original={mset.measies[m]}
update={updateMeasies} update={updateMeasies}
helpProvider={measurementHelpProvider} help={() => modalMeasurementHelp(m, setModal)}
/> />
))} ))}

View file

@ -1,5 +1,10 @@
import React from 'react' import React, { useContext } from 'react'
import { measurements as measurementTranslations } from '@freesewing/i18n'
// Context
import { ModalContext } from '@freesewing/react/context/Modal'
// Components
import { MeasurementInput } from '@freesewing/react/components/Input' import { MeasurementInput } from '@freesewing/react/components/Input'
import { modalMeasurementHelp } from '@freesewing/react/components/Help'
/** /**
* This MeasurementsEditor component allows inline-editing of the measurements * This MeasurementsEditor component allows inline-editing of the measurements
@ -9,10 +14,13 @@ 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, helpProvider = false }) => { export const MeasurementsEditor = ({ Design, update, state }) => {
// Context
const { setModal, modalContent } = useContext(ModalContext)
console.log({ modalContent })
/* /*
* Helper method to handle state updates for measurements * Helper method to handle state updates for measurements
*/ */
@ -26,7 +34,7 @@ export const MeasurementsEditor = ({ Design, update, state, helpProvider = false
const { settings = {} } = state const { settings = {} } = state
return ( return (
<div className="tw:max-w-2xl tw:mx-auto"> <div className="tw:max-w-xl tw:w-full tw:mx-auto">
<h4>Required Measurements</h4> <h4>Required Measurements</h4>
{Object.keys(Design.patternConfig.measurements).length === 0 ? ( {Object.keys(Design.patternConfig.measurements).length === 0 ? (
<p>This design does not require any measurements.</p> <p>This design does not require any measurements.</p>
@ -40,7 +48,8 @@ export const MeasurementsEditor = ({ Design, update, state, helpProvider = false
original={settings.measurements?.[m]} original={settings.measurements?.[m]}
update={(m, newVal) => onUpdate(m, newVal)} update={(m, newVal) => onUpdate(m, newVal)}
id={`edit-${m}`} id={`edit-${m}`}
helpProvider={helpProvider} label={measurementTranslations[m]}
help={() => modalMeasurementHelp(m, setModal)}
/> />
))} ))}
<br /> <br />
@ -58,6 +67,7 @@ export const MeasurementsEditor = ({ Design, update, state, helpProvider = false
original={settings.measurements?.[m]} original={settings.measurements?.[m]}
update={(m, newVal) => onUpdate(m, newVal)} update={(m, newVal) => onUpdate(m, newVal)}
id={`edit-${m}`} id={`edit-${m}`}
help={() => modalMeasurementHelp(m, setModal)}
/> />
)) ))
)} )}

View file

@ -2,8 +2,10 @@
import { designMeasurements } from '../../lib/index.mjs' import { designMeasurements } from '../../lib/index.mjs'
import { capitalize, horFlexClasses as horFlexClasses } from '@freesewing/utils' import { capitalize, horFlexClasses as horFlexClasses } from '@freesewing/utils'
import { measurements as measurementsTranslations } from '@freesewing/i18n' import { measurements as measurementsTranslations } from '@freesewing/i18n'
// Context
import { ModalContext } from '@freesewing/react/context/Modal'
// Hooks // Hooks
import React, { Fragment, useState, useEffect } from 'react' import React, { Fragment, useState, useEffect, useContext } from 'react'
import { useBackend } from '@freesewing/react/hooks/useBackend' import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components // Components
import { Popout } from '@freesewing/react/components/Popout' import { Popout } from '@freesewing/react/components/Popout'
@ -37,7 +39,6 @@ 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 = ({
@ -47,8 +48,8 @@ export const MeasurementsView = ({
state, state,
update, update,
design, design,
measurementHelpProvider = false,
}) => { }) => {
const { modalContent } = useContext(ModalContext)
/* /*
* 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
* Which is a bit confusing. So in this case, set the view to measurements. * Which is a bit confusing. So in this case, set the view to measurements.
@ -170,10 +171,7 @@ 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 <MeasurementsEditor key={2} {...{ Design, config, update, state }} />,
key={2}
{...{ Design, config, update, state, helpProvider: measurementHelpProvider }}
/>,
'edit', 'edit',
]) ])
@ -218,6 +216,7 @@ export const MeasurementsView = ({
)} )}
{items.length > 1 ? <Accordion items={items} /> : items} {items.length > 1 ? <Accordion items={items} /> : items}
</div> </div>
{modalContent}
</> </>
) )
} }

View file

@ -0,0 +1,62 @@
import React from 'react'
// Components
import { ModalWrapper } from '@freesewing/react/components/Modal'
/**
* A component to display inline help for a measurement.
*
* This is typically loaded as modal content as it returns an ifram
*
* @component
* @param {object} props - All component props
* @param {string} [props.m = undefined] - The measurment name (id)
* @returns {JSX.Element}
*/
export const DesignOptionHelp = ({ design, o }) =>
design && o ? (
<iframe
src={`https://freesewing.eu/docs/designs/${design.toLowerCase()}/options/${o.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
title="Design Option Help"
style={{ height: '90vh', width: '90vw' }}
/>
) : (
<p>Invalid props provided to DesignOptionHelp.</p>
)
/**
* A component to display inline help for a measurement.
*
* This is typically loaded as modal content as it returns an ifram
*
* @component
* @param {object} props - All component props
* @param {string} [props.m = undefined] - The measurment name (id)
* @returns {JSX.Element}
*/
export const MeasurementHelp = ({ m }) =>
m ? (
<iframe
src={`https://freesewing.eu/docs/measurements/${m.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
title="Measurement Help"
style={{ height: '90vh', width: '90vw' }}
/>
) : (
<p>No measurment name provided in the m prop.</p>
)
export function modalDesignOptionHelp(design, o, setModal) {
setModal(
<ModalWrapper fullWidth>
<DesignOptionHelp {...{ design, o }} />
</ModalWrapper>
)
}
export function modalMeasurementHelp(m, setModal) {
console.log('in modalMeasurmentHelp', { m, setModal })
setModal(
<ModalWrapper fullWidth>
<MeasurementHelp m={m} />
</ModalWrapper>
)
}

View file

@ -33,8 +33,8 @@ const HelpLink = ({ help, Link = false }) => {
if (typeof help === 'function') if (typeof help === 'function')
return ( return (
<button onClick={() => help} title="Show help"> <button onClick={help} title="Show help">
<HelpIcon className="tw:w-5 tw:h-5" /> <HelpIcon className="tw:w-5 tw:h-5 tw:text-secondary tw:hover:cursor-pointer" />
</button> </button>
) )
@ -774,7 +774,7 @@ export const MarkdownInput = ({
* @component * @component
* @param {object} props - All component props * @param {object} props - All component props
* @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset * @param {boolean} [props.box = false] - Set this to true to render a boxed fieldset
* @param {string|function} [props.props.help = false] - An optional URL/method to link/show help or docs * @param {string|function} [props.help = false] - An optional URL/method to link/show help or docs
* @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels * @param {string} [props.id = ''] - Id of the HTML element to link the fieldset labels
* @param {boolean} [props.imperial = false] - Set this to true to render imperial units * @param {boolean} [props.imperial = false] - Set this to true to render imperial units
* @param {string} [props.labelBR = false] - The bottom-right) label * @param {string} [props.labelBR = false] - The bottom-right) label
@ -861,7 +861,7 @@ export const MeasurementInput = ({
<Fieldset <Fieldset
{...{ box, help, labelTR, labelBR, legend }} {...{ box, help, labelTR, labelBR, legend }}
forId={id} forId={id}
label={measurementsTranslations[m] + (isDegree ? ' (°)' : '')} legend={measurementsTranslations[m] + (isDegree ? ' (°)' : '')}
labelBL={bottomLeftLabel} labelBL={bottomLeftLabel}
> >
<label <label

View file

@ -38,12 +38,15 @@
"./components/Button": "./components/Button/index.mjs", "./components/Button": "./components/Button/index.mjs",
"./components/Collection": "./components/Collection/index.mjs", "./components/Collection": "./components/Collection/index.mjs",
"./components/Control": "./components/Control/index.mjs", "./components/Control": "./components/Control/index.mjs",
"./components/CopyToClipboardButton": "./components/CopyToClipboardButton/index.mjs",
"./components/CuratedSet": "./components/CuratedSet/index.mjs", "./components/CuratedSet": "./components/CuratedSet/index.mjs",
"./components/Design": "./components/Design/index.mjs",
"./components/DiffViewer": "./components/DiffViewer/index.mjs", "./components/DiffViewer": "./components/DiffViewer/index.mjs",
"./components/Docusaurus": "./components/Docusaurus/index.mjs", "./components/Docusaurus": "./components/Docusaurus/index.mjs",
"./components/Echart": "./components/Echart/index.mjs", "./components/Echart": "./components/Echart/index.mjs",
"./components/Editor": "./components/Editor/index.mjs", "./components/Editor": "./components/Editor/index.mjs",
"./components/Heading": "./components/Heading/index.mjs", "./components/Heading": "./components/Heading/index.mjs",
"./components/Help": "./components/Help/index.mjs",
"./components/Highlight": "./components/Highlight/index.mjs", "./components/Highlight": "./components/Highlight/index.mjs",
"./components/Icon": "./components/Icon/index.mjs", "./components/Icon": "./components/Icon/index.mjs",
"./components/Input": "./components/Input/index.mjs", "./components/Input": "./components/Input/index.mjs",
@ -56,6 +59,7 @@
"./components/Markdown": "./components/Markdown/index.mjs", "./components/Markdown": "./components/Markdown/index.mjs",
"./components/Mini": "./components/Mini/index.mjs", "./components/Mini": "./components/Mini/index.mjs",
"./components/Modal": "./components/Modal/index.mjs", "./components/Modal": "./components/Modal/index.mjs",
"./components/New": "./components/New/index.mjs",
"./components/Newsletter": "./components/Newsletter/index.mjs", "./components/Newsletter": "./components/Newsletter/index.mjs",
"./components/Null": "./components/Null/index.mjs", "./components/Null": "./components/Null/index.mjs",
"./components/Number": "./components/Number/index.mjs", "./components/Number": "./components/Number/index.mjs",

View file

@ -226,3 +226,13 @@ nav.navbar {
justify-content: start; justify-content: start;
} }
} }
/*
* Styles for embedding docs in iframes
*/
html[data-fs-embed='true'] .navbar,
html[data-fs-embed='true'] nav,
html[data-fs-embed='true'] aside,
html[data-fs-embed='true'] footer {
display: none;
}