From 4c1bc50649afcf31f403b7b887ecbdc95ba31772 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 16:34:04 -0600 Subject: [PATCH 1/8] Initial styling for new room list This is a work in progress, but covers the coarse areas. This uses all-new classes to better describe what everything is, and to reduce the number of selectors we keep track of. This is primarily layout for the list and not actually the final structure. For example, some buttons are missing and other areas are not styled correctly - the idea in this commit was to get things roughly in the right place and work on it. --- res/css/_components.scss | 3 + res/css/structures/_LeftPanel.scss | 8 -- res/css/structures/_LeftPanel2.scss | 91 +++++++++++++++++++++ res/css/structures/_MatrixChat.scss | 2 +- res/css/views/rooms/_RoomList2.scss | 23 ++++++ res/css/views/rooms/_RoomSublist2.scss | 2 +- res/css/views/rooms/_RoomTile2.scss | 18 ++++ src/components/structures/LeftPanel2.tsx | 63 +++++++++----- src/components/views/rooms/RoomList2.tsx | 2 +- src/components/views/rooms/RoomSublist2.tsx | 21 +++-- src/components/views/rooms/RoomTile2.tsx | 32 ++++---- 11 files changed, 205 insertions(+), 60 deletions(-) create mode 100644 res/css/structures/_LeftPanel2.scss create mode 100644 res/css/views/rooms/_RoomList2.scss create mode 100644 res/css/views/rooms/_RoomTile2.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index b047519d99..62bec5ad62 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -12,6 +12,7 @@ @import "./structures/_HeaderButtons.scss"; @import "./structures/_HomePage.scss"; @import "./structures/_LeftPanel.scss"; +@import "./structures/_LeftPanel2.scss"; @import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; @import "./structures/_MyGroups.scss"; @@ -177,10 +178,12 @@ @import "./views/rooms/_RoomDropTarget.scss"; @import "./views/rooms/_RoomHeader.scss"; @import "./views/rooms/_RoomList.scss"; +@import "./views/rooms/_RoomList2.scss"; @import "./views/rooms/_RoomPreviewBar.scss"; @import "./views/rooms/_RoomRecoveryReminder.scss"; @import "./views/rooms/_RoomSublist2.scss"; @import "./views/rooms/_RoomTile.scss"; +@import "./views/rooms/_RoomTile2.scss"; @import "./views/rooms/_RoomUpgradeWarningBar.scss"; @import "./views/rooms/_SearchBar.scss"; @import "./views/rooms/_SendMessageComposer.scss"; diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index 899824bc57..35d9f0e7da 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -23,14 +23,6 @@ limitations under the License. flex: 0 0 auto; } -// TODO: Remove temporary indicator of new room list implementation. -// This border is meant to visually distinguish between the two components when the -// user has turned on the new room list implementation, at least until the designs -// themselves give it away. -.mx_LeftPanel2 .mx_LeftPanel { - border-left: 5px #e26dff solid; -} - .mx_LeftPanel_container.collapsed { min-width: unset; /* Collapsed LeftPanel 50px */ diff --git a/res/css/structures/_LeftPanel2.scss b/res/css/structures/_LeftPanel2.scss new file mode 100644 index 0000000000..52ee4f16ac --- /dev/null +++ b/res/css/structures/_LeftPanel2.scss @@ -0,0 +1,91 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +$tagPanelWidth: 70px; +$roomListMinimizedWidth: 50px; + +.mx_LeftPanel2 { + background-color: $header-panel-bg-color; + min-width: 260px; + max-width: 50%; + + // Create a row-based flexbox for the TagPanel and the room list + display: flex; + + .mx_LeftPanel2_tagPanelContainer { + flex-grow: 0; + flex-shrink: 0; + flex-basis: $tagPanelWidth; + height: 100%; + + // Create another flexbox so the TagPanel fills the container + display: flex; + + // TagPanel handles its own CSS + } + + // Note: The 'room list' in this context is actually everything that isn't the tag + // panel, such as the menu options, breadcrumbs, filtering, etc + .mx_LeftPanel2_roomListContainer { + width: calc(100% - $tagPanelWidth); + + // Create another flexbox (this time a column) for the room list components + display: flex; + flex-direction: column; + + .mx_LeftPanel2_userHeader { + padding: 14px 12px 20px; // 14px top, 12px sides, 20px bottom + + // Create another flexbox column for the rows to stack within + display: flex; + flex-direction: column; + + // There's 2 rows when breadcrumbs are present: the top bit and the breadcrumbs + .mx_LeftPanel2_headerRow { + // Create yet another flexbox, this time within the row, to ensure items stay + // aligned correctly. This is also a row-based flexbox. + display: flex; + align-items: center; + } + + .mx_LeftPanel2_userAvatarContainer { + position: relative; // to make default avatars work + margin-right: 8px; + } + + .mx_LeftPanel2_userName { + font-weight: 600; + font-size: $font-15px; + line-height: $font-20px; + } + + .mx_LeftPanel2_breadcrumbsContainer { + // TODO: Improve CSS for breadcrumbs (currently shoved into the view rather than placed) + width: 100%; + overflow: hidden; + } + } + + .mx_LeftPanel2_filterContainer { + // TODO: Improve CSS for filtering and its input + } + + .mx_LeftPanel2_actualRoomListContainer { + flex-grow: 1; // fill the available space + overflow-y: auto; + } + } +} diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index 05c703ab6d..08ed9e5559 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -66,7 +66,7 @@ limitations under the License. } /* not the left panel, and not the resize handle, so the roomview/groupview/... */ -.mx_MatrixChat > :not(.mx_LeftPanel_container):not(.mx_ResizeHandle) { +.mx_MatrixChat > :not(.mx_LeftPanel_container):not(.mx_LeftPanel2):not(.mx_ResizeHandle) { background-color: $primary-bg-color; flex: 1 1 0; diff --git a/res/css/views/rooms/_RoomList2.scss b/res/css/views/rooms/_RoomList2.scss new file mode 100644 index 0000000000..add7214468 --- /dev/null +++ b/res/css/views/rooms/_RoomList2.scss @@ -0,0 +1,23 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_RoomList2 { + // Create a column-based flexbox for the sublists. That's pretty much all we have to + // worry about in this stylesheet. + display: flex; + flex-direction: column; + flex-wrap: wrap; +} diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index abc3133fc1..55b16843b3 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -16,7 +16,7 @@ limitations under the License. @import "../../../../node_modules/react-resizable/css/styles.css"; -.mx_RoomList2 .mx_RoomSubList_labelContainer { +.mx_RoomList2 .mx_RoomSubList2_labelContainer { z-index: 12; background-color: purple; } diff --git a/res/css/views/rooms/_RoomTile2.scss b/res/css/views/rooms/_RoomTile2.scss new file mode 100644 index 0000000000..6577f1ce25 --- /dev/null +++ b/res/css/views/rooms/_RoomTile2.scss @@ -0,0 +1,18 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_RoomTile2 { +} diff --git a/src/components/structures/LeftPanel2.tsx b/src/components/structures/LeftPanel2.tsx index c9a4948539..bf0e72beeb 100644 --- a/src/components/structures/LeftPanel2.tsx +++ b/src/components/structures/LeftPanel2.tsx @@ -24,6 +24,9 @@ import SearchBox from "./SearchBox"; import RoomList2 from "../views/rooms/RoomList2"; import TopLeftMenuButton from "./TopLeftMenuButton"; import { Action } from "../../dispatcher/actions"; +import { MatrixClientPeg } from "../../MatrixClientPeg"; +import BaseAvatar from '../views/avatars/BaseAvatar'; +import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs"; /******************************************************************* * CAUTION * @@ -82,24 +85,44 @@ export default class LeftPanel2 extends React.Component { } } + private renderHeader(): React.ReactNode { + // TODO: Use real profile info + // TODO: Presence + // TODO: Breadcrumbs toggle + // TODO: Menu button + const avatarSize = 32; + return ( +
+
+ + + + Irene +
+
+ +
+
+ ); + } + public render(): React.ReactNode { const tagPanel = ( -
+
); - const exploreButton = ( -
- dis.dispatch({action: 'view_room_directory'})}> - {_t("Explore")} - -
- ); - const searchBox = ( { // TODO: Conference handling / calls const containerClasses = classNames({ - "mx_LeftPanel_container": true, - "mx_fadable": true, - "collapsed": false, // TODO: Collapsed support - "mx_LeftPanel_container_hasTagPanel": true, // TODO: TagPanel support - "mx_fadable_faded": false, - "mx_LeftPanel2": true, // TODO: Remove flag when RoomList2 ships (used as an indicator) + "mx_LeftPanel2": true, }); return (
{tagPanel} -
); diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index 15aa880109..af366e9685 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -216,7 +216,7 @@ export default class RoomList2 extends React.Component { onFocus={this.props.onFocus} onBlur={this.props.onBlur} onKeyDown={onKeyDownHandler} - className="mx_RoomList mx_RoomList2" + className="mx_RoomList2" role="tree" aria-label={_t("Rooms")} // Firefox sometimes makes this element focusable due to diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index cc56f92769..e7682a9bb4 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -113,9 +113,9 @@ export default class RoomSublist2 extends React.Component { let chevron = null; if (this.hasTiles()) { const chevronClasses = classNames({ - 'mx_RoomSubList_chevron': true, - 'mx_RoomSubList_chevronRight': false, // isCollapsed - 'mx_RoomSubList_chevronDown': true, // !isCollapsed + 'mx_RoomSublist2_chevron': true, + 'mx_RoomSublist2_chevronRight': false, // isCollapsed + 'mx_RoomSublist2_chevronDown': true, // !isCollapsed }); chevron = (
); } @@ -130,8 +130,8 @@ export default class RoomSublist2 extends React.Component { let badge; if (true) { // !isCollapsed const badgeClasses = classNames({ - 'mx_RoomSubList_badge': true, - 'mx_RoomSubList_badgeHighlight': notifHighlight, + 'mx_RoomSublist2_badge': true, + 'mx_RoomSublist2_badgeHighlight': notifHighlight, }); // Wrap the contents in a div and apply styles to the child div so that the browser default outline works if (notifCount > 0) { @@ -168,7 +168,7 @@ export default class RoomSublist2 extends React.Component { ); @@ -176,11 +176,11 @@ export default class RoomSublist2 extends React.Component { // TODO: a11y (see old component) return ( -
+
@@ -204,9 +204,8 @@ export default class RoomSublist2 extends React.Component { const classes = classNames({ // TODO: Proper collapse support - 'mx_RoomSubList': true, - 'mx_RoomSubList_hidden': false, // len && isCollapsed - 'mx_RoomSubList_nonEmpty': this.hasTiles(), // len && !isCollapsed + 'mx_RoomSublist2': true, + 'mx_RoomSublist2_collapsed': false, // len && isCollapsed }); let content = null; diff --git a/src/components/views/rooms/RoomTile2.tsx b/src/components/views/rooms/RoomTile2.tsx index c95cd108dc..40c7bcbc12 100644 --- a/src/components/views/rooms/RoomTile2.tsx +++ b/src/components/views/rooms/RoomTile2.tsx @@ -195,28 +195,28 @@ export default class RoomTile2 extends React.Component { const hasBadge = this.state.notificationState.color > NotificationColor.Bold; const isUnread = this.state.notificationState.color > NotificationColor.None; const classes = classNames({ - 'mx_RoomTile': true, + 'mx_RoomTile2': true, // 'mx_RoomTile_selected': this.state.selected, - 'mx_RoomTile_unread': isUnread, - 'mx_RoomTile_unreadNotify': this.state.notificationState.color >= NotificationColor.Grey, - 'mx_RoomTile_highlight': this.state.notificationState.color >= NotificationColor.Red, - 'mx_RoomTile_invited': this.roomIsInvite, + 'mx_RoomTile2_unread': isUnread, + 'mx_RoomTile2_unreadNotify': this.state.notificationState.color >= NotificationColor.Grey, + 'mx_RoomTile2_highlight': this.state.notificationState.color >= NotificationColor.Red, + 'mx_RoomTile2_invited': this.roomIsInvite, // 'mx_RoomTile_menuDisplayed': isMenuDisplayed, - 'mx_RoomTile_noBadges': !hasBadge, + 'mx_RoomTile2_noBadges': !hasBadge, // 'mx_RoomTile_transparent': this.props.transparent, // 'mx_RoomTile_hasSubtext': subtext && !this.props.collapsed, }); const avatarClasses = classNames({ - 'mx_RoomTile_avatar': true, + 'mx_RoomTile2_avatar': true, }); let badge; if (hasBadge) { const badgeClasses = classNames({ - 'mx_RoomTile_badge': true, - 'mx_RoomTile_badgeButton': false, // this.state.badgeHover || isMenuDisplayed + 'mx_RoomTile2_badge': true, + 'mx_RoomTile2_badgeButton': false, // this.state.badgeHover || isMenuDisplayed }); badge =
{this.state.notificationState.symbol}
; } @@ -227,16 +227,16 @@ export default class RoomTile2 extends React.Component { name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon const nameClasses = classNames({ - 'mx_RoomTile_name': true, - 'mx_RoomTile_invite': this.roomIsInvite, - 'mx_RoomTile_badgeShown': hasBadge, + 'mx_RoomTile2_name': true, + 'mx_RoomTile2_invite': this.roomIsInvite, + 'mx_RoomTile2_badgeShown': hasBadge, }); // TODO: Support collapsed state properly let tooltip = null; if (false) { // isCollapsed if (this.state.hover) { - tooltip = + tooltip = } } @@ -255,12 +255,12 @@ export default class RoomTile2 extends React.Component { role="treeitem" >
-
+
-
-
+
+
{name}
From 0c15b2bdb6c332713b8e95cb907c6b50adeaeeda Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 21:21:04 -0600 Subject: [PATCH 2/8] Simple structuring of the room list itself This covers the larger parts of the design, but doesn't deal with the nuances of hover states, badge sizing, etc. --- res/css/views/rooms/_RoomSublist2.scss | 26 +++- res/css/views/rooms/_RoomTile2.scss | 76 +++++++++++ res/themes/light/css/_light.scss | 5 + src/components/views/rooms/RoomList2.tsx | 3 +- src/components/views/rooms/RoomSublist2.tsx | 135 ++++++++++---------- src/components/views/rooms/RoomTile2.tsx | 65 ++++------ src/i18n/strings/en_EN.json | 9 +- src/stores/room-list/ListLayout.ts | 2 +- 8 files changed, 205 insertions(+), 116 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 55b16843b3..4d8c3fffff 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -16,7 +16,27 @@ limitations under the License. @import "../../../../node_modules/react-resizable/css/styles.css"; -.mx_RoomList2 .mx_RoomSubList2_labelContainer { - z-index: 12; - background-color: purple; +.mx_RoomSublist2 { + // The sublist is a column of rows, essentially + display: flex; + flex-direction: column; + + margin-left: 8px; + margin-top: 12px; + margin-bottom: 12px; + + .mx_RoomSublist2_headerContainer { + text-transform: uppercase; + opacity: 0.5; + line-height: $font-16px; + font-size: $font-12px; + padding-bottom: 8px; + } + + .mx_RoomSublist2_resizeBox { + // Create another flexbox column for the tiles + display: flex; + flex-direction: column; + overflow: hidden; + } } diff --git a/res/css/views/rooms/_RoomTile2.scss b/res/css/views/rooms/_RoomTile2.scss index 6577f1ce25..bb27942f81 100644 --- a/res/css/views/rooms/_RoomTile2.scss +++ b/res/css/views/rooms/_RoomTile2.scss @@ -14,5 +14,81 @@ See the License for the specific language governing permissions and limitations under the License. */ +// Note: the room tile expects to be in a flexbox column container .mx_RoomTile2 { + width: 100%; + padding-bottom: 12px; + + // The tile is also a flexbox row itself + display: flex; + flex-wrap: wrap; + + .mx_RoomTile2_avatarContainer { + margin-right: 8px; + } + + .mx_RoomTile2_nameContainer { + // Create a new column layout flexbox for the name parts + display: flex; + flex-direction: column; + justify-content: center; + + .mx_RoomTile2_name, + .mx_RoomTile2_messagePreview { + margin: 0 2px; + } + + // TODO: Ellipsis on the name and preview + + .mx_RoomTile2_name { + font-weight: 600; + font-size: $font-14px; + line-height: $font-19px; + } + + .mx_RoomTile2_messagePreview { + font-size: $font-13px; + line-height: $font-18px; + color: $roomtile2-preview-color; + } + } + + .mx_RoomTile2_badgeContainer { + flex-grow: 1; + + // Create another flexbox row because it's super easy to position the badge at + // the end this way. + display: flex; + align-items: center; + justify-content: flex-end; + + .mx_RoomTile2_badge { + background-color: $roomtile2-badge-color; + + &:not(.mx_RoomTile2_badgeEmpty) { + border-radius: 16px; + font-size: $font-10px; + line-height: $font-14px; + text-align: center; + font-weight: bold; + margin-right: 14px; + color: #fff; // TODO: Variable + + // TODO: Confirm padding on counted badges + padding: 2px 5px; + } + + &.mx_RoomTile2_badgeEmpty { + width: 6px; + height: 6px; + border-radius: 6px; + margin-right: 18px; + } + + &.mx_RoomTile2_badgeHighlight { + // TODO: Use a more specific variable + background-color: $warning-color; + } + } + } } diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 78fe2a74c5..683c02528d 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -172,6 +172,11 @@ $header-divider-color: #91A1C0; // ******************** +// TODO: Update variables for new room list +// TODO: Dark theme +$roomtile2-preview-color: #9e9e9e; +$roomtile2-badge-color: #61708b; + $roomtile-name-color: #61708b; $roomtile-badge-fg-color: $accent-fg-color; $roomtile-selected-color: #212121; diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index af366e9685..ce1956f68d 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -96,7 +96,7 @@ const TAG_AESTHETICS: { defaultHidden: false, }, [DefaultTagID.DM]: { - sectionLabel: _td("Direct Messages"), + sectionLabel: _td("People"), isInvite: false, defaultHidden: false, addRoomLabel: _td("Start chat"), @@ -200,6 +200,7 @@ export default class RoomList2 extends React.Component { addRoomLabel={aesthetics.addRoomLabel} isInvite={aesthetics.isInvite} layout={this.state.layouts.get(orderedTagId)} + showMessagePreviews={orderedTagId === DefaultTagID.DM} /> ); } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index e7682a9bb4..84bcb1ea4d 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -20,15 +20,13 @@ import * as React from "react"; import { createRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from 'classnames'; -import * as RoomNotifs from '../../../RoomNotifs'; import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import { _t } from "../../../languageHandler"; import AccessibleButton from "../../views/elements/AccessibleButton"; -import AccessibleTooltipButton from "../../views/elements/AccessibleTooltipButton"; -import * as FormattingUtils from '../../../utils/FormattingUtils'; import RoomTile2 from "./RoomTile2"; import { ResizableBox, ResizeCallbackData } from "react-resizable"; import { ListLayout } from "../../../stores/room-list/ListLayout"; +import { DefaultTagID, TagID } from "../../../stores/room-list/models"; /******************************************************************* * CAUTION * @@ -43,6 +41,7 @@ interface IProps { rooms?: Room[]; startAsHidden: boolean; label: string; + showMessagePreviews: boolean; onAddRoom?: () => void; addRoomLabel: string; isInvite: boolean; @@ -93,7 +92,13 @@ export default class RoomSublist2 extends React.Component { if (this.props.rooms) { for (const room of this.props.rooms) { - tiles.push(); + tiles.push( + + ); } } @@ -101,25 +106,16 @@ export default class RoomSublist2 extends React.Component { } private renderHeader(): React.ReactElement { - const notifications = !this.props.isInvite - ? RoomNotifs.aggregateNotificationCount(this.props.rooms) - : {count: 0, highlight: true}; - const notifCount = notifications.count; - const notifHighlight = notifications.highlight; + // TODO: Handle badge count + // const notifications = !this.props.isInvite + // ? RoomNotifs.aggregateNotificationCount(this.props.rooms) + // : {count: 0, highlight: true}; + // const notifCount = notifications.count; + // const notifHighlight = notifications.highlight; // TODO: Title on collapsed // TODO: Incoming call box - let chevron = null; - if (this.hasTiles()) { - const chevronClasses = classNames({ - 'mx_RoomSublist2_chevron': true, - 'mx_RoomSublist2_chevronRight': false, // isCollapsed - 'mx_RoomSublist2_chevronDown': true, // !isCollapsed - }); - chevron = (
); - } - return ( {({onFocus, isActive, ref}) => { @@ -127,52 +123,55 @@ export default class RoomSublist2 extends React.Component { const tabIndex = isActive ? 0 : -1; // TODO: Collapsed state - let badge; - if (true) { // !isCollapsed - const badgeClasses = classNames({ - 'mx_RoomSublist2_badge': true, - 'mx_RoomSublist2_badgeHighlight': notifHighlight, - }); - // Wrap the contents in a div and apply styles to the child div so that the browser default outline works - if (notifCount > 0) { - badge = ( - -
- {FormattingUtils.formatCount(notifCount)} -
-
- ); - } else if (this.props.isInvite && this.hasTiles()) { - // Render the `!` badge for invites - badge = ( - -
- {FormattingUtils.formatCount(this.numTiles)} -
-
- ); - } - } + // TODO: Handle badge count + // let badge; + // if (true) { // !isCollapsed + // const showCount = localStorage.getItem("mx_rls_count") || notifHighlight; + // const badgeClasses = classNames({ + // 'mx_RoomSublist2_badge': true, + // 'mx_RoomSublist2_badgeHighlight': notifHighlight, + // 'mx_RoomSublist2_badgeEmpty': !showCount, + // }); + // // Wrap the contents in a div and apply styles to the child div so that the browser default outline works + // if (notifCount > 0) { + // const count =
{FormattingUtils.formatCount(notifCount)}
; + // badge = ( + // + // {showCount ? count : null} + // + // ); + // } else if (this.props.isInvite && this.hasTiles()) { + // // Render the `!` badge for invites + // badge = ( + // + //
+ // {FormattingUtils.formatCount(this.numTiles)} + //
+ //
+ // ); + // } + // } - let addRoomButton = null; - if (!!this.props.onAddRoom) { - addRoomButton = ( - - ); - } + // TODO: Aux button + // let addRoomButton = null; + // if (!!this.props.onAddRoom) { + // addRoomButton = ( + // + // ); + // } // TODO: a11y (see old component) return ( @@ -184,11 +183,8 @@ export default class RoomSublist2 extends React.Component { role="treeitem" aria-level="1" > - {chevron} {this.props.label} - {badge} - {addRoomButton}
); }} @@ -243,13 +239,14 @@ export default class RoomSublist2 extends React.Component { // TODO: CSS TBD // TODO: Show N more instead of infinity more? // TODO: Safely use the same height of a tile, not hardcoded hacks + const moreTileHeightPx = `${layout.tileHeight}px`; visibleTiles.splice(visibleTiles.length - 1, 1, (
- {_t("Show %(n)s more rooms", {n: numMissing})} + {_t("Show %(n)s more", {n: numMissing})}
)); } diff --git a/src/components/views/rooms/RoomTile2.tsx b/src/components/views/rooms/RoomTile2.tsx index 40c7bcbc12..8a51327ae2 100644 --- a/src/components/views/rooms/RoomTile2.tsx +++ b/src/components/views/rooms/RoomTile2.tsx @@ -51,6 +51,7 @@ enum NotificationColor { interface IProps { room: Room; + showMessagePreview: boolean; // TODO: Allow falsifying counts (for invites and stuff) // TODO: Transparency? Was this ever used? @@ -192,33 +193,22 @@ export default class RoomTile2 extends React.Component { // TODO: a11y proper // TODO: Render more than bare minimum - const hasBadge = this.state.notificationState.color > NotificationColor.Bold; - const isUnread = this.state.notificationState.color > NotificationColor.None; const classes = classNames({ 'mx_RoomTile2': true, - // 'mx_RoomTile_selected': this.state.selected, - 'mx_RoomTile2_unread': isUnread, - 'mx_RoomTile2_unreadNotify': this.state.notificationState.color >= NotificationColor.Grey, - 'mx_RoomTile2_highlight': this.state.notificationState.color >= NotificationColor.Red, - 'mx_RoomTile2_invited': this.roomIsInvite, - // 'mx_RoomTile_menuDisplayed': isMenuDisplayed, - 'mx_RoomTile2_noBadges': !hasBadge, - // 'mx_RoomTile_transparent': this.props.transparent, - // 'mx_RoomTile_hasSubtext': subtext && !this.props.collapsed, }); - const avatarClasses = classNames({ - 'mx_RoomTile2_avatar': true, - }); - - let badge; + const hasBadge = this.state.notificationState.color > NotificationColor.Bold; if (hasBadge) { + const hasNotif = this.state.notificationState.color >= NotificationColor.Red; + const isEmptyBadge = !localStorage.getItem("mx_rl_rt_badgeCount"); const badgeClasses = classNames({ 'mx_RoomTile2_badge': true, - 'mx_RoomTile2_badgeButton': false, // this.state.badgeHover || isMenuDisplayed + 'mx_RoomTile2_badgeHighlight': hasNotif, + 'mx_RoomTile2_badgeEmpty': isEmptyBadge, }); - badge =
{this.state.notificationState.symbol}
; + const symbol = this.state.notificationState.symbol; + badge =
{isEmptyBadge ? null : symbol}
; } // TODO: the original RoomTile uses state for the room name. Do we need to? @@ -226,20 +216,21 @@ export default class RoomTile2 extends React.Component { if (typeof name !== 'string') name = ''; name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon - const nameClasses = classNames({ - 'mx_RoomTile2_name': true, - 'mx_RoomTile2_invite': this.roomIsInvite, - 'mx_RoomTile2_badgeShown': hasBadge, - }); - // TODO: Support collapsed state properly - let tooltip = null; - if (false) { // isCollapsed - if (this.state.hover) { - tooltip = - } + // TODO: Tooltip? + + let messagePreview = null; + if (this.props.showMessagePreview) { + // TODO: Actually get the real message preview from state + messagePreview =
I just ate a pie.
; } + const nameClasses = classNames({ + "mx_RoomTile2_name": true, + "mx_RoomTile2_nameWithPreview": !!messagePreview, + }); + + const avatarSize = 32; return ( @@ -254,20 +245,18 @@ export default class RoomTile2 extends React.Component { onClick={this.onTileClick} role="treeitem" > -
-
- -
+
+
-
-
- {name} -
+
+ {name}
+ {messagePreview} +
+
{badge}
- {tooltip} } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 884192b22a..cf6dc2431a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1090,6 +1090,7 @@ "Low priority": "Low priority", "Historical": "Historical", "System Alerts": "System Alerts", + "People": "People", "This room": "This room", "Joining room …": "Joining room …", "Loading …": "Loading …", @@ -1133,10 +1134,7 @@ "Securely back up your keys to avoid losing them. Learn more.": "Securely back up your keys to avoid losing them. Learn more.", "Not now": "Not now", "Don't ask me again": "Don't ask me again", - "Jump to first unread room.": "Jump to first unread room.", - "Jump to first invite.": "Jump to first invite.", - "Add room": "Add room", - "Show %(n)s more rooms": "Show %(n)s more rooms", + "Show %(n)s more": "Show %(n)s more", "Options": "Options", "%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.", "%(count)s unread messages including mentions.|one": "1 unread mention.", @@ -2017,6 +2015,9 @@ "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", "Active call": "Active call", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", + "Jump to first unread room.": "Jump to first unread room.", + "Jump to first invite.": "Jump to first invite.", + "Add room": "Add room", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", "You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?", "Search failed": "Search failed", diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index fd57a03ca1..ee51230a61 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const TILE_HEIGHT_PX = 34; +const TILE_HEIGHT_PX = 44; interface ISerializedListLayout { numTiles: number; From 211ad66fea90e3c488a890fb9c7c71e3d24cf1ad Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 08:39:38 -0600 Subject: [PATCH 3/8] Fix i18n --- src/i18n/strings/en_EN.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1f70edc5d1..cf6dc2431a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1134,9 +1134,6 @@ "Securely back up your keys to avoid losing them. Learn more.": "Securely back up your keys to avoid losing them. Learn more.", "Not now": "Not now", "Don't ask me again": "Don't ask me again", - "Jump to first unread room.": "Jump to first unread room.", - "Jump to first invite.": "Jump to first invite.", - "Add room": "Add room", "Show %(n)s more": "Show %(n)s more", "Options": "Options", "%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.", From 6752c2832ee8a21e95ce105888b2257ec5bfce2a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 08:40:32 -0600 Subject: [PATCH 4/8] Add missing var --- src/components/views/rooms/RoomSublist2.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 15a0ff801b..1a58b67377 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -237,6 +237,7 @@ export default class RoomSublist2 extends React.Component { // TODO: CSS TBD // TODO: Make this an actual tile + const moreTileHeightPx = layout.tileHeight; visibleTiles.splice(visibleTiles.length - 1, 1, (
Date: Fri, 5 Jun 2020 08:48:23 -0600 Subject: [PATCH 5/8] Give the show more button some real CSS This is still somewhat placeholder. --- res/css/views/rooms/_RoomSublist2.scss | 9 +++++++++ src/components/views/rooms/RoomSublist2.tsx | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 4d8c3fffff..da1c23b664 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -38,5 +38,14 @@ limitations under the License. display: flex; flex-direction: column; overflow: hidden; + + .mx_RoomSublist2_showMoreButton { + height: 44px; // 1 room tile high + cursor: pointer; + + // We create a flexbox to cheat at alignment + display: flex; + align-items: center; + } } } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 1a58b67377..90231596fe 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -237,11 +237,10 @@ export default class RoomSublist2 extends React.Component { // TODO: CSS TBD // TODO: Make this an actual tile - const moreTileHeightPx = layout.tileHeight; visibleTiles.splice(visibleTiles.length - 1, 1, (
{_t("Show %(n)s more", {n: numMissing})} From 1d8833e9f83a50e9223b04c59b8e216b86c56f04 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 14:08:20 -0600 Subject: [PATCH 6/8] Selected state, cleanup, and profile display --- res/css/structures/_LeftPanel2.scss | 3 +++ res/css/views/rooms/_RoomList2.scss | 2 ++ res/css/views/rooms/_RoomSublist2.scss | 2 ++ res/css/views/rooms/_RoomTile2.scss | 13 +++++++++++-- res/themes/light/css/_light.scss | 1 + src/ActiveRoomObserver.js | 14 +++++++++----- src/components/structures/LeftPanel2.tsx | 17 +++++++++++++---- src/components/views/rooms/RoomTile2.tsx | 11 ++++++++++- 8 files changed, 51 insertions(+), 12 deletions(-) diff --git a/res/css/structures/_LeftPanel2.scss b/res/css/structures/_LeftPanel2.scss index 52ee4f16ac..822a5ac399 100644 --- a/res/css/structures/_LeftPanel2.scss +++ b/res/css/structures/_LeftPanel2.scss @@ -14,6 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +// TODO: Rename to mx_LeftPanel during replacement of old component + +// TODO: Put these variables in the right place, or namespace them. $tagPanelWidth: 70px; $roomListMinimizedWidth: 50px; diff --git a/res/css/views/rooms/_RoomList2.scss b/res/css/views/rooms/_RoomList2.scss index add7214468..89760958f9 100644 --- a/res/css/views/rooms/_RoomList2.scss +++ b/res/css/views/rooms/_RoomList2.scss @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +// TODO: Rename to mx_RoomList during replacement of old component + .mx_RoomList2 { // Create a column-based flexbox for the sublists. That's pretty much all we have to // worry about in this stylesheet. diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index da1c23b664..3b3eccfd60 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +// TODO: Rename to mx_RoomSublist during replacement of old component + @import "../../../../node_modules/react-resizable/css/styles.css"; .mx_RoomSublist2 { diff --git a/res/css/views/rooms/_RoomTile2.scss b/res/css/views/rooms/_RoomTile2.scss index bb27942f81..3151bb8716 100644 --- a/res/css/views/rooms/_RoomTile2.scss +++ b/res/css/views/rooms/_RoomTile2.scss @@ -14,15 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ +// TODO: Rename to mx_RoomTile during replacement of old component + // Note: the room tile expects to be in a flexbox column container .mx_RoomTile2 { - width: 100%; - padding-bottom: 12px; + width: calc(100% - 11px); // 8px for padding (4px on either side), 3px for margin + margin-bottom: 4px; + margin-right: 3px; + padding: 4px; // The tile is also a flexbox row itself display: flex; flex-wrap: wrap; + &.mx_RoomTile2_selected { + background-color: $roomtile2-selected-bg-color; + border-radius: 32px; + } + .mx_RoomTile2_avatarContainer { margin-right: 8px; } diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 683c02528d..5aeb125774 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -176,6 +176,7 @@ $header-divider-color: #91A1C0; // TODO: Dark theme $roomtile2-preview-color: #9e9e9e; $roomtile2-badge-color: #61708b; +$roomtile2-selected-bg-color: #FFF; $roomtile-name-color: #61708b; $roomtile-badge-fg-color: $accent-fg-color; diff --git a/src/ActiveRoomObserver.js b/src/ActiveRoomObserver.js index d6fbb460b5..b7695d401d 100644 --- a/src/ActiveRoomObserver.js +++ b/src/ActiveRoomObserver.js @@ -27,7 +27,7 @@ import RoomViewStore from './stores/RoomViewStore'; */ class ActiveRoomObserver { constructor() { - this._listeners = {}; + this._listeners = {}; // key=roomId, value=function(isActive:boolean) this._activeRoomId = RoomViewStore.getRoomId(); // TODO: We could self-destruct when the last listener goes away, or at least @@ -35,6 +35,10 @@ class ActiveRoomObserver { this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this)); } + get activeRoomId(): string { + return this._activeRoomId; + } + addListener(roomId, listener) { if (!this._listeners[roomId]) this._listeners[roomId] = []; this._listeners[roomId].push(listener); @@ -51,23 +55,23 @@ class ActiveRoomObserver { } } - _emit(roomId) { + _emit(roomId, isActive: boolean) { if (!this._listeners[roomId]) return; for (const l of this._listeners[roomId]) { - l.call(); + l.call(null, isActive); } } _onRoomViewStoreUpdate() { // emit for the old room ID - if (this._activeRoomId) this._emit(this._activeRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId, false); // update our cache this._activeRoomId = RoomViewStore.getRoomId(); // and emit for the new one - if (this._activeRoomId) this._emit(this._activeRoomId); + if (this._activeRoomId) this._emit(this._activeRoomId, true); } } diff --git a/src/components/structures/LeftPanel2.tsx b/src/components/structures/LeftPanel2.tsx index bf0e72beeb..00419465eb 100644 --- a/src/components/structures/LeftPanel2.tsx +++ b/src/components/structures/LeftPanel2.tsx @@ -86,26 +86,35 @@ export default class LeftPanel2 extends React.Component { } private renderHeader(): React.ReactNode { - // TODO: Use real profile info + // TODO: Update when profile info changes // TODO: Presence // TODO: Breadcrumbs toggle // TODO: Menu button const avatarSize = 32; + // TODO: Don't do this profile lookup in render() + const client = MatrixClientPeg.get(); + let displayName = client.getUserId(); + let avatarUrl: string = null; + const myUser = client.getUser(client.getUserId()); + if (myUser) { + displayName = myUser.rawDisplayName; + avatarUrl = myUser.avatarUrl; + } return (
- Irene + {displayName}
diff --git a/src/components/views/rooms/RoomTile2.tsx b/src/components/views/rooms/RoomTile2.tsx index 8a51327ae2..09d7b46ba5 100644 --- a/src/components/views/rooms/RoomTile2.tsx +++ b/src/components/views/rooms/RoomTile2.tsx @@ -23,7 +23,6 @@ import classNames from "classnames"; import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import AccessibleButton from "../../views/elements/AccessibleButton"; import RoomAvatar from "../../views/avatars/RoomAvatar"; -import Tooltip from "../../views/elements/Tooltip"; import dis from '../../../dispatcher/dispatcher'; import { Key } from "../../../Keyboard"; import * as RoomNotifs from '../../../RoomNotifs'; @@ -32,6 +31,7 @@ import * as Unread from '../../../Unread'; import * as FormattingUtils from "../../../utils/FormattingUtils"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import ActiveRoomObserver from "../../../ActiveRoomObserver"; /******************************************************************* * CAUTION * @@ -66,6 +66,7 @@ interface INotificationState { interface IState { hover: boolean; notificationState: INotificationState; + selected: boolean; } export default class RoomTile2 extends React.Component { @@ -88,12 +89,14 @@ export default class RoomTile2 extends React.Component { this.state = { hover: false, notificationState: this.getNotificationState(), + selected: ActiveRoomObserver.activeRoomId === this.props.room.roomId, }; this.props.room.on("Room.receipt", this.handleRoomEventUpdate); this.props.room.on("Room.timeline", this.handleRoomEventUpdate); this.props.room.on("Room.redaction", this.handleRoomEventUpdate); MatrixClientPeg.get().on("Event.decrypted", this.handleRoomEventUpdate); + ActiveRoomObserver.addListener(this.props.room.roomId, this.onActiveRoomUpdate); } public componentWillUnmount() { @@ -101,6 +104,7 @@ export default class RoomTile2 extends React.Component { this.props.room.removeListener("Room.receipt", this.handleRoomEventUpdate); this.props.room.removeListener("Room.timeline", this.handleRoomEventUpdate); this.props.room.removeListener("Room.redaction", this.handleRoomEventUpdate); + ActiveRoomObserver.removeListener(this.props.room.roomId, this.onActiveRoomUpdate); } if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("Event.decrypted", this.handleRoomEventUpdate); @@ -187,6 +191,10 @@ export default class RoomTile2 extends React.Component { }); }; + private onActiveRoomUpdate = (isActive: boolean) => { + this.setState({selected: isActive}); + }; + public render(): React.ReactElement { // TODO: Collapsed state // TODO: Invites @@ -195,6 +203,7 @@ export default class RoomTile2 extends React.Component { const classes = classNames({ 'mx_RoomTile2': true, + 'mx_RoomTile2_selected': this.state.selected, }); let badge; From 829bf3c774498bacad2aadbaecc582821457ccab Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 14:11:04 -0600 Subject: [PATCH 7/8] Add another TODO comment --- res/css/views/rooms/_RoomSublist2.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 3b3eccfd60..e6e5af3b48 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -16,6 +16,8 @@ limitations under the License. // TODO: Rename to mx_RoomSublist during replacement of old component +// TODO: Just use the 3 selectors we need from this instead of importing it. +// We're going to end up with heavy modifications anyways. @import "../../../../node_modules/react-resizable/css/styles.css"; .mx_RoomSublist2 { From 2806c8c18ba4f8bf864b981b54011c5211c333ab Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 14:13:28 -0600 Subject: [PATCH 8/8] Fix temporary class --- src/components/structures/LeftPanel2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/LeftPanel2.tsx b/src/components/structures/LeftPanel2.tsx index 00419465eb..c66c0a6799 100644 --- a/src/components/structures/LeftPanel2.tsx +++ b/src/components/structures/LeftPanel2.tsx @@ -131,7 +131,7 @@ export default class LeftPanel2 extends React.Component { ); const searchBox = (