feat: add histoire #2724
|
@ -36,3 +36,6 @@ cypress/videos
|
|||
|
||||
# Local Netlify folder
|
||||
.netlify
|
||||
|
||||
# histoire
|
||||
.histoire
|
|
@ -1,6 +1,7 @@
|
|||
/// <reference types="vite/client" />
|
||||
/// <reference types="vite-svg-loader" />
|
||||
/// <reference types="cypress" />
|
||||
/// <reference types="@histoire/plugin-vue/components" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_IS_ONLINE: boolean
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {defineConfig, defaultColors} from 'histoire'
|
||||
import {HstVue} from '@histoire/plugin-vue'
|
||||
import {HstScreenshot} from '@histoire/plugin-screenshot'
|
||||
|
||||
export default defineConfig({
|
||||
setupFile: './src/histoire.setup.ts',
|
||||
storyIgnored: [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
// see https://kolaente.dev/vikunja/frontend/pulls/2724#issuecomment-42012
|
||||
'**/.direnv/**',
|
||||
],
|
||||
plugins: [
|
||||
HstVue(),
|
||||
HstScreenshot({
|
||||
// Options here
|
||||
}),
|
||||
],
|
||||
theme: {
|
||||
title: 'Vikunja',
|
||||
colors: {
|
||||
// https://histoire.dev/guide/config.html#builtin-colors
|
||||
gray: defaultColors.zinc,
|
||||
primary: defaultColors.cyan,
|
||||
},
|
||||
// logo: {
|
||||
// square: './img/square.png',
|
||||
// light: './img/light.png',
|
||||
// dark: './img/dark.png',
|
||||
// },
|
||||
// logoHref: 'https://acme.com',
|
||||
// favicon: './favicon.ico',
|
||||
},
|
||||
})
|
|
@ -19,7 +19,10 @@
|
|||
"browserslist:update": "pnpm dlx browserslist@latest --update-db",
|
||||
"fonts:update": "pnpm fonts:download && pnpm fonts:subset",
|
||||
"fonts:download": "./scripts/fonts-download.sh",
|
||||
"fonts:subset": "./scripts/fonts-subset.sh"
|
||||
"fonts:subset": "./scripts/fonts-subset.sh",
|
||||
"story:dev": "histoire dev",
|
||||
"story:build": "histoire build",
|
||||
"story:preview": "histoire preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.2.1",
|
||||
|
@ -74,6 +77,8 @@
|
|||
"@cypress/vite-dev-server": "5.0.2",
|
||||
"@cypress/vue": "5.0.3",
|
||||
"@faker-js/faker": "7.6.0",
|
||||
"@histoire/plugin-screenshot": "0.12.4",
|
||||
"@histoire/plugin-vue": "0.12.4",
|
||||
"@rushstack/eslint-patch": "1.2.0",
|
||||
"@types/codemirror": "5.60.6",
|
||||
"@types/dompurify": "2.4.0",
|
||||
|
@ -99,6 +104,7 @@
|
|||
"eslint": "8.31.0",
|
||||
"eslint-plugin-vue": "9.8.0",
|
||||
"happy-dom": "8.1.1",
|
||||
"histoire": "0.12.4",
|
||||
"netlify-cli": "12.5.0",
|
||||
"postcss": "8.4.20",
|
||||
"postcss-easing-gradients": "3.0.1",
|
||||
|
|
947
pnpm-lock.yaml
947
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,58 @@
|
|||
<script lang="ts" setup>
|
||||
import {logEvent} from 'histoire/client'
|
||||
import {reactive} from 'vue'
|
||||
import {createRouter, createMemoryHistory} from 'vue-router'
|
||||
import BaseButton from './BaseButton.vue'
|
||||
|
||||
function setupApp({ app }) {
|
||||
// Router mock
|
||||
app.use(createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes: [
|
||||
{ path: '/', name: 'home', component: { render: () => null } },
|
||||
konrad marked this conversation as resolved
Outdated
|
||||
],
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
const state = reactive({
|
||||
disabled: false,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story :setup-app="setupApp" :layout="{ type: 'grid', width: '200px' }">
|
||||
<Variant title="custom">
|
||||
<template #controls>
|
||||
<HstCheckbox v-model="state.disabled" title="Disabled" />
|
||||
</template>
|
||||
<BaseButton :disabled="state.disabled">
|
||||
Hello!
|
||||
</BaseButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="disabled">
|
||||
<BaseButton disabled>
|
||||
Hello!
|
||||
</BaseButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="router link">
|
||||
<BaseButton :to="'home'">
|
||||
Hello!
|
||||
</BaseButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="external link">
|
||||
<BaseButton href="https://vikunja.io">
|
||||
Hello!
|
||||
</BaseButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="button">
|
||||
<BaseButton @click="logEvent('Click', $event)">
|
||||
Hello!
|
||||
</BaseButton>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
|
@ -61,12 +61,12 @@ export type BaseButtonTypes = typeof BASE_BUTTON_TYPES_MAP[keyof typeof BASE_BUT
|
|||
|
||||
import {unrefElement} from '@vueuse/core'
|
||||
import {ref, type HTMLAttributes} from 'vue'
|
||||
import type {RouteLocationNamedRaw} from 'vue-router'
|
||||
import type {RouteLocationRaw} from 'vue-router'
|
||||
|
||||
export interface BaseButtonProps extends HTMLAttributes {
|
||||
type?: BaseButtonTypes
|
||||
disabled?: boolean
|
||||
to?: RouteLocationNamedRaw
|
||||
to?: RouteLocationRaw
|
||||
href?: string
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts" setup>
|
||||
import {logEvent} from 'histoire/client'
|
||||
import XButton from './button.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story :layout="{ type: 'grid', width: '200px' }">
|
||||
<Variant title="primary">
|
||||
<XButton @click="logEvent('Click', $event)" variant="primary">
|
||||
Order pizza!
|
||||
</XButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="secondary">
|
||||
<XButton @click="logEvent('Click', $event)" variant="secondary">
|
||||
Order spaghetti!
|
||||
</XButton>
|
||||
</Variant>
|
||||
|
||||
<Variant title="tertiary">
|
||||
<XButton @click="logEvent('Click', $event)" variant="tertiary">
|
||||
Order tortellini!
|
||||
</XButton>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
|
@ -0,0 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import {reactive} from 'vue'
|
||||
import ColorPicker from './ColorPicker.vue'
|
||||
|
||||
const state = reactive({
|
||||
color: '#f2f2f2',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story :layout="{ type: 'grid', width: '200px' }">
|
||||
<ColorPicker v-model="state.color" />
|
||||
</Story>
|
||||
</template>
|
|
@ -37,6 +37,7 @@
|
|||
<script setup lang="ts">
|
||||
import {computed, ref, toRef, watch} from 'vue'
|
||||
import {createRandomID} from '@/helpers/randomId'
|
||||
import XButton from '@/components/input/button.vue'
|
||||
|
||||
const DEFAULT_COLORS = [
|
||||
'#1973ff',
|
|
@ -0,0 +1,11 @@
|
|||
<script lang="ts" setup>
|
||||
import Card from './card.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Story :layout="{ type: 'grid', width: '200px' }">
|
||||
<Card>
|
||||
Card content
|
||||
</Card>
|
||||
</Story>
|
||||
</template>
|
|
@ -0,0 +1,25 @@
|
|||
import { defineSetupVue3 } from '@histoire/plugin-vue'
|
||||
import {i18n} from './i18n'
|
||||
|
||||
// import './histoire.css' // Import global CSS
|
||||
import './styles/global.scss'
|
||||
|
||||
import {createPinia} from 'pinia'
|
||||
|
||||
import FontAwesomeIcon from '@/components/misc/Icon'
|
||||
import XButton from '@/components/input/button.vue'
|
||||
import Modal from '@/components/misc/modal.vue'
|
||||
import Card from '@/components/misc/card.vue'
|
||||
|
||||
|
||||
export const setupVue3 = defineSetupVue3(({ app }) => {
|
||||
// Add Pinia store
|
||||
const pinia = createPinia()
|
||||
app.use(pinia)
|
||||
app.use(i18n)
|
||||
|
||||
app.component('icon', FontAwesomeIcon)
|
||||
app.component('XButton', XButton)
|
||||
app.component('modal', Modal)
|
||||
app.component('card', Card)
|
||||
})
|
|
@ -115,7 +115,7 @@ import {useI18n} from 'vue-i18n'
|
|||
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
import Editor from '@/components/input/AsyncEditor'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
|
||||
import LabelModel from '@/models/label'
|
||||
import type {ILabel} from '@/modelTypes/ILabel'
|
||||
|
|
|
@ -40,7 +40,7 @@ import {useI18n} from 'vue-i18n'
|
|||
import {useRouter} from 'vue-router'
|
||||
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
|
||||
import LabelModel from '@/models/label'
|
||||
import {useLabelStore} from '@/stores/labels'
|
||||
|
|
|
@ -39,7 +39,7 @@ import {useRouter, useRoute} from 'vue-router'
|
|||
import ListService from '@/services/list'
|
||||
import ListModel from '@/models/list'
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
|
||||
import {success} from '@/message'
|
||||
import {useTitle} from '@/composables/useTitle'
|
||||
|
|
|
@ -75,7 +75,7 @@ import {useRouter} from 'vue-router'
|
|||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import Editor from '@/components/input/AsyncEditor'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
|
||||
import type {IList} from '@/modelTypes/IList'
|
||||
|
|
|
@ -50,7 +50,7 @@ import {useRouter} from 'vue-router'
|
|||
|
||||
import Message from '@/components/misc/message.vue'
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
|
||||
import NamespaceModel from '@/models/namespace'
|
||||
import NamespaceService from '@/services/namespace'
|
||||
|
|
|
@ -62,7 +62,7 @@ import router from '@/router'
|
|||
|
||||
import AsyncEditor from '@/components/input/AsyncEditor'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
|
||||
import NamespaceService from '@/services/namespace'
|
||||
|
|
|
@ -465,7 +465,7 @@ import BaseButton from '@/components/base/BaseButton.vue'
|
|||
// partials
|
||||
import Attachments from '@/components/tasks/partials/attachments.vue'
|
||||
import ChecklistSummary from '@/components/tasks/partials/checklist-summary.vue'
|
||||
import ColorPicker from '@/components/input/colorPicker.vue'
|
||||
import ColorPicker from '@/components/input/ColorPicker.vue'
|
||||
import Comments from '@/components/tasks/partials/comments.vue'
|
||||
import CreatedUpdated from '@/components/tasks/partials/createdUpdated.vue'
|
||||
import Datepicker from '@/components/input/datepicker.vue'
|
||||
|
|
Reference in New Issue
Do we need this in every story?
Only where wewant to use the router. It can also be done in the global setup. I didn't want to do this so that we also have the option to test components without router. Could be abstracted into a function if we want to reuse it in other component stories later. But as of now it's only used here.
Yeah makes sense. Let's keep it like this for now and abstract it out if needed in more than one place.
To be clear: we create here mock targets for the router.