1
0
Fork 0

🚧 More work on React components

This commit is contained in:
Joost De Cock 2019-04-25 08:03:20 +02:00
parent a1400bd159
commit a50aa4d17f
13 changed files with 368 additions and 39 deletions

View file

@ -0,0 +1,142 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import { gistDefaults } from "../utils";
import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage } from "react-intl";
import List from "@material-ui/core/List";
import ListSubheader from "@material-ui/core/ListSubheader";
import CollapsedIcon from "@material-ui/icons/ArrowDropDown";
import ExpandedIcon from "@material-ui/icons/ArrowRight";
import DraftSettingSa from "../DraftSettingSa";
import DraftSettingMargin from "../DraftSettingMargin";
import DraftSettingComplete from "../DraftSettingComplete";
import DraftSettingPaperless from "../DraftSettingPaperless";
import DraftSettingUnits from "../DraftSettingUnits";
import DraftSettingLanguage from "../DraftSettingLanguage";
import DraftSettingOnly from "../DraftSettingOnly";
const DraftSettings = props => {
const [expanded, setExpanded] = useState([]);
const toggleGroup = group => {
let shown = expanded.slice(0);
let index = shown.indexOf(group);
if (index === -1) shown.push(group);
else shown.splice(index, 1);
setExpanded(shown);
};
let pattern = patternInfo[props.pattern];
let dflts = gistDefaults(pattern.config, props.gist);
let noyes = [
<FormattedMessage id="app.no" />,
<FormattedMessage id="app.yes" />
];
let units = {
metric: <FormattedMessage id="app.metricUnits" />,
imperial: <FormattedMessage id="app.imperialUnits" />
};
const addProps = setting => {
const labels = {
sa: {
none: <FormattedMessage id="app.noSeamAllowance" />,
dflt: <FormattedMessage id="app.standardSeamAllowance" />,
custom: <FormattedMessage id="app.customSeamAllowance" />
},
only: {
dflt: <FormattedMessage id="app.default" />,
custom: <FormattedMessage id="app.custom" />
},
paperless: noyes,
complete: noyes
};
let childProps = {
triggerAction: props.triggerAction,
updateValue: props.updateValue,
units: props.units,
key: setting,
name: setting,
labels: labels[setting]
};
childProps.title = (
<FormattedMessage id={"settings." + setting + ".title"} />
);
childProps.desc = (
<FormattedMessage id={"settings." + setting + ".description"} />
);
if (setting === "only") {
childProps.dflt = "dflt";
childProps.customDflt = [];
childProps.parts = {};
for (let part of pattern.parts)
childProps.parts[part] = <FormattedMessage id={"parts." + part} />;
}
return childProps;
};
let groups = {
preferences: [
<DraftSettingSa {...addProps("sa")} />,
<DraftSettingPaperless {...addProps("paperless")} dflt={false} />,
<DraftSettingComplete {...addProps("complete")} dflt={true} />
],
advanced: [
<DraftSettingOnly {...addProps("only")} />,
<DraftSettingMargin {...addProps("margin")} dflt={2} />,
<DraftSettingUnits
{...addProps("units")}
dflt={props.units}
list={units}
/>,
<DraftSettingLanguage
{...addProps("locale")}
dflt={props.language}
languages={props.languages}
/>
]
};
return (
<List subheader={<h3 />} className="draft-settings gist-side">
{Object.keys(groups).map(group => {
let open = true;
if (expanded.indexOf(group) === -1) open = false;
return (
<React.Fragment key={group + "-ghead"}>
<ListSubheader
className="optiongroup-heading"
className={
(open ? "expanded" : "collapsed") + " optiongroup-heading"
}
onClick={() => toggleGroup(group)}
>
<h3>
{open ? (
<CollapsedIcon className="collapse-icon" />
) : (
<ExpandedIcon className="collapse-icon" />
)}
<FormattedMessage id={"optiongroups." + group} />
</h3>
</ListSubheader>
{expanded.indexOf(group) === -1
? null
: groups[group].map(component => component)}
</React.Fragment>
);
})}
</List>
);
};
DraftSettings.propTypes = {
pattern: PropTypes.oneOf(patternList),
units: PropTypes.oneOf(["metric", "imperial"]).isRequired
};
DraftSettings.defaultProps = {};
export default DraftSettings;

View file

@ -0,0 +1,31 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import DraftSettings from ".";
const props = {
triggerAction: (type, data) =>
console.log(`Action of type ${type} triggered, data passed is`, data),
updateValue: (type, data) =>
console.log(`Update ${type} with new value`, data),
gist: {
settings: {
options: {}
}
},
languages: {
de: "German",
en: "English",
es: "Spanish",
fr: "French",
nl: "Dutch"
},
language: "en"
};
storiesOf("DraftSettings", module)
.add("Simon metric", () => (
<DraftSettings pattern="simon" gist={false} units="metric" {...props} />
))
.add("Trayvon imperial", () => (
<DraftSettings pattern="trayvon" gist={false} units="imperial" {...props} />
));

View file

