1
0
Fork 0

🚧 Progress on React components

This commit is contained in:
Joost De Cock 2019-04-27 10:50:44 +02:00
parent ea87274eb2
commit d8cc1f76f3
59 changed files with 341 additions and 260 deletions

View file

@ -1,89 +0,0 @@
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 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";
import DownIcon from "@material-ui/icons/KeyboardArrowDown";
const DraftActions = 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 paperSizes = ["A4", "Letter", "A3", "Tabloid", "A2", "A1", "A0"];
let groups = {
saveDraft: [
<li>
<FormattedMessage id="app.saveDraftToYourAccount" />
</li>,
<li>
<FormattedMessage id="app.saveGistAsJSON" />
</li>,
<li>
<FormattedMessage id="app.saveGistAsYAML" />
</li>,
<li>
<FormattedMessage id="app.saveSvg" />
</li>
],
exportDraft: [
<li>
<FormattedMessage id="app.exportDraft" />: PDF
</li>,
paperSizes.map(size => (
<li>
<FormattedMessage id="app.exportTiledPdf" />: {size}
</li>
))
]
};
return (
<ul className="nav l2">
{Object.keys(groups).map(group => {
let open = true;
if (expanded.indexOf(group) === -1) open = false;
let children = null;
if (open) children = groups[group].map(component => component);
return (
<React.Fragment>
<li
className={open ? "expanded" : "collapsed"}
key={group + "-ghead"}
>
<h3 onClick={() => toggleGroup(group)}>
<DownIcon
className={
"icon-col-exp " + (open ? "expanded" : "collapsed")
}
/>
<FormattedMessage id={"app." + group} />
</h3>
</li>
{children}
</React.Fragment>
);
})}
</ul>
);
};
DraftActions.propTypes = {};
DraftActions.defaultProps = {};
export default DraftActions;

View file

@ -14,6 +14,6 @@ const props = {
labels: ["No", "Yes"] labels: ["No", "Yes"]
}; };
storiesOf("DraftSettingComplete", module).add("Basic", () => ( storiesOf("Low level/DraftSettingComplete", module).add("Basic", () => (
<Complete {...props} /> <Complete {...props} />
)); ));

View file

