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,32 @@ +div.tabsContainer { + color: var(--fg); + display: flex; + flex-direction: column; + overflow: hidden; +} +div.tabsHeaderContainer { + display: flex; +} + +div.tabHeader { + flex: 1; + cursor: pointer; + padding: 16px; + display: flex; + justify-content: center; +} + +div.activeTabHeader { + cursor: default; + color: var(--tabs-header-active-color); + border-bottom: 2px solid var(--tabs-header-active-border); +} +div.backgroundTabHeader { + color: var(--tabs-header-background-color); + border-bottom: 2px solid var(--tabs-header-background-border); +} + +div.backgroundTabHeader:hover { + color: var(--tabs-header-background-color-hover); + border-bottom: 2px solid 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,60 @@ +// @flow + +import classnames from 'classnames'; +import * as React from 'react'; + +import css from './tabs.css'; + +export type TabInfo = { + id: string, + header: string | React.Node, + content: React.Node, +}; + +type Props = { + +tabs: $ReadOnlyArray, + +activeTab: string, + +setTab: string => mixed, +}; + +function Tabs(props: Props): React.Node { + const { tabs, activeTab, setTab } = props; + + const headers = React.useMemo( + () => + tabs.map(tab => { + const isActive = tab.id === activeTab; + const headerClasses = classnames(css.tabHeader, { + [css.activeTabHeader]: isActive, + [css.backgroundTabHeader]: !isActive, + }); + return ( +
setTab(tab.id)} + > + {tab.header} +
+ ); + }), + [activeTab, setTab, tabs], + ); + + const content = React.useMemo(() => { + const currentTab = tabs.find(tab => tab.id === activeTab); + if (currentTab) { + return currentTab.content; + } + return null; + }, [activeTab, tabs]); + + return ( +
+
{headers}
+ {content} +
+ ); +} + +export default Tabs; diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -114,4 +114,10 @@ --search-clear-color: var(--shades-black-60); --search-input-color: var(--shades-white-100); --search-input-placeholder: 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); }