diff --git a/web/components/tabs-header.js b/web/components/tabs-header.js new file mode 100644 --- /dev/null +++ b/web/components/tabs-header.js @@ -0,0 +1,28 @@ +// @flow + +import classnames from 'classnames'; +import * as React from 'react'; + +import css from './tabs.css'; + +type Props = { + +children?: React.Node, + +isActive: boolean, + +setTab: T => mixed, + +id: T, +}; + +function TabsHeader(props: Props): React.Node { + const { children, isActive, setTab, id } = props; + const headerClasses = classnames(css.tabHeader, { + [css.backgroundTabHeader]: !isActive, + }); + const onClickSetTab = React.useCallback(() => setTab(id), [setTab, id]); + return ( +
+ {children} +
+ ); +} + +export default TabsHeader; diff --git a/web/components/tabs.css b/web/components/tabs.css new file mode 100644 --- /dev/null +++ b/web/components/tabs.css @@ -0,0 +1,29 @@ +div.tabsContainer { + color: var(--fg); + display: flex; + flex-direction: column; + overflow: hidden; +} +div.tabsHeaderContainer { + display: flex; +} + +div.tabHeader { + flex: 1; + padding: 16px; + display: flex; + justify-content: center; + color: var(--tabs-header-active-color); + border-bottom: 2px solid var(--tabs-header-active-border); +} + +div.backgroundTabHeader { + cursor: pointer; + color: var(--tabs-header-background-color); + border-bottom-color: var(--tabs-header-background-border); +} + +div.backgroundTabHeader:hover { + color: var(--tabs-header-background-color-hover); + border-bottom-color: var(--tabs-header-background-border-hover); +} diff --git a/web/components/tabs.react.js b/web/components/tabs.react.js new file mode 100644 --- /dev/null +++ b/web/components/tabs.react.js @@ -0,0 +1,58 @@ +// @flow + +import * as React from 'react'; + +import TabsHeader from './tabs-header'; +import css from './tabs.css'; + +type TabsContainerProps = { + +children?: React.ChildrenArray>, + +activeTab: T, + +setTab: T => mixed, +}; + +function TabsContainer(props: TabsContainerProps): React.Node { + const { children, activeTab, setTab } = props; + + const headers = React.Children.map(children, tab => { + const { id, header } = tab.props; + + const isActive = id === activeTab; + return ( + + {header} + + ); + }); + + const currentTab = React.Children.toArray(children).find( + tab => tab.props.id === activeTab, + ); + + const currentContent = currentTab ? currentTab.props.children : null; + + return ( +
+
{headers}
+ {currentContent} +
+ ); +} + +type TabsItemProps = { + +children: React.Node, + +id: T, + +header: React.Node, +}; + +function TabsItem(props: TabsItemProps): React.Node { + const { children } = props; + return children; +} + +const Tabs = { + Container: TabsContainer, + Item: TabsItem, +}; + +export default Tabs; diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -118,4 +118,10 @@ --search-input-color: var(--shades-white-100); --search-input-placeholder: var(--shades-black-60); --search-icon-color: var(--shades-black-60); + --tabs-header-active-color: var(--shades-white-100); + --tabs-header-active-border: var(--violet-light-100); + --tabs-header-background-color: var(--shades-black-60); + --tabs-header-background-border: var(--shades-black-80); + --tabs-header-background-color-hover: var(--shades-white-80); + --tabs-header-background-border-hover: var(--shades-black-70); }