@ -1,10 +1,12 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
import { injectIntl } from "react-intl";
import { i18n as languages } from "@freesewing/i18n";
const DraftSettingLanguage = props => { const DraftSettingLanguage = props => {
const [value, setValue] = useState(props.dflt); const [value, setValue] = useState(props.intl.locale);
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const update = (name, newValue, evt) => { const update = (name, newValue, evt) => {
@ -13,33 +15,32 @@ const DraftSettingLanguage = props => {
}; };
const reset = () => { const reset = () => {
setValue(props.dflt); setValue(props.intl.locale);
props.updateValue(props.name, props.dflt); props.updateValue(props.name, props.intl.locale);
}; };
const toggleExpanded = () => setExpanded(!expanded); const toggleExpanded = () => setExpanded(!expanded);
const option = ( const option = (
<FormFieldList <FormFieldList
name={props.name} name={props.name}
value={value} value={value}
dflt={props.dflt} dflt={props.intl.locale}
onChange={update} onChange={update}
label={"po-list-" + props.name} label={"po-list-" + props.name}
updateValue={update} updateValue={update}
list={props.languages} list={languages[props.intl.locale]}
/> />
); );
return ( return (
<li> <li>
<OptionPreamble <OptionPreamble
dflt={props.dflt} dflt={props.intl.locale}
value={value} value={value}
desc={props.desc} desc={props.desc}
title={props.title} title={props.title}
id={"po-list-" + props.name} id={"po-list-" + props.name}
displayValue={props.languages[value]} displayValue={languages[props.intl.locale][value]}
reset={reset} reset={reset}
toggleExpanded={toggleExpanded} toggleExpanded={toggleExpanded}
expanded={expanded} expanded={expanded}
@ -59,13 +60,9 @@ DraftSettingLanguage.propTypes = {
triggerAction: PropTypes.func.isRequired, triggerAction: PropTypes.func.isRequired,
updateValue: PropTypes.func.isRequired, updateValue: PropTypes.func.isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
dflt: PropTypes.oneOfType([
PropTypes.number.isRequired,
PropTypes.string.isRequired
]),
title: PropTypes.node.isRequired, title: PropTypes.node.isRequired,
desc: PropTypes.node.isRequired, desc: PropTypes.node.isRequired,
list: PropTypes.object.isRequired list: PropTypes.object.isRequired
}; };
export default DraftSettingLanguage; export default injectIntl(DraftSettingLanguage);

View file

@ -22,6 +22,6 @@ const props = {
} }
}; };
storiesOf("DraftSettingLanguage", module).add("Basic", () => ( storiesOf("Low level/DraftSettingLanguage", module).add("Basic", () => (
<Lang {...props} /> <Lang {...props} />
)); ));

View file

@ -1,12 +1,13 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import FormFieldSlider from "../FormFieldSlider"; import FormFieldSlider from "../../form/FormFieldSlider";
import { formatMm, roundMm, defaultSa, sliderStep } from "../utils"; import { formatMm, roundMm, defaultSa, sliderStep } from "../../utils";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const DraftSettingMargin = props => { const DraftSettingMargin = props => {
const [value, setValue] = useState(props.dflt); const [value, setValue] = useState(props.dflt);
const [expanded, setExpanded] = useState(false);
const update = (name, newValue, evt) => { const update = (name, newValue, evt) => {
newValue = roundMm(newValue); newValue = roundMm(newValue);
@ -27,23 +28,9 @@ const DraftSettingMargin = props => {
props.updateValue("margin", props.dflt); props.updateValue("margin", props.dflt);
}; };
return ( const toggleExpanded = () => setExpanded(!expanded);
<div className={"pattern-option list"}>
<OptionPreamble let option = (
dflt={props.dflt}
value={value}
desc={props.desc}
title={props.title}
id="po-slider-margin"
displayValue={formatMm(value, props.units)}
reset={reset}
showHelp={() =>
props.triggerAction("showHelp", {
type: "draftSetting",
value: "margin"
})
}
/>
<FormFieldSlider <FormFieldSlider
name="customSa" name="customSa"
value={value} value={value}
@ -54,7 +41,29 @@ const DraftSettingMargin = props => {
max={25.4} max={25.4}
step={sliderStep[props.units]} step={sliderStep[props.units]}
/> />
</div> );
return (
<li>
<OptionPreamble
dflt={props.dflt}
value={value}
desc={props.desc}
title={props.title}
id="po-slider-margin"
displayValue={formatMm(value, props.units)}
reset={reset}
toggleExpanded={toggleExpanded}
expanded={expanded}
showHelp={() =>
props.triggerAction("showHelp", {
type: "draftSetting",
value: "margin"
})
}
option={option}
/>
</li>
); );
}; };

View file

@ -14,6 +14,6 @@ const props = {
"This is the margin description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it." "This is the margin description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it."
}; };
storiesOf("DraftSettingMargin", module) storiesOf("Low level/DraftSettingMargin", module)
.add("Metric", () => <Margin {...props} units="metric" />) .add("Metric", () => <Margin {...props} units="metric" />)
.add("Imperial", () => <Margin {...props} units="imperial" />); .add("Imperial", () => <Margin {...props} units="imperial" />);

View file

@ -1,8 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import FormFieldChecks from "../FormFieldChecks"; import FormFieldChecks from "../../form/FormFieldChecks";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import FormFieldSlider from "../FormFieldSlider"; import FormFieldSlider from "../../form/FormFieldSlider";
import { formatMm, roundMm, defaultSa, sliderStep } from "../utils"; import { formatMm, roundMm, defaultSa, sliderStep } from "../../utils";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const DraftSettingOnly = props => { const DraftSettingOnly = props => {

View file

@ -24,7 +24,7 @@ const props = {
} }
}; };
storiesOf("DraftSettingOnly", module) storiesOf("Low level/DraftSettingOnly", module)
.add("Default", () => <Sa {...props} />) .add("Default", () => <Sa {...props} />)
.add("Default, all parts preselected", () => ( .add("Default, all parts preselected", () => (
<Sa {...props} customDflt={Object.keys(props.parts)} /> <Sa {...props} customDflt={Object.keys(props.parts)} />

View file

@ -15,6 +15,6 @@ const props = {
labels: ["No", "Yes"] labels: ["No", "Yes"]
}; };
storiesOf("DraftSettingPaperless", module).add("Basic", () => ( storiesOf("Low level/DraftSettingPaperless", module).add("Basic", () => (
<Paperless {...props} /> <Paperless {...props} />
)); ));

View file

@ -1,8 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import FormFieldSlider from "../FormFieldSlider"; import FormFieldSlider from "../../form/FormFieldSlider";
import { formatMm, roundMm, defaultSa, sliderStep } from "../utils"; import { formatMm, roundMm, defaultSa, sliderStep } from "../../utils";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const DraftSettingSa = props => { const DraftSettingSa = props => {

View file

@ -19,6 +19,6 @@ const props = {
} }
}; };
storiesOf("DraftSettingSa", module) storiesOf("Low level/DraftSettingSa", module)
.add("Metric", () => <Sa {...props} units="metric" />) .add("Metric", () => <Sa {...props} units="metric" />)
.add("Imperial", () => <Sa {...props} units="imperial" />); .add("Imperial", () => <Sa {...props} units="imperial" />);

View file

@ -1,5 +1,5 @@
import React, { useState } from "react"; import React, { useState } from "react";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const DraftSettingUnits = props => { const DraftSettingUnits = props => {

View file

@ -18,4 +18,4 @@ const props = {
} }
}; };
storiesOf("DraftSettingUnits", module).add("Basic", () => <Units {...props} />); storiesOf("Low level/DraftSettingUnits", module).add("Basic", () => <Units {...props} />);

View file

@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { gistDefaults } from "../utils"; import { gistDefaults } from "../../utils";
import { patternInfo, patternList } from "@freesewing/patterns"; import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import List from "@material-ui/core/List"; import List from "@material-ui/core/List";
@ -89,11 +89,7 @@ const DraftSettings = props => {
dflt={props.units} dflt={props.units}
list={units} list={units}
/>, />,
<DraftSettingLanguage <DraftSettingLanguage {...addProps("locale")} />
{...addProps("locale")}
dflt={props.language}
languages={props.languages}
/>
] ]
}; };

