From 4528e1bc8812c142919ec11342a0d99abf13a815 Mon Sep 17 00:00:00 2001 From: joostdecock Date: Thu, 7 Sep 2023 10:29:19 +0200 Subject: [PATCH] feat(shared): Added support for flags --- plugins/plugin-annotations/i18n/en.json | 4 + plugins/plugin-annotations/src/cutlist.mjs | 6 +- plugins/plugin-annotations/src/cutonfold.mjs | 13 +-- plugins/plugin-annotations/src/flag.mjs | 76 +++++++++++++ plugins/plugin-annotations/src/index.mjs | 4 +- plugins/plugin-annotations/src/scalebox.mjs | 14 ++- plugins/plugin-annotations/src/title.mjs | 2 + sites/shared/components/workbench/new.mjs | 1 + .../{view-header.mjs => draft/header.mjs} | 2 +- .../workbench/views/draft/index.mjs | 7 +- .../components/workbench/views/flags.mjs | 105 ++++++++++++++++++ .../workbench/views/pattern-with-menu.mjs | 16 +-- sites/shared/i18n/flag/en.yaml | 4 + sites/shared/utils.mjs | 2 +- 14 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 plugins/plugin-annotations/src/flag.mjs rename sites/shared/components/workbench/views/{view-header.mjs => draft/header.mjs} (98%) create mode 100644 sites/shared/components/workbench/views/flags.mjs create mode 100644 sites/shared/i18n/flag/en.yaml diff --git a/plugins/plugin-annotations/i18n/en.json b/plugins/plugin-annotations/i18n/en.json index 8264fd4da38..bbe9c6da3a8 100644 --- a/plugins/plugin-annotations/i18n/en.json +++ b/plugins/plugin-annotations/i18n/en.json @@ -4,6 +4,10 @@ "cutOnFold": "Cut on fold", "cutOnFoldAndGrainline": "Cut on fold / Grainline", "fabric": "main fabric", + "altFabric1": "alternative fabric", + "altFabric2": "alternative fabric #2", + "altFabric3": "alternative fabric #3", + "altFabric4": "alternative fabric #4", "facing": "facing", "from": "from", "fusible": "fusible interfacing", diff --git a/plugins/plugin-annotations/src/cutlist.mjs b/plugins/plugin-annotations/src/cutlist.mjs index a4c8f7d4c2b..5245f1eebf5 100644 --- a/plugins/plugin-annotations/src/cutlist.mjs +++ b/plugins/plugin-annotations/src/cutlist.mjs @@ -30,7 +30,11 @@ export const cutlistHooks = { * @param {boolean} so.ignoreOnFold should these cutting instructions ignore any cutOnFold information set by the part */ function addCut(store, so = {}) { - const { cut = 2, material = 'fabric', identical = false, bias = false, ignoreOnFold = false } = so + const { cut = 2, identical = false, bias = false, ignoreOnFold = false } = so + // Make 'from' an alias for material + let { material = 'fabric' } = so + if (so.from) material = so.from + const partName = store.get('activePart') if (cut === false) { if (material === false) store.unset(['cutlist', partName, 'materials']) diff --git a/plugins/plugin-annotations/src/cutonfold.mjs b/plugins/plugin-annotations/src/cutonfold.mjs index 29221eed9d8..47b4138c98c 100644 --- a/plugins/plugin-annotations/src/cutonfold.mjs +++ b/plugins/plugin-annotations/src/cutonfold.mjs @@ -12,6 +12,7 @@ const macroDefaults = { grainline: false, margin: 0.05, offset: 15, + reverse: false, } // Export defs @@ -90,15 +91,13 @@ const cutonfold = function (config, { points, paths, Path, complete, store, scal /* * Draw the path */ - const from = mc.from.shiftFractionTowards(mc.to, mc.margin / 100) - const to = mc.to.shiftFractionTowards(mc.from, mc.margin / 100) + const from = mc.from.shiftFractionTowards(mc.to, mc.margin) + const to = mc.to.shiftFractionTowards(mc.from, mc.margin) const via1 = from.shiftTowards(mc.from, mc.offset * scale).rotate(-90, from) const via2 = to.shiftTowards(mc.to, mc.offset * scale).rotate(90, to) - paths[ids.line] = new Path() - .move(from) - .line(via1) - .line(via2) - .line(to) + paths[ids.line] = new Path().move(from).line(via1).line(via2).line(to) + if (mc.reverse) paths[ids.line] = paths[ids.line].reverse() + paths[ids.line] = paths[ids.line] .attr('class', mc.classes.line) .attr('marker-start', 'url(#cutonfoldFrom)') .attr('marker-end', 'url(#cutonfoldTo)') diff --git a/plugins/plugin-annotations/src/flag.mjs b/plugins/plugin-annotations/src/flag.mjs new file mode 100644 index 00000000000..bcf99af03f5 --- /dev/null +++ b/plugins/plugin-annotations/src/flag.mjs @@ -0,0 +1,76 @@ +const storeRoot = ['plugins', 'plugin-annotations', 'flags'] + +// This is also the order in which they will be displayed +export const flagTypes = ['error', 'warn', 'note', 'info', 'tip', 'fixme'] + +export const flagStores = [ + ['flag.info', (store, data) => flag('info', store, data)], + ['flag.tip', (store, data) => flag('tip', store, data)], + ['flag.note', (store, data) => flag('note', store, data)], + ['flag.warn', (store, data) => flag('warn', store, data)], + ['flag.fixme', (store, data) => flag('fixme', store, data)], + ['flag.error', (store, data) => flag('error', store, data)], + ['flag.preset', (store, preset) => flag('preset', store, preset)], + ['unflag.info', (store, id) => unflag('info', store, id)], + ['unflag.tip', (store, id) => unflag('tip', store, id)], + ['unflag.note', (store, id) => unflag('note', store, id)], + ['unflag.warn', (store, id) => unflag('warn', store, id)], + ['unflag.fixme', (store, id) => unflag('fixme', store, id)], + ['unflag.error', (store, id) => unflag('error', store, id)], + ['unflag.preset', (store, preset) => unflag('preset', store, preset)], +] + +/* + * Method that adds a flag to the store + * + * @param {type} string - The type of flag + * @param {store} object - The pattern store + * @param {data} object - The flag data + */ +function flag(type, store, data) { + // Load presets + if (type === 'preset' && presets[data]) { + data = presets[data] + type = data.type + } + + if (!data.id && !data.msg) { + store.log.warning(`store.flag.${type} called without an id or msg property`) + console.log(data) + return + } + + store.set([...storeRoot, type, data.id ? data.id : data.msg], data) +} + +/* + * Method that removes a flag from the store + * + * @param {type} string - The type of flag + * @param {store} object - The pattern store + * @param {id} string - The flag id to remove + */ +function unflag(type, store, id) { + if (type === 'preset' && presets[preset]) { + id = presets[preset].id || presets[preset].msg + type = presets[preset].type + } + store.unset([...storeRoot, type, id]) +} + +/* + * Available flag presets + */ +const presets = { + expand: { + type: 'tip', + msg: 'flag:expandIsOff', + suggest: { + text: 'flag:enable', + icon: 'expand', + update: { + settings: ['expand', 1], + }, + }, + }, +} diff --git a/plugins/plugin-annotations/src/index.mjs b/plugins/plugin-annotations/src/index.mjs index 24bff66d380..aecfadcddbe 100644 --- a/plugins/plugin-annotations/src/index.mjs +++ b/plugins/plugin-annotations/src/index.mjs @@ -19,6 +19,8 @@ import { dimensionsMacros, dimensionsDefs } from './dimensions.mjs' import { grainlineMacros, grainlineDefs } from './grainline.mjs' import { pleatMacros, pleatDefs } from './pleat.mjs' import { sewtogetherMacros, sewtogetherDefs } from './sewtogether.mjs' +// Only stores +import { flagStores } from './flag.mjs' export const plugin = { name, @@ -59,7 +61,7 @@ export const plugin = { ...sewtogetherMacros, ...titleMacros, }, - store: [...cutlistStores], + store: [...cutlistStores, ...flagStores], } export const annotationsPlugin = plugin diff --git a/plugins/plugin-annotations/src/scalebox.mjs b/plugins/plugin-annotations/src/scalebox.mjs index f7b600a2261..a449bdfb856 100644 --- a/plugins/plugin-annotations/src/scalebox.mjs +++ b/plugins/plugin-annotations/src/scalebox.mjs @@ -71,7 +71,10 @@ const removeScaleAnnotation = function (id = false, { paths, points, store, part /* * The scalebox macro */ -const scalebox = function (config, { store, points, paths, scale, Point, Path, complete, part }) { +const scalebox = function ( + config, + { store, points, paths, scale, Point, Path, complete, log, part } +) { /* * Don't add a title when complete is false, unless force is true */ @@ -103,7 +106,7 @@ const scalebox = function (config, { store, points, paths, scale, Point, Path, c */ if (!mc.at || typeof mc.at.attr !== 'function') { log.warn(`Scalebox macro called without a valid at point. Using (0,0) for at.`) - mc.from = new Point(0, 0) + mc.at = new Point(0, 0) } /* @@ -262,7 +265,10 @@ const scalebox = function (config, { store, points, paths, scale, Point, Path, c /* * The miniscale macro */ -const miniscale = function (config, { points, paths, scale, Point, Path, part, complete, store }) { +const miniscale = function ( + config, + { points, paths, scale, Point, Path, part, complete, log, store } +) { /* * Don't add a title when complete is false, unless force is true */ @@ -293,7 +299,7 @@ const miniscale = function (config, { points, paths, scale, Point, Path, part, c */ if (!mc.at || typeof mc.at.attr !== 'function') { log.warn(`Scalebox macro called without a valid at point. Using (0,0) for at.`) - mc.from = new Point(0, 0) + mc.at = new Point(0, 0) } /* diff --git a/plugins/plugin-annotations/src/title.mjs b/plugins/plugin-annotations/src/title.mjs index 57ed94a6b54..b1d6bae4221 100644 --- a/plugins/plugin-annotations/src/title.mjs +++ b/plugins/plugin-annotations/src/title.mjs @@ -199,6 +199,7 @@ const addTitleMacro = function ( .shift(-90, shift) .attr('data-text', `(${store.data.for})`) .attr('data-text-class', `${mc.classes.for} ${mc.align}`) + .attr('data-text-transform', transform) shift += mc.dy } else delete ids.for @@ -217,6 +218,7 @@ const addTitleMacro = function ( }) ) .attr('data-text-class', `${mc.classes.date} ${mc.align}`) + .attr('data-text-transform', transform) /* * Store all IDs in the store so we can remove this macro with rmtitle diff --git a/sites/shared/components/workbench/new.mjs b/sites/shared/components/workbench/new.mjs index 2a6aa7e26cc..7b8d69b1d35 100644 --- a/sites/shared/components/workbench/new.mjs +++ b/sites/shared/components/workbench/new.mjs @@ -29,6 +29,7 @@ import { MeasiesView, ns as measiesNs } from 'shared/components/workbench/views/ export const ns = [ 'account', 'workbench', + 'flag', ...draftNs, ...saveNs, ...printNs, diff --git a/sites/shared/components/workbench/views/view-header.mjs b/sites/shared/components/workbench/views/draft/header.mjs similarity index 98% rename from sites/shared/components/workbench/views/view-header.mjs rename to sites/shared/components/workbench/views/draft/header.mjs index fe138b83bd6..151bcd33386 100644 --- a/sites/shared/components/workbench/views/view-header.mjs +++ b/sites/shared/components/workbench/views/draft/header.mjs @@ -74,7 +74,7 @@ const ZoomButtons = ({ t, zoomFunctions, zoomed }) => { const Spacer = () => | -export const ViewHeader = ({ update, settings, ui, control, account, design, setSettings }) => { +export const DraftHeader = ({ update, settings, ui, control, account, design, setSettings }) => { const { t, i18n } = useTranslation(ns) const { zoomFunctions, zoomed } = useContext(PanZoomContext) const backend = useBackend() diff --git a/sites/shared/components/workbench/views/draft/index.mjs b/sites/shared/components/workbench/views/draft/index.mjs index 762e1ca3932..34de1fd3fb3 100644 --- a/sites/shared/components/workbench/views/draft/index.mjs +++ b/sites/shared/components/workbench/views/draft/index.mjs @@ -1,8 +1,9 @@ import { PanZoomPattern as ShowPattern } from 'shared/components/workbench/pan-zoom-pattern.mjs' import { DraftMenu, ns as menuNs } from './menu.mjs' -import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs' +import { PatternWithMenu } from '../pattern-with-menu.mjs' +import { DraftHeader, ns as headerNs } from './header.mjs' -export const ns = [...menuNs, ...wrapperNs] +export const ns = [...menuNs, ...headerNs] export const DraftView = ({ design, @@ -47,6 +48,8 @@ export const DraftView = ({ design, pattern: output, setSettings, + Header: DraftHeader, + flags: pattern.setStores?.[0]?.plugins?.['plugin-annotations']?.flags, menu: ( { + const handleUpdate = (config) => { + if (config.settings) update.settings(...config.settings) + if (config.ui) update.ui(...config.settings) + } + + return ( +
+ {flagTypes.map((type) => + flags[type] + ? Object.values(flags[type]).map((flag) => ( + + )) + : null + )} +
+ ) +} + +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] + const Icon = flagIcons[type] + const BtnIcon = data.suggest?.icon ? flagIcons[data.suggest.icon] : false + + const button = + data.suggest?.text && data.suggest?.update ? ( + + ) : null + + const msg = data.replace ? mustache.render(t(data.msg), data.replace) : t(data.msg) + + return ( +
+
+
+
+
+
+ {button} + +
+
+
+
+
+ ) +} diff --git a/sites/shared/components/workbench/views/pattern-with-menu.mjs b/sites/shared/components/workbench/views/pattern-with-menu.mjs index 8574376d0c2..6d074854895 100644 --- a/sites/shared/components/workbench/views/pattern-with-menu.mjs +++ b/sites/shared/components/workbench/views/pattern-with-menu.mjs @@ -1,10 +1,10 @@ import { PanZoomContextProvider } from 'shared/components/workbench/pattern/pan-zoom-context.mjs' -import { ViewHeader, ns as headerNs } from './view-header.mjs' import { MenuWrapper } from 'shared/components/workbench/menus/shared/menu-wrapper.mjs' +import { Flags } from './flags.mjs' -export const ns = headerNs +export const ns = ['common', 'core-settings', 'ui-settings'] -/** a layout for views that include a drafted pattern, a sidebar menu, and the draft view header */ +/** a layout for views that include a drafted pattern, a sidebar menu, and a header you pass it */ export const PatternWithMenu = ({ settings, ui, @@ -16,12 +16,13 @@ export const PatternWithMenu = ({ pattern, menu, setSettings, - noHeader = false, + Header = false, + flags = false, }) => (
- {noHeader ? null : ( - - )} + ) : null} + {flags ? : null}
{title} diff --git a/sites/shared/i18n/flag/en.yaml b/sites/shared/i18n/flag/en.yaml new file mode 100644 index 00000000000..a126d3c6fbb --- /dev/null +++ b/sites/shared/i18n/flag/en.yaml @@ -0,0 +1,4 @@ +dismiss: Dismiss +expandIsOff: The expand core setting is disabled. Some parts are not fully drawn. Enable it to see them. +enable: Enable +show: Show diff --git a/sites/shared/utils.mjs b/sites/shared/utils.mjs index e1a318b18f7..79e9647a9f3 100644 --- a/sites/shared/utils.mjs +++ b/sites/shared/utils.mjs @@ -259,7 +259,7 @@ export const nsMerge = (...args) => { if (typeof arg === 'string') ns.add(arg) else if (Array.isArray(arg)) { for (const el of nsMerge(...arg)) ns.add(el) - } else console.log('Unexpected namespect type:', { arg }) + } } return [...ns]