From 0bed0f65d5440a3cda8dab3fb2e85db262e16cee Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Tue, 21 Dec 2021 16:23:25 +0000 Subject: [PATCH 01/13] Prevent panning and zooming of map on timeline --- src/components/views/messages/MLocationBody.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 9fc3316c498..00a37647b65 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -62,6 +62,7 @@ export default class MLocationBody extends React.Component { style: config.map_style_url, center: coordinates, zoom: 13, + interactive: false, }); new maplibregl.Marker({ From 3a8099dd959ffd3e7e1d0c9cd97607bdcddf58a7 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Wed, 5 Jan 2022 12:41:07 +0000 Subject: [PATCH 02/13] Show error in timeline when map fails to load --- src/components/views/messages/MLocationBody.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 00a37647b65..6aa137c2d13 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -98,8 +98,8 @@ export default class MLocationBody extends React.Component { : null; return
-
{ error } +
Date: Wed, 5 Jan 2022 13:27:49 +0000 Subject: [PATCH 03/13] Open map in a dialog when it is clicked --- res/css/_components.scss | 1 + .../views/dialogs/_LocationViewDialog.scss | 57 ++++++ .../views/location/LocationViewDialog.tsx | 93 +++++++++ .../views/messages/MLocationBody.tsx | 192 ++++++++++++------ 4 files changed, 282 insertions(+), 61 deletions(-) create mode 100644 res/css/views/dialogs/_LocationViewDialog.scss create mode 100644 src/components/views/location/LocationViewDialog.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index c172af7e11e..8972cdb4b57 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -97,6 +97,7 @@ @import "./views/dialogs/_JoinRuleDropdown.scss"; @import "./views/dialogs/_KeyboardShortcutsDialog.scss"; @import "./views/dialogs/_LeaveSpaceDialog.scss"; +@import "./views/dialogs/_LocationViewDialog.scss"; @import "./views/dialogs/_ManageRestrictedJoinRuleDialog.scss"; @import "./views/dialogs/_MessageEditHistoryDialog.scss"; @import "./views/dialogs/_ModalWidgetDialog.scss"; diff --git a/res/css/views/dialogs/_LocationViewDialog.scss b/res/css/views/dialogs/_LocationViewDialog.scss new file mode 100644 index 00000000000..23cd50c5879 --- /dev/null +++ b/res/css/views/dialogs/_LocationViewDialog.scss @@ -0,0 +1,57 @@ +/* +Copyright 2022 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_LocationViewDialog_wrapper .mx_Dialog { + padding: 0px; + + /* Unset contain and position to allow the close button + to appear outside the dialog */ + contain: unset; + position: unset; +} + +.mx_LocationViewDialog { + /* subtract 0.5px to prevent single-pixel margin due to rounding */ + width: calc(79vw - 0.5px); + height: calc(79vh - 0.5px); + overflow: hidden; + + .mx_Dialog_header { + margin: 0px; + padding: 0px; + position: unset; + + .mx_Dialog_title { + display: none; + } + + .mx_Dialog_cancelButton { + z-index: 4010; + position: absolute; + right: 5vw; + top: 5vh; + width: 20px; + height: 20px; + background-color: $background; + } + } + + .mx_MLocationBody .mx_MLocationBody_map { + width: 79vw; + height: 79vh; + } +} + diff --git a/src/components/views/location/LocationViewDialog.tsx b/src/components/views/location/LocationViewDialog.tsx new file mode 100644 index 00000000000..824531d0473 --- /dev/null +++ b/src/components/views/location/LocationViewDialog.tsx @@ -0,0 +1,93 @@ +/* +Copyright 2022 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 React from 'react'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; + +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { _t } from '../../../languageHandler'; +import BaseDialog from "../dialogs/BaseDialog"; +import { IDialogProps } from "../dialogs/IDialogProps"; +import { createMap, LocationBodyContent, locationEventGeoUri, parseGeoUri } from '../messages/MLocationBody'; + +interface IProps extends IDialogProps { + mxEvent: MatrixEvent; +} + +interface IState { + error: Error; +} + +@replaceableComponent("views.location.LocationViewDialog") +export default class LocationViewDialog extends React.Component { + private coords: GeolocationCoordinates; + + constructor(props: IProps) { + super(props); + + this.coords = parseGeoUri(locationEventGeoUri(this.props.mxEvent)); + this.state = { + error: undefined, + }; + } + + componentDidMount() { + if (this.state.error) { + return; + } + + createMap( + this.coords, + true, + this.getBodyId(), + this.getMarkerId(), + (e: Error) => this.setState({ error: e }), + ); + + // Set class mx_Dialog_nonDialogButton on all buttons inside + // the map container. This prevents our CSS from styling the + // attribution button as if it were a dialog submit/cancel button. + const container: Element = document.getElementById(this.getBodyId()); + container.querySelectorAll("button").forEach( + (b: Element) => b.classList.add("mx_Dialog_nonDialogButton") + ); + } + + private getBodyId = () => { + return `mx_LocationViewDialog_${this.props.mxEvent.getId()}`; + }; + + private getMarkerId = () => { + return `mx_MLocationViewDialog_marker_${this.props.mxEvent.getId()}`; + }; + + render() { + return ( + + + + ); + } +} diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 6aa137c2d13..c8d8c4858c0 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -25,6 +25,8 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; import { IBodyProps } from "./IBodyProps"; import { _t } from '../../../languageHandler'; import MemberAvatar from '../avatars/MemberAvatar'; +import Modal from '../../../Modal'; +import LocationViewDialog from '../location/LocationViewDialog'; interface IState { error: Error; @@ -32,55 +34,29 @@ interface IState { @replaceableComponent("views.messages.MLocationBody") export default class MLocationBody extends React.Component { - private map: maplibregl.Map; private coords: GeolocationCoordinates; constructor(props: IBodyProps) { super(props); - // unfortunately we're stuck supporting legacy `content.geo_uri` - // events until the end of days, or until we figure out mutable - // events - so folks can read their old chat history correctly. - // https://github.com/matrix-org/matrix-doc/issues/3516 - const content = this.props.mxEvent.getContent(); - const loc = content[LOCATION_EVENT_TYPE.name]; - const uri = loc ? loc.uri : content['geo_uri']; - - this.coords = parseGeoUri(uri); + this.coords = parseGeoUri(locationEventGeoUri(this.props.mxEvent)); this.state = { error: undefined, }; } componentDidMount() { - const config = SdkConfig.get(); - const coordinates = new maplibregl.LngLat( - this.coords.longitude, this.coords.latitude); - - this.map = new maplibregl.Map({ - container: this.getBodyId(), - style: config.map_style_url, - center: coordinates, - zoom: 13, - interactive: false, - }); - - new maplibregl.Marker({ - element: document.getElementById(this.getMarkerId()), - anchor: 'bottom', - offset: [0, -1], - }) - .setLngLat(coordinates) - .addTo(this.map); - - this.map.on('error', (e)=>{ - logger.error( - "Failed to load map: check map_style_url in config.json has a " - + "valid URL and API key", - e.error, - ); - this.setState({ error: e.error }); - }); + if (this.state.error) { + return; + } + + createMap( + this.coords, + false, + this.getBodyId(), + this.getMarkerId(), + (e: Error) => this.setState({ error: e }), + ); } private getBodyId = () => { @@ -91,33 +67,127 @@ export default class MLocationBody extends React.Component { return `mx_MLocationBody_marker_${this.props.mxEvent.getId()}`; }; + private onClick = ( + event: React.MouseEvent + ) => { + // Don't open map if we clicked the attribution button + const target = event.target as Element; + if (target.classList.contains("maplibregl-ctrl-attrib-button")) { + return; + } + + Modal.createTrackedDialog( + 'Location View', + '', + LocationViewDialog, + { mxEvent: this.props.mxEvent }, + "mx_LocationViewDialog_wrapper", + false, // isPriority + true, // isStatic + ); + }; + render() { - const error = this.state.error ? -
- { _t("Failed to load map") } -
: null; - - return
- { error } -
-
-
- + return + } +} + +interface ILocationBodyContentProps { + mxEvent: MatrixEvent; + bodyId: string; + markerId: string; + error: Error; + onClick?: (event: React.MouseEvent) => void; +} + +export function LocationBodyContent(props: ILocationBodyContentProps) { + return
+ { + props.error + ?
+ { _t("Failed to load map") }
- +
+
+
-
; - } + +
+
; +} + +export function createMap( + coords: GeolocationCoordinates, + interactive: boolean, + bodyId: string, + markerId: string, + onError: (error: Error) => void +): maplibregl.Map { + const style_url = SdkConfig.get().map_style_url; + const coordinates = new maplibregl.LngLat(coords.longitude, coords.latitude); + + const map = new maplibregl.Map({ + container: bodyId, + style: style_url, + center: coordinates, + zoom: 13, + interactive, + }); + + new maplibregl.Marker({ + element: document.getElementById(markerId), + anchor: 'bottom', + offset: [0, -1], + }) + .setLngLat(coordinates) + .addTo(map); + + map.on('error', (e) => { + logger.error( + "Failed to load map: check map_style_url in config.json has a " + + "valid URL and API key", + e.error, + ); + onError(e.error); + }); + + return map; +} + +/** + * Find the geo-URI contained within a location event. + */ +export function locationEventGeoUri(mxEvent: MatrixEvent): string { + // unfortunately we're stuck supporting legacy `content.geo_uri` + // events until the end of days, or until we figure out mutable + // events - so folks can read their old chat history correctly. + // https://github.com/matrix-org/matrix-doc/issues/3516 + const content = mxEvent.getContent(); + const loc = LOCATION_EVENT_TYPE.findIn(content) as { uri?: string }; + return loc ? loc.uri : content['geo_uri']; } export function parseGeoUri(uri: string): GeolocationCoordinates { From e3fc6a28c9dd7602f83eec1a45923d0f9aa9a459 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Wed, 5 Jan 2022 13:56:21 +0000 Subject: [PATCH 04/13] Fix lint errors --- res/css/views/dialogs/_LocationViewDialog.scss | 1 - src/components/views/location/LocationViewDialog.tsx | 3 +-- src/components/views/messages/MLocationBody.tsx | 10 +++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/res/css/views/dialogs/_LocationViewDialog.scss b/res/css/views/dialogs/_LocationViewDialog.scss index 23cd50c5879..ed8d30acae9 100644 --- a/res/css/views/dialogs/_LocationViewDialog.scss +++ b/res/css/views/dialogs/_LocationViewDialog.scss @@ -54,4 +54,3 @@ limitations under the License. height: 79vh; } } - diff --git a/src/components/views/location/LocationViewDialog.tsx b/src/components/views/location/LocationViewDialog.tsx index 824531d0473..09992b83fbe 100644 --- a/src/components/views/location/LocationViewDialog.tsx +++ b/src/components/views/location/LocationViewDialog.tsx @@ -18,7 +18,6 @@ import React from 'react'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { replaceableComponent } from "../../../utils/replaceableComponent"; -import { _t } from '../../../languageHandler'; import BaseDialog from "../dialogs/BaseDialog"; import { IDialogProps } from "../dialogs/IDialogProps"; import { createMap, LocationBodyContent, locationEventGeoUri, parseGeoUri } from '../messages/MLocationBody'; @@ -62,7 +61,7 @@ export default class LocationViewDialog extends React.Component // attribution button as if it were a dialog submit/cancel button. const container: Element = document.getElementById(this.getBodyId()); container.querySelectorAll("button").forEach( - (b: Element) => b.classList.add("mx_Dialog_nonDialogButton") + (b: Element) => b.classList.add("mx_Dialog_nonDialogButton"), ); } diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index c8d8c4858c0..bb35b55ae15 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -68,7 +68,7 @@ export default class MLocationBody extends React.Component { }; private onClick = ( - event: React.MouseEvent + event: React.MouseEvent, ) => { // Don't open map if we clicked the attribution button const target = event.target as Element; @@ -94,7 +94,7 @@ export default class MLocationBody extends React.Component { markerId={this.getMarkerId()} error={this.state.error} onClick={this.onClick} - /> + />; } } @@ -144,14 +144,14 @@ export function createMap( interactive: boolean, bodyId: string, markerId: string, - onError: (error: Error) => void + onError: (error: Error) => void, ): maplibregl.Map { - const style_url = SdkConfig.get().map_style_url; + const styleUrl = SdkConfig.get().map_style_url; const coordinates = new maplibregl.LngLat(coords.longitude, coords.latitude); const map = new maplibregl.Map({ container: bodyId, - style: style_url, + style: styleUrl, center: coordinates, zoom: 13, interactive, From f49da8b0a1e83663ca8861812f10578e29b0ac54 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Wed, 5 Jan 2022 15:36:00 +0000 Subject: [PATCH 05/13] Provide a colour for the external dialog close button that is visible in all themes --- res/css/views/dialogs/_LocationViewDialog.scss | 2 +- res/themes/dark/css/_dark.scss | 1 + res/themes/legacy-dark/css/_legacy-dark.scss | 1 + res/themes/legacy-light/css/_legacy-light.scss | 1 + res/themes/light/css/_light.scss | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/res/css/views/dialogs/_LocationViewDialog.scss b/res/css/views/dialogs/_LocationViewDialog.scss index ed8d30acae9..c65336dbb74 100644 --- a/res/css/views/dialogs/_LocationViewDialog.scss +++ b/res/css/views/dialogs/_LocationViewDialog.scss @@ -45,7 +45,7 @@ limitations under the License. top: 5vh; width: 20px; height: 20px; - background-color: $background; + background-color: $dialog-close-external-color; } } diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index cdb64086822..94564aa779f 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -104,6 +104,7 @@ $input-lighter-bg-color: #f2f5f8; $dialog-title-fg-color: $primary-content; $dialog-backdrop-color: $menu-border-color; $dialog-close-fg-color: #9fa9ba; +$dialog-close-external-color: $primary-content; // ******************** // RoomList diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index 73f9206f77a..bd17f4f03f7 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -70,6 +70,7 @@ $dialog-title-fg-color: $base-text-color; $dialog-backdrop-color: #000; $dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-close-fg-color: #9fa9ba; +$dialog-close-external-color: $text-primary-color; $lightbox-background-bg-color: #000; $lightbox-background-bg-opacity: 0.85; diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index 881b98a2ee1..4760386532e 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -93,6 +93,7 @@ $dialog-title-fg-color: #45474a; $dialog-backdrop-color: rgba(46, 48, 51, 0.38); $dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-close-fg-color: #c1c1c1; +$dialog-close-external-color: $primary-bg-color; $lightbox-background-bg-color: #000; $lightbox-background-bg-opacity: 0.95; diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 20fb2591424..c1c8f31fc4e 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -153,6 +153,7 @@ $input-fg-color: rgba(74, 74, 74, 0.9); $dialog-title-fg-color: #45474a; $dialog-backdrop-color: rgba(46, 48, 51, 0.38); $dialog-close-fg-color: #c1c1c1; +$dialog-close-external-color: $background; $dialog-shadow-color: rgba(0, 0, 0, 0.48); // ******************** From cee37d14dbaadbdab2cf43b7dde917fd8dc234c3 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 6 Jan 2022 11:10:58 +0000 Subject: [PATCH 06/13] Location map size -> 80vw/vh --- res/css/views/dialogs/_LocationViewDialog.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/css/views/dialogs/_LocationViewDialog.scss b/res/css/views/dialogs/_LocationViewDialog.scss index c65336dbb74..4c37090f72c 100644 --- a/res/css/views/dialogs/_LocationViewDialog.scss +++ b/res/css/views/dialogs/_LocationViewDialog.scss @@ -25,8 +25,8 @@ limitations under the License. .mx_LocationViewDialog { /* subtract 0.5px to prevent single-pixel margin due to rounding */ - width: calc(79vw - 0.5px); - height: calc(79vh - 0.5px); + width: calc(80vw - 0.5px); + height: calc(80vh - 0.5px); overflow: hidden; .mx_Dialog_header { @@ -50,7 +50,7 @@ limitations under the License. } .mx_MLocationBody .mx_MLocationBody_map { - width: 79vw; - height: 79vh; + width: 80vw; + height: 80vh; } } From a5991af0a9a1546a43493da56e6772ebb41c238d Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 6 Jan 2022 13:55:34 +0000 Subject: [PATCH 07/13] Prevent dialog styling affecting map attribution button using CSS --- res/css/_common.scss | 10 +++++----- src/components/views/location/LocationViewDialog.tsx | 8 -------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index c72e4362ce7..44c924f8b6b 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -423,7 +423,7 @@ legend { * We should go through and have one consistent set of styles for buttons throughout the app. * For now, I am duplicating the selectors here for mx_Dialog and mx_DialogButtons. */ -.mx_Dialog button:not(.mx_Dialog_nonDialogButton), +.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button), .mx_Dialog input[type="submit"], .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton), .mx_Dialog_buttons input[type="submit"] { @@ -440,18 +440,18 @@ legend { font-family: inherit; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton):last-child { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):last-child { margin-right: 0px; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton):hover, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):hover, .mx_Dialog input[type="submit"]:hover, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):hover, .mx_Dialog_buttons input[type="submit"]:hover { @mixin mx_DialogButton_hover; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton):focus, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):focus, .mx_Dialog input[type="submit"]:focus, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):focus, .mx_Dialog_buttons input[type="submit"]:focus { @@ -482,7 +482,7 @@ legend { color: $alert; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton):disabled, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):disabled, .mx_Dialog input[type="submit"]:disabled, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):disabled, .mx_Dialog_buttons input[type="submit"]:disabled { diff --git a/src/components/views/location/LocationViewDialog.tsx b/src/components/views/location/LocationViewDialog.tsx index 09992b83fbe..87ea6576bad 100644 --- a/src/components/views/location/LocationViewDialog.tsx +++ b/src/components/views/location/LocationViewDialog.tsx @@ -55,14 +55,6 @@ export default class LocationViewDialog extends React.Component this.getMarkerId(), (e: Error) => this.setState({ error: e }), ); - - // Set class mx_Dialog_nonDialogButton on all buttons inside - // the map container. This prevents our CSS from styling the - // attribution button as if it were a dialog submit/cancel button. - const container: Element = document.getElementById(this.getBodyId()); - container.querySelectorAll("button").forEach( - (b: Element) => b.classList.add("mx_Dialog_nonDialogButton"), - ); } private getBodyId = () => { From 042d74931f9fff098bde186602a0c6b2c02e00a6 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 6 Jan 2022 17:32:48 +0000 Subject: [PATCH 08/13] Display a tooltip when you hover over a location --- src/components/views/elements/Tooltip.tsx | 16 +++++++++- .../views/elements/TooltipTarget.tsx | 2 ++ .../views/messages/MLocationBody.tsx | 29 +++++++++++++++---- src/i18n/strings/en_EN.json | 1 + 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index 5e6df02666b..4ca0ed9082c 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -32,6 +32,7 @@ export enum Alignment { Right, Top, // Centered Bottom, // Centered + InnerBottom, // Inside the target, at the bottom } export interface ITooltipProps { @@ -50,6 +51,8 @@ export interface ITooltipProps { // id describing tooltip // used to associate tooltip with target for a11y id?: string; + // If the parent is over this width, act as if it is only this wide + maxParentWidth?: number; } @replaceableComponent("views.elements.Tooltip") @@ -107,11 +110,18 @@ export default class Tooltip extends React.Component { offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT); } const width = UIStore.instance.windowWidth; + const parentWidth = ( + this.props.maxParentWidth + ? Math.min(parentBox.width, this.props.maxParentWidth) + : parentBox.width + ); const baseTop = (parentBox.top - 2 + this.props.yOffset) + window.pageYOffset; const top = baseTop + offset; const right = width - parentBox.right - window.pageXOffset - 16; const left = parentBox.right + window.pageXOffset + 6; - const horizontalCenter = parentBox.right - window.pageXOffset - (parentBox.width / 2); + const horizontalCenter = ( + parentBox.left - window.pageXOffset + (parentWidth / 2) + ); switch (this.props.alignment) { case Alignment.Natural: if (parentBox.right > width / 2) { @@ -136,6 +146,10 @@ export default class Tooltip extends React.Component { style.top = baseTop + parentBox.height; style.left = horizontalCenter; break; + case Alignment.InnerBottom: + style.top = baseTop + parentBox.height - 50; + style.left = horizontalCenter; + style.transform = "translate(-50%)" } return style; diff --git a/src/components/views/elements/TooltipTarget.tsx b/src/components/views/elements/TooltipTarget.tsx index 22da867887a..9ccd572ea8a 100644 --- a/src/components/views/elements/TooltipTarget.tsx +++ b/src/components/views/elements/TooltipTarget.tsx @@ -36,6 +36,7 @@ const TooltipTarget: React.FC = ({ alignment, yOffset, tooltipClassName, + maxParentWidth, ...rest }) => { const [isVisible, setIsVisible] = useState(false); @@ -63,6 +64,7 @@ const TooltipTarget: React.FC = ({ yOffset={yOffset} alignment={alignment} visible={isVisible} + maxParentWidth={maxParentWidth} />
); diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index bb35b55ae15..7c47a635d00 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -27,6 +27,8 @@ import { _t } from '../../../languageHandler'; import MemberAvatar from '../avatars/MemberAvatar'; import Modal from '../../../Modal'; import LocationViewDialog from '../location/LocationViewDialog'; +import TooltipTarget from '../elements/TooltipTarget'; +import {Alignment} from '../elements/Tooltip'; interface IState { error: Error; @@ -93,16 +95,19 @@ export default class MLocationBody extends React.Component { bodyId={this.getBodyId()} markerId={this.getMarkerId()} error={this.state.error} + tooltip={_t("Expand map")} onClick={this.onClick} />; } } + interface ILocationBodyContentProps { mxEvent: MatrixEvent; bodyId: string; markerId: string; error: Error; + tooltip?: String; onClick?: (event: React.MouseEvent) => void; } @@ -115,11 +120,25 @@ export function LocationBodyContent(props: ILocationBodyContentProps) {
: null } -
+ { + props.tooltip + ? +
+ + :
+ }
Date: Thu, 6 Jan 2022 17:40:25 +0000 Subject: [PATCH 09/13] Fix lint errors --- src/components/views/elements/Tooltip.tsx | 2 +- src/components/views/messages/MLocationBody.tsx | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx index 4ca0ed9082c..3e20c6c2689 100644 --- a/src/components/views/elements/Tooltip.tsx +++ b/src/components/views/elements/Tooltip.tsx @@ -149,7 +149,7 @@ export default class Tooltip extends React.Component { case Alignment.InnerBottom: style.top = baseTop + parentBox.height - 50; style.left = horizontalCenter; - style.transform = "translate(-50%)" + style.transform = "translate(-50%)"; } return style; diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 7c47a635d00..223edfaeee7 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -28,7 +28,7 @@ import MemberAvatar from '../avatars/MemberAvatar'; import Modal from '../../../Modal'; import LocationViewDialog from '../location/LocationViewDialog'; import TooltipTarget from '../elements/TooltipTarget'; -import {Alignment} from '../elements/Tooltip'; +import { Alignment } from '../elements/Tooltip'; interface IState { error: Error; @@ -101,7 +101,6 @@ export default class MLocationBody extends React.Component { } } - interface ILocationBodyContentProps { mxEvent: MatrixEvent; bodyId: string; @@ -127,7 +126,7 @@ export function LocationBodyContent(props: ILocationBodyContentProps) { alignment={Alignment.InnerBottom} maxParentWidth={450} > -
Date: Thu, 6 Jan 2022 17:42:16 +0000 Subject: [PATCH 10/13] Fix incorrect case of string Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/messages/MLocationBody.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 223edfaeee7..2131e8b56b9 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -106,7 +106,7 @@ interface ILocationBodyContentProps { bodyId: string; markerId: string; error: Error; - tooltip?: String; + tooltip?: string; onClick?: (event: React.MouseEvent) => void; } From f3cf86d87214425b317e93c71b26c44bb5bea164 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Thu, 6 Jan 2022 17:47:04 +0000 Subject: [PATCH 11/13] Share code of div containing the map --- .../views/messages/MLocationBody.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/views/messages/MLocationBody.tsx b/src/components/views/messages/MLocationBody.tsx index 2131e8b56b9..689de442334 100644 --- a/src/components/views/messages/MLocationBody.tsx +++ b/src/components/views/messages/MLocationBody.tsx @@ -111,6 +111,12 @@ interface ILocationBodyContentProps { } export function LocationBodyContent(props: ILocationBodyContentProps) { + const mapDiv =
; + return
{ props.error @@ -126,17 +132,9 @@ export function LocationBodyContent(props: ILocationBodyContentProps) { alignment={Alignment.InnerBottom} maxParentWidth={450} > -
+ { mapDiv } - :
+ : mapDiv }
From 1e1efcfa78e7e7e7a5cbb48368fc304f1bbedc39 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 7 Jan 2022 10:22:09 +0000 Subject: [PATCH 12/13] Correct selectors for not(.maplibregl) --- res/css/_common.scss | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index 44c924f8b6b..a22266ce7d1 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -422,8 +422,11 @@ legend { * in the app look the same by being AccessibleButtons, or possibly by having explict button classes. * We should go through and have one consistent set of styles for buttons throughout the app. * For now, I am duplicating the selectors here for mx_Dialog and mx_DialogButtons. + * + * Elements that should not be styled like a dialog button are mentioned in a :not() pseudo-class. + * For the widest browser support, we use multiple :not pseudo-classes instead of :not(.a, .b). */ -.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button), +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button), .mx_Dialog input[type="submit"], .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton), .mx_Dialog_buttons input[type="submit"] { @@ -440,25 +443,25 @@ legend { font-family: inherit; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):last-child { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):last-child { margin-right: 0px; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):hover, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):hover, .mx_Dialog input[type="submit"]:hover, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):hover, .mx_Dialog_buttons input[type="submit"]:hover { @mixin mx_DialogButton_hover; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):focus, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):focus, .mx_Dialog input[type="submit"]:focus, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):focus, .mx_Dialog_buttons input[type="submit"]:focus { filter: brightness($focus-brightness); } -.mx_Dialog button.mx_Dialog_primary, +.mx_Dialog button.mx_Dialog_primary:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button), .mx_Dialog input[type="submit"].mx_Dialog_primary, .mx_Dialog_buttons button.mx_Dialog_primary, .mx_Dialog_buttons input[type="submit"].mx_Dialog_primary { @@ -467,7 +470,7 @@ legend { min-width: 156px; } -.mx_Dialog button.danger, +.mx_Dialog button.danger:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button), .mx_Dialog input[type="submit"].danger, .mx_Dialog_buttons button.danger, .mx_Dialog_buttons input[type="submit"].danger { @@ -476,13 +479,13 @@ legend { color: $accent-fg-color; } -.mx_Dialog button.warning, +.mx_Dialog button.warning:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button), .mx_Dialog input[type="submit"].warning { border: solid 1px $alert; color: $alert; } -.mx_Dialog button:not(.mx_Dialog_nonDialogButton || .maplibregl-ctrl-attrib-button):disabled, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):disabled, .mx_Dialog input[type="submit"]:disabled, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):disabled, .mx_Dialog_buttons input[type="submit"]:disabled { From 046ac907db34fe6ad2d7f11ae471fa1d60ad3969 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 7 Jan 2022 11:22:35 +0000 Subject: [PATCH 13/13] Fix bad merge --- res/css/_common.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index a860b175a3f..6a7964c7e0a 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -454,7 +454,7 @@ legend { @mixin mx_DialogButton_hover; } -.mx_Dialog button:button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):not(.mx_AccessibleButton):focus, +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):not(.maplibregl-ctrl-attrib-button):not(.mx_AccessibleButton):focus, .mx_Dialog input[type="submit"]:focus, .mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):not(.mx_AccessibleButton):focus, .mx_Dialog_buttons input[type="submit"]:focus {