|
|
|
@ -1,8 +1,9 @@ |
|
|
|
import { css, cx } from '@emotion/css'; |
|
|
|
import { css, cx } from '@emotion/css'; |
|
|
|
import React from 'react'; |
|
|
|
import React from 'react'; |
|
|
|
|
|
|
|
import Skeleton from 'react-loading-skeleton'; |
|
|
|
|
|
|
|
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data'; |
|
|
|
import { GrafanaTheme2 } from '@grafana/data'; |
|
|
|
import { Icon, useStyles2 } from '@grafana/ui'; |
|
|
|
import { Badge, Icon, Stack, useStyles2 } from '@grafana/ui'; |
|
|
|
|
|
|
|
|
|
|
|
import { CatalogPlugin, PluginIconName, PluginListDisplayMode } from '../types'; |
|
|
|
import { CatalogPlugin, PluginIconName, PluginListDisplayMode } from '../types'; |
|
|
|
|
|
|
|
|
|
|
|
@ -36,67 +37,104 @@ export function PluginListItem({ plugin, pathName, displayMode = PluginListDispl |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const PluginListItemSkeleton = ({ displayMode = PluginListDisplayMode.Grid }: Pick<Props, 'displayMode'>) => { |
|
|
|
|
|
|
|
const styles = useStyles2(getStyles); |
|
|
|
|
|
|
|
const isList = displayMode === PluginListDisplayMode.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<div className={cx(styles.container, { [styles.list]: isList })}> |
|
|
|
|
|
|
|
<Skeleton |
|
|
|
|
|
|
|
containerClassName={cx( |
|
|
|
|
|
|
|
styles.pluginLogo, |
|
|
|
|
|
|
|
css({ |
|
|
|
|
|
|
|
lineHeight: 1, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
width={LOGO_SIZE} |
|
|
|
|
|
|
|
height={LOGO_SIZE} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
<h2 className={styles.name}> |
|
|
|
|
|
|
|
<Skeleton width={100} /> |
|
|
|
|
|
|
|
</h2> |
|
|
|
|
|
|
|
<div className={styles.content}> |
|
|
|
|
|
|
|
<p> |
|
|
|
|
|
|
|
<Skeleton width={120} /> |
|
|
|
|
|
|
|
</p> |
|
|
|
|
|
|
|
<Stack direction="row"> |
|
|
|
|
|
|
|
<Badge.Skeleton /> |
|
|
|
|
|
|
|
<Badge.Skeleton /> |
|
|
|
|
|
|
|
</Stack> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div className={styles.pluginType}> |
|
|
|
|
|
|
|
<Skeleton width={16} height={16} /> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PluginListItem.Skeleton = PluginListItemSkeleton; |
|
|
|
|
|
|
|
|
|
|
|
// Styles shared between the different type of list items
|
|
|
|
// Styles shared between the different type of list items
|
|
|
|
export const getStyles = (theme: GrafanaTheme2) => { |
|
|
|
export const getStyles = (theme: GrafanaTheme2) => { |
|
|
|
return { |
|
|
|
return { |
|
|
|
container: css` |
|
|
|
container: css({ |
|
|
|
display: grid; |
|
|
|
display: 'grid', |
|
|
|
grid-template-columns: ${LOGO_SIZE} 1fr ${theme.spacing(3)}; |
|
|
|
gridTemplateColumns: `${LOGO_SIZE} 1fr ${theme.spacing(3)}`, |
|
|
|
grid-template-rows: auto; |
|
|
|
gridTemplateRows: 'auto', |
|
|
|
gap: ${theme.spacing(2)}; |
|
|
|
gap: theme.spacing(2), |
|
|
|
grid-auto-flow: row; |
|
|
|
gridAutoFlow: 'row', |
|
|
|
background: ${theme.colors.background.secondary}; |
|
|
|
background: theme.colors.background.secondary, |
|
|
|
border-radius: ${theme.shape.radius.default}; |
|
|
|
borderRadius: theme.shape.radius.default, |
|
|
|
padding: ${theme.spacing(3)}; |
|
|
|
padding: theme.spacing(3), |
|
|
|
transition: ${theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], { |
|
|
|
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], { |
|
|
|
duration: theme.transitions.duration.short, |
|
|
|
duration: theme.transitions.duration.short, |
|
|
|
})}; |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
&:hover { |
|
|
|
'&:hover': { |
|
|
|
background: ${theme.colors.emphasize(theme.colors.background.secondary, 0.03)}; |
|
|
|
background: theme.colors.emphasize(theme.colors.background.secondary, 0.03), |
|
|
|
} |
|
|
|
}, |
|
|
|
`,
|
|
|
|
}), |
|
|
|
list: css` |
|
|
|
list: css({ |
|
|
|
row-gap: 0px; |
|
|
|
rowGap: 0, |
|
|
|
|
|
|
|
|
|
|
|
> img { |
|
|
|
'> img': { |
|
|
|
align-self: start; |
|
|
|
alignSelf: 'start', |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
> .plugin-content { |
|
|
|
'> .plugin-content': { |
|
|
|
min-height: 0px; |
|
|
|
minHeight: 0, |
|
|
|
grid-area: 2 / 2 / 4 / 3; |
|
|
|
gridArea: '2 / 2 / 4 / 3', |
|
|
|
|
|
|
|
|
|
|
|
> p { |
|
|
|
'> p': { |
|
|
|
margin: ${theme.spacing(0, 0, 0.5, 0)}; |
|
|
|
margin: theme.spacing(0, 0, 0.5, 0), |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
> .plugin-name { |
|
|
|
'> .plugin-name': { |
|
|
|
align-self: center; |
|
|
|
alignSelf: 'center', |
|
|
|
grid-area: 1 / 2 / 2 / 3; |
|
|
|
gridArea: '1 / 2 / 2 / 3', |
|
|
|
} |
|
|
|
}, |
|
|
|
`,
|
|
|
|
}), |
|
|
|
pluginType: css` |
|
|
|
pluginType: css({ |
|
|
|
grid-area: 1 / 3 / 2 / 4; |
|
|
|
gridArea: '1 / 3 / 2 / 4', |
|
|
|
color: ${theme.colors.text.secondary}; |
|
|
|
color: theme.colors.text.secondary, |
|
|
|
`,
|
|
|
|
}), |
|
|
|
pluginLogo: css` |
|
|
|
pluginLogo: css({ |
|
|
|
grid-area: 1 / 1 / 3 / 2; |
|
|
|
gridArea: '1 / 1 / 3 / 2', |
|
|
|
max-width: 100%; |
|
|
|
maxWidth: '100%', |
|
|
|
align-self: center; |
|
|
|
alignSelf: 'center', |
|
|
|
object-fit: contain; |
|
|
|
objectFit: 'contain', |
|
|
|
`,
|
|
|
|
}), |
|
|
|
content: css` |
|
|
|
content: css({ |
|
|
|
grid-area: 3 / 1 / 4 / 3; |
|
|
|
gridArea: '3 / 1 / 4 / 3', |
|
|
|
color: ${theme.colors.text.secondary}; |
|
|
|
color: theme.colors.text.secondary, |
|
|
|
`,
|
|
|
|
}), |
|
|
|
name: css` |
|
|
|
name: css({ |
|
|
|
grid-area: 1 / 2 / 3 / 3; |
|
|
|
gridArea: '1 / 2 / 3 / 3', |
|
|
|
align-self: center; |
|
|
|
alignSelf: 'center', |
|
|
|
font-size: ${theme.typography.h4.fontSize}; |
|
|
|
fontSize: theme.typography.h4.fontSize, |
|
|
|
color: ${theme.colors.text.primary}; |
|
|
|
color: theme.colors.text.primary, |
|
|
|
margin: 0; |
|
|
|
margin: 0, |
|
|
|
`,
|
|
|
|
}), |
|
|
|
}; |
|
|
|
}; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|