// Dependencies import { about, collection, tags, techniques, examples, requiredMeasurements, optionalMeasurements, } from '@freesewing/collection' import { capitalize, linkClasses, mutateObject } from '@freesewing/utils' import { measurements as measurementsTranslations } from '@freesewing/i18n' // Hooks import React, { useState, Fragment } from 'react' import { useFilter } from '@freesewing/react/hooks/useFilter' // Components import { Link as WebLink } from '@freesewing/react/components/Link' import { CircleIcon, CisFemaleIcon, DocsIcon, FilterIcon, NewPatternIcon, ResetIcon, ShowcaseIcon, } from '@freesewing/react/components/Icon' import { lineDrawingsFront as lineDrawings, lineDrawingsBack, } from '@freesewing/react/components/LineDrawing' import { IconButton } from '@freesewing/react/components/Button' import { KeyVal } from '@freesewing/react/components/KeyVal' import { MissingLinedrawing } from '../LineDrawing/missing.mjs' /** * A component to show the FreeSewing collection and pick a design. * * @component * @param {object} props - All component props * @param {React.Component} [props.Link = false] - A framework specific Link component for client-side routing * @param {boolean} [props.editor = false] - Set this to true when rendering inside the FreeSewing editor * @param {string} [props.linkTo = 'about'] - This controls where to link the design to. One of 'new', 'docs', or 'about'. * @param {functino} [props.onClick = false] - You can pass in an onClick handler rather than using links * @returns {JSX.Element} */ export const Collection = ({ Link = false, linkTo = 'about', editor = false, onClick = false }) => { if (!Link) Link = WebLink // State const [filter, setFilter] = useFilter() const [showFilters, setShowFilters] = useState(false) /* * Apply filter */ const filtered = {} for (const d of collection) { let skip = false if ( filter.tag && filter.tag.filter((tag) => about[d].tags.includes(tag)).length < filter.tag.length ) skip = true if ( filter.tech && filter.tech.filter((tech) => about[d].techniques.includes(tech)).length < filter.tech.length ) skip = true if (filter.difficulty && filter.difficulty !== about[d].difficulty) skip = true if (!skip) filtered[d] = d } const updateFilter = (path, val) => { // Allow clicking the same difficulty to remove it as a filter if (path === 'difficulty' && val === filter.difficulty) val = 'unset' const newFilter = mutateObject({ ...filter }, path, val) setFilter(newFilter) } const toggle = (type, val) => { const current = filter[type] || [] const newSet = new Set(current) if (newSet.has(val)) newSet.delete(val) else newSet.add(val) updateFilter(type, [...newSet]) } return ( <>
{Object.keys(filtered) .sort() .map((d) => onClick ? ( ) : ( {d} ) )}
{showFilters ? ( <>
Filtered Designs ({Object.keys(filtered).length}/{collection.length})
Tags: {tags.map((tag) => ( ))}
Techniques {techniques.sort().map((tech) => ( ))}
Difficulty: {[1, 2, 3, 4, 5].map((score) => ( ))}
) : (
)}
{Object.keys(filtered) .sort() .map((d) => ( ))}
) } const DesignCard = ({ name, lineDrawing = false, linkTo, Link, onClick }) => { if (!Link) Link = WebLink const LineDrawing = lineDrawing && lineDrawings[name] ? lineDrawings[name] : MissingLinedrawing const exampleImageUrl = examples.href[name] ? examples.href[name] : noExample const bg = { aspectRatio: '1/1.4' } if (!lineDrawing) { bg.backgroundImage = `url(${exampleImageUrl})` bg.backgroundSize = 'cover' bg.backgroundPosition = 'center center' } const inner = (
{about[name].name}
{lineDrawing ? (
) : ( )}
) return onClick ? ( ) : ( {inner} ) } /* * A helper component to show difficulety of a design * * @param {object} props - All React props * @param {number} props.score - The difficulty score of the design (1-5) */ const Difficulty = ({ score = 0, className = '' }) => (
{[0, 1, 2, 3, 4].map((i) => ( ))}
) const linkBuilders = { new: (design) => `/editor/#s={%22design%22%3A%22${design.toLowerCase()}%22%2C%22view%22%3A%22draft%22}`, docs: (design) => `/docs/designs/${design.toLowerCase()}/`, about: (design) => `/designs/${design.toLowerCase()}/`, } const noExample = 'https://images.pexels.com/photos/5626595/pexels-photo-5626595.jpeg?cs=srgb&fm=jpg&w=640&h=427' /** * A component to show info about a FreeSewing design * * @component * @param {object} props - All component props * @param {React.Component} props.Link - A framework specific Link component for client-side routing * @param {string} props.design - The name/id of the design * @param {boolean} props.noDocsLink - Set this to true to not render a link to the documentation * @returns {JSX.Element} */ export const DesignInfo = ({ Link = false, design = false, noDocsLink = false }) => { if (!Link) Link = WebLink // State const [back, setBack] = useState(false) if (!design) return null // Line drawings const LineDrawing = lineDrawings[design] || MissingLinedrawing const LineDrawingBack = lineDrawingsBack[design] || null // Make sure these always hold arrays, that way we can just map() over them in the JSX output const codeBy = Array.isArray(about[design].code) ? about[design].code : [about[design].code] const designBy = Array.isArray(about[design].design) ? about[design].design : [about[design].design] const tags = about[design].tags || [] const techniques = about[design].techniques || [] const makeButton = (
New {capitalize(design)} pattern
) const buttons = noDocsLink ? ( makeButton ) : (
Documentation {makeButton}
) return ( <>
{buttons}
{back ? : }
{LineDrawingBack ? ( ) : null}
Description
{about[design].description}
By
{codeBy.map((code) => ( ))} {designBy.map((code) => ( ))}
Difficulty
{optionalMeasurements[design].length > 0 ? ( <>
Optional Measurements
{optionalMeasurements[design].map((m, i) => ( {measurementsTranslations[m]} {i < optionalMeasurements[design].length - 1 ? , : null} ))}
) : null} {requiredMeasurements[design].length > 0 ? ( <>
Required Measurements
{requiredMeasurements[design].map((m, i) => ( {measurementsTranslations[m]} {i < requiredMeasurements[design].length - 1 ? , : null} ))}
) : null}
Tags
{tags.map((tag) => ( {tag} ))}
Techniques
{techniques.map((tech) => ( {tech} ))}
Examples
Documentation
Designer Notes, What You Need, Fabric Options, Cutting Instructions, Design Options, Sewing Instructions
{buttons}
) }