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:
Alex Khomenko 2024-02-16 12:13:50 +01:00 committed by GitHub
parent bb9d5799cf
commit df8250ff48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 199 additions and 520 deletions

View File

@ -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:

View 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;

View File

@ -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} />

View File

@ -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;