diff --git a/packages/react/components/Editor/components/HeaderMenu.mjs b/packages/react/components/Editor/components/HeaderMenu.mjs
index c513ed1c736..b1258cd6a82 100644
--- a/packages/react/components/Editor/components/HeaderMenu.mjs
+++ b/packages/react/components/Editor/components/HeaderMenu.mjs
@@ -1,7 +1,7 @@
// Dependencies
import { missingMeasurements, flattenFlags } from '../lib/index.mjs'
// Hooks
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
import { useBackend } from '@freesewing/react/hooks/useBackend'
import { useDesignTranslation } from '@freesewing/react/hooks/useDesignTranslation'
// Components
@@ -21,7 +21,9 @@ import {
MenuIcon,
OptionsIcon,
PaperlessIcon,
+ PrintIcon,
ResetAllIcon,
+ ResetIcon,
RightIcon,
RocketIcon,
RotateIcon,
@@ -38,6 +40,7 @@ import { ButtonFrame } from '@freesewing/react/components/Input'
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 { FlagsAccordionEntries } from './Flag.mjs'
import { UndoStep } from './views/UndosView.mjs'
@@ -50,6 +53,7 @@ const headerMenuIcons = {
right: RightIcon,
settings: SettingsIcon,
ui: UiIcon,
+ layout: PrintIcon,
}
export const HeaderMenuIcon = (props) => {
@@ -508,8 +512,106 @@ export const HeaderMenuViewMenu = (props) => {
)
}
+export const HeaderMenuLayoutView = (props) => (
+ <>
+
+
+ Print Settings
+ >
+ }
+ >
+
+
+
+ >
+)
+
+export const HeaderMenuLayoutViewIcons = (props) => {
+ const { pattern, update, state } = props
+ const [tweaks, setTweaks] = useState(0)
+
+ useEffect(() => {
+ /*
+ * When the layout is reset, the UI won't update to changes
+ * unless we apply them on the first change
+ */
+ if (
+ tweaks === 0 &&
+ typeof props.state.ui?.layout === 'object' &&
+ typeof props.state.settings?.layout !== 'object'
+ )
+ applyLayout()
+ setTweaks(tweaks + 1)
+ }, [props.state.ui.layout])
+
+ const applyLayout = () => {
+ setTweaks(-1)
+ update.settings('layout', state.ui.layout)
+ }
+ const resetLayout = () => {
+ setTweaks(-1)
+ update.ui('layout', true)
+ update.settings('layout', true)
+ }
+
+ const pages = pattern.setStores[0].get('pages', {})
+ const format = state.ui.print?.pages?.size
+ ? state.ui.print.pages.size
+ : state.settings?.units === 'imperial'
+ ? 'letter'
+ : 'a4'
+ const { cols, rows, count } = pages
+ const blank = cols * rows - count
+
+ return (
+ <>
+
+
+
+ {count} pages
+
+ ({cols}x{rows}, {blank} blank)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
+
const headerMenus = {
draft: HeaderMenuDraftView,
+ layout: HeaderMenuLayoutView,
//HeaderMenuDraftViewDesignOptions,
//HeaderMenuDraftViewCoreSettings,
//HeaderMenuDraftViewUiPreferences,
diff --git a/packages/react/components/Editor/components/MovablePattern.mjs b/packages/react/components/Editor/components/MovablePattern.mjs
index 3bc7046493a..5a141fefb0d 100644
--- a/packages/react/components/Editor/components/MovablePattern.mjs
+++ b/packages/react/components/Editor/components/MovablePattern.mjs
@@ -1,19 +1,26 @@
-import React, { useRef } from 'react'
-import { PanZoomPattern } from 'shared/components/workbench/pan-zoom-pattern.mjs'
-import { MovableStack } from './stack.mjs'
+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'
export const MovablePattern = ({
renderProps,
- showButtons = true,
+ state,
update,
fitImmovable = false,
immovable = [],
- layoutPath,
+ t,
}) => {
const svgRef = useRef(null)
if (!renderProps) return null
- // keep a fresh copy of the layout because we might manipulate it without saving to the gist
+ /* keep a fresh copy of the layout because we might manipulate it without
+ * update the state
+ */
let layout =
renderProps.settings[0].layout === true
? {
@@ -52,9 +59,15 @@ export const MovablePattern = ({
newLayout.topLeft = topLeft
if (history) {
- update.ui(layoutPath, newLayout)
+ update.ui('layout', newLayout)
} else {
- // we don't put it in the gist if it shouldn't contribute to history because we need some of the data calculated here for rendering purposes on the initial layout, but we don't want to actually save a layout until the user manipulates it. This is what allows the layout to respond appropriately to settings changes. Once the user has starting playing with the layout, all bets are off
+ /* we don't put it in the gist if it shouldn't contribute to history
+ * because we need some of the data calculated here for rendering
+ * purposes on the initial layout, but we don't want to actually save a
+ * layout until the user manipulates it. This is what allows the layout
+ * to respond appropriately to settings changes. Once the user has
+ * starting playing with the layout, all bets are off
+ */
layout = newLayout
}
}
@@ -82,20 +95,22 @@ export const MovablePattern = ({
movable: !immovable.includes(stackName),
layout: layout.stacks[stackName],
updateLayout,
- showButtons,
settings,
+ state,
}}
/>
)
return (
-
+
+
+
)
}
@@ -141,13 +156,6 @@ export const MovablePattern = ({
* more data and factors in the transforms. We then use our `domToSvg`
* function to move the points back into the SVG space.
*/
-//import { useRef, useState, useEffect, useCallback } from 'react'
-//import { generateStackTransform, getTransformedBounds } from '@freesewing/core'
-//import { getProps } from 'pkgs/react-components/src/pattern/utils.mjs'
-//import { angle } from '../utils.mjs'
-//import { drag } from 'd3-drag'
-//import { select } from 'd3-selection'
-//import { Buttons } from './transform-buttons.mjs'
export const MovableStack = ({
stackName,
@@ -157,8 +165,8 @@ export const MovableStack = ({
movable = true,
layout,
updateLayout,
- showButtons,
settings,
+ state,
}) => {
const stackExists = !movable || typeof layout?.move?.x !== 'undefined'
@@ -198,7 +206,7 @@ export const MovableStack = ({
return transforms
}, [liveTransforms, stackRef, stack])
- /** update the layout either locally or in the gist */
+ /** update the layout either locally or in the state */
const updateStacklayout = useCallback(
(history = true) => {
/** don't mess with what we don't lay out */
@@ -327,9 +335,12 @@ export const MovableStack = ({
}, [stackRef, movable, stackExists, handleDrag])
// // Don't just assume this makes sense
- if (!stackExists) return null
+ if (!stackExists) {
+ return null
+ }
const { Group, Part } = components
+
return (
@@ -348,23 +359,120 @@ export const MovableStack = ({
id={`${stackName}-layout-rect`}
onClick={toggleDragRotate}
/>
- {showButtons ? (
-
- ) : null}
+
>
)}
)
}
+
+function dx(pointA, pointB) {
+ return pointB.x - pointA.x
+}
+function dy(pointA, pointB) {
+ return pointB.y - pointA.y
+}
+function rad2deg(radians) {
+ return radians * 57.29577951308232
+}
+function angle(pointA, pointB) {
+ let rad = Math.atan2(-1 * dy(pointA, pointB), dx(pointA, pointB))
+ while (rad < 0) rad += 2 * Math.PI
+
+ return rad2deg(rad)
+}
+
+const rectSize = 24
+
+const Button = ({ onClickCb, transform, Icon, children, title = '' }) => {
+ const _onClick = (event) => {
+ event.stopPropagation()
+ onClickCb(event)
+ }
+
+ return (
+
+ {title}
+
+
+
+
+ )
+}
+
+export const ShowButtonsToggle = ({ ui, update }) => {
+ const hideButtons = (evt) => {
+ update.ui('hideMovableButtons', !evt.target.checked)
+ }
+ return (
+
+ )
+}
+
+/** buttons for manipulating the part */
+export const Buttons = ({ transform, flip, rotate, resetPart, rotate90, iconSize }) => {
+ return (
+
+
+ {rotate ? (
+
+ ) : (
+
+ )}
+
+
+ )
+}
diff --git a/packages/react/components/Editor/components/ZoomablePattern.mjs b/packages/react/components/Editor/components/ZoomablePattern.mjs
index 803ac63139a..1f9dadb5238 100644
--- a/packages/react/components/Editor/components/ZoomablePattern.mjs
+++ b/packages/react/components/Editor/components/ZoomablePattern.mjs
@@ -6,7 +6,7 @@ import { Pattern } from '@freesewing/react/components/Pattern'
* A pattern you can pan and zoom
*/
export const ZoomablePattern = forwardRef(function ZoomablePatternRef(props, ref) {
- const { renderProps, rotate } = props
+ const { renderProps, rotate, components = {} } = props
const { onTransformed, setZoomFunctions } = useContext(ZoomContext)
return (
@@ -26,7 +26,7 @@ export const ZoomablePattern = forwardRef(function ZoomablePatternRef(props, ref
>
{props.children || (
diff --git a/packages/react/components/Editor/components/menus/Input.mjs b/packages/react/components/Editor/components/menus/Input.mjs
index eb8980a6087..65beb0c8c95 100644
--- a/packages/react/components/Editor/components/menus/Input.mjs
+++ b/packages/react/components/Editor/components/menus/Input.mjs
@@ -192,6 +192,7 @@ export const MenuMmInput = (props) => {
const imperial = units === 'imperial'
const mmUpdateHandler = useCallback(
(path, newCurrent) => {
+ console.log('mmUpdateHandler', { path, newCurrent })
const calcCurrent =
typeof newCurrent === 'undefined' ? undefined : measurementAsMm(newCurrent, units)
updateHandler(path, calcCurrent)
@@ -199,7 +200,9 @@ export const MenuMmInput = (props) => {
[updateHandler, units]
)
- // add a default step that's appropriate to the unit. can be overwritten by config
+ /*
+ * Set a default step that matches the unit
+ */
const defaultStep = units === 'imperial' ? 0.125 : 0.1
return (
@@ -209,8 +212,8 @@ export const MenuMmInput = (props) => {
config: {
step: defaultStep,
...config,
- min: imperial ? config.min / 25.4 : config.min,
- max: imperial ? config.max / 25.4 : config.min,
+ min: imperial ? config.min / 25.4 : config.min / 10,
+ max: imperial ? config.max / 25.4 : config.max / 10,
dflt: measurementAsUnits(config.dflt, units),
},
current: current === undefined ? undefined : measurementAsUnits(current, units),
@@ -391,7 +394,7 @@ export const MenuEditOption = (props) => {
{type === 'pct' && typeof config.fromAbs === 'function' ? (
,
+
update.state.ui('hideMovableButtons', state.ui.hideMovableButtons ? false : true)}
+ label={
+ {'workbench:partTransfoDesc'}
+ }
+ list={[
+ {
+ val: true,
+ label: 'workbench:partTransfoNo',
+ desc: 'workbench:partTransfoNoDesc',
+ },
+ {
+ val: false,
+ label: 'workbench:partTransfoYes',
+ desc: 'workbench:partTransfoYesDesc',
+ },
+ ]}
+ current={state.ui.hideMovableButtons ? true : false}
+ />,
+ 'partTransfo',
+ ],
+ [
+
+
+
+ {'workbench:resetPrintLayout'}
+
+
+
,
+
+
+ {'workbench:resetPrintLayoutDesc'}
+ update.ui(['layouts', 'print'])}
+ >
+
+ {'workbench:resetPrintLayout'}
+
+ ,
+ 'reset',
+ ],
+ ]}
+ />
+)
+*/
diff --git a/packages/react/components/Editor/components/menus/UiPreferencesMenu.mjs b/packages/react/components/Editor/components/menus/UiPreferencesMenu.mjs
index bc58e355812..52255302d23 100644
--- a/packages/react/components/Editor/components/menus/UiPreferencesMenu.mjs
+++ b/packages/react/components/Editor/components/menus/UiPreferencesMenu.mjs
@@ -13,15 +13,11 @@ export const UiPreferencesMenu = ({ update, state, Design }) => {
const drillProps = { Design, state, update }
const inputs = {
ux: (props) => ,
- //aside: (props) => ,
- //kiosk: (props) => ,
rotate: (props) => ,
renderer: (props) => ,
}
const values = {
ux: (props) => {state.ui.ux}/5,
- //aside: MenuListValue,
- //kiosk: MenuListValue,
rotate: MenuListValue,
renderer: MenuListValue,
}
diff --git a/packages/react/components/Editor/components/views/ExportView.mjs b/packages/react/components/Editor/components/views/ExportView.mjs
index ae789a89dff..54a3c033d7b 100644
--- a/packages/react/components/Editor/components/views/ExportView.mjs
+++ b/packages/react/components/Editor/components/views/ExportView.mjs
@@ -151,9 +151,10 @@ export const ExportView = (props) => {
)
}
-function exportPattern(props) {
- props.setLink(false)
- props.setFormat(props.format)
+export function exportPattern(props) {
+ if (props.setLink) props.setLink(false)
+ if (props.setFormat) props.setFormat(props.format)
+
handleExport({
...props,
onComplete: (e) => (e.data?.link ? props.setLink(e.data.link) : null),
diff --git a/packages/react/components/Editor/components/views/LayoutView.mjs b/packages/react/components/Editor/components/views/LayoutView.mjs
index 6f3f9004729..633c6f04f25 100644
--- a/packages/react/components/Editor/components/views/LayoutView.mjs
+++ b/packages/react/components/Editor/components/views/LayoutView.mjs
@@ -1,142 +1,45 @@
// Dependencies
-import { defaultPrintSettings, printSettingsPath, handleExport } from '../../lib/export/index.mjs'
-import { tilerPlugin } from '../../lib/export/plugin-tiler.mjs'
-import { get } from '@freesewing/utils'
-import { draft } from '../../lib/index.mjs'
import React from 'react'
-//import {
-// handleExport,
-// ns as exportNs,
-//} from 'shared/components/workbench/exporting/export-handler.mjs'
-//import { pagesPlugin } from 'shared/plugins/plugin-layout-part.mjs'
-//import get from 'lodash.get'
-//import { defaultPrintSettings, printSettingsPath } from './config.mjs'
-//// Hooks
-//import { useContext } from 'react'
-//import { useTranslation } from 'next-i18next'
-//// Context
-//import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
+import { defaultPrintSettings, handleExport } from '../../lib/export/index.mjs'
+import { tilerPlugin } from '../../lib/export/plugin-tiler.mjs'
+import { capitalize, get } from '@freesewing/utils'
+import { draft } from '../../lib/index.mjs'
// Components
import { ZoomablePattern } from '../ZoomablePattern.mjs'
import { PatternLayout } from '../PatternLayout.mjs'
-//import { MovablePattern } from 'shared/components/workbench/pattern/movable/index.mjs'
-//import { PrintMenu, ns as menuNs } from './menu.mjs'
-//import { PatternWithMenu, ns as wrapperNs } from '../pattern-with-menu.mjs'
+import { MovablePattern } from '../MovablePattern.mjs'
+import { Accordion } from '../Accordion.mjs'
+import { CompareIcon, PrintIcon } from '@freesewing/react/components/Icon'
+import { MenuBoolInput, MenuMmInput, MenuListInput } from '../menus/Input.mjs'
+import { MenuBoolValue, MenuMmValue, MenuListValue } from '../menus/Value.mjs'
export const LayoutView = (props) => {
- // design,
- // pattern,
- // patternConfig,
- // settings,
- // setSettings,
- // ui,
- // update,
- // language,
- // account,
- // Design,
- //}) => {
-
const { config, state, update, Design } = props
- const defaultSettings = defaultPrintSettings(state.settings?.units)
+ const { ui, settings } = state
+ const defaultSettings = defaultPrintSettings(settings?.units)
// Settings for the tiler plugin
const pageSettings = {
...defaultSettings,
- ...get(state.ui, printSettingsPath, {}),
+ ...get(state.ui, 'layout', {}),
}
/*
* Now draft the pattern
*/
- const { pattern, failure, errors } = draft(Design, state.settings, [tilerPlugin(pageSettings)])
+ const { pattern, failure, errors } = draft(Design, settings, [tilerPlugin(pageSettings)])
if (failure) return Draft failed. FIXME: Handle this gracefully.
- const renderProps = pattern.getRenderProps()
-
- const exportIt = () => {
- update.startLoading('layout', { msg: 'Generating PDF' })
- handleExport({
- format: pageSettings.size,
- settings,
- design,
- t,
- Design,
- ui,
- startLoading: loading.startLoading,
- stopLoading: loading.stopLoading,
- onComplete: () => {
- setLoadingStatus([true, 'pdfReady', true, true])
- },
- onError: (err) => {
- setLoadingStatus([true, 'pdfFailed', true, true])
- console.log(err)
- },
- })
- }
-
const output = (
- //
)
return
-
- return (
- <>
- {t('workbench:printLayout')}
- ),
- pattern: (
-
- ),
- menu: (
-
- ),
- }}
- />
- >
- )
}
diff --git a/packages/react/components/Editor/components/views/index.mjs b/packages/react/components/Editor/components/views/index.mjs
index 2e0849733b1..761219abb0d 100644
--- a/packages/react/components/Editor/components/views/index.mjs
+++ b/packages/react/components/Editor/components/views/index.mjs
@@ -6,7 +6,7 @@ import { DraftView } from './DraftView.mjs'
import { SaveView } from './SaveView.mjs'
import { ExportView } from './ExportView.mjs'
import { UndosView } from './UndosView.mjs'
-//import { LayoutView } from './LayoutView.mjs'
+import { LayoutView } from './LayoutView.mjs'
import { ErrorIcon } from '@freesewing/react/components/Icon'
import {
OptionsIcon,
@@ -58,7 +58,7 @@ export const View = (props) => {
if (view === 'save') return
if (view === 'export') return
if (view === 'undos') return
- //if (view === 'layout') return
+ if (view === 'layout') return
/*
viewComponents: {
draft: 'DraftView',
@@ -109,7 +109,7 @@ export const viewLabels = {
d: 'Shows detailed timing of the pattern being drafted, allowing you to find bottlenecks in performance',
},
layout: {
- t: 'Pattern Layout',
+ t: 'Print Layout',
d: 'Organize your pattern parts to minimize paper use',
},
save: {
diff --git a/packages/react/components/Editor/lib/index.mjs b/packages/react/components/Editor/lib/index.mjs
index 8a7d53172c0..67bfcfcdd56 100644
--- a/packages/react/components/Editor/lib/index.mjs
+++ b/packages/react/components/Editor/lib/index.mjs
@@ -10,6 +10,7 @@ import {
menuCoreSettingsStructure,
} from './core-settings.mjs'
import { findOption, getOptionStructure, menuDesignOptionsStructure } from './design-options.mjs'
+import { menuLayoutSettingsStructure } from './layout-settings.mjs'
import {
addUndoStep,
cloneObject,
@@ -68,6 +69,8 @@ export {
findOption,
getOptionStructure,
menuDesignOptionsStructure,
+ // layout-settings.mjs
+ menuLayoutSettingsStructure,
// editor.mjs
addUndoStep,
cloneObject,
diff --git a/packages/react/components/Editor/lib/layout-settings.mjs b/packages/react/components/Editor/lib/layout-settings.mjs
new file mode 100644
index 00000000000..6c2d1bfa832
--- /dev/null
+++ b/packages/react/components/Editor/lib/layout-settings.mjs
@@ -0,0 +1,122 @@
+import React from 'react'
+import { defaultConfig } from '../config/index.mjs'
+import { linkClasses } from '@freesewing/utils'
+import {
+ CoverPageIcon,
+ MenuIcon,
+ KioskIcon,
+ RotateIcon,
+ RocketIcon,
+ UxIcon,
+ PageMarginIcon,
+ PageOrientationIcon,
+ PageSizeIcon,
+ PatternIcon,
+ ScaleIcon,
+} from '@freesewing/react/components/Icon'
+
+const UiDocsLink = ({ item }) => (
+
+ Learn more
+
+)
+
+const sizes = ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'legal', 'tabloid']
+const defaultPrintSettings = (units) => ({
+ size: units === 'imperial' ? 'letter' : 'a4',
+ orientation: 'portrait',
+ margin: units === 'imperial' ? 12.7 : 10,
+ coverPage: true,
+})
+
+export function menuLayoutSettingsStructure(units) {
+ const defaults = defaultPrintSettings(units)
+ const sizeTitles = {
+ a4: 'A4',
+ a3: 'A3',
+ a2: 'A2',
+ a1: 'A1',
+ a0: 'A0',
+ letter: 'Letter',
+ legal: 'Legal',
+ tabloid: 'Tabloid',
+ }
+
+ return {
+ size: {
+ dense: true,
+ title: 'Paper Size',
+ about: (
+
+ This control the pages overlay that helps you see how your pattern spans the pages. This
+ does not limit your export options, you can still export in a variety of paper sizes.
+
+ ),
+ ux: 1,
+ list: Object.keys(sizeTitles),
+ choiceTitles: sizeTitles,
+ valueTitles: sizeTitles,
+ dflt: defaults.size,
+ icon: PageSizeIcon,
+ },
+ orientation: {
+ dense: true,
+ title: 'Page Orientation',
+ about: (
+ Landscape or Portrait. Try both to see which yields the least amount of pages.
+ ),
+ ux: 1,
+ list: ['portrait', 'landscape'],
+ choiceTitles: {
+ portrait: (
+
+ ),
+ landscape: (
+
+ ),
+ },
+ icon: PageOrientationIcon,
+ },
+ margin: {
+ dense: true,
+ title: 'Page Margin',
+ min: units === 'imperial' ? 2.5 : 5,
+ max: 25,
+ dflt: defaults.margin,
+ icon: PageMarginIcon,
+ ux: 1,
+ },
+ coverPage: {
+ dense: true,
+ ux: 1,
+ icon: CoverPageIcon,
+ title: 'Cover Page',
+ about:
+ 'The cover page includes information about the pattern and an overview of how to assemble the pages.',
+ list: [0, 1],
+ choiceTitles: {
+ 0: 'Do not include a cover page',
+ 1: 'Include a cover page',
+ },
+ dflt: 0,
+ },
+ iconSize: {
+ dense: true,
+ ux: 1,
+ icon: ScaleIcon,
+ title: 'Icon Size',
+ about:
+ 'Controls the size of the icons that allow you to rotate/flip individual pattern parts',
+ min: 10,
+ dflt: 0.5,
+ step: 1,
+ max: 200,
+ },
+ }
+}
diff --git a/packages/react/components/Icon/index.mjs b/packages/react/components/Icon/index.mjs
index c15e838b676..ed8ee1abe95 100644
--- a/packages/react/components/Icon/index.mjs
+++ b/packages/react/components/Icon/index.mjs
@@ -1,6 +1,10 @@
import React from 'react'
import { logoPath } from '@freesewing/config'
+// Used in several icons
+const page =
+ 'M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z'
+
/*
* Used inside the pattern editor
*/
@@ -153,6 +157,16 @@ export const CopyIcon = (props) => (
)
+// Looks like a page with a smiley on it
+export const CoverPageIcon = (props) => (
+
+
+
+
+
+
+)
+
// Looks like a museum building
export const CuratedMeasurementsSetIcon = (props) => (
@@ -268,6 +282,13 @@ export const FlagIcon = (props) => (
)
+// Looks lik a flag
+export const FlipIcon = (props) => (
+
+
+
+)
+
// Looks like skully
export const FreeSewingIcon = (props) => (
@@ -452,6 +473,36 @@ export const OptionsIcon = (props) => (
)
+// Looks like a page with a margin drawn around
+export const PageMarginIcon = (props) => (
+
+
+
+
+)
+
+// Looks like a portrait and landscape page stacked
+export const PageOrientationIcon = (props) => (
+
+
+
+
+)
+
+// Looks like two differently sizes pages stacked
+export const PageSizeIcon = (props) => (
+
+
+
+
+)
+
// Looks like a grid
export const PaperlessIcon = (props) => (
@@ -466,7 +517,7 @@ export const PaperlessIcon = (props) => (
// Looks like a page
export const PatternIcon = (props) => (
-
+
)
@@ -536,7 +587,12 @@ export const RocketIcon = (props) => (
// Looks like two arrows in a circular layout
export const RotateIcon = (props) => (
-
+
)
diff --git a/sites/org/src/css/patterns.css b/sites/org/src/css/patterns.css
index 931a1cad5b3..9d348507542 100644
--- a/sites/org/src/css/patterns.css
+++ b/sites/org/src/css/patterns.css
@@ -278,6 +278,44 @@ svg.freesewing.pattern .muted {
opacity: 0.15;
}
+/* layout rectangles */
+svg.freesewing.pattern .layout-rect {
+ fill: var(--pattern-canvas);
+ fill-opacity: 0.05;
+}
+svg.freesewing.pattern .layout-rect:hover {
+ fill: var(--pattern-lining);
+ fill-opacity: 0.15;
+}
+svg.freesewing.pattern .layout-rect.move:hover {
+ cursor: move;
+}
+svg.freesewing.pattern .layout-rect.rotate:hover {
+ cursor: crosshair;
+}
+svg.freesewing.pattern .svg-layout-button {
+ fill: var(--pattern-note);
+ fill-opacity: 0;
+ stroke: none;
+}
+svg.freesewing.pattern .svg-layout-button:hover {
+ fill: var(--pattern-note);
+ fill-opacity: 1;
+ stroke: none;
+ cursor: pointer;
+}
+svg.freesewing.pattern .svg-layout-button path {
+ stroke-width: calc(var(--pattern-stroke) * 2 * var(--pattern-scale));
+ color: var(--pattern-contrast);
+}
+svg.freesewing.pattern .svg-layout-button:hover path {
+ stroke: #fff;
+}
+svg.freesewing.pattern .svg-layout-button:hover > rect.button {
+ fill: var(--pattern-contrast);
+ stroke: none;
+}
+
/* Developer view */
g.develop.point {
circle.center {