From 870df8c47f29a823602455dbba3a9cbf2e254538 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 19 Jan 2018 15:40:45 +0100 Subject: [PATCH 1/5] Tabbable component --- .eslintrc | 1 + src/components/base/Box/index.js | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 8771a924..9cac6933 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,6 +7,7 @@ "__DEV__": false, "__PROD__": false, "__static": false, + "window": false, }, "rules": { "camelcase": 0, diff --git a/src/components/base/Box/index.js b/src/components/base/Box/index.js index 7803f153..cc440d3a 100644 --- a/src/components/base/Box/index.js +++ b/src/components/base/Box/index.js @@ -1,6 +1,6 @@ // @flow -import React from 'react' +import React, { PureComponent } from 'react' import styled from 'styled-components' import { alignItems, @@ -79,4 +79,21 @@ export const GrowScroll = (props: *) => ( ) +export class Tabbable extends PureComponent { + componentDidMount() { + window.addEventListener('keydown', this.handleKeydown) + } + componentWillUnmount() { + window.removeEventListener('keydown', this.handleKeydown) + } + handleKeydown = (e: SyntheticKeyboardEvent) => { + if (e.which === 13 && this.props.onClick) { + this.props.onClick(e) + } + } + render() { + return + } +} + export default Box From cf362b801c5db28953e5207d39f19bac12ea5610 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 19 Jan 2018 15:41:38 +0100 Subject: [PATCH 2/5] Tabs component & story --- package.json | 1 + src/components/base/Tabs/index.js | 50 +++++++++++++++++++++++++++++ src/components/base/Tabs/stories.js | 28 ++++++++++++++++ src/styles/theme.js | 1 + yarn.lock | 6 ++++ 5 files changed, 86 insertions(+) create mode 100644 src/components/base/Tabs/index.js create mode 100644 src/components/base/Tabs/stories.js diff --git a/package.json b/package.json index 97e241d8..f643d433 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "lodash": "^4.17.4", "object-path": "^0.11.4", "react": "^16.2.0", + "react-collapse": "^4.0.3", "react-dom": "^16.2.0", "react-i18next": "^7.3.1", "react-mortal": "^3.0.1", diff --git a/src/components/base/Tabs/index.js b/src/components/base/Tabs/index.js new file mode 100644 index 00000000..d2b6040f --- /dev/null +++ b/src/components/base/Tabs/index.js @@ -0,0 +1,50 @@ +// @flow + +import React, { Fragment } from 'react' +import { Collapse } from 'react-collapse' +import styled from 'styled-components' + +import type { Element } from 'react' + +import Box, { Tabbable } from 'components/base/Box' + +const Tab = styled(Tabbable).attrs({ + flex: 1, + pb: 1, + align: 'center', + justify: 'center', +})` + border-bottom: 2px solid transparent; + border-bottom-color: ${p => (p.isActive ? p.theme.colors.blue : '')}; + color: ${p => (p.isActive ? p.theme.colors.blue : p.theme.colors.steel)}; + font-weight: ${p => (p.isActive ? 'bold' : '')}; + margin-bottom: -1px; + outline: none; +` + +type Item = { + key: string | number, + title: string | Element, + render: () => Element, +} + +type Props = { + items: Array, + index: number, + onTabClick: number => void, +} + +const Tabs = ({ items, index, onTabClick }: Props) => ( + + + {items.map((item, i) => ( + onTabClick(i)}> + {item.title} + + ))} + + {items[index] && {items[index].render()}} + +) + +export default Tabs diff --git a/src/components/base/Tabs/stories.js b/src/components/base/Tabs/stories.js new file mode 100644 index 00000000..5cbb22b7 --- /dev/null +++ b/src/components/base/Tabs/stories.js @@ -0,0 +1,28 @@ +import React from 'react' + +import { number } from '@storybook/addon-knobs' +import { action } from '@storybook/addon-actions' +import { storiesOf } from '@storybook/react' + +import Tabs from 'components/base/Tabs' + +const stories = storiesOf('Tabs', module) + +stories.add('basic', () => ( +
{'first tab content'}
, + }, + { + key: 'second', + title: 'second tab', + render: () =>
{'second tab content'}
, + }, + ]} + /> +)) diff --git a/src/styles/theme.js b/src/styles/theme.js index 9631ddc4..a4a8f46d 100644 --- a/src/styles/theme.js +++ b/src/styles/theme.js @@ -6,6 +6,7 @@ export default { white: '#ffffff', argile: '#eeeeee', + blue: '#6193ff', cream: '#f9f9f9', grenade: '#ea2e49', lead: '#999999', diff --git a/yarn.lock b/yarn.lock index ddd2614e..d476edf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7164,6 +7164,12 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7, rc@^1.2.1: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-collapse@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/react-collapse/-/react-collapse-4.0.3.tgz#b96de959ed0092a43534630b599a4753dd76d543" + dependencies: + prop-types "^15.5.8" + react-color@^2.11.4: version "2.13.8" resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.13.8.tgz#bcc58f79a722b9bfc37c402e68cd18f26970aee4" From 1f8532fd21108cf511395254cf0a745abe1b792b Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 19 Jan 2018 15:55:44 +0100 Subject: [PATCH 3/5] Sidebar style --- src/components/SideBar/Item.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/SideBar/Item.js b/src/components/SideBar/Item.js index 0c7d4f31..0e177da9 100644 --- a/src/components/SideBar/Item.js +++ b/src/components/SideBar/Item.js @@ -46,7 +46,11 @@ const Container = styled(Box).attrs({ p: 2, })` cursor: pointer; - color: ${p => (p.active ? p.theme.colors.white : '')}; + color: ${p => (p.isActive ? p.theme.colors.white : '')}; + background: ${p => (p.isActive ? 'rgba(255, 255, 255, 0.05)' : '')}; + box-shadow: ${p => + p.isActive ? `${p.theme.colors.blue} 4px 0 0 inset` : `${p.theme.colors.blue} 0 0 0 inset`}; + transition: ease-in-out 100ms box-shadow; &:hover { background: rgba(255, 255, 255, 0.05); @@ -54,9 +58,9 @@ const Container = styled(Box).attrs({ ` const IconWrapper = styled(Box)` - width: 30px; - height: 30px; - border: 2px solid rgba(255, 255, 255, 0.1); + width: 25px; + height: 25px; + border: 2px solid ${p => (p.isActive ? p.theme.colors.blue : 'rgba(255, 255, 255, 0.1)')}; ` function Item({ @@ -71,15 +75,19 @@ function Item({ isModalOpened, }: Props) { const { pathname } = location - const active = pathname === linkTo || isModalOpened + const isActive = pathname === linkTo || isModalOpened return ( push(linkTo)) : modal ? () => openModal(modal) : void 0 + linkTo + ? isActive ? undefined : () => push(linkTo) + : modal ? () => openModal(modal) : void 0 } - active={active} + isActive={isActive} > - {icon || null} + + {icon || null} +
{children} From 543e115a42d8623c950620691793e85cfb3b2f38 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 19 Jan 2018 17:12:53 +0100 Subject: [PATCH 4/5] Add tabs to SettingsPage --- package.json | 1 - .../Profile.js} | 9 ++- src/components/SettingsPage/index.js | 70 +++++++++++++++++++ src/components/base/Tabs/index.js | 35 ++++++---- yarn.lock | 6 -- 5 files changed, 96 insertions(+), 25 deletions(-) rename src/components/{SettingsPage.js => SettingsPage/Profile.js} (96%) create mode 100644 src/components/SettingsPage/index.js diff --git a/package.json b/package.json index f643d433..97e241d8 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "lodash": "^4.17.4", "object-path": "^0.11.4", "react": "^16.2.0", - "react-collapse": "^4.0.3", "react-dom": "^16.2.0", "react-i18next": "^7.3.1", "react-mortal": "^3.0.1", diff --git a/src/components/SettingsPage.js b/src/components/SettingsPage/Profile.js similarity index 96% rename from src/components/SettingsPage.js rename to src/components/SettingsPage/Profile.js index 9cc1dbb0..64eb6f08 100644 --- a/src/components/SettingsPage.js +++ b/src/components/SettingsPage/Profile.js @@ -16,7 +16,7 @@ import type { Settings } from 'types/common' import { saveSettings } from 'actions/settings' import { unlock } from 'reducers/application' -import Box from 'components/base/Box' +import Box, { Card } from 'components/base/Box' import Input from 'components/base/Input' import Button from 'components/base/Button' @@ -33,6 +33,7 @@ type Props = { unlock: Function, } type State = { + tab: number, inputValue: InputValue, } @@ -93,11 +94,9 @@ class SettingsPage extends PureComponent { render() { const { inputValue } = this.state - return (
- - {'settings'} + { - + ) } diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js new file mode 100644 index 00000000..52f85f8b --- /dev/null +++ b/src/components/SettingsPage/index.js @@ -0,0 +1,70 @@ +// @flow + +import React, { PureComponent } from 'react' + +import Box from 'components/base/Box' +import Text from 'components/base/Text' +import Tabs from 'components/base/Tabs' + +import TabProfile from './Profile' + +class SettingsPage extends PureComponent { + state = { + tab: 'profile', + } + + handleChangeTab = tab => this.setState({ tab }) + + render() { + const { tab } = this.state + + return ( + + {'Settings'} +
{'Affichage'}
, + }, + { + key: 'money', + title: 'Monnaie', + render: () =>
{'Monnaie'}
, + }, + { + key: 'material', + title: 'Matériel', + render: () =>
{'Matériel'}
, + }, + { + key: 'app', + title: 'App (beta)', + render: () =>
{'App (beta)'}
, + }, + { + key: 'tools', + title: 'Outils', + render: () =>
{'Outils'}
, + }, + { + key: 'blockchain', + title: 'Blockchain', + render: () =>
{'Blockchain'}
, + }, + { + key: 'profile', + title: 'Profil', + render: () => , + }, + ]} + /> +
+ ) + } +} + +export default SettingsPage diff --git a/src/components/base/Tabs/index.js b/src/components/base/Tabs/index.js index d2b6040f..1615ff81 100644 --- a/src/components/base/Tabs/index.js +++ b/src/components/base/Tabs/index.js @@ -1,8 +1,8 @@ // @flow import React, { Fragment } from 'react' -import { Collapse } from 'react-collapse' import styled from 'styled-components' +import isString from 'lodash/isString' import type { Element } from 'react' @@ -13,6 +13,7 @@ const Tab = styled(Tabbable).attrs({ pb: 1, align: 'center', justify: 'center', + fontSize: 1, })` border-bottom: 2px solid transparent; border-bottom-color: ${p => (p.isActive ? p.theme.colors.blue : '')}; @@ -20,6 +21,7 @@ const Tab = styled(Tabbable).attrs({ font-weight: ${p => (p.isActive ? 'bold' : '')}; margin-bottom: -1px; outline: none; + cursor: ${p => (p.isActive ? 'default' : 'pointer')}; ` type Item = { @@ -34,17 +36,24 @@ type Props = { onTabClick: number => void, } -const Tabs = ({ items, index, onTabClick }: Props) => ( - - - {items.map((item, i) => ( - onTabClick(i)}> - {item.title} - - ))} - - {items[index] && {items[index].render()}} - -) +const Tabs = ({ items, index, onTabClick }: Props) => { + const item = isString(index) ? items.find(item => item.key === index) : items[index] + return ( + + + {items.map((item, i) => ( + onTabClick(i)} + > + {item.title} + + ))} + + {item && item.render()} + + ) +} export default Tabs diff --git a/yarn.lock b/yarn.lock index d476edf8..ddd2614e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7164,12 +7164,6 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7, rc@^1.2.1: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-collapse@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/react-collapse/-/react-collapse-4.0.3.tgz#b96de959ed0092a43534630b599a4753dd76d543" - dependencies: - prop-types "^15.5.8" - react-color@^2.11.4: version "2.13.8" resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.13.8.tgz#bcc58f79a722b9bfc37c402e68cd18f26970aee4" From af69d7f5126859c75f18301656f13472fd85fa90 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 19 Jan 2018 17:33:09 +0100 Subject: [PATCH 5/5] Work on SettingsPage --- src/components/SettingsPage/Profile.js | 1 - src/components/SettingsPage/index.js | 10 ++++++-- src/components/base/Box/index.js | 6 ++++- src/components/base/Tabs/index.js | 32 ++++++++++---------------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/components/SettingsPage/Profile.js b/src/components/SettingsPage/Profile.js index 64eb6f08..9a9790c8 100644 --- a/src/components/SettingsPage/Profile.js +++ b/src/components/SettingsPage/Profile.js @@ -33,7 +33,6 @@ type Props = { unlock: Function, } type State = { - tab: number, inputValue: InputValue, } diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index 52f85f8b..328c3695 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -8,12 +8,18 @@ import Tabs from 'components/base/Tabs' import TabProfile from './Profile' +type Props = {} + +type State = { + tab: number, +} + class SettingsPage extends PureComponent { state = { - tab: 'profile', + tab: 6, } - handleChangeTab = tab => this.setState({ tab }) + handleChangeTab = (tab: number) => this.setState({ tab }) render() { const { tab } = this.state diff --git a/src/components/base/Box/index.js b/src/components/base/Box/index.js index cc440d3a..1764dd5e 100644 --- a/src/components/base/Box/index.js +++ b/src/components/base/Box/index.js @@ -59,7 +59,7 @@ const RawCard = styled(Box).attrs({ bg: 'white', p: 3 })` border-radius: 5px; ` -export const Card = ({ title, ...props }: { title: string }) => { +export const Card = ({ title, ...props }: { title?: string }) => { if (title) { return ( @@ -73,6 +73,10 @@ export const Card = ({ title, ...props }: { title: string }) => { return } +Card.defaultProps = { + title: undefined, +} + export const GrowScroll = (props: *) => ( diff --git a/src/components/base/Tabs/index.js b/src/components/base/Tabs/index.js index 1615ff81..a8d847ab 100644 --- a/src/components/base/Tabs/index.js +++ b/src/components/base/Tabs/index.js @@ -2,7 +2,6 @@ import React, { Fragment } from 'react' import styled from 'styled-components' -import isString from 'lodash/isString' import type { Element } from 'react' @@ -36,24 +35,17 @@ type Props = { onTabClick: number => void, } -const Tabs = ({ items, index, onTabClick }: Props) => { - const item = isString(index) ? items.find(item => item.key === index) : items[index] - return ( - - - {items.map((item, i) => ( - onTabClick(i)} - > - {item.title} - - ))} - - {item && item.render()} - - ) -} +const Tabs = ({ items, index, onTabClick }: Props) => ( + + + {items.map((item, i) => ( + onTabClick(i)}> + {item.title} + + ))} + + {items[index] && items[index].render()} + +) export default Tabs