import {css} from '@emotion/react'; import styled from '@emotion/styled'; import {PlatformIcon} from 'platformicons'; import Tooltip from 'sentry/components/tooltip'; import {PlatformKey} from 'sentry/data/platformCategories'; import {tn} from 'sentry/locale'; import getPlatformName from 'sentry/utils/getPlatformName'; import {Theme} from 'sentry/utils/theme'; type Props = { className?: string; /** * Will set container width to be size of having `this.props.max` icons * This is good for lists where the project name is displayed */ consistentWidth?: boolean; direction?: 'right' | 'left'; /** * Maximum number of platform icons to display */ max?: number; platforms?: PlatformKey[]; /** * If true and if the number of children is greater than the max prop, * a counter will be displayed at the end of the stack */ showCounter?: boolean; /** * Platform icon size in pixels */ size?: number; }; type WrapperProps = Required< Pick >; function PlatformList({ platforms = [], direction = 'right', max = 3, size = 16, consistentWidth = false, showCounter = false, className, }: Props) { const visiblePlatforms = platforms.slice(0, max); const numNotVisiblePlatforms = platforms.length - visiblePlatforms.length; const displayCounter = showCounter && !!numNotVisiblePlatforms; function renderContent() { if (!platforms.length) { return ; } const platformIcons = visiblePlatforms.slice().reverse(); if (displayCounter) { return ( {platformIcons.map((visiblePlatform, index) => ( ))} {numNotVisiblePlatforms} {'\u002B'} ); } return ( {platformIcons.map((visiblePlatform, index) => ( ))} ); } return ( {renderContent()} ); } export default PlatformList; function getOverlapWidth(size: number) { return Math.round(size / 4); } const commonStyles = ({theme}: {theme: Theme}) => ` cursor: default; border-radius: ${theme.borderRadius}; box-shadow: 0 0 0 1px ${theme.background}; :hover { z-index: 1; } `; const PlatformIcons = styled('div')` display: flex; `; const InnerWrapper = styled('div')` display: flex; position: relative; `; const Plus = styled('span')` font-size: 10px; `; const StyledPlatformIcon = styled(PlatformIcon)` ${p => commonStyles(p)}; `; const Counter = styled('div')` ${p => commonStyles(p)}; display: flex; align-items: center; justify-content: center; text-align: center; font-weight: 600; font-size: ${p => p.theme.fontSizeExtraSmall}; background-color: ${p => p.theme.gray200}; color: ${p => p.theme.gray300}; padding: 0 1px; position: absolute; right: -1px; `; const Wrapper = styled('div')` display: flex; flex-shrink: 0; justify-content: ${p => (p.direction === 'right' ? 'flex-end' : 'flex-start')}; ${p => p.consistentWidth && `width: ${p.size + (p.max - 1) * getOverlapWidth(p.size)}px;`}; ${PlatformIcons} { ${p => p.showCounter ? css` z-index: 1; flex-direction: row-reverse; > * :not(:first-child) { margin-right: ${p.size * -1 + getOverlapWidth(p.size)}px; } ` : css` > * :not(:first-child) { margin-left: ${p.size * -1 + getOverlapWidth(p.size)}px; } `} } ${InnerWrapper} { padding-right: ${p => p.size / 2 + 1}px; } ${Counter} { height: ${p => p.size}px; min-width: ${p => p.size}px; } `;