diff --git a/CHANGES.md b/CHANGES.md index 9c70246a026..ee136b60633 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ #### next release (8.3.4) +- Move map credits to map column so it don't get hidden by chart panel +- TSify `MapColumn` module and reorganize components directory structure. - [The next improvement] #### next release (8.3.3) @@ -10,7 +12,6 @@ - Fixed rectangle drawing in 2D mode. - Added EPSG:7855 to `Proj4Definitions`. - Fix multi level nesting in ArcGIS Mapserver. -- [The next improvement] #### 8.3.2 - 2023-08-11 diff --git a/lib/Models/Terria.ts b/lib/Models/Terria.ts index 81f8cc049aa..38a7eed4086 100644 --- a/lib/Models/Terria.ts +++ b/lib/Models/Terria.ts @@ -70,7 +70,7 @@ import TimeVarying from "../ModelMixins/TimeVarying"; import { HelpContentItem } from "../ReactViewModels/defaultHelpContent"; import { defaultTerms, Term } from "../ReactViewModels/defaultTerms"; import NotificationState from "../ReactViewModels/NotificationState"; -import { ICredit } from "../ReactViews/Credits"; +import { ICredit } from "../ReactViews/Map/BottomBar/Credits"; import { SHARE_VERSION } from "../ReactViews/Map/Panels/SharePanel/BuildShareLink"; import { shareConvertNotification } from "../ReactViews/Notification/shareConvertNotification"; import MappableTraits from "../Traits/TraitsClasses/MappableTraits"; diff --git a/lib/ReactViewModels/MouseCoords.ts b/lib/ReactViewModels/MouseCoords.ts index 409e4e56346..f68381192b2 100644 --- a/lib/ReactViewModels/MouseCoords.ts +++ b/lib/ReactViewModels/MouseCoords.ts @@ -79,12 +79,13 @@ export default class MouseCoords { ); } - @action + @action.bound toggleUseProjection() { this.useProjection = !this.useProjection; this.updateEvent.raiseEvent(); } + @action updateCoordinatesFromCesium(terria: Terria, position: Cartesian2) { if (!terria.cesium) { return; @@ -187,6 +188,7 @@ export default class MouseCoords { } } + @action updateCoordinatesFromLeaflet(terria: Terria, mouseMoveEvent: MouseEvent) { if (!terria.leaflet) { return; diff --git a/lib/ReactViews/ActionBar/ActionBar.tsx b/lib/ReactViews/ActionBar/ActionBar.tsx index 937d2127b2c..5ddefabe205 100644 --- a/lib/ReactViews/ActionBar/ActionBar.tsx +++ b/lib/ReactViews/ActionBar/ActionBar.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import styled from "styled-components"; import Box from "../../Styled/Box"; import { PortalChild } from "../StandardUserInterface/Portal"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { ActionBarPortalId } from "./ActionBarPortal"; /** diff --git a/lib/ReactViews/BottomDock/BottomDock.tsx b/lib/ReactViews/BottomDock/BottomDock.tsx index 900ccd370d3..d5bd89c0992 100644 --- a/lib/ReactViews/BottomDock/BottomDock.tsx +++ b/lib/ReactViews/BottomDock/BottomDock.tsx @@ -10,13 +10,13 @@ import Styles from "./bottom-dock.scss"; import ChartDisclaimer from "./ChartDisclaimer"; import Timeline from "./Timeline/Timeline"; -interface PropsType extends MeasureElementProps { +interface PropsType { terria: Terria; viewState: ViewState; } @observer -class BottomDock extends React.Component { +class BottomDock extends React.Component { refToMeasure: HTMLDivElement | null = null; handleClick() { @@ -25,7 +25,7 @@ class BottomDock extends React.Component { }); } - componentDidUpdate(prevProps: PropsType) { + componentDidUpdate(prevProps: PropsType & MeasureElementProps) { if ( prevProps.heightFromMeasureElementHOC !== this.props.heightFromMeasureElementHOC diff --git a/lib/ReactViews/StandardUserInterface/ContextProviders.tsx b/lib/ReactViews/Context/ContextProviders.tsx similarity index 91% rename from lib/ReactViews/StandardUserInterface/ContextProviders.tsx rename to lib/ReactViews/Context/ContextProviders.tsx index 44bc042c5e6..06854c0c0de 100644 --- a/lib/ReactViews/StandardUserInterface/ContextProviders.tsx +++ b/lib/ReactViews/Context/ContextProviders.tsx @@ -3,7 +3,7 @@ import { DefaultTheme, ThemeProvider } from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; import { ViewStateProvider } from "./ViewStateContext"; -export default (props: { +export const ContextProviders = (props: { viewState: ViewState; theme: DefaultTheme | ((theme: DefaultTheme) => DefaultTheme); children: React.ReactNode[]; diff --git a/lib/ReactViews/StandardUserInterface/ViewStateContext.tsx b/lib/ReactViews/Context/ViewStateContext.tsx similarity index 100% rename from lib/ReactViews/StandardUserInterface/ViewStateContext.tsx rename to lib/ReactViews/Context/ViewStateContext.tsx diff --git a/lib/ReactViews/Context/index.ts b/lib/ReactViews/Context/index.ts new file mode 100644 index 00000000000..fba95c1445c --- /dev/null +++ b/lib/ReactViews/Context/index.ts @@ -0,0 +1,2 @@ +export * from "./ViewStateContext"; +export * from "./ContextProviders"; diff --git a/lib/ReactViews/Credits/index.ts b/lib/ReactViews/Credits/index.ts deleted file mode 100644 index c64853d9cd8..00000000000 --- a/lib/ReactViews/Credits/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ICredit } from "./Credit.type"; -export { MapCredits } from "./MapCredits/MapCredits"; diff --git a/lib/ReactViews/Custom/ExternalLink.tsx b/lib/ReactViews/Custom/ExternalLink.tsx index a82e7964c3e..5d6669b974e 100644 --- a/lib/ReactViews/Custom/ExternalLink.tsx +++ b/lib/ReactViews/Custom/ExternalLink.tsx @@ -1,7 +1,7 @@ import { AnchorHTMLAttributes, default as React } from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; const Icon = require("../../Styled/Icon").default; const { StyledIcon } = require("../../Styled/Icon"); diff --git a/lib/ReactViews/Disclaimer.jsx b/lib/ReactViews/Disclaimer.jsx index d5660523e83..656ec1ef8f7 100644 --- a/lib/ReactViews/Disclaimer.jsx +++ b/lib/ReactViews/Disclaimer.jsx @@ -12,7 +12,7 @@ import Button from "../Styled/Button"; import Spacing from "../Styled/Spacing"; import Text from "../Styled/Text"; import parseCustomMarkdownToReact from "./Custom/parseCustomMarkdownToReact"; -import { withViewState } from "./StandardUserInterface/ViewStateContext"; +import { withViewState } from "./Context"; import FadeIn from "./Transitions/FadeIn/FadeIn"; const TopElementBox = styled(Box)` diff --git a/lib/ReactViews/DragDropFile.tsx b/lib/ReactViews/DragDropFile.tsx index 3016c81ec5f..2dec3623ea3 100644 --- a/lib/ReactViews/DragDropFile.tsx +++ b/lib/ReactViews/DragDropFile.tsx @@ -14,10 +14,7 @@ import MappableMixin from "../ModelMixins/MappableMixin"; import addUserFiles from "../Models/Catalog/addUserFiles"; import { BaseModel } from "../Models/Definition/Model"; import Styles from "./drag-drop-file.scss"; -import { - WithViewState, - withViewState -} from "./StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "./Context"; import { raiseFileDragDropEvent } from "../ViewModels/FileDragDropListener"; interface PropsType extends WithTranslation, WithViewState {} diff --git a/lib/ReactViews/DragDropNotification.jsx b/lib/ReactViews/DragDropNotification.jsx index fec17f6ab94..63bf30c8c7d 100644 --- a/lib/ReactViews/DragDropNotification.jsx +++ b/lib/ReactViews/DragDropNotification.jsx @@ -6,7 +6,7 @@ import PropTypes from "prop-types"; import React from "react"; import Icon from "../Styled/Icon"; import Styles from "./drag-drop-notification.scss"; -import { withViewState } from "./StandardUserInterface/ViewStateContext"; +import { withViewState } from "./Context"; @observer class DragDropNotification extends React.Component { diff --git a/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx b/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx index 91dac320a8b..5ed52578fe7 100644 --- a/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx +++ b/lib/ReactViews/ExplorerWindow/ExplorerWindow.tsx @@ -2,7 +2,7 @@ import { action } from "mobx"; import { observer } from "mobx-react"; import React from "react"; import ViewState from "../../ReactViewModels/ViewState"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import ModalPopup from "./ModalPopup"; import Tabs from "./Tabs"; diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx index d68d0433d9b..437ed11cab6 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoDownload.tsx @@ -6,7 +6,7 @@ import filterOutUndefined from "../../Core/filterOutUndefined"; import JsonValue, { JsonObject } from "../../Core/Json"; import ViewState from "../../ReactViewModels/ViewState"; import Icon from "../../Styled/Icon"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./feature-info-download.scss"; const Dropdown = require("../Generic/Dropdown"); diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx index 656ead4cf06..5d45367fb28 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoPanel.tsx @@ -29,7 +29,7 @@ import Workbench from "../../Models/Workbench"; import ViewState from "../../ReactViewModels/ViewState"; import Icon from "../../Styled/Icon"; import Loader from "../Loader"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./feature-info-panel.scss"; import FeatureInfoCatalogItem from "./FeatureInfoCatalogItem"; diff --git a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx index ea9ad19bc4f..58ea83eab25 100644 --- a/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx +++ b/lib/ReactViews/FeatureInfo/FeatureInfoSection.tsx @@ -31,10 +31,7 @@ import FeatureInfoContext from "../../Models/Feature/FeatureInfoContext"; import Icon from "../../Styled/Icon"; import { FeatureInfoPanelButton as FeatureInfoPanelButtonModel } from "../../ViewModels/FeatureInfoPanel"; import parseCustomMarkdownToReact from "../Custom/parseCustomMarkdownToReact"; -import { - withViewState, - WithViewState -} from "../StandardUserInterface/ViewStateContext"; +import { withViewState, WithViewState } from "../Context"; import Styles from "./feature-info-section.scss"; import FeatureInfoDownload from "./FeatureInfoDownload"; import FeatureInfoPanelButton from "./FeatureInfoPanelButton"; diff --git a/lib/ReactViews/Feedback/FeedbackForm.tsx b/lib/ReactViews/Feedback/FeedbackForm.tsx index 54a68d88045..675f47de837 100644 --- a/lib/ReactViews/Feedback/FeedbackForm.tsx +++ b/lib/ReactViews/Feedback/FeedbackForm.tsx @@ -16,10 +16,7 @@ import Text from "../../Styled/Text"; import parseCustomMarkdownToReact, { parseCustomMarkdownToReactWithOptions } from "../Custom/parseCustomMarkdownToReact"; -import { - WithViewState, - withViewState -} from "../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../Context"; import { applyTranslationIfExists } from "./../../Language/languageHelpers"; interface IProps extends WithTranslation, WithViewState { diff --git a/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx b/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx index 57aa0fbfcd2..5bf038c3956 100644 --- a/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx +++ b/lib/ReactViews/HelpScreens/SatelliteHelpPrompt.jsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; import React from "react"; import { useTranslation } from "react-i18next"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import HelpPrompt from "./HelpPrompt"; export const SATELLITE_HELP_PROMPT_KEY = "satelliteGuidance"; diff --git a/lib/ReactViews/Map/BottomBar/BottomBar.tsx b/lib/ReactViews/Map/BottomBar/BottomBar.tsx new file mode 100644 index 00000000000..cd903ba6e3c --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/BottomBar.tsx @@ -0,0 +1,32 @@ +import { VFC } from "react"; +import Box from "../../../Styled/Box"; +import { useViewState } from "../../Context"; +import { MapCredits } from "./Credits"; +import { DistanceLegend } from "./DistanceLegend"; +import { LocationBar } from "./LocationBar"; +import React from "react"; + +export const BottomBar: VFC = () => { + const viewState = useViewState(); + return ( + + + + + + + + ); +}; diff --git a/lib/ReactViews/Credits/Credit.tsx b/lib/ReactViews/Map/BottomBar/Credits/Credit.tsx similarity index 89% rename from lib/ReactViews/Credits/Credit.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Credit.tsx index 5901407ea9c..751297ff0f7 100644 --- a/lib/ReactViews/Credits/Credit.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/Credit.tsx @@ -1,6 +1,6 @@ import React, { FC } from "react"; import { useTranslation } from "react-i18next"; -import { ExternalLinkIcon } from "../Custom/ExternalLink"; +import { ExternalLinkIcon } from "../../../Custom/ExternalLink"; import { ICredit } from "./Credit.type"; import { Spacer } from "./Spacer"; diff --git a/lib/ReactViews/Credits/Credit.type.ts b/lib/ReactViews/Map/BottomBar/Credits/Credit.type.ts similarity index 100% rename from lib/ReactViews/Credits/Credit.type.ts rename to lib/ReactViews/Map/BottomBar/Credits/Credit.type.ts diff --git a/lib/ReactViews/Credits/Credits.tsx b/lib/ReactViews/Map/BottomBar/Credits/Credits.tsx similarity index 100% rename from lib/ReactViews/Credits/Credits.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Credits.tsx diff --git a/lib/ReactViews/Credits/CreditsContainer.tsx b/lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx similarity index 62% rename from lib/ReactViews/Credits/CreditsContainer.tsx rename to lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx index 3bc865a84bc..3fd049e8c8e 100644 --- a/lib/ReactViews/Credits/CreditsContainer.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/CreditsContainer.tsx @@ -1,19 +1,12 @@ import styled from "styled-components"; -import Box from "../../Styled/Box"; +import Box from "../../../../Styled/Box"; export const CreditsContainer = styled(Box).attrs(() => ({ - fullWidth: true, styledHeight: "30px", styledMaxHeight: "30px", verticalCenter: true, - gap: true, - position: "absolute" + gap: true }))` - z-index: 0; - bottom: 0; - background: linear-gradient(180deg, #000000 0%, #000000 100%); - font-size: 0.7rem; - opacity: 0.75; a { text-decoration: underline; cursor: pointer; @@ -21,7 +14,6 @@ export const CreditsContainer = styled(Box).attrs(() => ({ display: flex; align-items: center; } - img { height: 24px; } diff --git a/lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx b/lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx similarity index 86% rename from lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx rename to lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx index 0e6be655b42..b5b1856e5ca 100644 --- a/lib/ReactViews/Credits/DataAttribution/DataAttributionModal.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/DataAttribution/DataAttributionModal.tsx @@ -3,13 +3,13 @@ import React, { FC } from "react"; import ReactDOM from "react-dom"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; -import Box from "../../../Styled/Box"; -import { Li } from "../../../Styled/List"; -import Spacing from "../../../Styled/Spacing"; -import Text from "../../../Styled/Text"; -import parseCustomHtmlToReact from "../../Custom/parseCustomHtmlToReact"; -import CloseButton from "../../Generic/CloseButton"; -import { PrefaceBox } from "../../Generic/PrefaceBox"; +import Box from "../../../../../Styled/Box"; +import { Li } from "../../../../../Styled/List"; +import Spacing from "../../../../../Styled/Spacing"; +import Text from "../../../../../Styled/Text"; +import parseCustomHtmlToReact from "../../../../Custom/parseCustomHtmlToReact"; +import CloseButton from "../../../../Generic/CloseButton"; +import { PrefaceBox } from "../../../../Generic/PrefaceBox"; interface IDataAttributionModalProps { closeModal: () => void; @@ -20,7 +20,6 @@ const AttributionText = styled(Text).attrs(() => ({ medium: true }))` a { color: ${(props) => props.theme.textDark}; text-decoration: underline; - img { height: 19px; vertical-align: middle; diff --git a/lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx b/lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx similarity index 75% rename from lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx rename to lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx index 9ba2b6be382..7f0cffb0b18 100644 --- a/lib/ReactViews/Credits/MapCredits/MapCreditLogo.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/MapCreditLogo.tsx @@ -1,8 +1,8 @@ import React, { FC } from "react"; import CreditDisplay from "terriajs-cesium/Source/Scene/CreditDisplay"; -import GlobeOrMap from "../../../Models/GlobeOrMap"; -import Leaflet from "../../../Models/Leaflet"; -import parseCustomHtmlToReact from "../../Custom/parseCustomHtmlToReact"; +import GlobeOrMap from "../../../../Models/GlobeOrMap"; +import Leaflet from "../../../../Models/Leaflet"; +import parseCustomHtmlToReact from "../../../Custom/parseCustomHtmlToReact"; interface IMapCreditLogoProps { currentViewer: GlobeOrMap; diff --git a/lib/ReactViews/Credits/MapCredits/MapCredits.tsx b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx similarity index 84% rename from lib/ReactViews/Credits/MapCredits/MapCredits.tsx rename to lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx index 404abdeeb8b..05a8a30a118 100644 --- a/lib/ReactViews/Credits/MapCredits/MapCredits.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/MapCredits.tsx @@ -2,13 +2,13 @@ import { reaction } from "mobx"; import { observer } from "mobx-react"; import React, { FC, useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import GlobeOrMap from "../../../Models/GlobeOrMap"; -import { ICredit } from "../Credit.type"; -import { Credits } from "../Credits"; -import { CreditsContainer } from "../CreditsContainer"; -import { DataAttributionModal } from "../DataAttribution/DataAttributionModal"; -import { Spacer } from "../Spacer"; -import { TerriaLogo } from "../TerriaLogo"; +import GlobeOrMap from "../../../../Models/GlobeOrMap"; +import { ICredit } from "./Credit.type"; +import { Credits } from "./Credits"; +import { CreditsContainer } from "./CreditsContainer"; +import { DataAttributionModal } from "./DataAttribution/DataAttributionModal"; +import { Spacer } from "./Spacer"; +import { TerriaLogo } from "./TerriaLogo"; import { MapCreditLogo } from "./MapCreditLogo"; interface IMapCreditsProps { diff --git a/lib/ReactViews/Credits/Spacer.tsx b/lib/ReactViews/Map/BottomBar/Credits/Spacer.tsx similarity index 100% rename from lib/ReactViews/Credits/Spacer.tsx rename to lib/ReactViews/Map/BottomBar/Credits/Spacer.tsx diff --git a/lib/ReactViews/Credits/TerriaLogo.tsx b/lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx similarity index 71% rename from lib/ReactViews/Credits/TerriaLogo.tsx rename to lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx index ab56a9046ed..fd035fd8688 100644 --- a/lib/ReactViews/Credits/TerriaLogo.tsx +++ b/lib/ReactViews/Map/BottomBar/Credits/TerriaLogo.tsx @@ -1,7 +1,7 @@ import React, { FC } from "react"; -import Box from "../../Styled/Box"; +import Box from "../../../../Styled/Box"; -const logo = require("../../../wwwroot/images/terria-watermark.svg"); +const logo = require("../../../../../wwwroot/images/terria-watermark.svg"); export const TerriaLogo: FC = () => { return ( diff --git a/lib/ReactViews/Map/BottomBar/Credits/index.ts b/lib/ReactViews/Map/BottomBar/Credits/index.ts new file mode 100644 index 00000000000..ebd9ea095ca --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/Credits/index.ts @@ -0,0 +1,2 @@ +export { ICredit } from "./Credit.type"; +export { MapCredits } from "./MapCredits"; diff --git a/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx new file mode 100644 index 00000000000..eb17467a7d8 --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/DistanceLegend.tsx @@ -0,0 +1,211 @@ +"use strict"; +import L from "leaflet"; +import { runInAction } from "mobx"; +import { observer } from "mobx-react"; +import React, { FC, useEffect, useState, memo } from "react"; +import { useTheme } from "styled-components"; +import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; +import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic"; +import CesiumEvent from "terriajs-cesium/Source/Core/Event"; +import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; +import Scene from "terriajs-cesium/Source/Scene/Scene"; +import isDefined from "../../../Core/isDefined"; +import Box from "../../../Styled/Box"; +import Text from "../../../Styled/Text"; +import { useViewState } from "../../Context"; + +const geodesic = new EllipsoidGeodesic(); + +const distances = [ + 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1000, 2000, 3000, 5000, 10000, + 20000, 30000, 50000, 100000, 200000, 300000, 500000, 1000000, 2000000, + 3000000, 5000000, 10000000, 20000000, 30000000, 50000000 +]; + +interface IDistanceLegendProps { + scale?: number; + isPrintMode?: boolean; +} + +export const DistanceLegend: FC = observer( + ({ scale = 1, isPrintMode = false }) => { + const [distanceLabel, setDistanceLabel] = useState(); + const [barWidth, setBarWidth] = useState(0); + + const { terria } = useViewState(); + const theme = useTheme(); + + let removeUpdateSubscription: + | CesiumEvent.RemoveCallback + | (() => void) + | undefined; + + useEffect(() => { + const viewerSubscriptions: CesiumEvent.RemoveCallback[] = []; + + removeUpdateSubscription = addUpdateSubscription(); + + return () => { + if (removeUpdateSubscription) { + removeUpdateSubscription(); + } + viewerSubscriptions.forEach((clear) => clear()); + }; + }, [terria.cesium, terria.leaflet]); + + const addUpdateSubscription = (): + | CesiumEvent.RemoveCallback + | (() => void) + | undefined => { + if (isDefined(terria.cesium)) { + const scene = terria.cesium.scene; + let removeUpdateSubscription: CesiumEvent.RemoveCallback | undefined = + scene.postRender.addEventListener(() => { + updateDistanceLegendCesium(scene); + if (isPrintMode) { + removeUpdateSubscription?.(); + removeUpdateSubscription = undefined; + } + }); + return removeUpdateSubscription; + } else if (isDefined(terria.leaflet)) { + const map = terria.leaflet.map; + let removeUpdateSubscription: (() => void) | undefined = undefined; + + if (!isPrintMode) { + const potentialChangeCallback = function potentialChangeCallback() { + updateDistanceLegendLeaflet(map); + }; + removeUpdateSubscription = function () { + map.off("zoomend", potentialChangeCallback); + map.off("moveend", potentialChangeCallback); + }; + + map.on("zoomend", potentialChangeCallback); + map.on("moveend", potentialChangeCallback); + } + + updateDistanceLegendLeaflet(map); + return removeUpdateSubscription; + } + }; + + const updateDistanceLegendCesium = (scene: Scene) => { + const now = getTimestamp(); + + // Find the distance between two pixels at the bottom center of the screen. + const width = scene.canvas.clientWidth; + const height = scene.canvas.clientHeight; + + const left = scene.camera.getPickRay( + new Cartesian2((width / 2) | 0, height - 1) + ); + const right = scene.camera.getPickRay( + new Cartesian2((1 + width / 2) | 0, height - 1) + ); + + const globe = scene.globe; + + if (!isDefined(left) || !isDefined(right)) { + return; + } + + const leftPosition = globe.pick(left, scene); + const rightPosition = globe.pick(right, scene); + + if (!isDefined(leftPosition) || !isDefined(rightPosition)) { + setBarWidth(0); + setDistanceLabel(undefined); + return; + } + + const leftCartographic = + globe.ellipsoid.cartesianToCartographic(leftPosition); + const rightCartographic = + globe.ellipsoid.cartesianToCartographic(rightPosition); + + geodesic.setEndPoints(leftCartographic, rightCartographic); + const pixelDistance = geodesic.surfaceDistance; + runInAction(() => (terria.mainViewer.scale = pixelDistance)); + + // Find the first distance that makes the scale bar less than 100 pixels. + const maxBarWidth = 100; + let distance; + for (let i = distances.length - 1; !isDefined(distance) && i >= 0; --i) { + if (distances[i] / pixelDistance < maxBarWidth) { + distance = distances[i]; + } + } + + if (isDefined(distance)) { + let label; + if (distance >= 1000) { + label = (distance / 1000).toString() + " km"; + } else { + label = distance.toString() + " m"; + } + setBarWidth(((distance / pixelDistance) * scale) | 0); + setDistanceLabel(label); + } else { + setBarWidth(0); + setDistanceLabel(undefined); + } + }; + + const updateDistanceLegendLeaflet = (map: L.Map) => { + const halfHeight = map.getSize().y / 2; + const maxPixelWidth = 100; + const maxMeters = map + .containerPointToLatLng([0, halfHeight]) + .distanceTo(map.containerPointToLatLng([maxPixelWidth, halfHeight])); + + runInAction(() => (terria.mainViewer.scale = maxMeters / 100)); + // @ts-ignore + const meters = L.control.scale()._getRoundNum(maxMeters); + const label = meters < 1000 ? meters + " m" : meters / 1000 + " km"; + + setBarWidth((meters / maxMeters) * maxPixelWidth * scale); + setDistanceLabel(label); + }; + + const barStyle = { + width: barWidth + "px", + left: 5 + (125 - barWidth) / 2 + "px", + height: "2px" + }; + + return distanceLabel ? ( + + + {distanceLabel} + +
+ + ) : null; + } +); diff --git a/lib/ReactViews/Map/BottomBar/LocationBar.tsx b/lib/ReactViews/Map/BottomBar/LocationBar.tsx new file mode 100644 index 00000000000..a8b99e2133c --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/LocationBar.tsx @@ -0,0 +1,114 @@ +import React from "react"; +import { observer } from "mobx-react"; +import { FC, RefObject, useEffect, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import styled, { useTheme } from "styled-components"; +import MouseCoords from "../../../ReactViewModels/MouseCoords"; +import Box from "../../../Styled/Box"; +import { RawButton } from "../../../Styled/Button"; + +interface ILocationBarProps { + mouseCoords: MouseCoords; +} + +const Section = styled(Box).attrs({ + paddedHorizontally: true +})``; + +const StyledText = styled.span` + font-family: ${(props) => props.theme.fontMono}; + color: ${(props) => props.theme.textLight}; + white-space: nowrap; + font-size: 0.7rem; + padding: 0 5px 0 5px; +`; + +const setInnerText = (ref: RefObject, value: string) => { + if (ref.current) ref.current.innerText = value; +}; + +export const LocationBar: FC = observer( + ({ mouseCoords }) => { + const theme = useTheme(); + const { t } = useTranslation(); + + const elevationRef = useRef(null); + const longitudeRef = useRef(null); + const latitudeRef = useRef(null); + const utmZoneRef = useRef(null); + const eastRef = useRef(null); + const northRef = useRef(null); + + useEffect(() => { + const disposer = mouseCoords.updateEvent.addEventListener(() => { + setInnerText(elevationRef, mouseCoords.elevation ?? ""); + setInnerText(longitudeRef, mouseCoords.longitude ?? ""); + setInnerText(latitudeRef, mouseCoords.latitude ?? ""); + setInnerText(utmZoneRef, mouseCoords.utmZone ?? ""); + setInnerText(eastRef, mouseCoords.east ?? ""); + setInnerText(northRef, mouseCoords.north ?? ""); + }); + return disposer; + }); + + return ( + + + {!mouseCoords.useProjection ? ( + <> +
+ {t("legend.lat")} + + {mouseCoords.latitude} + +
+
+ {t("legend.lon")} + + {mouseCoords.longitude} + +
+ + ) : ( + <> +
+ {t("legend.zone")} + {mouseCoords.utmZone} +
+
+ {t("legend.e")} + {mouseCoords.east} +
+
+ {t("legend.n")} + {mouseCoords.north} +
+ + )} +
+ {t("legend.elev")} + {mouseCoords.elevation} +
+
+
+ ); + } +); diff --git a/lib/ReactViews/Map/BottomBar/index.ts b/lib/ReactViews/Map/BottomBar/index.ts new file mode 100644 index 00000000000..c8b81e2ff08 --- /dev/null +++ b/lib/ReactViews/Map/BottomBar/index.ts @@ -0,0 +1 @@ +export { BottomBar } from "./BottomBar"; diff --git a/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx b/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx index 053feec01d1..f6fdd77d369 100644 --- a/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx +++ b/lib/ReactViews/Map/BottomLeftBar/BottomLeftBar.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { FC } from "react"; import { useTranslation } from "react-i18next"; import ViewState from "../../../ReactViewModels/ViewState"; @@ -10,47 +10,43 @@ import MapDataCount from "../../BottomDock/MapDataCount"; import Terria from "../../../Models/Terria"; import MapIconButton from "../../MapIconButton/MapIconButton"; import defined from "terriajs-cesium/Source/Core/defined"; - -interface Props { - terria: Terria; - viewState: ViewState; -} +import { useViewState } from "../../Context"; const BottomLeftContainer = styled(Box)` position: absolute; bottom: 40px; - @media (max-width: ${(props) => props.theme.mobile}px) { bottom: 35px; } `; -const shouldShowPlayStoryButton = (props: Props) => - props.terria.configParameters.storyEnabled && - defined(props.terria.stories) && - props.terria.stories.length > 0 && - props.viewState.useSmallScreenInterface; +const shouldShowPlayStoryButton = (viewState: ViewState) => + viewState.terria.configParameters.storyEnabled && + defined(viewState.terria.stories) && + viewState.terria.stories.length > 0 && + viewState.useSmallScreenInterface; -const BottomLeftBar = (props: Props) => { +const BottomLeftBar: FC = () => { const { t } = useTranslation(); const theme = useTheme(); + const viewState = useViewState(); const isNotificationActive = - props.terria.notificationState.currentNotification; + viewState.terria.notificationState.currentNotification; return ( - {shouldShowPlayStoryButton(props) ? ( + {shouldShowPlayStoryButton(viewState) ? ( } - onClick={() => props.viewState.runStories()} + onClick={() => viewState.runStories()} primary={!isNotificationActive} > {t("story.playStory")} diff --git a/lib/ReactViews/Map/HelpButton/help-button.scss b/lib/ReactViews/Map/HelpButton/help-button.scss deleted file mode 100644 index c89132566d1..00000000000 --- a/lib/ReactViews/Map/HelpButton/help-button.scss +++ /dev/null @@ -1,4 +0,0 @@ -.helpBtn { - composes: btn from "../../../Sass/common/_buttons.scss"; - composes: btn--map from "../../../Sass/common/_buttons.scss"; -} diff --git a/lib/ReactViews/Map/Legend/DistanceLegend.jsx b/lib/ReactViews/Map/Legend/DistanceLegend.jsx deleted file mode 100644 index ec367981f3e..00000000000 --- a/lib/ReactViews/Map/Legend/DistanceLegend.jsx +++ /dev/null @@ -1,202 +0,0 @@ -"use strict"; -import React from "react"; -import PropTypes from "prop-types"; -import L from "leaflet"; -import Cartesian2 from "terriajs-cesium/Source/Core/Cartesian2"; -import defined from "terriajs-cesium/Source/Core/defined"; -import EllipsoidGeodesic from "terriajs-cesium/Source/Core/EllipsoidGeodesic"; -import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; -import Styles from "./legend.scss"; -import { observer, disposeOnUnmount } from "mobx-react"; -import { autorun, runInAction } from "mobx"; - -const geodesic = new EllipsoidGeodesic(); - -const distances = [ - 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1000, 2000, 3000, 5000, 10000, - 20000, 30000, 50000, 100000, 200000, 300000, 500000, 1000000, 2000000, - 3000000, 5000000, 10000000, 20000000, 30000000, 50000000 -]; - -@observer -class DistanceLegend extends React.Component { - constructor(props) { - super(props); - this.state = { - distanceLabel: undefined, - barWidth: 0 - }; - } - static displayName = "DistanceLegend"; - static propTypes = { - terria: PropTypes.object, - scale: PropTypes.number, - isPrintMode: PropTypes.bool - }; - - /* eslint-disable-next-line camelcase */ - UNSAFE_componentWillMount() { - this.viewerSubscriptions = []; - this.removeUpdateSubscription = undefined; - - this._lastLegendUpdate = undefined; - this.viewerSubscriptions.push( - this.props.terria.mainViewer.beforeViewerChanged.addEventListener(() => { - if (defined(this.removeUpdateSubscription)) { - this.removeUpdateSubscription(); - this.removeUpdateSubscription = undefined; - } - }) - ); - disposeOnUnmount( - this, - autorun(() => this.addUpdateSubscription()) - ); - } - - componentWillUnmount() { - this.removeUpdateSubscription && this.removeUpdateSubscription(); - this.viewerSubscriptions.forEach((remove) => remove()); - } - - addUpdateSubscription() { - const that = this; - if (defined(this.props.terria.cesium)) { - const scene = this.props.terria.cesium.scene; - this.removeUpdateSubscription = scene.postRender.addEventListener(() => { - this.updateDistanceLegendCesium(scene); - if (this.props.isPrintMode) { - this.removeUpdateSubscription(); - this.removeUpdateSubscription = null; - } - }); - } else if (defined(this.props.terria.leaflet)) { - const map = this.props.terria.leaflet.map; - - const potentialChangeCallback = function potentialChangeCallback() { - that.updateDistanceLegendLeaflet(map); - }; - if (!this.props.isPrintMode) { - that.removeUpdateSubscription = function () { - map.off("zoomend", potentialChangeCallback); - map.off("moveend", potentialChangeCallback); - }; - - map.on("zoomend", potentialChangeCallback); - map.on("moveend", potentialChangeCallback); - } - - that.updateDistanceLegendLeaflet(map); - } - } - - updateDistanceLegendCesium(scene) { - const now = getTimestamp(); - if (now < this._lastLegendUpdate + 250) { - return; - } - - this._lastLegendUpdate = now; - - // Find the distance between two pixels at the bottom center of the screen. - const width = scene.canvas.clientWidth; - const height = scene.canvas.clientHeight; - - const left = scene.camera.getPickRay( - new Cartesian2((width / 2) | 0, height - 1) - ); - const right = scene.camera.getPickRay( - new Cartesian2((1 + width / 2) | 0, height - 1) - ); - - const globe = scene.globe; - const leftPosition = globe.pick(left, scene); - const rightPosition = globe.pick(right, scene); - - if (!defined(leftPosition) || !defined(rightPosition)) { - this.setState({ - barWidth: undefined, - distanceLabel: undefined - }); - return; - } - - const leftCartographic = - globe.ellipsoid.cartesianToCartographic(leftPosition); - const rightCartographic = - globe.ellipsoid.cartesianToCartographic(rightPosition); - - geodesic.setEndPoints(leftCartographic, rightCartographic); - const pixelDistance = geodesic.surfaceDistance; - runInAction(() => (this.props.terria.mainViewer.scale = pixelDistance)); - - // Find the first distance that makes the scale bar less than 100 pixels. - const maxBarWidth = 100; - let distance; - for (let i = distances.length - 1; !defined(distance) && i >= 0; --i) { - if (distances[i] / pixelDistance < maxBarWidth) { - distance = distances[i]; - } - } - - if (defined(distance)) { - let label; - if (distance >= 1000) { - label = (distance / 1000).toString() + " km"; - } else { - label = distance.toString() + " m"; - } - - this.setState({ - barWidth: ((distance / pixelDistance) * this.props.scale) | 0, - distanceLabel: label - }); - } else { - this.setState({ - barWidth: undefined, - distanceLabel: undefined - }); - } - } - - updateDistanceLegendLeaflet(map) { - const halfHeight = map.getSize().y / 2; - const maxPixelWidth = 100; - const maxMeters = map - .containerPointToLatLng([0, halfHeight]) - .distanceTo(map.containerPointToLatLng([maxPixelWidth, halfHeight])); - - runInAction(() => (this.props.terria.mainViewer.scale = maxMeters / 100)); - - const meters = L.control.scale()._getRoundNum(maxMeters); - const label = meters < 1000 ? meters + " m" : meters / 1000 + " km"; - - this.setState({ - barWidth: (meters / maxMeters) * maxPixelWidth * this.props.scale, - distanceLabel: label - }); - } - - render() { - const barStyle = { - width: this.state.barWidth + "px", - left: 5 + (125 - this.state.barWidth) / 2 + "px", - height: "2px" - }; - - const distanceLabel = this.state.distanceLabel ? ( -
- -
-
- ) : null; - - return distanceLabel; - } -} -DistanceLegend.defaultProps = { - scale: 1, - isPrintMode: false -}; - -export default DistanceLegend; diff --git a/lib/ReactViews/Map/Legend/LocationBar.tsx b/lib/ReactViews/Map/Legend/LocationBar.tsx deleted file mode 100644 index b7b0431059d..00000000000 --- a/lib/ReactViews/Map/Legend/LocationBar.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import classNames from "classnames"; -import { observer } from "mobx-react"; -import React, { RefObject, useEffect, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import styled from "styled-components"; -import Terria from "../../../Models/Terria"; -import MouseCoords from "../../../ReactViewModels/MouseCoords"; -import Styles from "./legend.scss"; - -interface PropsType { - terria: Terria; - showUtmZone: boolean; - mouseCoords: MouseCoords; -} - -const LocationBar: React.FC = observer(({ mouseCoords }) => { - const { t } = useTranslation(); - const elevationRef = useRef(null); - const longitudeRef = useRef(null); - const latitudeRef = useRef(null); - const utmZoneRef = useRef(null); - const eastRef = useRef(null); - const northRef = useRef(null); - - useEffect(() => { - const disposer = mouseCoords.updateEvent.addEventListener(() => { - setInnerText(elevationRef, mouseCoords.elevation ?? ""); - setInnerText(longitudeRef, mouseCoords.longitude ?? ""); - setInnerText(latitudeRef, mouseCoords.latitude ?? ""); - setInnerText(utmZoneRef, mouseCoords.utmZone ?? ""); - setInnerText(eastRef, mouseCoords.east ?? ""); - setInnerText(northRef, mouseCoords.north ?? ""); - }); - return disposer; - }); - - return ( - mouseCoords.toggleUseProjection()} - > - {!mouseCoords.useProjection && ( - <> -
- {t("legend.lat")} - {mouseCoords.latitude} -
-
- {t("legend.lon")} - {mouseCoords.longitude} -
- - )} - {mouseCoords.useProjection && ( - <> -
- {t("legend.zone")} - {mouseCoords.utmZone} -
-
- {t("legend.e")} - {mouseCoords.east} -
-
- {t("legend.n")} - {mouseCoords.north} -
- - )} -
- {t("legend.elev")} - {mouseCoords.elevation} -
-
- ); -}); - -function setInnerText(ref: RefObject, value: string) { - if (ref.current) ref.current.innerText = value; -} - -const LocationButton = styled.button` - &:hover { - background: ${(p) => p.theme.colorPrimary}; - } -`; - -export default LocationBar; diff --git a/lib/ReactViews/Map/Legend/legend.scss b/lib/ReactViews/Map/Legend/legend.scss deleted file mode 100644 index 58110a76b6e..00000000000 --- a/lib/ReactViews/Map/Legend/legend.scss +++ /dev/null @@ -1,75 +0,0 @@ -@import "~terriajs-variables"; -@import "../../../Sass/common/mixins"; - -$distance-bg: rgba($dark, 0.9); - -.baseLegend { - box-sizing: border-box; - font-family: $font-base; - float: left; - background-color: #fff; - color: $text-dark; - padding: $padding-small $padding-small; - font-size: $font-size-mid-mini; - text-align: center; - line-height: 1; - border: 0; - outline: 0; - font-family: $font-mono; - max-height: 21px; - margin-top: $padding-mini; - &:hover { - background: $faint-bg; - } - - .bar { - background: #fff; - margin: 0 auto; - display: block; - @include transition(all 0.5s ease-in-out); - } -} - -.locationBar, -.distanceLegend { - composes: baseLegend; - // Adjust colors to match btn--map. - background-color: unset; - margin-bottom: $padding-mini; - color: $text-light; - &:hover { - // background: $color-primary; - } - // - margin-right: $padding-small; - span { - padding: 0 $padding-small; - } - - li, - div { - display: inline-block; - padding: 0 $padding-small; - text-align: left; - } - - .section-long { - width: 130px; - } - - .section { - width: 112px; - } - - .section-short { - width: 70px; - } -} - -.distanceLegend { - &:hover { - background: $charcoal-grey; - } - text-align: center; - width: 110px; -} diff --git a/lib/ReactViews/Map/Legend/legend.scss.d.ts b/lib/ReactViews/Map/Legend/legend.scss.d.ts deleted file mode 100644 index 2216fd3b3ba..00000000000 --- a/lib/ReactViews/Map/Legend/legend.scss.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'bar': string; - 'baseLegend': string; - 'distanceLegend': string; - 'locationBar': string; - 'section': string; - 'section-long': string; - 'section-short': string; - 'sectionLong': string; - 'sectionShort': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/MapColumn.tsx b/lib/ReactViews/Map/MapColumn.tsx new file mode 100644 index 00000000000..eb33ebc28c8 --- /dev/null +++ b/lib/ReactViews/Map/MapColumn.tsx @@ -0,0 +1,140 @@ +import { observer } from "mobx-react"; +import React, { FC } from "react"; +import { useTranslation } from "react-i18next"; +import Box from "../../Styled/Box"; +import ActionBarPortal from "../ActionBar/ActionBarPortal"; +import BottomDock from "../BottomDock/BottomDock"; +import { useViewState } from "../Context"; +import Loader from "../Loader"; +import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; +import { BottomBar } from "./BottomBar"; +import BottomLeftBar from "./BottomLeftBar/BottomLeftBar"; +import { MapNavigation } from "./MapNavigation"; +import MenuBar from "./MenuBar/MenuBar"; +import { ProgressBar } from "./ProgressBar"; +import { TerriaViewerWrapper } from "./TerriaViewerWrapper"; +import Toast from "./Toast"; + +interface IMapColumnProps { + customFeedbacks: any; + animationDuration: number; + customElements: any; +} + +/** + * Right-hand column that contains the map, controls that sit over the map and sometimes the bottom dock containing + * the timeline and charts. + */ +export const MapColumn: FC = observer( + ({ customFeedbacks, customElements, animationDuration }) => { + const viewState = useViewState(); + const { t } = useTranslation(); + + return ( + + +
+ +
+ {!viewState.hideMapUi && ( +
+ + +
+ )} + + + + {!viewState.hideMapUi && ( + <> + + + + + + + + + + + + {viewState.terria.configParameters.printDisclaimer && ( + + {viewState.terria.configParameters.printDisclaimer.text} + + )} + + )} +
+
+ {!viewState.hideMapUi && ( + + )} +
+
+ ); + } +); + +export default MapColumn; diff --git a/lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx b/lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx similarity index 84% rename from lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx rename to lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx index cd99a45382f..57b1ef8c648 100644 --- a/lib/ReactViews/Map/Navigation/Items/OverflowNavigationItem.tsx +++ b/lib/ReactViews/Map/MapNavigation/CollapsedNavigation.tsx @@ -3,16 +3,16 @@ import { observer } from "mobx-react"; import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; import styled, { useTheme } from "styled-components"; -import { applyTranslationIfExists } from "../../../../Language/languageHelpers"; -import Box, { BoxSpan } from "../../../../Styled/Box"; -import { StyledIcon } from "../../../../Styled/Icon"; -import Spacing from "../../../../Styled/Spacing"; -import Text from "../../../../Styled/Text"; -import { IMapNavigationItem } from "../../../../ViewModels/MapNavigation/MapNavigationModel"; -import CloseButton from "../../../Generic/CloseButton"; -import { PrefaceBox } from "../../../Generic/PrefaceBox"; -import { useViewState } from "../../../StandardUserInterface/ViewStateContext"; -import { filterViewerAndScreenSize } from "../MapNavigation"; +import { applyTranslationIfExists } from "../../../Language/languageHelpers"; +import Box, { BoxSpan } from "../../../Styled/Box"; +import { StyledIcon } from "../../../Styled/Icon"; +import Spacing from "../../../Styled/Spacing"; +import Text from "../../../Styled/Text"; +import { IMapNavigationItem } from "../../../ViewModels/MapNavigation/MapNavigationModel"; +import { useViewState } from "../../Context"; +import CloseButton from "../../Generic/CloseButton"; +import { PrefaceBox } from "../../Generic/PrefaceBox"; +import { filterViewerAndScreenSize } from "./filterViewerAndScreenSize"; interface PropTypes { items: IMapNavigationItem[]; @@ -128,7 +128,7 @@ const CollapsedNavigationPanel: React.FC = observer( ); const CollapsedNavigationDisplayName = "CollapsedNavigation"; -const CollapsedNavigation: React.FC = observer(() => { +export const CollapsedNavigation: React.FC = observer(() => { const viewState = useViewState(); useEffect(() => autorun(() => { @@ -163,5 +163,3 @@ const CollapsedNavigation: React.FC = observer(() => { ); }); - -export default CollapsedNavigation; diff --git a/lib/ReactViews/Map/Navigation/Items/AugmentedVirtualityTool.tsx b/lib/ReactViews/Map/MapNavigation/Items/AugmentedVirtualityTool.tsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/AugmentedVirtualityTool.tsx rename to lib/ReactViews/Map/MapNavigation/Items/AugmentedVirtualityTool.tsx diff --git a/lib/ReactViews/Map/Navigation/Items/CatalogShortcut.jsx b/lib/ReactViews/Map/MapNavigation/Items/CatalogShortcut.jsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/CatalogShortcut.jsx rename to lib/ReactViews/Map/MapNavigation/Items/CatalogShortcut.jsx diff --git a/lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx b/lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx similarity index 65% rename from lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx rename to lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx index 719b03526d0..377e116533d 100644 --- a/lib/ReactViews/Map/Navigation/Items/CloseToolButton.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/CloseToolButton.tsx @@ -1,15 +1,12 @@ -import React from "react"; -import { withTranslation, WithTranslation } from "react-i18next"; -import ViewState from "../../../../ReactViewModels/ViewState"; +import React, { FC } from "react"; +import { useTranslation } from "react-i18next"; import Icon from "../../../../Styled/Icon"; +import { useViewState } from "../../../Context"; import MapIconButton from "../../../MapIconButton/MapIconButton"; -interface PropsType extends WithTranslation { - viewState: ViewState; - t: any; -} - -function CloseToolButton({ viewState, t }: PropsType) { +export const CloseToolButton: FC = () => { + const { t } = useTranslation(); + const viewState = useViewState(); const closeText = t("tool.closeButtonTitle", { toolName: viewState.currentTool?.toolName }); @@ -31,6 +28,4 @@ function CloseToolButton({ viewState, t }: PropsType) { {closeText} ); -} - -export default withTranslation()(CloseToolButton); +}; diff --git a/lib/ReactViews/Map/Navigation/Items/Compass.tsx b/lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx similarity index 97% rename from lib/ReactViews/Map/Navigation/Items/Compass.tsx rename to lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx index 48981d45895..a989f007286 100644 --- a/lib/ReactViews/Map/Navigation/Items/Compass.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/Compass.tsx @@ -10,7 +10,8 @@ */ // import { TFunction } from "i18next"; -import { computed, runInAction, when, makeObservable } from "mobx"; +import { computed, runInAction, when } from "mobx"; +import debounce from "lodash-es/debounce"; import React from "react"; import { WithTranslation, withTranslation } from "react-i18next"; import styled, { DefaultTheme, withTheme } from "styled-components"; @@ -22,17 +23,16 @@ import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; import CesiumMath from "terriajs-cesium/Source/Core/Math"; import Matrix4 from "terriajs-cesium/Source/Core/Matrix4"; import Ray from "terriajs-cesium/Source/Core/Ray"; -import Transforms from "terriajs-cesium/Source/Core/Transforms"; -import isDefined from "../../../../Core/isDefined"; -import Terria from "../../../../Models/Terria"; -import ViewState from "../../../../ReactViewModels/ViewState"; -import Box from "../../../../Styled/Box"; -import Icon, { StyledIcon } from "../../../../Styled/Icon"; -import GyroscopeGuidance from "../../../GyroscopeGuidance/GyroscopeGuidance"; -import { withTerriaRef } from "../../../HOCs/withTerriaRef"; -import FadeIn from "../../../Transitions/FadeIn/FadeIn"; -import debounce from "lodash-es/debounce"; import Scene from "terriajs-cesium/Source/Scene/Scene"; +import Transforms from "terriajs-cesium/Source/Core/Transforms"; +import isDefined from "../../../../../Core/isDefined"; +import Terria from "../../../../../Models/Terria"; +import ViewState from "../../../../../ReactViewModels/ViewState"; +import Box from "../../../../../Styled/Box"; +import Icon, { StyledIcon } from "../../../../../Styled/Icon"; +import { GyroscopeGuidance } from "./GyroscopeGuidance"; +import { withTerriaRef } from "../../../../HOCs/withTerriaRef"; +import FadeIn from "../../../../Transitions/FadeIn/FadeIn"; const CameraFlightPath = require("terriajs-cesium/Source/Scene/CameraFlightPath").default; @@ -178,7 +178,6 @@ class Compass extends React.PureComponent { */ constructor(props: PropTypes) { super(props); - makeObservable(this); this.state = { orbitCursorAngle: 0, heading: 0.0, @@ -385,7 +384,7 @@ class Compass extends React.PureComponent { this.setState({ active: true })} onMouseOut={() => { diff --git a/lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx similarity index 91% rename from lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx rename to lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx index 1c985776010..b1ff9cf0ff5 100644 --- a/lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance.jsx +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance.jsx @@ -3,15 +3,15 @@ import styled, { css } from "styled-components"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -import Icon from "../../Styled/Icon"; -import Box from "../../Styled/Box"; -import { TextSpan } from "../../Styled/Text"; -import { RawButton } from "../../Styled/Button"; -import Spacing from "../../Styled/Spacing"; -import MapIconButton from "../MapIconButton/MapIconButton"; +import Icon from "../../../../../Styled/Icon"; +import Box from "../../../../../Styled/Box"; +import { TextSpan } from "../../../../../Styled/Text"; +import { RawButton } from "../../../../../Styled/Button"; +import Spacing from "../../../../../Styled/Spacing"; +import MapIconButton from "../../../../MapIconButton/MapIconButton"; // import MenuPanel from "../StandardUserInterface/customizable/MenuPanel"; -import CleanDropdownPanel from "../CleanDropdownPanel/CleanDropdownPanel"; -import { COMPASS_LOCAL_PROPERTY_KEY } from "../Map/Navigation/Items/Compass"; +import CleanDropdownPanel from "../../../../CleanDropdownPanel/CleanDropdownPanel"; +import { COMPASS_LOCAL_PROPERTY_KEY } from "./Compass"; GyroscopeGuidance.propTypes = { viewState: PropTypes.object.isRequired, @@ -129,7 +129,7 @@ GyroscopeGuidancePanel.propTypes = { onClose: PropTypes.func.isRequired }; -export default function GyroscopeGuidance(props) { +export function GyroscopeGuidance(props) { const [controlPanelOpen, setControlPanelOpen] = useState(false); const controlsMapIcon = useRef(); const { t } = useTranslation(); diff --git a/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts b/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts new file mode 100644 index 00000000000..8c4f56534da --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/Items/Compass/index.ts @@ -0,0 +1,4 @@ +import Compass from "./Compass"; + +export { COMPASS_TOOL_ID } from "./Compass"; +export { Compass }; diff --git a/lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx b/lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx similarity index 94% rename from lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx rename to lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx index 00dd022ea15..7cf03c5e460 100644 --- a/lib/ReactViews/Map/Navigation/Items/MapNavigationItem.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/MapNavigationItem.tsx @@ -19,7 +19,7 @@ interface PropTypes { } @observer -class MapNavigationItem extends React.Component { +class MapNavigationItemBase extends React.Component { constructor(props: PropTypes) { super(props); } @@ -73,4 +73,4 @@ export const Control = styled(Box).attrs({ text-align: center; `; -export default withTranslation()(MapNavigationItem); +export const MapNavigationItem = withTranslation()(MapNavigationItemBase); diff --git a/lib/ReactViews/Map/Navigation/Items/MeasureTool.ts b/lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts similarity index 99% rename from lib/ReactViews/Map/Navigation/Items/MeasureTool.ts rename to lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts index 65beee07da7..d84a06c0ce4 100644 --- a/lib/ReactViews/Map/Navigation/Items/MeasureTool.ts +++ b/lib/ReactViews/Map/MapNavigation/Items/MeasureTool.ts @@ -21,7 +21,7 @@ interface MeasureToolOptions { onClose(): void; } -export default class MeasureTool extends MapNavigationItemController { +export class MeasureTool extends MapNavigationItemController { static id = "measure-tool"; static displayName = "MeasureTool"; diff --git a/lib/ReactViews/Map/Navigation/Items/MyLocation.ts b/lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts similarity index 98% rename from lib/ReactViews/Map/Navigation/Items/MyLocation.ts rename to lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts index 87bec7836d6..b2245d98a4e 100644 --- a/lib/ReactViews/Map/Navigation/Items/MyLocation.ts +++ b/lib/ReactViews/Map/MapNavigation/Items/MyLocation.ts @@ -19,7 +19,7 @@ interface PropTypes { terria: Terria; } -class MyLocation extends MapNavigationItemController { +export class MyLocation extends MapNavigationItemController { static id = "my-location"; static displayName = "MyLocation"; readonly terria: Terria; @@ -200,5 +200,3 @@ class MyLocation extends MapNavigationItemController { } } } - -export default MyLocation; diff --git a/lib/ReactViews/Map/Navigation/Items/ToggleSplitterTool.ts b/lib/ReactViews/Map/MapNavigation/Items/ToggleSplitterTool.ts similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/ToggleSplitterTool.ts rename to lib/ReactViews/Map/MapNavigation/Items/ToggleSplitterTool.ts diff --git a/lib/ReactViews/Map/Navigation/Items/ToolButton.tsx b/lib/ReactViews/Map/MapNavigation/Items/ToolButton.tsx similarity index 100% rename from lib/ReactViews/Map/Navigation/Items/ToolButton.tsx rename to lib/ReactViews/Map/MapNavigation/Items/ToolButton.tsx diff --git a/lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx similarity index 97% rename from lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx rename to lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx index 429a76d15af..61aa2971de0 100644 --- a/lib/ReactViews/Map/Navigation/Items/ZoomControl.tsx +++ b/lib/ReactViews/Map/MapNavigation/Items/ZoomControl.tsx @@ -17,7 +17,7 @@ import Box from "../../../../Styled/Box"; import { RawButton } from "../../../../Styled/Button"; import Icon, { GLYPHS } from "../../../../Styled/Icon"; import Ul, { Li } from "../../../../Styled/List"; -import Terria from "./../../../../Models/Terria"; +import Terria from "../../../../Models/Terria"; const Tween = require("terriajs-cesium/Source/ThirdParty/Tween").default; @@ -29,7 +29,7 @@ interface PropTypes extends WithTranslation { export const ZOOM_CONTROL_ID = "zoom"; -class ZoomControl extends React.Component { +class ZoomControlBase extends React.Component { static displayName = "ZoomControl"; constructor(props: PropTypes) { @@ -236,10 +236,9 @@ const StyledZoomControl = styled(Box).attrs((props) => ({ width: 20px; fill: ${(props) => props.theme.darkWithOverlay}; } - ${Li} { margin: 5px 0; } `; -export default withTranslation()(withTheme(ZoomControl)); +export const ZoomControl = withTranslation()(withTheme(ZoomControlBase)); diff --git a/lib/ReactViews/Map/MapNavigation/Items/index.ts b/lib/ReactViews/Map/MapNavigation/Items/index.ts new file mode 100644 index 00000000000..7d28299b240 --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/Items/index.ts @@ -0,0 +1,14 @@ +export { + AR_TOOL_ID, + AugmentedVirtualityController, + AugmentedVirtualityHoverController, + AugmentedVirtualityRealign, + AugmentedVirtualityRealignController +} from "./AugmentedVirtualityTool"; +export { CloseToolButton } from "./CloseToolButton"; +export * from "./Compass"; +export { Control, MapNavigationItem } from "./MapNavigationItem"; +export { MeasureTool } from "./MeasureTool"; +export { MyLocation } from "./MyLocation"; +export { ToggleSplitterController } from "./ToggleSplitterTool"; +export { ZoomControl, ZOOM_CONTROL_ID } from "./ZoomControl"; diff --git a/lib/ReactViews/Map/Navigation/MapNavigation.tsx b/lib/ReactViews/Map/MapNavigation/MapNavigation.tsx similarity index 90% rename from lib/ReactViews/Map/Navigation/MapNavigation.tsx rename to lib/ReactViews/Map/MapNavigation/MapNavigation.tsx index e1be09ea9e3..5f6ef8cf951 100644 --- a/lib/ReactViews/Map/Navigation/MapNavigation.tsx +++ b/lib/ReactViews/Map/MapNavigation/MapNavigation.tsx @@ -13,7 +13,6 @@ import { observer } from "mobx-react"; import React from "react"; import { WithTranslation, withTranslation } from "react-i18next"; import styled, { DefaultTheme, withTheme } from "styled-components"; -import isDefined from "../../../Core/isDefined"; import ViewState from "../../../ReactViewModels/ViewState"; import Box from "../../../Styled/Box"; import Icon, { GLYPHS } from "../../../Styled/Icon"; @@ -23,9 +22,9 @@ import MapNavigationModel, { } from "../../../ViewModels/MapNavigation/MapNavigationModel"; import withControlledVisibility from "../../HOCs/withControlledVisibility"; import MapIconButton from "../../MapIconButton/MapIconButton"; -import MapNavigationItem, { Control } from "./Items/MapNavigationItem"; +import { filterViewerAndScreenSize } from "./filterViewerAndScreenSize"; +import { Control, MapNavigationItem } from "./Items"; import { registerMapNavigations } from "./registerMapNavigations"; -import { ScreenSize } from "../../../ViewModels/CompositeBar/CompositeBarModel"; const OVERFLOW_ACTION_SIZE = 42; @@ -56,11 +55,9 @@ const StyledMapNavigation = styled.div` } } pointer-events: none; - button { pointer-events: auto; } - ${(p) => p.trainerBarVisible && ` @@ -90,7 +87,7 @@ enum Orientation { } @observer -class MapNavigation extends React.Component { +class MapNavigationBase extends React.Component { static displayName = "MapNavigation"; private navigationRef = React.createRef(); private readonly resizeListener: () => any; @@ -330,27 +327,6 @@ class MapNavigation extends React.Component { } } -export default withTranslation()( - withTheme(withControlledVisibility(MapNavigation)) +export const MapNavigation = withTranslation()( + withTheme(withControlledVisibility(MapNavigationBase)) ); - -export function filterViewerAndScreenSize( - item: IMapNavigationItem, - viewState: ViewState -) { - const currentViewer = viewState.terria.mainViewer.viewerMode; - const screenSize: ScreenSize = item.screenSize ?? "any"; - if (viewState.useSmallScreenInterface) { - return ( - (!isDefined(item.controller.viewerMode) || - item.controller.viewerMode === currentViewer) && - (screenSize === "any" || item.screenSize === "small") - ); - } else { - return ( - (!isDefined(item.controller.viewerMode) || - item.controller.viewerMode === currentViewer) && - (screenSize === "any" || item.screenSize === "medium") - ); - } -} diff --git a/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts b/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts new file mode 100644 index 00000000000..d555f60305a --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/filterViewerAndScreenSize.ts @@ -0,0 +1,25 @@ +import isDefined from "../../../Core/isDefined"; +import ViewState from "../../../ReactViewModels/ViewState"; +import { ScreenSize } from "../../../ViewModels/CompositeBar/CompositeBarModel"; +import { IMapNavigationItem } from "../../../ViewModels/MapNavigation/MapNavigationModel"; + +export function filterViewerAndScreenSize( + item: IMapNavigationItem, + viewState: ViewState +) { + const currentViewer = viewState.terria.mainViewer.viewerMode; + const screenSize: ScreenSize = item.screenSize ?? "any"; + if (viewState.useSmallScreenInterface) { + return ( + (!isDefined(item.controller.viewerMode) || + item.controller.viewerMode === currentViewer) && + (screenSize === "any" || item.screenSize === "small") + ); + } else { + return ( + (!isDefined(item.controller.viewerMode) || + item.controller.viewerMode === currentViewer) && + (screenSize === "any" || item.screenSize === "medium") + ); + } +} diff --git a/lib/ReactViews/Map/MapNavigation/index.ts b/lib/ReactViews/Map/MapNavigation/index.ts new file mode 100644 index 00000000000..0511deeab3f --- /dev/null +++ b/lib/ReactViews/Map/MapNavigation/index.ts @@ -0,0 +1,2 @@ +export { CollapsedNavigation } from "./CollapsedNavigation"; +export { MapNavigation } from "./MapNavigation"; diff --git a/lib/ReactViews/Map/Navigation/registerMapNavigations.tsx b/lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx similarity index 92% rename from lib/ReactViews/Map/Navigation/registerMapNavigations.tsx rename to lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx index 2a3a731c1e2..3c48d555e87 100644 --- a/lib/ReactViews/Map/Navigation/registerMapNavigations.tsx +++ b/lib/ReactViews/Map/MapNavigation/registerMapNavigations.tsx @@ -18,14 +18,16 @@ import { AugmentedVirtualityController, AugmentedVirtualityHoverController, AugmentedVirtualityRealign, - AugmentedVirtualityRealignController -} from "./Items/AugmentedVirtualityTool"; -import CloseToolButton from "./Items/CloseToolButton"; -import Compass, { COMPASS_TOOL_ID } from "./Items/Compass"; -import MeasureTool from "./Items/MeasureTool"; -import MyLocation from "./Items/MyLocation"; -import { ToggleSplitterController } from "./Items/ToggleSplitterTool"; -import ZoomControl, { ZOOM_CONTROL_ID } from "./Items/ZoomControl"; + AugmentedVirtualityRealignController, + CloseToolButton, + Compass, + COMPASS_TOOL_ID, + MeasureTool, + MyLocation, + ToggleSplitterController, + ZoomControl, + ZOOM_CONTROL_ID +} from "./Items"; export const CLOSE_TOOL_ID = "close-tool"; @@ -135,7 +137,7 @@ export const registerMapNavigations = (viewState: ViewState) => { location: "TOP", screenSize: undefined, controller: closeToolButtonController, - render: , + render: , order: 7 }); closeToolButtonController.setVisible(false); diff --git a/lib/ReactViews/Map/HelpButton/HelpButton.tsx b/lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx similarity index 85% rename from lib/ReactViews/Map/HelpButton/HelpButton.tsx rename to lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx index f0df7e8cbf4..2bfb674249a 100644 --- a/lib/ReactViews/Map/HelpButton/HelpButton.tsx +++ b/lib/ReactViews/Map/MenuBar/HelpButton/HelpButton.tsx @@ -1,10 +1,10 @@ import { observer } from "mobx-react"; import React from "react"; import { useTranslation } from "react-i18next"; -import Icon from "../../../Styled/Icon"; -import Text from "../../../Styled/Text"; -import Prompt from "../../Generic/Prompt"; -import { useViewState } from "../../StandardUserInterface/ViewStateContext"; +import Icon from "../../../../Styled/Icon"; +import Text from "../../../../Styled/Text"; +import Prompt from "../../../Generic/Prompt"; +import { useViewState } from "../../../Context"; import Styles from "./help-button.scss"; diff --git a/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss new file mode 100644 index 00000000000..fa774176e12 --- /dev/null +++ b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss @@ -0,0 +1,4 @@ +.helpBtn { + composes: btn from "../../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../../Sass/common/_buttons.scss"; +} diff --git a/lib/ReactViews/Map/HelpButton/help-button.scss.d.ts b/lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/HelpButton/help-button.scss.d.ts rename to lib/ReactViews/Map/MenuBar/HelpButton/help-button.scss.d.ts diff --git a/lib/ReactViews/Map/MenuBar.jsx b/lib/ReactViews/Map/MenuBar/MenuBar.jsx similarity index 90% rename from lib/ReactViews/Map/MenuBar.jsx rename to lib/ReactViews/Map/MenuBar/MenuBar.jsx index 14530ef9f57..51466898134 100644 --- a/lib/ReactViews/Map/MenuBar.jsx +++ b/lib/ReactViews/Map/MenuBar/MenuBar.jsx @@ -4,14 +4,14 @@ import { observer } from "mobx-react"; import PropTypes from "prop-types"; import React from "react"; import styled from "styled-components"; -import withControlledVisibility from "../../ReactViews/HOCs/withControlledVisibility"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; -import HelpButton from "./HelpButton/HelpButton"; -import LangPanel from "./Panels/LangPanel/LangPanel"; -import SettingPanel from "./Panels/SettingPanel"; -import SharePanel from "./Panels/SharePanel/SharePanel"; -import ToolsPanel from "./Panels/ToolsPanel/ToolsPanel"; +import withControlledVisibility from "../../HOCs/withControlledVisibility"; +import { useViewState } from "../../Context"; +import LangPanel from "../Panels/LangPanel/LangPanel"; +import SettingPanel from "../Panels/SettingPanel"; +import SharePanel from "../Panels/SharePanel/SharePanel"; +import ToolsPanel from "../Panels/ToolsPanel/ToolsPanel"; import StoryButton from "./StoryButton/StoryButton"; +import HelpButton from "./HelpButton/HelpButton"; import Styles from "./menu-bar.scss"; diff --git a/lib/ReactViews/Map/StoryButton/StoryButton.tsx b/lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx similarity index 88% rename from lib/ReactViews/Map/StoryButton/StoryButton.tsx rename to lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx index 14a24c72158..afc1afb5972 100644 --- a/lib/ReactViews/Map/StoryButton/StoryButton.tsx +++ b/lib/ReactViews/Map/MenuBar/StoryButton/StoryButton.tsx @@ -2,13 +2,13 @@ import React, { Ref } from "react"; import { Trans, useTranslation } from "react-i18next"; import { DefaultTheme } from "styled-components"; -import triggerResize from "../../../Core/triggerResize"; -import Terria from "../../../Models/Terria"; -import ViewState from "../../../ReactViewModels/ViewState"; -import Icon from "../../../Styled/Icon"; -import Text from "../../../Styled/Text"; -import Prompt from "../../Generic/Prompt"; -import { useRefForTerria } from "../../Hooks/useRefForTerria"; +import triggerResize from "../../../../Core/triggerResize"; +import Terria from "../../../../Models/Terria"; +import ViewState from "../../../../ReactViewModels/ViewState"; +import Icon from "../../../../Styled/Icon"; +import Text from "../../../../Styled/Text"; +import Prompt from "../../../Generic/Prompt"; +import { useRefForTerria } from "../../../Hooks/useRefForTerria"; import Styles from "./story-button.scss"; diff --git a/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss new file mode 100644 index 00000000000..b3aa3dad359 --- /dev/null +++ b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss @@ -0,0 +1,13 @@ +@import "~terriajs-variables"; + +.storyBtn { + composes: btn from "../../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../../Sass/common/_buttons.scss"; + + &:hover, + &:focus { + svg { + fill: #ffffff; + } + } +} diff --git a/lib/ReactViews/Map/StoryButton/story-button.scss.d.ts b/lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/StoryButton/story-button.scss.d.ts rename to lib/ReactViews/Map/MenuBar/StoryButton/story-button.scss.d.ts diff --git a/lib/ReactViews/Map/menu-bar.scss b/lib/ReactViews/Map/MenuBar/menu-bar.scss similarity index 83% rename from lib/ReactViews/Map/menu-bar.scss rename to lib/ReactViews/Map/MenuBar/menu-bar.scss index 97656d4e0df..0508b8c6abc 100644 --- a/lib/ReactViews/Map/menu-bar.scss +++ b/lib/ReactViews/Map/MenuBar/menu-bar.scss @@ -22,9 +22,9 @@ margin-left: 165px; } .menu { - composes: list-reset from "../../Sass/common/_base.scss"; - composes: clearfix from "../../Sass/common/_base.scss"; - composes: sm-show from "../../Sass/common/_base.scss"; + composes: list-reset from "../../../Sass/common/_base.scss"; + composes: clearfix from "../../../Sass/common/_base.scss"; + composes: sm-show from "../../../Sass/common/_base.scss"; margin: 0 $padding-small $padding-small $padding-small; @@ -75,11 +75,11 @@ } .flex { - composes: flex from "../../Sass/common/_base.scss"; + composes: flex from "../../../Sass/common/_base.scss"; } .langBtn { - composes: btn from "../../Sass/common/_buttons.scss"; - composes: btn--map from "../../Sass/common/_buttons.scss"; + composes: btn from "../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../Sass/common/_buttons.scss"; text-transform: uppercase; } diff --git a/lib/ReactViews/Map/menu-bar.scss.d.ts b/lib/ReactViews/Map/MenuBar/menu-bar.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/menu-bar.scss.d.ts rename to lib/ReactViews/Map/MenuBar/menu-bar.scss.d.ts diff --git a/lib/ReactViews/Map/Navigation/FullScreenButton.jsx b/lib/ReactViews/Map/Navigation/FullScreenButton.jsx deleted file mode 100644 index 36b8f1ec15a..00000000000 --- a/lib/ReactViews/Map/Navigation/FullScreenButton.jsx +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -const React = require("react"); -const createReactClass = require("create-react-class"); -const PropTypes = require("prop-types"); -import Styles from "./full_screen_button.scss"; -import classNames from "classnames"; -import Icon from "../../../Styled/Icon"; - -// The button to make the map full screen and hide the workbench. -const FullScreenButton = createReactClass({ - displayName: "FullScreenButton", - - propTypes: { - terria: PropTypes.object, - viewState: PropTypes.object.isRequired, - animationDuration: PropTypes.number // Defaults to 1 millisecond. - }, - - getInitialState() { - return { - isActive: false - }; - }, - - toggleFullScreen() { - this.props.viewState.setIsMapFullScreen( - !this.props.viewState.isMapFullScreen - ); - }, - - renderButtonText() { - if (this.props.viewState.isMapFullScreen) { - return Show Workbench; - } else { - return ; - } - }, - - render() { - const btnClassName = classNames(Styles.btn, { - [Styles.isActive]: this.props.viewState.isMapFullScreen - }); - const btnTitle = this.props.viewState.isMapFullScreen - ? "Show workbench" - : "Hide workbench"; - return ( -
- -
- ); - } -}); -module.exports = FullScreenButton; diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx index 6823a29fc26..aa6e72ee181 100644 --- a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx +++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanel.jsx @@ -14,7 +14,7 @@ import Icon, { StyledIcon } from "../../../../Styled/Icon"; import Spacing from "../../../../Styled/Spacing"; import Text from "../../../../Styled/Text"; import parseCustomMarkdownToReact from "../../../Custom/parseCustomMarkdownToReact"; -import { withViewState } from "../../../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../../../Context"; import HelpPanelItem from "./HelpPanelItem"; export const HELP_PANEL_ID = "help"; diff --git a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx index d93280354da..c2bca7af626 100644 --- a/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx +++ b/lib/ReactViews/Map/Panels/HelpPanel/HelpPanelItem.jsx @@ -10,7 +10,7 @@ import { import { isJsonString } from "../../../../Core/Json"; import Icon, { StyledIcon } from "../../../../Styled/Icon"; import Text from "../../../../Styled/Text"; -import { applyTranslationIfExists } from "./../../../../Language/languageHelpers"; +import { applyTranslationIfExists } from "../../../../Language/languageHelpers"; import HelpVideoPanel from "./HelpVideoPanel"; @observer diff --git a/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx b/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx index f05b81a990d..2ad49bc15b8 100644 --- a/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx +++ b/lib/ReactViews/Map/Panels/LangPanel/LangPanel.tsx @@ -6,7 +6,7 @@ import { RawButton } from "../../../../Styled/Button"; import Icon from "../../../../Styled/Icon"; import Ul, { Li } from "../../../../Styled/List"; import MenuPanel from "../../../StandardUserInterface/customizable/MenuPanel"; -import Styles from "../../menu-bar.scss"; +import Styles from "../../MenuBar/menu-bar.scss"; const stripLangLocale = (lang: string = ""): string => lang.split("-")[0]; diff --git a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx index 094fe520987..8f283732101 100644 --- a/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx +++ b/lib/ReactViews/Map/Panels/SharePanel/Print/PrintView.tsx @@ -2,9 +2,9 @@ import DOMPurify from "dompurify"; import React, { useEffect, useRef, useState } from "react"; import ReactDOM from "react-dom"; import { StyleSheetManager, ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../StandardUserInterface/StandardTheme"; -import { useViewState } from "../../../../StandardUserInterface/ViewStateContext"; -import DistanceLegend from "../../../Legend/DistanceLegend"; +import { terriaTheme } from "../../../../StandardUserInterface"; +import { useViewState } from "../../../../Context"; +import { DistanceLegend } from "../../../BottomBar/DistanceLegend"; import { buildShareLink, buildShortShareLink, @@ -72,10 +72,19 @@ const styles = ` padding: 5px; } + .tjs-legend__distanceLegend > label { + color: black; + } + + .tjs-legend__distanceLegend:hover { + background: #fff; + } + .tjs-legend__bar { border-bottom: 3px solid black; border-right: 3px solid black; border-left: 3px solid black; + margin: 0 auto; } body { @@ -174,7 +183,6 @@ const PrintView = (props: Props) => { {screenshot ? ( 0 ? rawPercentage : 100); - - this.setState({ - percentage: sanitisedPercentage - }); - } - - setMode(loading) { - this.setState({ loading: loading }); - } - - componentWillUnmount() { - this.eventHelper.removeAll(); - } - - /** - * Progress bar is influced by two loading states: - * The base globe where the progress bar shows actual progress, - * Sources where load progress is indeterminate including 3DTilesets where the progress bar is animated. - */ - render() { - const determinateProgress = this.state.percentage + "%"; - const indeterminateStillLoading = this.state.loading; - const allComplete = this.state.percentage === 100 && !this.state.loading; - - // use the baseMapContrastColor to ensure progress bar is visible on light backgrounds. If contrast color is white, use it. If its black, use the primary color of the current theme. - const backgroundColor = - this.props.viewState.terria.baseMapContrastColor === "#ffffff" - ? "#ffffff" - : this.props.theme.colorPrimary; - - return ( -
- ); - } -} - -export default withViewState(withTheme(ProgressBar)); diff --git a/lib/ReactViews/Map/ProgressBar.tsx b/lib/ReactViews/Map/ProgressBar.tsx new file mode 100644 index 00000000000..9fcc5359d60 --- /dev/null +++ b/lib/ReactViews/Map/ProgressBar.tsx @@ -0,0 +1,90 @@ +import React, { VFC, useCallback, useEffect, useMemo, useState } from "react"; +import styled, { css, keyframes, useTheme } from "styled-components"; +import EventHelper from "terriajs-cesium/Source/Core/EventHelper"; +import { useViewState } from "../Context"; + +export const ProgressBar: VFC = () => { + const [loadPercentage, setLoadPercentage] = useState(0); + const [indeterminateLoading, setIndeterminateLoading] = useState(); + + const theme = useTheme(); + const { terria } = useViewState(); + + const setProgress = useCallback((remaining: number, max: number) => { + const rawPercentage = (1 - remaining / max) * 100; + const sanitisedPercentage = Math.floor(remaining > 0 ? rawPercentage : 100); + setLoadPercentage(sanitisedPercentage); + }, []); + + const setMode = (mode: boolean) => { + setIndeterminateLoading(mode); + }; + + useEffect(() => { + const eventHelper = new EventHelper(); + + eventHelper.add(terria.tileLoadProgressEvent, setProgress); + + eventHelper.add(terria.indeterminateTileLoadProgressEvent, setMode); + + return () => { + eventHelper.removeAll(); + }; + }, []); + + const backgroundColor = useMemo( + () => + terria.baseMapContrastColor === "#ffffff" + ? "#ffffff" + : theme.colorPrimary, + [terria.baseMapContrastColor] + ); + + const allComplete = loadPercentage === 100 && !indeterminateLoading; + + return ( + + ); +}; + +interface IStyledProgressBarProps { + loadPercentage: string; + complete: boolean; + indeterminate: boolean; + backgroundColor: string; +} + +const StyledProgressBar = styled.div` + height: 5px; + overflow: hidden; + transition: opacity 200ms linear, width 200ms linear, visibility 400ms linear; + background-color: ${(props) => props.backgroundColor}; + width: ${(props) => props.loadPercentage}; + + ${(props) => props.complete && `visibility: hidden;`} + + ${(props) => + props.indeterminate && + css` + width: 100%; + animation: ${indeterminateAnimation} 1.2s infinite linear; + transform-origin: 0% 50%; + `} +`; + +const indeterminateAnimation = keyframes` + 0% { + transform: translateX(0) scaleX(0); + } + 40% { + transform: translateX(0) scaleX(0.4); + } + 100% { + transform: translateX(100%) scaleX(0.5); + } +}`; diff --git a/lib/ReactViews/Map/Splitter.jsx b/lib/ReactViews/Map/Splitter.jsx deleted file mode 100644 index 9031e37bd44..00000000000 --- a/lib/ReactViews/Map/Splitter.jsx +++ /dev/null @@ -1,231 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { withTranslation } from "react-i18next"; -import { GLYPHS, StyledIcon } from "../../Styled/Icon"; -import Styles from "./splitter.scss"; -import { observer } from "mobx-react"; -import { runInAction } from "mobx"; - -// Feature detect support for passive: true in event subscriptions. -// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support -let passiveSupported = false; -try { - const options = Object.defineProperty({}, "passive", { - get: function () { - passiveSupported = true; - return true; - } - }); - - window.addEventListener("test", null, options); - window.removeEventListener("test", null, options); -} catch (err) {} - -const notPassive = passiveSupported ? { passive: false } : false; - -@observer -class Splitter extends React.Component { - static propTypes = { - terria: PropTypes.object.isRequired, - viewState: PropTypes.object.isRequired, - thumbSize: PropTypes.number, - padding: PropTypes.number, - t: PropTypes.func.isRequired - }; - - static defaultProps = { - thumbSize: 42, - padding: 0 - }; - - constructor(props) { - super(props); - this.forceRefresh = this.forceRefresh.bind(this); - this.drag = this.drag.bind(this); - this.startDrag = this.startDrag.bind(this); - this.stopDrag = this.stopDrag.bind(this); - } - - componentDidMount() { - const that = this; - window.addEventListener("resize", function () { - that.forceRefresh(); - }); - } - - componentWillUnmount() { - this.unsubscribe(); - } - - forceRefresh() { - const smallChange = - this.props.terria.splitPosition < 0.5 ? 0.0001 : -0.0001; // Make sure never <0 or >1. - runInAction(() => { - this.props.terria.splitPosition += smallChange; - }); - } - - startDrag(event) { - const viewer = this.props.terria.currentViewer; - viewer.pauseMapInteraction(); - - // While dragging is in progress, subscribe to document-level movement and up events. - document.addEventListener("mousemove", this.drag, notPassive); - document.addEventListener("touchmove", this.drag, notPassive); - document.addEventListener("mouseup", this.stopDrag, notPassive); - document.addEventListener("touchend", this.stopDrag, notPassive); - - event.preventDefault(); - event.stopPropagation(); - } - - drag(event) { - let clientX = event.clientX; - let clientY = event.clientY; - if (event.targetTouches && event.targetTouches.length > 0) { - clientX = event.targetTouches.item(0).clientX; - clientY = event.targetTouches.item(0).clientY; - } - - const viewer = this.props.terria.mainViewer.currentViewer; - const container = viewer.getContainer(); - const mapRect = container.getBoundingClientRect(); - - const that = this; - function computeSplitFraction(startBound, endBound, position) { - const difference = endBound - startBound; - const fraction = (position - startBound) / difference; - - const min = startBound + that.props.padding + that.props.thumbSize * 0.5; - const max = endBound - that.props.padding - that.props.thumbSize * 0.5; - const minFraction = (min - startBound) / difference; - const maxFraction = (max - startBound) / difference; - - return Math.min(maxFraction, Math.max(minFraction, fraction)); - } - let splitFractionX = computeSplitFraction( - mapRect.left, - mapRect.right, - clientX - ); - let splitFractionY = computeSplitFraction( - mapRect.top, - mapRect.bottom, - clientY - ); - - // We compute the maximum and minium windows bounds as a percentage so that we can always apply the bounds - // restriction as a percentage for consistency (we currently use absolute values for X and percentage values for - // Y, but always apply the constraint as a percentage). - // We use absolute pixel values for horizontal restriction because of the fixed UI elements which occupy an - // absolute amount of screen relestate and 100 px seems like a fine amount for the current UI. - const minX = computeSplitFraction( - mapRect.left, - mapRect.right, - mapRect.left + 100 - ); - const maxX = computeSplitFraction( - mapRect.left, - mapRect.right, - mapRect.right - 100 - ); - // Resctrict to within +/-30% of the center vertically (so we don't run into the top and bottom UI elements). - const minY = 0.2; - const maxY = 0.8; - - splitFractionX = Math.min(maxX, Math.max(minX, splitFractionX)); - splitFractionY = Math.min(maxY, Math.max(minY, splitFractionY)); - - runInAction(() => { - this.props.terria.splitPosition = splitFractionX; - this.props.terria.splitPositionVertical = splitFractionY; - }); - - event.preventDefault(); - event.stopPropagation(); - } - - stopDrag(event) { - this.unsubscribe(); - - const viewer = this.props.terria.currentViewer; - // Ensure splitter stays in sync with map - this.props.viewState.triggerResizeEvent(); - - viewer.resumeMapInteraction(); - - event.preventDefault(); - event.stopPropagation(); - } - - unsubscribe() { - document.removeEventListener("mousemove", this.drag, notPassive); - document.removeEventListener("touchmove", this.drag, notPassive); - document.removeEventListener("mouseup", this.stopDrag, notPassive); - document.removeEventListener("touchend", this.stopDrag, notPassive); - window.removeEventListener("resize", this.forceRefresh); - } - - getPosition() { - const canvasWidth = - this.props.terria.currentViewer.getContainer().clientWidth; - const canvasHeight = - this.props.terria.currentViewer.getContainer().clientHeight; - return { - x: this.props.terria.splitPosition * canvasWidth, - y: this.props.terria.splitPositionVertical * canvasHeight - }; - } - - render() { - if ( - !this.props.terria.showSplitter || - !this.props.terria.currentViewer.canShowSplitter || - !this.props.terria.currentViewer.getContainer() - ) { - return null; - } - - const thumbWidth = this.props.thumbSize; - const position = this.getPosition(); - - const dividerStyle = { - left: position.x + "px", - backgroundColor: this.props.terria.baseMapContrastColor - }; - - const thumbStyle = { - left: position.x + "px", - top: position.y + "px", - width: thumbWidth + "px", - height: thumbWidth + "px", - marginLeft: "-" + thumbWidth * 0.5 + "px", - marginTop: "-" + thumbWidth * 0.5 + "px", - lineHeight: thumbWidth - 2 + "px", - borderRadius: thumbWidth * 0.5 + "px", - fontSize: thumbWidth - 12 + "px" - }; - - const { t } = this.props; - - return ( -
-
-
-
- -
- ); - } -} - -module.exports = withTranslation()(Splitter); diff --git a/lib/ReactViews/Map/StoryButton/story-button.scss b/lib/ReactViews/Map/StoryButton/story-button.scss deleted file mode 100644 index 51c17ff0a88..00000000000 --- a/lib/ReactViews/Map/StoryButton/story-button.scss +++ /dev/null @@ -1,13 +0,0 @@ -@import "~terriajs-variables"; - -.storyBtn { - composes: btn from "../../../Sass/common/_buttons.scss"; - composes: btn--map from "../../../Sass/common/_buttons.scss"; - - &:hover, - &:focus { - svg { - fill: #ffffff; - } - } -} diff --git a/lib/ReactViews/Map/TerriaViewerWrapper.jsx b/lib/ReactViews/Map/TerriaViewerWrapper.jsx deleted file mode 100644 index e90d9beb9dc..00000000000 --- a/lib/ReactViews/Map/TerriaViewerWrapper.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { observer } from "mobx-react"; - -import Styles from "./terria-viewer-wrapper.scss"; - -import Splitter from "./Splitter"; -// eslint-disable-next-line no-unused-vars -import TerriaViewer from "../../ViewModels/TerriaViewer"; - -/** - * @typedef {object} Props - * @prop {Terria} terria - * @prop {ViewState} viewState - * - * @extends {React.Component} - */ -@observer -class TerriaViewerWrapper extends React.Component { - static propTypes = { - terria: PropTypes.object.isRequired, - viewState: PropTypes.object.isRequired - }; - - /** - * @argument {HTMLDivElement} container - */ - containerRef = (container) => { - this.props.terria.mainViewer.attached && - this.props.terria.mainViewer.detach(); - if (container !== null) { - this.props.terria.mainViewer.attach(container); - } - }; - - componentWillUnmount() { - this.props.terria.mainViewer.attached && - this.props.terria.mainViewer.detach(); - } - - render() { - return ( - - ); - } -} -module.exports = TerriaViewerWrapper; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx new file mode 100644 index 00000000000..664abf6a569 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/Splitter.tsx @@ -0,0 +1,102 @@ +import { runInAction } from "mobx"; +import { observer } from "mobx-react"; +import React, { FC, useCallback, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useTheme } from "styled-components"; +import Terria from "../../../../Models/Terria"; +import { GLYPHS, StyledIcon } from "../../../../Styled/Icon"; +import { useViewState } from "../../../Context"; +import { useDragHook } from "./dragHook"; + +interface ISplitterProps { + thumbSize?: number; + padding?: number; +} + +export const Splitter: FC = observer( + ({ thumbSize = 42, padding = 0 }) => { + const viewState = useViewState(); + const theme = useTheme(); + const { t } = useTranslation(); + + const { startDrag, dragUnsubscribe } = useDragHook( + viewState, + padding, + thumbSize + ); + + const onResize = useCallback(() => { + const smallChange = + viewState.terria.splitPosition < 0.5 ? 0.0001 : -0.0001; // Make sure never <0 or >1. + runInAction(() => { + viewState.terria.splitPosition += smallChange; + }); + }, [viewState]); + + useEffect(() => { + window.addEventListener("resize", onResize); + return () => { + dragUnsubscribe(); + window.removeEventListener("resize", onResize); + }; + }, [onResize, dragUnsubscribe]); + + if ( + !viewState.terria.showSplitter || + !viewState.terria.currentViewer.canShowSplitter || + !viewState.terria.currentViewer.getContainer() + ) { + return null; + } + + const position = getPosition(viewState.terria); + + return ( +
+
+
+
+ +
+ ); + } +); + +const getPosition = (terria: Terria) => { + const canvasWidth = terria.currentViewer.getContainer()?.clientWidth || 0; + const canvasHeight = terria.currentViewer.getContainer()?.clientHeight || 0; + return { + x: terria.splitPosition * canvasWidth, + y: terria.splitPositionVertical * canvasHeight + }; +}; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts new file mode 100644 index 00000000000..2014e467f34 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/Splitter/dragHook.ts @@ -0,0 +1,166 @@ +import { runInAction } from "mobx"; +import { + MouseEvent as ReactMouseEvent, + TouchEvent as ReactTouchEvent, + useCallback +} from "react"; +import ViewState from "../../../../ReactViewModels/ViewState"; + +// Feature detect support for passive: true in event subscriptions. +// See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support +let passiveSupported = false; +try { + const options = Object.defineProperty({}, "passive", { + get: function () { + passiveSupported = true; + return true; + } + }); + + const callback = () => { + return null; + }; + + window.addEventListener("test", callback, options); + window.removeEventListener("test", callback, options); +} catch (err) {} + +const notPassive = passiveSupported ? { passive: false } : false; + +export const useDragHook = ( + viewState: ViewState, + padding: number, + thumbSize: number +) => { + const drag = useCallback( + (e: MouseEvent | TouchEvent) => { + let clientX: number | undefined = undefined; + let clientY: number | undefined = undefined; + if (e instanceof MouseEvent) { + clientX = e.clientX; + clientY = e.clientY; + } else { + if (e.targetTouches && e.targetTouches.length > 0) { + clientX = e.targetTouches.item(0)?.clientX; + clientY = e.targetTouches.item(0)?.clientY; + } + } + if (!clientX || !clientY) return; + + const viewer = viewState.terria.mainViewer.currentViewer; + const container = viewer.getContainer(); + const mapRect = container?.getBoundingClientRect(); + if (!mapRect) return; + + let splitFractionX = computeSplitFraction( + mapRect.left, + mapRect.right, + clientX, + padding, + thumbSize + ); + let splitFractionY = computeSplitFraction( + mapRect.top, + mapRect.bottom, + clientY, + padding, + thumbSize + ); + + // We compute the maximum and minium windows bounds as a percentage so that we can always apply the bounds + // restriction as a percentage for consistency (we currently use absolute values for X and percentage values for + // Y, but always apply the constraint as a percentage). + // We use absolute pixel values for horizontal restriction because of the fixed UI elements which occupy an + // absolute amount of screen relestate and 100 px seems like a fine amount for the current UI. + const minX = computeSplitFraction( + mapRect.left, + mapRect.right, + mapRect.left + 100, + padding, + thumbSize + ); + const maxX = computeSplitFraction( + mapRect.left, + mapRect.right, + mapRect.right - 100, + padding, + thumbSize + ); + // Resctrict to within +/-30% of the center vertically (so we don't run into the top and bottom UI elements). + const minY = 0.2; + const maxY = 0.8; + + splitFractionX = Math.min(maxX, Math.max(minX, splitFractionX)); + splitFractionY = Math.min(maxY, Math.max(minY, splitFractionY)); + + runInAction(() => { + viewState.terria.splitPosition = splitFractionX; + viewState.terria.splitPositionVertical = splitFractionY; + }); + + e.preventDefault(); + e.stopPropagation(); + }, + [viewState] + ); + + const stopDrag = useCallback( + (e: Event) => { + dragUnsubscribe(); + + const viewer = viewState.terria.currentViewer; + // Ensure splitter stays in sync with map + viewState.triggerResizeEvent(); + + viewer.resumeMapInteraction(); + + e.preventDefault(); + e.stopPropagation(); + }, + [viewState] + ); + + const startDrag = useCallback( + (e: ReactMouseEvent | ReactTouchEvent | undefined) => { + const viewer = viewState.terria.currentViewer; + viewer.pauseMapInteraction(); + + // While dragging is in progress, subscribe to document-level movement and up events. + document.addEventListener("mousemove", drag, notPassive); + document.addEventListener("touchmove", drag, notPassive); + document.addEventListener("mouseup", stopDrag, notPassive); + document.addEventListener("touchend", stopDrag, notPassive); + + e?.preventDefault(); + e?.stopPropagation(); + }, + [drag, stopDrag, viewState] + ); + + const dragUnsubscribe = useCallback(() => { + document.removeEventListener("mousemove", drag, notPassive as never); + document.removeEventListener("touchmove", drag, notPassive as never); + document.removeEventListener("mouseup", stopDrag, notPassive as never); + document.removeEventListener("touchend", stopDrag, notPassive as never); + }, [drag, stopDrag]); + + return { startDrag, dragUnsubscribe }; +}; + +function computeSplitFraction( + startBound: number, + endBound: number, + position: number, + padding: number, + thumbSize: number +) { + const difference = endBound - startBound; + const fraction = (position - startBound) / difference; + + const min = startBound + padding + thumbSize * 0.5; + const max = endBound - padding - thumbSize * 0.5; + const minFraction = (min - startBound) / difference; + const maxFraction = (max - startBound) / difference; + + return Math.min(maxFraction, Math.max(minFraction, fraction)); +} diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx b/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx new file mode 100644 index 00000000000..b66aa1f51ed --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/TerriaViewerWrapper.tsx @@ -0,0 +1,84 @@ +import React, { FC, useEffect, useRef } from "react"; + +import { Splitter } from "./Splitter/Splitter"; +import { useViewState } from "../../Context"; +import styled from "styled-components"; + +export const TerriaViewerWrapper: FC = () => { + const viewState = useViewState(); + const containerRef = useRef(null); + + useEffect(() => { + if (viewState.terria.mainViewer.attached) { + viewState.terria.mainViewer.detach(); + } + if (containerRef.current) { + viewState.terria.mainViewer.attach(containerRef.current); + } + + return () => { + viewState.terria.mainViewer.detach(); + }; + }, [viewState]); + + return ( + + + Loading the map, please wait... + + +
+ + ); +}; + +const TerrriaViewerContainer = styled.aside` + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; +`; + +const StyledMapPlaceholder = styled.div` + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + color: black; + text-align: center; + width: 100%; + height: 25%; + margin: auto; + @media (min-width: ${(p) => p.theme.sm}px) { + color: white; + } +`; diff --git a/lib/ReactViews/Map/TerriaViewerWrapper/index.ts b/lib/ReactViews/Map/TerriaViewerWrapper/index.ts new file mode 100644 index 00000000000..fb3377a1c87 --- /dev/null +++ b/lib/ReactViews/Map/TerriaViewerWrapper/index.ts @@ -0,0 +1 @@ +export { TerriaViewerWrapper } from "./TerriaViewerWrapper"; diff --git a/lib/ReactViews/StandardUserInterface/Toast.tsx b/lib/ReactViews/Map/Toast.tsx similarity index 100% rename from lib/ReactViews/StandardUserInterface/Toast.tsx rename to lib/ReactViews/Map/Toast.tsx diff --git a/lib/ReactViews/Map/experimental-features.scss b/lib/ReactViews/Map/experimental-features.scss deleted file mode 100644 index c9a98d01566..00000000000 --- a/lib/ReactViews/Map/experimental-features.scss +++ /dev/null @@ -1,22 +0,0 @@ -@import "~terriajs-variables"; - -.experimental-features { - position: absolute; - left: 25px; - bottom: 25px; - z-index: 1; - - @media (min-width: $sm) { - top: auto; - bottom: 100px; - } -} - -.control { - margin: 15px 0; - text-align: center; - - &:last-child { - margin-bottom: 0; - } -} diff --git a/lib/ReactViews/Map/experimental-features.scss.d.ts b/lib/ReactViews/Map/experimental-features.scss.d.ts deleted file mode 100644 index d84db085ee8..00000000000 --- a/lib/ReactViews/Map/experimental-features.scss.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'control': string; - 'experimental-features': string; - 'experimentalFeatures': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/progress-bar.scss b/lib/ReactViews/Map/progress-bar.scss deleted file mode 100644 index 7e05acb098d..00000000000 --- a/lib/ReactViews/Map/progress-bar.scss +++ /dev/null @@ -1,31 +0,0 @@ -.progress-bar { - z-index: 1; - position: absolute; - top: 0; - left: 0; - height: 5px; - overflow: hidden; - transition: opacity 200ms linear, width 200ms linear, visibility 400ms linear; -} - -.complete { - visibility: hidden; -} - -.indeterminate-bar-animated { - width: 100%; - animation: indeterminateAnimation 1.2s infinite linear; - transform-origin: 0% 50%; -} - -@keyframes indeterminateAnimation { - 0% { - transform: translateX(0) scaleX(0); - } - 40% { - transform: translateX(0) scaleX(0.4); - } - 100% { - transform: translateX(100%) scaleX(0.5); - } -} diff --git a/lib/ReactViews/Map/progress-bar.scss.d.ts b/lib/ReactViews/Map/progress-bar.scss.d.ts deleted file mode 100644 index ae6c7a6c853..00000000000 --- a/lib/ReactViews/Map/progress-bar.scss.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'complete': string; - 'indeterminate-bar-animated': string; - 'indeterminateAnimation': string; - 'indeterminateBarAnimated': string; - 'progress-bar': string; - 'progressBar': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/splitter.scss b/lib/ReactViews/Map/splitter.scss deleted file mode 100644 index 9849d3c22d8..00000000000 --- a/lib/ReactViews/Map/splitter.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "~terriajs-variables"; - -.divider-wrapper { - position: absolute; - width: 100%; - height: 100%; -} - -.divider { - position: absolute; - top: 0; - bottom: 0; - left: 50%; - width: 1px; - background-color: #fff; - pointer-events: none; - z-index: 999; -} - -.thumb { - position: absolute; - width: 40px; - height: 40px; - border-radius: 20px; - border: 1px solid lightgrey; - text-align: center; - line-height: 38px; - left: 50%; - top: 50%; - font-size: 28px; - font-family: monospace; - background-color: white; - color: grey; - margin-top: -20px; - margin-left: -20px; - z-index: 999; - padding: 8px; - cursor: ew-resize; - svg { - fill: #000; - } -} diff --git a/lib/ReactViews/Map/splitter.scss.d.ts b/lib/ReactViews/Map/splitter.scss.d.ts deleted file mode 100644 index e6984139b8c..00000000000 --- a/lib/ReactViews/Map/splitter.scss.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'divider': string; - 'divider-wrapper': string; - 'dividerWrapper': string; - 'thumb': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Map/terria-viewer-wrapper.scss b/lib/ReactViews/Map/terria-viewer-wrapper.scss deleted file mode 100644 index 21961915fee..00000000000 --- a/lib/ReactViews/Map/terria-viewer-wrapper.scss +++ /dev/null @@ -1,57 +0,0 @@ -@import "~terriajs-variables"; -@import "../../Sass/common/mixins"; - -.container { - top: 0; - right: 0; - bottom: 0; - left: 0; - position: absolute; -} - -.cesium-container { - top: 0; - right: 0; - bottom: 0; - left: 0; - position: absolute; - cursor: auto; - - :global { - .selection-indicator { - pointer-events: none; - position: absolute; - width: 50px; - height: 50px; - } - - #terriaLogoWrapper { - display: inline-block; - } - - .cesium-widget, - .cesium-widget canvas { - position: absolute; - width: 100%; - height: 100%; - touch-action: none; - } - } -} - -.mapPlaceholder { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - color: black; - text-align: center; - width: 100%; - height: 25%; - margin: auto; - - @media (min-width: $sm) { - color: white; - } -} diff --git a/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts b/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts deleted file mode 100644 index 8f5c50b26cb..00000000000 --- a/lib/ReactViews/Map/terria-viewer-wrapper.scss.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'cesium-container': string; - 'cesiumContainer': string; - 'container': string; - 'mapPlaceholder': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Mobile/MobileHeader.jsx b/lib/ReactViews/Mobile/MobileHeader.jsx index f0858d21f14..63800fa92a2 100644 --- a/lib/ReactViews/Mobile/MobileHeader.jsx +++ b/lib/ReactViews/Mobile/MobileHeader.jsx @@ -11,7 +11,7 @@ import { RawButton } from "../../Styled/Button"; import Icon, { StyledIcon } from "../../Styled/Icon"; import SearchBox from "../Search/SearchBox"; import Branding from "../SidePanel/Branding"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./mobile-header.scss"; import MobileMenu from "./MobileMenu"; import MobileModalWindow from "./MobileModalWindow"; @@ -260,7 +260,6 @@ class MobileHeader extends React.Component { menuItems={this.props.menuItems} menuLeftItems={this.props.menuLeftItems} viewState={this.props.viewState} - allBaseMaps={this.props.allBaseMaps} terria={this.props.viewState.terria} showFeedback={ !!this.props.viewState.terria.configParameters.feedbackUrl @@ -300,7 +299,6 @@ const HamburgerButton = styled(RawButton)` MobileHeader.propTypes = { viewState: PropTypes.object.isRequired, - allBaseMaps: PropTypes.array, version: PropTypes.string, menuLeftItems: PropTypes.array, menuItems: PropTypes.array, diff --git a/lib/ReactViews/Notification/MapInteractionWindow.tsx b/lib/ReactViews/Notification/MapInteractionWindow.tsx index 75aa172fba1..4c476613ab8 100644 --- a/lib/ReactViews/Notification/MapInteractionWindow.tsx +++ b/lib/ReactViews/Notification/MapInteractionWindow.tsx @@ -10,7 +10,7 @@ import isDefined from "../../Core/isDefined"; import MapInteractionMode, { UIMode } from "../../Models/MapInteractionMode"; import ViewState from "../../ReactViewModels/ViewState"; import parseCustomHtmlToReact from "../Custom/parseCustomHtmlToReact"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./map-interaction-window.scss"; const MapInteractionWindowWrapper = styled.div<{ isDiffTool: boolean }>` diff --git a/lib/ReactViews/Notification/Notification.tsx b/lib/ReactViews/Notification/Notification.tsx index bf33f2c27b3..4b7e597d1bc 100644 --- a/lib/ReactViews/Notification/Notification.tsx +++ b/lib/ReactViews/Notification/Notification.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; import React from "react"; import triggerResize from "../../Core/triggerResize"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; // Avoid type error caused by importing untyped jsx const NotificationWindow = require("./NotificationWindow").default; diff --git a/lib/ReactViews/RelatedMaps/RelatedMaps.tsx b/lib/ReactViews/RelatedMaps/RelatedMaps.tsx index 8464d3490e9..2194252874a 100644 --- a/lib/ReactViews/RelatedMaps/RelatedMaps.tsx +++ b/lib/ReactViews/RelatedMaps/RelatedMaps.tsx @@ -6,10 +6,7 @@ import { RelatedMap } from "../../Models/RelatedMaps"; import Box from "../../Styled/Box"; import { ExternalLinkIcon } from "../Custom/ExternalLink"; import parseCustomMarkdownToReact from "../Custom/parseCustomMarkdownToReact"; -import { - withViewState, - WithViewState -} from "../StandardUserInterface/ViewStateContext"; +import { withViewState, WithViewState } from "../Context"; import Styles from "./related-maps.scss"; const MenuPanel = diff --git a/lib/ReactViews/SidePanel/Branding.tsx b/lib/ReactViews/SidePanel/Branding.tsx index 8e2b6fdda03..705f90549e3 100644 --- a/lib/ReactViews/SidePanel/Branding.tsx +++ b/lib/ReactViews/SidePanel/Branding.tsx @@ -4,7 +4,7 @@ import React from "react"; import isDefined from "../../Core/isDefined"; import ViewState from "../../ReactViewModels/ViewState"; import parseCustomHtmlToReact from "../Custom/parseCustomHtmlToReact"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; const DEFAULT_BRANDING = ''; diff --git a/lib/ReactViews/SidePanel/FullScreenButton.jsx b/lib/ReactViews/SidePanel/FullScreenButton.jsx index 7bff73db311..5f43f8e8f10 100644 --- a/lib/ReactViews/SidePanel/FullScreenButton.jsx +++ b/lib/ReactViews/SidePanel/FullScreenButton.jsx @@ -7,7 +7,7 @@ import { withTranslation } from "react-i18next"; import { Category, ViewAction } from "../../Core/AnalyticEvents/analyticEvents"; import Icon from "../../Styled/Icon"; import withControlledVisibility from "../HOCs/withControlledVisibility"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Styles from "./full_screen_button.scss"; // The button to make the map full screen and hide the workbench. diff --git a/lib/ReactViews/SidePanel/SidePanel.tsx b/lib/ReactViews/SidePanel/SidePanel.tsx index ff3aefd9e14..58c06eaa18e 100644 --- a/lib/ReactViews/SidePanel/SidePanel.tsx +++ b/lib/ReactViews/SidePanel/SidePanel.tsx @@ -11,17 +11,21 @@ import Text from "../../Styled/Text"; import { ExplorerWindowElementName } from "../ExplorerWindow/ExplorerWindow"; import { useRefForTerria } from "../Hooks/useRefForTerria"; import SearchBoxAndResults from "../Search/SearchBoxAndResults"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import Workbench from "../Workbench/Workbench"; const BoxHelpfulHints = styled(Box)``; const ResponsiveSpacing = styled(Box)` + height: 110px; height: 110px; // Hardcoded px value, TODO: make it not hardcoded @media (max-height: 700px) { height: 3vh; } + @media (max-height: 700px) { + height: 3vh; + } `; const HelpfulHintsIcon = () => { diff --git a/lib/ReactViews/Map/ExperimentalFeatures.tsx b/lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx similarity index 91% rename from lib/ReactViews/Map/ExperimentalFeatures.tsx rename to lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx index 4c897f61895..e16194b3861 100644 --- a/lib/ReactViews/Map/ExperimentalFeatures.tsx +++ b/lib/ReactViews/StandardUserInterface/ExperimentalFeatures.tsx @@ -1,7 +1,7 @@ import React from "react"; import styled from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; interface IProps { viewState: ViewState; @@ -13,7 +13,6 @@ const ControlsWrapper = styled.div` left: 25px; bottom: 25px; z-index: 1; - @media (min-width: ${(props) => props.theme.sm}px) { top: auto; bottom: 100px; @@ -22,7 +21,6 @@ const ControlsWrapper = styled.div` const Control = styled.div` margin: 15px 0; text-align: center; - &:last-child { margin-bottom: 0; } diff --git a/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts b/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts index 8ed3aa75bb5..556bf96b116 100644 --- a/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts +++ b/lib/ReactViews/StandardUserInterface/GlobalTerriaStyles.ts @@ -67,4 +67,19 @@ body { button { cursor: pointer; } + +.selection-indicator { + pointer-events: none; + position: absolute; + width: 50px; + height: 50px; +} + +.cesium-widget, +.cesium-widget canvas { + position: absolute; + width: 100%; + height: 100%; + touch-action: none; +} `; diff --git a/lib/ReactViews/StandardUserInterface/MapColumn.jsx b/lib/ReactViews/StandardUserInterface/MapColumn.jsx deleted file mode 100644 index 1a7411ba12e..00000000000 --- a/lib/ReactViews/StandardUserInterface/MapColumn.jsx +++ /dev/null @@ -1,215 +0,0 @@ -import classNames from "classnames"; -import { observer } from "mobx-react"; -import PropTypes from "prop-types"; -import React from "react"; -import { withTranslation } from "react-i18next"; -import FeatureDetection from "terriajs-cesium/Source/Core/FeatureDetection"; -import ActionBarPortal from "../ActionBar/ActionBarPortal"; -import BottomDock from "../BottomDock/BottomDock"; -import { MapCredits } from "../Credits"; -import Loader from "../Loader"; -import BottomLeftBar from "../Map/BottomLeftBar/BottomLeftBar"; -import DistanceLegend from "../Map/Legend/DistanceLegend"; -import LocationBar from "../Map/Legend/LocationBar"; -import MenuBar from "../Map/MenuBar"; -import MapNavigation from "../Map/Navigation/MapNavigation"; -import TerriaViewerWrapper from "../Map/TerriaViewerWrapper"; -import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; -import Styles from "./map-column.scss"; -import Toast from "./Toast"; -import { withViewState } from "./ViewStateContext"; - -const chromeVersion = FeatureDetection.chromeVersion(); - -/** - * Right-hand column that contains the map, controls that sit over the map and sometimes the bottom dock containing - * the timeline and charts. - */ -@observer -class MapColumn extends React.Component { - static propTypes = { - viewState: PropTypes.object.isRequired, - customFeedbacks: PropTypes.array.isRequired, - allBaseMaps: PropTypes.array.isRequired, - animationDuration: PropTypes.number.isRequired, - customElements: PropTypes.object.isRequired, - t: PropTypes.func.isRequired - }; - - constructor(props) { - super(props); - this.state = {}; - } - - render() { - const { customElements } = this.props; - const { t } = this.props; - // TODO: remove? see: https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 - const isAboveChrome75 = - chromeVersion && chromeVersion[0] && Number(chromeVersion[0]) > 75; - const mapCellClass = classNames(Styles.mapCell, { - [Styles.mapCellChrome]: isAboveChrome75 - }); - return ( -
-
-
- -
- - -
-
-
- -
- - - - - - - - - -
- - -
-
- {/* TODO: re-implement/support custom feedbacks */} - {/* -
- -
-
*/} - - - -
{feedbackItem}
-
-
-
- - - -
- -
-
- -
-
-
-
- ); - } -} - -export default withTranslation()(withViewState(MapColumn)); diff --git a/lib/ReactViews/StandardUserInterface/Portal.tsx b/lib/ReactViews/StandardUserInterface/Portal.tsx index 5ee53a4e75e..e492c2274f8 100644 --- a/lib/ReactViews/StandardUserInterface/Portal.tsx +++ b/lib/ReactViews/StandardUserInterface/Portal.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import React, { useEffect } from "react"; import ReactDOM from "react-dom"; import ViewState from "../../ReactViewModels/ViewState"; -import { useViewState } from "./ViewStateContext"; +import { useViewState } from "../Context"; type PortalProps = { /** diff --git a/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx b/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx index 582810e0b12..e78d7c1eeb1 100644 --- a/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx +++ b/lib/ReactViews/StandardUserInterface/SidePanelContainer.tsx @@ -1,7 +1,7 @@ import { action } from "mobx"; import styled from "styled-components"; import ViewState from "../../ReactViewModels/ViewState"; -import { withViewState } from "./ViewStateContext"; +import { withViewState } from "../Context"; type PropsType = { viewState: ViewState; diff --git a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx index 17d3e476174..11571f4e972 100644 --- a/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx +++ b/lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx @@ -17,12 +17,11 @@ import FeedbackForm from "../Feedback/FeedbackForm"; import { Medium, Small } from "../Generic/Responsive"; import SatelliteHelpPrompt from "../HelpScreens/SatelliteHelpPrompt"; import withFallback from "../HOCs/withFallback"; -import ExperimentalFeatures from "../Map/ExperimentalFeatures"; -import CollapsedNavigation from "../Map/Navigation/Items/OverflowNavigationItem"; +import ExperimentalFeatures from "./ExperimentalFeatures"; +import { CollapsedNavigation } from "../Map/MapNavigation"; import HelpPanel from "../Map/Panels/HelpPanel/HelpPanel"; import PrintView from "../Map/Panels/SharePanel/Print/PrintView"; -import ProgressBar from "../Map/ProgressBar"; -import TrainerBar from "../Map/TrainerBar/TrainerBar"; +import TrainerBar from "./TrainerBar/TrainerBar"; import MobileHeader from "../Mobile/MobileHeader"; import MapInteractionWindow from "../Notification/MapInteractionWindow"; import Notification from "../Notification/Notification"; @@ -35,9 +34,9 @@ import Tool from "../Tools/Tool"; import TourPortal from "../Tour/TourPortal"; import WelcomeMessage from "../WelcomeMessage/WelcomeMessage"; import SelectableDimensionWorkflow from "../Workflow/SelectableDimensionWorkflow"; -import ContextProviders from "./ContextProviders"; +import { ContextProviders } from "../Context"; import { GlobalTerriaStyles } from "./GlobalTerriaStyles"; -import MapColumn from "./MapColumn"; +import MapColumn from "../Map/MapColumn"; import processCustomElements from "./processCustomElements"; import SidePanelContainer from "./SidePanelContainer"; import Styles from "./standard-user-interface.scss"; @@ -49,15 +48,14 @@ export const animationDuration = 250; interface StandardUserInterfaceProps { terria: ViewState["terria"]; viewState: ViewState; - allBaseMaps?: any[]; themeOverrides?: Partial; minimumLargeScreenWidth?: number; version: string; children?: ReactNode; } -const StandardUserInterface: React.FC = observer( - (props) => { +const StandardUserInterfaceBase: React.FC = + observer((props) => { const { t } = useTranslation(); const acceptDragDropFile = action(() => { @@ -135,7 +133,6 @@ const StandardUserInterface: React.FC = observer( ); const terria = props.terria; - const allBaseMaps = props.allBaseMaps; const showStoryBuilder = props.viewState.storyBuilderShown && @@ -178,7 +175,6 @@ const StandardUserInterface: React.FC = observer( menuItems={customElements.menu} menuLeftItems={customElements.menuLeft} version={props.version} - allBaseMaps={allBaseMaps} /> @@ -228,11 +224,9 @@ const StandardUserInterface: React.FC = observer(
-
@@ -308,7 +302,7 @@ const StandardUserInterface: React.FC = observer( )} ); - } -); + }); -export default withFallback(StandardUserInterface); +export const StandardUserInterface = withFallback(StandardUserInterfaceBase); +export default withFallback(StandardUserInterfaceBase); diff --git a/lib/ReactViews/Map/TrainerBar/TrainerBar.tsx b/lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx similarity index 99% rename from lib/ReactViews/Map/TrainerBar/TrainerBar.tsx rename to lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx index f2ed5ad2ca3..3794c229355 100644 --- a/lib/ReactViews/Map/TrainerBar/TrainerBar.tsx +++ b/lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar.tsx @@ -17,10 +17,7 @@ import Select from "../../../Styled/Select"; import Spacing from "../../../Styled/Spacing"; import Text, { TextSpan } from "../../../Styled/Text"; import measureElement, { MeasureElementProps } from "../../HOCs/measureElement"; -import { - WithViewState, - withViewState -} from "../../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../../Context"; import { applyTranslationIfExists } from "./../../../Language/languageHelpers"; const StyledHtml: any = diff --git a/lib/ReactViews/Map/MenuButton.jsx b/lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx similarity index 95% rename from lib/ReactViews/Map/MenuButton.jsx rename to lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx index 52395c1ec2b..626bac2eacf 100644 --- a/lib/ReactViews/Map/MenuButton.jsx +++ b/lib/ReactViews/StandardUserInterface/customizable/MenuButton.jsx @@ -1,6 +1,6 @@ import React from "react"; import classNames from "classnames"; -import Icon from "../../Styled/Icon"; +import Icon from "../../../Styled/Icon"; import PropTypes from "prop-types"; import Styles from "./menu-button.scss"; diff --git a/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx b/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx index 9a8f1aaf321..897122345f0 100644 --- a/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx +++ b/lib/ReactViews/StandardUserInterface/customizable/MenuItem.jsx @@ -1,4 +1,4 @@ -import MenuButton from "../../Map/MenuButton"; +import MenuButton from "./MenuButton"; import responsiveSwitch from "./ResponsiveSwitch"; import withControlledVisibility from "../../HOCs/withControlledVisibility"; import MobileMenuItem from "../../Mobile/MobileMenuItem"; diff --git a/lib/ReactViews/Map/menu-button.scss b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss similarity index 74% rename from lib/ReactViews/Map/menu-button.scss rename to lib/ReactViews/StandardUserInterface/customizable/menu-button.scss index eac534aec5d..b35fa5b3397 100644 --- a/lib/ReactViews/Map/menu-button.scss +++ b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss @@ -1,8 +1,8 @@ @import "~terriajs-variables"; .btn--about-link { - composes: btn from "../../Sass/common/_buttons.scss"; - composes: btn--map from "../../Sass/common/_buttons.scss"; + composes: btn from "../../../Sass/common/_buttons.scss"; + composes: btn--map from "../../../Sass/common/_buttons.scss"; border-radius: $radius-small; border: 0; svg { diff --git a/lib/ReactViews/Map/menu-button.scss.d.ts b/lib/ReactViews/StandardUserInterface/customizable/menu-button.scss.d.ts similarity index 100% rename from lib/ReactViews/Map/menu-button.scss.d.ts rename to lib/ReactViews/StandardUserInterface/customizable/menu-button.scss.d.ts diff --git a/lib/ReactViews/StandardUserInterface/index.ts b/lib/ReactViews/StandardUserInterface/index.ts new file mode 100644 index 00000000000..f0f63b85c00 --- /dev/null +++ b/lib/ReactViews/StandardUserInterface/index.ts @@ -0,0 +1,5 @@ +export { + StandardUserInterface, + StandardUserInterface as default +} from "./StandardUserInterface"; +export { terriaTheme } from "./StandardTheme"; diff --git a/lib/ReactViews/StandardUserInterface/map-column.scss b/lib/ReactViews/StandardUserInterface/map-column.scss deleted file mode 100644 index 93bf7fa4475..00000000000 --- a/lib/ReactViews/StandardUserInterface/map-column.scss +++ /dev/null @@ -1,99 +0,0 @@ -@import "~terriajs-variables"; -@import "../../Sass/common/mixins"; - -.map__inner { - display: table; - width: 100%; - height: 100%; - - * { - box-sizing: border-box; - } -} -.map__innerChrome { - // Chrome only :( hack until - // https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 gets resolved - display: flex; - flex-flow: column; -} - -.map__row { - display: table-row; - - &:first-child { - height: 100%; - position: relative; - } -} - -.map__cell { - display: table-cell; - position: relative; - width: 100%; -} -.map__cellChrome { - // Chrome only :( hack until - // https://bugs.chromium.org/p/chromium/issues/detail?id=1001663 gets resolved - display: block; - height: 100%; -} - -@include empty-module("map-cell-map"); - -.map-wrapper { - position: absolute; - top: 0; - width: 100%; - z-index: 0; -} - -@include empty-module("feedback"); - -.location-distance { - composes: clearfix from "../../Sass/common/_base.scss"; - display: none; - @media (min-width: $sm) { - display: block; - } - position: absolute; - bottom: 2px; - right: 3px; - z-index: 1; -} - -.feedback-button-wrapper { - @media (min-width: $sm) { - bottom: 100px; - right: $padding * 2; - margin: 0; - } - - @media (max-width: $mobile) { - position: fixed; - } - position: absolute; - z-index: 0; - bottom: 25px; - right: 16px; - margin: 4px 0; -} - -.with-time-series-controls { - bottom: 58px; - - @media (max-width: $mobile) { - bottom: $mobile-bottom-timeline; - } -} - -.print-disclaimer { - display: none; -} - -@media print { - .print-disclaimer { - display: block; - width: 100%; - clear: both; - } -} diff --git a/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts b/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts deleted file mode 100644 index 8f9308b3b49..00000000000 --- a/lib/ReactViews/StandardUserInterface/map-column.scss.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -// This file is automatically generated. -// Please do not change this file! -interface CssExports { - 'feedback': string; - 'feedback-button-wrapper': string; - 'feedbackButtonWrapper': string; - 'location-distance': string; - 'locationDistance': string; - 'map-cell-map': string; - 'map-wrapper': string; - 'mapCell': string; - 'mapCellChrome': string; - 'mapCellMap': string; - 'mapInner': string; - 'mapInnerChrome': string; - 'mapRow': string; - 'mapWrapper': string; - 'map__cell': string; - 'map__cellChrome': string; - 'map__inner': string; - 'map__innerChrome': string; - 'map__row': string; - 'print-disclaimer': string; - 'printDisclaimer': string; - 'with-time-series-controls': string; - 'withTimeSeriesControls': string; -} -declare var cssExports: CssExports; -export = cssExports; diff --git a/lib/ReactViews/Story/StoryBuilder.tsx b/lib/ReactViews/Story/StoryBuilder.tsx index 4797adccf6e..4525fcb2eee 100644 --- a/lib/ReactViews/Story/StoryBuilder.tsx +++ b/lib/ReactViews/Story/StoryBuilder.tsx @@ -27,10 +27,7 @@ import measureElement, { MeasureElementProps } from "../HOCs/measureElement"; import VideoGuide from "../Map/Panels/HelpPanel/VideoGuide"; import { getShareData } from "../Map/Panels/SharePanel/BuildShareLink"; import SharePanel from "../Map/Panels/SharePanel/SharePanel"; -import { - WithViewState, - withViewState -} from "../StandardUserInterface/ViewStateContext"; +import { WithViewState, withViewState } from "../Context"; import Story from "./Story"; import Styles from "./story-builder.scss"; import StoryEditor from "./StoryEditor.jsx"; diff --git a/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx b/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx index 68c6c48b3b6..ee891ed530d 100644 --- a/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx +++ b/lib/ReactViews/Story/StoryPanel/StoryPanel.tsx @@ -15,11 +15,8 @@ import TerriaError from "../../../Core/TerriaError"; import Terria from "../../../Models/Terria"; import Box from "../../../Styled/Box"; import Hr from "../../../Styled/Hr"; -import { onStoryButtonClick } from "../../Map/StoryButton/StoryButton"; -import { - WithViewState, - withViewState -} from "../../StandardUserInterface/ViewStateContext"; +import { onStoryButtonClick } from "../../Map/MenuBar/StoryButton/StoryButton"; +import { WithViewState, withViewState } from "../../Context"; import { Story } from "../Story"; import Styles from "../story-panel.scss"; import StoryBody from "./StoryBody"; diff --git a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx index 60ad3919660..04ad26a0218 100644 --- a/lib/ReactViews/Tools/DiffTool/DiffTool.tsx +++ b/lib/ReactViews/Tools/DiffTool/DiffTool.tsx @@ -51,7 +51,7 @@ import { GLYPHS, StyledIcon } from "../../../Styled/Icon"; import Loader from "../../Loader"; import DatePicker from "./DatePicker"; import LocationPicker from "./LocationPicker"; -import { CLOSE_TOOL_ID } from "../../Map/Navigation/registerMapNavigations"; +import { CLOSE_TOOL_ID } from "../../Map/MapNavigation/registerMapNavigations"; const dateFormat = require("dateformat"); @@ -843,7 +843,6 @@ const CloseDifferenceButton = styled(Button)` left: 50%; transform: translateX(-50%); top: 18px; - padding: 0 20px; `; diff --git a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx index f48dd76fb61..5d020221363 100644 --- a/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx +++ b/lib/ReactViews/Tools/PedestrianMode/PedestrianMode.tsx @@ -8,7 +8,7 @@ import PositionRightOfWorkbench from "../../Workbench/PositionRightOfWorkbench"; import DropPedestrianToGround from "./DropPedestrianToGround"; import MiniMap, { getViewFromScene, MiniMapView } from "./MiniMap"; import MovementControls from "./MovementControls"; -import MeasureTool from "../../Map/Navigation/Items/MeasureTool"; +import { MeasureTool } from "../../Map/MapNavigation/Items"; // The desired camera height measured from the surface in metres export const PEDESTRIAN_HEIGHT = 1.7; diff --git a/lib/ReactViews/Tools/Tool.tsx b/lib/ReactViews/Tools/Tool.tsx index 62bb2ba6824..665747b4ec0 100644 --- a/lib/ReactViews/Tools/Tool.tsx +++ b/lib/ReactViews/Tools/Tool.tsx @@ -11,7 +11,7 @@ import Terria from "../../Models/Terria"; import ViewerMode from "../../Models/ViewerMode"; import ViewState from "../../ReactViewModels/ViewState"; import MapNavigationItemController from "../../ViewModels/MapNavigation/MapNavigationItemController"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; interface ToolProps { toolName: string; diff --git a/lib/ReactViews/Tour/TourPortal.jsx b/lib/ReactViews/Tour/TourPortal.jsx index 6fa9c3785bb..d7a45815329 100644 --- a/lib/ReactViews/Tour/TourPortal.jsx +++ b/lib/ReactViews/Tour/TourPortal.jsx @@ -23,7 +23,7 @@ import { parseCustomMarkdownToReactWithOptions } from "../Custom/parseCustomMark import Caret from "../Generic/Caret"; import CloseButton from "../Generic/CloseButton"; import { useWindowSize } from "../Hooks/useWindowSize"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { applyTranslationIfExists } from "./../../Language/languageHelpers"; import { calculateLeftPosition, diff --git a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx index 5cc78d90fa4..5ef747bb44f 100644 --- a/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx +++ b/lib/ReactViews/WelcomeMessage/WelcomeMessage.jsx @@ -12,7 +12,7 @@ import Text, { TextSpan } from "../../Styled/Text"; import { ExplorerWindowElementName } from "../ExplorerWindow/ExplorerWindow"; import { useKeyPress } from "../Hooks/useKeyPress.js"; import VideoGuide from "../Map/Panels/HelpPanel/VideoGuide"; -import { withViewState } from "../StandardUserInterface/ViewStateContext"; +import { withViewState } from "../Context"; import { TourPortalDisplayName } from "../Tour/TourPortal"; import FadeIn from "../Transitions/FadeIn/FadeIn"; import SlideUpFadeIn from "../Transitions/SlideUpFadeIn/SlideUpFadeIn"; diff --git a/lib/ReactViews/Map/Panels/TerrainSide.tsx b/lib/ReactViews/Workbench/TerrainSide.tsx similarity index 92% rename from lib/ReactViews/Map/Panels/TerrainSide.tsx rename to lib/ReactViews/Workbench/TerrainSide.tsx index d28ca65917a..b2191b56413 100644 --- a/lib/ReactViews/Map/Panels/TerrainSide.tsx +++ b/lib/ReactViews/Workbench/TerrainSide.tsx @@ -4,13 +4,13 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { useTheme } from "styled-components"; import SplitDirection from "terriajs-cesium/Source/Scene/SplitDirection"; -import Terria from "../../../Models/Terria"; -import ViewerMode from "../../../Models/ViewerMode"; -import Box from "../../../Styled/Box"; -import Checkbox from "../../../Styled/Checkbox/Checkbox"; -import { TextSpan } from "../../../Styled/Text"; -import { RawButton } from "./../../../Styled/Button"; -import { Spacing } from "./../../../Styled/Spacing"; +import Terria from "../../Models/Terria"; +import ViewerMode from "../../Models/ViewerMode"; +import Box from "../../Styled/Box"; +import Checkbox from "../../Styled/Checkbox/Checkbox"; +import { TextSpan } from "../../Styled/Text"; +import { RawButton } from "../../Styled/Button"; +import { Spacing } from "../../Styled/Spacing"; const sides = { left: "settingPanel.terrain.left", diff --git a/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx b/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx index 924354e1d26..578aa8528f2 100644 --- a/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx +++ b/lib/ReactViews/Workbench/WorkbenchSplitScreen.tsx @@ -11,7 +11,7 @@ import Box from "../../Styled/Box"; import { RawButton } from "../../Styled/Button"; import { GLYPHS, StyledIcon } from "../../Styled/Icon"; import Spacing from "../../Styled/Spacing"; -import TerrainSide from "../Map/Panels/TerrainSide"; +import TerrainSide from "./TerrainSide"; interface IWorkbenchSplitScreenProps { terria: Terria; diff --git a/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx b/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx index 986b1e74f09..9ea5d301d73 100644 --- a/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx +++ b/lib/ReactViews/Workflow/SelectableDimensionWorkflow.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next"; import { getName } from "../../ModelMixins/CatalogMemberMixin"; import { filterSelectableDimensions } from "../../Models/SelectableDimensions/SelectableDimensions"; import SelectableDimension from "../SelectableDimensions/SelectableDimension"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import WorkbenchItemControls, { hideAllControls } from "../Workbench/Controls/WorkbenchItemControls"; diff --git a/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx b/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx index f79856f8715..2866e06c45d 100644 --- a/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx +++ b/lib/ReactViews/Workflow/WorkflowPanelPortal.tsx @@ -1,7 +1,7 @@ import React from "react"; import styled from "styled-components"; import { Portal } from "../StandardUserInterface/Portal"; -import { useViewState } from "../StandardUserInterface/ViewStateContext"; +import { useViewState } from "../Context"; import { WorkflowPanelPortalId } from "./WorkflowPanel"; type PropsType = { @@ -24,10 +24,8 @@ const Container = styled.div<{ show: boolean }>` height: 100vh; width: ${(p) => p.theme.workflowPanelWidth}px; max-width: ${(p) => p.theme.workflowPanelWidth}px; - transition: all 0.25s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - visibility: ${(p) => (p.show ? "visible" : "hidden")}; margin-left: ${(p) => (p.show ? "0px" : `-${p.theme.workflowPanelWidth}px`)}; opacity: ${(p) => (p.show ? 1 : 0)}; diff --git a/lib/Styled/Text.tsx b/lib/Styled/Text.tsx index f0836f4a72b..0e58759baab 100644 --- a/lib/Styled/Text.tsx +++ b/lib/Styled/Text.tsx @@ -32,7 +32,7 @@ interface ITextWeight { export interface ITextPropsBase { displayBlock?: boolean; isLink?: boolean; - nunito?: boolean; + mono?: boolean; openSans?: boolean; breakWord?: boolean; uppercase?: boolean; @@ -68,6 +68,8 @@ export const Text = styled.div` // TODO: themeify family font-family: ${(props) => props.theme.fontBase}; + ${(props) => props.mono && `font-family: ${props.theme.fontMono};`} + ${(props) => props.breakWord && ` @@ -184,11 +186,6 @@ export const Text = styled.div` ` font-size: ${props.styledFontSize}; `} - ${(props) => - props.styledLineHeight && - ` - line-height: ${props.styledLineHeight}; - `} ${(props) => props.highlightLinks && diff --git a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts index a173ff3c2e6..b39d29200e6 100644 --- a/lib/ThirdParty/terriajs-cesium-extra/index.d.ts +++ b/lib/ThirdParty/terriajs-cesium-extra/index.d.ts @@ -53,4 +53,5 @@ declare interface FeatureDetection { isEdge(): boolean; isInternetExplorer(): boolean; internetExplorerVersion(): number[]; + chromeVersion(): number[]; } diff --git a/test/Map/StyledHtmlSpec.tsx b/test/Map/StyledHtmlSpec.tsx index b458f8784e5..e363ed5811e 100644 --- a/test/Map/StyledHtmlSpec.tsx +++ b/test/Map/StyledHtmlSpec.tsx @@ -5,7 +5,7 @@ import { ThemeProvider } from "styled-components"; import { act } from "react-dom/test-utils"; import Terria from "../../lib/Models/Terria"; import ViewState from "../../lib/ReactViewModels/ViewState"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import { StyledHtmlRaw } from "../../lib/ReactViews/Map/Panels/HelpPanel/StyledHtml"; import { TooltipWithButtonLauncher } from "../../lib/ReactViews/Generic/TooltipWrapper"; import registerCustomComponentTypes from "../../lib/ReactViews/Custom/registerCustomComponentTypes"; diff --git a/test/ReactViews/ClipboardSpec.tsx b/test/ReactViews/ClipboardSpec.tsx index eb239b7f848..4af48217ac2 100644 --- a/test/ReactViews/ClipboardSpec.tsx +++ b/test/ReactViews/ClipboardSpec.tsx @@ -2,7 +2,7 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import Clipboard from "../../lib/ReactViews/Clipboard"; import Input from "../../lib/Styled/Input"; import Button from "../../lib/Styled/Button"; diff --git a/test/ReactViews/DimensionSelectorSectionSpec.tsx b/test/ReactViews/DimensionSelectorSectionSpec.tsx index 9022477e954..073a2fc0500 100644 --- a/test/ReactViews/DimensionSelectorSectionSpec.tsx +++ b/test/ReactViews/DimensionSelectorSectionSpec.tsx @@ -15,7 +15,7 @@ import SelectableDimensions, { import Terria from "../../lib/Models/Terria"; import { SelectableDimensionGroup } from "../../lib/ReactViews/SelectableDimensions/Group"; import SelectableDimension from "../../lib/ReactViews/SelectableDimensions/SelectableDimension"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import SelectableDimensionSection from "../../lib/ReactViews/Workbench/Controls/SelectableDimensionSection"; import Checkbox from "../../lib/Styled/Checkbox"; import CatalogMemberTraits from "../../lib/Traits/TraitsClasses/CatalogMemberTraits"; diff --git a/test/ReactViews/Generic/PromptSpec.tsx b/test/ReactViews/Generic/PromptSpec.tsx index 2decc5f462f..31b7fa6f65b 100644 --- a/test/ReactViews/Generic/PromptSpec.tsx +++ b/test/ReactViews/Generic/PromptSpec.tsx @@ -5,7 +5,7 @@ import Terria from "../../../lib/Models/Terria"; import ViewState from "../../../lib/ReactViewModels/ViewState"; import { runInAction } from "mobx"; const Prompt: any = require("../../../lib/ReactViews/Generic/Prompt").default; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; import Caret from "../../../lib/ReactViews/Generic/Caret"; describe("HelpPrompt", function () { diff --git a/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx b/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx index 633f79e4040..d88e6da7f4f 100644 --- a/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx +++ b/test/ReactViews/Map/Navigation/Compass/CompassSpec.tsx @@ -5,10 +5,8 @@ import { act } from "react-dom/test-utils"; import Terria from "../../../../../lib/Models/Terria"; import ViewState from "../../../../../lib/ReactViewModels/ViewState"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface/StandardTheme"; -// import Compass from "../../../../../lib/ReactViews/Map/Navigation/Compass"; -const Compass: any = - require("../../../../../lib/ReactViews/Map/Navigation/Items/Compass").default; +import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface"; +import Compass from "../../../../../lib/ReactViews/Map/MapNavigation/Items/Compass/Compass"; import { StyledIcon } from "../../../../../lib/Styled/Icon"; describe("Compass", function () { diff --git a/test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx b/test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx similarity index 74% rename from test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx rename to test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx index 1450248f69b..f7883198777 100644 --- a/test/ReactViews/GyroscopeGuidance/GyroscopeGuidanceSpec.tsx +++ b/test/ReactViews/Map/Navigation/Compass/GyroscopeGuidanceSpec.tsx @@ -1,10 +1,10 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; -import Terria from "../../../lib/Models/Terria"; -import ViewState from "../../../lib/ReactViewModels/ViewState"; -import GyroscopeGuidance from "../../../lib/ReactViews/GyroscopeGuidance/GyroscopeGuidance"; -import MapIconButton from "../../../lib/ReactViews/MapIconButton/MapIconButton"; +import Terria from "../../../../../lib/Models/Terria"; +import ViewState from "../../../../../lib/ReactViewModels/ViewState"; +import { GyroscopeGuidance } from "../../../../../lib/ReactViews/Map/MapNavigation/Items/Compass/GyroscopeGuidance"; +import MapIconButton from "../../../../../lib/ReactViews/MapIconButton/MapIconButton"; describe("GyroscopeGuidance", function () { let terria: Terria; diff --git a/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx b/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx index 803c40e90e5..884d9ffeaf5 100644 --- a/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx +++ b/test/ReactViews/Map/Panels/HelpPanel/VideoGuideSpec.tsx @@ -2,7 +2,7 @@ const create: any = require("react-test-renderer").create; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../../../lib/ReactViews/StandardUserInterface"; import Terria from "../../../../../lib/Models/Terria"; import ViewState from "../../../../../lib/ReactViewModels/ViewState"; const VideoGuide: any = diff --git a/test/ReactViews/MeasureToolSpec.jsx b/test/ReactViews/MeasureToolSpec.jsx index 326b3296c84..f79ced47844 100644 --- a/test/ReactViews/MeasureToolSpec.jsx +++ b/test/ReactViews/MeasureToolSpec.jsx @@ -5,7 +5,7 @@ import React from "react"; import Terria from "../../lib/Models/Terria"; import { getMountedInstance } from "./MoreShallowTools"; -import { MeasureTool } from "../../lib/ReactViews/Map/Navigation/MeasureTool"; +import { MeasureTool } from "../../lib/ReactViews/Map/MapNavigation/MeasureTool"; const Entity = require("terriajs-cesium/Source/DataSources/Entity.js").default; const Ellipsoid = require("terriajs-cesium/Source/Core/Ellipsoid.js").default; const ConstantPositionProperty = diff --git a/test/ReactViews/Preview/DescriptionSpec.tsx b/test/ReactViews/Preview/DescriptionSpec.tsx index 2d5873e46dc..fa1ec7c33d6 100644 --- a/test/ReactViews/Preview/DescriptionSpec.tsx +++ b/test/ReactViews/Preview/DescriptionSpec.tsx @@ -7,7 +7,7 @@ import Terria from "../../../lib/Models/Terria"; import updateModelFromJson from "../../../lib/Models/Definition/updateModelFromJson"; import WebMapServiceCatalogItem from "../../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; import Description from "../../../lib/ReactViews/Preview/Description"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("DescriptionSpec", function () { let testRenderer: ReactTestRenderer; diff --git a/test/ReactViews/Search/BreadcrumbsSpec.tsx b/test/ReactViews/Search/BreadcrumbsSpec.tsx index 2eb3218fea6..f85ce9a5278 100644 --- a/test/ReactViews/Search/BreadcrumbsSpec.tsx +++ b/test/ReactViews/Search/BreadcrumbsSpec.tsx @@ -9,7 +9,7 @@ const DataCatalogTab: any = require("../../../lib/ReactViews/ExplorerWindow/Tabs/DataCatalogTab").default; import Icon from "../../../lib/Styled/Icon"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; import { runInAction } from "mobx"; describe("Breadcrumbs", function () { diff --git a/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx b/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx index 57862533302..f62f0fd3a6d 100644 --- a/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx +++ b/test/ReactViews/Search/SearchBoxAndResultsSpec.tsx @@ -8,7 +8,7 @@ import SearchBoxAndResults, { SearchInDataCatalog } from "../../../lib/ReactViews/Search/SearchBoxAndResults"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("SearchBoxAndResults", function () { let terria: Terria; diff --git a/test/ReactViews/Search/SearchBoxSpec.tsx b/test/ReactViews/Search/SearchBoxSpec.tsx index ecf678efc20..bb60465a479 100644 --- a/test/ReactViews/Search/SearchBoxSpec.tsx +++ b/test/ReactViews/Search/SearchBoxSpec.tsx @@ -4,7 +4,7 @@ import { act } from "react-dom/test-utils"; import Terria from "../../../lib/Models/Terria"; import ViewState from "../../../lib/ReactViewModels/ViewState"; import { SearchBox } from "../../../lib/ReactViews/Search/SearchBox"; -import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../../lib/ReactViews/StandardUserInterface"; describe("SearchBox", function () { let terria: Terria; diff --git a/test/ReactViews/ShortReportSpec.tsx b/test/ReactViews/ShortReportSpec.tsx index c7bd4424564..7ea0022b6b4 100644 --- a/test/ReactViews/ShortReportSpec.tsx +++ b/test/ReactViews/ShortReportSpec.tsx @@ -8,7 +8,7 @@ import { import { ThemeProvider } from "styled-components"; import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; import Terria from "../../lib/Models/Terria"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import ShortReport from "../../lib/ReactViews/Workbench/Controls/ShortReport"; import Text from "../../lib/Styled/Text"; diff --git a/test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx b/test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx similarity index 96% rename from test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx rename to test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx index 14d8cab4a97..7bba0db2c75 100644 --- a/test/ReactViews/Map/TrainerBar/TrainerBarSpec.tsx +++ b/test/ReactViews/StandardUserInterface/TrainerBar/TrainerBarSpec.tsx @@ -3,7 +3,7 @@ import React from "react"; import { act } from "react-dom/test-utils"; import Terria from "../../../../lib/Models/Terria"; import ViewState from "../../../../lib/ReactViewModels/ViewState"; -import TrainerBar from "../../../../lib/ReactViews/Map/TrainerBar/TrainerBar"; +import TrainerBar from "../../../../lib/ReactViews/StandardUserInterface/TrainerBar/TrainerBar"; import Box from "../../../../lib/Styled/Box"; import { createWithContexts } from "../../withContext"; import TestHelpContent from "./test-help-content"; diff --git a/test/ReactViews/Map/TrainerBar/test-help-content.js b/test/ReactViews/StandardUserInterface/TrainerBar/test-help-content.js similarity index 100% rename from test/ReactViews/Map/TrainerBar/test-help-content.js rename to test/ReactViews/StandardUserInterface/TrainerBar/test-help-content.js diff --git a/test/ReactViews/WarningBoxSpec.tsx b/test/ReactViews/WarningBoxSpec.tsx index 842688bb523..ce62e67fee8 100644 --- a/test/ReactViews/WarningBoxSpec.tsx +++ b/test/ReactViews/WarningBoxSpec.tsx @@ -2,7 +2,7 @@ import { create, ReactTestInstance } from "react-test-renderer"; import React from "react"; import { act } from "react-dom/test-utils"; import { ThemeProvider } from "styled-components"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; import WarningBox from "../../lib/ReactViews/Preview/WarningBox"; import Terria from "../../lib/Models/Terria"; import WebMapServiceCatalogItem from "../../lib/Models/Catalog/Ows/WebMapServiceCatalogItem"; diff --git a/test/ReactViews/withContext.tsx b/test/ReactViews/withContext.tsx index fcdcd03c866..35da0173e4d 100644 --- a/test/ReactViews/withContext.tsx +++ b/test/ReactViews/withContext.tsx @@ -2,8 +2,8 @@ import React from "react"; import { create, TestRendererOptions } from "react-test-renderer"; import { ThemeProvider } from "styled-components"; import ViewState from "../../lib/ReactViewModels/ViewState"; -import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface/StandardTheme"; -import { ViewStateProvider } from "../../lib/ReactViews/StandardUserInterface/ViewStateContext"; +import { terriaTheme } from "../../lib/ReactViews/StandardUserInterface"; +import { ViewStateProvider } from "../../lib/ReactViews/Context/ViewStateContext"; export function withThemeContext(node: React.ReactNode) { return {node};