mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Card: Remove mdx file and render docs from the story (#82565)
* Card: Generate docs from the story * Update sort * Update betterer to check for the "autodocs" tag
This commit is contained in:
parent
bb9d5799cf
commit
df8250ff48
11
.betterer.ts
11
.betterer.ts
@ -31,9 +31,16 @@ function countUndocumentedStories() {
|
||||
await Promise.all(
|
||||
filePaths.map(async (filePath) => {
|
||||
// look for .mdx import in the story file
|
||||
const regex = new RegExp("^import.*.mdx';$", 'gm');
|
||||
const mdxImportRegex = new RegExp("^import.*\\.mdx';$", 'gm');
|
||||
// Looks for the "autodocs" string in the file
|
||||
const autodocsStringRegex = /autodocs/;
|
||||
|
||||
const fileText = await fs.readFile(filePath, 'utf8');
|
||||
if (!regex.test(fileText)) {
|
||||
|
||||
const hasMdxImport = mdxImportRegex.test(fileText);
|
||||
const hasAutodocsString = autodocsStringRegex.test(fileText);
|
||||
// If both .mdx import and autodocs string are missing, add an issue
|
||||
if (!hasMdxImport && !hasAutodocsString) {
|
||||
// In this case the file contents don't matter:
|
||||
const file = fileTestResult.addFile(filePath, '');
|
||||
// Add the issue to the first character of the file:
|
||||
|
@ -50,6 +50,10 @@ const preview: Preview = {
|
||||
// We should be able to use the builtin alphabetical sort, but is broken in SB 7.0
|
||||
// https://github.com/storybookjs/storybook/issues/22470
|
||||
storySort: (a, b) => {
|
||||
// Skip sorting for stories with nosort tag
|
||||
if (a.tags.includes('nosort') || b.tags.includes('nosort')) {
|
||||
return 0;
|
||||
}
|
||||
if (a.title.startsWith('Docs Overview')) {
|
||||
if (b.title.startsWith('Docs Overview')) {
|
||||
return 0;
|
||||
|
@ -1,450 +0,0 @@
|
||||
import { Meta, Preview, ArgTypes } from '@storybook/blocks';
|
||||
import { Card } from './Card';
|
||||
import { Button } from '../Button';
|
||||
import { IconButton } from '../IconButton/IconButton';
|
||||
import { TagList } from '../Tags/TagList';
|
||||
|
||||
export const logo = 'https://grafana.com/static/assets/img/apple-touch-icon.png';
|
||||
|
||||
<Meta title="MDX/Card" component={Card} />
|
||||
|
||||
# Card
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic
|
||||
|
||||
A basic `Card` component expects at least a heading, used as a title.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>Filter data by query.</Card.Description>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>Filter by name</Card.Heading>
|
||||
<Card.Description>Filter data by query.</Card.Description>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Multiple metadata elements
|
||||
|
||||
For providing metadata elements, which can be any extra information for the card, `Card.Meta` component should be used. If metadata consists of multiple strings, each of them has to be escaped (wrapped in brackets `{}`) or better passed in as an array.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>{['Folder: Test', 'Views: 100']}</Card.Meta>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>{['Folder: Test', 'Views: 100']}</Card.Meta>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
Metadata also accepts HTML elements, which could be links, for example. For elements, that are not strings, a `key` prop has to be manually specified.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
The separator for multiple metadata elements defaults to a vertical line `|`, but can be customised.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta separator={'-'}>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta separator={'-'}>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Tags
|
||||
|
||||
Tags can be rendered inside the Card, by being wrapped in `Card.Tags` component. Note that this component does not provide any tag styling and that should be handled by the children. It is recommended to use it with Grafana-UI's `TagList` component.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Description>Card with a list of tags</Card.Description>
|
||||
<Card.Tags>
|
||||
<TagList tags={['tag1', 'tag2', 'tag3']} onClick={(tag) => console.log(tag)} />
|
||||
</Card.Tags>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Description>Card with a list of tags</Card.Description>
|
||||
<Card.Tags>
|
||||
<TagList tags={['tag1', 'tag2', 'tag3']} onClick={(tag) => console.log(tag)} />
|
||||
</Card.Tags>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### As a link
|
||||
|
||||
Card can be used as a clickable link item by specifying `href` prop.
|
||||
|
||||
```jsx
|
||||
<Card href="https://grafana.com">
|
||||
<Card.Heading>Redirect to Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will redirect to grafana website</Card.Description>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card href="https://grafana.com">
|
||||
<Card.Heading>Redirect to Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will redirect to grafana website</Card.Description>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### As a button
|
||||
|
||||
Card can be used as a clickable buttons item by specifying `onClick` prop.
|
||||
|
||||
```jsx
|
||||
<Card onClick={() => alert('Hello, Grafana!')}>
|
||||
<Card.Heading>Hello, Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will create an alert</Card.Description>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card onClick={() => alert('Hello, Grafana!')}>
|
||||
<Card.Heading>Hello, Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will create an alert</Card.Description>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
> **Note**: When used in conjunction with [Metadata elements](#multiple-metadata-elements), clicking on any element
|
||||
> inside `<Card.Meta>` will prevent the card action to be executed (either `href` to be followed or `onClick` to be called).
|
||||
>
|
||||
> Example:
|
||||
|
||||
```jsx
|
||||
<Card onClick={() => alert('Hello, Grafana!')}>
|
||||
<Card.Heading>Hello, Grafana</Card.Heading>
|
||||
<Card.Meta>Clicking on this text (Meta) WILL NOT trigger the alert!</Card.Meta>
|
||||
<Card.Description>Clicking on this text (Description) WILL trigger the alert!</Card.Description>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card onClick={() => alert('Hello, Grafana!')}>
|
||||
<Card.Heading>Hello, Grafana</Card.Heading>
|
||||
<Card.Meta>Clicking on this text (Meta) WILL NOT trigger the alert!</Card.Meta>
|
||||
<Card.Description>Clicking on this text (Description) WILL trigger the alert!</Card.Description>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Inside a list item
|
||||
|
||||
To render cards in a list, it is possible to nest them inside `li` items.
|
||||
|
||||
```jsx
|
||||
<ul>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<ul style={{ padding: '20px', maxWidth: '800px', listStyle: 'none', display: 'grid' }}>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
</Preview>
|
||||
|
||||
### With media elements
|
||||
|
||||
Cards can also be rendered with media content such icons or images. Such elements need to be wrapped in `Card.Figure` component.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Action Cards
|
||||
|
||||
Cards also accept primary and secondary actions. Usually the primary actions are displayed as buttons while secondary actions are displayed as icon buttons. The actions need to be wrappd in `Card.Actions` and `Card.SecondaryActions` components respectively.
|
||||
|
||||
```jsx
|
||||
<Card>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Actions>
|
||||
<Button key="settings" variant="secondary">
|
||||
Settings
|
||||
</Button>
|
||||
<Button key="explore" variant="secondary">
|
||||
Explore
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
<Card.SecondaryActions>
|
||||
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
|
||||
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
|
||||
</Card.SecondaryActions>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Actions>
|
||||
<Button key="settings" variant="secondary">
|
||||
Settings
|
||||
</Button>
|
||||
<Button key="explore" variant="secondary">
|
||||
Explore
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
<Card.SecondaryActions>
|
||||
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
|
||||
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
|
||||
</Card.SecondaryActions>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Disabled state
|
||||
|
||||
Card can have a disabled state, effectively making it and its actions non-clickable. If there are any actions, they will be disabled instead of the whole card.
|
||||
|
||||
```jsx
|
||||
<Card disabled>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card disabled>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
```jsx
|
||||
<Card disabled>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Actions>
|
||||
<Button key="settings" variant="secondary">
|
||||
Settings
|
||||
</Button>
|
||||
<Button key="explore" variant="secondary">
|
||||
Explore
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
<Card.SecondaryActions>
|
||||
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
|
||||
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
|
||||
</Card.SecondaryActions>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card disabled>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Actions>
|
||||
<Button key="settings" variant="secondary">
|
||||
Settings
|
||||
</Button>
|
||||
<Button key="explore" variant="secondary">
|
||||
Explore
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
<Card.SecondaryActions>
|
||||
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
|
||||
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
|
||||
</Card.SecondaryActions>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Selectable
|
||||
|
||||
```jsx
|
||||
<Card isSelected disabled>
|
||||
<Card.Heading>Option #1</Card.Heading>
|
||||
<Card.Meta>This is a really great option, you won't regret it.</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
```
|
||||
|
||||
<Preview>
|
||||
<Card isSelected disabled>
|
||||
<Card.Heading>Option #1</Card.Heading>
|
||||
<Card.Description>This is a really great option, you won't regret it.</Card.Description>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
</Preview>
|
||||
|
||||
### Props
|
||||
|
||||
<ArgTypes of={Card} />
|
@ -3,27 +3,27 @@ import React from 'react';
|
||||
|
||||
import { Button } from '../Button';
|
||||
import { IconButton } from '../IconButton/IconButton';
|
||||
import { VerticalGroup } from '../Layout/Layout';
|
||||
import { TagList } from '../Tags/TagList';
|
||||
|
||||
import { Card } from './Card';
|
||||
import mdx from './Card.mdx';
|
||||
|
||||
const logo = 'https://grafana.com/static/assets/img/apple-touch-icon.png';
|
||||
|
||||
const meta: Meta<typeof Card> = {
|
||||
title: 'General/Card',
|
||||
component: Card,
|
||||
// nosort is a custom tag used so the stories shown in docs keep the order they are defined in the file
|
||||
tags: ['autodocs', 'nosort'],
|
||||
parameters: {
|
||||
docs: {
|
||||
page: mdx,
|
||||
},
|
||||
controls: {
|
||||
exclude: ['onClick', 'href', 'heading', 'description', 'className'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* A basic Card component expects at least a heading, used as a title.
|
||||
*/
|
||||
export const Basic: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
@ -36,60 +36,157 @@ export const Basic: StoryFn<typeof Card> = (args) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const AsLink: StoryFn<typeof Card> = (args) => {
|
||||
/**
|
||||
* For providing metadata elements, which can be any extra information for the card, Card.Meta component should be used.
|
||||
* If metadata consists of multiple strings, each of them has to be escaped (wrapped in brackets {}) or better passed in as an array.
|
||||
*/
|
||||
export const MultipleMetadataElements: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<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" {...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" {...args}>
|
||||
<Card.Heading>Production system overview</Card.Heading>
|
||||
<Card.Meta>Meta tags</Card.Meta>
|
||||
</Card>
|
||||
</VerticalGroup>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>{['Folder: Test', 'Views: 100']}</Card.Meta>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithTags: StoryFn<typeof Card> = (args) => {
|
||||
/**
|
||||
* Metadata also accepts HTML elements, which could be links, for example.
|
||||
* For elements, that are not strings, a `key` prop has to be manually specified.
|
||||
*/
|
||||
export const ComplexMetadataElements: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
<Card.Heading>Elasticsearch – Custom Templated Query</Card.Heading>
|
||||
<Card.Meta>Elastic Search</Card.Meta>
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta>
|
||||
<>Grafana</>
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
<>https://ops-us-east4.grafana.net/api/prom</>
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* The separator for multiple metadata elements defaults to a vertical line `|`, but can be customised.
|
||||
*/
|
||||
export const MultipleMetadataWithCustomSeparator: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Meta separator={'-'}>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tags can be rendered inside the Card, by being wrapped in `Card.Tags` component.
|
||||
* Note that this component does not provide any tag styling and that should be handled by the children.
|
||||
* It is recommended to use it with Grafana-UI's `TagList` component.
|
||||
*/
|
||||
export const Tags: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card>
|
||||
<Card.Heading>Test dashboard</Card.Heading>
|
||||
<Card.Description>Card with a list of tags</Card.Description>
|
||||
<Card.Tags>
|
||||
<TagList tags={['elasticsearch', 'test', 'testdata']} onClick={(tag) => console.log('tag', tag)} />
|
||||
<TagList tags={['tag1', 'tag2', 'tag3']} onClick={(tag) => console.log(tag)} />
|
||||
</Card.Tags>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithMedia: StoryFn<typeof Card> = (args) => {
|
||||
/**
|
||||
* Card can be used as a clickable link item by specifying `href` prop.
|
||||
*/
|
||||
export const AsALink: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Prometheus
|
||||
<a key="link2" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Prometheus Logo" height="40" width="40" />
|
||||
</Card.Figure>
|
||||
<Card href="https://grafana.com">
|
||||
<Card.Heading>Redirect to Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will redirect to grafana website</Card.Description>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
export const WithActions: StoryFn<typeof Card> = (args) => {
|
||||
|
||||
/**
|
||||
* Card can be used as a clickable buttons item by specifying `onClick` prop.
|
||||
* **Note:** When used in conjunction with [Metadata elements](#multiple-metadata-elements), clicking on any element
|
||||
* inside `<Card.Meta>` will prevent the card action to be executed (either `href` to be followed or `onClick` to be called).
|
||||
*/
|
||||
export const AsAButton: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card onClick={() => alert('Hello, Grafana!')}>
|
||||
<Card.Heading>Hello, Grafana</Card.Heading>
|
||||
<Card.Description>Clicking this card will create an alert</Card.Description>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* To render cards in a list, it is possible to nest them inside `li` items.
|
||||
*/
|
||||
export const InsideAListItem: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<ul style={{ padding: '20px', listStyle: 'none', display: 'grid' }}>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
<li>
|
||||
<Card>
|
||||
<Card.Heading>List card item</Card.Heading>
|
||||
<Card.Description>Card that is rendered inside li element.</Card.Description>
|
||||
</Card>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cards can also be rendered with media content such icons or images. Such elements need to be wrapped in `Card.Figure` component.
|
||||
*/
|
||||
export const WithMediaElements: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cards also accept primary and secondary actions. Usually the primary actions are displayed as buttons
|
||||
* while secondary actions are displayed as icon buttons. The actions need to be wrapped in `Card.Actions`
|
||||
* and `Card.SecondaryActions` components respectively.
|
||||
*/
|
||||
export const ActionCards: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
@ -118,6 +215,51 @@ export const WithActions: StoryFn<typeof Card> = (args) => {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Card can have a disabled state, effectively making it and its actions non-clickable.
|
||||
* If there are any actions, they will be disabled instead of the whole card.
|
||||
*/
|
||||
export const DisabledState: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card disabled>
|
||||
<Card.Heading>1-ops-tools1-fallback</Card.Heading>
|
||||
<Card.Meta>
|
||||
Grafana
|
||||
<a key="prom-link" href="https://ops-us-east4.grafana.net/api/prom">
|
||||
https://ops-us-east4.grafana.net/api/prom
|
||||
</a>
|
||||
</Card.Meta>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
<Card.Actions>
|
||||
<Button key="settings" variant="secondary">
|
||||
Settings
|
||||
</Button>
|
||||
<Button key="explore" variant="secondary">
|
||||
Explore
|
||||
</Button>
|
||||
</Card.Actions>
|
||||
<Card.SecondaryActions>
|
||||
<IconButton key="showAll" name="apps" tooltip="Show all dashboards for this data source" />
|
||||
<IconButton key="delete" name="trash-alt" tooltip="Delete this data source" />
|
||||
</Card.SecondaryActions>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const Selectable: StoryFn<typeof Card> = () => {
|
||||
return (
|
||||
<Card isSelected disabled>
|
||||
<Card.Heading>Option #1</Card.Heading>
|
||||
<Card.Description>This is a really great option, you will not regret it.</Card.Description>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const Full: StoryFn<typeof Card> = (args) => {
|
||||
return (
|
||||
<Card {...args}>
|
||||
@ -155,28 +297,4 @@ export const Full: StoryFn<typeof Card> = (args) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Selected: StoryFn<typeof Card> = () => {
|
||||
return (
|
||||
<Card isSelected>
|
||||
<Card.Heading>Spaces</Card.Heading>
|
||||
<Card.Description>Spaces are the superior form of indenting code.</Card.Description>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const NotSelected: StoryFn<typeof Card> = () => {
|
||||
return (
|
||||
<Card isSelected={false}>
|
||||
<Card.Heading>Tabs</Card.Heading>
|
||||
<Card.Description>Tabs are the preferred way of indentation.</Card.Description>
|
||||
<Card.Figure>
|
||||
<img src={logo} alt="Grafana Logo" width="40" height="40" />
|
||||
</Card.Figure>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
Loading…
Reference in New Issue
Block a user