mirror of
https://github.com/grafana/grafana.git
synced 2024-11-28 11:44:26 -06:00
Card: Add isCompact
prop and Overline
sub-component (#82077)
This commit is contained in:
parent
48b4ca8228
commit
bc83d8263b
@ -445,6 +445,24 @@ Card can have a disabled state, effectively making it and its actions non-clicka
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### With overline
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Overline>Filter option</Card.Overline>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>Filter data by query.</Card.Description>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Overline>Filter option</Card.Overline>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>Filter data by query.</Card.Description>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Props
|
||||
|
||||
<ArgTypes of={Card} />
|
||||
|
@ -24,9 +24,9 @@ const meta: Meta<typeof Card> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Basic: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const Basic: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled={disabled}>
|
||||
<Card {...args}>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>
|
||||
Filter data by query. This is useful if you are sharing the results from a different panel that has many queries
|
||||
@ -36,24 +36,24 @@ export const Basic: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const AsLink: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const AsLink: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<Card href="https://grafana.com" disabled={disabled}>
|
||||
<Card href="https://grafana.com" {...args}>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>
|
||||
Filter data by query. This is useful if you are sharing the results from a different panel that has many
|
||||
queries and you want to only visualize a subset of that in this panel.
|
||||
</Card.Description>
|
||||
</Card>
|
||||
<Card href="https://grafana.com" disabled={disabled}>
|
||||
<Card href="https://grafana.com" {...args}>
|
||||
<Card.Heading>Filter by name2</Card.Heading>
|
||||
<Card.Description>
|
||||
Filter data by query. This is useful if you are sharing the results from a different panel that has many
|
||||
queries and you want to only visualize a subset of that in this panel.
|
||||
</Card.Description>
|
||||
</Card>
|
||||
<Card href="https://grafana.com" disabled={disabled}>
|
||||
<Card href="https://grafana.com" {...args}>
|
||||
<Card.Heading>Production system overview</Card.Heading>
|
||||
<Card.Meta>Meta tags</Card.Meta>
|
||||
</Card>
|
||||
@ -61,9 +61,9 @@ export const AsLink: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const WithTags: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const WithTags: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled={disabled}>
|
||||
<Card {...args}>
|
||||
<Card.Heading>Elasticsearch – Custom Templated Query</Card.Heading>
|
||||
<Card.Meta>Elastic Search</Card.Meta>
|
||||
<Card.Tags>
|
||||
@ -73,9 +73,9 @@ export const WithTags: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const WithMedia: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const WithMedia: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled={disabled}>
|
||||
<Card {...args}>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Prometheus
|
||||
@ -89,9 +89,9 @@ export const WithMedia: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
export const WithActions: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const WithActions: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled={disabled}>
|
||||
<Card {...args}>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Prometheus
|
||||
@ -118,9 +118,9 @@ export const WithActions: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Full: StoryFn<typeof Card> = ({ disabled }) => {
|
||||
export const Full: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled={disabled}>
|
||||
<Card {...args}>
|
||||
<Card.Heading>Card title</Card.Heading>
|
||||
<Card.Description>
|
||||
Description, body text. Greetings! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
@ -179,4 +179,18 @@ export const NotSelected: StoryFn<typeof Card> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const WithOverline: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
<Card.Overline>Overline text above the title</Card.Overline>
|
||||
<Card.Heading>Card title</Card.Heading>
|
||||
<Card.Description>
|
||||
Description, body text. Greetings! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
|
||||
laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</Card.Description>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
@ -5,6 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { useStyles2 } from '../../themes';
|
||||
import { getFocusStyles } from '../../themes/mixins';
|
||||
import { Text } from '../Text/Text';
|
||||
|
||||
import { CardContainer, CardContainerProps, getCardContainerStyles } from './CardContainer';
|
||||
|
||||
@ -23,9 +24,12 @@ export interface Props extends Omit<CardContainerProps, 'disableEvents' | 'disab
|
||||
/** @deprecated Use `Card.Description` instead */
|
||||
description?: string;
|
||||
isSelected?: boolean;
|
||||
/** If true, the padding of the Card will be smaller */
|
||||
isCompact?: boolean;
|
||||
}
|
||||
|
||||
export interface CardInterface extends FC<Props> {
|
||||
Overline: typeof Overline;
|
||||
Heading: typeof Heading;
|
||||
Tags: typeof Tags;
|
||||
Figure: typeof Figure;
|
||||
@ -47,7 +51,16 @@ const CardContext = React.createContext<{
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const Card: CardInterface = ({ disabled, href, onClick, children, isSelected, className, ...htmlProps }) => {
|
||||
export const Card: CardInterface = ({
|
||||
disabled,
|
||||
href,
|
||||
onClick,
|
||||
children,
|
||||
isSelected,
|
||||
isCompact,
|
||||
className,
|
||||
...htmlProps
|
||||
}) => {
|
||||
const hasHeadingComponent = useMemo(
|
||||
() => React.Children.toArray(children).some((c) => React.isValidElement(c) && c.type === Heading),
|
||||
[children]
|
||||
@ -55,7 +68,7 @@ export const Card: CardInterface = ({ disabled, href, onClick, children, isSelec
|
||||
|
||||
const disableHover = disabled || (!onClick && !href);
|
||||
const onCardClick = onClick && !disabled ? onClick : undefined;
|
||||
const styles = useStyles2(getCardContainerStyles, disabled, disableHover, isSelected);
|
||||
const styles = useStyles2(getCardContainerStyles, disabled, disableHover, isSelected, isCompact);
|
||||
|
||||
return (
|
||||
<CardContainer
|
||||
@ -153,6 +166,28 @@ const getHeadingStyles = (theme: GrafanaTheme2) => ({
|
||||
}),
|
||||
});
|
||||
|
||||
/** Card text to be displayed above title */
|
||||
const Overline = ({ children, className }: ChildProps) => {
|
||||
const styles = useStyles2(getOverlineStyles);
|
||||
return (
|
||||
<div className={cx(styles.overline, className)}>
|
||||
{children && (
|
||||
<Text color="info" weight="medium" variant="bodySmall">
|
||||
{children}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Overline.displayName = 'Overline';
|
||||
|
||||
const getOverlineStyles = (theme: GrafanaTheme2) => ({
|
||||
overline: css({
|
||||
gridArea: 'Overline',
|
||||
marginBottom: theme.spacing(0.5),
|
||||
}),
|
||||
});
|
||||
|
||||
const Tags = ({ children, className }: ChildProps) => {
|
||||
const styles = useStyles2(getTagStyles);
|
||||
return <div className={cx(styles.tagList, className)}>{children}</div>;
|
||||
@ -349,6 +384,7 @@ export const getCardStyles = (theme: GrafanaTheme2) => {
|
||||
};
|
||||
};
|
||||
|
||||
Card.Overline = Overline;
|
||||
Card.Heading = Heading;
|
||||
Card.Tags = Tags;
|
||||
Card.Figure = Figure;
|
||||
|
@ -70,7 +70,8 @@ export const getCardContainerStyles = (
|
||||
theme: GrafanaTheme2,
|
||||
disabled = false,
|
||||
disableHover = false,
|
||||
isSelected?: boolean
|
||||
isSelected?: boolean,
|
||||
isCompact?: boolean
|
||||
) => {
|
||||
const isSelectable = isSelected !== undefined;
|
||||
|
||||
@ -79,16 +80,17 @@ export const getCardContainerStyles = (
|
||||
display: 'grid',
|
||||
position: 'relative',
|
||||
gridTemplateColumns: 'auto 1fr auto',
|
||||
gridTemplateRows: '1fr auto auto auto',
|
||||
gridTemplateRows: 'auto 1fr auto auto auto',
|
||||
gridAutoColumns: '1fr',
|
||||
gridAutoFlow: 'row',
|
||||
gridTemplateAreas: `
|
||||
"Figure Overline Tags"
|
||||
"Figure Heading Tags"
|
||||
"Figure Meta Tags"
|
||||
"Figure Description Tags"
|
||||
"Figure Actions Secondary"`,
|
||||
width: '100%',
|
||||
padding: theme.spacing(2),
|
||||
padding: theme.spacing(isCompact ? 1 : 2),
|
||||
background: theme.colors.background.secondary,
|
||||
borderRadius: theme.shape.radius.default,
|
||||
marginBottom: '8px',
|
||||
|
Loading…
Reference in New Issue
Block a user