wip(shared): Working on custom layout
This commit is contained in:
parent
f4ee97a626
commit
34c8a6b2a5
13 changed files with 357 additions and 0 deletions
7
packages/freesewing.shared/components/icons/page-size.js
Normal file
7
packages/freesewing.shared/components/icons/page-size.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const PageSizeIcon = props => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default PageSizeIcon
|
7
packages/freesewing.shared/components/icons/page.js
Normal file
7
packages/freesewing.shared/components/icons/page.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const PageIcon = props => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default PageIcon
|
|
@ -0,0 +1,21 @@
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import Settings from './settings'
|
||||
|
||||
const CutLayout = props => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="capitalize">
|
||||
{
|
||||
t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': '
|
||||
+ t('forCutting')
|
||||
}
|
||||
</h2>
|
||||
<Settings {...props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CutLayout
|
|
@ -0,0 +1,10 @@
|
|||
const CutLayoutSettings = props => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Fixme: Cut layout settings here</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CutLayoutSettings
|
|
@ -0,0 +1,33 @@
|
|||
import Svg from '../draft/svg'
|
||||
import Defs from '../draft/defs'
|
||||
import Part from '../draft/part'
|
||||
|
||||
const Draft = props => {
|
||||
const { patternProps, gist, app, updateGist, unsetGist, bgProps={} } = props
|
||||
|
||||
return (
|
||||
<div className="my-8 w-11/12 m-auto">
|
||||
<Svg {...patternProps} embed={gist.embed}>
|
||||
<Defs {...patternProps} />
|
||||
<style>{`:root { --pattern-scale: ${gist.scale || 1}}`}</style>
|
||||
<g>
|
||||
<rect x="0" y="0" width={patternProps.width} height={patternProps.height} {...bgProps} />
|
||||
{Object.keys(patternProps.parts).map((name) => (
|
||||
<Part
|
||||
key={name}
|
||||
partName={name}
|
||||
part={patternProps.parts[name]}
|
||||
app={app}
|
||||
gist={gist}
|
||||
updateGist={updateGist}
|
||||
unsetGist={unsetGist}
|
||||
/>
|
||||
))}
|
||||
</g>
|
||||
</Svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Draft
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import Settings from './settings'
|
||||
import Draft from '../draft'
|
||||
import pluginBuilder from './plugin'
|
||||
|
||||
const addPages = (gist) => {
|
||||
const pages = []
|
||||
}
|
||||
|
||||
|
||||
const PrintLayout = props => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
||||
const draft = new props.pattern(props.gist).use(pluginBuilder(
|
||||
props.gist?._state?.layout?.forPrinting?.page?.size,
|
||||
props.gist?._state?.layout?.forPrinting?.page?.orientation,
|
||||
))
|
||||
let patternProps
|
||||
try {
|
||||
draft.draft()
|
||||
patternProps = draft.getRenderProps()
|
||||
} catch(err) {
|
||||
console.log(err)
|
||||
}
|
||||
const bgProps = { fill: "url(#page)" }
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="capitalize">
|
||||
{
|
||||
t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': '
|
||||
+ t('forPrinting')
|
||||
}
|
||||
</h2>
|
||||
<div className="m-4">
|
||||
<Settings {...props} />
|
||||
</div>
|
||||
<Draft
|
||||
draft={draft}
|
||||
gist={props.gist}
|
||||
patternProps={patternProps}
|
||||
bgProps={bgProps}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PrintLayout
|
|
@ -0,0 +1,29 @@
|
|||
import PageIcon from 'shared/components/icons/page'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
const PageOrientationPicker = ({ gist, updateGist }) => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
|
||||
return (
|
||||
<button className={`
|
||||
btn btn-primary flex flex-row gap-2 items-center
|
||||
hover:text-primary-content
|
||||
`}
|
||||
onClick={() => updateGist(
|
||||
['_state', 'layout', 'forPrinting', 'page', 'orientation'],
|
||||
gist._state?.layout?.forPrinting?.page?.orientation === 'portrait'
|
||||
? 'landscape'
|
||||
: 'portrait'
|
||||
)}
|
||||
>
|
||||
<span className={
|
||||
gist._state?.layout?.forPrinting?.page?.orientation === 'landscape'
|
||||
? 'rotate-90'
|
||||
: ''
|
||||
}><PageIcon /></span>
|
||||
<span>{t(`pageOrientation`)}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageOrientationPicker
|
|
@ -0,0 +1,78 @@
|
|||
import PageSizeIcon from 'shared/components/icons/page-size'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Popout from 'shared/components/popout'
|
||||
|
||||
|
||||
const sizes = ['a4', 'a3', 'a2', 'a1', 'a0', 'letter', 'tabloid']
|
||||
|
||||
|
||||
const PageSizePicker = ({ gist, updateGist }) => {
|
||||
const { t } = useTranslation(['workbench'])
|
||||
const setSize = size => {
|
||||
updateGist(
|
||||
['_state', 'layout', 'forPrinting', 'page', 'size'],
|
||||
size
|
||||
)
|
||||
if (!gist._state?.layout?.forPrinting?.page?.orientation) {
|
||||
updateGist(
|
||||
['_state', 'layout', 'forPrinting', 'page', 'orientation'],
|
||||
'portrait'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!gist._state?.layout?.forPrinting?.page?.size ||
|
||||
sizes.indexOf(gist._state.layout.forPrinting.page.size) === -1
|
||||
) return (
|
||||
<Popout tip>
|
||||
<h3>{t('startBySelectingAThing', { thing: t('pageSize')})}</h3>
|
||||
<div className="flex flex-row gap-4">
|
||||
{sizes.map(size => (
|
||||
<button
|
||||
key={size}
|
||||
onClick={() => setSize(size)}
|
||||
className="btn btn-primary"
|
||||
>
|
||||
<span className="capitalize">
|
||||
{size}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</Popout>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={`dropdown`}>
|
||||
<div tabIndex="0" className={`
|
||||
m-0 btn btn-primary flex flex-row gap-2
|
||||
hover:text-primary-content
|
||||
|
||||
`}>
|
||||
<PageSizeIcon />
|
||||
<span>{t(`pageSize`)}:</span>
|
||||
<span className="ml-2 font-bold">{gist._state.layout.forPrinting.page.size}</span>
|
||||
</div>
|
||||
<ul
|
||||
tabIndex="0"
|
||||
className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52"
|
||||
>
|
||||
{sizes.map(size => (
|
||||
<li key={size}>
|
||||
<button
|
||||
onClick={() => setSize(size)}
|
||||
className="btn btn-ghost hover:bg-base-200"
|
||||
>
|
||||
<span className="text-base-content capitalize">
|
||||
{size}
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageSizePicker
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
const name = 'Pages Plugin'
|
||||
const version = '1.0.0'
|
||||
const sizes = {
|
||||
a4: [ 210, 297 ],
|
||||
a3: [ 297, 420 ],
|
||||
a2: [ 420, 594 ],
|
||||
a1: [ 594, 841 ],
|
||||
a0: [ 841, 1188 ],
|
||||
letter: [ 215.9, 279.4 ],
|
||||
tabloid: [ 279.4, 431.8 ],
|
||||
}
|
||||
|
||||
const drawPage = (x, y, size, orientation) => {
|
||||
//
|
||||
}
|
||||
|
||||
const pagesPlugin = (size='a4', orientation='portrait') => ({
|
||||
name,
|
||||
version,
|
||||
hooks: {
|
||||
postLayout: function(pattern) {
|
||||
// Add part
|
||||
pattern.parts.pages = pattern.Part('pages')
|
||||
// Keep part out of layout
|
||||
pattern.parts.pages.layout = false
|
||||
// Add pages
|
||||
const { macro } = pattern.parts.pages.shorthand()
|
||||
const { height, width } = pattern
|
||||
macro('addPages', { size, orientation, height, width })
|
||||
}
|
||||
},
|
||||
macros: {
|
||||
addPages: function(so) {
|
||||
const ls = so.orientation === 'landscape'
|
||||
const w = sizes[so.size][ls ? 1 : 0]
|
||||
const h = sizes[so.size][ls ? 0 : 1]
|
||||
const cols = Math.ceil(so.width / w)
|
||||
const rows = Math.ceil(so.height / h)
|
||||
const { points, Point, paths, Path } = this.shorthand()
|
||||
let x = 0
|
||||
let y = 0
|
||||
let count = 0
|
||||
for (let row=0;row<rows;row++) {
|
||||
x=0
|
||||
for (let col=0;col<cols;col++) {
|
||||
count++
|
||||
points[`_pages__row${row}-col${col}-tl`] = new Point(x,y)
|
||||
points[`_pages__row${row}-col${col}-tr`] = new Point(x+w,y)
|
||||
points[`_pages__row${row}-col${col}-br`] = new Point(x+w,y+h)
|
||||
points[`_pages__row${row}-col${col}-bl`] = new Point(x,y+h)
|
||||
points[`_pages__row${row}-col${col}-circle`] = new Point(x+w/2,y+h/2-24)
|
||||
.attr('data-circle', 42)
|
||||
.attr('data-circle-class', 'stroke-4xl muted')
|
||||
points[`_pages__row${row}-col${col}-text`] = new Point(x+w/2,y+h/2)
|
||||
.attr('data-text', `${count}`)
|
||||
.attr('data-text-class', 'text-4xl center bold muted')
|
||||
|
||||
paths[`_pages__row${row}-col${col}`] = new Path()
|
||||
.move(points[`_pages__row${row}-col${col}-tl`])
|
||||
.line(points[`_pages__row${row}-col${col}-bl`])
|
||||
.line(points[`_pages__row${row}-col${col}-br`])
|
||||
.line(points[`_pages__row${row}-col${col}-tr`])
|
||||
.close()
|
||||
.attr('class', 'fill-fabric')
|
||||
.attr('style', `stroke-opacity: 0; fill-opacity: ${(col+row)%2===0 ? 0.03 : 0.09};`)
|
||||
x += w
|
||||
}
|
||||
y += h
|
||||
}
|
||||
this.pages = { cols, rows, count: (cols+1)*(rows+1) }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default pagesPlugin
|
|
@ -0,0 +1,20 @@
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import PageSizePicker from './pagesize-picker'
|
||||
import OrientationPicker from './orientation-picker'
|
||||
|
||||
const PrintLayoutSettings = props => {
|
||||
const settingsProps = {
|
||||
gist: props.gist,
|
||||
updateGist: props.updateGist
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-row gap-4 justify-center">
|
||||
<PageSizePicker {...props} />
|
||||
<OrientationPicker {...props} />
|
||||
<pre>{JSON.stringify(props.gist._state, null ,2)}</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PrintLayoutSettings
|
|
@ -20,8 +20,21 @@ const View = props => {
|
|||
title: t('testPattern', { pattern: props.pattern.config.name }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'test')
|
||||
},
|
||||
{
|
||||
name: 'printingLayout',
|
||||
title: t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': ' + t('forPrinting'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'printingLayout')
|
||||
},
|
||||
{
|
||||
name: 'cuttingLayout',
|
||||
title: t('layoutThing', { thing: props.pattern.config.name })
|
||||
+ ': ' + t('forCutting'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'cuttingLayout')
|
||||
},
|
||||
{
|
||||
name: 'export',
|
||||
title: t('exportThing', { thing: props.pattern.config.name }),
|
||||
title: t('export'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'export')
|
||||
},
|
||||
|
@ -40,6 +53,11 @@ const View = props => {
|
|||
title: t('JSON'),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'json')
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
title: t('editThing', { thing: 'YAML' }),
|
||||
onClick: () => props.updateGist(['_state', 'view'], 'edit')
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
|
|
|
@ -16,11 +16,15 @@ import ExportDraft from 'shared/components/workbench/export.js'
|
|||
import GistAsJson from 'shared/components/workbench/json.js'
|
||||
import GistAsYaml from 'shared/components/workbench/yaml.js'
|
||||
import DraftEvents from 'shared/components/workbench/events.js'
|
||||
import CutLayout from 'shared/components/workbench/layout/cut'
|
||||
import PrintLayout from 'shared/components/workbench/layout/print'
|
||||
|
||||
const views = {
|
||||
measurements: Measurements,
|
||||
draft: LabDraft,
|
||||
test: LabSample,
|
||||
printingLayout: PrintLayout,
|
||||
cuttingLayout: CutLayout,
|
||||
export: ExportDraft,
|
||||
events: DraftEvents,
|
||||
yaml: GistAsYaml,
|
||||
|
|
|
@ -57,6 +57,11 @@ svg.freesewing.pattern {
|
|||
.center { text-anchor: middle; }
|
||||
.right { text-anchor: end; }
|
||||
|
||||
/* muted page numbers */
|
||||
.muted {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
/* Developer view */
|
||||
g.develop.point {
|
||||
circle.center {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue