1
0
Fork 0

feat [org]: Wrote Editor docs

This commit is contained in:
joostdecock 2025-06-01 17:02:46 +02:00
parent 3d01c0136c
commit 0c1d886e94
53 changed files with 1054 additions and 496 deletions

View file

@ -3,7 +3,7 @@ import { copyToClipboard } from '@freesewing/utils'
import { CopyIcon, OkIcon } from '@freesewing/react/components/Icon'
import { LoadingStatusContext } from '@freesewing/react/context/LoadingStatus'
const handleCopied = (content, setCopied, setLoadingStatus, label) => {
const handleCopied = (content, setCopied, setLoadingStatus, label, handler=false) => {
copyToClipboard(content)
setCopied(true)
setLoadingStatus([
@ -13,6 +13,7 @@ const handleCopied = (content, setCopied, setLoadingStatus, label) => {
true,
])
setTimeout(() => setCopied(false), 1000)
if (typeof handler === 'function') handler(content, label)
}
/**
@ -21,12 +22,14 @@ const handleCopied = (content, setCopied, setLoadingStatus, label) => {
* @component
* @param {object} props - All component props
* @param {JSX.element} props.children - The component children
* @param {string} [props.btnClasses = 'tw:daisy-btn tw:daisy-btn-ghost tw:hover:border-transparent w:hover:border-transparent tw:hover:shadow-none'] - The content that should be copied to the clipboard
* @param {string} props.content - The content that should be copied to the clipboard
* @param {string} props.label - The label to show when the content is copied
* @param {function} [props.onCopy=false] - An optional handler to call after copying to the clipboard, receives content, label as parameters
* @param {boolean} props.sup - Set this to true to render as superscript (above the line)
* @returns {JSX.Element}
*/
export const CopyToClipboardButton = ({ children, content, label = false, sup = false }) => {
export const CopyToClipboardButton = ({ children, content, label = false, sup = false, btnClasses="tw:daisy-btn tw:daisy-btn-ghost tw:hover:border-transparent w:hover:border-transparent tw:hover:shadow-none", onCopy=false }) => {
const [copied, setCopied] = useState(false)
const { setLoadingStatus } = useContext(LoadingStatusContext)
@ -36,9 +39,10 @@ export const CopyToClipboardButton = ({ children, content, label = false, sup =
<button
className={
(copied ? 'tw:text-success ' : '') +
'tw:daisy-btn tw:w-full tw:daisy-btn-ghost tw:lg:w-auto tw:hover:bg-transparent tw:hover:border-transparent tw:group tw:hover:shadow-none'
btnClasses +
' tw:w-full tw:lg:w-auto tw:group tw:flex tw:flex-row tw:justify-between'
}
onClick={() => handleCopied(content, setCopied, setLoadingStatus, label)}
onClick={() => handleCopied(content, setCopied, setLoadingStatus, label, onCopy)}
>
{sup ? children : null}
{copied ? (

View file

@ -179,7 +179,7 @@ export const Collection = ({ Link = false, linkTo = 'about', editor = false, onC
onClick={() => setFilter({ ld: 1 })}
>
<ResetIcon />
Clear Filter
Clear Filters
</button>
<button
className="tw:daisy-btn tw:daisy-btn-secondary tw:daisy-btn-outline"

View file

@ -17,6 +17,7 @@ import {
ExportIcon,
FixmeIcon,
FlagIcon,
MeasurementsIcon,
OptionsIcon,
PaperlessIcon,
PrintIcon,
@ -52,6 +53,7 @@ const headerMenuIcons = {
settings: SettingsIcon,
ui: UiIcon,
layout: PrintIcon,
measurements: MeasurementsIcon,
}
export const HeaderMenuIcon = (props) => {
@ -121,7 +123,7 @@ export const HeaderMenuTestViewDesignMeasurements = (props) => {
tooltip="See how changes to a measurement influence the pattern being generated."
toggle={
<>
<HeaderMenuIcon name="options" extraClasses="tw:text-secondary" />
<HeaderMenuIcon name="measurements" extraClasses="tw:text-secondary" />
<span className="tw:hidden tw:lg:inline">Test Measurements</span>
</>
}
@ -463,12 +465,12 @@ export const HeaderMenuTestIcons = (props) => {
const Button = HeaderMenuButton
return (
<div className="tw:flex tw:flex-row tw:flex-wrap tw:items-center tw:justify-center tw:px-0.5 tw:lg:px-1">
<div className="tw:flex tw:flex-row tw:flex-wrap tw:items-center tw:justify-center tw:px-0.5 tw:lg:px-1 tw:items-center">
<Button
updateHandler={() => update.settings('sample', undefined)}
tooltip="Clear the test so you can select another"
>
Clear Test
<ResetIcon /> <span className="tw:hidden tw:lg:inline">Clear Test</span>
</Button>
</div>
)
@ -528,7 +530,7 @@ export const HeaderMenuButton = ({
}) => (
<Tooltip tip={tooltip}>
<button
className={`${lgOnly ? 'tw:hidden tw:lg:inline' : ''} tw:daisy-btn tw:daisy-btn-ghost tw:daisy-btn-sm tw:px-1 tw:disabled:bg-transparent`}
className={`${lgOnly ? 'tw:hidden tw:lg:inline' : ''} tw:daisy-btn tw:daisy-btn-ghost tw:my-1 tw:px-1 tw:disabled:bg-transparent`}
onClick={updateHandler}
disabled={disabled}
>
@ -604,7 +606,7 @@ export const HeaderMenuViewMenu = (props) => {
}
export const HeaderMenuLayoutView = (props) => (
<>
<div className="tw:flex tw:flex-row tw:items-center">
<HeaderMenuDropdown
{...props}
id="layoutOptions"
@ -619,7 +621,7 @@ export const HeaderMenuLayoutView = (props) => (
<LayoutSettingsMenu {...props} />
</HeaderMenuDropdown>
<HeaderMenuLayoutViewIcons {...props} />
</>
</div>
)
export const HeaderMenuLayoutViewIcons = (props) => {

View file

@ -2,7 +2,6 @@ import React, { useRef, useState, useEffect, useCallback } from 'react'
import { ZoomablePattern } from './ZoomablePattern.mjs'
import { generateStackTransform, getTransformedBounds } from '@freesewing/core'
import { getProps } from '@freesewing/react/components/Pattern'
import { FlipIcon, RotateIcon, ResetIcon } from '@freesewing/react/components/Icon'
import { drag } from 'd3-drag'
import { select } from 'd3-selection'
//import { Buttons } from './transform-buttons.mjs'
@ -413,6 +412,26 @@ const Button = ({ onClickCb, transform, Icon, title = '' }) => {
)
}
const InnerFlipIcon = () => (
<path
strokeLinkecap="round"
strokeLinejoin="round"
d="M7.5 21 3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5"
/>
)
const InnerRotateIcon = ({ props }) => (
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M 19.5,12 C 19.5,10.768 19.454,9.547 19.362,8.338 19.21576,6.3582806 17.641719,4.7842398 15.662,4.638 14.504476,4.5506731 13.344609,4.5048098 12.184624,4.5004103 M 19.5,12 l 3,-3 m -3,3 -3,-3 m -12,3 c 0,1.232 0.046,2.453 0.138,3.662 0.1462398,1.979719 1.7202806,3.55376 3.7,3.7 1.295324,0.09777 2.593584,0.143587 3.891661,0.13746 M 4.5,12 l 3,3 m -3,-3 -3,3"
{...props}
/>
)
const InnerResetIcon = () => (
<path d="M12 9.75 14.25 12m0 0 2.25 2.25M14.25 12l2.25-2.25M14.25 12 12 14.25m-2.58 4.92-6.374-6.375a1.125 1.125 0 0 1 0-1.59L9.42 4.83c.21-.211.497-.33.795-.33H19.5a2.25 2.25 0 0 1 2.25 2.25v10.5a2.25 2.25 0 0 1-2.25 2.25h-9.284c-.298 0-.585-.119-.795-.33Z" />
)
/** buttons for manipulating the part */
export const Buttons = ({ transform, flip, rotate, resetPart, rotate90, iconSize }) => {
return (
@ -438,31 +457,31 @@ export const Buttons = ({ transform, flip, rotate, resetPart, rotate90, iconSize
<Button
onClickCb={resetPart}
transform={`translate(${rectSize / -2}, ${rectSize / -2})`}
Icon={() => <ResetIcon wrapped={0} />}
Icon={() => <InnerResetIcon />}
title="Reset part orientation"
/>
<Button
onClickCb={() => rotate90()}
transform={`translate(${rectSize * -2.7}, ${rectSize / -2})`}
Icon={() => <RotateIcon wrapped={0} style={{}} />}
Icon={() => <InnerRotateIcon />}
title="Rotate part clockwise"
/>
<Button
onClickCb={() => flip('y')}
transform={`rotate(90) translate(${rectSize / -2}, ${rectSize * -1.6})`}
Icon={() => <FlipIcon wrapped={0} />}
Icon={() => <InnerFlipIcon />}
title="Flip part top/bottom"
/>
<Button
onClickCb={() => flip('x')}
transform={`translate(${rectSize * -1.6}, ${rectSize / -2})`}
Icon={() => <FlipIcon style={{}} wrapped={0} />}
Icon={() => <InnerFlipIcon />}
title="Flip part left/right"
/>
<Button
onClickCb={() => rotate90(-1)}
transform={`translate(${rectSize * 1.7}, ${rectSize / -2})`}
Icon={() => <RotateIcon transform="scale(-1,1), translate(-24,0)" wrapped={0} />}
Icon={() => <InnerRotateIcon transform="scale(-1,1), translate(-24,0)" />}
title="Rotate part counter-clockwise"
/>
</g>

View file

@ -4,6 +4,9 @@ import { HeaderMenu } from './HeaderMenu.mjs'
import { DesignOptionsMenu } from './menus/DesignOptionsMenu.mjs'
import { CoreSettingsMenu } from './menus/CoreSettingsMenu.mjs'
import { UiPreferencesMenu } from './menus/UiPreferencesMenu.mjs'
import { LayoutSettingsMenu } from './menus/LayoutMenu.mjs'
import { TestOptionsMenu, TestMeasurementsMenu } from './menus/TestMenu.mjs'
import { useDesignTranslation } from '@freesewing/react/hooks/useDesignTranslation'
/**
* A layout for views that include a drafted pattern
@ -17,6 +20,7 @@ import { UiPreferencesMenu } from './menus/UiPreferencesMenu.mjs'
*/
export const PatternLayout = (props) => {
const { Design, pattern, update, config, state } = props
const i18n = useDesignTranslation(Design.designConfig.data.id)
return (
<ZoomContextProvider>
@ -29,30 +33,63 @@ export const PatternLayout = (props) => {
<div className="tw:lg:w-2/3 tw:flex tw:flex-col tw:h-full tw:grow tw:p-2 tw:shadow tw:mx-2">
{props.output}
</div>
{state.ui?.aside ? (
<div
className={`tw:hidden tw:md:block tw:w-1/3 tw:shrink tw:grow-0 tw:lg:p-4 tw:max-w-2xl tw:h-full tw:overflow-scroll`}
>
<h5 className="tw:capitalize">{pattern.designConfig.data.id} Options</h5>
<SideMenuUl>
<DesignOptionsMenu {...props} />
</SideMenuUl>
<h5>Core Settings</h5>
<SideMenuUl>
<CoreSettingsMenu {...props} />
</SideMenuUl>
<h5>UI Preferences</h5>
<SideMenuUl>
<UiPreferencesMenu {...props} />
</SideMenuUl>
</div>
) : null}
<PatternAsideMenu {...props} i18n={i18n} />
</div>
</div>
</ZoomContextProvider>
)
}
const PatternAsideMenu = (props) => {
if (!props.state.ui?.aside) return null
if (props.state.view === 'draft') return (
<PatternAsideWrapper>
<h5 className="tw:capitalize">{props.pattern.designConfig.data.id} Options</h5>
<SideMenuUl>
<DesignOptionsMenu {...props} />
</SideMenuUl>
<h5>Core Settings</h5>
<SideMenuUl>
<CoreSettingsMenu {...props} />
</SideMenuUl>
<h5>UI Preferences</h5>
<SideMenuUl>
<UiPreferencesMenu {...props} />
</SideMenuUl>
</PatternAsideWrapper>
)
if (props.state.view === 'layout') return (
<PatternAsideWrapper>
<h5>Layout Settings</h5>
<SideMenuUl>
<LayoutSettingsMenu {...props} />
</SideMenuUl>
</PatternAsideWrapper>
)
if (props.state.view === 'test') return (
<PatternAsideWrapper>
<h5>Test Design Options</h5>
<SideMenuUl>
<TestOptionsMenu {...props} />
</SideMenuUl>
<h5>Test Measurements</h5>
<SideMenuUl>
<TestMeasurementsMenu {...props} />
</SideMenuUl>
</PatternAsideWrapper>
)
return null
}
const PatternAsideWrapper = ({ children }) => (
<div
className={`tw:hidden tw:md:block tw:w-1/3 tw:shrink tw:grow-0 tw:lg:p-4 tw:max-w-2xl tw:h-full tw:overflow-scroll`}
>
{children}
</div>
)
export const SideMenuUl = ({ children }) => (
<ul
className="tw:daisy-menu tw:daisy-dropdown-content tw:flex-nowrap tw:bg-base-200 tw:rounded-box tw:z-1 tw:w-full tw:p-0 tw:pl-0"

View file

@ -5,7 +5,7 @@ import { measurements as measurementsTranslations } from '@freesewing/i18n'
import React, { useMemo } from 'react'
// Components
import { MenuButtonGroup } from './Container.mjs'
import { BeakerIcon, OptionsIcon } from '@freesewing/react/components/Icon'
import { MeasurementsIcon, OptionsIcon } from '@freesewing/react/components/Icon'
/**
* The test design options menu
@ -87,7 +87,7 @@ const SampleOptionButton = ({ name, i18n, update }) => (
}
onClick={() => update.settings('sample', { type: 'option', option: name })}
>
<BeakerIcon className="tw:w-5 tw:h-5" />
<OptionsIcon className="tw:w-5 tw:h-5" />
<span>{i18n.en?.o[name]?.t ?? name}</span>
</button>
)
@ -100,7 +100,7 @@ const SampleMeasurementButton = ({ name, update }) => (
}
onClick={() => update.settings('sample', { type: 'measurement', measurement: name })}
>
<BeakerIcon className="tw:w-5 tw:h-5" />
<MeasurementsIcon className="tw:w-5 tw:h-5" />
<span>{measurementsTranslations[name]}</span>
</button>
)

View file

@ -1,11 +1,15 @@
// Dependencies
import { linkClasses, capitalize } from '@freesewing/utils'
// Context
import { ModalContext } from '@freesewing/react/context/Modal'
// Hooks
import React from 'react'
import React, { useContext } from 'react'
// Components
import { H1, H5 } from '@freesewing/react/components/Heading'
import { Popout } from '@freesewing/react/components/Popout'
import { H1, H2 } from '@freesewing/react/components/Heading'
import { modalDocsHelp } from '@freesewing/react/components/Help'
import { HeaderMenu } from '../HeaderMenu.mjs'
import { Popout } from '@freesewing/react/components/Popout'
/**
* This is the docs view, it just shows content
@ -16,51 +20,51 @@ import { HeaderMenu } from '../HeaderMenu.mjs'
* @param {Object} props.update - Helper object for updating the editor state
*/
export const DocsView = ({ state, config, update }) => {
const { setModal, modalContent } = useContext(ModalContext)
return (
<>
<HeaderMenu state={state} {...{ config, update }} />
<div className="tw:m-auto tw:mt-8 tw:max-w-2xl tw:px-4 tw:mb-8">
<H1>Documentation</H1>
{state?.design ? (
<Popout type="link">
<H5>Design Documentation</H5>
<p className="tw:text-lg">
You can find documentation for the {capitalize(state.design)} design at:
<br />
<b>
<>
<H2>Design Documentation</H2>
<Popout type="link" compact dense>
<div className="tw:font-bold tw:py-1">
<a
className={linkClasses}
href={`https://freesewing.eu/docs/designs/${state.design}`}
>{`FreeSewing.eu/docs/designs/${state.design}`}</a>
</b>
</p>
</Popout>
</div>
</Popout>
<button
className="tw:daisy-btn tw:daisy-btn-secondary tw:daisy-btn-outline tw:mt-4"
onClick={() => modalDocsHelp(`docs/designs/${state.design}`, setModal)}
>Open without leaving the Editor</button>
</>
) : null}
<Popout type="link">
<H5>Understanding the FreeSewing Pattern Editor</H5>
<p className="tw:text-lg">
Please refer to the pattern editor documentation at:
<br />
<b>
<a
className={linkClasses}
href="https://freesewing.eu/docs/about/editor"
>{`FreeSewing.eu/docs/about/editor`}</a>
</b>
</p>
<H2>Editor Documentation</H2>
<Popout type="link" compact dense>
<div className="tw:font-bold tw:py-1">
<a
className={linkClasses}
href="https://freesewing.eu/docs/editor"
>{`FreeSewing.eu/docs/editor`}</a>
</div>
</Popout>
<Popout type="tip">
<H5>
Looking for info on how it <em>really</em> works?
</H5>
<p>
Documentation for developers and contributors is available at{' '}
<b>
<a className={linkClasses} href="https://freesewing.dev/">{`FreeSewing.dev`}</a>
</b>
</p>
<button
className="tw:daisy-btn tw:daisy-btn-secondary tw:daisy-btn-outline tw:mt-4"
onClick={() => modalDocsHelp(`docs/editor`, setModal)}
>Open without leaving the Editor</button>
<H2>Developer Documentation</H2>
<Popout type="link" compact>
<b>
<a className={linkClasses} href="https://freesewing.dev/">{`FreeSewing.dev`}</a>
</b>
</Popout>
</div>
{modalContent}
</>
)
}

View file

@ -58,10 +58,26 @@ export const ExportView = (props) => {
<H2>Share your pattern</H2>
<p>If you merely want to share your pattern with others, you can copy these URLs:</p>
<div className="tw:grid tw:grid-cols-1 tw:lg:grid-cols-2 tw:gap-2 tw:mt-2 ">
<CopyToClipboardButton content={urls.a} update={update}>
<CopyToClipboardButton
content={urls.a}
btnClasses="tw:daisy-btn tw-daisy-btn-neutral tw:daisy-btn-outline"
label="Pattern and Measurements URL"
onCopy={() => {
console.log('handler called')
update.notifySuccess('Pattern and Measurements URL copied to clipboard')
}}
>
Pattern and Measurements
</CopyToClipboardButton>
<CopyToClipboardButton content={urls.b} update={update}>
<CopyToClipboardButton
content={urls.b}
btnClasses="tw:daisy-btn tw-daisy-btn-neutral tw:daisy-btn-outline"
label="Pattern URL"
onCopy={() => {
console.log('handler called')
update.notifySuccess('Pattern URL copied to clipboard')
}}
>
Pattern only
</CopyToClipboardButton>
</div>

View file

@ -162,7 +162,7 @@ export const SaveView = ({ config, state, update }) => {
To access your saved patterns, go to:
<b>
{' '}
<Link href="/account/patterns">/account/patterns</Link>
<Link href="/account/data/patterns/">/account/data/patterns</Link>
</b>
</p>
</div>

View file

@ -14,6 +14,7 @@ import { ZoomablePattern } from '../ZoomablePattern.mjs'
import { PatternLayout } from '../PatternLayout.mjs'
import { HeaderMenu } from '../HeaderMenu.mjs'
import { H1, H3, H4, H5 } from '@freesewing/react/components/Heading'
import { OptionsIcon, MeasurementsIcon } from '@freesewing/react/components/Icon'
/**
* The test view allows users to test options and measurements
@ -87,6 +88,7 @@ export const TestView = ({ Design, state, update, config }) => {
't',
'ASC'
)
const btnClasses = "tw:my-0.5 tw:block tw:daisy-btn tw:daisy-btn-primary tw:daisy-btn-outline tw:daisy-btn-xs tw:flex tw:flex-row tw:items-center tw:justify-between tw:w-full tw:max-w-64"
return (
<>
@ -106,12 +108,13 @@ export const TestView = ({ Design, state, update, config }) => {
{trm.map(({ t, m }) => (
<button
key={m}
className="tw:my-0.5 tw:block tw:daisy-btn tw:daisy-btn-primary tw:daisy-btn-outline tw:daisy-btn-xs"
className={btnClasses}
onClick={() =>
update.settings(['sample'], { type: 'measurement', measurement: m })
}
>
{t}
<MeasurementsIcon className="tw:w-4 tw:h-4" />
<span>{t}</span>
</button>
))}
</div>
@ -122,12 +125,13 @@ export const TestView = ({ Design, state, update, config }) => {
{tom.map(({ t, m }) => (
<button
key={m}
className="tw:my-0.5 tw:block tw:daisy-btn tw:daisy-btn-primary tw:daisy-btn-outline tw:daisy-btn-xs"
className={btnClasses}
onClick={() =>
update.settings(['sample'], { type: 'measurement', measurement: m })
}
>
{t}
<MeasurementsIcon className="tw:w-4 tw:h-4" />
<span>{t}</span>
</button>
))}
</div>
@ -158,6 +162,7 @@ const SampleOptionsMenu = ({ Design, state, update }) => {
const SampleOptionsSubMenu = ({ structure, update, level = 1 }) => {
const output = []
const btnClasses = "tw:my-0.5 tw:block tw:daisy-btn tw:daisy-btn-primary tw:daisy-btn-outline tw:daisy-btn-xs tw:flex tw:flex-row tw:items-center tw:justify-between tw:w-full tw:max-w-64"
/*
* Show entries alphabetic, but force groups last, and advanced last among them
*/
@ -175,10 +180,11 @@ const SampleOptionsSubMenu = ({ structure, update, level = 1 }) => {
output.push(
<button
key={name}
className="tw:my-0.5 tw:block tw:daisy-btn tw:daisy-btn-primary tw:daisy-btn-outline tw:daisy-btn-xs"
className={btnClasses}
onClick={() => update.settings(['sample'], { type: 'option', option: name })}
>
{struct.title}
<OptionsIcon className="tw:w-4 tw:h-4" />
<span>{struct.title}</span>
</button>
)
}

View file

@ -108,33 +108,33 @@ export const UndoStep = ({ update, state, step, Design, compact = false, index =
return (
<>
<p className="tw:text-sm tw:italic tw:font-medium tw:opacity-70 tw:text-right tw:p-0 tw:tw:m-0 tw:-mb-2 tw:pr-2">
<UndoStepTimeAgo step={step} />
</p>
<ButtonFrame onClick={() => update.restore(index, state._)}>
<div className="tw:flex tw:flex-row tw:items-center tw:justify-between tw:gap-2 tw:w-full tw:m-0 tw:p-0 tw:-mt-2 tw:text-lg">
<span className="tw:flex tw:flex-row tw:gap-2 tw:items-center">
{data.fieldIcon || null}
{data.title}
</span>
<span className="tw:opacity-70 tw:flex tw:flex-row tw:gap-1 tw:items-center tw:text-base">
{data.icon || null} {data.menu}
</span>
</div>
<div className="tw:flex tw:flex-row tw:gap-1 tw:items-center tw:align-start tw:w-full">
{data.msg ? (
data.msg
) : (
<>
<span className="">
{Array.isArray(data.newVal) ? data.newVal.join(', ') : data.newVal}
</span>
<LeftIcon className="tw:w-4 tw:h-4 tw:text-secondary tw:shrink-0" stroke={4} />
<span className="tw:line-through tw:decoration-1 tw:opacity-70">
{Array.isArray(data.oldVal) ? data.oldVal.join(', ') : data.oldVal}
</span>
</>
)}
<div className="tw:flex tw:flex-col tw:font-medium tw:items-end tw:w-full tw:-mb-2">
<div className="tw:text-sm tw:-mt-2 tw:italic"><UndoStepTimeAgo step={step} /></div>
<div className="tw:flex tw:flex-row tw:items-center tw:justify-start tw:gap-2 tw:w-full tw:text-lg tw:-mt-2">
<span className="tw:opacity-70 tw:flex tw:flex-row tw:gap-1 tw:items-center tw:text-base">
{data.menu}
</span>
<span>&raquo;</span>
<span className="tw:flex tw:flex-row tw:gap-2 tw:items-center">
{data.title}
</span>
</div>
<div className="tw:flex tw:flex-row tw:gap-1 tw:items-center tw:align-start tw:w-full">
{data.msg ? (
data.msg
) : (
<>
<span className="">
{Array.isArray(data.newVal) ? data.newVal.join(', ') : data.newVal}
</span>
<LeftIcon className="tw:w-4 tw:h-4 tw:text-secondary tw:shrink-0" stroke={4} />
<span className="tw:line-through tw:decoration-1 tw:opacity-70">
{Array.isArray(data.oldVal) ? data.oldVal.join(', ') : data.oldVal}
</span>
</>
)}
</div>
</div>
</ButtonFrame>
</>

View file

@ -2,7 +2,26 @@ import React from 'react'
// Components
import { ModalWrapper } from '@freesewing/react/components/Modal'
const Iframe = (props) => <iframe {...props} style={{ height: '90vh', width: '90vh' }} />
/*
* A component to display an iframe intended for a modal window.
*
* All props are passed down to the iframe tag.
*
* @component
* @param {object} props - All component props
* @returns {JSX.Element}
*/
const Iframe = (props) => <iframe {...props} style={{ height: '90vh', width: '90vw' }} className="tw:w-full tw:mx-auto tw:max-w-4xl" />
/*
* A component to display an iframe with FreeSewing.eu docs content intended for a modal window.
*
* @component
* @param {object} props - All component props
* @param {string} props.path - The (relative) URL path of the page to load
* @returns {JSX.Element}
*/
const DocsHelp = ({ path }) => <Iframe src={`https://freesewing.eu/${path}/?docusaurus-data-fs-embed=true`} />
/*
* A component to display inline help for a design option
@ -19,7 +38,7 @@ 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"
title="Design Options Help"
/>
) : (
<p>Invalid props provided to DesignOptionHelp.</p>
@ -38,7 +57,7 @@ const DesignOptionHelp = ({ design, o }) =>
const CoreSettingHelp = ({ name }) =>
name ? (
<Iframe
src={`https://freesewing.eu/docs/about/site/draft/${name.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
src={`https://freesewing.eu/docs/editor/menus/settings/${name.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
title="Core Setting Help"
/>
) : (
@ -58,8 +77,8 @@ const CoreSettingHelp = ({ name }) =>
const UiPreferenceHelp = ({ name }) =>
name ? (
<Iframe
src={`https://freesewing.eu/docs/about/site/draft/${name.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
title="UI Preference Help"
src={`https://freesewing.eu/docs/editor/menus/preferences/${name.toLowerCase()}/index.html?docusaurus-data-fs-embed=true`}
title="UI Preferences Help"
/>
) : (
<p>Invalid props provided to UiPreferenceHelp.</p>
@ -111,10 +130,17 @@ export function modalDesignOptionHelp(design, o, setModal) {
}
export function modalMeasurementHelp(m, setModal) {
console.log('in modalMeasurmentHelp', { m, setModal })
setModal(
<ModalWrapper fullWidth keepOpenOnClick>
<MeasurementHelp m={m} />
</ModalWrapper>
)
}
export function modalDocsHelp(path, setModal) {
setModal(
<ModalWrapper wide keepOpenOnClick>
<DocsHelp path={path} />
</ModalWrapper>
)
}

View file

@ -24,6 +24,7 @@ const slideClasses = {
* @param {bool} [keepOpenOnClick = false] - Set to true to prevent a click in the modal content from closing the modal
* @param {string} [slideFrom = left] - Direction to slide in from on mobile
* @param {bool} [fullWidth = false] - Set to true to not constrain the width
* @param {bool} [wide = false] - Set to true to not set a wide max width
* @returns {JSX.Element}
*/
export const ModalWrapper = ({
@ -37,6 +38,7 @@ export const ModalWrapper = ({
keepOpenOnClick = false,
slideFrom = 'left',
fullWidth = false,
wide = false,
}) => {
const { clearModal } = useContext(ModalContext)
const [animate, setAnimate] = useState('in')
@ -82,7 +84,8 @@ export const ModalWrapper = ({
onClick={keepOpenOnClick ? stopClick : null}
className={`tw:z-30 tw:bg-base-100 tw:p-4 tw:lg:px-8 tw:lg:rounded-lg tw:lg:shadow-lg tw:max-h-full tw:overflow-auto tw:hover:cursor-default ${
fullWidth ? 'tw:w-full' : ''
}`}
} ${wide ? 'tw:max-w-5xl tw:w-full' : ''} `}
>
{children}
<button