diff --git a/web/chat/thread-menu.react.js b/web/chat/thread-menu.react.js index 78c34a723..62e984d53 100644 --- a/web/chat/thread-menu.react.js +++ b/web/chat/thread-menu.react.js @@ -1,281 +1,291 @@ // @flow import * as React from 'react'; import { leaveThread, leaveThreadActionTypes, } from 'lib/actions/thread-actions'; import { usePromoteSidebar } from 'lib/hooks/promote-sidebar.react'; import { childThreadInfos } from 'lib/selectors/thread-selectors'; import { threadHasPermission, viewerIsMember, threadIsChannel, } from 'lib/shared/thread-utils'; import { type ThreadInfo, threadTypes, threadPermissions, } from 'lib/types/thread-types'; import { useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils'; import MenuItem from '../components/menu-item.react'; import Menu from '../components/menu.react'; import SidebarPromoteModal from '../modals/chat/sidebar-promote-modal.react'; import { useModalContext } from '../modals/modal-provider.react'; import ConfirmLeaveThreadModal from '../modals/threads/confirm-leave-thread-modal.react'; +import ComposeSubchannelModal from '../modals/threads/create/compose-subchannel-modal.react'; import ThreadMembersModal from '../modals/threads/members/members-modal.react'; import ThreadNotificationsModal from '../modals/threads/notifications/notifications-modal.react'; import ThreadSettingsModal from '../modals/threads/settings/thread-settings-modal.react'; import SidebarsModal from '../modals/threads/sidebars/sidebars-modal.react'; import SubchannelsModal from '../modals/threads/subchannels/subchannels-modal.react'; import { useSelector } from '../redux/redux-utils'; import SWMansionIcon from '../SWMansionIcon.react'; import css from './thread-menu.css'; type ThreadMenuProps = { +threadInfo: ThreadInfo, }; function ThreadMenu(props: ThreadMenuProps): React.Node { const { pushModal, popModal } = useModalContext(); const { threadInfo } = props; const { onPromoteSidebar, canPromoteSidebar } = usePromoteSidebar(threadInfo); const onClickSettings = React.useCallback( () => pushModal(), [pushModal, threadInfo.id], ); const settingsItem = React.useMemo(() => { return ( ); }, [onClickSettings]); const onClickMembers = React.useCallback( () => pushModal( , ), [popModal, pushModal, threadInfo.id], ); const membersItem = React.useMemo(() => { if (threadInfo.type === threadTypes.PERSONAL) { return null; } return ( ); }, [onClickMembers, threadInfo.type]); const childThreads = useSelector( state => childThreadInfos(state)[threadInfo.id], ); const hasSidebars = React.useMemo(() => { return childThreads?.some( childThreadInfo => childThreadInfo.type === threadTypes.SIDEBAR, ); }, [childThreads]); const onClickSidebars = React.useCallback( () => pushModal(), [popModal, pushModal, threadInfo.id], ); const sidebarItem = React.useMemo(() => { if (!hasSidebars) { return null; } return ( ); }, [hasSidebars, onClickSidebars]); const canCreateSubchannels = React.useMemo( () => threadHasPermission(threadInfo, threadPermissions.CREATE_SUBCHANNELS), [threadInfo], ); const hasSubchannels = React.useMemo(() => { return !!childThreads?.some(threadIsChannel); }, [childThreads]); const onClickViewSubchannels = React.useCallback( () => pushModal( , ), [popModal, pushModal, threadInfo.id], ); const viewSubchannelsItem = React.useMemo(() => { if (!hasSubchannels) { return null; } return ( ); }, [hasSubchannels, onClickViewSubchannels]); + const onClickCreateSubchannel = React.useCallback( + () => + pushModal( + , + ), + [popModal, pushModal, threadInfo], + ); + const createSubchannelsItem = React.useMemo(() => { if (!canCreateSubchannels) { return null; } return ( ); - }, [canCreateSubchannels]); + }, [canCreateSubchannels, onClickCreateSubchannel]); const dispatchActionPromise = useDispatchActionPromise(); const callLeaveThread = useServerCall(leaveThread); const onConfirmLeaveThread = React.useCallback(() => { dispatchActionPromise( leaveThreadActionTypes, callLeaveThread(threadInfo.id), ); popModal(); }, [callLeaveThread, popModal, dispatchActionPromise, threadInfo.id]); const onClickLeaveThread = React.useCallback( () => pushModal( , ), [popModal, onConfirmLeaveThread, pushModal, threadInfo], ); const leaveThreadItem = React.useMemo(() => { const canLeaveThread = threadHasPermission( threadInfo, threadPermissions.LEAVE_THREAD, ); if (!viewerIsMember(threadInfo) || !canLeaveThread) { return null; } return ( ); }, [onClickLeaveThread, threadInfo]); const onClickPromoteSidebarToThread = React.useCallback( () => pushModal( , ), [pushModal, threadInfo, popModal, onPromoteSidebar], ); const promoteSidebar = React.useMemo(() => { return ( ); }, [onClickPromoteSidebarToThread]); const onClickNotifications = React.useCallback(() => { pushModal( , ); }, [popModal, pushModal, threadInfo.id]); const notificationsItem = React.useMemo(() => { if (!viewerIsMember(threadInfo)) { return null; } return ( ); }, [onClickNotifications, threadInfo]); const menuItems = React.useMemo(() => { const separator =
; - // TODO: Enable menu items when the modals are implemented - const SHOW_CREATE_SUBCHANNELS = false; - const items = [ settingsItem, notificationsItem, membersItem, sidebarItem, viewSubchannelsItem, - SHOW_CREATE_SUBCHANNELS && createSubchannelsItem, + createSubchannelsItem, leaveThreadItem && separator, canPromoteSidebar && promoteSidebar, leaveThreadItem, ]; return items.filter(Boolean); }, [ settingsItem, notificationsItem, membersItem, sidebarItem, viewSubchannelsItem, promoteSidebar, createSubchannelsItem, leaveThreadItem, canPromoteSidebar, ]); const icon = React.useMemo( () => , [], ); return {menuItems}; } export default ThreadMenu; diff --git a/web/modals/threads/create/compose-subchannel-modal.css b/web/modals/threads/create/compose-subchannel-modal.css new file mode 100644 index 000000000..3fbfefe81 --- /dev/null +++ b/web/modals/threads/create/compose-subchannel-modal.css @@ -0,0 +1,30 @@ +div.modalHeader { + padding: 15px; + font-weight: var(--semi-bold); + color: var(--compose-subchannel-header-fg); + background-color: var(--compose-subchannel-header-bg); + display: flex; + align-items: center; + justify-content: center; + margin-top: 30px; +} + +div.modalHeaderParentName { + color: var(--compose-subchannel-mark-color); + display: inline; +} + +div.container { + width: 383px; + overflow-y: auto; +} + +div.stepContainer { + position: relative; + height: 100vh; + max-height: 533px; +} + +div.stepItem { + padding: 20px; +} diff --git a/web/modals/threads/create/compose-subchannel-modal.react.js b/web/modals/threads/create/compose-subchannel-modal.react.js new file mode 100644 index 000000000..e0dae6554 --- /dev/null +++ b/web/modals/threads/create/compose-subchannel-modal.react.js @@ -0,0 +1,190 @@ +// @flow +import * as React from 'react'; + +import type { ThreadInfo } from 'lib/types/thread-types'; +import { trimText } from 'lib/utils/text-utils'; + +import Stepper from '../../../components/stepper.react'; +import Modal from '../../modal.react'; +import css from './compose-subchannel-modal.css'; +import SubchannelMembers from './steps/subchannel-members.react'; +import SubchannelSettings from './steps/subchannel-settings.react'; +import type { VisibilityType } from './steps/subchannel-settings.react'; + +type Props = { + +onClose: () => void, + +parentThreadInfo: ThreadInfo, +}; + +type Steps = 'settings' | 'members'; + +type HeaderProps = { + +parentThreadName: string, +}; + +function ComposeSubchannelHeader(props: HeaderProps): React.Node { + const { parentThreadName } = props; + return ( +
+
+ {'within '} +
{parentThreadName}
+
+
+ ); +} + +function ComposeSubchannelModal(props: Props): React.Node { + const { parentThreadInfo, onClose } = props; + const { uiName: parentThreadName } = parentThreadInfo; + + const [activeStep, setActiveStep] = React.useState('settings'); + + const [channelName, setChannelName] = React.useState(''); + const [visibilityType, setVisibilityType] = React.useState( + 'open', + ); + const [announcement, setAnnouncement] = React.useState(false); + const [selectedUsers, setSelectedUsers] = React.useState< + $ReadOnlySet, + >(new Set()); + const [searchUserText, setSearchUserText] = React.useState(''); + + const onChangeChannelName = React.useCallback( + (event: SyntheticEvent) => { + const target = event.currentTarget; + setChannelName(target.value); + }, + [], + ); + + const onOpenVisibilityTypeSelected = React.useCallback( + () => setVisibilityType('open'), + [], + ); + + const onSecretVisibilityTypeSelected = React.useCallback( + () => setVisibilityType('secret'), + [], + ); + + const onAnnouncementSelected = React.useCallback( + () => setAnnouncement(!announcement), + [announcement], + ); + + const toggleUserSelection = React.useCallback((userID: string) => { + setSelectedUsers((users: $ReadOnlySet) => { + const newUsers = new Set(users); + if (newUsers.has(userID)) { + newUsers.delete(userID); + } else { + newUsers.add(userID); + } + return newUsers; + }); + }, []); + + const subchannelSettings = React.useMemo( + () => ( + + ), + [ + channelName, + visibilityType, + announcement, + onChangeChannelName, + onOpenVisibilityTypeSelected, + onSecretVisibilityTypeSelected, + onAnnouncementSelected, + ], + ); + + const stepperButtons = React.useMemo( + () => ({ + settings: { + nextProps: { + content: 'Next', + disabled: !channelName.trim(), + onClick: () => { + setChannelName(channelName.trim()); + setActiveStep('members'); + }, + }, + }, + members: { + prevProps: { + content: 'Back', + onClick: () => setActiveStep('settings'), + }, + nextProps: { + content: 'Create', + onClick: () => { + // TODO: make form logic + }, + }, + }, + }), + [channelName], + ); + + const subchannelMembers = React.useMemo( + () => ( + + ), + [ + selectedUsers, + toggleUserSelection, + parentThreadInfo, + searchUserText, + setSearchUserText, + ], + ); + + const modalName = + activeStep === 'members' + ? `Create channel - ${trimText(channelName, 11)}` + : 'Create channel'; + + return ( + + +
+
+ + + + +
+
+
+ ); +} + +export default ComposeSubchannelModal; diff --git a/web/modals/threads/create/steps/subchannel-members-list.react.js b/web/modals/threads/create/steps/subchannel-members-list.react.js new file mode 100644 index 000000000..8fa4436bd --- /dev/null +++ b/web/modals/threads/create/steps/subchannel-members-list.react.js @@ -0,0 +1,97 @@ +// @flow + +import * as React from 'react'; +import { useSelector } from 'react-redux'; + +import { stringForUser } from 'lib/shared/user-utils'; +import type { ThreadInfo } from 'lib/types/thread-types'; + +import AddMembersList from '../../../components/add-members-list.react'; + +type Props = { + +searchText: string, + +searchResult: $ReadOnlySet, + +communityThreadInfo: ThreadInfo, + +parentThreadInfo: ThreadInfo, + +selectedUsers: $ReadOnlySet, + +toggleUserSelection: (userID: string) => void, +}; + +function Memberlist(props: Props): React.Node { + const { + searchText, + searchResult, + communityThreadInfo, + parentThreadInfo, + selectedUsers, + toggleUserSelection, + } = props; + + const { members: parentMembers } = parentThreadInfo; + + const { + members: communityMembers, + name: communityName, + } = communityThreadInfo; + + const currentUserId = useSelector(state => state.currentUserInfo.id); + + const parentMembersSet = React.useMemo( + () => new Set(parentThreadInfo.members.map(user => user.id)), + [parentThreadInfo], + ); + + const parentMemberList = React.useMemo( + () => + parentMembers + .filter( + user => + user.id !== currentUserId && + (searchResult.has(user.id) || searchText.length === 0), + ) + .map(user => ({ id: user.id, username: stringForUser(user) })), + + [parentMembers, currentUserId, searchResult, searchText], + ); + + const otherMemberList = React.useMemo( + () => + communityMembers + .filter( + user => + !parentMembersSet.has(user.id) && + user.id !== currentUserId && + (searchResult.has(user.id) || searchText.length === 0), + ) + .map(user => ({ id: user.id, username: stringForUser(user) })), + [ + communityMembers, + parentMembersSet, + currentUserId, + searchResult, + searchText, + ], + ); + + const sortedGroupedUserList = React.useMemo( + () => + [ + { header: 'Users in parent channel', userInfos: parentMemberList }, + { + header: `All users in ${communityName ?? 'community'}`, + userInfos: otherMemberList, + }, + ].filter(item => item.userInfos.length), + [parentMemberList, otherMemberList, communityName], + ); + + return ( + + ); +} + +export default Memberlist; diff --git a/web/modals/threads/create/steps/subchannel-members.css b/web/modals/threads/create/steps/subchannel-members.css new file mode 100644 index 000000000..3dcd4c365 --- /dev/null +++ b/web/modals/threads/create/steps/subchannel-members.css @@ -0,0 +1,10 @@ +.members { + overflow-y: auto; +} + +.searchBar { + background-color: var(--modal-bg); + position: sticky; + padding: 2.5px 0; + top: 0; +} diff --git a/web/modals/threads/create/steps/subchannel-members.react.js b/web/modals/threads/create/steps/subchannel-members.react.js new file mode 100644 index 000000000..cdddb8f17 --- /dev/null +++ b/web/modals/threads/create/steps/subchannel-members.react.js @@ -0,0 +1,64 @@ +// @flow + +import * as React from 'react'; +import { useSelector } from 'react-redux'; + +import { userStoreSearchIndex } from 'lib/selectors/user-selectors'; +import { useAncestorThreads } from 'lib/shared/ancestor-threads'; +import type { ThreadInfo } from 'lib/types/thread-types'; + +import Search from '../../../../components/search.react'; +import MembersList from './subchannel-members-list.react'; +import css from './subchannel-members.css'; + +type SubchannelMembersProps = { + +parentThreadInfo: ThreadInfo, + +selectedUsers: $ReadOnlySet, + +searchText: string, + +setSearchText: string => void, + +toggleUserSelection: (userID: string) => void, +}; + +function SubchannelMembers(props: SubchannelMembersProps): React.Node { + const { + toggleUserSelection, + searchText, + setSearchText, + parentThreadInfo, + selectedUsers, + } = props; + + const ancestorThreads = useAncestorThreads(parentThreadInfo); + + const communityThread = ancestorThreads[0] ?? parentThreadInfo; + + const userSearchIndex = useSelector(userStoreSearchIndex); + const searchResult = React.useMemo( + () => new Set(userSearchIndex.getSearchResults(searchText)), + [userSearchIndex, searchText], + ); + + return ( + <> +
+ +
+
+ +
+ + ); +} + +export default SubchannelMembers; diff --git a/web/modals/threads/create/steps/subchannel-settings.css b/web/modals/threads/create/steps/subchannel-settings.css new file mode 100644 index 000000000..c5cf5f1d0 --- /dev/null +++ b/web/modals/threads/create/steps/subchannel-settings.css @@ -0,0 +1,8 @@ +.wrapper { + color: var(--enum-option-icon-color); +} + +.label { + padding: 20px 0; + color: var(--compose-subchannel-label-color); +} diff --git a/web/modals/threads/create/steps/subchannel-settings.react.js b/web/modals/threads/create/steps/subchannel-settings.react.js new file mode 100644 index 000000000..ea9a3599c --- /dev/null +++ b/web/modals/threads/create/steps/subchannel-settings.react.js @@ -0,0 +1,123 @@ +// @flow + +import * as React from 'react'; + +import { threadTypeDescriptions } from 'lib/shared/thread-utils'; +import { threadTypes } from 'lib/types/thread-types'; + +import CommIcon from '../../../../CommIcon.react'; +import EnumSettingsOption from '../../../../components/enum-settings-option.react'; +import SWMansionIcon from '../../../../SWMansionIcon.react'; +import Input from '../../../input.react'; +import css from './subchannel-settings.css'; + +const { COMMUNITY_OPEN_SUBTHREAD, COMMUNITY_SECRET_SUBTHREAD } = threadTypes; + +const openStatements = [ + { + statement: threadTypeDescriptions[COMMUNITY_OPEN_SUBTHREAD], + isStatementValid: true, + styleStatementBasedOnValidity: false, + }, +]; + +const secretStatements = [ + { + statement: threadTypeDescriptions[COMMUNITY_SECRET_SUBTHREAD], + isStatementValid: true, + styleStatementBasedOnValidity: false, + }, +]; + +const announcementStatements = [ + { + statement: 'Admins can create Announcement channels.', + isStatementValid: true, + styleStatementBasedOnValidity: false, + }, +]; + +export type VisibilityType = 'open' | 'secret'; + +type Props = { + +channelName: string, + +onChangeChannelName: (SyntheticEvent) => void, + +visibilityType: VisibilityType, + +onOpenTypeSelect: () => void, + +onSecretTypeSelect: () => void, + +announcement: boolean, + +onAnnouncementSelected: () => void, +}; + +function SubchannelSettings(props: Props): React.Node { + const { + channelName, + onChangeChannelName, + visibilityType, + onOpenTypeSelect, + onSecretTypeSelect, + announcement, + onAnnouncementSelected, + } = props; + + const globeIcon = React.useMemo( + () => , + [], + ); + + const lockIcon = React.useMemo( + () => , + [], + ); + + const flagIcon = React.useMemo( + () => , + [], + ); + + return ( + <> + + +
+
Visibility
+ + +
+ +
+
Optional settings
+ +
+ + ); +} + +export default SubchannelSettings; diff --git a/web/theme.css b/web/theme.css index 2783cca4a..fb4f71b67 100644 --- a/web/theme.css +++ b/web/theme.css @@ -1,185 +1,190 @@ :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; --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-primary: var(--violet-dark-100); --btn-bg-primary-hover: var(--violet-dark-80); --btn-bg-primary-disabled: var(--shades-black-80); --btn-bg-secondary: var(--shades-black-90); --btn-bg-secondary-hover: var(--shades-black-80); --btn-bg-secondary-disabled: var(--shades-black-90); --btn-bg-success: var(--success-dark-50); --btn-bg-success-hover: var(--success-dark-90); --btn-bg-success-disabled: var(--shades-black-80); --btn-bg-danger: var(--error-primary); --btn-bg-danger-hover: var(--error-dark-50); --btn-bg-danger-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-secondary-border: var(--shades-black-60); --thread-color-read: var(--shades-black-60); --thread-from-color-read: var(--shades-black-80); --thread-last-message-color-read: var(--shades-black-60); --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); --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-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); --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-sidebar-bg: var(--shades-black-70); --inline-sidebar-bg-hover: var(--shades-black-80); --inline-sidebar-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); }