diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index aae255f81a..348fb853d4 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -15,16 +15,43 @@ See the License for the specific language governing permissions and limitations under the License. */ -/* - Size settings -*/ -$AppsDrawerMinHeight: 50px; -$AppsDrawerDefaultHeight: 300px; $MiniAppTileHeight: 114px; .mx_AppsDrawer { - margin: 5px; - display: block; + margin: 5px 5px 5px 18px; + position: relative; + display: flex; + flex-direction: column; + overflow: hidden; + + .mx_RoomSublist_resizerHandles { + flex: 0 0 4px; + } + + .mx_RoomSublist_resizerHandle { + cursor: ns-resize; + border-radius: 3px; + + // Override styles from library + width: unset !important; + height: 4px !important; + + // This is positioned directly below frame + position: absolute; + bottom: -8px !important; // override from library + + // Together, these make the bar 64px wide + // These are also overridden from the library + left: calc(50% - 32px) !important; + right: calc(50% - 32px) !important; + } + + &:hover { + .mx_RoomSublist_resizerHandle { + opacity: 0.8; + background: $primary-fg-color; + } + } } .mx_AppsDrawer_hidden { @@ -36,13 +63,13 @@ $MiniAppTileHeight: 114px; flex-direction: row; align-items: stretch; justify-content: center; - min-height: $AppsDrawerMinHeight; - height: $AppsDrawerDefaultHeight; + height: 100%; } .mx_AppsDrawer_minimised .mx_AppsContainer { - min-height: inherit; - height: inherit; + // override the re-resizable inline styles + height: inherit !important; + min-height: inherit !important; } .mx_AddWidget_button { @@ -70,15 +97,14 @@ $MiniAppTileHeight: 114px; .mx_AppTile { max-width: 960px; width: 50%; - margin-right: 5px; border: 5px solid $widget-menu-bar-bg-color; border-radius: 4px; display: flex; flex-direction: column; -} -.mx_AppTile:last-child { - margin-right: 1px; + & + .mx_AppTile { + margin-left: 5px; + } } .mx_AppTileFullWidth { @@ -105,7 +131,7 @@ $MiniAppTileHeight: 114px; .mx_AppTile.mx_AppTile_minimised, .mx_AppTileFullWidth.mx_AppTile_minimised, .mx_AppTile_mini.mx_AppTile_minimised { - min-height: inherit; + height: 14px; } .mx_AppTile .mx_AppTile_persistedWrapper, @@ -117,7 +143,6 @@ $MiniAppTileHeight: 114px; .mx_AppTile_persistedWrapper div { width: 100%; height: 100%; - min-width: 300px; } .mx_AppTileMenuBar { @@ -402,7 +427,7 @@ form.mx_Custom_Widget_Form div { margin-right: auto; } -.mx_AppsDrawer_minimised .mx_ResizeHandle { +.mx_AppsDrawer_minimised .mx_RoomSublist_resizerHandle { display: none; } diff --git a/res/css/views/voip/_CallContainer.scss b/res/css/views/voip/_CallContainer.scss index 8d1b68dd99..4d26d8a312 100644 --- a/res/css/views/voip/_CallContainer.scss +++ b/res/css/views/voip/_CallContainer.scss @@ -36,6 +36,10 @@ limitations under the License. } } + .mx_AppTile_persistedWrapper div { + min-width: 300px; + } + .mx_IncomingCallBox { min-width: 250px; background-color: $primary-bg-color; diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index a79e5b0aa8..7605bdbfc0 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1547,9 +1547,9 @@ export default createReactClass({ // header + footer + status + give us at least 120px of scrollback at all times. let auxPanelMaxHeight = window.innerHeight - - (83 + // height of RoomHeader + (54 + // height of RoomHeader 36 + // height of the status area - 72 + // minimum height of the message compmoser + 51 + // minimum height of the message compmoser 120); // amount of desired scrollback // XXX: this is a bit of a hack and might possibly cause the video to push out the page anyway diff --git a/src/components/views/elements/PersistedElement.js b/src/components/views/elements/PersistedElement.js index 7f9bfdebf4..9a64b7c7c4 100644 --- a/src/components/views/elements/PersistedElement.js +++ b/src/components/views/elements/PersistedElement.js @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; - +import {throttle} from "lodash"; import ResizeObserver from 'resize-observer-polyfill'; import dis from '../../../dispatcher/dispatcher'; @@ -156,7 +156,7 @@ export default class PersistedElement extends React.Component { child.style.display = visible ? 'block' : 'none'; } - updateChildPosition(child, parent) { + updateChildPosition = throttle((child, parent) => { if (!child || !parent) return; const parentRect = parent.getBoundingClientRect(); @@ -167,9 +167,9 @@ export default class PersistedElement extends React.Component { width: parentRect.width + 'px', height: parentRect.height + 'px', }); - } + }, 100, {trailing: true, leading: true}); render() { - return
; + return
; } } diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index f173d76f24..502cbdc692 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -31,8 +31,8 @@ import AccessibleButton from '../elements/AccessibleButton'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; import SettingsStore from "../../../settings/SettingsStore"; import classNames from 'classnames'; -import ResizeHandle from '../elements/ResizeHandle'; -import {Resizer, FixedDistributor} from '../../../resizer'; +import {Resizable} from "re-resizable"; +import {useLocalStorageState} from "../../../hooks/useLocalStorage"; // The maximum number of widgets that can be added in a room const MAX_WIDGETS = 2; @@ -63,7 +63,6 @@ export default createReactClass({ MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents); WidgetEchoStore.on('update', this._updateApps); this.dispatcherRef = dis.register(this.onAction); - this._createResizer(); }, componentWillUnmount: function() { @@ -73,10 +72,6 @@ export default createReactClass({ } WidgetEchoStore.removeListener('update', this._updateApps); if (this.dispatcherRef) dis.unregister(this.dispatcherRef); - if (this.resizer) { - this.resizer.detach(); - this.resizer = null; - } }, // TODO: [REACT-WARNING] Replace with appropriate lifecycle event @@ -162,30 +157,6 @@ export default createReactClass({ this._launchManageIntegrations(); }, - _createResizer: function() { - if (!this.resizeContainer) { - return; - } - - const classNames = { - handle: "mx_ResizeHandle", - vertical: "mx_ResizeHandle_vertical", - resizing: "mx_AppsDrawer_resizing", - }; - const resizer = new Resizer( - this.resizeContainer, - FixedDistributor, - {}, - ); - resizer.setClassNames(classNames); - resizer.attach(); - this.resizer = resizer; - }, - - _setResizeContainerRef: function(div) { - this.resizeContainer = div; - }, - render: function() { const apps = this.state.apps.map((app, index, arr) => { const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId); @@ -193,7 +164,7 @@ export default createReactClass({ return (); }); - if (apps.length == 0) { - return
; + if (apps.length === 0) { + return
; } let addWidget; @@ -223,13 +194,6 @@ export default createReactClass({ ; } - const containerStyle = { - maxHeight: Math.max(this.props.maxHeight - 50, 300), - }; - if (!this.props.showApps && this.resizer) { - this.resizer.forHandleAt(0).item.clearSize(); - } - let spinner; if ( apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets( @@ -249,14 +213,39 @@ export default createReactClass({ }); return ( -
-
+
+ { apps } { spinner } -
- + { this._canUserModify() && addWidget }
); }, }); + +const PersistentVResizer = ({id, minHeight, maxHeight, className, handleWrapperClass, handleClass, children}) => { + const [height, setHeight] = useLocalStorageState("pvr_" + id, 100); + + return { + setHeight(height + d.height); + }} + handleWrapperClass={handleWrapperClass} + handleClasses={{bottom: handleClass}} + className={className} + enable={{bottom: true}} + > + { children } + ; +}; diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000000..2f110c58f2 --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,37 @@ +/* +Copyright 2019 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 {useEffect, useRef, useState} from "react"; + +// Hook behaving like useState but persisting the value to localStorage. Returns same as useState +export const useLocalStorageState = (key: string, initialValue: boolean) => { + const lsKey = useRef("useLocalStorageState_" + key).current; + + const [value, setValue] = useState(() => { + try { + const item = window.localStorage.getItem(lsKey); + return item ? JSON.parse(item) : initialValue; + } catch (error) { + return initialValue; + } + }); + + useEffect(() => { + window.localStorage.setItem(lsKey, JSON.stringify(value)); + }, [lsKey, value]); + + return [value, setValue]; +};