feat(lite/stories): first stories for components (#6616)

This commit is contained in:
Thierry Goettelmann
2023-03-29 10:34:26 +02:00
committed by GitHub
parent 53e0f17c55
commit e5c890e29b
21 changed files with 591 additions and 2 deletions

View File

@@ -38,6 +38,11 @@ code * {
color: var(--color-extra-blue-d20);
}
.link:active {
.link:active,
.link.router-link-active {
color: var(--color-extra-blue-d40);
}
.link.router-link-active {
text-decoration: underline;
}

View File

@@ -19,6 +19,7 @@
class="preset-tab"
@click="open"
>
<UiIcon :icon="faSliders" />
Presets
</UiTab>
</template>
@@ -105,6 +106,7 @@ import UiButton from "@/components/ui/UiButton.vue";
import UiCard from "@/components/ui/UiCard.vue";
import UiCardTitle from "@/components/ui/UiCardTitle.vue";
import UiCounter from "@/components/ui/UiCounter.vue";
import UiIcon from "@/components/ui/icon/UiIcon.vue";
import UiTab from "@/components/ui/UiTab.vue";
import UiTabBar from "@/components/ui/UiTabBar.vue";
import {
@@ -116,6 +118,7 @@ import {
ModelParam,
type Param,
} from "@/libs/story/story-param";
import { faSliders } from "@fortawesome/free-solid-svg-icons";
import "highlight.js/styles/github-dark.css";
import { uniqueId, upperFirst } from "lodash-es";
import { computed, reactive, ref, watch, watchEffect } from "vue";

View File

@@ -2,7 +2,7 @@
<StoryParamsTable>
<thead>
<tr>
<th>Prop</th>
<th>Setting</th>
<th><!--Widget--></th>
<th>Help</th>
</tr>

View File

@@ -0,0 +1,15 @@
When using a `string` as `before` or `after` prop, you will probably have to set `before-width` and `after-width` accordingly.
```vue-template
<FormInput
v-model="myValue"
color="error"
:before="before"
:after="after"
:before-width="beforeWidth"
:after-width="afterWidth"
right
disabled
:wrapper-attrs="wrapperAttrs"
/>
```

View File

@@ -0,0 +1,40 @@
<template>
<ComponentStory
:params="[
colorProp(),
iconProp('before').type('IconDefinition | string'),
iconProp('after').type('IconDefinition | string'),
model().type('string').required(),
prop('right').bool().widget(),
prop('disabled').bool().widget(),
prop('wrapper-attrs')
.obj('HTMLAttributes')
.widget()
.preset({ foo: 'bar' }),
prop('before-width').str().widget(),
prop('after-width').str().widget(),
]"
:presets="presets"
v-slot="{ properties }"
>
<FormInput v-bind="properties" />
</ComponentStory>
</template>
<script lang="ts" setup>
import { faDollarSign } from "@fortawesome/free-solid-svg-icons";
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import FormInput from "@/components/form/FormInput.vue";
import { colorProp, iconProp, model, prop } from "@/libs/story/story-param";
const presets = {
$100: {
props: {
modelValue: "100",
before: faDollarSign,
},
},
};
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,62 @@
# LinearChart
### Type
```typescript
type LinearChartData = {
label: string;
data: {
timestamp: number;
value: number;
}[];
}[];
```
### Example
```vue-template
<LinearChart
title="Chart title"
subtitle="Chart subtitle"
:data="data"
/>
```
```vue-script
const data: LinearChartData = [
{
"label": "First series",
"data": [
{
"timestamp": 1640995200000,
"value": 4986790
},
{
"timestamp": 1641081600000,
"value": 354312074
},
{
"timestamp": 1641168000000,
"value": 379858800
},
]
},
{
"label": "Second series",
"data": [
{
"timestamp": 1640995200000,
"value": 102528411
},
{
"timestamp": 1641081600000,
"value": 10682534
},
{
"timestamp": 1641168000000,
"value": 10421188
},
]
}
]
```

View File

@@ -0,0 +1,138 @@
<template>
<ComponentStory
:params="[
prop('title').preset('Chart title').widget(),
prop('subtitle').preset('Here is a subtitle').widget(),
prop('data')
.preset(data)
.required()
.obj('LinearChartData')
.help('See doc for typing')
.widget(),
prop('value-formatter').type('(value: number) => string'),
prop('max-value').type('number').widget().default(200),
]"
:presets="presets"
v-slot="{ properties }"
>
<LinearChart v-bind="properties" />
</ComponentStory>
</template>
<script lang="ts" setup>
import humanFormat from "human-format";
import type { LinearChartData } from "@/types/chart";
import LinearChart from "@/components/charts/LinearChart.vue";
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import { prop } from "@/libs/story/story-param";
const byteFormatter = (value: number) => humanFormat.bytes(value);
let time = 0;
const firstDay = () => (time = 1640995200000);
const nextDay = () => (time += 86400000);
const data: LinearChartData = [
{
label: "Foo",
data: [
{ timestamp: firstDay(), value: 50 },
{ timestamp: nextDay(), value: 20 },
{ timestamp: nextDay(), value: 90 },
{ timestamp: nextDay(), value: 30 },
{ timestamp: nextDay(), value: 70 },
],
},
{
label: "Bar",
data: [
{ timestamp: firstDay(), value: 10 },
{ timestamp: nextDay(), value: 80 },
{ timestamp: nextDay(), value: 30 },
{ timestamp: nextDay(), value: 40 },
{ timestamp: nextDay(), value: 20 },
],
},
];
const presets = {
"Network bandwidth": {
props: {
title: "Network bandwidth",
subtitle: "Last week",
"value-formatter": byteFormatter,
"max-value": 500000000,
data: [
{
label: "Download",
data: [
{
timestamp: firstDay(),
value: 4986790,
},
{
timestamp: nextDay(),
value: 354312074,
},
{
timestamp: nextDay(),
value: 379858800,
},
{
timestamp: nextDay(),
value: 319522087,
},
{
timestamp: nextDay(),
value: 344568079,
},
{
timestamp: nextDay(),
value: 46295651,
},
{
timestamp: nextDay(),
value: 344130914,
},
],
},
{
label: "Upload",
data: [
{
timestamp: firstDay(),
value: 102528411,
},
{
timestamp: nextDay(),
value: 10682534,
},
{
timestamp: nextDay(),
value: 10421188,
},
{
timestamp: nextDay(),
value: 102156882,
},
{
timestamp: nextDay(),
value: 102028168,
},
{
timestamp: nextDay(),
value: 102733601,
},
{
timestamp: nextDay(),
value: 102523226,
},
],
},
],
},
},
};
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,3 @@
```vue-template
<PowerStateIcon :state="powerState" />
```

View File

@@ -0,0 +1,22 @@
<template>
<ComponentStory
:params="[
prop('state')
.enum('Running', 'Suspended', 'Halted', 'Paused')
.required()
.preset('Running')
.widget(),
]"
v-slot="{ properties }"
>
<PowerStateIcon style="font-size: 10rem" v-bind="properties" />
</ComponentStory>
</template>
<script lang="ts" setup>
import PowerStateIcon from "@/components/PowerStateIcon.vue";
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import { prop } from "@/libs/story/story-param";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,6 @@
```vue-template
<ProgressCircle
:value="value"
:max-value="maxValue"
/>
```