View file

@ -22,7 +22,7 @@ const props = {
language: "en" language: "en"
}; };
storiesOf("DraftActions", module) storiesOf("Low level/DraftSettings", module)
.add("Simon metric", () => ( .add("Simon metric", () => (
<DraftSettings pattern="simon" gist={false} units="metric" {...props} /> <DraftSettings pattern="simon" gist={false} units="metric" {...props} />
)) ))

View file

@ -6,12 +6,11 @@ import Mm from "../PatternOptionMillimeter";
import Bool from "../PatternOptionBool"; import Bool from "../PatternOptionBool";
import List from "../PatternOptionList"; import List from "../PatternOptionList";
import Count from "../PatternOptionCount"; import Count from "../PatternOptionCount";
import { optionType } from "../utils"; import { optionType } from "../../utils";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { injectIntl } from "react-intl"; import { injectIntl } from "react-intl";
const OptionGroup = props => { const OptionGroup = props => {
const update = (name, value) => props.updateValue("option", name, value);
const renderOption = (name, sub=false) => { const renderOption = (name, sub=false) => {
let option = props.pattern.config.options[name]; let option = props.pattern.config.options[name];
@ -21,7 +20,7 @@ const OptionGroup = props => {
name, name,
dflt: props.dflts.options[name], dflt: props.dflts.options[name],
units: props.units, units: props.units,
updateValue: update, updateValue: props.updateValue,
triggerAction: props.triggerAction, triggerAction: props.triggerAction,
title: <FormattedMessage id={stringKey + "title"} />, title: <FormattedMessage id={stringKey + "title"} />,
desc: <FormattedMessage id={stringKey + "description"} />, desc: <FormattedMessage id={stringKey + "description"} />,

View file

@ -35,6 +35,6 @@ const props = {
options: Object.keys(options) options: Object.keys(options)
}; };
storiesOf("OptionGroup", module).add("Simon metric", () => ( storiesOf("Low level/OptionGroup", module).add("Simon metric", () => (
<OptionGroup pattern="simon" {...props} units="metric" /> <OptionGroup pattern="simon" {...props} units="metric" />
)); ));

View file

@ -15,6 +15,6 @@ const props = {
"This is the description. I'm wrapped in a p tag. This component is used within other components, and not very useful on its own." "This is the description. I'm wrapped in a p tag. This component is used within other components, and not very useful on its own."
}; };
storiesOf("OptionPreamble", module).add("Preamble", () => ( storiesOf("Low level/OptionPreamble", module).add("Preamble", () => (
<Preamble {...props} /> <Preamble {...props} />
)); ));

View file

@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldBool from "../FormFieldBool"; import FormFieldBool from "../../form/FormFieldBool";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const PatternOptionBool = props => { const PatternOptionBool = props => {

View file

@ -16,6 +16,6 @@ const props = {
labels: ["No", "Yes"] labels: ["No", "Yes"]
}; };
storiesOf("PatternOptionBool", module) storiesOf("Low level/PatternOptionBool", module)
.add("Basic", () => <Bool {...props} />) .add("Basic", () => <Bool {...props} />)
.add("Yes as default", () => <Bool {...props} dflt={true} />); .add("Yes as default", () => <Bool {...props} dflt={true} />);

View file

@ -15,7 +15,7 @@ const props = {
"This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it." "This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it."
}; };
storiesOf("PatternOptionCount", module) storiesOf("Low level/PatternOptionCount", module)
.add("Basic", () => <Count {...props} />) .add("Basic", () => <Count {...props} />)
.add("From 20 to 80", () => <Count {...props} min={20} max={80} />) .add("From 20 to 80", () => <Count {...props} min={20} max={80} />)
.add("Step: 5", () => <Count {...props} step={5} />); .add("Step: 5", () => <Count {...props} step={5} />);

View file

@ -16,7 +16,7 @@ const props = {
"This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it." "This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it."
}; };
storiesOf("PatternOptionDegree", module) storiesOf("Low level/PatternOptionDegree", module)
.add("Basic", () => <Pct {...props} />) .add("Basic", () => <Pct {...props} />)
.add("From 30 to 45", () => <Pct {...props} min={30} max={45} />) .add("From 30 to 45", () => <Pct {...props} min={30} max={45} />)
.add("Step: 10", () => <Pct {...props} step={10} max={180} dflt={90} />); .add("Step: 10", () => <Pct {...props} step={10} max={180} dflt={90} />);

View file

@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldList from "../FormFieldList"; import FormFieldList from "../../form/FormFieldList";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const PatternOptionList = props => { const PatternOptionList = props => {

View file

@ -20,4 +20,4 @@ const props = {
} }
}; };
storiesOf("PatternOptionList", module).add("Basic", () => <List {...props} />); storiesOf("Low level/PatternOptionList", module).add("Basic", () => <List {...props} />);

View file

@ -6,8 +6,8 @@ import {
roundMmUp, roundMmUp,
roundMmDown, roundMmDown,
formatMm formatMm
} from "../utils"; } from "../../utils";
import FormFieldSlider from "../FormFieldSlider"; import FormFieldSlider from "../../form/FormFieldSlider";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const PatternOptionMillimeter = props => { const PatternOptionMillimeter = props => {

View file

@ -21,7 +21,7 @@ const maxNotOnStep =
const minNotOnStep = const minNotOnStep =
"Since our step is 0.1mm and our min value is 24.06 mm, it falls in between two steps (24mm and 24.1mm). Picking the min value would result in the rounded min value of 24mm, which is outside our min boundary. So we always round the min value up to the closest step. Also note that while the displayed value rounds to mm, under the hood we use 1/10th of a mm and the actual value passed for the min here is not 2.4cm but 24.1mm (2.41cm)"; "Since our step is 0.1mm and our min value is 24.06 mm, it falls in between two steps (24mm and 24.1mm). Picking the min value would result in the rounded min value of 24mm, which is outside our min boundary. So we always round the min value up to the closest step. Also note that while the displayed value rounds to mm, under the hood we use 1/10th of a mm and the actual value passed for the min here is not 2.4cm but 24.1mm (2.41cm)";
storiesOf("PatternOptionMillimeter", module) storiesOf("Low level/PatternOptionMillimeter", module)
.add("Metric", () => <Mm {...props} />) .add("Metric", () => <Mm {...props} />)
.add("Max: 12.486 cm", () => ( .add("Max: 12.486 cm", () => (
<Mm {...props} max={124.86} desc={maxNotOnStep} /> <Mm {...props} max={124.86} desc={maxNotOnStep} />

View file

@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FormFieldSlider from "../FormFieldSlider"; import FormFieldSlider from "../../form/FormFieldSlider";
import OptionPreamble from "../OptionPreamble"; import OptionPreamble from "../OptionPreamble";
const PatternOptionPctDegCount = props => { const PatternOptionPctDegCount = props => {

View file

@ -14,12 +14,12 @@ const props = {
"This is the description. I'm wrapped in a p tag. This component is the base for the percentage, degree, and count pattern options." "This is the description. I'm wrapped in a p tag. This component is the base for the percentage, degree, and count pattern options."
}; };
storiesOf("PatternOptionPctDegCount", module).add("Percentage", () => ( storiesOf("Low level/PatternOptionPctDegCount", module).add("Percentage", () => (
<PctDegCount {...props} type="pct" /> <PctDegCount {...props} type="pct" />
)); ));
storiesOf("PatternOptionPctDegCount", module).add("Degree", () => ( storiesOf("Low level/PatternOptionPctDegCount", module).add("Degree", () => (
<PctDegCount {...props} type="deg" /> <PctDegCount {...props} type="deg" />
)); ));
storiesOf("PatternOptionPctDegCount", module).add("Count", () => ( storiesOf("Low level/PatternOptionPctDegCount", module).add("Count", () => (
<PctDegCount {...props} type="count" /> <PctDegCount {...props} type="count" />
)); ));

View file

@ -15,7 +15,7 @@ const props = {
"This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it." "This is the description. I'm wrapped in a p tag. This component only sets the CSS class on a non-default value. It's up to you to supply the CSS to style it."
}; };
storiesOf("PatternOptionPercentage", module) storiesOf("Low level/PatternOptionPercentage", module)
.add("Basic", () => <Pct {...props} />) .add("Basic", () => <Pct {...props} />)
.add("From 20 to 80", () => <Pct {...props} min={20} max={80} />) .add("From 20 to 80", () => <Pct {...props} min={20} max={80} />)
.add("Step: 5", () => <Pct {...props} step={5} />); .add("Step: 5", () => <Pct {...props} step={5} />);

View file

@ -5,7 +5,7 @@ import Deg from "../PatternOptionDegree";
import Mm from "../PatternOptionMillimeter"; import Mm from "../PatternOptionMillimeter";
import Bool from "../PatternOptionBool"; import Bool from "../PatternOptionBool";
import OptionGroup from "../OptionGroup"; import OptionGroup from "../OptionGroup";
import { optionType, defaultGist, gistDefaults } from "../utils"; import { optionType, defaultGist, gistDefaults } from "../../utils";
import { patternInfo, patternList } from "@freesewing/patterns"; import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import List from "@material-ui/core/List"; import List from "@material-ui/core/List";

View file

@ -14,7 +14,7 @@ const props = {
} }
}; };
storiesOf("PatternOptions", module) storiesOf("Low level/PatternOptions", module)
.add("Simon metric", () => ( .add("Simon metric", () => (
<PatternOptions pattern="simon" gist={false} units="metric" {...props} /> <PatternOptions pattern="simon" gist={false} units="metric" {...props} />
)) ))

View file

@ -1,23 +1,22 @@
import React, { useState } from "react"; import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import Pct from "../PatternOptionPercentage"; import Pct from "./PatternOptionPercentage";
import Deg from "../PatternOptionDegree"; import Deg from "./PatternOptionDegree";
import Mm from "../PatternOptionMillimeter"; import Mm from "./PatternOptionMillimeter";
import Bool from "../PatternOptionBool"; import Bool from "./PatternOptionBool";
import OptionGroup from "../OptionGroup"; import OptionGroup from "./OptionGroup";
import { optionType, gistDefaults } from "../utils"; import { optionType, gistDefaults } from "../utils";
import { patternInfo, patternList } from "@freesewing/patterns"; import { patternInfo, patternList } from "@freesewing/patterns";
import { FormattedMessage, injectIntl } from "react-intl"; import { FormattedMessage } from "react-intl";
import { i18n as languages } from "@freesewing/i18n";
import CollapsedIcon from "@material-ui/icons/ArrowDropDown"; import CollapsedIcon from "@material-ui/icons/ArrowDropDown";
import ExpandedIcon from "@material-ui/icons/ArrowRight"; import ExpandedIcon from "@material-ui/icons/ArrowRight";
import PatternOptions from "../PatternOptions"; import PatternOptions from "./PatternOptions";
import DraftSettings from "../DraftSettings"; import DraftSettings from "./DraftSettings";
import DraftActions from "../DraftActions"; //import DraftActions from "DraftActions";
import withGist from "../withGist";
const GistConfigurator = props => { const DraftConfigurator = props => {
console.log(languages); const [gist, setGist] = useState(props.gist.get);
const [gist, setGist] = useState(props.gist);
const [expanded, setExpanded] = useState([]); const [expanded, setExpanded] = useState([]);
const update = (type, name, value) => { const update = (type, name, value) => {
@ -31,9 +30,8 @@ const GistConfigurator = props => {
else shown.splice(index, 1); else shown.splice(index, 1);
setExpanded(shown); setExpanded(shown);
}; };
let pattern = patternInfo[props.pattern]; let pattern = patternInfo[props.pattern];
let dflts = gistDefaults(pattern.config, props.gist); let dflts = gistDefaults(pattern.config, props.gist.get);
return ( return (
<ul className="nav l1"> <ul className="nav l1">
@ -44,7 +42,7 @@ const GistConfigurator = props => {
<PatternOptions <PatternOptions
pattern={props.pattern} pattern={props.pattern}
units={props.units} units={props.units}
updateValue={update} updateValue={(name, value) => props.gist.set(value, 'settings', 'options', name)}
triggerAction={props.triggerAction} triggerAction={props.triggerAction}
/> />
</li> </li>
@ -55,27 +53,19 @@ const GistConfigurator = props => {
<DraftSettings <DraftSettings
pattern={props.pattern} pattern={props.pattern}
units={props.units} units={props.units}
updateValue={update} updateValue={(name, value) => props.gist.set(value, 'settings', name)}
triggerAction={props.triggerAction} triggerAction={props.triggerAction}
language={props.intl.locale}
languages={languages[props.intl.locale]}
/> />
</li> </li>
<li>
<h2>
<FormattedMessage id="app.save" />
</h2>
<DraftActions />
</li>
</ul> </ul>
); );
}; };
GistConfigurator.propTypes = { DraftConfigurator.propTypes = {
pattern: PropTypes.oneOf(patternList), pattern: PropTypes.oneOf(patternList),
units: PropTypes.oneOf(["metric", "imperial"]).isRequired units: PropTypes.oneOf(["metric", "imperial"]).isRequired
}; };
GistConfigurator.defaultProps = {}; DraftConfigurator.defaultProps = {};
export default injectIntl(GistConfigurator); export default withGist(DraftConfigurator, {gist: {}, store: "yes"});

View file

@ -9,14 +9,9 @@ const props = {
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) => updateValue: (type, data) =>
console.log(`Update ${type} with new value`, data), console.log(`Update ${type} with new value`, data),
gist: {
settings: {
options: {}
}
}
}; };
storiesOf("GistConfigurator", module) storiesOf("DraftConfigurator", module)
.add("Simon metric", () => ( .add("Simon metric", () => (
<GistConfigurator pattern="simon" {...props} units="metric" /> <GistConfigurator pattern="simon" {...props} units="metric" />
)) ))

View file

@ -1,31 +0,0 @@
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

@ -3,8 +3,8 @@ import PropTypes from "prop-types";
const Emblem = props => ( const Emblem = props => (
<React.Fragment> <React.Fragment>
<span className="emb" style={{color: props.c1}}>{props.t1}</span> <span className="emb" style={{color: props.c1, fontSize: props.size+"px"}}>{props.t1}</span>
<span className="lem" style={{color: props.c2}}>{props.t2}</span> <span className="lem" style={{color: props.c2, fontSize: props.size+"px"}}>{props.t2}</span>
</React.Fragment> </React.Fragment>
); );
@ -17,11 +17,11 @@ Emblem.propTypes = {
}; };
Emblem.defaultProps = { Emblem.defaultProps = {
size: 24, size: 36,
c1: "#111111", c1: "#111111",
c2: "#111111", c2: "#111111",
t1: "", t1: "",
t2: "" t2: "",
}; };
export default Emblem; export default Emblem;

View file

@ -0,0 +1,42 @@
import React from "react";
import PropTypes from "prop-types";
import Logo from "../Logo";
import Emblem from "../Emblem";
import { FormattedMessage } from "react-intl";
const Navbar = props => {
const renderNav = nav => {
let title = nav.title || nav.text;
let text = typeof nav.text === "string"
? <FormattedMessage id={nav.text} />
: nav.text
if (nav.type === "component") return nav.component
return <a href={nav.href} className="nav" title={nav.title}>{text}</a>
}
return (
<header className="navbar">
<div>
<div className="logo">{props.logo}</div>
<div className="emblem">{props.emblem}</div>
{props.navs.left.map(nav => renderNav(nav))}
<div className="spread" />
{props.navs.right.map(nav => renderNav(nav))}
</div>
</header>
);
};
Navbar.propTypes = {
navs: PropTypes.object,
logo: PropTypes.node,
emblem: PropTypes.node,
};
Navbar.defaultProps = {
navs: {left:[], right: []},
logo: <Logo size={32} />,
emblem: <Emblem t1="Free" t2="Sewing" size={20} c1="#74c0fc" c2="#e9ecef"/>
};
export default Navbar;

View file

@ -0,0 +1,55 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import Navbar from ".";
import LanguageIcon from "@material-ui/icons/Translate";
import DarkModeIcon from "@material-ui/icons/Brightness3";
import Avatar from '@material-ui/core/Avatar';
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),
};
const navs = {
left: [
{
type: "link",
href: "https://freesewing.org/",
text: "app.patterns"
},
{
type: "link",
href: "https://freesewing.org/",
text: "app.docs"
},
{
type: "link",
href: "https://freesewing.org/",
text: "app.community"
},
],
right: [
{
type: "link",
href: "https://freesewing.org/",
text: "app.account",
},
{
type: "link",
href: "https://freesewing.org/",
text: <LanguageIcon className="nav-icon"/>,
title: 'Languages'
},
{
type: "link",
href: "https://freesewing.org/",
text: <DarkModeIcon className="nav-icon moon"/>,
title: 'Dark mode'
},
],
}
storiesOf("Navbar", module)
.add("Basic", () => <Navbar navs={navs}/>)

View file

@ -9,7 +9,7 @@ const props = {
}; };
const noyes = ["No", "Yes"]; const noyes = ["No", "Yes"];
storiesOf("FormFieldBool", module) storiesOf("Low level/Form/FormFieldBool", module)
.add("Basic", () => <FormFieldBool {...props} />) .add("Basic", () => <FormFieldBool {...props} />)
.add("False", () => <FormFieldBool {...props} dflt={false} />) .add("False", () => <FormFieldBool {...props} dflt={false} />)
.add("True", () => <FormFieldBool {...props} dflt={true} />) .add("True", () => <FormFieldBool {...props} dflt={true} />)

