UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

245 lines (227 loc) 8.14 kB
// Copyright (c) 2021 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import React from 'react'; import styled from 'styled-components'; import CloudTile from './cloud-tile'; import ImageModalContainer from './image-modal-container'; import ProviderModalContainer from './provider-modal-container'; import StatusPanel, {UploadAnimation} from './status-panel'; import {MAP_THUMBNAIL_DIMENSION, MAP_INFO_CHARACTER} from 'constants/default-settings'; import { StyledModalContent, InputLight, TextAreaLight, StyledExportSection, StyledModalSection, StyledModalInputFootnote } from 'components/common/styled-components'; import ImagePreview from 'components/common/image-preview'; import {FormattedMessage} from 'localization'; /** @typedef {import('./save-map-modal').SaveMapModalProps} SaveMapModalProps */ const StyledSaveMapModal = styled.div.attrs({ className: 'save-map-modal' })` .save-map-modal-content { min-height: 400px; flex-direction: column; } .description { width: 300px; } .image-preview-panel { width: 300px; .image-preview { padding: 0; } } .map-info-panel { flex-direction: column; } .save-map-modal-description { .modal-section-subtitle { margin-left: 6px; } } `; const nop = _ => {}; export const MapInfoPanel = ({ mapInfo = {description: '', title: ''}, characterLimits, onChangeInput }) => ( <div className="selection map-info-panel"> <StyledModalSection className="save-map-modal-name"> <div className="modal-section-title">Name*</div> <div> <InputLight id="map-title" type="text" value={mapInfo.title} onChange={e => onChangeInput('title', e)} placeholder="Type map title" /> </div> </StyledModalSection> <StyledModalSection> <div className="save-map-modal-description" style={{display: 'flex'}}> <div className="modal-section-title">Description</div> <div className="modal-section-subtitle">(optional)</div> </div> <div> <TextAreaLight rows="3" id="map-description" style={{resize: 'none'}} value={mapInfo.description} onChange={e => onChangeInput('description', e)} placeholder="Type map description" /> </div> <StyledModalInputFootnote className="save-map-modal-description__footnote" error={ characterLimits.description && mapInfo.description.length > characterLimits.description } > {mapInfo.description.length}/{characterLimits.description || MAP_INFO_CHARACTER.description}{' '} characters </StyledModalInputFootnote> </StyledModalSection> </div> ); function SaveMapModalFactory() { /** * @type {React.FunctionComponent<SaveMapModalProps>} */ const SaveMapModal = ({ mapInfo, exportImage, characterLimits = {}, cloudProviders, isProviderLoading, currentProvider, providerError, onSetCloudProvider, onUpdateImageSetting, cleanupExportImage, onSetMapInfo }) => { const onChangeInput = (key, {target: {value}}) => { onSetMapInfo({[key]: value}); }; const provider = currentProvider ? cloudProviders.find(p => p.name === currentProvider) : null; return ( <ProviderModalContainer onSetCloudProvider={onSetCloudProvider} cloudProviders={cloudProviders} currentProvider={currentProvider} > <ImageModalContainer currentProvider={currentProvider} cloudProviders={cloudProviders} onUpdateImageSetting={onUpdateImageSetting} cleanupExportImage={cleanupExportImage} > <StyledSaveMapModal> <StyledModalContent className="save-map-modal-content"> <StyledExportSection disabled={isProviderLoading}> <div className="description"> <div className="title"> <FormattedMessage id={'modal.saveMap.title'} /> </div> <div className="subtitle"> <FormattedMessage id={'modal.saveMap.subtitle'} /> </div> </div> <div className="selection"> {cloudProviders.map(cloudProvider => ( <CloudTile key={cloudProvider.name} onSelect={() => onSetCloudProvider(cloudProvider.name)} onSetCloudProvider={onSetCloudProvider} cloudProvider={cloudProvider} isSelected={cloudProvider.name === currentProvider} isConnected={Boolean( cloudProvider.getAccessToken && cloudProvider.getAccessToken() )} /> ))} </div> </StyledExportSection> {provider && provider.getManagementUrl && ( <StyledExportSection style={{margin: '2px 0'}}> <div className="description" /> <div className="selection"> <a key={1} href={provider.getManagementUrl()} target="_blank" rel="noopener noreferrer" style={{textDecoration: 'underline'}} > Go to your Kepler.gl {provider.displayName} page </a> </div> </StyledExportSection> )} <StyledExportSection> <div className="description image-preview-panel"> <ImagePreview exportImage={exportImage} width={MAP_THUMBNAIL_DIMENSION.width} showDimension={false} /> </div> {isProviderLoading ? ( <div className="selection map-saving-animation"> <UploadAnimation icon={provider && provider.icon} /> </div> ) : ( <MapInfoPanel mapInfo={mapInfo} characterLimits={characterLimits} onChangeInput={onChangeInput} /> )} </StyledExportSection> {providerError ? ( <StatusPanel isLoading={false} error={providerError} providerIcon={provider && provider.icon} /> ) : null} </StyledModalContent> </StyledSaveMapModal> </ImageModalContainer> </ProviderModalContainer> ); }; SaveMapModal.defaultProps = { characterLimits: MAP_INFO_CHARACTER, cloudProviders: [], providerError: null, isProviderLoading: false, onSetCloudProvider: nop, onUpdateImageSetting: nop }; return SaveMapModal; } export default SaveMapModalFactory;