grafana/public/app/features/dimensions/editors/ResourceCards.tsx
CommanderRoot d29b8e8858
Chore: Replace deprecated String.prototype.substr() (#46763)
.substr() is deprecated so we replace it with .slice() which works similarily but isn't deprecated
Signed-off-by: Tobias Speicher <rootcommander@gmail.com>
2022-04-04 11:08:06 +02:00

133 lines
3.5 KiB
TypeScript

import React, { memo, CSSProperties } from 'react';
import { areEqual, FixedSizeGrid as Grid } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2, stylesFactory } from '@grafana/ui';
import SVG from 'react-inlinesvg';
import { css, cx } from '@emotion/css';
import { ResourceItem } from './FolderPickerTab';
interface CellProps {
columnIndex: number;
rowIndex: number;
style: CSSProperties;
data: {
cards: ResourceItem[];
columnCount: number;
onChange: (value: string) => void;
selected?: string;
};
}
function Cell(props: CellProps) {
const { columnIndex, rowIndex, style, data } = props;
const { cards, columnCount, onChange, selected } = data;
const singleColumnIndex = columnIndex + rowIndex * columnCount;
const card = cards[singleColumnIndex];
const theme = useTheme2();
const styles = getStyles(theme);
return (
<div style={style}>
{card && (
<div
key={card.value}
className={selected === card.value ? cx(styles.card, styles.selected) : styles.card}
onClick={() => onChange(card.value)}
>
{card.imgUrl.endsWith('.svg') ? (
<SVG src={card.imgUrl} className={styles.img} />
) : (
<img src={card.imgUrl} className={styles.img} />
)}
<h6 className={styles.text}>{card.label.slice(0, -4)}</h6>
</div>
)}
</div>
);
}
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
card: css`
display: inline-block;
width: 90px;
height: 90px;
margin: 0.75rem;
margin-left: 15px;
text-align: center;
cursor: pointer;
position: relative;
background-color: transparent;
border: 1px solid transparent;
border-radius: 8px;
padding-top: 6px;
:hover {
border-color: ${theme.colors.action.hover};
box-shadow: ${theme.shadows.z2};
}
`,
selected: css`
border: 2px solid ${theme.colors.primary.main};
:hover {
border-color: ${theme.colors.primary.main};
}
`,
img: css`
width: 40px;
height: 40px;
object-fit: cover;
vertical-align: middle;
fill: ${theme.colors.text.primary};
`,
text: css`
color: ${theme.colors.text.primary};
white-space: nowrap;
font-size: 12px;
text-overflow: ellipsis;
display: block;
overflow: hidden;
`,
grid: css`
border: 1px solid ${theme.colors.border.medium};
`,
};
});
interface CardProps {
onChange: (value: string) => void;
cards: ResourceItem[];
value?: string;
}
export const ResourceCards = (props: CardProps) => {
const { onChange, cards, value } = props;
const theme = useTheme2();
const styles = getStyles(theme);
return (
<AutoSizer defaultWidth={680}>
{({ width, height }) => {
const cardWidth = 90;
const cardHeight = 90;
const columnCount = Math.floor(width / cardWidth);
const rowCount = Math.ceil(cards.length / columnCount);
return (
<Grid
width={width}
height={height}
columnCount={columnCount}
columnWidth={cardWidth}
rowCount={rowCount}
rowHeight={cardHeight}
itemData={{ cards, columnCount, onChange, selected: value }}
className={styles.grid}
>
{memo(Cell, areEqual)}
</Grid>
);
}}
</AutoSizer>
);
};