feat: add histoire #2724

Merged
konrad merged 4 commits from dpschen/frontend:feature/add-histoire into main 2023-01-06 09:27:11 +00:00
19 changed files with 1128 additions and 18 deletions

3
.gitignore vendored
View File

@ -36,3 +36,6 @@ cypress/videos
# Local Netlify folder
.netlify
# histoire
.histoire

1
env.d.ts vendored
View File

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

34
histoire.config.ts Normal file
View File

@ -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',
},
})

View File

@ -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",

File diff suppressed because it is too large Load Diff

View File

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

Do we need this in every story?

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.

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.

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.

To be clear: we create here mock targets for the router.
],
}))
}
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>

View File

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

View File

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

View File

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

View File

@ -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',

View File

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

25
src/histoire.setup.ts Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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