UNPKG

terriajs

Version:

Geospatial data visualization platform.

159 lines 11.4 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { observer } from "mobx-react"; import { Component, Fragment } from "react"; import { Translation, withTranslation } from "react-i18next"; import styled, { withTheme } from "styled-components"; import { PaneMode } from "../../../ReactViewModels/defaultHelpContent"; import Box from "../../../Styled/Box"; import Button, { RawButton } from "../../../Styled/Button"; import { GLYPHS, StyledIcon } from "../../../Styled/Icon"; import Select from "../../../Styled/Select"; import Spacing from "../../../Styled/Spacing"; import Text, { TextSpan } from "../../../Styled/Text"; import measureElement from "../../HOCs/measureElement"; import { withViewState } from "../../Context"; import { applyTranslationIfExists } from "../../../Language/languageHelpers"; import StyledHtml from "../../Map/Panels/HelpPanel/StyledHtml"; import CloseButton from "../../Generic/CloseButton"; const TrainerBarWrapper = styled(Box) ` top: 0; left: ${(p) => p.isMapFullScreen ? 0 : Number(p.theme.workbenchWidth) + Number(p.theme.workbenchMargin) * 2}px; z-index: ${(p) => Number(p.theme.frontComponentZIndex) + 100}; `; // Help with discoverability const BoxTrainerExpandedSteps = styled(Box) ``; const getSelectedTrainerFromHelpContent = (viewState, helpContent) => { const selected = viewState.selectedTrainerItem; const found = helpContent.find((item) => item.itemName === selected); // Try and find the item that we selected, otherwise find the first trainer pane return (found || helpContent.find((item) => item.paneMode === PaneMode.trainer)); }; // Ripped from StyledHtml.jsx const Numbers = styled(Text) ` width: 22px; height: 22px; line-height: 22px; border-radius: 50%; background-color: ${(props) => props.theme.textLight}; `; const StepText = styled(Text).attrs({}) ` ol, ul { padding: 0; margin: 0; // Dislike these arbitrary aligned numbers but leaving it in for now padding-left: 17px; } li { padding-left: 8px; } `; const renderStep = (step, number, viewState, options = { renderDescription: true, comfortable: false, footerComponent: undefined }) => { return (_jsxs(Box, { paddedVertically: true, children: [_jsxs(Box, { alignItemsFlexStart: true, children: [_jsx(Numbers, { textDarker: true, textAlignCenter: true, darkBg: true, children: number }), _jsx(Spacing, { right: 3 })] }), _jsxs(Box, { column: true, children: [_jsx(Translation, { children: (_t, { i18n }) => (_jsx(Text, { textLight: true, extraExtraLarge: true, semiBold: true, children: applyTranslationIfExists(step.title, i18n) })) }), options.renderDescription && step?.markdownDescription && (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: options.comfortable ? 2 : 1 }), _jsx(StepText, { medium: true, textLightDimmed: true, children: _jsx(StyledHtml, { viewState: viewState, styledTextProps: { textDark: false, textLightDimmed: true }, markdown: step.markdownDescription }) })] })), options.footerComponent?.()] })] }, number)); }; const renderOrderedStepList = function (steps, viewState) { return steps.map((step, index) => (_jsxs(Fragment, { children: [renderStep(step, index + 1, viewState), index + 1 !== steps.length && _jsx(Spacing, { bottom: 3 })] }, index))); }; // Originally written as a SFC but measureElement only supports class components at the moment class StepAccordionRaw extends Component { refToMeasure; render() { const { viewState, selectedTrainerSteps, t, theme, selectedTrainer, isShowingAllSteps, setIsShowingAllSteps, isExpanded, setIsExpanded, heightFromMeasureElementHOC } = this.props; return (_jsxs(Box, { centered: !isExpanded, fullWidth: true, justifySpaceBetween: true, children: [_jsx(Box, { paddedHorizontally: 4, column: true, "aria-hidden": isExpanded, overflow: "hidden", css: ` max-height: 64px; pointer-events: none; `, ref: (component) => { if (!isExpanded) this.refToMeasure = component; }, children: renderStep(selectedTrainerSteps[viewState.currentTrainerStepIndex], viewState.currentTrainerStepIndex + 1, viewState, { renderDescription: false, comfortable: true }) }), isExpanded && (_jsx(Box, { paddedHorizontally: 4, column: true, position: "absolute", fullWidth: true, css: ` top: 0; padding-bottom: 20px; // This padding forces the absolutely positioned box to align with // the relative width in its clone padding-right: 60px; `, backgroundColor: theme.darkMid, ref: (component) => (this.refToMeasure = component), children: renderStep(selectedTrainerSteps[viewState.currentTrainerStepIndex], viewState.currentTrainerStepIndex + 1, viewState, { renderDescription: true, comfortable: true, footerComponent: () => (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 3 }), _jsx(RawButton, { onClick: () => setIsShowingAllSteps(!isShowingAllSteps), title: isShowingAllSteps ? t("trainer.hideAllSteps") : t("trainer.showAllSteps"), children: _jsx(TextSpan, { medium: true, primary: true, isLink: true, textAlignLeft: true, children: isShowingAllSteps ? t("trainer.hideAllSteps") : t("trainer.showAllSteps") }) })] })) }) })), _jsx(Box, { paddedHorizontally: 2, children: _jsx(RawButton, { onClick: () => setIsExpanded(!isExpanded), // onMouseOver={() => setIsPeeking(true)} // onFocus={() => setIsPeeking(true)} title: isExpanded ? t("trainer.collapseTrainer") : t("trainer.expandTrainer"), // onBlur={() => { // if (!isExpanded) setIsPeeking(false); // }} css: "z-index:2;", children: _jsx(StyledIcon, { styledWidth: "26px", light: true, glyph: isExpanded ? GLYPHS.accordionClose : GLYPHS.accordionOpen }) }) }), isShowingAllSteps && (_jsxs(BoxTrainerExpandedSteps, { column: true, position: "absolute", backgroundColor: theme.darkMid, fullWidth: true, paddedRatio: 4, overflowY: "auto", css: ` // top: 32px; padding-bottom: 10px; top: ${heightFromMeasureElementHOC}px; max-height: calc(100vh - ${heightFromMeasureElementHOC}px - 20px); `, children: [renderOrderedStepList(selectedTrainerSteps, viewState), selectedTrainer.footnote ? (_jsxs(_Fragment, { children: [_jsx(Spacing, { bottom: 3 }), _jsx(Text, { medium: true, textLightDimmed: true, children: _jsx(StyledHtml, { viewState: viewState, styledTextProps: { textDark: false, textLightDimmed: true }, markdown: selectedTrainer.footnote }) })] })) : (_jsx(Spacing, { bottom: 3 }))] }))] })); } } const StepAccordion = withTranslation()(withViewState(measureElement(StepAccordionRaw))); export const TrainerBar = observer((props) => { const { i18n, t, theme, viewState } = props; const terria = viewState.terria; const { helpContent } = terria.configParameters; // All these null guards are because we are rendering based on nested // map-owner defined (helpContent)content which could be malformed if (!viewState.trainerBarVisible || !helpContent) { return null; } const selectedTrainer = getSelectedTrainerFromHelpContent(viewState, helpContent); const selectedTrainerItems = selectedTrainer?.trainerItems; if (!selectedTrainerItems) { return null; } const trainerItemIndex = viewState.currentTrainerItemIndex <= selectedTrainerItems.length ? viewState.currentTrainerItemIndex : 0; const selectedTrainerItem = selectedTrainerItems[trainerItemIndex]; const selectedTrainerSteps = selectedTrainerItem?.steps; if (!selectedTrainerSteps) { return null; } const isMapFullScreen = viewState.isMapFullScreen; return (_jsx(TrainerBarWrapper, { centered: true, position: "absolute", styledWidth: isMapFullScreen ? "100%" : `calc(100% - ${Number(Number(theme.workbenchWidth) + Number(theme.workbenchMargin) * 2)}px)`, isMapFullScreen: isMapFullScreen, onClick: () => viewState.setTopElement("TrainerBar"), children: _jsxs(Box, { fullWidth: true, fullHeight: true, centered: true, justifySpaceBetween: true, backgroundColor: theme.darkMid, children: [_jsx(Box, { css: "min-height: 64px;", children: _jsx(Select, { css: ` // Overrides on normal select here as we are using a non-normal // nowhere-else-in-app usage of select width: 290px; @media (max-width: ${(p) => p.theme.lg}px) { width: 84px; // hack to effectively visually disable the current option // without minimising select click target color: transparent; } `, paddingForLeftIcon: "45px", leftIcon: () => (_jsx(StyledIcon, { css: "padding-left:15px;", light: true, styledWidth: "21px", glyph: GLYPHS.oneTwoThree })), onChange: (e) => viewState.setCurrentTrainerItemIndex(Number(e.target.value)), value: viewState.currentTrainerItemIndex, children: selectedTrainerItems.map((item, index) => (_jsx("option", { value: index, children: applyTranslationIfExists(item.title, i18n) }, item.title))) }) }), _jsx(StepAccordion, { selectedTrainerSteps: selectedTrainerSteps, isShowingAllSteps: viewState.trainerBarShowingAllSteps, setIsShowingAllSteps: (bool) => viewState.setTrainerBarShowingAllSteps(bool), isExpanded: viewState.trainerBarExpanded, setIsExpanded: (bool) => viewState.setTrainerBarExpanded(bool), selectedTrainer: selectedTrainerItem, theme: theme }), _jsx(Spacing, { right: 4 }), _jsxs(Box, { children: [_jsx(Button, { secondary: true, shortMinHeight: true, css: ` background: transparent; color: ${theme.textLight}; border-color: ${theme.textLight}; ${viewState.currentTrainerStepIndex === 0 && `visibility: hidden;`} `, onClick: () => { viewState.setCurrentTrainerStepIndex(viewState.currentTrainerStepIndex - 1); }, children: t("general.back") }), _jsx(Spacing, { right: 2 }), _jsx(Button, { primary: true, shortMinHeight: true, css: ` ${viewState.currentTrainerStepIndex === selectedTrainerSteps.length - 1 && `visibility: hidden;`} `, onClick: () => { viewState.setCurrentTrainerStepIndex(viewState.currentTrainerStepIndex + 1); }, children: t("general.next") }), _jsx(Spacing, { right: 5 }), _jsx(Box, { centered: true, children: _jsx(CloseButton, { noAbsolute: true, // topRight color: theme.textLight, onClick: () => viewState.setTrainerBarVisible(false) }) }), _jsx(Spacing, { right: 6 })] })] }) })); }); export default withTranslation()(withViewState(withTheme(TrainerBar))); //# sourceMappingURL=TrainerBar.js.map