From fb75411ddc96506ab84b21383bd7891855897b39 Mon Sep 17 00:00:00 2001 From: An Date: Mon, 1 Nov 2021 13:21:43 -0400 Subject: [PATCH] Resource Picker: update design and layout (#41046) --- packages/grafana-ui/src/types/icon.ts | 1 + .../dimensions/editors/ResourceCards.tsx | 58 ++++-- .../editors/ResourceDimensionEditor.tsx | 11 +- .../dimensions/editors/ResourcePicker.tsx | 171 +++++++++++------- 4 files changed, 152 insertions(+), 89 deletions(-) diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index 86bba8a126f..c032c2f95e8 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -65,6 +65,7 @@ export const getAvailableIcons = () => 'external-link-alt', 'eye', 'eye-slash', + 'ellipsis-h', 'fa fa-spinner', 'favorite', 'file-alt', diff --git a/public/app/features/dimensions/editors/ResourceCards.tsx b/public/app/features/dimensions/editors/ResourceCards.tsx index 22bbeca39d3..0b328673237 100644 --- a/public/app/features/dimensions/editors/ResourceCards.tsx +++ b/public/app/features/dimensions/editors/ResourceCards.tsx @@ -1,21 +1,27 @@ import React, { memo, CSSProperties } from 'react'; import { areEqual, FixedSizeGrid as Grid } from 'react-window'; import AutoSizer from 'react-virtualized-auto-sizer'; -import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { GrafanaTheme2 } from '@grafana/data'; import { useTheme2, stylesFactory } from '@grafana/ui'; import SVG from 'react-inlinesvg'; -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; +import { ResourceItem } from './ResourcePicker'; interface CellProps { columnIndex: number; rowIndex: number; style: CSSProperties; - data: any; + 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, folder } = data; + const { cards, columnCount, onChange, selected } = data; const singleColumnIndex = columnIndex + rowIndex * columnCount; const card = cards[singleColumnIndex]; const theme = useTheme2(); @@ -24,8 +30,12 @@ function Cell(props: CellProps) { return (
{card && ( -
onChange(`${folder.value}/${card.value}`)}> - {folder.value.includes('icons') ? ( +
onChange(card.value)} + > + {card.imgUrl.endsWith('.svg') ? ( ) : ( @@ -41,9 +51,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => { return { card: css` display: inline-block; - width: 80px; - height: 80px; + width: 90px; + height: 90px; margin: 0.75rem; + margin-left: 15px; text-align: center; cursor: pointer; position: relative; @@ -51,15 +62,20 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => { 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: 50px; - height: 50px; + width: 40px; + height: 40px; object-fit: cover; vertical-align: middle; fill: ${theme.colors.text.primary}; @@ -72,23 +88,28 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => { display: block; overflow: hidden; `, + grid: css` + border: 1px solid ${theme.colors.border.medium}; + `, }; }); interface CardProps { onChange: (value: string) => void; - cards: SelectableValue[]; - currentFolder: SelectableValue | undefined; + cards: ResourceItem[]; + value?: string; } export const ResourceCards = (props: CardProps) => { - const { onChange, cards, currentFolder: folder } = props; + const { onChange, cards, value } = props; + const theme = useTheme2(); + const styles = getStyles(theme); return ( - + {({ width, height }) => { - const cardWidth = 80; - const cardHeight = 80; + const cardWidth = 90; + const cardHeight = 90; const columnCount = Math.floor(width / cardWidth); const rowCount = Math.ceil(cards.length / columnCount); return ( @@ -99,7 +120,8 @@ export const ResourceCards = (props: CardProps) => { columnWidth={cardWidth} rowCount={rowCount} rowHeight={cardHeight} - itemData={{ cards, columnCount, onChange, folder }} + itemData={{ cards, columnCount, onChange, selected: value }} + className={styles.grid} > {memo(Cell, areEqual)} diff --git a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx index 003de0a9133..593e20893a7 100644 --- a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx +++ b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx @@ -75,7 +75,13 @@ export const ResourceDimensionEditor: FC< <> {isOpen && ( setOpen(false)} closeOnEscape> - + )} {showSourceRadio && ( @@ -106,9 +112,9 @@ export const ResourceDimensionEditor: FC< readOnly={true} onClick={openModal} prefix={srcPath && } + suffix={ +
+
+ + + + + { + onChangeSearch(v); + setSearchQuery(v); + }} + /> + + + )} + {source?.value === 'url' && ( + + setNewValue(e.currentTarget.value)} value={newValue} /> + + )} +
+
+ +
+ {mediaType === 'icon' && } + {mediaType === 'image' && newValue && } +
+
+ +
- - {tabs.map((tab, index) => ( - setTabs(tabs.map((tab, idx) => ({ ...tab, active: idx === index })))} - /> - ))} - - - {tabs[0].active && ( -
- - {filteredIndex ? ( -
- -
- ) : ( - - )} -
- )} - {/* TODO: add file upload + {source?.value === 'folder' && filteredIndex && ( +
+ setNewValue(v)} value={newValue} /> +
+ )} + + + + + + {/* TODO: add file upload {tabs[1].active && ( console.log('file', currentTarget?.files && currentTarget.files[0])} className={styles.tabContent} /> )} */} -
); } @@ -150,7 +164,10 @@ export function ResourcePicker(props: Props) { const getStyles = stylesFactory((theme: GrafanaTheme2) => { return { cardsWrapper: css` - height: calc(100vh - 480px); + height: calc(100vh - 550px); + min-height: 50px; + margin-top: 5px; + max-width: 680px; `, tabContent: css` margin-top: 20px; @@ -158,18 +175,34 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => { margin-top: 10px; }, `, - currentItem: css` + iconPreview: css` + width: 95px; + height: 79px; + border: 1px solid ${theme.colors.border.medium}; display: flex; - justify-content: space-between; align-items: center; - column-gap: 2px; - margin: -18px 0px 18px 0px; + justify-content: center; + `, + iconContainer: css` + display: flex; + flex-direction: column; + width: 40%; + align-items: center; `, img: css` - width: 40px; - height: 40px; + width: 49px; + height: 49px; fill: ${theme.colors.text.primary}; `, + child: css` + width: 60%; + `, + upper: css` + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + `, }; });