@ -5,19 +5,36 @@ import Deg from "../PatternOptionDegree";
import Mm from "../PatternOptionMillimeter";
import Bool from "../PatternOptionBool";
import OptionGroup from "../OptionGroup";
import { optionType, defaultGist, gistDefaults } from "../utils";
import { optionType, gistDefaults } from "../utils";
import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage } from "react-intl";
import { FormattedMessage, injectIntl } from "react-intl";
import { i18n as languages } from "@freesewing/i18n";
import List from "@material-ui/core/List";
import ListSubheader from "@material-ui/core/ListSubheader";
import CollapsedIcon from "@material-ui/icons/ArrowDropDown";
import ExpandedIcon from "@material-ui/icons/ArrowRight";
import PatternOptions from "../PatternOptions";
import DraftSettings from "../DraftSettings";
const GistConfigurator = props => {
const [gist, setGist] = useState(props.gist || defaultGist);
console.log(languages);
const [gist, setGist] = useState(props.gist);
const [expanded, setExpanded] = useState([]);
const update = (type, name, value) => {
console.log("updating", type, name, value);
};
const toggleGroup = group => {
let shown = expanded.slice(0);
let index = shown.indexOf(group);
if (index === -1) shown.push(group);
else shown.splice(index, 1);
setExpanded(shown);
};
let pattern = patternInfo[props.pattern];
let dflts = gistDefaults(pattern.config, gist);
let dflts = gistDefaults(pattern.config, props.gist);
return (
<div className="gist-config">
@ -25,25 +42,23 @@ const GistConfigurator = props => {
<h2>
<FormattedMessage id="app.patternOptions" />
</h2>
{Object.keys(pattern.optionGroups).map(group => (
<React.Fragment key={group}>
<h3 key={group + "-title"}>
<FormattedMessage id={"optiongroups." + group} />
</h3>
<OptionGroup
key={group + "-group"}
<PatternOptions
pattern={props.pattern}
units={props.units}
pattern={pattern}
dflts={dflts}
options={pattern.optionGroups[group]}
updateValue={update}
triggerAction={props.triggerAction}
/>
</React.Fragment>
))}
<h2>
<FormattedMessage id="app.draftSettings" />
</h2>
<DraftSettings
pattern={props.pattern}
units={props.units}
updateValue={update}
triggerAction={props.triggerAction}
language={props.intl.locale}
languages={languages[props.intl.locale]}
/>
</div>
</div>
);
@ -56,4 +71,4 @@ GistConfigurator.propTypes = {
GistConfigurator.defaultProps = {};
export default GistConfigurator;
export default injectIntl(GistConfigurator);

View file

@ -6,13 +6,20 @@ import GistConfigurator from ".";
const props = {
triggerAction: (type, data) =>
console.log(`Action of type ${type} triggered, data passed is`, data)
console.log(`Action of type ${type} triggered, data passed is`, data),
updateValue: (type, data) =>
console.log(`Update ${type} with new value`, data),
gist: {
settings: {
options: {}
}
}
};
storiesOf("GistConfigurator", module)
.add("Simon metric", () => (
<GistConfigurator pattern="simon" gist={false} units="metric" />
<GistConfigurator pattern="simon" {...props} units="metric" />
))
.add("Trayvon imperial", () => (
<GistConfigurator pattern="trayvon" gist={false} units="imperial" />
<GistConfigurator pattern="trayvon" {...props} units="imperial" />
));

View file

@ -9,6 +9,8 @@ import Count from "../PatternOptionCount";
import { optionType } from "../utils";
import { FormattedMessage } from "react-intl";
import { injectIntl } from "react-intl";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
const OptionGroup = props => {
const update = (name, value) => props.updateValue("option", name, value);
@ -26,33 +28,31 @@ const OptionGroup = props => {
title: <FormattedMessage id={stringKey + "title"} />,
desc: <FormattedMessage id={stringKey + "description"} />,
intl: props.intl,
pattern: props.pattern.config.name
pattern: props.pattern.config.name,
key: name
};
let noyes = [
<FormattedMessage id="app.no" />,
<FormattedMessage id="app.yes" />
];
switch (type) {
case "pct":
return <Pct {...option} {...extraProps} key={name} />;
return <Pct {...option} {...extraProps} />;
break;
case "deg":
return <Deg {...option} {...extraProps} key={name} />;
return <Deg {...option} {...extraProps} />;
break;
case "mm":
return (
<Mm {...option} {...extraProps} key={name} units={props.units} />
);
return <Mm {...option} {...extraProps} units={props.units} />;
break;
case "bool":
return <Bool {...option} {...extraProps} key={name} labels={noyes} />;
return <Bool {...option} {...extraProps} labels={noyes} />;
break;
case "list":
return <List {...option} {...extraProps} key={name} />;
return <List {...option} {...extraProps} />;
break;
case "count":
return <Count {...option} {...extraProps} key={name} />;
return <Count {...option} {...extraProps} />;
break;
default:
throw new Error("Unsupport option type: " + type);
@ -62,8 +62,10 @@ const OptionGroup = props => {
return (
<div className="optiongroup">
{props.options.map(name => {
let key = name;
let output = [];
if (typeof name === "object") {
key = Object.keys(name).pop();
// Subgroup
for (let subGroup of Object.keys(name)) {
output.push(
@ -76,7 +78,11 @@ const OptionGroup = props => {
}
} else output.push(renderOption(name));
return output;
return (
<ListItem key={`lki-${key}`}>
<ListItemText>{output}</ListItemText>
</ListItem>
);
})}
</div>
);

View file

@ -0,0 +1,78 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import Pct from "../PatternOptionPercentage";
import Deg from "../PatternOptionDegree";
import Mm from "../PatternOptionMillimeter";
import Bool from "../PatternOptionBool";
import OptionGroup from "../OptionGroup";
import { optionType, defaultGist, gistDefaults } from "../utils";
import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage } from "react-intl";
import List from "@material-ui/core/List";
import ListSubheader from "@material-ui/core/ListSubheader";
import CollapsedIcon from "@material-ui/icons/ArrowDropDown";
import ExpandedIcon from "@material-ui/icons/ArrowRight";
const PatternOptions = props => {
const [expanded, setExpanded] = useState([]);
const toggleGroup = group => {
let shown = expanded.slice(0);
let index = shown.indexOf(group);
if (index === -1) shown.push(group);
else shown.splice(index, 1);
setExpanded(shown);
};
let pattern = patternInfo[props.pattern];
let dflts = gistDefaults(pattern.config, props.gist);
return (
<List subheader={<h3 />} className="pattern-options gist-side">
{Object.keys(pattern.optionGroups).map(group => {
let open = true;
if (expanded.indexOf(group) === -1) open = false;
return (
<React.Fragment key={group + "-ghead"}>
<ListSubheader
className="optiongroup-heading"
className={
(open ? "expanded" : "collapsed") + " optiongroup-heading"
}
onClick={() => toggleGroup(group)}
>
<h3>
{open ? (
<CollapsedIcon className="collapse-icon" />
) : (
<ExpandedIcon className="collapse-icon" />
)}
<FormattedMessage id={"optiongroups." + group} />
</h3>
</ListSubheader>
{expanded.indexOf(group) === -1 ? null : (
<OptionGroup
key={group + "-group"}
units={props.units}
pattern={pattern}
dflts={dflts}
options={pattern.optionGroups[group]}
updateValue={props.updateValue}
triggerAction={props.triggerAction}
/>
)}
</React.Fragment>
);
})}
</List>
);
};
PatternOptions.propTypes = {
pattern: PropTypes.oneOf(patternList),
units: PropTypes.oneOf(["metric", "imperial"]).isRequired
};
PatternOptions.defaultProps = {};
export default PatternOptions;

View file

@ -0,0 +1,28 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import PatternOptions from ".";
const props = {
triggerAction: (type, data) =>
console.log(`Action of type ${type} triggered, data passed is`, data),
updateValue: (type, data) =>
console.log(`Update ${type} with new value`, data),
gist: {
settings: {
options: {}
}
}
};
storiesOf("PatternOptions", module)
.add("Simon metric", () => (
<PatternOptions pattern="simon" gist={false} units="metric" {...props} />
))
.add("Trayvon imperial", () => (
<PatternOptions
pattern="trayvon"
gist={false}
units="imperial"
{...props}
/>
));

View file

@ -122,7 +122,7 @@ export const defaultGist = {
}
};
export const gistDefaults = (config, gist) => {
export const gistDefaults = (config, gist = { settings: {} }) => {
let options = {};
for (let option of Object.keys(config.options)) {
if (
@ -137,7 +137,7 @@ export const gistDefaults = (config, gist) => {
delete settings.locale;
delete settings.units;
for (let setting of Object.keys(settings)) {
if (typeof gist.settings[setting] !== undefined) {
if (typeof gist.settings[setting] !== "undefined") {
settings[setting] = gist.settings[setting];
}
}

View file

@ -1,2 +1,3 @@
@import "components/emblem";
@import "components/pattern-option";
@import "components/pattern-options";

View file

@ -1,3 +1,5 @@
$fc-bg-light: $oc-gray-0;
$fc-bg-dark: $oc-gray-9;
$fc-notice-light: $oc-lime-9;
$fc-notice-dark: $oc-lime-3;
$fc-hoverbg-light: $oc-gray-1;

View file

@ -0,0 +1,20 @@
li.optiongroup-heading {
background: $fc-bg-light;
z-index: 3;
h3 {
margin: 0;
svg.collapse-icon { margin-bottom: -5px;}
}
}
li.optiongroup-heading:hover {
cursor: pointer;
background: $fc-hoverbg-light;
}
body.dark {
li.optiongroup-heading {
background: $fc-bg-dark;
}
li.optiongroup-heading:hover {
background: $fc-hoverbg-dark;
}
}

View file

@ -1,4 +1,4 @@
@import '../node_modules/open-color/open-color.scss';
@import '../../../node_modules/open-color/open-color.scss';
@import "variables";
@import "mixins";
@import "components";

View file

@ -30,7 +30,6 @@ export default {
"sleeveLengthBonus",
"waistEase",
"hipsEase",
"collarEase",
"yokeDart"
],
style: [