View file

@ -14,7 +14,7 @@ const props = {
dflt: [] dflt: []
}; };
storiesOf("FormFieldChecks", module) storiesOf("Low level/Form/FormFieldChecks", module)
.add("Basic", () => <FormFieldChecks {...props} />) .add("Basic", () => <FormFieldChecks {...props} />)
.add("Apple", () => <FormFieldChecks {...props} dflt={["apple"]} />) .add("Apple", () => <FormFieldChecks {...props} dflt={["apple"]} />)
.add("Banana", () => <FormFieldChecks {...props} dflt={["banana"]} />) .add("Banana", () => <FormFieldChecks {...props} dflt={["banana"]} />)

View file

@ -13,7 +13,7 @@ const props = {
} }
}; };
storiesOf("FormFieldList", module) storiesOf("Low level/Form/FormFieldList", module)
.add("Basic", () => <FormFieldList {...props} />) .add("Basic", () => <FormFieldList {...props} />)
.add("Apple", () => <FormFieldList {...props} dflt="apple" />) .add("Apple", () => <FormFieldList {...props} dflt="apple" />)
.add("Banana", () => <FormFieldList {...props} dflt="banana" />) .add("Banana", () => <FormFieldList {...props} dflt="banana" />)

View file

@ -8,7 +8,7 @@ const props = {
name: "exampleSliderOption" name: "exampleSliderOption"
}; };
storiesOf("FormFieldSlider", module) storiesOf("Low level/Form/FormFieldSlider", module)
.add("Basic", () => <FormFieldSlider {...props} />) .add("Basic", () => <FormFieldSlider {...props} />)
.add("From 1 to 10", () => <FormFieldSlider {...props} min={1} max={10} />) .add("From 1 to 10", () => <FormFieldSlider {...props} min={1} max={10} />)
.add("Step: 1", () => ( .add("Step: 1", () => (

View file

@ -159,3 +159,28 @@ export const optionDefault = option => {
return option[type]; return option[type];
} }
}; };
export const storage = {
set: (key, value, raw) => {
if (typeof localStorage === "undefined")
throw(new Error("No localStorage support. And we need it. Bailing out."));
const _key = "fs_" + key;
if (typeof value === "undefined" || value === null)
localStorage.removeItem(_key);
else localStorage.setItem(_key, raw ? value : JSON.stringify(value));
return value;
},
get: (key, raw) => {
if (typeof localStorage === "undefined")
throw(new Error("No localStorage support. And we need it. Bailing out."));
const value = localStorage.getItem("fs_"+key);
return raw ? value : JSON.parse(value);
}
}
export const cloneObject = src => Object.assign({}, src);

View file

@ -0,0 +1,39 @@
import React from "react";
import { storage, cloneObject } from "../utils";
const withGist = (WrappedComponent, settings={gist:{}, store:false}) => {
return class extends React.Component {
constructor(props) {
super(props);
this.update = this.update.bind(this);
this.state = settings.gist || {};
}
update(value, l1 = false, l2 = false, l3 = false) {
console.log('update', value, l1, l2, l3, this.state);
if (!l1) return;
let gist = this.state;
if(typeof gist === "undefined") gist = {};
if(l1 && typeof gist[l1] === "undefined") gist[l1] = {};
if(l2 && typeof gist[l1][l2] === "undefined") gist[l1][l2] = {};
if(l3 && typeof gist[l1][l2][l3] === "undefined") gist[l1][l2][l3] = {};
if (l3) gist[l1][l2][l3] = value;
else if (l2) gist[l1][l2] = value;
else if (l1) gist[l1] = value;
this.setState(gist, () => {
if (settings.store) storage.set(settings.store, this.state);
console.log(this.state);
});
}
render() {
return <WrappedComponent gist={{get: this.state.gist, set: this.update}} {...this.props} />;
}
};
}
export default withGist;

View file

@ -1,3 +1,3 @@
@import "components/emblem"; @import "components/emblem";
@import "components/pattern-option"; @import "components/navbar";
@import "components/pattern-options"; @import "components/draft-configurator";

View file

@ -1,6 +1,13 @@
$fc-text-light: $oc-gray-9;
$fc-text-dark: $oc-gray-0;
$fc-bg-light: $oc-gray-0; $fc-bg-light: $oc-gray-0;
$fc-bg-dark: $oc-gray-9; $fc-bg-dark: $oc-gray-9;
$fc-notice-light: $oc-yellow-7; $fc-notice-light: $oc-yellow-7;
$fc-notice-dark: $oc-lime-3; $fc-notice-dark: $oc-lime-3;
$fc-hoverbg-light: $oc-gray-1; $fc-hoverbg-light: $oc-gray-1;
$fc-hoverbg-dark: $oc-gray-8; $fc-hoverbg-dark: $oc-gray-8;
$fc-accentbg-light: $oc-teal-5;
$fc-accentbg-dark: $oc-teal-8;
$fc-link-light: $oc-teal-8;
$fc-link-dark: $oc-blue-3;

View file

@ -65,7 +65,8 @@ svg.icon-col-exp.expanded {
} }
ul.nav.l2 div.col-exp, ul.nav.l2 div.col-exp,
ul.nav.l3 div.col-exp { ul.nav.l3 div.col-exp,
ul.nav.l4 div.col-exp {
margin: 0 27px; margin: 0 27px;
} }

View file

@ -0,0 +1,65 @@
header.navbar {
position: fixed;
top: 0;
left: 0;
height: 64px;
width: calc(100% - 52px);
margin: 0;
padding: 0 26px;
background: $fc-bg-dark;
div.logo {
height: 64px;
padding: 0;
margin: 0;
margin-right: 13px;
display: flex;
align-items: center;
color: $oc-gray-2;
}
div.emblem {
margin-right: 26px;
}
div.spread { flex-grow: 1}
a.nav,
button {
@include title-font;
margin: 0;
padding: 0 13px;
height: 60px;
color: $fc-text-dark;
border: 0;
line-height: 64px;
border-bottom: 4px solid $fc-bg-dark;
font-size: 18px;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease-in-out;
background:none;
}
button {
/* For buttons, border does not count for height */
height: 64px;
}
button:hover,
a.nav:hover {
cursor: pointer;
color: $fc-link-dark;
border-color: $fc-link-dark;
}
a.nav.active {
border-color: $fc-link-dark;
}
svg.nav-icon {
margin-right: 5px;
margin-bottom: -6px;
}
svg.nav-icon.moon {
transform: rotate(26deg);
}
}
header.navbar > div {
display: flex;
align-items: center;
}

View file

@ -1,19 +0,0 @@
div.pattern-option {
.po-custom {
color: $fc-notice-light;
}
label.po-list-item:hover {
background: $fc-hoverbg-light;
}
}
body.dark {
div.pattern-option {
.po-custom {
color: $fc-notice-dark;
}
label.po-list-item:hover {
background: $fc-hoverbg-dark;
}
}
}

View file

@ -1,5 +1,5 @@
export default class Storage { export default class Storage {
set(key, value, isJson) { set(key, value, raw = false) {
if (typeof localStorage === "undefined") { if (typeof localStorage === "undefined") {
return; return;
} }
@ -9,13 +9,13 @@ export default class Storage {
if (typeof value === "undefined" || value === null) { if (typeof value === "undefined" || value === null) {
localStorage.removeItem(_key); localStorage.removeItem(_key);
} else { } else {
localStorage.setItem(_key, isJson ? JSON.stringify(value) : value); localStorage.setItem(_key, raw ? value : JSON.stringify(value));
} }
return value; return value;
} }
get(key, isJson) { get(key, raw = false) {
if (typeof localStorage === "undefined") { if (typeof localStorage === "undefined") {
return; return;
} }
@ -24,6 +24,6 @@ export default class Storage {
const value = localStorage.getItem(_key); const value = localStorage.getItem(_key);
return isJson ? JSON.parse(value) : value; return raw ? value : JSON.parse(value);
} }
} }