Storybook is Histoire (#20647)

Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
This commit is contained in:
Pascal Jufer
2023-12-06 13:49:28 +01:00
committed by GitHub
parent a94cd79e72
commit 5454fdf438
97 changed files with 1434 additions and 5303 deletions

View File

@@ -67,6 +67,8 @@ const vueRules = {
'vue/require-default-prop': 'off',
// Require shorthand form attribute when v-bind value is true
'vue/prefer-true-attribute-shorthand': 'error',
// Allow unused variables when they begin with an underscore
'vue/no-unused-vars': ['error', { ignorePattern: '^_' }],
};
const getExtends = (configs = []) => [

View File

@@ -1,17 +0,0 @@
import { action } from '@storybook/addon-actions';
export function fix(args, argTypes) {
if (args === undefined) args = {};
for (let type of Object.values(argTypes)) {
if (type.table.category !== 'events') continue;
if (type.name.startsWith('update:')) {
args[type.name] = (event) => {
action(type.name)(event);
};
} else args[type.name] = action(type.name);
}
return { args };
}

View File

@@ -1,33 +0,0 @@
const path = require('path');
const { mergeConfig } = require('vite');
module.exports = {
async viteFinal(config) {
return mergeConfig(config, {
resolve: {
dedupe: ['@storybook/client-api'],
alias: [
{
find: '@',
replacement: path.resolve(__dirname, '..', 'src'),
},
],
},
});
},
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-actions',
'@storybook/addon-mdx-gfm',
],
framework: {
name: '@storybook/vue3-vite',
options: {},
},
docs: {
autodocs: true,
},
};

View File

@@ -1,2 +0,0 @@
<div id="dialog-outlet"></div>
<div id="menu-outlet"></div>

View File

@@ -1,62 +0,0 @@
import '../src/styles/main.scss';
import './styles.scss';
import { useArgs } from '@storybook/client-api';
import { Preview, setup } from '@storybook/vue3';
import { createRouter, createWebHistory } from 'vue-router';
import { createI18n } from 'vue-i18n';
import { register } from './register';
import { fix } from './fix-actions';
setup((app) => {
const router = createRouter({
history: createWebHistory(),
routes: [
{
name: 'Home',
path: '/:_(.+)+',
component: { template: '<div>Home</div>' },
} as any,
],
});
const i18n = createI18n({
locale: 'en-US',
legacy: false,
messages: {
'en-US': {
edit: 'Edit',
copy_to: 'Copy to...',
delete: 'Delete',
duplicate: 'Duplicate',
},
},
});
app.use(router);
app.use(i18n);
register(app);
});
const preview: Preview = {
decorators: [
(_, { args, argTypes }) => {
const [__, update] = useArgs();
const newArgs = fix(args, argTypes, update);
return {
args: newArgs,
template: '<story />',
};
},
],
parameters: {
// actions: { argTypesRegex: "(change|emoji-selected|update:.*?)" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};
export default preview;

View File

@@ -1,138 +0,0 @@
import TransitionBounce from '../src/components/transition/bounce.vue';
import TransitionDialog from '../src/components/transition/dialog.vue';
import TransitionExpand from '../src/components/transition/expand.vue';
import VAvatar from '../src/components/v-avatar.vue';
import VBadge from '../src/components/v-badge.vue';
import VBreadcrumb from '../src/components/v-breadcrumb.vue';
import VButton from '../src/components/v-button.vue';
import VCard from '../src/components/v-card.vue';
import VCardActions from '../src/components/v-card-actions.vue';
import VCardSubtitle from '../src/components/v-card-subtitle.vue';
import VCardText from '../src/components/v-card-text.vue';
import VCardTitle from '../src/components/v-card-title.vue';
import VCheckbox from '../src/components/v-checkbox.vue';
import VCheckboxTree from '../src/components/v-checkbox-tree/v-checkbox-tree.vue';
import VChip from '../src/components/v-chip.vue';
import VDivider from '../src/components/v-divider.vue';
import VFancySelect from '../src/components/v-fancy-select.vue';
import VHover from '../src/components/v-hover.vue';
import VHighlight from '../src/components/v-highlight.vue';
import VIcon from '../src/components/v-icon/v-icon.vue';
import VIconFile from '../src/components/v-icon-file.vue';
import VInfo from '../src/components/v-info.vue';
import VInput from '../src/components/v-input.vue';
import VItemGroup from '../src/components/v-item-group.vue';
import VItem from '../src/components/v-item.vue';
import VList from '../src/components/v-list.vue';
import VListGroup from '../src/components/v-list-group.vue';
import VListItem from '../src/components/v-list-item.vue';
import VListItemContent from '../src/components/v-list-item-content.vue';
import VListItemHint from '../src/components/v-list-item-hint.vue';
import VListItemIcon from '../src/components/v-list-item-icon.vue';
import VMenu from '../src/components/v-menu.vue';
import VNotice from '../src/components/v-notice.vue';
import VOverlay from '../src/components/v-overlay.vue';
import VPagination from '../src/components/v-pagination.vue';
import VProgressCircular from '../src/components/v-progress-circular.vue';
import VProgressLinear from '../src/components/v-progress-linear.vue';
import VRadio from '../src/components/v-radio.vue';
import VSelect from '../src/components/v-select/v-select.vue';
import VSheet from '../src/components/v-sheet.vue';
import VSkeletonLoader from '../src/components/v-skeleton-loader.vue';
import VSlider from '../src/components/v-slider.vue';
import VTabs from '../src/components/v-tabs.vue';
import VTab from '../src/components/v-tab.vue';
import VTabItem from '../src/components/v-tab-item.vue';
import VTabsItems from '../src/components/v-tabs-items.vue';
import VTemplateInput from '../src/components/v-template-input.vue';
import VTextOverflow from '../src/components/v-text-overflow.vue';
import VTextarea from '../src/components/v-textarea.vue';
import VEmojiPicker from '../src/components/v-emoji-picker.vue';
import VWorkspace from '../src/components/v-workspace.vue';
import VWorkspaceTile from '../src/components/v-workspace-tile.vue';
// import VTable from './v-table/v-table.vue';
// import VUpload from './v-upload.vue';
// import VDatePicker from './v-date-picker.vue';
// import VDetail from './v-detail.vue';
// import VDialog from './v-dialog.vue';
// import VError from './v-error.vue';
// import VDrawer from './v-drawer.vue';
// import VFieldTemplate from './v-field-template/v-field-template.vue';
// import VFieldList from './v-field-list/v-field-list.vue';
// import VForm from './v-form/v-form.vue';
// import VImage from './v-image.vue';
import Focus from '../src/directives/focus';
import Tooltip from '../src/directives/tooltip';
import ClickOutside from '../src/directives/click-outside';
export function register(app) {
app.directive('focus', Focus);
app.directive('tooltip', Tooltip);
app.directive('click-outside', ClickOutside);
app.component('VAvatar', VAvatar);
app.component('VBadge', VBadge);
app.component('VBreadcrumb', VBreadcrumb);
app.component('VButton', VButton);
app.component('VCardActions', VCardActions);
app.component('VCardSubtitle', VCardSubtitle);
app.component('VCardText', VCardText);
app.component('VCardTitle', VCardTitle);
app.component('VCard', VCard);
app.component('VCheckbox', VCheckbox);
app.component('VCheckboxTree', VCheckboxTree);
app.component('VChip', VChip);
// app.component('VDetail', VDetail);
// app.component('VDialog', VDialog);
app.component('VDivider', VDivider);
// app.component('VError', VError);
app.component('VFancySelect', VFancySelect);
// app.component('VFieldTemplate', VFieldTemplate);
// app.component('VFieldList', VFieldList);
// app.component('VForm', VForm);
app.component('VHover', VHover);
app.component('VHighlight', VHighlight);
app.component('VIcon', VIcon);
// app.component('VImage', VImage);
app.component('VIconFile', VIconFile);
app.component('VInfo', VInfo);
app.component('VInput', VInput);
app.component('VItemGroup', VItemGroup);
app.component('VItem', VItem);
app.component('VListGroup', VListGroup);
app.component('VListItemContent', VListItemContent);
app.component('VListItemHint', VListItemHint);
app.component('VListItemIcon', VListItemIcon);
app.component('VListItem', VListItem);
app.component('VList', VList);
app.component('VMenu', VMenu);
// app.component('VDrawer', VDrawer);
app.component('VNotice', VNotice);
app.component('VOverlay', VOverlay);
app.component('VPagination', VPagination);
app.component('VProgressCircular', VProgressCircular);
app.component('VProgressLinear', VProgressLinear);
app.component('VRadio', VRadio);
app.component('VSelect', VSelect);
app.component('VSheet', VSheet);
app.component('VSkeletonLoader', VSkeletonLoader);
app.component('VSlider', VSlider);
app.component('VTabItem', VTabItem);
app.component('VTab', VTab);
// app.component('VTable', VTable);
app.component('VTabsItems', VTabsItems);
app.component('VTabs', VTabs);
app.component('VTemplateInput', VTemplateInput);
app.component('VTextarea', VTextarea);
app.component('VTextOverflow', VTextOverflow);
// app.component('VUpload', VUpload);
// app.component('VDatePicker', VDatePicker);
app.component('VEmojiPicker', VEmojiPicker);
app.component('VWorkspace', VWorkspace);
app.component('VWorkspaceTile', VWorkspaceTile);
app.component('TransitionBounce', TransitionBounce);
app.component('TransitionDialog', TransitionDialog);
app.component('TransitionExpand', TransitionExpand);
}

View File

@@ -1,3 +0,0 @@
.active {
color: var(--theme--primary);
}

1
app/env.d.ts vendored
View File

@@ -1,3 +1,4 @@
/// <reference types="vite/client" />
/// <reference types="@histoire/plugin-vue/components" />
declare const __DIRECTUS_VERSION__: string;

33
app/histoire.config.ts Normal file
View File

@@ -0,0 +1,33 @@
import { HstVue } from '@histoire/plugin-vue';
import { defineConfig } from 'histoire';
export default defineConfig({
plugins: [HstVue()],
setupFile: './src/histoire/setup.ts',
theme: {
title: 'Directus Components',
favicon: './public/favicon.ico',
logo: {
light: './src/assets/logo-dark.svg',
dark: './src/assets/logo.svg',
},
logoHref: 'https://directus.io',
colors: {
primary: {
50: '#fcfcff',
100: '#ece7ff',
200: '#cabeff',
300: '#a996ff',
400: '#876dff',
500: '#6644ff',
600: '#380cff',
700: '#2600d3',
800: '#1c009b',
900: '#120063',
},
},
},
backgroundPresets: [],
viteIgnorePlugins: ['directus-extensions-serve', 'directus-extensions-build'],
viteNodeInlineDeps: [/@joeattardi\/emoji-button/],
});

View File

@@ -22,9 +22,10 @@
],
"scripts": {
"build": "vite build",
"build-storybook": "storybook build",
"dev": "vite",
"storybook": "storybook dev -p 6006",
"story:build": "histoire build",
"story:dev": "histoire dev",
"story:preview": "histoire preview",
"test": "vitest --watch=false",
"typecheck": "vue-tsc --noEmit"
},
@@ -62,6 +63,7 @@
"@fullcalendar/interaction": "6.1.7",
"@fullcalendar/list": "6.1.7",
"@fullcalendar/timegrid": "6.1.7",
"@histoire/plugin-vue": "0.17.6",
"@joeattardi/emoji-button": "4.6.4",
"@mapbox/mapbox-gl-draw": "1.4.1",
"@mapbox/mapbox-gl-draw-static-mode": "1.0.1",
@@ -70,18 +72,6 @@
"@popperjs/core": "2.11.7",
"@rollup/plugin-yaml": "4.1.0",
"@sindresorhus/slugify": "2.2.1",
"@storybook/addon-actions": "7.0.12",
"@storybook/addon-backgrounds": "7.0.12",
"@storybook/addon-docs": "7.0.12",
"@storybook/addon-essentials": "7.0.12",
"@storybook/addon-links": "7.0.12",
"@storybook/addon-mdx-gfm": "7.0.12",
"@storybook/addon-measure": "7.0.12",
"@storybook/addon-outline": "7.0.12",
"@storybook/client-api": "7.0.12",
"@storybook/client-logger": "7.0.12",
"@storybook/vue3": "7.0.12",
"@storybook/vue3-vite": "7.0.12",
"@tinymce/tinymce-vue": "5.1.0",
"@turf/meta": "6.5.0",
"@types/base-64": "1.0.0",
@@ -124,6 +114,7 @@
"flatpickr": "4.6.13",
"geojson": "0.5.0",
"happy-dom": "12.10.3",
"histoire": "0.17.6",
"html-entities": "2.3.3",
"json-to-graphql-query": "2.2.5",
"json2csv": "5.0.7",
@@ -140,10 +131,7 @@
"pinia": "2.1.7",
"pretty-ms": "8.0.0",
"qrcode": "1.5.3",
"react": "18",
"react-dom": "18",
"sass": "1.62.1",
"storybook": "7.0.12",
"tinymce": "6.6.0",
"typescript": "5.3.2",
"vite": "4.3.7",

View File

@@ -1,22 +0,0 @@
import TransitionBounce from './bounce.vue';
import type { StoryFn } from '@storybook/vue3';
document.body.classList.add('light');
export default {
title: 'Components/Transition/TransitionBounce',
component: TransitionBounce,
argTypes: {},
};
const Template: StoryFn = (args) => ({
setup() {
return { args };
},
template:
'<v-hover v-slot="{ hover }">Hover me!<transition-bounce v-bind="args" v-on="args"><div v-if="hover" style="background-color: var(--theme--background-normal); height: 200px; width: 400px; display: flex; justify-content: center; align-items: center">This is only shown on hover.</div></transition-bounce></v-hover>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref } from 'vue';
import TransitionBounce from './bounce.vue';
const show = ref(true);
</script>
<template>
<Story title="Transition/TransitionBounce">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<transition-bounce v-bind="state">
<div
v-if="show"
style="
background-color: var(--theme--background-normal);
height: 200px;
width: 400px;
display: flex;
justify-content: center;
align-items: center;
"
>
This is inside transition bounce.
</div>
</transition-bounce>
</template>
<template #controls>
<HstCheckbox v-model="show" title="Toggle" />
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import TransitionDialog from './dialog.vue';
import type { StoryFn } from '@storybook/vue3';
document.body.classList.add('light');
export default {
title: 'Components/Transition/TransitionDialog',
component: TransitionDialog,
argTypes: {},
};
const Template: StoryFn = (args) => ({
setup() {
return { args };
},
template:
'<v-hover v-slot="{ hover }">Hover me!<transition-dialog v-bind="args" v-on="args"><div v-if="hover" style="background-color: var(--theme--background-normal); height: 200px; width: 400px; display: flex; justify-content: center; align-items: center">This is only shown on hover.</div></transition-dialog></v-hover>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref } from 'vue';
import TransitionDialog from './dialog.vue';
const show = ref(true);
</script>
<template>
<Story title="Transition/TransitionDialog">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<transition-dialog v-bind="state">
<div
v-if="show"
style="
background-color: var(--theme--background-normal);
height: 200px;
width: 400px;
display: flex;
justify-content: center;
align-items: center;
"
>
This is inside transition dialog.
</div>
</transition-dialog>
</template>
<template #controls>
<HstCheckbox v-model="show" title="Toggle" />
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import TransitionExpand from './expand.vue';
import type { StoryFn } from '@storybook/vue3';
document.body.classList.add('light');
export default {
title: 'Components/Transition/TransitionExpand',
component: TransitionExpand,
argTypes: {},
};
const Template: StoryFn = (args) => ({
setup() {
return { args };
},
template:
'<v-hover v-slot="{ hover }">Hover me!<transition-expand v-bind="args" v-on="args"><div v-if="hover" style="background-color: var(--theme--background-normal); height: 200px; width: 400px; display: flex; justify-content: center; align-items: center">This is only shown on hover.</div></transition-expand></v-hover>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
import { ref } from 'vue';
import TransitionExpand from './expand.vue';
const show = ref(true);
</script>
<template>
<Story title="Transition/TransitionExpand">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<transition-expand v-bind="state">
<div
v-if="show"
style="
background-color: var(--theme--background-normal);
height: 200px;
width: 400px;
display: flex;
justify-content: center;
align-items: center;
"
>
This is inside transition expand.
</div>
</transition-expand>
</template>
<template #controls>
<HstCheckbox v-model="show" title="Toggle" />
</template>
</Story>
</template>

View File

@@ -1,21 +0,0 @@
import VAvatar from './v-avatar.vue';
import type { StoryFn } from '@storybook/vue3';
document.body.classList.add('light');
export default {
title: 'Components/VAvatar',
component: VAvatar,
argTypes: {},
};
const Template: StoryFn = (args) => ({
setup() {
return { args };
},
template: '<v-avatar v-bind="args" v-on="args" ><v-icon name="person" /></v-avatar>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,13 @@
<script setup lang="ts">
import VAvatar from './v-avatar.vue';
</script>
<template>
<Story title="VAvatar">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-avatar v-bind="state">
<v-icon name="person" />
</v-avatar>
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VBadge from './v-badge.vue';
document.body.classList.add('light');
export default {
title: 'Components/VBadge',
component: VBadge,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-badge v-bind="args" v-on="args" ><v-icon name="notifications_active" /></v-badge>',
});
export const Primary = Template.bind({});
Primary.args = {
value: '+9',
};

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import VBadge from './v-badge.vue';
function initState() {
return {
value: '+9',
};
}
</script>
<template>
<Story title="VBadge" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-badge v-bind="state"><v-icon name="notifications_active" /></v-badge>
</template>
</Story>
</template>

View File

@@ -1,38 +0,0 @@
import VBreadcrumb from './v-breadcrumb.vue';
document.body.classList.add('light');
export default {
title: 'Components/VBreadcrumb',
component: VBreadcrumb,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-breadcrumb v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
items: [
{
to: '/',
name: 'Home',
},
{
to: '/settings',
name: 'settings',
icon: 'settings',
},
{
to: '/settings/profile',
name: 'Profile',
icon: 'person',
disabled: true,
},
],
};

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import VBreadcrumb from './v-breadcrumb.vue';
function initState() {
return {
items: [
{
to: '/',
name: 'Home',
},
{
to: '/settings',
name: 'Settings',
icon: 'settings',
},
{
to: '/settings/profile',
name: 'Profile',
icon: 'person',
disabled: true,
},
],
};
}
</script>
<template>
<Story title="VBreadcrumb" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-breadcrumb v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VButton from './v-button.vue';
document.body.classList.add('light');
export default {
title: 'Components/VButton',
component: VButton,
argTypes: {
click: { action: 'clicked' },
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-button v-bind="args" v-on="args">My Button{{args.onClick}}</v-button>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import { logEvent } from 'histoire/client';
import VButton from './v-button.vue';
</script>
<template>
<Story title="VButton">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-button v-bind="state" @click="logEvent('click', $event)">My Button</v-button>
</template>
</Story>
</template>

View File

@@ -1,30 +0,0 @@
import VCard from './v-card.vue';
document.body.classList.add('light');
export default {
title: 'Components/VCard',
component: VCard,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `<v-card v-bind="args" v-on="args" >
<v-card-title>Want a cake?</v-card-title>
<v-card-text>
If you want a cake, you have to click on accept.
And the cake is definitely not a lie.
</v-card-text>
<v-card-actions>
<v-button secondary>Decline</v-button>
<v-button>Accept</v-button>
</v-card-actions>
</v-card>`,
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import VCard from './v-card.vue';
import { logEvent } from 'histoire/client';
</script>
<template>
<Story title="VCard">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-card v-bind="state">
<v-card-title>Want a cake?</v-card-title>
<v-card-text>
If you want a cake, you have to click on accept. And the cake is definitely not a lie.
</v-card-text>
<v-card-actions>
<v-button secondary @click="logEvent('decline', $event)">Decline</v-button>
<v-button @click="logEvent('accept', $event)">Accept</v-button>
</v-card-actions>
</v-card>
</template>
</Story>
</template>

View File

@@ -53,7 +53,7 @@ withDefaults(defineProps<Props>(), {
cursor: not-allowed;
pointer-events: none;
& > * {
& :deep(> *) {
opacity: 0.4;
}
}

View File

@@ -1,48 +0,0 @@
import VCheckboxTree from './v-checkbox-tree/v-checkbox-tree.vue';
document.body.classList.add('light');
export default {
title: 'Components/VCheckboxTree',
component: VCheckboxTree,
argTypes: {
search: { control: 'text' },
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-checkbox-tree v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
choices: [
{
text: 'Choice 1',
value: 'choice-1',
children: [
{
text: 'Choice 1.1',
value: 'choice-1.1',
},
{
text: 'Choice 1.2',
value: 'choice-1.2',
},
],
},
{
text: 'Choice 2',
value: 'choice-2',
},
{
text: 'Choice 3',
value: 'choice-3',
},
],
modelValue: ['choice-1.1', 'choice-3'],
};

View File

@@ -0,0 +1,47 @@
<script setup lang="ts">
import { ref } from 'vue';
import VCheckboxTree from './v-checkbox-tree.vue';
function initState() {
return {
choices: [
{
text: 'Choice 1',
value: 'choice-1',
children: [
{
text: 'Choice 1.1',
value: 'choice-1.1',
},
{
text: 'Choice 1.2',
value: 'choice-1.2',
},
],
},
{
text: 'Choice 2',
value: 'choice-2',
},
{
text: 'Choice 3',
value: 'choice-3',
},
],
};
}
const value = ref([]);
</script>
<template>
<Story title="VCheckboxTree" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-checkbox-tree v-model="value" v-bind="state" />
</template>
<template #controls>
<HstJson v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,24 +0,0 @@
import VCheckbox from './v-checkbox.vue';
document.body.classList.add('light');
export default {
title: 'Components/VCheckbox',
component: VCheckbox,
argTypes: {
modelValue: { action: 'updateModelValue' },
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-checkbox v-bind="args" v-on="args">My Checkbox</v-checkbox>',
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: true,
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { ref } from 'vue';
import VCheckbox from './v-checkbox.vue';
const value = ref();
</script>
<template>
<Story title="VCheckbox">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-checkbox v-model="value" v-bind="state">My Checkbox</v-checkbox>
</template>
<template #controls>
<HstCheckbox v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VChip from './v-chip.vue';
document.body.classList.add('light');
export default {
title: 'Components/VChip',
component: VChip,
argTypes: {
close: { control: 'boolean' },
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-chip v-bind="args" v-on="args" >Cake</v-chip>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VChip from './v-chip.vue';
</script>
<template>
<Story title="VChip">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-chip v-bind="state">Cake</v-chip>
</template>
</Story>
</template>

View File

@@ -1,20 +0,0 @@
import VDivider from './v-divider.vue';
document.body.classList.add('light');
export default {
title: 'Components/VDivider',
component: VDivider,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-divider v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VDivider from './v-divider.vue';
</script>
<template>
<Story title="VDivider">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-divider v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,20 +0,0 @@
import VEmojiPicker from './v-emoji-picker.vue';
document.body.classList.add('light');
export default {
title: 'Components/VEmojiPicker',
component: VEmojiPicker,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-emoji-picker v-bind="args" v-on="args" >My Button</v-emoji-picker>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,12 @@
<script setup lang="ts">
import { logEvent } from 'histoire/client';
import VEmojiPicker from './v-emoji-picker.vue';
</script>
<template>
<Story title="VEmojiPicker">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-emoji-picker v-bind="state" @emoji-selected="logEvent('emoji-selected', $event)">My Button</v-emoji-picker>
</template>
</Story>
</template>

View File

@@ -1,41 +0,0 @@
import VFancySelect from './v-fancy-select.vue';
document.body.classList.add('light');
export default {
title: 'Components/VFancySelect',
component: VFancySelect,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-fancy-select v-bind="args" v-on="args" >My Button</v-fancy-select>',
});
export const Primary = Template.bind({});
Primary.args = {
items: [
{
icon: 'person',
value: 'person',
text: 'Person',
},
{
icon: 'directions_car',
value: 'car',
text: 'Car',
},
{
divider: true,
},
{
icon: 'home',
value: 'home',
text: 'Home',
},
],
};

View File

@@ -0,0 +1,43 @@
<script setup lang="ts">
import { ref } from 'vue';
import VFancySelect from './v-fancy-select.vue';
function initState() {
return {
items: [
{
icon: 'person',
value: 'person',
text: 'Person',
},
{
icon: 'directions_car',
value: 'car',
text: 'Car',
},
{
divider: true,
},
{
icon: 'home',
value: 'home',
text: 'Home',
},
],
};
}
const value = ref();
</script>
<template>
<Story title="VFancySelect" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-fancy-select v-model="value" v-bind="state">My Button</v-fancy-select>
</template>
<template #controls>
<HstText v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VHighlight from './v-highlight.vue';
document.body.classList.add('light');
export default {
title: 'Components/VHighlight',
component: VHighlight,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-highlight v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
text: 'The cake is a lie.',
query: ['cake', 'lie'],
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import VHighlight from './v-highlight.vue';
function initState() {
return {
text: 'The cake is a lie.',
query: ['cake', 'lie'],
};
}
</script>
<template>
<Story title="VHighlight" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-highlight v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,21 +0,0 @@
import VHover from './v-hover.vue';
document.body.classList.add('light');
export default {
title: 'Components/VHover',
component: VHover,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template:
'<v-hover v-bind="args" v-on="args" v-slot="{ hover }">Hover me!<div v-if="hover">This is only shown on hover.</div></v-hover>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,14 @@
<script setup lang="ts">
import VHover from './v-hover.vue';
</script>
<template>
<Story title="VHover">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-hover v-slot="{ hover }" v-bind="state">
Hover me!
<div v-if="hover">This is only shown on hover.</div>
</v-hover>
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VIconFile from './v-icon-file.vue';
document.body.classList.add('light');
export default {
title: 'Components/VIconFile',
component: VIconFile,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-icon-file v-bind="args" v-on="args" >My Button</v-icon-file>',
});
export const Primary = Template.bind({});
Primary.args = {
ext: 'png',
};

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import VIconFile from './v-icon-file.vue';
function initState() {
return {
ext: 'png',
};
}
</script>
<template>
<Story title="VIconFile" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-icon-file v-bind="state">My Button</v-icon-file>
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VIcon from './v-icon/v-icon.vue';
document.body.classList.add('light');
export default {
title: 'Components/VIcon',
component: VIcon,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-icon v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
name: 'delete',
};

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import VIcon from './v-icon.vue';
function initState() {
return {
name: 'cruelty_free',
};
}
</script>
<template>
<Story title="VIcon" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-icon v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VInfo from './v-info.vue';
document.body.classList.add('light');
export default {
title: 'Components/VInfo',
component: VInfo,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-info v-bind="args" v-on="args" >You have sadly eaten all the cookies!</v-info>',
});
export const Primary = Template.bind({});
Primary.args = {
title: 'No more cookies',
icon: 'cookie',
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import VInfo from './v-info.vue';
function initState() {
return {
title: 'No More Cookies',
icon: 'cookie',
};
}
</script>
<template>
<Story title="VInfo" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-info v-bind="state">You have sadly eaten all the cookies!</v-info>
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VInput from './v-input.vue';
document.body.classList.add('light');
export default {
title: 'Components/VInput',
component: VInput,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-input v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: 'Shut up and take my money. 💸',
disabled: false,
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { ref } from 'vue';
import VInput from './v-input.vue';
const value = ref('Shut up and take my money. 💸');
</script>
<template>
<Story title="VInput">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-input v-model="value" v-bind="state" />
</template>
<template #controls>
<HstText v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VItemGroup from './v-item-group.vue';
document.body.classList.add('light');
export default {
title: 'Components/VItemGroup',
component: VItemGroup,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template:
'<v-item-group v-bind="args" v-on="args" ><v-item watch value="item1" v-slot="{active}">First item is active: {{active}}</v-item><v-item value="item2" v-slot="{active}">Second item is active: {{active}}</v-item></v-item-group>',
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: ['item1'],
};

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import { ref } from 'vue';
import VItemGroup from './v-item-group.vue';
const value = ref(['item1']);
</script>
<template>
<Story title="VItemGroup">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-item-group v-model="value" v-bind="state">
<v-item v-slot="{ active }" watch value="item1">First item is active: {{ active }}</v-item>
<v-item v-slot="{ active }" value="item2">Second item is active: {{ active }}</v-item>
</v-item-group>
</template>
<template #controls>
<HstJson v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,38 +0,0 @@
import VListGroup from './v-list-group.vue';
document.body.classList.add('light');
export default {
title: 'Components/List/VListGroup',
component: VListGroup,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `
<v-list>
<v-list-item>Item 1 </v-list-item>
<v-list-item>Item 2 </v-list-item>
<v-list-group v-bind="args" v-on="args">
<template #activator="{active}">
<v-list-item>Group Item 3</v-list-item>
</template>
<v-list-item>Item 3-1</v-list-item>
<v-list-item>Item 3-2</v-list-item>
<v-list-item>Item 3-2</v-list-item>
</v-list-group>
<v-list-item>Item 4 </v-list-item>
</v-list>
`,
});
export const Primary = Template.bind({});
Primary.args = {
open: true,
};

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
import VListGroup from './v-list-group.vue';
</script>
<template>
<Story title="VList/VListGroup">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<!-- <v-list>
<v-list-item>Item 1</v-list-item>
<v-list-item>Item 2</v-list-item> -->
<ul class="v-list">
<v-list-group v-bind="state">
<template #activator>
<v-list-item>Group Item 3</v-list-item>
</template>
<v-list-item>Item 3-1</v-list-item>
<v-list-item>Item 3-2</v-list-item>
<v-list-item>Item 3-2</v-list-item>
</v-list-group>
</ul>
<!-- <v-list-item>Item 4</v-list-item>
</v-list> -->
</template>
</Story>
</template>
<style scoped>
.v-list {
list-style: none;
padding: var(--v-list-padding, 4px 0);
}
</style>

View File

@@ -1,22 +0,0 @@
import VListItem from './v-list-item.vue';
document.body.classList.add('light');
export default {
title: 'Components/List/VListItem',
component: VListItem,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `
<v-list-item v-bind="args" v-on="args" >List Item 1</v-list-item>
`,
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VListItem from './v-list-item.vue';
</script>
<template>
<Story title="VList/VListItem">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-list-item v-bind="state">List Item 1</v-list-item>
</template>
</Story>
</template>

View File

@@ -1,28 +0,0 @@
import VList from './v-list.vue';
document.body.classList.add('light');
export default {
title: 'Components/List/VList',
component: VList,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `
<v-list v-bind="args" v-on="args" >
<v-list-item>Item 1 </v-list-item>
<v-list-item>Item 2 </v-list-item>
<v-list-item>Item 3 </v-list-item>
</v-list>
`,
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: [1],
};

View File

@@ -0,0 +1,15 @@
<script setup lang="ts">
import VList from './v-list.vue';
</script>
<template>
<Story title="VList/VList">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-list v-bind="state">
<v-list-item>Item 1</v-list-item>
<v-list-item>Item 2</v-list-item>
<v-list-item>Item 3</v-list-item>
</v-list>
</template>
</Story>
</template>

View File

@@ -1,40 +0,0 @@
import VMenu from './v-menu.vue';
document.body.classList.add('light');
export default {
title: 'Components/VMenu',
component: VMenu,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `
<v-menu v-bind="args" v-on="args" >
<template #activator="{ toggle }">
<v-icon clickable class="options" name="more_vert" @click="toggle" />
</template>
<v-list>
<v-list-item clickable>
<v-list-item-icon><v-icon name="folder_open" /></v-list-item-icon>
<v-list-item-content>
Choose from Library
</v-list-item-content>
</v-list-item>
<v-list-item clickable>
<v-list-item-icon><v-icon name="link" /></v-list-item-icon>
<v-list-item-content>
Choose from Url
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>`,
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,26 @@
<script setup lang="ts">
import VMenu from './v-menu.vue';
</script>
<template>
<Story title="VMenu">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-menu v-bind="state">
<template #activator="{ toggle }">
<v-icon clickable class="options" name="more_vert" @click="toggle" />
</template>
<v-list>
<v-list-item clickable>
<v-list-item-icon><v-icon name="folder_open" /></v-list-item-icon>
<v-list-item-content>Choose from Library</v-list-item-content>
</v-list-item>
<v-list-item clickable>
<v-list-item-icon><v-icon name="link" /></v-list-item-icon>
<v-list-item-content>Choose from Url</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
</template>
</Story>
</template>

View File

@@ -1,25 +0,0 @@
import VNotice from './v-notice.vue';
document.body.classList.add('light');
export default {
title: 'Components/VNotice',
component: VNotice,
argTypes: {
type: {
control: 'select',
options: ['normal', 'info', 'success', 'warning', 'danger'],
},
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-notice v-bind="args" v-on="args" >Making a pizza ist best done without ordering a pizza.</v-notice>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VNotice from './v-notice.vue';
</script>
<template>
<Story title="VNotice">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-notice v-bind="state">Making a pizza ist best done without ordering a pizza.</v-notice>
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VOverlay from './v-overlay.vue';
document.body.classList.add('light');
export default {
title: 'Components/VOverlay',
component: VOverlay,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<div>This is hidden behind the overlay.</div><v-overlay v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
active: true,
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import VOverlay from './v-overlay.vue';
function initState() {
return {
active: true,
};
}
</script>
<template>
<Story title="VOverlay" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-overlay v-bind="state" />
<div>This is hidden behind the overlay.</div>
</template>
</Story>
</template>

View File

@@ -1,24 +0,0 @@
import VPagination from './v-pagination.vue';
document.body.classList.add('light');
export default {
title: 'Components/VPagination',
component: VPagination,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-pagination v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
length: 7,
totalVisible: 4,
modelValue: 3,
};

View File

@@ -0,0 +1,25 @@
<script setup lang="ts">
import { ref } from 'vue';
import VPagination from './v-pagination.vue';
function initState() {
return {
length: 7,
totalVisible: 4,
};
}
const value = ref(3);
</script>
<template>
<Story title="VPagination" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-pagination v-model="value" v-bind="state" />
</template>
<template #controls>
<HstNumber v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VProgressCircular from './v-progress-circular.vue';
document.body.classList.add('light');
export default {
title: 'Components/VProgressCircular',
component: VProgressCircular,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-progress-circular v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
value: 70,
};

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import VProgressCircular from './v-progress-circular.vue';
function initState() {
return {
value: 70,
};
}
</script>
<template>
<Story title="VProgressCircular" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-progress-circular v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VProgressLinear from './v-progress-linear.vue';
document.body.classList.add('light');
export default {
title: 'Components/VProgressLinear',
component: VProgressLinear,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-progress-linear v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
value: 70,
colorful: true,
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import VProgressLinear from './v-progress-linear.vue';
function initState() {
return {
value: 70,
colorful: true,
};
}
</script>
<template>
<Story title="VProgressLinear" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-progress-linear v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,24 +0,0 @@
import VRadio from './v-radio.vue';
document.body.classList.add('light');
export default {
title: 'Components/VRadio',
component: VRadio,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-radio v-bind="args" v-on="args"/>',
});
export const Primary = Template.bind({});
Primary.args = {
value: '1',
label: 'My Radio',
modelValue: '1',
};

View File

@@ -0,0 +1,19 @@
<script setup lang="ts">
import VRadio from './v-radio.vue';
function initState() {
return {
value: '1',
label: 'My Radio',
modelValue: '1',
};
}
</script>
<template>
<Story title="VRadio" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-radio v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,36 +0,0 @@
import VSelect from './v-select/v-select.vue';
document.body.classList.add('light');
export default {
title: 'Components/VSelect',
component: VSelect,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `<v-select v-bind="args" v-on="args"></v-select>`,
});
export const Primary = Template.bind({});
Primary.args = {
items: [
{
text: 'Item 1',
value: 'item1',
},
{
text: 'Item 2',
value: 'item2',
},
{
text: 'Item 3',
value: 'item3',
},
],
modelValue: 'item2',
};

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import { ref } from 'vue';
import VSelect from './v-select.vue';
function initState() {
return {
items: [
{
text: 'Item 1',
value: 'item1',
},
{
text: 'Item 2',
value: 'item2',
},
{
text: 'Item 3',
value: 'item3',
},
],
};
}
const value = ref('item2');
</script>
<template>
<Story title="VSelect" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-select v-model="value" v-bind="state" />
</template>
<template #controls>
<HstText v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,21 +0,0 @@
import VSheet from './v-sheet.vue';
document.body.classList.add('light');
export default {
title: 'Components/VSheet',
component: VSheet,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template:
'<v-sheet v-bind="args" v-on="args" >This is some wanky sheet that is not even used inside Directus.</v-sheet>',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VSheet from './v-sheet.vue';
</script>
<template>
<Story title="VSheet">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-sheet v-bind="state">This is some wanky sheet that is not even used inside Directus.</v-sheet>
</template>
</Story>
</template>

View File

@@ -1,25 +0,0 @@
import VSkeletonLoader from './v-skeleton-loader.vue';
document.body.classList.add('light');
export default {
title: 'Components/VSkeletonLoader',
component: VSkeletonLoader,
argTypes: {
type: {
control: 'select',
options: ['input', 'input-tall', 'block-list-item', 'block-list-item-dense', 'text', 'list-item-icon'],
},
},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-skeleton-loader v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
Primary.args = {};

View File

@@ -0,0 +1,11 @@
<script setup lang="ts">
import VSkeletonLoader from './v-skeleton-loader.vue';
</script>
<template>
<Story title="VSkeletonLoader">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-skeleton-loader v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,31 +0,0 @@
import VSlider from './v-slider.vue';
document.body.classList.add('light');
// More on default export: https://storybook.js.org/docs/vue/writing-stories/introduction#default-export
export default {
title: 'Components/VSlider',
component: VSlider,
// More on argTypes: https://storybook.js.org/docs/vue/api/argtypes
argTypes: {
'update:modelValue': { action: 'update:modelValue' },
},
};
// More on component templates: https://storybook.js.org/docs/vue/writing-stories/introduction#using-args
const Template = (args) => ({
// The story's `args` need to be mapped into the template through the `setup()` method
setup() {
return { args };
},
// And then the `args` are bound to your component with `v-bind="args" v-on="args"`
template: '<v-slider v-bind="args" v-on="args" />',
});
export const Primary = Template.bind({});
// More on args: https://storybook.js.org/docs/vue/writing-stories/args
Primary.args = {
modelValue: 50,
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { ref } from 'vue';
import VSlider from './v-slider.vue';
const value = ref(50);
</script>
<template>
<Story title="VSlider">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-slider v-model="value" v-bind="state" />
</template>
<template #controls>
<HstNumber v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,41 +0,0 @@
import VTabs from './v-tabs.vue';
document.body.classList.add('light');
export default {
title: 'Components/VTabs',
component: VTabs,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: `
<div>
<v-tabs v-bind="args" v-on="args" >
<v-tab>Foods</v-tab>
<v-tab>Drinks</v-tab>
<v-tab>Extras</v-tab>
</v-tabs>
<v-tabs-items :modelValue="args.modelValue">
<v-tab-item>
<h1>This is the first page</h1>
</v-tab-item>
<v-tab-item>
<h1>This is the second page</h1>
</v-tab-item>
<v-tab-item>
<h1>This is the third page</h1>
</v-tab-item>
</v-tabs-items>
</div>
`,
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: [1],
};

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue';
import VTabs from './v-tabs.vue';
const value = ref([1]);
</script>
<template>
<Story title="VTabs">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-tabs v-model="value" v-bind="state">
<v-tab>Foods</v-tab>
<v-tab>Drinks</v-tab>
<v-tab>Extras</v-tab>
</v-tabs>
<v-tabs-items :model-value="value">
<v-tab-item>
<h1>This is the first page</h1>
</v-tab-item>
<v-tab-item>
<h1>This is the second page</h1>
</v-tab-item>
<v-tab-item>
<h1>This is the third page</h1>
</v-tab-item>
</v-tabs-items>
</template>
<template #controls>
<HstJson v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,29 +0,0 @@
import VTemplateInput from './v-template-input.vue';
document.body.classList.add('light');
export default {
title: 'Components/VTemplateInput',
component: VTemplateInput,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-template-input v-bind="args" v-on="args" >My Template Input</v-template-input>',
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: 'Hey ho everyone, I am a new comment!',
multiline: true,
'trigger-character': '@',
items: {
item1: 'Test1',
item2: 'Test2',
},
captureGroup: '(@[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12})',
};

View File

@@ -0,0 +1,39 @@
<script setup lang="ts">
import { ref } from 'vue';
import VTemplateInput from './v-template-input.vue';
import { logEvent } from 'histoire/client';
function initState() {
return {
multiline: true,
'trigger-character': '@',
items: {
item1: 'Test1',
item2: 'Test2',
},
captureGroup: '(@[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12})',
};
}
const value = ref('Hey ho everyone, I am a new comment!');
</script>
<template>
<Story title="VTemplateInput" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-template-input
v-model="value"
v-bind="state"
@trigger="logEvent('trigger', $event)"
@deactivate="logEvent('deactivate', $event)"
@up="logEvent('up', $event)"
@down="logEvent('down', $event)"
@enter="logEvent('enter', $event)"
/>
</template>
<template #controls>
<HstText v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,22 +0,0 @@
import VTextOverflow from './v-text-overflow.vue';
document.body.classList.add('light');
export default {
title: 'Components/VTextOverflow',
component: VTextOverflow,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-text-overflow v-bind="args" v-on="args"></v-text-overflow>',
});
export const Primary = Template.bind({});
Primary.args = {
text: 'This text should not wrap to a new line!',
};

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import VTextOverflow from './v-text-overflow.vue';
function initState() {
return {
text: 'This text should not wrap to a new line!',
placement: 'bottom',
};
}
</script>
<template>
<Story title="VTextOverflow" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-text-overflow v-bind="state" />
</template>
</Story>
</template>

View File

@@ -1,23 +0,0 @@
import VTextarea from './v-textarea.vue';
document.body.classList.add('light');
export default {
title: 'Components/VTextarea',
component: VTextarea,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-textarea v-bind="args" v-on="args" >My Button</v-textarea>',
});
export const Primary = Template.bind({});
Primary.args = {
modelValue: `This is some text that will be displayed in the textarea.
This is a new line.`,
};

View File

@@ -0,0 +1,19 @@
<script setup lang="ts">
import { ref } from 'vue';
import VTextarea from './v-textarea.vue';
const value = ref(`This is some text that will be displayed in the textarea.
This is a new line.`);
</script>
<template>
<Story title="VTextarea">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-textarea v-model="value" v-bind="state" />
</template>
<template #controls>
<HstTextarea v-model="value" title="Value" />
</template>
</Story>
</template>

View File

@@ -1,27 +0,0 @@
import VWorkspaceTile from './v-workspace-tile.vue';
document.body.classList.add('light');
export default {
title: 'Components/VWorkspaceTile',
component: VWorkspaceTile,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-workspace-tile v-bind="args" v-on="args" >Contents of the tile</v-workspace-tile>',
});
export const Primary = Template.bind({});
Primary.args = {
name: 'My Tile',
id: '1',
x: 0,
y: 0,
width: 10,
height: 10,
};

View File

@@ -0,0 +1,22 @@
<script setup lang="ts">
import VWorkspaceTile from './v-workspace-tile.vue';
function initState() {
return {
name: 'My Tile',
id: '1',
x: 0,
y: 0,
width: 10,
height: 10,
};
}
</script>
<template>
<Story title="VWorkspaceTile" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-workspace-tile v-bind="state">Contents of the tile</v-workspace-tile>
</template>
</Story>
</template>

View File

@@ -1,40 +0,0 @@
import VWorkspace from './v-workspace.vue';
document.body.classList.add('light');
export default {
title: 'Components/VWorkspace',
component: VWorkspace,
argTypes: {},
};
const Template = (args) => ({
setup() {
return { args };
},
template: '<v-workspace v-bind="args" v-on="args" ></v-workspace>',
});
export const Primary = Template.bind({});
Primary.args = {
editMode: false,
tiles: [
{
id: '1',
x: 1,
y: 1,
width: 10,
height: 10,
name: 'My Tile 1',
},
{
id: '2',
x: 15,
y: 5,
width: 10,
height: 10,
name: 'My Tile 2',
},
],
};

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
import VWorkspace from './v-workspace.vue';
function initState() {
return {
editMode: false,
tiles: [
{
id: '1',
x: 1,
y: 1,
width: 10,
height: 10,
name: 'My Tile 1',
},
{
id: '2',
x: 15,
y: 5,
width: 10,
height: 10,
name: 'My Tile 2',
},
],
};
}
</script>
<template>
<Story title="VWorkspace" :init-state="initState">
<template #default="{ state: { _hPropState, _hPropDefs, $data: _, ...state } }">
<v-workspace v-bind="state" />
</template>
</Story>
</template>

View File

@@ -0,0 +1,119 @@
import type { App } from 'vue';
import ContextMenu from '@/directives//context-menu';
import Focus from '@/directives//focus';
import Tooltip from '@/directives//tooltip';
import ClickOutside from '@/directives/click-outside';
import TransitionBounce from '@/components/transition/bounce.vue';
import TransitionDialog from '@/components/transition/dialog.vue';
import TransitionExpand from '@/components/transition/expand.vue';
import VAvatar from '@/components/v-avatar.vue';
import VBadge from '@/components/v-badge.vue';
import VBreadcrumb from '@/components/v-breadcrumb.vue';
import VButton from '@/components/v-button.vue';
import VCardActions from '@/components/v-card-actions.vue';
import VCardSubtitle from '@/components/v-card-subtitle.vue';
import VCardText from '@/components/v-card-text.vue';
import VCardTitle from '@/components/v-card-title.vue';
import VCard from '@/components/v-card.vue';
import VCheckboxTree from '@/components/v-checkbox-tree/v-checkbox-tree.vue';
import VCheckbox from '@/components/v-checkbox.vue';
import VChip from '@/components/v-chip.vue';
import VDivider from '@/components/v-divider.vue';
import VEmojiPicker from '@/components/v-emoji-picker.vue';
import VFancySelect from '@/components/v-fancy-select.vue';
import VHighlight from '@/components/v-highlight.vue';
import VHover from '@/components/v-hover.vue';
import VIconFile from '@/components/v-icon-file.vue';
import VIcon from '@/components/v-icon/v-icon.vue';
import VInfo from '@/components/v-info.vue';
import VInput from '@/components/v-input.vue';
import VItemGroup from '@/components/v-item-group.vue';
import VItem from '@/components/v-item.vue';
import VListGroup from '@/components/v-list-group.vue';
import VListItemContent from '@/components/v-list-item-content.vue';
import VListItemHint from '@/components/v-list-item-hint.vue';
import VListItemIcon from '@/components/v-list-item-icon.vue';
import VListItem from '@/components/v-list-item.vue';
import VList from '@/components/v-list.vue';
import VMenu from '@/components/v-menu.vue';
import VNotice from '@/components/v-notice.vue';
import VOverlay from '@/components/v-overlay.vue';
import VPagination from '@/components/v-pagination.vue';
import VProgressCircular from '@/components/v-progress-circular.vue';
import VProgressLinear from '@/components/v-progress-linear.vue';
import VRadio from '@/components/v-radio.vue';
import VSelect from '@/components/v-select/v-select.vue';
import VSheet from '@/components/v-sheet.vue';
import VSkeletonLoader from '@/components/v-skeleton-loader.vue';
import VSlider from '@/components/v-slider.vue';
import VTabItem from '@/components/v-tab-item.vue';
import VTab from '@/components/v-tab.vue';
import VTabsItems from '@/components/v-tabs-items.vue';
import VTabs from '@/components/v-tabs.vue';
import VTemplateInput from '@/components/v-template-input.vue';
import VTextOverflow from '@/components/v-text-overflow.vue';
import VTextarea from '@/components/v-textarea.vue';
import VWorkspaceTile from '@/components/v-workspace-tile.vue';
import VWorkspace from '@/components/v-workspace.vue';
export function register(app: App): void {
app.directive('context-menu', ContextMenu);
app.directive('focus', Focus);
app.directive('tooltip', Tooltip);
app.directive('click-outside', ClickOutside);
app.component('TransitionBounce', TransitionBounce);
app.component('TransitionDialog', TransitionDialog);
app.component('TransitionExpand', TransitionExpand);
app.component('VAvatar', VAvatar);
app.component('VBadge', VBadge);
app.component('VBreadcrumb', VBreadcrumb);
app.component('VButton', VButton);
app.component('VCard', VCard);
app.component('VCardActions', VCardActions);
app.component('VCardSubtitle', VCardSubtitle);
app.component('VCardText', VCardText);
app.component('VCardTitle', VCardTitle);
app.component('VCheckbox', VCheckbox);
app.component('VCheckboxTree', VCheckboxTree);
app.component('VChip', VChip);
app.component('VDivider', VDivider);
app.component('VEmojiPicker', VEmojiPicker);
app.component('VFancySelect', VFancySelect);
app.component('VHighlight', VHighlight);
app.component('VHover', VHover);
app.component('VIcon', VIcon);
app.component('VIconFile', VIconFile);
app.component('VInfo', VInfo);
app.component('VInput', VInput);
app.component('VItem', VItem);
app.component('VItemGroup', VItemGroup);
app.component('VList', VList);
app.component('VListGroup', VListGroup);
app.component('VListItem', VListItem);
app.component('VListItemContent', VListItemContent);
app.component('VListItemHint', VListItemHint);
app.component('VListItemIcon', VListItemIcon);
app.component('VMenu', VMenu);
app.component('VNotice', VNotice);
app.component('VOverlay', VOverlay);
app.component('VPagination', VPagination);
app.component('VProgressCircular', VProgressCircular);
app.component('VProgressLinear', VProgressLinear);
app.component('VRadio', VRadio);
app.component('VSelect', VSelect);
app.component('VSheet', VSheet);
app.component('VSkeletonLoader', VSkeletonLoader);
app.component('VSlider', VSlider);
app.component('VTab', VTab);
app.component('VTabItem', VTabItem);
app.component('VTabs', VTabs);
app.component('VTabsItems', VTabsItems);
app.component('VTemplateInput', VTemplateInput);
app.component('VTextOverflow', VTextOverflow);
app.component('VTextarea', VTextarea);
app.component('VWorkspaceTile', VWorkspaceTile);
app.component('VWorkspace', VWorkspace);
}

42
app/src/histoire/setup.ts Normal file
View File

@@ -0,0 +1,42 @@
import { defineSetupVue3 } from '@histoire/plugin-vue';
import { createHead } from '@unhead/vue';
import { createPinia } from 'pinia';
import { createI18n } from 'vue-i18n';
import { createMemoryHistory, createRouter } from 'vue-router';
import datetimeFormats from '@/lang/date-formats.yaml';
import numberFormats from '@/lang/number-formats.yaml';
import enUSBase from '@/lang/translations/en-US.yaml';
import { register } from './register';
import Wrapper from './wrapper.vue';
export const setupVue3 = defineSetupVue3(({ app, addWrapper }) => {
app.use(
createRouter({
history: createMemoryHistory(),
routes: [{ path: '/:catchAll(.*)', name: 'all', component: { render: () => null } }],
}),
);
app.use(
createI18n({
legacy: false,
locale: 'en-US',
fallbackLocale: 'en-US',
messages: {
'en-US': enUSBase,
},
silentTranslationWarn: true,
datetimeFormats,
numberFormats,
}),
);
app.use(createPinia());
app.use(createHead());
register(app);
addWrapper(Wrapper);
});

View File

@@ -0,0 +1,102 @@
<script setup lang="ts">
import { rulesToCssVars, useTheme } from '@directus/themes';
import { useMutationObserver } from '@vueuse/core';
import { computed, ref, watch } from 'vue';
import '@/styles/_variables.scss';
const isIframe = window.self !== window.top;
const topHtmlElement = window.top?.document.documentElement;
const iframe = window.self.document;
if (isIframe && topHtmlElement) {
iframe.documentElement.classList.add('custom-html');
for (const teleportTargetId of ['dialog-outlet', 'menu-outlet']) {
const existingElement = window.self.document.getElementById(teleportTargetId);
if (existingElement) continue;
const element = document.createElement('div');
element.setAttribute('id', teleportTargetId);
iframe.body.appendChild(element);
}
const darkMode = ref(topHtmlElement.classList.contains('htw-dark'));
useMutationObserver(
topHtmlElement,
(mutations) => {
const isClassMutation = mutations.some((mutation) => mutation.attributeName == 'class');
if (!isClassMutation) return;
const hasDarkModeClass = topHtmlElement.classList.contains('htw-dark');
if (hasDarkModeClass !== darkMode.value) {
darkMode.value = hasDarkModeClass;
}
},
{ attributes: true },
);
watch(
darkMode,
(value) => {
iframe.body.classList.add(value ? 'dark' : 'light');
iframe.body.classList.remove(value ? 'light' : 'dark');
},
{ immediate: true },
);
const { theme } = useTheme(darkMode, null, null, {}, {});
const cssString = computed(() => {
const cssVariables = rulesToCssVars(theme.value.rules);
cssVariables['--project-color'] = '#6644ff';
const variables = `:root {${Object.entries(cssVariables)
.map(([key, value]) => `${key}: ${value};`)
.join(' ')}}`;
return variables;
});
watch(
cssString,
(value) => {
const existingStyle = window.self.document.querySelector('head > style#theme');
if (existingStyle) {
existingStyle.textContent = value;
} else {
const style = document.createElement('style');
style.setAttribute('id', 'theme');
style.textContent = value;
window.self.document.head.appendChild(style);
}
},
{ immediate: true },
);
}
</script>
<template>
<div class="custom-wrapper">
<slot />
</div>
</template>
<style lang="scss">
.custom-html {
@import '@/styles/main';
}
.histoire-generic-render-story:not(.__histoire-render-custom-controls) .custom-wrapper {
position: relative;
height: calc(100vh - 2 * 24px);
padding: 24px;
background-color: var(--theme--background);
}
</style>

4169
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff