diff --git a/web/chat/chat-tabs.react.js b/web/chat/chat-tabs.react.js index 89c0117ec..c94fddedc 100644 --- a/web/chat/chat-tabs.react.js +++ b/web/chat/chat-tabs.react.js @@ -1,75 +1,79 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { unreadBackgroundCount } from 'lib/selectors/thread-selectors.js'; import css from './chat-tabs.css'; import ChatThreadList from './chat-thread-list.react.js'; import ChatThreadTab from './chat-thread-tab.react.js'; import { ThreadListContext } from './thread-list-provider.js'; import Tabs from '../components/tabs.react.js'; import { useSelector } from '../redux/redux-utils.js'; function ChatTabs(): React.Node { let backgroundTitle = 'Background'; const unreadBackgroundCountVal = useSelector(unreadBackgroundCount); if (unreadBackgroundCountVal) { backgroundTitle += ` (${unreadBackgroundCountVal})`; } const threadListContext = React.useContext(ThreadListContext); invariant( threadListContext, 'threadListContext should be set in ChatThreadList', ); const { activeTab, setActiveTab } = threadListContext; const setActiveChatTab = React.useCallback( (newTab: 'Background' | 'Focus') => { setActiveTab(newTab); }, [setActiveTab], ); const chatThreadList = React.useMemo( () => (
), [], ); const focusTabsItem = React.useMemo( () => ( }> {chatThreadList} ), [chatThreadList], ); const backgroundTabsItem = React.useMemo( () => ( } > {chatThreadList} ), [backgroundTitle, chatThreadList], ); return (
- + {focusTabsItem} {backgroundTabsItem}
); } export default ChatTabs; diff --git a/web/components/tabs-header.js b/web/components/tabs-header.js index cda07934c..a59162562 100644 --- a/web/components/tabs-header.js +++ b/web/components/tabs-header.js @@ -1,29 +1,34 @@ // @flow import classnames from 'classnames'; import * as React from 'react'; import Button from './button.react.js'; -import css from './tabs.css'; +import cssPill from './tabs-pill.css'; +import cssUnderline from './tabs-underline.css'; + +export type TabsHeaderStyle = 'pill' | 'underline'; type Props = { +children: React.Node, +isActive: boolean, +setTab: T => mixed, +id: T, + +headerStyle?: TabsHeaderStyle, }; function TabsHeader(props: Props): React.Node { - const { children, isActive, setTab, id } = props; + const { children, isActive, setTab, id, headerStyle = 'underline' } = props; + const css = headerStyle === 'pill' ? cssPill : cssUnderline; const headerClasses = classnames(css.tabHeader, { [css.backgroundTabHeader]: !isActive, }); const onClickSetTab = React.useCallback(() => setTab(id), [setTab, id]); return ( ); } export default TabsHeader; diff --git a/web/components/tabs.css b/web/components/tabs-pill.css similarity index 94% rename from web/components/tabs.css rename to web/components/tabs-pill.css index cf0e3dc99..fa7af224a 100644 --- a/web/components/tabs.css +++ b/web/components/tabs-pill.css @@ -1,46 +1,46 @@ div.tabsContainer { color: var(--fg); display: flex; flex-direction: column; overflow: hidden; max-height: 100%; flex: 1; } div.tabsHeaderContainer { border-bottom: 1px solid var(--border); height: 56px; } .tabsHeaderContainerPill { display: flex; background-color: var(--menu-bg); border-radius: 8px; margin: 8px; align-items: center; } .tabHeader { flex: 1; font-size: var(--s-font-14); font-weight: var(--semi-bold); color: var(--tabs-header-active-color); height: 32px; border-radius: 4px; background-color: var(--tabs-header-active-background); margin: 4px; } .backgroundTabHeader { - color: var(--tabs-header-background-color); + color: var(--tabs-header-background-color-pill); background-color: transparent; } .backgroundTabHeader:hover { color: var(--tabs-header-background-color-hover); transition: color 100ms; } .backgroundTabHeader:not(:hover) { transition: color 100ms; } diff --git a/web/components/tabs-underline.css b/web/components/tabs-underline.css new file mode 100644 index 000000000..7bfe8eb9b --- /dev/null +++ b/web/components/tabs-underline.css @@ -0,0 +1,35 @@ +div.tabsContainer { + color: var(--fg); + display: flex; + flex-direction: column; + overflow: hidden; + max-height: 100%; + flex: 1; +} + +div.tabsHeaderContainer { + display: flex; +} + +.tabsHeaderContainerPill { + display: flex; + width: 100%; +} + +.tabHeader { + flex: 1; + padding: 16px; + font-size: var(--m-font-16); + color: var(--tabs-header-active-color); + border-bottom: 2px solid var(--tabs-header-active-border); +} + +.backgroundTabHeader { + color: var(--tabs-header-background-color); + border-bottom-color: var(--tabs-header-background-border); +} + +.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 index 2a0141b80..b8814b787 100644 --- a/web/components/tabs.react.js +++ b/web/components/tabs.react.js @@ -1,60 +1,70 @@ // @flow import * as React from 'react'; import TabsHeader from './tabs-header.js'; -import css from './tabs.css'; +import type { TabsHeaderStyle } from './tabs-header.js'; +import cssPill from './tabs-pill.css'; +import cssUnderline from './tabs-underline.css'; type TabsContainerProps = { +children?: React.ChildrenArray>, +activeTab: T, +setTab: T => mixed, + +headerStyle?: TabsHeaderStyle, }; function TabsContainer(props: TabsContainerProps): React.Node { - const { children, activeTab, setTab } = props; + const { children, activeTab, setTab, headerStyle = 'underline' } = props; + + const css = headerStyle === 'pill' ? cssPill : cssUnderline; 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 index e1ca24847..0b7a35a08 100644 --- a/web/theme.css +++ b/web/theme.css @@ -1,205 +1,206 @@ :root { /* Never use color values defined here directly in CSS. Add color variables to "Color Theme" below The reason we never use color values defined here directly in CSS is 1. It makes changing themes from light / dark / user generated impossible. 2. Gives the programmer context into the color being used. 3. If our color system changes it's much easier to change color values in one place. Add a color value to the theme below, and then use it in your CSS. naming convention: - bg: background. - fg: foreground. - color: text-color */ --shades-white-100: #ffffff; --shades-white-90: #f5f5f5; --shades-white-80: #ebebeb; --shades-white-70: #e0e0e0; --shades-white-60: #cccccc; --shades-black-100: #0a0a0a; --shades-black-90: #1f1f1f; --shades-black-80: #404040; --shades-black-70: #666666; --shades-black-60: #808080; --violet-dark-100: #7e57c2; --violet-dark-80: #6d49ab; --violet-dark-60: #563894; --violet-dark-40: #44297a; --violet-dark-20: #331f5c; --violet-light-100: #ae94db; --violet-light-80: #b9a4df; --violet-light-60: #d3c6ec; --violet-light-40: #e8e0f5; --violet-light-20: #f3f0fa; --success-light-10: #d5f6e3; --success-light-50: #6cdf9c; --success-primary: #00c853; --success-dark-50: #029841; --success-dark-90: #034920; --error-light-10: #feebe6; --error-light-50: #f9947b; --error-primary: #f53100; --error-dark-50: #b62602; --error-dark-90: #4f1203; --logo-bg: #111827; --spoiler-color: #33332c; --loading-foreground: #1b0e38; --bg: var(--shades-black-100); --fg: var(--shades-white-100); --color-disabled: var(--shades-black-60); --text-input-bg: var(--shades-black-80); --text-input-color: var(--shades-white-60); --text-input-placeholder: var(--shades-white-60); --border: var(--shades-black-80); --error: var(--error-primary); --success: var(--success-dark-50); /* Color Theme */ --btn-bg-filled: var(--violet-dark-100); --btn-bg-outline: var(--shades-black-90); --btn-bg-success: var(--success-dark-50); --btn-bg-danger: var(--error-primary); --btn-bg-disabled: var(--shades-black-80); --btn-disabled-color: var(--shades-black-60); --chat-bg: var(--violet-dark-80); --chat-confirmation-icon: var(--violet-dark-100); --keyserver-selection: var(--violet-dark-60); --thread-selection: var(--violet-light-80); --thread-hover-bg: var(--shades-black-80); --thread-active-bg: var(--shades-black-80); --chat-timestamp-color: var(--shades-black-60); --tool-tip-bg: var(--shades-black-80); --tool-tip-color: var(--shades-white-60); --border-color: var(--shades-black-80); --calendar-chevron: var(--shades-black-60); --calendar-day-bg: var(--shades-black-60); --calendar-day-selected-color: var(--violet-dark-80); --community-bg: var(--shades-black-90); --community-settings-selected: var(--violet-dark-60); --unread-bg: var(--error-primary); --settings-btn-bg: var(--violet-dark-100); --modal-bg: var(--shades-black-90); --modal-fg: var(--shades-white-60); --join-bg: var(--shades-black-90); --help-color: var(--shades-black-60); --breadcrumb-color: var(--shades-white-60); --breadcrumb-color-unread: var(--shades-white-60); --btn-outline-border: var(--shades-black-60); --thread-color-read: var(--shades-black-60); --thread-preview-secondary: var(--shades-black-70); --relationship-button-green: var(--success-dark-50); --relationship-button-red: var(--error-primary); --relationship-button-text: var(--fg); --disconnected-bar-alert-bg: var(--error-dark-50); --disconnected-bar-alert-color: var(--shades-white-100); --disconnected-bar-connecting-bg: var(--shades-white-70); --disconnected-bar-connecting-color: var(--shades-black-100); --permission-color: var(--shades-white-60); --thread-top-bar-color: var(--shades-white-100); --thread-top-bar-menu-color: var(--shades-white-70); --thread-ancestor-keyserver-border: var(--shades-black-70); --thread-ancestor-color-light: var(--shades-white-70); --thread-ancestor-color-dark: var(--shades-black-100); --thread-ancestor-separator-color: var(--shades-white-60); --text-message-default-background: var(--shades-black-80); --message-action-tooltip-bg: var(--shades-black-90); --message-action-tooltip-bg-light: var(--shades-black-80); --menu-bg: var(--shades-black-90); --menu-bg-light: var(--shades-black-80); --menu-separator-color: var(--shades-black-80); --menu-color: var(--shades-black-60); --menu-color-light: var(--shades-white-60); --menu-color-hover: var(--shades-white-100); --menu-color-dangerous: var(--error-primary); --menu-color-dangerous-hover: var(--error-light-50); --app-list-icon-read-only-color: var(--shades-black-60); --app-list-icon-enabled-color: var(--success-primary); --app-list-icon-disabled-color: var(--shades-white-80); --account-settings-label: var(--shades-black-60); --account-button-color: var(--violet-dark-100); --chat-thread-list-color-active: var(--shades-white-60); --chat-thread-list-menu-color: var(--shades-white-60); --chat-thread-list-menu-bg: var(--shades-black-80); --chat-thread-list-menu-active-color: var(--shades-white-60); --chat-thread-list-menu-active-bg: var(--shades-black-90); --search-clear-color: var(--shades-white-100); --search-clear-bg: var(--shades-black-70); --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-active-background: var(--violet-dark-100); - --tabs-header-background-color: var(--shades-white-60); + --tabs-header-background-color: var(--shades-black-60); + --tabs-header-background-color-pill: var(--shades-white-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); --members-modal-member-text: var(--shades-black-60); --members-modal-member-text-hover: var(--shades-white-100); --label-default-bg: var(--violet-dark-80); --label-default-color: var(--shades-white-80); --subchannels-modal-color: var(--shades-black-60); --subchannels-modal-color-hover: var(--shades-white-100); --color-selector-active-bg: var(--shades-black-80); --relationship-modal-color: var(--shades-black-60); --arrow-extension-color: var(--shades-black-60); --modal-close-color: var(--shades-black-60); --modal-close-color-hover: var(--shades-white-100); --add-members-group-header-color: var(--shades-black-60); --add-members-item-color: var(--shades-black-60); --add-members-item-color-hover: var(--shades-white-100); --add-members-item-disabled-color: var(--shades-black-80); --add-members-item-disabled-color-hover: var(--shades-black-60); --add-members-remove-pending-color: var(--error-primary); --add-members-remove-pending-color-hover: var(--error-light-50); --radio-border: var(--shades-black-70); --radio-color: var(--shades-white-60); --notification-settings-option-selected-bg: var(--shades-black-80); --notification-settings-option-title-color: var(--shades-white-90); --notification-settings-option-color: var(--shades-white-60); --notification-settings-option-invalid-color: var(--shades-black-80); --notification-settings-option-invalid-selected-color: var(--shades-black-60); --danger-zone-subheading-color: var(--shades-white-60); --danger-zone-explanation-color: var(--shades-black-60); --thread-creation-search-container-bg: var(--shades-black-90); --thread-creation-close-search-color: var(--shades-black-60); --thread-creation-search-item-bg-hover: var(--shades-black-80); --thread-creation-search-item-info-color: var(--shades-black-60); --chat-message-list-active-border: #5989d6; --sidebars-modal-color: var(--shades-black-60); --sidebars-modal-color-hover: var(--shades-white-100); --inline-engagement-bg: var(--shades-black-70); --inline-engagement-bg-hover: var(--shades-black-80); --inline-engagement-color: var(--fg); --compose-subchannel-header-fg: var(--shades-black-60); --compose-subchannel-header-bg: var(--shades-black-80); --compose-subchannel-label-color: var(--shades-black-60); --compose-subchannel-mark-color: var(--violet-light-100); --enum-option-icon-color: var(--violet-dark-100); --show-password-bg-hover: var(--shades-black-70); --typeahead-overlay-light: var(--shades-black-80); --typeahead-overlay-dark: var(--shades-black-90); --typeahead-overlay-text: var(--shades-white-100); --typeahead-overlay-shadow-primary: rgba(0, 0, 0, 0.25); --typeahead-overlay-shadow-secondary: rgba(0, 0, 0, 0.4); --spoiler-text-color: var(--spoiler-color); --spoiler-background-color: var(--spoiler-color); --purple-link: var(--violet-light-100); --drawer-expand-button: var(--shades-black-60); --drawer-expand-button-disabled: var(--shades-black-80); --drawer-item-color: var(--shades-white-60); --drawer-active-item-color: var(--shades-white-100); --drawer-open-community-bg: #191919; --active-drawer-item-bg: rgba(0, 0, 0, 0.5); --community-drawer-lines: rgba(255, 255, 255, 0.08); }