View File

@@ -0,0 +1,39 @@
<template>
<ComponentStory
:params="[
prop('value').num().preset(25).required().widget(),
prop('max-value').num().default(100).widget(),
]"
:presets="presets"
v-slot="{ properties }"
>
<ProgressCircle v-bind="properties" />
</ComponentStory>
</template>
<script lang="ts" setup>
import ProgressCircle from "@/components/ProgressCircle.vue";
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import { prop } from "@/libs/story/story-param";
const presets = {
"Half of 500": {
props: {
"max-value": 500,
value: 250,
},
},
"75% of 300": {
props: {
"max-value": 300,
value: 225,
},
},
};
</script>
<style lang="postcss" scoped>
.progress-circle {
max-width: 30rem;
}
</style>

View File

@@ -0,0 +1,25 @@
<template>
<ComponentStory
v-slot="{ properties, settings }"
:params="[
prop('to').required().type('RouteLocationRaw').preset({ name: 'home' }),
prop('disabled').bool().widget(),
slot(),
setting('label').widget(text()).preset('Foobar'),
]"
>
<UiTabBar>
<RouterTab v-bind="properties">{{ settings.label }}</RouterTab>
</UiTabBar>
</ComponentStory>
</template>
<script lang="ts" setup>
import RouterTab from "@/components/RouterTab.vue";
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiTabBar from "@/components/ui/UiTabBar.vue";
import { prop, setting, slot } from "@/libs/story/story-param.js";
import { text } from "@/libs/story/story-widget.js";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,14 @@
<template>
<ComponentStory
:params="[iconProp(), setting('label').preset('65%').widget(), slot()]"
v-slot="{ properties, settings }"
>
<UiBadge v-bind="properties">{{ settings.label }}</UiBadge>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiBadge from "@/components/ui/UiBadge.vue";
import { iconProp, setting, slot } from "@/libs/story/story-param";
</script>

View File

@@ -0,0 +1,29 @@
<template>
<ComponentStory
:params="[
prop('busy').type('boolean').widget(),
prop('disabled').type('boolean').widget(),
colorProp(),
prop('outlined').type('boolean').widget(),
prop('transparent').type('boolean').widget(),
prop('merge').type('boolean').widget(),
slot().help('Meant to receive UiButton components'),
]"
v-slot="{ properties }"
>
<UiButtonGroup v-bind="properties">
<UiButton>Button 1</UiButton>
<UiButton>Button 2</UiButton>
<UiButton>Button 3</UiButton>
</UiButtonGroup>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiButton from "@/components/ui/UiButton.vue";
import UiButtonGroup from "@/components/ui/UiButtonGroup.vue";
import { colorProp, prop, slot } from "@/libs/story/story-param";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,5 @@
Here is some doc for UiButton component
```vue-template
<UiButton @click="doSomething">Click me</UiButton>
```

