// Dependencies import { cloudflareImageUrl } from 'shared/utils.mjs' // Context import { ModalContext } from 'shared/context/modal-context.mjs' // Hooks import { useState, useCallback, useContext } from 'react' import { useTranslation } from 'next-i18next' import { useDropzone } from 'react-dropzone' // Components import { Popout } from 'shared/components/popout/index.mjs' import Markdown from 'react-markdown' import { ResetIcon, DocsIcon, HelpIcon } from 'shared/components/icons.mjs' import { ModalWrapper } from 'shared/components/wrappers/modal.mjs' import { isDegreeMeasurement } from 'config/measurements.mjs' import { measurementAsMm, formatMm, measurementAsUnits, parseDistanceInput } from 'shared/utils.mjs' //import { Collapse } from 'shared/components/collapse.mjs' //import { PlusIcon, EditIcon } from 'shared/components/icons.mjs' //import { NumberInput } from 'shared/components/workbench/menus/shared/inputs.mjs' //import { useState, useCallback } from 'react' export const ns = ['account', 'measurements'] /* * Helper component to display a tab heading */ export const Tab = ({ id, // The tab ID label, // A label for the tab, if not set we'll use the ID activeTab, // Which tab (id) is active setActiveTab, // Method to set the active tab }) => ( ) /* * Helper component to wrap a form control with a label */ export const FormControl = ({ label, // the (top-left) label children, // Children to go inside the form control docs = false, // Optional top-right label labelBL = false, // Optional bottom-left label labelBR = false, // Optional bottom-right label }) => { const { setModal } = useContext(ModalContext) return (
{children} {labelBL || labelBR ? ( ) : null}
) } /* * Helper method to wrap content in a button */ export const ButtonFrame = ({ children, // Children of the button onClick, // onClick handler active, // Whether or not to render the button as active/selected }) => ( ) /* * Input for strings */ export const StringInput = ({ label, // Label to use update, // onChange handler valid, // Method that should return whether the value is valid or not current, // The current value original, // The original value placeholder, // The placeholder text docs = false, // Docs to load, if any }) => { const { setModal } = useContext(ModalContext) const labelTR = docs ? ( ) : ( false ) return ( update(evt.target.value)} className={`input w-full input-bordered ${ current === original ? 'input-secondary' : valid(current) ? 'input-success' : 'input-error' }`} /> ) } /* * Input for an image that is passive (it does not upload the image) */ export const PassiveImageInput = ({ label, // The label update, // The onChange handler current, // The current value original, // The original value docs = false, // Docs to load, if any }) => { const { t } = useTranslation(ns) const onDrop = useCallback( (acceptedFiles) => { const reader = new FileReader() reader.onload = async () => { update(reader.result) } acceptedFiles.forEach((file) => reader.readAsDataURL(file)) }, [current] ) const { getRootProps, getInputProps } = useDropzone({ onDrop }) if (current) return (
) return (

{t('imgDragAndDropImageHere')}

{t('or')}

{t('or')}

update(evt.target.value)} />
) } /* * Input for a list of things to pick from */ export const ListInput = ({ update, // the onChange handler label, // The label list, // The list of items to present { val, label, desc } current, // The (value of the) current item original, // The original value docs = false, // Docs to load, if any }) => ( {list.map((item, i) => ( update(item.val)}>
{item.label}
{item.desc}
))}
) /* * Input for markdown content */ export const MarkdownInput = ({ label, // The label current, // The current value (markdown) original, // The original value update, // The onChange handler placeholder, // The placeholder content docs = false, // Docs to load, if any }) => { const { t } = useTranslation(ns) const [activeTab, setActiveTab] = useState('edit') return (
{['edit', 'preview'].map((tab) => ( ))}
{activeTab === 'edit' ? (