2022-09-30 15:11:24 +02:00
|
|
|
import { css, cx } from '@emotion/css';
|
|
|
|
|
import React from 'react';
|
2023-12-11 10:43:36 +00:00
|
|
|
import Skeleton from 'react-loading-skeleton';
|
2022-09-30 15:11:24 +02:00
|
|
|
|
|
|
|
|
import { DataFrameView, GrafanaTheme2, textUtil, dateTimeFormat } from '@grafana/data';
|
|
|
|
|
import { useStyles2 } from '@grafana/ui';
|
|
|
|
|
|
|
|
|
|
import { NewsItem } from '../types';
|
|
|
|
|
|
|
|
|
|
interface NewsItemProps {
|
|
|
|
|
width: number;
|
|
|
|
|
showImage?: boolean;
|
|
|
|
|
index: number;
|
|
|
|
|
data: DataFrameView<NewsItem>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function News({ width, showImage, data, index }: NewsItemProps) {
|
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
|
const useWideLayout = width > 600;
|
|
|
|
|
const newsItem = data.get(index);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<article className={cx(styles.item, useWideLayout && styles.itemWide)}>
|
|
|
|
|
{showImage && newsItem.ogImage && (
|
|
|
|
|
<a
|
|
|
|
|
tabIndex={-1}
|
|
|
|
|
href={textUtil.sanitizeUrl(newsItem.link)}
|
|
|
|
|
target="_blank"
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
className={cx(styles.socialImage, useWideLayout && styles.socialImageWide)}
|
|
|
|
|
aria-hidden
|
|
|
|
|
>
|
|
|
|
|
<img src={newsItem.ogImage} alt={newsItem.title} />
|
|
|
|
|
</a>
|
|
|
|
|
)}
|
|
|
|
|
<div className={styles.body}>
|
|
|
|
|
<time className={styles.date} dateTime={dateTimeFormat(newsItem.date, { format: 'MMM DD' })}>
|
|
|
|
|
{dateTimeFormat(newsItem.date, { format: 'MMM DD' })}{' '}
|
|
|
|
|
</time>
|
|
|
|
|
<a className={styles.link} href={textUtil.sanitizeUrl(newsItem.link)} target="_blank" rel="noopener noreferrer">
|
|
|
|
|
<h3 className={styles.title}>{newsItem.title}</h3>
|
|
|
|
|
</a>
|
|
|
|
|
<div className={styles.content} dangerouslySetInnerHTML={{ __html: textUtil.sanitize(newsItem.content) }} />
|
|
|
|
|
</div>
|
|
|
|
|
</article>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-11 10:43:36 +00:00
|
|
|
const NewsSkeleton = ({ width, showImage }: Pick<NewsItemProps, 'width' | 'showImage'>) => {
|
|
|
|
|
const styles = useStyles2(getStyles);
|
|
|
|
|
const useWideLayout = width > 600;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={cx(styles.item, useWideLayout && styles.itemWide)}>
|
|
|
|
|
{showImage && (
|
|
|
|
|
<Skeleton
|
|
|
|
|
containerClassName={cx(styles.socialImage, useWideLayout && styles.socialImageWide)}
|
|
|
|
|
width={useWideLayout ? '250px' : '100%'}
|
|
|
|
|
height={useWideLayout ? '150px' : width * 0.5}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
<div className={styles.body}>
|
|
|
|
|
<Skeleton containerClassName={styles.date} width={60} />
|
|
|
|
|
<Skeleton containerClassName={styles.title} width={250} />
|
|
|
|
|
<Skeleton containerClassName={styles.content} width="100%" count={6} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
News.Skeleton = NewsSkeleton;
|
|
|
|
|
|
2022-09-30 15:11:24 +02:00
|
|
|
const getStyles = (theme: GrafanaTheme2) => ({
|
2023-12-11 10:43:36 +00:00
|
|
|
container: css({
|
|
|
|
|
height: '100%',
|
|
|
|
|
}),
|
|
|
|
|
item: css({
|
|
|
|
|
display: 'flex',
|
|
|
|
|
padding: theme.spacing(1),
|
|
|
|
|
position: 'relative',
|
|
|
|
|
marginBottom: theme.spacing(0.5),
|
|
|
|
|
marginRight: theme.spacing(1),
|
|
|
|
|
borderBottom: `2px solid ${theme.colors.border.weak}`,
|
|
|
|
|
background: theme.colors.background.primary,
|
|
|
|
|
flexDirection: 'column',
|
|
|
|
|
flexShrink: 0,
|
|
|
|
|
}),
|
|
|
|
|
itemWide: css({
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
}),
|
|
|
|
|
body: css({
|
|
|
|
|
display: 'flex',
|
|
|
|
|
flexDirection: 'column',
|
|
|
|
|
flex: 1,
|
|
|
|
|
}),
|
|
|
|
|
socialImage: css({
|
|
|
|
|
display: 'flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
marginBottom: theme.spacing(1),
|
|
|
|
|
'> img': {
|
|
|
|
|
width: '100%',
|
|
|
|
|
borderRadius: `${theme.shape.radius.default} ${theme.shape.radius.default} 0 0`,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
socialImageWide: css({
|
|
|
|
|
marginRight: theme.spacing(2),
|
|
|
|
|
marginBottom: 0,
|
|
|
|
|
'> img': {
|
|
|
|
|
width: '250px',
|
|
|
|
|
borderRadius: theme.shape.radius.default,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
link: css({
|
|
|
|
|
color: theme.colors.text.link,
|
|
|
|
|
display: 'inline-block',
|
2022-09-30 15:11:24 +02:00
|
|
|
|
2023-12-11 10:43:36 +00:00
|
|
|
'&:hover': {
|
|
|
|
|
color: theme.colors.text.link,
|
|
|
|
|
textDecoration: 'underline',
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
title: css({
|
|
|
|
|
fontSize: '16px',
|
|
|
|
|
marginBottom: theme.spacing(0.5),
|
|
|
|
|
}),
|
|
|
|
|
content: css({
|
|
|
|
|
p: {
|
|
|
|
|
marginBottom: theme.spacing(0.5),
|
|
|
|
|
color: theme.colors.text.primary,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
date: css({
|
|
|
|
|
marginBottom: theme.spacing(0.5),
|
|
|
|
|
fontWeight: 500,
|
|
|
|
|
borderRadius: `0 0 0 ${theme.shape.radius.default}`,
|
|
|
|
|
color: theme.colors.text.secondary,
|
|
|
|
|
}),
|
2022-09-30 15:11:24 +02:00
|
|
|
});
|