From 5a1d255d2a07ffd0b1c85bab52658015b39de8b5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:23:02 +0200 Subject: [PATCH 01/37] implement room grid view model --- src/domain/session/RoomGridViewModel.js | 89 +++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/domain/session/RoomGridViewModel.js diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js new file mode 100644 index 00000000..dcea1a26 --- /dev/null +++ b/src/domain/session/RoomGridViewModel.js @@ -0,0 +1,89 @@ +/* +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. +*/ + +import {ViewModel} from "../ViewModel.js"; + +export class RoomGridViewModel extends ViewModel { + constructor(options) { + super(options); + this._width = options.width; + this._height = options.height; + this._selectedIndex = 0; + this._viewModels = []; + } + + roomViewModelAt(idx) { + return this._viewModels[idx]?.vm; + } + + get focusedIndex() { + return this._selectedIndex; + } + + setFocusedIndex(idx) { + const oldItem = this._viewModels[this._selectedIndex]; + oldItem?.tileVM?.close(); + this._selectedIndex = idx; + const newItem = this._viewModels[this._selectedIndex]; + if (newItem) { + newItem.vm.focus(); + newItem.tileVM.open(); + } + this.emitChange("focusedIndex"); + } + get width() { + return this._width; + } + + get height() { + return this._height; + } + + /** + * Sets a pair of room and room tile view models at the current index + * @param {RoomViewModel} vm + * @param {RoomTileViewModel} tileVM + * @package + */ + setRoomViewModel(vm, tileVM) { + const old = this._viewModels[this._selectedIndex]; + this.disposeTracked(old?.vm); + old?.tileVM?.close(); + this._viewModels[this._selectedIndex] = {vm: this.track(vm), tileVM}; + this.emitChange(`${this._selectedIndex}`); + } + + /** + * @package + */ + hasRoomId(roomId) { + return this._viewModels.some(vms => vms?.vm._room.id === roomId); + } + + /** + * Returns the first set of room and room tile vm, + * and untracking them so they are not owned by this view model anymore. + * @package + */ + getAndUntrackFirst() { + for (const item of this._viewModels) { + if (item) { + this.untrack(item.vm); + return item; + } + } + } +} From 9cc7833d7ae400cde62dbe6c4eaa0c1690d1a73e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:24:44 +0200 Subject: [PATCH 02/37] implement room grid view --- src/ui/web/session/RoomGridView.js | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/ui/web/session/RoomGridView.js diff --git a/src/ui/web/session/RoomGridView.js b/src/ui/web/session/RoomGridView.js new file mode 100644 index 00000000..d87d1e9d --- /dev/null +++ b/src/ui/web/session/RoomGridView.js @@ -0,0 +1,43 @@ +/* +Copyright 2020 Bruno Windels + +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. +*/ + +import {RoomView} from "./room/RoomView.js"; +import {RoomPlaceholderView} from "./RoomPlaceholderView.js"; +import {TemplateView} from "../general/TemplateView.js"; + +export class RoomGridView extends TemplateView { + render(t, vm) { + const roomViews = []; + const len = vm.width * vm.height; + for (let i = 0; i < len; i+=1) { + roomViews[i] = t.div({ + onClick: () => vm.setFocusedIndex(i), + onFocusin: () => vm.setFocusedIndex(i), + className: {focused: vm => vm.focusedIndex === i}, + },t.mapView(vm => vm.roomViewModelAt(i), roomVM => { + if (roomVM) { + return new RoomView(roomVM); + } else { + return new RoomPlaceholderView(); + } + })) + } + return t.div({ + className: "RoomGridView", + style: `--columns: ${vm.width}; --rows: ${vm.height}` + }, roomViews); + } +} From 614ec08238930afce78e90388da6176128ca9ba8 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:25:03 +0200 Subject: [PATCH 03/37] integrate grid vm with session vm, allowing to switch --- src/domain/ViewModel.js | 6 ++ src/domain/session/SessionViewModel.js | 81 ++++++++++++++++++++++---- src/utils/Disposables.js | 7 +++ 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/domain/ViewModel.js b/src/domain/ViewModel.js index 7f973ad7..bb651d87 100644 --- a/src/domain/ViewModel.js +++ b/src/domain/ViewModel.js @@ -40,6 +40,12 @@ export class ViewModel extends EventEmitter { return this.disposables.track(disposable); } + untrack(disposable) { + if (this.disposables) { + return this.disposables.untrack(disposable); + } + } + dispose() { if (this.disposables) { this.disposables.dispose(); diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index f7d28fed..467bc169 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -18,6 +18,7 @@ limitations under the License. import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js"; import {RoomViewModel} from "./room/RoomViewModel.js"; import {SessionStatusViewModel} from "./SessionStatusViewModel.js"; +import {RoomGridViewModel} from "./RoomGridViewModel.js"; import {ViewModel} from "../ViewModel.js"; export class SessionViewModel extends ViewModel { @@ -32,16 +33,34 @@ export class SessionViewModel extends ViewModel { }))); this._leftPanelViewModel = new LeftPanelViewModel(this.childOptions({ rooms: this._session.rooms, - openRoom: this._openRoom.bind(this) + openRoom: this._openRoom.bind(this), + gridEnabled: { + get: () => !!this._gridViewModel, + set: value => this._enabledGrid(value) + } })); this._currentRoomTileViewModel = null; this._currentRoomViewModel = null; + this._gridViewModel = null; } start() { this._sessionStatusViewModel.start(); } + get middlePanelViewType() { + if (this._currentRoomViewModel) { + return "room"; + } else if (this._gridViewModel) { + return "roomgrid"; + } + return "placeholder"; + } + + get roomGridViewModel() { + return this._gridViewModel; + } + get leftPanelViewModel() { return this._leftPanelViewModel; } @@ -58,24 +77,62 @@ export class SessionViewModel extends ViewModel { return this._currentRoomViewModel; } + _enabledGrid(enabled) { + if (enabled) { + this._gridViewModel = this.track(new RoomGridViewModel(this.childOptions({width: 3, height: 2}))); + // transfer current room + if (this._currentRoomViewModel) { + this.untrack(this._currentRoomViewModel); + this._gridViewModel.setRoomViewModel(this._currentRoomViewModel, this._currentRoomTileViewModel); + this._currentRoomViewModel = null; + this._currentRoomTileViewModel = null; + } + } else { + const VMs = this._gridViewModel.getAndUntrackFirst(); + if (VMs) { + this._currentRoomViewModel = this.track(VMs.vm); + this._currentRoomTileViewModel = VMs.tileVM; + this._currentRoomTileViewModel.open(); + } + this._gridViewModel = this.disposeTracked(this._gridViewModel); + } + this.emitChange("middlePanelViewType"); + } + _closeCurrentRoom() { - this._currentRoomTileViewModel?.close(); - this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); + // no closing in grid for now + if (!this._gridViewModel) { + this._currentRoomTileViewModel?.close(); + this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); + return true; + } } _openRoom(room, roomTileVM) { - this._closeCurrentRoom(); - this._currentRoomTileViewModel = roomTileVM; - this._currentRoomViewModel = this.track(new RoomViewModel(this.childOptions({ + // for now, we don't support having the same room opened more than once, + // so bail out if we already have the room open + if (this._gridViewModel?.hasRoomId(room.id)) { + return; + } else if (this._currentRoomViewModel?._room.id === room.id) { + return; + } + const roomVM = new RoomViewModel(this.childOptions({ room, ownUserId: this._session.user.id, closeCallback: () => { - this._closeCurrentRoom(); - this.emitChange("currentRoom"); + if (this._closeCurrentRoom()) { + this.emitChange("currentRoom"); + } }, - }))); - this._currentRoomViewModel.load(); - this.emitChange("currentRoom"); + })); + roomVM.load(); + if (this._gridViewModel) { + this._gridViewModel.setRoomViewModel(roomVM, roomTileVM); + } else { + this._closeCurrentRoom(); + this._currentRoomTileViewModel = roomTileVM; + this._currentRoomViewModel = this.track(roomVM); + this.emitChange("currentRoom"); + } } } - diff --git a/src/utils/Disposables.js b/src/utils/Disposables.js index efc49897..bd13abc2 100644 --- a/src/utils/Disposables.js +++ b/src/utils/Disposables.js @@ -35,6 +35,13 @@ export class Disposables { return disposable; } + untrack(disposable) { + const idx = this._disposables.indexOf(disposable); + if (idx >= 0) { + this._disposables.splice(idx, 1); + } + } + dispose() { if (this._disposables) { for (const d of this._disposables) { From dc1357bb316094ffb5b140af9441a362c661c6bb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:30:46 +0200 Subject: [PATCH 04/37] support clearing unread when focusing a room --- src/domain/session/room/RoomViewModel.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/domain/session/room/RoomViewModel.js b/src/domain/session/room/RoomViewModel.js index ab453e01..87d0cb6c 100644 --- a/src/domain/session/room/RoomViewModel.js +++ b/src/domain/session/room/RoomViewModel.js @@ -51,10 +51,18 @@ export class RoomViewModel extends ViewModel { this._timelineError = err; this.emitChange("error"); } + this._clearUnreadAfterDelay(); + } + + async _clearUnreadAfterDelay() { + if (this._clearUnreadTimout) { + return; + } this._clearUnreadTimout = this.clock.createTimeout(2000); try { await this._clearUnreadTimout.elapsed(); await this._room.clearUnread(); + this._clearUnreadTimout = null; } catch (err) { if (err.name !== "AbortError") { throw err; @@ -62,6 +70,10 @@ export class RoomViewModel extends ViewModel { } } + focus() { + this._clearUnreadAfterDelay(); + } + dispose() { super.dispose(); if (this._clearUnreadTimout) { From 7955462dda3b24e4d7ebd51957a3574b2ba72986 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:31:24 +0200 Subject: [PATCH 05/37] render grid view in session view --- src/ui/web/session/SessionView.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/web/session/SessionView.js b/src/ui/web/session/SessionView.js index eb8d3153..63fe819d 100644 --- a/src/ui/web/session/SessionView.js +++ b/src/ui/web/session/SessionView.js @@ -19,6 +19,7 @@ import {RoomView} from "./room/RoomView.js"; import {TemplateView} from "../general/TemplateView.js"; import {RoomPlaceholderView} from "./RoomPlaceholderView.js"; import {SessionStatusView} from "./SessionStatusView.js"; +import {RoomGridView} from "./RoomGridView.js"; export class SessionView extends TemplateView { render(t, vm) { @@ -31,11 +32,14 @@ export class SessionView extends TemplateView { t.view(new SessionStatusView(vm.sessionStatusViewModel)), t.div({className: "main"}, [ t.view(new LeftPanelView(vm.leftPanelViewModel)), - t.mapView(vm => vm.currentRoom, currentRoom => { - if (currentRoom) { - return new RoomView(currentRoom); - } else { - return new RoomPlaceholderView(); + t.mapView(vm => vm.middlePanelViewType, middlePanelViewType => { + switch (middlePanelViewType) { + case "room": + return new RoomView(vm.currentRoom); + case "roomgrid": + return new RoomGridView(vm.roomGridViewModel); + case "placeholder": + return new RoomPlaceholderView(); } }) ]) From 1ff6d36ec3012616d662d7fcfe24c92424496785 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 12:31:52 +0200 Subject: [PATCH 06/37] add grid toggle button to left panel --- src/domain/session/leftpanel/LeftPanelViewModel.js | 12 +++++++++++- src/ui/web/session/leftpanel/LeftPanelView.js | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/domain/session/leftpanel/LeftPanelViewModel.js b/src/domain/session/leftpanel/LeftPanelViewModel.js index 50864b4c..fe5ce05b 100644 --- a/src/domain/session/leftpanel/LeftPanelViewModel.js +++ b/src/domain/session/leftpanel/LeftPanelViewModel.js @@ -23,7 +23,8 @@ import {ApplyMap} from "../../../observable/map/ApplyMap.js"; export class LeftPanelViewModel extends ViewModel { constructor(options) { super(options); - const {rooms, openRoom} = options; + const {rooms, openRoom, gridEnabled} = options; + this._gridEnabled = gridEnabled; const roomTileVMs = rooms.mapValues((room, emitChange) => { return new RoomTileViewModel({ room, @@ -35,6 +36,15 @@ export class LeftPanelViewModel extends ViewModel { this._roomList = this._roomListFilterMap.sortValues((a, b) => a.compare(b)); } + get gridEnabled() { + return this._gridEnabled.get(); + } + + toggleGrid() { + this._gridEnabled.set(!this._gridEnabled.get()); + this.emitChange("gridEnabled"); + } + get roomList() { return this._roomList; } diff --git a/src/ui/web/session/leftpanel/LeftPanelView.js b/src/ui/web/session/leftpanel/LeftPanelView.js index f262e954..d7c588ad 100644 --- a/src/ui/web/session/leftpanel/LeftPanelView.js +++ b/src/ui/web/session/leftpanel/LeftPanelView.js @@ -40,7 +40,8 @@ export class LeftPanelView extends TemplateView { t.button({onClick: () => { filterInput.value = ""; vm.clearFilter(); - }}, vm.i18n`Clear`) + }}, vm.i18n`Clear`), + t.button({onClick: () => vm.toggleGrid()}, vm => vm.gridEnabled ? "Single" : "Grid") ]), t.view(new ListView( { From b9d2da736ac6d738696f72cbc936c520e3cf922b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 13:18:19 +0200 Subject: [PATCH 07/37] when opening room, focus in grid if already open --- src/domain/session/RoomGridViewModel.js | 7 +++++-- src/domain/session/SessionViewModel.js | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js index dcea1a26..d8dc38ab 100644 --- a/src/domain/session/RoomGridViewModel.js +++ b/src/domain/session/RoomGridViewModel.js @@ -34,6 +34,9 @@ export class RoomGridViewModel extends ViewModel { } setFocusedIndex(idx) { + if (idx === this._selectedIndex) { + return; + } const oldItem = this._viewModels[this._selectedIndex]; oldItem?.tileVM?.close(); this._selectedIndex = idx; @@ -69,8 +72,8 @@ export class RoomGridViewModel extends ViewModel { /** * @package */ - hasRoomId(roomId) { - return this._viewModels.some(vms => vms?.vm._room.id === roomId); + roomIndex(roomId) { + return this._viewModels.findIndex(vms => vms?.vm._room.id === roomId); } /** diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 467bc169..082d738f 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -111,8 +111,12 @@ export class SessionViewModel extends ViewModel { _openRoom(room, roomTileVM) { // for now, we don't support having the same room opened more than once, // so bail out if we already have the room open - if (this._gridViewModel?.hasRoomId(room.id)) { - return; + if (this._gridViewModel) { + const roomIndex = this._gridViewModel.roomIndex(room.id); + if (roomIndex >= 0) { + this._gridViewModel.setFocusedIndex(roomIndex); + return; + } } else if (this._currentRoomViewModel?._room.id === room.id) { return; } From 99ff387dece6cbff299529bd903cfa1194940653 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:18:35 +0200 Subject: [PATCH 08/37] index the room by x,y instead of index from the view so it is easier to implement a focus-ring as a separate dom node --- src/domain/session/RoomGridViewModel.js | 43 +++++++++++++++++++++---- src/domain/session/SessionViewModel.js | 10 ++---- src/ui/web/session/RoomGridView.js | 33 ++++++++++--------- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js index d8dc38ab..40b7192c 100644 --- a/src/domain/session/RoomGridViewModel.js +++ b/src/domain/session/RoomGridViewModel.js @@ -25,15 +25,39 @@ export class RoomGridViewModel extends ViewModel { this._viewModels = []; } - roomViewModelAt(idx) { - return this._viewModels[idx]?.vm; + _posToIdx(x, y) { + return (y * this.width) + x; } - get focusedIndex() { - return this._selectedIndex; + _idxToX(idx) { + return idx % this.width; } - setFocusedIndex(idx) { + _idxToY(idx) { + return Math.floor(idx / this.width); + } + + roomViewModelAt(x, y) { + return this._viewModels[this._posToIdx(x, y)]?.vm; + } + + get focusX() { + return this._idxToX(this._selectedIndex); + } + + get focusY() { + return this._idxToY(this._selectedIndex); + } + + isFocusAt(x, y) { + return this._posToIdx(x, y) === this._selectedIndex; + } + + setFocusAt(x, y) { + this._setFocusedIndex(this._posToIdx(x, y)); + } + + _setFocusedIndex(idx) { if (idx === this._selectedIndex) { return; } @@ -72,8 +96,13 @@ export class RoomGridViewModel extends ViewModel { /** * @package */ - roomIndex(roomId) { - return this._viewModels.findIndex(vms => vms?.vm._room.id === roomId); + tryFocusRoom(roomId) { + const index = this._viewModels.findIndex(vms => vms?.vm._room.id === roomId); + if (index >= 0) { + this._setFocusedIndex(index); + return true; + } + return false; } /** diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 082d738f..e6965c8c 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -109,14 +109,8 @@ export class SessionViewModel extends ViewModel { } _openRoom(room, roomTileVM) { - // for now, we don't support having the same room opened more than once, - // so bail out if we already have the room open - if (this._gridViewModel) { - const roomIndex = this._gridViewModel.roomIndex(room.id); - if (roomIndex >= 0) { - this._gridViewModel.setFocusedIndex(roomIndex); - return; - } + if (this._gridViewModel?.tryFocusRoom(room.id)) { + return; } else if (this._currentRoomViewModel?._room.id === room.id) { return; } diff --git a/src/ui/web/session/RoomGridView.js b/src/ui/web/session/RoomGridView.js index d87d1e9d..f954c4f1 100644 --- a/src/ui/web/session/RoomGridView.js +++ b/src/ui/web/session/RoomGridView.js @@ -20,24 +20,27 @@ import {TemplateView} from "../general/TemplateView.js"; export class RoomGridView extends TemplateView { render(t, vm) { - const roomViews = []; - const len = vm.width * vm.height; - for (let i = 0; i < len; i+=1) { - roomViews[i] = t.div({ - onClick: () => vm.setFocusedIndex(i), - onFocusin: () => vm.setFocusedIndex(i), - className: {focused: vm => vm.focusedIndex === i}, - },t.mapView(vm => vm.roomViewModelAt(i), roomVM => { - if (roomVM) { - return new RoomView(roomVM); - } else { - return new RoomPlaceholderView(); - } - })) + const children = []; + for (let y = 0; y < vm.height; y+=1) { + for (let x = 0; x < vm.width; x+=1) { + children.push(t.div({ + onClick: () => vm.setFocusAt(x, y), + onFocusin: () => vm.setFocusAt(x, y), + className: "container", + style: `--column: ${x + 1}; --row: ${y + 1}` + },t.mapView(vm => vm.roomViewModelAt(x, y), roomVM => { + if (roomVM) { + return new RoomView(roomVM); + } else { + return new RoomPlaceholderView(); + } + }))); + } } + children.push(t.div({className: "focus-ring", style: vm => `--column: ${vm.focusX + 1}; --row: ${vm.focusY + 1}`})); return t.div({ className: "RoomGridView", style: `--columns: ${vm.width}; --rows: ${vm.height}` - }, roomViews); + }, children); } } From 152a83f75fe32d7b1c0aa9b9ec2c38b249145454 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:22:00 +0200 Subject: [PATCH 09/37] css for the grid view --- src/ui/web/css/layout.css | 25 +++++++++++++++++-- src/ui/web/css/themes/element/theme.css | 17 +++++++++++++ src/ui/web/session/leftpanel/LeftPanelView.js | 5 +++- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/ui/web/css/layout.css b/src/ui/web/css/layout.css index c1a47eb2..eea0eed2 100644 --- a/src/ui/web/css/layout.css +++ b/src/ui/web/css/layout.css @@ -48,8 +48,11 @@ html { /* mobile layout */ @media screen and (max-width: 800px) { + /* show back button */ .RoomHeader button.back { display: block; } - div.RoomView, div.RoomPlaceholderView { display: none; } + /* hide grid button */ + .LeftPanel button.grid { display: none; } + div.RoomView, div.RoomPlaceholderView, div.RoomGridView { display: none; } div.LeftPanel {flex-grow: 1;} div.room-shown div.RoomView { display: flex; } div.room-shown div.LeftPanel { display: none; } @@ -61,7 +64,7 @@ html { min-width: 0; } -.RoomPlaceholderView, .RoomView { +.RoomPlaceholderView, .RoomView, .RoomGridView { flex: 1 0 0; min-width: 0; } @@ -88,3 +91,21 @@ html { .RoomHeader { display: flex; } + +.RoomGridView { + display: grid; + grid-template-columns: repeat(var(--columns), 1fr); + grid-template-rows: repeat(var(--rows), 1fr); +} + +.RoomGridView > div { + display: flex; + min-width: 0; + grid-column: var(--column); + grid-row: var(--row); +} + +.RoomGridView > div.focus-ring { + z-index: 1; + pointer-events: none; +} diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 3e627eb7..56c9fb29 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -211,6 +211,7 @@ a { background-color: #3D88FA; color: white; border-radius: 10px; + z-index: 2; } .room-shown .SessionStatusView { @@ -258,6 +259,22 @@ a { color: #FF4B55; } + +/*.RoomGridView > :not(.focused) .MessageComposer { + display: none; +} +*/ + +.RoomGridView > div.container { + border-right: 1px solid rgba(245, 245, 245, 0.90); + border-bottom: 1px solid rgba(245, 245, 245, 0.90); +} + +.RoomGridView > div.focus-ring { + border: 2px solid rgba(134, 193, 165, 1); + border-radius: 2px; +} + .RoomHeader { background: rgba(245, 245, 245, 0.90); padding: 10px; diff --git a/src/ui/web/session/leftpanel/LeftPanelView.js b/src/ui/web/session/leftpanel/LeftPanelView.js index d7c588ad..b993531d 100644 --- a/src/ui/web/session/leftpanel/LeftPanelView.js +++ b/src/ui/web/session/leftpanel/LeftPanelView.js @@ -41,7 +41,10 @@ export class LeftPanelView extends TemplateView { filterInput.value = ""; vm.clearFilter(); }}, vm.i18n`Clear`), - t.button({onClick: () => vm.toggleGrid()}, vm => vm.gridEnabled ? "Single" : "Grid") + t.button({ + onClick: () => vm.toggleGrid(), + className: "grid" + }, vm => vm.gridEnabled ? "Single" : "Grid") ]), t.view(new ListView( { From de14d6b54b8bc60de8f9169f780346429305489e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:22:14 +0200 Subject: [PATCH 10/37] fix filter field taking up too much width --- src/ui/web/css/left-panel.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/web/css/left-panel.css b/src/ui/web/css/left-panel.css index 6833341d..5a5240a2 100644 --- a/src/ui/web/css/left-panel.css +++ b/src/ui/web/css/left-panel.css @@ -27,6 +27,7 @@ limitations under the License. display: block; flex: 1; box-sizing: border-box; + min-width: 0; } .LeftPanel ul { From 537972b97b9e7c9254b3421c5c4ca66206dadb4e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:25:32 +0200 Subject: [PATCH 11/37] clarify comment --- src/domain/session/SessionViewModel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index e6965c8c..076d8178 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -100,7 +100,7 @@ export class SessionViewModel extends ViewModel { } _closeCurrentRoom() { - // no closing in grid for now + // no closing in grid for now as it is disabled on narrow viewports if (!this._gridViewModel) { this._currentRoomTileViewModel?.close(); this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); From 46b24c3f24a33e91dd2781b1a347ccbf2fba3099 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:32:57 +0200 Subject: [PATCH 12/37] fix room not changing when not in grid view --- src/domain/session/SessionViewModel.js | 4 ++-- src/ui/web/session/SessionView.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 076d8178..5ad50600 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -48,9 +48,9 @@ export class SessionViewModel extends ViewModel { this._sessionStatusViewModel.start(); } - get middlePanelViewType() { + get selectionId() { if (this._currentRoomViewModel) { - return "room"; + return this._currentRoomViewModel._room.id; } else if (this._gridViewModel) { return "roomgrid"; } diff --git a/src/ui/web/session/SessionView.js b/src/ui/web/session/SessionView.js index 63fe819d..aaeecc5c 100644 --- a/src/ui/web/session/SessionView.js +++ b/src/ui/web/session/SessionView.js @@ -32,14 +32,14 @@ export class SessionView extends TemplateView { t.view(new SessionStatusView(vm.sessionStatusViewModel)), t.div({className: "main"}, [ t.view(new LeftPanelView(vm.leftPanelViewModel)), - t.mapView(vm => vm.middlePanelViewType, middlePanelViewType => { - switch (middlePanelViewType) { - case "room": - return new RoomView(vm.currentRoom); + t.mapView(vm => vm.selectionId, selectionId => { + switch (selectionId) { case "roomgrid": return new RoomGridView(vm.roomGridViewModel); case "placeholder": return new RoomPlaceholderView(); + default: //room id + return new RoomView(vm.currentRoom); } }) ]) From f6d9ffa7bbcd7cc131803acefd9adc5b5f572eeb Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:36:08 +0200 Subject: [PATCH 13/37] friends don't read each others private properties --- src/domain/session/SessionViewModel.js | 4 ++-- src/domain/session/room/RoomViewModel.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 5ad50600..beb35872 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -50,7 +50,7 @@ export class SessionViewModel extends ViewModel { get selectionId() { if (this._currentRoomViewModel) { - return this._currentRoomViewModel._room.id; + return this._currentRoomViewModel.id; } else if (this._gridViewModel) { return "roomgrid"; } @@ -111,7 +111,7 @@ export class SessionViewModel extends ViewModel { _openRoom(room, roomTileVM) { if (this._gridViewModel?.tryFocusRoom(room.id)) { return; - } else if (this._currentRoomViewModel?._room.id === room.id) { + } else if (this._currentRoomViewModel?.id === room.id) { return; } const roomVM = new RoomViewModel(this.childOptions({ diff --git a/src/domain/session/room/RoomViewModel.js b/src/domain/session/room/RoomViewModel.js index 87d0cb6c..7c8df7bc 100644 --- a/src/domain/session/room/RoomViewModel.js +++ b/src/domain/session/room/RoomViewModel.js @@ -98,6 +98,10 @@ export class RoomViewModel extends ViewModel { return this._room.name || this.i18n`Empty Room`; } + get id() { + return this._room.id; + } + get timelineViewModel() { return this._timelineVM; } From 61b5369f2fa3c1768a3e70a19768cf2d435995ef Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 14:53:41 +0200 Subject: [PATCH 14/37] also show status view a bit lower for grid --- src/ui/web/session/SessionView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/web/session/SessionView.js b/src/ui/web/session/SessionView.js index aaeecc5c..cf96be54 100644 --- a/src/ui/web/session/SessionView.js +++ b/src/ui/web/session/SessionView.js @@ -26,7 +26,7 @@ export class SessionView extends TemplateView { return t.div({ className: { "SessionView": true, - "room-shown": vm => !!vm.currentRoom + "room-shown": vm => !!vm.selectionId }, }, [ t.view(new SessionStatusView(vm.sessionStatusViewModel)), From ddda03d82c707fc13c99eee70022aafddabb82ee Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 17:59:14 +0200 Subject: [PATCH 15/37] style filter field and grid button --- src/ui/web/css/form.css | 10 +++ src/ui/web/css/left-panel.css | 7 +- src/ui/web/css/themes/element/icons/clear.svg | 4 + .../css/themes/element/icons/disable-grid.svg | 5 ++ .../css/themes/element/icons/enable-grid.svg | 6 ++ src/ui/web/css/themes/element/theme.css | 44 +++++++++++ src/ui/web/session/leftpanel/LeftPanelView.js | 75 +++++++++++++------ 7 files changed, 125 insertions(+), 26 deletions(-) create mode 100644 src/ui/web/css/themes/element/icons/clear.svg create mode 100644 src/ui/web/css/themes/element/icons/disable-grid.svg create mode 100644 src/ui/web/css/themes/element/icons/enable-grid.svg diff --git a/src/ui/web/css/form.css b/src/ui/web/css/form.css index 741d2bfd..e9771611 100644 --- a/src/ui/web/css/form.css +++ b/src/ui/web/css/form.css @@ -20,3 +20,13 @@ limitations under the License. width: 100%; box-sizing: border-box; } + +.FilterField { + display: flex; +} + +.FilterField input { + display: block; + flex: 1; + min-width: 0; +} diff --git a/src/ui/web/css/left-panel.css b/src/ui/web/css/left-panel.css index 5a5240a2..5a7ae221 100644 --- a/src/ui/web/css/left-panel.css +++ b/src/ui/web/css/left-panel.css @@ -19,15 +19,12 @@ limitations under the License. flex-direction: column; } -.LeftPanel .filter { +.LeftPanel .utilities { display: flex; } -.LeftPanel .filter input { - display: block; +.LeftPanel .utilities .FilterField { flex: 1; - box-sizing: border-box; - min-width: 0; } .LeftPanel ul { diff --git a/src/ui/web/css/themes/element/icons/clear.svg b/src/ui/web/css/themes/element/icons/clear.svg new file mode 100644 index 00000000..9227cf4d --- /dev/null +++ b/src/ui/web/css/themes/element/icons/clear.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/ui/web/css/themes/element/icons/disable-grid.svg b/src/ui/web/css/themes/element/icons/disable-grid.svg new file mode 100644 index 00000000..1be4ae6a --- /dev/null +++ b/src/ui/web/css/themes/element/icons/disable-grid.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/ui/web/css/themes/element/icons/enable-grid.svg b/src/ui/web/css/themes/element/icons/enable-grid.svg new file mode 100644 index 00000000..776fec35 --- /dev/null +++ b/src/ui/web/css/themes/element/icons/enable-grid.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 56c9fb29..234b63ef 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -117,6 +117,50 @@ button.styled { font-weight: 500; } +.FilterField { + background-color: #e1e3e6; + border-radius: 16px; + height: 32px; + align-items: center; + padding: 0 8px; + box-sizing: border-box; +} + +.FilterField :not(:first-child) { + margin-left: 8px; +} + +.FilterField:focus-within { + border: 1px #e1e3e6 solid; + background-color: white; +} + +/*.FilterField:not(:focus-within) button { + display: none; +}*/ + +.FilterField input { + font-family: "Inter"; + font-size: 1.3rem; + font-weight: 500; + line-height: 1.573rem; + outline: none; + border: none; + background-color: transparent; + height: 100%; +} + +.FilterField button { + width: 16px; + height: 16px; + background-position: center; + background-color: #e1e3e6; + background-repeat: no-repeat; + background-image: url('icons/clear.svg'); + border: none; + border-radius: 100%; +} + .PreSessionScreen { padding: 30px; } diff --git a/src/ui/web/session/leftpanel/LeftPanelView.js b/src/ui/web/session/leftpanel/LeftPanelView.js index b993531d..3eeaaada 100644 --- a/src/ui/web/session/leftpanel/LeftPanelView.js +++ b/src/ui/web/session/leftpanel/LeftPanelView.js @@ -18,34 +18,67 @@ import {ListView} from "../../general/ListView.js"; import {TemplateView} from "../../general/TemplateView.js"; import {RoomTileView} from "./RoomTileView.js"; -export class LeftPanelView extends TemplateView { - render(t, vm) { +class FilterField extends TemplateView { + render(t, options) { + const clear = () => { + filterInput.value = ""; + filterInput.blur(); + clearButton.blur(); + options.clear(); + }; const filterInput = t.input({ type: "text", - placeholder: vm.i18n`Filter rooms…`, - "aria-label": vm.i18n`Filter rooms by name`, - autocomplete: true, - name: "room-filter", - onInput: event => vm.setFilter(event.target.value), + placeholder: options?.label, + "aria-label": options?.label, + autocomplete: options?.autocomplete, + name: options?.name, + onInput: event => options.set(event.target.value), onKeydown: event => { if (event.key === "Escape" || event.key === "Esc") { - filterInput.value = ""; - vm.clearFilter(); + clear(); } - } + }, + onFocus: () => filterInput.select() }); + const clearButton = t.button({ + onClick: clear, + title: options.i18n`Clear`, + "aria-label": options.i18n`Clear` + }); + return t.div({className: "FilterField"}, [filterInput, clearButton]); + } +} + +export class LeftPanelView extends TemplateView { + render(t, vm) { + const gridButtonLabel = vm => { + return vm.gridEnabled ? + vm.i18n`Show single room` : + vm.i18n`Enable grid layout`; + }; + const utilitiesRow = t.div({className: "utilities"}, [ + t.view(new FilterField({ + i18n: vm.i18n, + label: vm.i18n`Filter rooms…`, + name: "room-filter", + autocomplete: true, + set: query => vm.setFilter(query), + clear: () => vm.clearFilter() + })), + t.button({ + onClick: () => vm.toggleGrid(), + className: { + utility: true, + grid: true, + on: vm => vm.gridEnabled + }, + title: gridButtonLabel, + "aria-label": gridButtonLabel + }) + ]); + return t.div({className: "LeftPanel"}, [ - t.div({className: "filter"}, [ - filterInput, - t.button({onClick: () => { - filterInput.value = ""; - vm.clearFilter(); - }}, vm.i18n`Clear`), - t.button({ - onClick: () => vm.toggleGrid(), - className: "grid" - }, vm => vm.gridEnabled ? "Single" : "Grid") - ]), + utilitiesRow, t.view(new ListView( { className: "RoomList", From bd959bc14728b0eabe0d2587ee616959cf6958a6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 17:59:28 +0200 Subject: [PATCH 16/37] style grid button --- src/ui/web/css/themes/element/theme.css | 41 +++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 234b63ef..41a9b82f 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -117,6 +117,24 @@ button.styled { font-weight: 500; } +button.utility { + width: 32px; + height: 32px; + background-position: center; + background-color: #e1e3e6; + background-repeat: no-repeat; + border: none; + border-radius: 100%; +} + +button.utility.grid { + background-image: url('icons/enable-grid.svg'); +} + +button.utility.grid.on { + background-image: url('icons/disable-grid.svg'); +} + .FilterField { background-color: #e1e3e6; border-radius: 16px; @@ -185,6 +203,15 @@ button.styled { .LeftPanel { background: rgba(245, 245, 245, 0.90); font-size: 1.5rem; + padding: 12px 0 0 8px; +} + +.LeftPanel .utilities { + margin-right: 8px; +} + +.LeftPanel .utilities :not(:first-child) { + margin-left: 8px; } .LeftPanel .filter { @@ -202,8 +229,8 @@ button.styled { } .LeftPanel li { - margin: 3px 10px; - padding: 5px; + margin: 12px 0; + padding-right: 5px; /* vertical align */ align-items: center; } @@ -265,6 +292,8 @@ a { .RoomPlaceholderView { align-items: center; justify-content: center; + text-align: center; + padding: 20px; } .SessionPickerView li { @@ -303,12 +332,6 @@ a { color: #FF4B55; } - -/*.RoomGridView > :not(.focused) .MessageComposer { - display: none; -} -*/ - .RoomGridView > div.container { border-right: 1px solid rgba(245, 245, 245, 0.90); border-bottom: 1px solid rgba(245, 245, 245, 0.90); @@ -316,7 +339,7 @@ a { .RoomGridView > div.focus-ring { border: 2px solid rgba(134, 193, 165, 1); - border-radius: 2px; + border-radius: 12px; } .RoomHeader { From c80c369c42d3352697541268f76bdf798d7152f5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 17:59:40 +0200 Subject: [PATCH 17/37] prevent grid item from growing to max content height --- src/ui/web/css/layout.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/web/css/layout.css b/src/ui/web/css/layout.css index eea0eed2..7a30381b 100644 --- a/src/ui/web/css/layout.css +++ b/src/ui/web/css/layout.css @@ -101,6 +101,7 @@ html { .RoomGridView > div { display: flex; min-width: 0; + min-height: 0; grid-column: var(--column); grid-row: var(--row); } From b79b41adcd02cca37386cee8c415d308160e3457 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 17:59:58 +0200 Subject: [PATCH 18/37] keep focused class --- src/ui/web/session/RoomGridView.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/web/session/RoomGridView.js b/src/ui/web/session/RoomGridView.js index f954c4f1..235af6da 100644 --- a/src/ui/web/session/RoomGridView.js +++ b/src/ui/web/session/RoomGridView.js @@ -26,7 +26,10 @@ export class RoomGridView extends TemplateView { children.push(t.div({ onClick: () => vm.setFocusAt(x, y), onFocusin: () => vm.setFocusAt(x, y), - className: "container", + className: { + "container": true, + "focused": vm => vm.isFocusAt(x, y) + }, style: `--column: ${x + 1}; --row: ${y + 1}` },t.mapView(vm => vm.roomViewModelAt(x, y), roomVM => { if (roomVM) { From dafa9954296792ccd714d330b1ad9944a40b0865 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 18:00:07 +0200 Subject: [PATCH 19/37] placeholder does not count as room shown --- src/ui/web/session/SessionView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/web/session/SessionView.js b/src/ui/web/session/SessionView.js index cf96be54..f997c0d0 100644 --- a/src/ui/web/session/SessionView.js +++ b/src/ui/web/session/SessionView.js @@ -26,7 +26,7 @@ export class SessionView extends TemplateView { return t.div({ className: { "SessionView": true, - "room-shown": vm => !!vm.selectionId + "room-shown": vm => vm.selectionId !== "placeholder" }, }, [ t.view(new SessionStatusView(vm.sessionStatusViewModel)), From 423a463cd64161f1a48fb30a4ce55379c2c76c17 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 18:00:26 +0200 Subject: [PATCH 20/37] disable css variables transformation as it breaks the grid layout f/ now --- scripts/build.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/build.mjs b/scripts/build.mjs index f8f08e39..45a668c1 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -302,7 +302,6 @@ async function buildCssLegacy(entryPath, urlMapper = null) { const preCss = await fs.readFile(entryPath, "utf8"); const options = [ postcssImport, - cssvariables(), flexbugsFixes() ]; if (urlMapper) { From 1a331a22ec3d8b1c4b9335789aafa4fecd0d74df Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 7 Oct 2020 18:01:52 +0200 Subject: [PATCH 21/37] release v0.1.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 954f3cb9..4f48d59f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydrogen-web", - "version": "0.1.7", + "version": "0.1.8", "description": "A javascript matrix client prototype, trying to minize RAM usage by offloading as much as possible to IndexedDB", "main": "index.js", "directories": { From 26112fe3de9ac7c66e68a9990056a07ff419d500 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 10:10:03 +0200 Subject: [PATCH 22/37] update grid icons --- src/ui/web/css/themes/element/icons/disable-grid.svg | 4 +--- src/ui/web/css/themes/element/icons/enable-grid.svg | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/ui/web/css/themes/element/icons/disable-grid.svg b/src/ui/web/css/themes/element/icons/disable-grid.svg index 1be4ae6a..db870fcd 100644 --- a/src/ui/web/css/themes/element/icons/disable-grid.svg +++ b/src/ui/web/css/themes/element/icons/disable-grid.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/ui/web/css/themes/element/icons/enable-grid.svg b/src/ui/web/css/themes/element/icons/enable-grid.svg index 776fec35..1e06f9b7 100644 --- a/src/ui/web/css/themes/element/icons/enable-grid.svg +++ b/src/ui/web/css/themes/element/icons/enable-grid.svg @@ -1,6 +1,3 @@ - - - - + From e80f37603bb8a699083fee18959277e3b7688cb7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 10:10:39 +0200 Subject: [PATCH 23/37] prevent breaking narrow layouts with inputs --- src/ui/web/css/form.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/web/css/form.css b/src/ui/web/css/form.css index e9771611..bdb47bec 100644 --- a/src/ui/web/css/form.css +++ b/src/ui/web/css/form.css @@ -18,6 +18,7 @@ limitations under the License. .form input { display: block; width: 100%; + min-width: 0; box-sizing: border-box; } From c2eebb9af29dd17f261efacf96408aed49fa8f72 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 10:11:12 +0200 Subject: [PATCH 24/37] prevent filter field and composer breaking narrow layouts --- src/ui/web/css/left-panel.css | 1 + src/ui/web/css/room.css | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ui/web/css/left-panel.css b/src/ui/web/css/left-panel.css index 5a7ae221..3b49ff51 100644 --- a/src/ui/web/css/left-panel.css +++ b/src/ui/web/css/left-panel.css @@ -25,6 +25,7 @@ limitations under the License. .LeftPanel .utilities .FilterField { flex: 1; + min-width: 0; } .LeftPanel ul { diff --git a/src/ui/web/css/room.css b/src/ui/web/css/room.css index 07999a2a..4ed19c35 100644 --- a/src/ui/web/css/room.css +++ b/src/ui/web/css/room.css @@ -71,6 +71,7 @@ limitations under the License. .MessageComposer > input { display: block; flex: 1; + min-width: 0; box-sizing: border-box; } From fd4b3d238fefaf98882841a405737e8fa897218c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 10:13:05 +0200 Subject: [PATCH 25/37] increase click area of clear filter button, add search icon --- .../web/css/themes/element/icons/search.svg | 3 +++ src/ui/web/css/themes/element/theme.css | 23 +++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 src/ui/web/css/themes/element/icons/search.svg diff --git a/src/ui/web/css/themes/element/icons/search.svg b/src/ui/web/css/themes/element/icons/search.svg new file mode 100644 index 00000000..1531c7ac --- /dev/null +++ b/src/ui/web/css/themes/element/icons/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 41a9b82f..f1109baa 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -136,22 +136,26 @@ button.utility.grid.on { } .FilterField { + background-image: url('icons/search.svg'); + background-repeat: no-repeat; + background-position: 8px center; background-color: #e1e3e6; + /* to prevent jumps when adding a border on focus */ + border: 1px solid transparent; border-radius: 16px; height: 32px; align-items: center; - padding: 0 8px; + padding-left: 30px; /* 8 + 14 (icon) + 8*/ box-sizing: border-box; } -.FilterField :not(:first-child) { - margin-left: 8px; -} - .FilterField:focus-within { border: 1px #e1e3e6 solid; background-color: white; } +.FilterField:focus-within button { + border-color: white; +} /*.FilterField:not(:focus-within) button { display: none; @@ -169,14 +173,15 @@ button.utility.grid.on { } .FilterField button { - width: 16px; - height: 16px; + width: 30px; /* 32 - 1 (top) - 1 (bottom) */ + height: 30px; /* 32 - 1 (top) - 1 (bottom) */ background-position: center; background-color: #e1e3e6; background-repeat: no-repeat; background-image: url('icons/clear.svg'); - border: none; + border: 7px solid transparent; /* 8 - 1 */ border-radius: 100%; + box-sizing: border-box; } .PreSessionScreen { @@ -210,7 +215,7 @@ button.utility.grid.on { margin-right: 8px; } -.LeftPanel .utilities :not(:first-child) { +.LeftPanel .utilities > :not(:first-child) { margin-left: 8px; } From c4cfb6f6d1445956d8af1fe7068b79f01ee6f4f6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 10:29:30 +0200 Subject: [PATCH 26/37] align left panel to 4px grid better, and simply margins --- src/ui/web/css/themes/element/theme.css | 34 ++++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index f1109baa..b099d83b 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -208,11 +208,11 @@ button.utility.grid.on { .LeftPanel { background: rgba(245, 245, 245, 0.90); font-size: 1.5rem; - padding: 12px 0 0 8px; + padding: 12px 8px 0 8px; } -.LeftPanel .utilities { - margin-right: 8px; +.LeftPanel > :not(:first-child) { + margin-top: 12px; } .LeftPanel .utilities > :not(:first-child) { @@ -228,36 +228,40 @@ button.utility.grid.on { border: none; } -.LeftPanel ul { +.LeftPanel .RoomList { padding: 0; - margin: 0; + margin-right: -8px; /* make scrollbar hit right edge of parent */ } -.LeftPanel li { - margin: 12px 0; - padding-right: 5px; +.RoomList li { + margin: 0; + padding-right: 8px; /* vertical align */ align-items: center; } -.LeftPanel li.active { +.RoomList li:not(:first-child) { + margin-top: 12px; +} + +.RoomList li.active { background: rgba(141, 151, 165, 0.1); border-radius: 5px; } -.LeftPanel li > * { - margin-right: 10px; +.RoomList li > * { + margin-right: 8px; } -.LeftPanel .description { +.RoomList .description { align-items: baseline; } -.LeftPanel .name.unread { +.RoomList .name.unread { font-weight: 600; } -.LeftPanel .badge { +.RoomList .badge { min-width: 1.6rem; height: 1.6rem; border-radius: 1.6rem; @@ -271,7 +275,7 @@ button.utility.grid.on { text-align: center; } -.LeftPanel .badge.highlighted { +.RoomList .badge.highlighted { background-color: #ff4b55; } From 47a43869e684bb5e7446aba4e5b6db487449a2d2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 14:17:43 +0200 Subject: [PATCH 27/37] fix grid layout in IE 11 this brings back index addressing rather than x y in the grid vm, as we need to have a css class for every position for IE 11, as we can't use css variables and autoprefixer can translate grid-areas --- package.json | 5 +- scripts/build.mjs | 3 + src/domain/session/RoomGridViewModel.js | 36 ++------- src/ui/web/css/layout.css | 18 ++++- src/ui/web/session/RoomGridView.js | 41 +++++----- yarn.lock | 99 ++++++++++++++++++++++++- 6 files changed, 142 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 4f48d59f..5d6ccdd0 100644 --- a/package.json +++ b/package.json @@ -29,13 +29,14 @@ "@rollup/plugin-commonjs": "^15.0.0", "@rollup/plugin-multi-entry": "^4.0.0", "@rollup/plugin-node-resolve": "^9.0.0", + "autoprefixer": "^10.0.1", "cheerio": "^1.0.0-rc.3", "commander": "^6.0.0", "core-js": "^3.6.5", "finalhandler": "^1.1.1", "impunity": "^1.0.0", "mdn-polyfills": "^5.20.0", - "postcss": "^7.0.32", + "postcss": "^8.1.1", "postcss-css-variables": "^0.17.0", "postcss-flexbugs-fixes": "^4.2.1", "postcss-import": "^12.0.1", @@ -47,11 +48,11 @@ "xxhashjs": "^0.2.2" }, "dependencies": { - "es6-promise": "https://github.com/bwindels/es6-promise.git#bwindels/expose-flush", "aes-js": "^3.1.2", "another-json": "^0.2.0", "base64-arraybuffer": "^0.2.0", "bs58": "^4.0.1", + "es6-promise": "https://github.com/bwindels/es6-promise.git#bwindels/expose-flush", "olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz", "text-encoding": "^0.7.0" } diff --git a/scripts/build.mjs b/scripts/build.mjs index 45a668c1..1d632768 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -39,6 +39,7 @@ import removeJsComments from 'rollup-plugin-cleanup'; import postcssUrl from "postcss-url"; import cssvariables from "postcss-css-variables"; +import autoprefixer from "autoprefixer"; import flexbugsFixes from "postcss-flexbugs-fixes"; const __filename = fileURLToPath(import.meta.url); @@ -302,6 +303,8 @@ async function buildCssLegacy(entryPath, urlMapper = null) { const preCss = await fs.readFile(entryPath, "utf8"); const options = [ postcssImport, + cssvariables(), + autoprefixer({overrideBrowserslist: ["IE 11"], grid: "no-autoplace"}), flexbugsFixes() ]; if (urlMapper) { diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js index 40b7192c..4c169c3a 100644 --- a/src/domain/session/RoomGridViewModel.js +++ b/src/domain/session/RoomGridViewModel.js @@ -25,39 +25,15 @@ export class RoomGridViewModel extends ViewModel { this._viewModels = []; } - _posToIdx(x, y) { - return (y * this.width) + x; + roomViewModelAt(i) { + return this._viewModels[i]?.vm; } - _idxToX(idx) { - return idx % this.width; + get focusIndex() { + return this._selectedIndex; } - _idxToY(idx) { - return Math.floor(idx / this.width); - } - - roomViewModelAt(x, y) { - return this._viewModels[this._posToIdx(x, y)]?.vm; - } - - get focusX() { - return this._idxToX(this._selectedIndex); - } - - get focusY() { - return this._idxToY(this._selectedIndex); - } - - isFocusAt(x, y) { - return this._posToIdx(x, y) === this._selectedIndex; - } - - setFocusAt(x, y) { - this._setFocusedIndex(this._posToIdx(x, y)); - } - - _setFocusedIndex(idx) { + setFocusIndex(idx) { if (idx === this._selectedIndex) { return; } @@ -99,7 +75,7 @@ export class RoomGridViewModel extends ViewModel { tryFocusRoom(roomId) { const index = this._viewModels.findIndex(vms => vms?.vm._room.id === roomId); if (index >= 0) { - this._setFocusedIndex(index); + this.setFocusIndex(index); return true; } return false; diff --git a/src/ui/web/css/layout.css b/src/ui/web/css/layout.css index 7a30381b..6d6feb07 100644 --- a/src/ui/web/css/layout.css +++ b/src/ui/web/css/layout.css @@ -94,16 +94,26 @@ html { .RoomGridView { display: grid; - grid-template-columns: repeat(var(--columns), 1fr); - grid-template-rows: repeat(var(--rows), 1fr); } +.RoomGridView.layout3x2 { + grid-template: + "t0 t1 t2" 1fr + "t3 t4 t5" 1fr / + 1fr 1fr 1fr; +} + +.RoomGridView > .tile0 {grid-area: t0;} +.RoomGridView > .tile1 {grid-area: t1;} +.RoomGridView > .tile2 {grid-area: t2;} +.RoomGridView > .tile3 {grid-area: t3;} +.RoomGridView > .tile4 {grid-area: t4;} +.RoomGridView > .tile5 {grid-area: t5;} + .RoomGridView > div { display: flex; min-width: 0; min-height: 0; - grid-column: var(--column); - grid-row: var(--row); } .RoomGridView > div.focus-ring { diff --git a/src/ui/web/session/RoomGridView.js b/src/ui/web/session/RoomGridView.js index 235af6da..d7b3e591 100644 --- a/src/ui/web/session/RoomGridView.js +++ b/src/ui/web/session/RoomGridView.js @@ -21,29 +21,24 @@ import {TemplateView} from "../general/TemplateView.js"; export class RoomGridView extends TemplateView { render(t, vm) { const children = []; - for (let y = 0; y < vm.height; y+=1) { - for (let x = 0; x < vm.width; x+=1) { - children.push(t.div({ - onClick: () => vm.setFocusAt(x, y), - onFocusin: () => vm.setFocusAt(x, y), - className: { - "container": true, - "focused": vm => vm.isFocusAt(x, y) - }, - style: `--column: ${x + 1}; --row: ${y + 1}` - },t.mapView(vm => vm.roomViewModelAt(x, y), roomVM => { - if (roomVM) { - return new RoomView(roomVM); - } else { - return new RoomPlaceholderView(); - } - }))); - } + for (let i = 0; i < (vm.height * vm.width); i+=1) { + children.push(t.div({ + onClick: () => vm.setFocusIndex(i), + onFocusin: () => vm.setFocusIndex(i), + className: { + "container": true, + [`tile${i}`]: true, + "focused": vm => vm.focusIndex === i + }, + },t.mapView(vm => vm.roomViewModelAt(i), roomVM => { + if (roomVM) { + return new RoomView(roomVM); + } else { + return new RoomPlaceholderView(); + } + }))); } - children.push(t.div({className: "focus-ring", style: vm => `--column: ${vm.focusX + 1}; --row: ${vm.focusY + 1}`})); - return t.div({ - className: "RoomGridView", - style: `--columns: ${vm.width}; --rows: ${vm.height}` - }, children); + children.push(t.div({className: vm => `focus-ring tile${vm.focusIndex}`})); + return t.div({className: "RoomGridView layout3x2"}, children); } } diff --git a/yarn.lock b/yarn.lock index 232f948c..0a7b8e74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -933,6 +933,18 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +autoprefixer@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.0.1.tgz#e2d9000f84ebd98d77b7bc16f8adb2ff1f7bb946" + integrity sha512-aQo2BDIsoOdemXUAOBpFv4ZQa2DrOtEufarYhtFsK1088Ca0TUwu/aQWf0M3mrILXZ3mTIVn1lR3hPW8acacsw== + dependencies: + browserslist "^4.14.5" + caniuse-lite "^1.0.30001137" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss-value-parser "^4.1.0" + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -980,6 +992,16 @@ browserslist@^4.12.0, browserslist@^4.8.5: escalade "^3.0.2" node-releases "^1.1.60" +browserslist@^4.14.5: + version "4.14.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.5.tgz#1c751461a102ddc60e40993639b709be7f2c4015" + integrity sha512-Z+vsCZIvCBvqLoYkBFTwEYH3v5MCQbsAjp50ERycpOjnPmolg1Gjy4+KaWWpm8QOJt9GHkhdqAl14NpCX73CWA== + dependencies: + caniuse-lite "^1.0.30001135" + electron-to-chromium "^1.3.571" + escalade "^3.1.0" + node-releases "^1.1.61" + bs58@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -997,6 +1019,11 @@ caniuse-lite@^1.0.30001111: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001115.tgz#c04cd828883ba47f6f776312e0817bcc9040cfa4" integrity sha512-NZrG0439ePYna44lJX8evHX2L7Z3/z3qjVLnHgbBb/duNEnGo348u+BQS5o4HTWcrb++100dHFrU36IesIrC1Q== +caniuse-lite@^1.0.30001135, caniuse-lite@^1.0.30001137: + version "1.0.30001144" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001144.tgz#bca0fffde12f97e1127a351fec3bfc1971aa3b3d" + integrity sha512-4GQTEWNMnVZVOFG3BK0xvGeaDAtiPAbG2N8yuMXuXzx/c2Vd4XoMPO8+E918zeXn5IF0FRVtGShBfkfQea2wHQ== + chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1030,6 +1057,11 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +colorette@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" + integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== + colors@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -1190,6 +1222,11 @@ electron-to-chromium@^1.3.523: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.534.tgz#fc7af8518dd00a5b22a24aed3f116b5d097e2330" integrity sha512-7x2S3yUrspNHQOoPk+Eo+iHViSiJiEGPI6BpmLy1eT2KRNGCkBt/NUYqjfXLd1DpDCQp7n3+LfA1RkbG+LqTZQ== +electron-to-chromium@^1.3.571: + version "1.3.578" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.578.tgz#e6671936f4571a874eb26e2e833aa0b2c0b776e0" + integrity sha512-z4gU6dA1CbBJsAErW5swTGAaU2TBzc2mPAonJb00zqW1rOraDo2zfBMDRvaz9cVic+0JEZiYbHWPw/fTaZlG2Q== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -1214,6 +1251,11 @@ escalade@^3.0.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== +escalade@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" + integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1382,6 +1424,18 @@ is-reference@^1.2.1: dependencies: "@types/estree" "*" +isarray@1.0.0, isarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + js-cleanup@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-cleanup/-/js-cleanup-1.0.1.tgz#1d38080c7ee92e1d2d2b94054d0a33c48951e0df" @@ -1425,6 +1479,14 @@ levenary@^1.1.1: dependencies: leven "^3.1.0" +line-column@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/line-column/-/line-column-1.0.2.tgz#d25af2936b6f4849172b312e4792d1d987bc34a2" + integrity sha1-0lryk2tvSEkXKzEuR5LR2Ye8NKI= + dependencies: + isarray "^1.0.0" + isobject "^2.0.0" + lodash@^4.15.0: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" @@ -1506,11 +1568,26 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +nanoid@^3.1.12: + version "3.1.12" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" + integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== + node-releases@^1.1.60: version "1.1.60" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== +node-releases@^1.1.61: + version "1.1.61" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" + integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + nth-check@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -1518,6 +1595,11 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + object-keys@^1.0.11, object-keys@^1.0.12: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -1631,6 +1713,11 @@ postcss-value-parser@^3.2.3: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + postcss@^6.0.8: version "6.0.23" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" @@ -1649,7 +1736,7 @@ postcss@^7.0.1: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.32: +postcss@^7.0.2, postcss@^7.0.26: version "7.0.32" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== @@ -1658,6 +1745,16 @@ postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.32: source-map "^0.6.1" supports-color "^6.1.0" +postcss@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.1.1.tgz#c3a287dd10e4f6c84cb3791052b96a5d859c9389" + integrity sha512-9DGLSsjooH3kSNjTZUOt2eIj2ZTW0VI2PZ/3My+8TC7KIbH2OKwUlISfDsf63EP4aiRUt3XkEWMWvyJHvJelEg== + dependencies: + colorette "^1.2.1" + line-column "^1.0.2" + nanoid "^3.1.12" + source-map "^0.6.1" + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" From 5c299c1db9a0367aeef94b4f33136e5b0b748765 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 14:18:48 +0200 Subject: [PATCH 28/37] remove prefixes now we auto prefix --- src/ui/web/css/avatar.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ui/web/css/avatar.css b/src/ui/web/css/avatar.css index f64d39ae..4c7d1074 100644 --- a/src/ui/web/css/avatar.css +++ b/src/ui/web/css/avatar.css @@ -21,9 +21,6 @@ limitations under the License. height: var(--avatar-size); overflow: hidden; flex-shrink: 0; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; user-select: none; line-height: var(--avatar-size); font-size: calc(var(--avatar-size) * 0.6); From cdd1efe47706ae44859cc77e7fd3acf14bd003f0 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 14:19:02 +0200 Subject: [PATCH 29/37] ignore build packages --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 00e360eb..bd1c201e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ sessionexports bundle.js target lib +*.tar.gz From 2cbe349a4dc353b1d79a751f52cd5658d2a496a5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 14:21:34 +0200 Subject: [PATCH 30/37] don't read private parts --- src/domain/session/RoomGridViewModel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain/session/RoomGridViewModel.js b/src/domain/session/RoomGridViewModel.js index 4c169c3a..9d91cd99 100644 --- a/src/domain/session/RoomGridViewModel.js +++ b/src/domain/session/RoomGridViewModel.js @@ -73,7 +73,7 @@ export class RoomGridViewModel extends ViewModel { * @package */ tryFocusRoom(roomId) { - const index = this._viewModels.findIndex(vms => vms?.vm._room.id === roomId); + const index = this._viewModels.findIndex(vms => vms?.vm.id === roomId); if (index >= 0) { this.setFocusIndex(index); return true; From 59802d18125295c02d0771462a22c421b6ef629c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 15:00:20 +0200 Subject: [PATCH 31/37] style room header --- src/ui/web/css/room.css | 9 ++----- .../css/themes/element/icons/chevron-left.svg | 10 +++++++ src/ui/web/css/themes/element/theme.css | 27 +++++++------------ src/ui/web/session/room/RoomView.js | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-) create mode 100644 src/ui/web/css/themes/element/icons/chevron-left.svg diff --git a/src/ui/web/css/room.css b/src/ui/web/css/room.css index 4ed19c35..827b3b1b 100644 --- a/src/ui/web/css/room.css +++ b/src/ui/web/css/room.css @@ -24,13 +24,8 @@ limitations under the License. align-items: center; } -.RoomHeader > *:last-child { - margin-right: 0; -} - -.RoomHeader > * { - margin-right: 10px; - flex: 0 0 auto; +.RoomHeader h2 { + flex: 1; } .RoomHeader button { diff --git a/src/ui/web/css/themes/element/icons/chevron-left.svg b/src/ui/web/css/themes/element/icons/chevron-left.svg new file mode 100644 index 00000000..c686cf88 --- /dev/null +++ b/src/ui/web/css/themes/element/icons/chevron-left.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index b099d83b..f347fc46 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -352,8 +352,11 @@ a { } .RoomHeader { - background: rgba(245, 245, 245, 0.90); - padding: 10px; + box-sizing: border-box; + height: 58px; /* 12 + 36 + 12 to align with filter field + margin */ + background: white; + padding: 0 16px; + border-bottom: 1px solid rgba(245, 245, 245, 0.90); } .RoomHeader h2 { @@ -361,23 +364,13 @@ a { font-weight: 600; } -.RoomHeader button { - width: 40px; - height: 40px; - font-size: 1.5em; - padding: 0; - background: white; - border: none; - font-weight: bolder; - line-height: 40px; +.RoomHeader > :not(:first-child) { + margin-left: 8px; } -.back::before { - content: "☰"; -} - -.more::before { - content: "⋮"; +button.back { + background-image: url('icons/chevron-left.svg'); + background-position-x: 10px; } .RoomHeader .topic { diff --git a/src/ui/web/session/room/RoomView.js b/src/ui/web/session/room/RoomView.js index 3f9b9bce..9eeeb554 100644 --- a/src/ui/web/session/room/RoomView.js +++ b/src/ui/web/session/room/RoomView.js @@ -26,7 +26,7 @@ export class RoomView extends TemplateView { return t.div({className: "RoomView"}, [ t.div({className: "TimelinePanel"}, [ t.div({className: "RoomHeader"}, [ - t.button({className: "back", onClick: () => vm.close()}), + t.button({className: "utility back", onClick: () => vm.close()}), renderAvatar(t, vm, 32), t.div({className: "room-description"}, [ t.h2(vm => vm.name), From 868b1a10457605475a846f58169980ce72705c7a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 15:10:32 +0200 Subject: [PATCH 32/37] style composer --- src/ui/web/css/room.css | 1 + src/ui/web/css/themes/element/theme.css | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ui/web/css/room.css b/src/ui/web/css/room.css index 827b3b1b..e57af8e5 100644 --- a/src/ui/web/css/room.css +++ b/src/ui/web/css/room.css @@ -61,6 +61,7 @@ limitations under the License. .MessageComposer { display: flex; + align-items: center; } .MessageComposer > input { diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index f347fc46..f3440ef5 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -383,15 +383,25 @@ button.back { .MessageComposer { border-top: 1px solid rgba(245, 245, 245, 0.90); + padding: 8px 16px; +} + +.MessageComposer > :not(:first-child) { + margin-left: 12px; } .MessageComposer > input { - padding: 0.8em; + padding: 0 16px; border: none; + border-radius: 24px; + background: #F6F6F6; + height: 48px; + line-height: 48px; + font-size: 14px; + font-family: "Inter", sans-serif; } .MessageComposer > button.send { - margin: 8px; width: 32px; height: 32px; display: block; From 4783e03871d289ffb398aea048d73d75c964b9c3 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 15:21:16 +0200 Subject: [PATCH 33/37] fix room header margin issue with hidden back button --- src/ui/web/css/themes/element/theme.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index f3440ef5..0bf46aef 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -364,8 +364,11 @@ a { font-weight: 600; } -.RoomHeader > :not(:first-child) { - margin-left: 8px; +.RoomHeader > :not(:last-child) { + /* use margin-right because the first item, + button.back might be hidden and then we don't + want a margin-left on the second item*/ + margin-right: 8px; } button.back { From 93e301e4fa1673bcbce7eb1b7e84c0c2086ef453 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 15:53:13 +0200 Subject: [PATCH 34/37] fix spinner margins --- src/ui/web/css/login.css | 11 +++++++++-- src/ui/web/css/room.css | 4 ++-- src/ui/web/css/themes/element/theme.css | 4 ++++ src/ui/web/css/timeline.css | 5 ++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ui/web/css/login.css b/src/ui/web/css/login.css index 1032ead0..192ccc13 100644 --- a/src/ui/web/css/login.css +++ b/src/ui/web/css/login.css @@ -34,7 +34,10 @@ limitations under the License. cursor: pointer; display: flex; align-items: center; - gap: 10px; +} + +.SessionPickerView .session-info > :not(:first-child) { + margin-left: 8px; } .SessionPickerView li .user-id { @@ -53,9 +56,13 @@ limitations under the License. display: flex; } +.SessionLoadView > :not(:first-child) { + margin-left: 12px; +} + .SessionLoadView p { flex: 1; - margin: 0 0 0 10px; + margin: 0; } .SessionLoadView .spinner { diff --git a/src/ui/web/css/room.css b/src/ui/web/css/room.css index e57af8e5..8c70edf2 100644 --- a/src/ui/web/css/room.css +++ b/src/ui/web/css/room.css @@ -77,6 +77,6 @@ limitations under the License. justify-content: center; } -.TimelineLoadingView div { - margin-right: 10px; +.TimelineLoadingView > :not(:first-child) { + margin-left: 12px; } diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 0bf46aef..8c71a839 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -507,3 +507,7 @@ ul.Timeline > li.messageStatus .message-container > p { text-align: center; border-radius: 10px; } + +.GapView > :not(:first-child) { + margin-left: 12px; +} diff --git a/src/ui/web/css/timeline.css b/src/ui/web/css/timeline.css index d3f29fc9..44ff29d6 100644 --- a/src/ui/web/css/timeline.css +++ b/src/ui/web/css/timeline.css @@ -76,7 +76,6 @@ limitations under the License. visibility: visible; } -.GapView > div { - flex: 1 1 0; - margin-right: 10px; +.GapView > :nth-child(2) { + flex: 1; } From 35832e387aefb8f69525bf43736a1f926b44c0c6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 16:14:59 +0200 Subject: [PATCH 35/37] Swap grid tile description based on focus swap RoomPlaceholderView for generic StaticView --- src/ui/web/css/layout.css | 7 ++++++- src/ui/web/css/room.css | 5 ----- src/ui/web/css/themes/bubbles/theme.css | 2 +- src/ui/web/css/themes/element/theme.css | 15 ++++++++++++++- .../StaticView.js} | 8 ++++---- src/ui/web/session/RoomGridView.js | 7 +++++-- src/ui/web/session/SessionView.js | 4 ++-- 7 files changed, 32 insertions(+), 16 deletions(-) rename src/ui/web/{session/RoomPlaceholderView.js => general/StaticView.js} (79%) diff --git a/src/ui/web/css/layout.css b/src/ui/web/css/layout.css index 6d6feb07..2b95a29c 100644 --- a/src/ui/web/css/layout.css +++ b/src/ui/web/css/layout.css @@ -28,6 +28,11 @@ html { } } +.room-placeholder { + display: flex; + flex-direction: row; +} + .SessionView { display: flex; flex-direction: column; @@ -64,7 +69,7 @@ html { min-width: 0; } -.RoomPlaceholderView, .RoomView, .RoomGridView { +.room-placeholder, .RoomView, .RoomGridView { flex: 1 0 0; min-width: 0; } diff --git a/src/ui/web/css/room.css b/src/ui/web/css/room.css index 8c70edf2..27630728 100644 --- a/src/ui/web/css/room.css +++ b/src/ui/web/css/room.css @@ -15,11 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.RoomPlaceholderView { - display: flex; - flex-direction: row; -} - .RoomHeader { align-items: center; } diff --git a/src/ui/web/css/themes/bubbles/theme.css b/src/ui/web/css/themes/bubbles/theme.css index d06b49f1..1cb3013d 100644 --- a/src/ui/web/css/themes/bubbles/theme.css +++ b/src/ui/web/css/themes/bubbles/theme.css @@ -70,7 +70,7 @@ a { background-color: #555; } -.RoomPlaceholderView { +.room-placeholder { align-items: center; justify-content: center; } diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 8c71a839..3ea34fa3 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -298,7 +298,7 @@ a { top: 72px; } -.RoomPlaceholderView { +.room-placeholder { align-items: center; justify-content: center; text-align: center; @@ -346,6 +346,19 @@ a { border-bottom: 1px solid rgba(245, 245, 245, 0.90); } +.RoomGridView > .focused > .room-placeholder .unfocused { + display: none; +} + +.RoomGridView > :not(.focused) > .room-placeholder .focused { + display: none; +} + +.room-placeholder .unfocused { + color: #8D99A5; +} + + .RoomGridView > div.focus-ring { border: 2px solid rgba(134, 193, 165, 1); border-radius: 12px; diff --git a/src/ui/web/session/RoomPlaceholderView.js b/src/ui/web/general/StaticView.js similarity index 79% rename from src/ui/web/session/RoomPlaceholderView.js rename to src/ui/web/general/StaticView.js index 3b79b7ef..ae4f0f98 100644 --- a/src/ui/web/session/RoomPlaceholderView.js +++ b/src/ui/web/general/StaticView.js @@ -1,5 +1,6 @@ /* Copyright 2020 Bruno Windels +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. @@ -16,13 +17,12 @@ limitations under the License. import {tag} from "../general/html.js"; -export class RoomPlaceholderView { - constructor() { - this._root = null; +export class StaticView { + constructor(render) { + this._root = render(tag); } mount() { - this._root = tag.div({className: "RoomPlaceholderView"}, tag.h2("Choose a room on the left side.")); return this._root; } diff --git a/src/ui/web/session/RoomGridView.js b/src/ui/web/session/RoomGridView.js index d7b3e591..29eeb329 100644 --- a/src/ui/web/session/RoomGridView.js +++ b/src/ui/web/session/RoomGridView.js @@ -15,8 +15,8 @@ limitations under the License. */ import {RoomView} from "./room/RoomView.js"; -import {RoomPlaceholderView} from "./RoomPlaceholderView.js"; import {TemplateView} from "../general/TemplateView.js"; +import {StaticView} from "../general/StaticView.js"; export class RoomGridView extends TemplateView { render(t, vm) { @@ -34,7 +34,10 @@ export class RoomGridView extends TemplateView { if (roomVM) { return new RoomView(roomVM); } else { - return new RoomPlaceholderView(); + return new StaticView(t => t.div({className: "room-placeholder"}, [ + t.h2({className: "focused"}, vm.i18n`Select a room on the left`), + t.h2({className: "unfocused"}, vm.i18n`Click to select this tile`), + ])); } }))); } diff --git a/src/ui/web/session/SessionView.js b/src/ui/web/session/SessionView.js index f997c0d0..a85ff3dd 100644 --- a/src/ui/web/session/SessionView.js +++ b/src/ui/web/session/SessionView.js @@ -17,7 +17,7 @@ limitations under the License. import {LeftPanelView} from "./leftpanel/LeftPanelView.js"; import {RoomView} from "./room/RoomView.js"; import {TemplateView} from "../general/TemplateView.js"; -import {RoomPlaceholderView} from "./RoomPlaceholderView.js"; +import {StaticView} from "../general/StaticView.js"; import {SessionStatusView} from "./SessionStatusView.js"; import {RoomGridView} from "./RoomGridView.js"; @@ -37,7 +37,7 @@ export class SessionView extends TemplateView { case "roomgrid": return new RoomGridView(vm.roomGridViewModel); case "placeholder": - return new RoomPlaceholderView(); + return new StaticView(t => t.div({className: "room-placeholder"}, t.h2(vm.i18n`Choose a room on the left side.`))); default: //room id return new RoomView(vm.currentRoom); } From 0db3842fcc5e8f1100e6749aa111c4647f11d075 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 16:18:55 +0200 Subject: [PATCH 36/37] release v0.1.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d6ccdd0..0d0f6585 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hydrogen-web", - "version": "0.1.8", + "version": "0.1.9", "description": "A javascript matrix client prototype, trying to minize RAM usage by offloading as much as possible to IndexedDB", "main": "index.js", "directories": { From cb0ef1a1aeb718105c5140cbdcc44cb77bf766b9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Oct 2020 16:29:38 +0200 Subject: [PATCH 37/37] this makes the caret huge on gnome web --- src/ui/web/css/themes/element/theme.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 3ea34fa3..3cf4aa3f 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -412,7 +412,6 @@ button.back { border-radius: 24px; background: #F6F6F6; height: 48px; - line-height: 48px; font-size: 14px; font-family: "Inter", sans-serif; }