chore(chared): Updated flag UI and api
This commit is contained in:
parent
893490d42a
commit
f5edf74936
13 changed files with 158 additions and 112 deletions
|
@ -6,8 +6,10 @@
|
|||
"neckBinding": "Neck opening knit binding"
|
||||
},
|
||||
"s": {
|
||||
"cutArmBinding": "Not shown: the **Arm opening knit binding**, two strips of fabric {{{ width }}} wide and {{{ length }}} long <small>(this includes seam allowance)</small>",
|
||||
"cutNeckBinding": "Not shown: the **Neck opening knit binding**, a strip of fabric {{{ width }}} wide and {{{ length }}} long <small>(this includes seam allowance)</small>",
|
||||
"cutArmBinding.t": "The arm opening knit binding is not currently shown",
|
||||
"cutArmBinding.d": "The **Arm opening knit binding** are two strips of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). They are not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||
"cutNeckBinding.t": "The neck opening knit binding is not currently shown",
|
||||
"cutNeckBinding.d": "The **Neck opening knit binding** is a strip of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). It is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||
"cutOneStripToFinishTheNeckOpening": "Cut one strip to finish the neck opening",
|
||||
"cutTwoStripsToFinishTheArmholes": "Cut two strips to finish the armholes",
|
||||
"length": "Length",
|
||||
|
|
|
@ -23,7 +23,8 @@ export const armBinding = {
|
|||
if (!expand) {
|
||||
// Expand is on, do not draw the part but flag this to the user
|
||||
store.flag.note({
|
||||
msg: `aaron:cutArmBinding`,
|
||||
title: `aaron:cutArmBinding.t`,
|
||||
desc: `aaron:cutArmBinding.d`,
|
||||
replace: {
|
||||
width: units(w),
|
||||
length: units(l),
|
||||
|
|
|
@ -23,7 +23,8 @@ export const neckBinding = {
|
|||
if (!expand) {
|
||||
// Expand is on, do not draw the part but flag this to the user
|
||||
store.flag.note({
|
||||
msg: `aaron:cutNeckBinding`,
|
||||
title: `aaron:cutNeckBinding.t`,
|
||||
desc: `aaron:cutNeckBinding.d`,
|
||||
replace: {
|
||||
width: units(w),
|
||||
length: units(l),
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
},
|
||||
"s": {
|
||||
"attachStrap": "Attach strap",
|
||||
"cutPocket": "Not shown: the **Pocket**, a rectangle of {{{ width }}} wide and {{{ length }}} long <small>(this includes seam allowance)</small>",
|
||||
"cutStrap": "Not shown: the **Straps**, two rectangles of {{{ width }}} wide and {{{ length }}} long <small>(this includes seam allowance)</small>",
|
||||
"cutPocket.t": "The pocket is not currently shown",
|
||||
"cutPocket.d": "The **Pocket** is a rectangular piece of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance). It is not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||
"cutStrap.t": "The straps are not currently shown",
|
||||
"cutStrap.d": "The **Straps** are two strips of fabric {{{ width }}} wide and {{{ length }}} long (this includes seam allowance)</small>. They are not shown because the **expand** core setting is currently disabled. Enable it to show this pattern part.",
|
||||
"foldHere": "Fold here"
|
||||
},
|
||||
"o": {
|
||||
|
|
|
@ -22,7 +22,8 @@ export const pocket = {
|
|||
if (!expand) {
|
||||
// Expand is on, do not draw the part but flag this to the user
|
||||
store.flag.note({
|
||||
msg: `albert:cutPocket`,
|
||||
title: `albert:cutPocket.t`,
|
||||
desc: `albert:cutPocket.d`,
|
||||
replace: {
|
||||
width: units(pocketSize * 2 + 2 * sa),
|
||||
length: units(pocketSize + 2 * sa + store.get('strapWidth')),
|
||||
|
|
|
@ -41,10 +41,11 @@ export const strap = {
|
|||
if (!expand) {
|
||||
// Expand is on, do not draw the part but flag this to the user
|
||||
store.flag.note({
|
||||
msg: `albert:cutStrap`,
|
||||
title: `albert:cutStrap.t`,
|
||||
desc: `albert:cutStrap.d`,
|
||||
replace: {
|
||||
width: units(store.get('strapWidth') + 2 * sa),
|
||||
length: units(store.get('strapLength') + store.get('strapWidth') * 2 + 2 * sa),
|
||||
width: units(strapWidth + 2 * sa),
|
||||
length: units(strapLength + strapWidth * 2 + 2 * sa),
|
||||
},
|
||||
suggest: {
|
||||
text: 'flag:show',
|
||||
|
|
|
@ -34,13 +34,13 @@ function flag(type, store, data) {
|
|||
type = data.type
|
||||
}
|
||||
|
||||
if (!data.id && !data.msg) {
|
||||
store.log.warning(`store.flag.${type} called without an id or msg property`)
|
||||
if (!data.id && !data.title) {
|
||||
store.log.warn(`store.flag.${type} called without an id or title property`)
|
||||
console.log(data)
|
||||
return
|
||||
}
|
||||
|
||||
store.set([...storeRoot, type, data.id ? data.id : data.msg], data)
|
||||
store.set([...storeRoot, type, data.id ? data.id : data.title], data)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -53,7 +53,7 @@ function flag(type, store, data) {
|
|||
function unflag(type, store, id) {
|
||||
if (type === 'preset' && presets[id]) {
|
||||
type = presets[id].type
|
||||
id = presets[id].id || presets[id].msg
|
||||
id = presets[id].id || presets[id].title
|
||||
}
|
||||
store.unset([...storeRoot, type, id])
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ function unflag(type, store, id) {
|
|||
const presets = {
|
||||
expand: {
|
||||
type: 'tip',
|
||||
msg: 'flag:expandIsOff',
|
||||
title: 'flag:expandIsOff.t',
|
||||
desc: 'flag:expandIsOff.d',
|
||||
suggest: {
|
||||
text: 'flag:enable',
|
||||
icon: 'expand',
|
||||
|
|
|
@ -26,9 +26,12 @@ const BaseAccordion = ({
|
|||
}) => {
|
||||
const [active, setActive] = useState()
|
||||
|
||||
console.log(items)
|
||||
return (
|
||||
<nav>
|
||||
{items.map((item, i) =>
|
||||
{items
|
||||
.filter((item) => item[0])
|
||||
.map((item, i) =>
|
||||
active === i ? (
|
||||
<div key={i} {...propsGetter(active, i)}>
|
||||
<button onClick={setActive} className="w-full">
|
||||
|
|
|
@ -318,6 +318,12 @@ export const FingerprintIcon = (props) => (
|
|||
</IconWrapper>
|
||||
)
|
||||
|
||||
export const FlagIcon = (props) => (
|
||||
<IconWrapper {...props}>
|
||||
<path d="M3 3v1.5M3 21v-6m0 0l2.77-.693a9 9 0 016.208.682l.108.054a9 9 0 006.086.71l3.114-.732a48.524 48.524 0 01-.005-10.499l-3.11.732a9 9 0 01-6.085-.711l-.108-.054a9 9 0 00-6.208-.682L3 4.5M3 15V4.5" />
|
||||
</IconWrapper>
|
||||
)
|
||||
|
||||
export const FreeSewingIcon = (props) => (
|
||||
<IconWrapper {...props} stroke={0} fill>
|
||||
<path d={logoPath} />
|
||||
|
|
|
@ -49,7 +49,6 @@ export const DraftView = ({
|
|||
pattern: output,
|
||||
setSettings,
|
||||
Header: DraftHeader,
|
||||
flags: pattern.setStores?.[0]?.plugins?.['plugin-annotations']?.flags,
|
||||
menu: (
|
||||
<DraftMenu
|
||||
{...{
|
||||
|
@ -66,6 +65,7 @@ export const DraftView = ({
|
|||
renderProps,
|
||||
view,
|
||||
setView,
|
||||
flags: pattern.setStores?.[0]?.plugins?.['plugin-annotations']?.flags,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -9,8 +9,12 @@ import {
|
|||
import { UiSettings, ns as uiNs } from 'shared/components/workbench/menus/ui-settings/index.mjs'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { nsMerge } from 'shared/utils.mjs'
|
||||
import { SettingsIcon, OptionsIcon, DesktopIcon } from 'shared/components/icons.mjs'
|
||||
import { SettingsIcon, OptionsIcon, DesktopIcon, FlagIcon } from 'shared/components/icons.mjs'
|
||||
import { Accordion } from 'shared/components/accordion.mjs'
|
||||
import {
|
||||
FlagsAccordionTitle,
|
||||
FlagsAccordionEntries,
|
||||
} from 'shared/components/workbench/views/flags.mjs'
|
||||
|
||||
export const ns = nsMerge(coreMenuNs, designMenuNs, uiNs)
|
||||
|
||||
|
@ -26,6 +30,7 @@ export const DraftMenu = ({
|
|||
DynamicDocs,
|
||||
view,
|
||||
setView,
|
||||
flags = false,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const control = account.control
|
||||
|
@ -61,9 +66,14 @@ export const DraftMenu = ({
|
|||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
items={sections.map((section) => [
|
||||
const items = []
|
||||
if (flags)
|
||||
items.push([
|
||||
<FlagsAccordionTitle flags={flags} />,
|
||||
<FlagsAccordionEntries {...{ update, control, flags }} />,
|
||||
])
|
||||
items.push(
|
||||
...sections.map((section) => [
|
||||
<>
|
||||
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||
<span>{t(`${section.ns}:${section.name}.t`)}</span>
|
||||
|
@ -72,7 +82,8 @@ export const DraftMenu = ({
|
|||
<p className="text-left">{t(`${section.ns}:${section.name}.d`)}</p>
|
||||
</>,
|
||||
section.menu,
|
||||
])}
|
||||
/>
|
||||
])
|
||||
)
|
||||
|
||||
return <Accordion items={items} />
|
||||
}
|
||||
|
|
|
@ -13,16 +13,10 @@ import {
|
|||
ErrorIcon,
|
||||
WrenchIcon as FixmeIcon,
|
||||
ExpandIcon,
|
||||
FlagIcon,
|
||||
} from 'shared/components/icons.mjs'
|
||||
import Markdown from 'react-markdown'
|
||||
|
||||
const flagColors = {
|
||||
note: 'primary',
|
||||
tip: 'accent',
|
||||
warn: 'error',
|
||||
error: 'error',
|
||||
fixme: 'warning',
|
||||
}
|
||||
import { SubAccordion } from 'shared/components/accordion.mjs'
|
||||
|
||||
const flagIcons = {
|
||||
note: ChatIcon,
|
||||
|
@ -34,39 +28,14 @@ const flagIcons = {
|
|||
expand: ExpandIcon,
|
||||
}
|
||||
|
||||
export const Flags = ({ flags, update }) => {
|
||||
const handleUpdate = (config) => {
|
||||
if (config.settings) update.settings(...config.settings)
|
||||
if (config.ui) update.ui(...config.settings)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4 flex flex-row overflow-x-auto w-full gap-4 max-w-screen">
|
||||
{flagTypes.map((type) =>
|
||||
flags[type]
|
||||
? Object.values(flags[type]).map((flag) => (
|
||||
<Flag type={type} data={flag} handleUpdate={handleUpdate} key={flag.id} />
|
||||
))
|
||||
: null
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Flag = ({ type, data, handleUpdate }) => {
|
||||
const { t } = useTranslation(nsMerge('flag', data.ns, data.msg.split(':').shift()))
|
||||
const [hide, setHide] = useState(false)
|
||||
|
||||
if (hide || !data.msg) return null
|
||||
|
||||
const color = flagColors[type]
|
||||
export const Flag = ({ type, data, t, handleUpdate }) => {
|
||||
const Icon = flagIcons[type]
|
||||
const BtnIcon = data.suggest?.icon ? flagIcons[data.suggest.icon] : false
|
||||
|
||||
const button =
|
||||
data.suggest?.text && data.suggest?.update ? (
|
||||
<button
|
||||
className={`btn btn-sm sm:btn-normal btn-neutral btn-outline grow flex flex-row items-center justify-between sm:grow-0 shrink-0 z-10 ${
|
||||
className={`btn btn-secondary btn-outline flex flex-row items-center ${
|
||||
BtnIcon ? 'gap-6' : ''
|
||||
}`}
|
||||
onClick={() => handleUpdate(data.suggest.update)}
|
||||
|
@ -76,43 +45,87 @@ export const Flag = ({ type, data, handleUpdate }) => {
|
|||
</button>
|
||||
) : null
|
||||
|
||||
const msg = data.replace
|
||||
? mustache.render(t(data.msg), { ...data.replace, '"': '"' })
|
||||
: t(data.msg)
|
||||
const desc = data.replace ? mustache.render(t(data.desc), data.replace) : t(data.desc)
|
||||
|
||||
return (
|
||||
<div className="w-4/5 max-w-md shrink-0">
|
||||
<div className={`relative bg-${color} bg-opacity-10`}>
|
||||
<div className="p-3 rounded-lg shadow text-base">
|
||||
<div className="flex flex-row flex-wrap sm:flex-nowrap gap-2 items-start z-10">
|
||||
<div className="first:mt-0 popout-content grow z-10 md flag">
|
||||
<Markdown>{msg}</Markdown>
|
||||
</div>
|
||||
{button ? (
|
||||
<div className="flex flex-row justify-between sm:flex-col gap-2 shrink-0 z-10 w-full sm:w-auto">
|
||||
{button}
|
||||
<button
|
||||
className="w-1/2 sm:w-full btn btn-ghost btn-sm z-10 flex flex-row items-center justify-between w-full"
|
||||
onClick={() => setHide(true)}
|
||||
>
|
||||
{t('flag:dismiss')}
|
||||
<Icon className="w-5 h-6 sm:w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
className="btn btn-sm btn-circle btn-ghost"
|
||||
onClick={() => setHide(true)}
|
||||
title={t('flag:hide')}
|
||||
>
|
||||
<Icon className="w-5 h-5 sm:w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 items-start">
|
||||
<div className="first:mt-0 grow md flag">
|
||||
<Markdown children={desc} />
|
||||
</div>
|
||||
{button ? <div className="mt-2 w-full flex flex-row justify-end">{button}</div> : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const flattenFlags = (flags) => {
|
||||
const all = {}
|
||||
const ns = ['flag']
|
||||
for (const type of flagTypes) {
|
||||
let i = 0
|
||||
if (flags[type]) {
|
||||
for (const [key, flag] of Object.entries(flags[type])) {
|
||||
i++
|
||||
all[`${type}-${i}`] = { ...flag, type }
|
||||
if (flag.ns) ns.push(flag.ns)
|
||||
if (flag.title.includes(':')) ns.push(flag.title.split(':').shift())
|
||||
if (flag.desc.includes(':')) ns.push(flag.desc.split(':').shift())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [all, ns]
|
||||
}
|
||||
|
||||
export const FlagsAccordionTitle = ({ flags }) => {
|
||||
const { t } = useTranslation(['flag'])
|
||||
const [flagList] = flattenFlags(flags)
|
||||
|
||||
if (Object.keys(flagList).length < 1) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<h5 className="flex flex-row gap-2 items-center justify-between w-full">
|
||||
<span>
|
||||
{t('flag:flagMenu.t')} ({Object.keys(flagList).length})
|
||||
</span>
|
||||
<FlagIcon className="w-8 h-8" />
|
||||
</h5>
|
||||
<p className="text-left">
|
||||
{Object.keys(flagList).length > 1 ? t('flag:flagMenuMany.d') : t('flag:flagMenuOne.d')}
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const FlagsAccordionEntries = ({ flags, update }) => {
|
||||
const [flagList, ns] = flattenFlags(flags)
|
||||
const { t } = useTranslation(nsMerge(ns))
|
||||
const [all, setAll] = useState(flagList)
|
||||
|
||||
if (Object.keys(flagList).length < 1) return null
|
||||
|
||||
const handleUpdate = (config) => {
|
||||
if (config.settings) update.settings(...config.settings)
|
||||
if (config.ui) update.ui(...config.settings)
|
||||
}
|
||||
|
||||
return (
|
||||
<SubAccordion
|
||||
items={Object.entries(all).map(([key, flag], i) => {
|
||||
const Icon = flagIcons[flag.type]
|
||||
const title = flag.replace ? mustache.render(t(flag.title), flag.replace) : t(flag.title)
|
||||
|
||||
return [
|
||||
<div className="w-full flex flex-row gap2 justify-between" key={i}>
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<Icon />
|
||||
<span className="font-medium">{title}</span>
|
||||
</div>
|
||||
<span className="uppercase font-bold">{flag.type}</span>
|
||||
</div>,
|
||||
<Flag key={key} t={t} type={flag.type} data={flag} handleUpdate={handleUpdate} />,
|
||||
]
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
dismiss: Dismiss
|
||||
expandIsOff: The **expand** core setting is disabled. Some parts are not fully drawn. Enable it to see them.
|
||||
expandIsOff.t: This design saves space (and trees) because expand is disabled
|
||||
expandIsOff.d: Because the **expand** core setting is currently disabled, some parts are not fully drawn or not shown at all. Typically, these are simple rectangles that only take up space. To expand all pattern parts to their full size, enable the expand setting.
|
||||
enable: Enable
|
||||
flagMenu.t: Messages from the designer
|
||||
flagMenuOne.d: The designer of this pattern has flagged something about your current draft that deserves your attention.
|
||||
flagMenuMany.d: The designer of this pattern has flagged some things about your current draft that deserve your attention.
|
||||
hide: Hide
|
||||
show: Show
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue