From 71af62585a813a83c966c9a28bd3f894589a12c9 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 02:47:51 -0300 Subject: [PATCH 01/23] Adding Dropdown and Option Compoennt --- client/coral-ui/components/Dropdown.css | 50 +++++++++++ client/coral-ui/components/Dropdown.js | 115 ++++++++++++++++++++++++ client/coral-ui/components/Option.css | 10 ++- client/coral-ui/components/Option.js | 20 +++-- client/coral-ui/components/Select.css | 33 ------- client/coral-ui/components/Select.js | 14 --- client/coral-ui/index.js | 4 +- 7 files changed, 187 insertions(+), 59 deletions(-) create mode 100644 client/coral-ui/components/Dropdown.css create mode 100644 client/coral-ui/components/Dropdown.js delete mode 100644 client/coral-ui/components/Select.css delete mode 100644 client/coral-ui/components/Select.js diff --git a/client/coral-ui/components/Dropdown.css b/client/coral-ui/components/Dropdown.css new file mode 100644 index 000000000..431f59076 --- /dev/null +++ b/client/coral-ui/components/Dropdown.css @@ -0,0 +1,50 @@ +.dropdown { + position: relative; + width: 150px; + height: 36px; + background: #2c2c2c; + padding: 10px 15px; + box-sizing: border-box; + color: white; + border-radius: 2px; + box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); +} + +.dropdown { + cursor: pointer; +} + +.label { + text-transform: capitalize; +} + +.list { + position: absolute; + top: 30px; + left: 10px; + color: #2c2c2c; + border-radius: 2px; + background: white; + box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); + width: 100%; + list-style: none; + padding: 0; + margin: 0; + transform: scale(0); + transition: transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1); + transform-origin: 0 0; +} + +.listActive { + opacity: 1; + transform: scale(1); + z-index: 999; +} + +.arrow { + position: absolute; + right: 15px; + font-size: 1.2rem; + vertical-align: middle; + top: 13px; +} \ No newline at end of file diff --git a/client/coral-ui/components/Dropdown.js b/client/coral-ui/components/Dropdown.js new file mode 100644 index 000000000..c9bd357f1 --- /dev/null +++ b/client/coral-ui/components/Dropdown.js @@ -0,0 +1,115 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './Dropdown.css'; +import Icon from './Icon'; +import cn from 'classnames'; +import ClickOutside from 'coral-framework/components/ClickOutside'; + +class Dropdown extends React.Component { + + constructor(props) { + super(props); + this.state = { + selected: { + label: props.label || '', + value: props.value || '' + }, + isOpen: false + }; + } + + componentWillReceiveProps(newProps) { + if (newProps.value && newProps.value !== this.state.selected.value) { + this.setState({ + selected: { + label: newProps.label, + value: newProps.value + } + }); + } + } + + compoentDidMount() { + document.addEventListener('click', this.handleClick, false); + document.addEventListener('touchend', this.handleClick, false); + } + + componentWillUnmount() { + document.removeEventListener('click', this.handleClick, false); + document.removeEventListener('touchend', this.handleClick, false); + } + + fireChange = (newState) => { + if (newState.selected !== this.state.selected && this.props.onChange) { + this.props.onChange(newState.selected.value); + } + } + + setValue = (value, label) => { + const newState = { + selected: { + label: label, + value: value + }, + isOpen: false + }; + this.fireChange(newState); + this.setState(newState); + } + + handleClick = () => { + this.setState({ + isOpen: !this.state.isOpen + }); + } + + hideMenu = () => { + this.setState({ + isOpen: false + }); + } + + renderLabel() { + if (this.props.label) { + return this.props.label; + } else if (this.props.value) { + return this.props.value; + } else { + return this.props.placeholder; + } + } + + render() { + return ( + +
+ {this.props.icon && } + {this.renderLabel()} + {this.state.isOpen ? : } +
    + {React.Children.toArray(this.props.children) + .map((child) => + React.cloneElement(child, { + key: child.props.value, + onClick: () => this.setValue(child.props.value, child.props.children) + }))} +
+
+
+ ); + } +} + +Dropdown.propTypes = { + placeholder: PropTypes.string, + icon: PropTypes.string, + onChange: PropTypes.func.isRequired, + children: PropTypes.node.isRequired, + label: PropTypes.string, + value: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string + ]), +}; + +export default Dropdown; diff --git a/client/coral-ui/components/Option.css b/client/coral-ui/components/Option.css index 54784d8fc..243a2716c 100644 --- a/client/coral-ui/components/Option.css +++ b/client/coral-ui/components/Option.css @@ -1,3 +1,9 @@ -.Option { - +.option { + padding: 10px; + text-transform: capitalize; } + +.option:hover { + background-color: #eee; + cursor: pointer; +} \ No newline at end of file diff --git a/client/coral-ui/components/Option.js b/client/coral-ui/components/Option.js index e2c45664c..dc58cd194 100644 --- a/client/coral-ui/components/Option.js +++ b/client/coral-ui/components/Option.js @@ -1,14 +1,18 @@ import React from 'react'; -import {Option as OptionMDL} from 'react-mdl-selectfield'; +import PropTypes from 'prop-types'; import styles from './Option.css'; +import cn from 'classnames'; -const Option = (props) => { - const {children, ...attrs} = props; - return ( - - {children} - - ); +const Option = ({className, children, onClick}) => ( +
  • + {children || ''} +
  • +); + +Option.propTypes = { + className: PropTypes.string, + children: PropTypes.string, + onClick: PropTypes.func }; export default Option; diff --git a/client/coral-ui/components/Select.css b/client/coral-ui/components/Select.css deleted file mode 100644 index ac93a843c..000000000 --- a/client/coral-ui/components/Select.css +++ /dev/null @@ -1,33 +0,0 @@ -.Select { - position: relative; - width: 100%; - height: 40px; - background: #2c2c2c; - padding: 10px 15px; - box-sizing: border-box; - color: white; - border-radius: 2px; - box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); - - > div { - padding: 0; - } - - i { - position: absolute; - top: 7px; - right: 7px; - } - - input { - padding: 0; - font-size: 13px; - letter-spacing: 0.7px; - font-weight: 400; - } - - &:hover { - cursor: pointer; - } - -} diff --git a/client/coral-ui/components/Select.js b/client/coral-ui/components/Select.js deleted file mode 100644 index 2e71d2417..000000000 --- a/client/coral-ui/components/Select.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import {SelectField} from 'react-mdl-selectfield'; -import styles from './Select.css'; - -const Select = (props) => { - const {children, ...attrs} = props; - return ( - - {children} - - ); -}; - -export default Select; diff --git a/client/coral-ui/index.js b/client/coral-ui/index.js index 93fe5af64..c688857a1 100644 --- a/client/coral-ui/index.js +++ b/client/coral-ui/index.js @@ -21,10 +21,10 @@ export {default as Success} from './components/Success'; export {default as Pager} from './components/Pager'; export {default as Wizard} from './components/Wizard'; export {default as WizardNav} from './components/WizardNav'; -export {default as Select} from './components/Select'; -export {default as Option} from './components/Option'; export {default as SnackBar} from './components/SnackBar'; export {default as TextArea} from './components/TextArea'; export {default as Drawer} from './components/Drawer'; export {default as Label} from './components/Label'; export {default as FlagLabel} from './components/FlagLabel'; +export {default as Dropdown} from './components/Dropdown'; +export {default as Option} from './components/Option'; From 16847f9fec7802f41ac8a19abcec8ebbf8c8fa8d Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 02:48:12 -0300 Subject: [PATCH 02/23] Translations and PropTypes --- .../src/routes/Community/components/Table.js | 41 ++++++++++++------- locales/en.yml | 1 + locales/es.yml | 1 + 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/client/coral-admin/src/routes/Community/components/Table.js b/client/coral-admin/src/routes/Community/components/Table.js index 18f52592d..2efa5944b 100644 --- a/client/coral-admin/src/routes/Community/components/Table.js +++ b/client/coral-admin/src/routes/Community/components/Table.js @@ -1,9 +1,11 @@ import React from 'react'; -import {SelectField, Option} from 'react-mdl-selectfield'; import styles from '../components/Table.css'; import t from 'coral-framework/services/i18n'; +import PropTypes from 'prop-types'; +import {Dropdown, Option} from 'coral-ui'; +import capitalize from 'lodash/capitalize'; -export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onCommenterStatusChange, viewUserDetail}) => ( +const Table = ({headers, commenters, onHeaderClickHandler, onRoleChange, onCommenterStatusChange, viewUserDetail}) => ( @@ -28,29 +30,40 @@ export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onComm {row.created_at} ))}
    - onCommenterStatusChange(row.id, status)}> + onCommenterStatusChange(row.id, status)}> - + - onRoleChange(row.id, role)}> - + - +
    ); + +Table.propTypes = { + headers: PropTypes.array, + commenters: PropTypes.array, + onHeaderClickHandler: PropTypes.func, + onRoleChange: PropTypes.func, + onCommenterStatusChange: PropTypes.func, + viewUserDetail: PropTypes.func, +}; + +export default Table; diff --git a/locales/en.yml b/locales/en.yml index 92119f125..7cea0c6da 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -75,6 +75,7 @@ en: status: Status username_and_email: "Username and Email" yes_ban_user: "Yes Ban User" + none: "None" configure: apply: Apply banned_word_text: "Comments which contain these words or phrases (not case-sensitive) will be automatically removed from the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list." diff --git a/locales/es.yml b/locales/es.yml index 62fc94256..70fce5310 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -74,6 +74,7 @@ es: status: Estado username_and_email: "Usuario y Correo" yes_ban_user: "Si, Suspendan el usuario" + none: "Ninguno" configure: apply: Aplicar banned_word_text: "Comentarios que contengan estas palabras o frases, en mayusculas o minúsculas, serán automáticamente eliminados del hilo de comentario. Escribir una palabra y apretar Enter o Tabulador para agregarla. O pueden pegar una lista de palabras separadas por coma." From 7b38bac5259a0a9b7f99d26ba4066a3572b4b4db Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 03:18:28 -0300 Subject: [PATCH 03/23] Stories Dropdown, Proptypes and tiny refactor --- .../src/routes/Stories/components/Stories.css | 25 ------ .../src/routes/Stories/components/Stories.js | 76 ++++++++----------- client/coral-ui/components/Dropdown.js | 3 +- 3 files changed, 33 insertions(+), 71 deletions(-) diff --git a/client/coral-admin/src/routes/Stories/components/Stories.css b/client/coral-admin/src/routes/Stories/components/Stories.css index be6b6f921..e8e2b8474 100644 --- a/client/coral-admin/src/routes/Stories/components/Stories.css +++ b/client/coral-admin/src/routes/Stories/components/Stories.css @@ -76,31 +76,6 @@ display: block; } -.statusMenu { - border-radius: 2px; - width: 10em; - text-align: center; - float: right; - color: #fff; - cursor: pointer; - letter-spacing: 0.7px; - font-weight: 400; - box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); -} - -.statusMenuOpen { - padding: 10px; - background-color: #268D81; -} - -.statusMenuIcon { - float: right; -} - -.statusMenuClosed { - padding: 10px; - background-color: #262626; -} .hidden { display: none; diff --git a/client/coral-admin/src/routes/Stories/components/Stories.js b/client/coral-admin/src/routes/Stories/components/Stories.js index d57b8f779..af6b7a8f7 100644 --- a/client/coral-admin/src/routes/Stories/components/Stories.js +++ b/client/coral-admin/src/routes/Stories/components/Stories.js @@ -1,16 +1,16 @@ import React, {Component} from 'react'; -import styles from './Stories.css'; -import t from 'coral-framework/services/i18n'; import {Link} from 'react-router'; - -import {Pager, Icon} from 'coral-ui'; -import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl'; -import EmptyCard from 'coral-admin/src/components/EmptyCard'; +import PropTypes from 'prop-types'; import sortBy from 'lodash/sortBy'; +import {Dropdown, Option, Pager, Icon} from 'coral-ui'; +import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl'; +import t from 'coral-framework/services/i18n'; +import styles from './Stories.css'; +import EmptyCard from 'coral-admin/src/components/EmptyCard'; const limit = 25; -export default class Stories extends Component { +class Stories extends Component { state = { search: '', @@ -50,27 +50,13 @@ export default class Stories extends Component { return `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`; } - onStatusClick = (closeStream, id, statusMenuOpen) => async () => { - if (statusMenuOpen) { - this.setState((prev) => { - prev.statusMenus[id] = false; - return prev; - }); - - try { - await this.props.updateAssetState(id, closeStream ? Date.now() : null); - const {search, sort, filter, page} = this.state; - this.props.fetchAssets(page, limit, search, sort, filter); - } catch (err) { - - // TODO: handle error. - console.error(err); - } - } else { - this.setState((prev) => { - prev.statusMenus[id] = true; - return prev; - }); + onStatusClick = async (closeStream, id) => { + try { + this.props.updateAssetState(id, closeStream ? Date.now() : null); + const {search, sort, filter, page} = this.state; + this.props.fetchAssets(page, limit, search, sort, filter); + } catch(err) { + console.error(err); } } @@ -78,23 +64,15 @@ export default class Stories extends Component { renderStatus = (closedAt, {id}) => { const closed = closedAt && new Date(closedAt).getTime() < Date.now(); - const statusMenuOpen = this.state.statusMenus[id]; - return
    -
    - {!statusMenuOpen && } - {closed ? t('streams.closed') : t('streams.open')} -
    - { - statusMenuOpen && -
    - {!closed ? t('streams.closed') : t('streams.open')} -
    - } -
    ; + return ( + this.onStatusClick(!value, id)}> + + + + ); } onPageClick = (page) => { @@ -174,3 +152,11 @@ export default class Stories extends Component { } } +Stories.propTypes = { + assets: PropTypes.object, + fetchAssets: PropTypes.func, + updateAssetState: PropTypes.func, +}; + +export default Stories; + diff --git a/client/coral-ui/components/Dropdown.js b/client/coral-ui/components/Dropdown.js index c9bd357f1..b32036097 100644 --- a/client/coral-ui/components/Dropdown.js +++ b/client/coral-ui/components/Dropdown.js @@ -108,7 +108,8 @@ Dropdown.propTypes = { label: PropTypes.string, value: PropTypes.oneOfType([ PropTypes.number, - PropTypes.string + PropTypes.string, + PropTypes.bool ]), }; From bbad09d271a1944a602f40977db734d79d3dd857 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 12:26:06 -0300 Subject: [PATCH 04/23] Missing proptype --- client/coral-ui/components/Option.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/coral-ui/components/Option.js b/client/coral-ui/components/Option.js index dc58cd194..ffafe948c 100644 --- a/client/coral-ui/components/Option.js +++ b/client/coral-ui/components/Option.js @@ -12,7 +12,12 @@ const Option = ({className, children, onClick}) => ( Option.propTypes = { className: PropTypes.string, children: PropTypes.string, - onClick: PropTypes.func + onClick: PropTypes.func, + value: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string, + PropTypes.bool + ]), }; export default Option; From 18b18a7aefd5beecc78bf2c7b5bf9145337b8694 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 12:26:41 -0300 Subject: [PATCH 05/23] Removing global listeners --- client/coral-ui/components/Dropdown.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/coral-ui/components/Dropdown.js b/client/coral-ui/components/Dropdown.js index b32036097..8b30f6fbe 100644 --- a/client/coral-ui/components/Dropdown.js +++ b/client/coral-ui/components/Dropdown.js @@ -29,16 +29,6 @@ class Dropdown extends React.Component { } } - compoentDidMount() { - document.addEventListener('click', this.handleClick, false); - document.addEventListener('touchend', this.handleClick, false); - } - - componentWillUnmount() { - document.removeEventListener('click', this.handleClick, false); - document.removeEventListener('touchend', this.handleClick, false); - } - fireChange = (newState) => { if (newState.selected !== this.state.selected && this.props.onChange) { this.props.onChange(newState.selected.value); From 1c535bda89ad7f9c678ad7cdf5b40ad473ee82df Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 12:27:32 -0300 Subject: [PATCH 06/23] Lowering down the animation --- client/coral-ui/components/Dropdown.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-ui/components/Dropdown.css b/client/coral-ui/components/Dropdown.css index 431f59076..eaa8b8b34 100644 --- a/client/coral-ui/components/Dropdown.css +++ b/client/coral-ui/components/Dropdown.css @@ -31,7 +31,7 @@ padding: 0; margin: 0; transform: scale(0); - transition: transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1); + transition: transform .1s cubic-bezier(.4,0,.2,1),opacity .1s cubic-bezier(.4,0,.2,1),-webkit-transform .1s cubic-bezier(.4,0,.2,1); transform-origin: 0 0; } From 2028e56f48c1d7cc7e5471e047dcd7c495f020ad Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 12:40:09 -0300 Subject: [PATCH 07/23] using props, not state for selected --- client/coral-ui/components/Dropdown.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/client/coral-ui/components/Dropdown.js b/client/coral-ui/components/Dropdown.js index 8b30f6fbe..820f33346 100644 --- a/client/coral-ui/components/Dropdown.js +++ b/client/coral-ui/components/Dropdown.js @@ -10,27 +10,12 @@ class Dropdown extends React.Component { constructor(props) { super(props); this.state = { - selected: { - label: props.label || '', - value: props.value || '' - }, isOpen: false }; } - - componentWillReceiveProps(newProps) { - if (newProps.value && newProps.value !== this.state.selected.value) { - this.setState({ - selected: { - label: newProps.label, - value: newProps.value - } - }); - } - } fireChange = (newState) => { - if (newState.selected !== this.state.selected && this.props.onChange) { + if (this.props.onChange) { this.props.onChange(newState.selected.value); } } From 7fcc7753f854a0f8a4caa27e2c98db6e2a30dda5 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 10 Oct 2017 12:50:31 -0300 Subject: [PATCH 08/23] Update --- .../src/routes/Community/components/Table.js | 12 ++++----- .../src/routes/Stories/components/Stories.js | 4 +-- client/coral-ui/components/Dropdown.js | 27 +++++++------------ client/coral-ui/components/Option.js | 6 ++--- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/client/coral-admin/src/routes/Community/components/Table.js b/client/coral-admin/src/routes/Community/components/Table.js index 2efa5944b..846287dc1 100644 --- a/client/coral-admin/src/routes/Community/components/Table.js +++ b/client/coral-admin/src/routes/Community/components/Table.js @@ -35,8 +35,8 @@ const Table = ({headers, commenters, onHeaderClickHandler, onRoleChange, onComme label={capitalize(row.status)} placeholder={t('community.status')} onChange={(status) => onCommenterStatusChange(row.id, status)}> - - + - - - + - +