UNPKG

kepler.gl

Version:

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

278 lines (252 loc) 8.02 kB
// Copyright (c) 2018 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, {Component} from 'react'; import styled from 'styled-components'; import PropTypes from 'prop-types'; import {Tooltip} from 'components/common/styled-components'; import KeplerGlLogo from 'components/common/logo'; import {CodeAlt, Save, Files, Share, Picture} from 'components/common/icons'; import ClickOutsideCloseDropdown from 'components/side-panel/panel-dropdown'; const StyledPanelHeader = styled.div.attrs({ className: 'side-side-panel__header' })` background-color: ${props => props.theme.sidePanelHeaderBg}; padding: 12px 16px 0 16px; `; const StyledPanelHeaderTop = styled.div.attrs({ className: 'side-panel__header__top' })` display: flex; justify-content: space-between; margin-bottom: 16px; width: 100%; `; const StyledPanelTopActions = styled.div.attrs({ className: 'side-panel__header__actions' })` display: flex; `; const StyledPanelAction = styled.div.attrs({ className: 'side-panel__header__actions' })` align-items: center; border-radius: 2px; color: ${props => props.active ? props.theme.textColorHl : props.theme.subtextColor}; display: flex; height: 26px; justify-content: space-between; margin-left: 4px; width: 70px; padding: 5px; font-weight: bold; a { height: 20px; } :hover { cursor: pointer; background-color: ${props => props.theme.secondaryBtnActBgd}; color: ${props => props.theme.textColorHl}; a { color: ${props => props.theme.textColorHl}; } } `; const StyledPanelDropdown = styled.div` background-color: ${props => props.theme.dropdownListBgd}; box-shadow: ${props => props.theme.dropdownListShadow}; font-size: 11px; padding: 16px 0; position: absolute; transition: ${props => props.theme.transitionSlow}; display: flex; margin-top: ${props => props.show ? '6px' : '20px'}; opacity: ${props => props.show ? 1 : 0}; transform: translateX(calc(-50% + 20px)); pointer-events: ${props => props.show ? 'all' : 'none'}; z-index: 1000; .save-export-dropdown__inner { box-shadow: none; background-color: transparent; display: flex; } .save-export-dropdown__item { align-items: center; border-right: 1px solid ${props => props.theme.panelHeaderIcon}; color: ${props => props.theme.textColor}; display: flex; flex-direction: column; padding: 0 22px; :hover { cursor: pointer; color: ${props => props.theme.textColorHl}; } &:last-child { border-right: 0; } } .save-export-dropdown__title { white-space: nowrap; margin-top: 4px; } `; export const PanelAction = ({item, onClick}) => ( <StyledPanelAction className="side-panel__panel-header__action" data-tip data-for={`${item.id}-action`} onClick={onClick}> {item.label ? <p>{item.label}</p> : null} <a target={item.blank ? '_blank' : ''} href={item.href}> <item.iconComponent height="20px" /> </a> {item.tooltip ? (<Tooltip id={`${item.id}-action`} place="bottom" delayShow={500} effect="solid" > <span>{item.tooltip}</span> </Tooltip>) : null } </StyledPanelAction> ); const PanelItem = ({onClose, onClickHandler, label, icon}) => ( <div className="save-export-dropdown__item" onClick={(e) => { e.stopPropagation(); onClose(); onClickHandler(); }}> {icon} <div className="save-export-dropdown__title">{label}</div> </div> ); export const SaveExportDropdown = ({ onExportImage, onExportData, onExportConfig, onSaveMap, show, onClose }) => { return ( <StyledPanelDropdown show={show} className="save-export-dropdown"> <ClickOutsideCloseDropdown className="save-export-dropdown__inner" show={show} onClose={onClose}> <PanelItem label="Export Image" onClickHandler={onExportImage} onClose={onClose} icon={(<Picture height="16px" />)} /> <PanelItem label="Export Data" onClickHandler={onExportData} onClose={onClose} icon={(<Files height="16px" />)} /> <PanelItem label="Export Config" onClickHandler={onExportConfig} onClose={onClose} icon={(<CodeAlt height="16px" />)} /> {onSaveMap ? ( <PanelItem label="Save Map Url" onClickHandler={onSaveMap} onClose={onClose} icon={(<Share height="16px" />)} /> ) : null} </ClickOutsideCloseDropdown> </StyledPanelDropdown> ); }; const defaultActionItems = [ { id: 'save', iconComponent: Save, onClick: () => {}, label: 'Share', dropdownComponent: SaveExportDropdown } ]; function PanelHeaderFactory() { return class PanelHeader extends Component { static propTypes = { appName: PropTypes.string, version: PropTypes.string, uiState: PropTypes.object, uiStateActions: PropTypes.object, logoComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), actionItems: PropTypes.arrayOf(PropTypes.any) }; static defaultProps = { logoComponent: KeplerGlLogo, actionItems: defaultActionItems }; render() { const { appName, version, actionItems, onSaveMap, onExportImage, onExportData, onExportConfig, visibleDropdown, showExportDropdown, hideExportDropdown } = this.props; return ( <StyledPanelHeader className="side-panel__panel-header"> <StyledPanelHeaderTop className="side-panel__panel-header__top"> <this.props.logoComponent appName={appName} version={version}/> <StyledPanelTopActions> {actionItems.map(item => ( <div className="side-panel__panel-header__right" key={item.id} style={{position: 'relative'}}> <PanelAction item={item} onClick={() => { if (item.dropdownComponent) { showExportDropdown(item.id); } item.onClick(); }} /> {item.dropdownComponent ? ( <item.dropdownComponent onClose={hideExportDropdown} show={visibleDropdown === item.id} onSaveMap={onSaveMap} onExportData={onExportData} onExportImage={onExportImage} onExportConfig={onExportConfig} /> ) : null} </div> ))} </StyledPanelTopActions> </StyledPanelHeaderTop> </StyledPanelHeader> ); } } } export default PanelHeaderFactory;