View File

@@ -0,0 +1,47 @@
<template>
<ComponentStory
v-slot="{ properties, settings }"
:params="[
prop('type').enum('submit', 'button', 'reset').default('button'),
prop('busy').bool().widget(),
prop('disabled').bool().widget(),
iconProp(),
colorProp(),
prop('outlined').bool().widget(),
prop('transparent').bool().widget(),
prop('active').bool().widget(),
setting('label').preset('Click me').widget(),
]"
:presets="{
'Save Button': {
props: {
color: 'success',
icon: faFloppyDisk,
},
settings: {
label: 'Save',
},
},
'Delete Button': {
props: {
icon: faTrash,
color: 'error',
},
settings: {
label: 'Delete',
},
},
}"
>
<UiButton v-bind="properties">{{ settings.label }}</UiButton>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiButton from "@/components/ui/UiButton.vue";
import { colorProp, iconProp, prop, setting } from "@/libs/story/story-param";
import { faFloppyDisk, faTrash } from "@fortawesome/free-solid-svg-icons";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,22 @@
<template>
<ComponentStory
v-slot="{ properties, settings }"
:params="[
event('edit'),
event('remove'),
slot(),
setting('label').widget(text()).preset('Some filter'),
]"
>
<UiFilter v-bind="properties">{{ settings.label }}</UiFilter>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiFilter from "@/components/ui/UiFilter.vue";
import { event, setting, slot } from "@/libs/story/story-param";
import { text } from "@/libs/story/story-widget";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,19 @@
```vue-template
<button @click="open">Delete all items</button>
<UiModal v-if="isOpen" @close="close" :icon="faRemove">
<template #title>You are about to delete 12 items</template>
<template #subtitle>They'll be gone forever</template>
<template #buttons>
<UiButton @click="delete" color="error">Yes, delete</UiButton>
<UiButton @click="close">Cancel</UiButton>
</template>
</UiModal>
```
```vue-script
import { faRemove } from "@fortawesome/free-solid-svg-icons";
import { useModal } from "@composable/modal.composable";
const { open, close, isOpen } = useModal().
```

View File

@@ -0,0 +1,45 @@
<template>
<ComponentStory
:params="[
colorProp(),
iconProp(),
event('close').preset(close),
slot('default'),
slot('title'),
slot('subtitle'),
slot('icon'),
slot('buttons').help('Meant to receive UiButton components'),
setting('title').preset('Modal Title').widget(),
setting('subtitle').preset('Modal Subtitle').widget(),
]"
v-slot="{ properties, settings }"
>
<UiButton type="button" @click="open">Open Modal</UiButton>
<UiModal v-bind="properties" v-if="isOpen">
<template #title>{{ settings.title }}</template>
<template #subtitle>{{ settings.subtitle }}</template>
<template #buttons>
<UiButton @click="close">Discard</UiButton>
</template>
</UiModal>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiButton from "@/components/ui/UiButton.vue";
import UiModal from "@/components/ui/UiModal.vue";
import useModal from "@/composables/modal.composable";
import {
colorProp,
event,
iconProp,
setting,
slot,
} from "@/libs/story/story-param";
const { open, close, isOpen } = useModal();
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,24 @@
<template>
<ComponentStory
v-slot="{ properties }"
:params="[
prop('disabled').bool().widget(),
slot().help('Contains <RouterTab> or <UiTab>'),
]"
>
<UiTabBar v-bind="properties">
<UiTab>Foo</UiTab>
<UiTab>Bar</UiTab>
<UiTab>Baz</UiTab>
</UiTabBar>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiTab from "@/components/ui/UiTab.vue";
import UiTabBar from "@/components/ui/UiTabBar.vue";
import { prop, slot } from "@/libs/story/story-param.js";
</script>
<style lang="postcss" scoped></style>

View File

@@ -0,0 +1,26 @@
<template>
<ComponentStory
v-slot="{ properties, settings }"
:params="[
prop('disabled').bool().widget(),
prop('active').bool().widget(),
prop('tag').str().default('span'),
slot(),
setting('label').widget(text()).preset('Foobar'),
]"
>
<UiTabBar>
<UiTab v-bind="properties">{{ settings.label }}</UiTab>
</UiTabBar>
</ComponentStory>
</template>
<script lang="ts" setup>
import ComponentStory from "@/components/component-story/ComponentStory.vue";
import UiTab from "@/components/ui/UiTab.vue";
import UiTabBar from "@/components/ui/UiTabBar.vue";
import { prop, setting, slot } from "@/libs/story/story-param.js";
import { text } from "@/libs/story/story-widget.js";
</script>
<style lang="postcss" scoped></style>