-
-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow pages to be added to stories. #159
Comments
Guys, I am also trying to find a way to expose my page component but no success till now. I've posted it in the Discord channel, any updates I will share it here =)
|
Guys, any idea on that?! To be able to add my pages to Storybook I was thinking of having 2 components to compose a page like described below:
<template>
<!-- Probably not much template will be left for this component -->
<my-main-inner ...many-props />
</template>
<script>
// all the logic that cannot be handled by Storybook
// this will do all the needed communication with the MainInner through props and events
</script>
<template>
<div>Whatever I have to do here</div>
</template>
<script>
// This will be a 'dump-component' and all the this that cannot be handled by Storybook
// will be injected from the `Main.vue`
</script> Any feedback on it? |
Trying to do the same, but could not have luck. I also tried adding to
It doesn't help. |
Having a Props-based Page-like component that gets hydrated by storybook stories with mock-data and by nuxt's page component with real data is my go-to strategy as well. I think it's clean, it works well and it's straightforward. Did you follow up with it? I'm going to implement it in a project real soon |
The naming stinks Main and MainInner :( |
My "page components" live inside the |
What about the layout? Or you're just fine with stopping at the page. I once tried to go down the rabbit hole of trying to figure out how to render the App.js file generated by nuxt in storybook, but didn't get very far. |
What do you mean by layout? And why would you render the App.js file? Storybook is meant to validate and showcase your components/pages, it shouldn't be able to tinker with your entire application. |
In my regular vue applications (that i'd use for things like admin sections, etc.) I have top-level stories in which I mock the router and show the entire page as it would be rendered in the browser (so you'd see the header, menus, etc., in addition to whatever that route would render) |
Which, in my opinion, should be a page component + a global decorator with whatever the layout has (e.g: menu, footer etc) |
what do you do in the decorator...mock the component so that it shows the given page? |
I decorate the page with whatever component would be in the |
Not sure I understand you: That component usually looks like
how exactly are you using it to "decorate"? |
My layout: My IndexPage story: import IndexPage from '~/components/IndexPage'
// Mimics the layout behaviour
const layoutDecorator = (story) => ({
components: { story },
template: `
<div> <Menu/> <story /> <Footer /></div>
`
})
export default {
title: 'IndexPage',
decorators: [layoutDecorator]
}
const Template = (args, { argTypes }) => ({
components: IndexPage,
template: '<IndexPage />'
})
export const Page = Template.bind({}) |
ok...but you're duplicating your whole layout in the story... |
Yes. But as I said, layout behaviour should be separate from stories. Stories needs to be agnostic and introducing a ubercharged dynamic component like the |
My suggestion was have the decorator replace the component with , basically...not to use it as is
I don't mean copying the layoutDecorator code...I mean duplicating the layout itself...if you change the layout code you'd have to change the decorator. I suppose a potential way around that is to make "yet another" component for your layout which accepts a slot so
still, I miss the ability to just tell storybook "render me whatever is at router /foo/bar/23" |
Your solution is better. If you want to render whatever is at router /foo/bar/23 run the nuxt sever 😅 If you want to use storybook as it's meant to be used (with mocked data, component statuses etc) the way we paved in the comments above is the right way IMHO. |
without talking to a server...all data mocked with msw. |
Then again, I stand by my point. Using components composition and building stories on top of agnostic components (that can both work alone and inside nuxt supercharged components) is the way to go. |
I ended up with the solution based on @blocka's suggestion. I created a global decorator with the layout name-to-component map. As long as I declare the page component in the story's // preview.js
const layoutDecorator = (story, { parameters }) => {
const layouts = {
'my-custom': () => import('~/components/layout/MyCustomlayout.vue'),
}
const layoutFallbackComponent = {
template: '<div class="layout-not-found"><slot /></div>',
}
const pageLayout = parameters.component?.options?.layout
const LayoutComponent = layouts[pageLayout] ?? layoutFallbackComponent
return {
components: { story, LayoutComponent },
template: '<LayoutComponent><story /></LayoutComponent>',
}
}
export const decorators = [layoutDecorator] // some.story.js
export default {
title: 'pages/some-page',
component: SomePage,
} The downside is that you still have to maintain the layout map, but at least it's a simple key/value and could probably be extracted from the layouts directory by reading the raw files to go a step beyond. |
I could simulate pages on storybook to replace /** .storybook/preview.js */
import Vue from 'vue'
Vue.component('nuxt', {
render() {
// this.$root.$children[0].$children[0] is <layout-component />
return this.$root.$children[0].$children[0].$slots.default
}
})
export * from '../.nuxt-storybook/storybook/preview.js'
/** pages/foo/bar.stories.ts */
import { defineComponent, useRouter } from '@nuxtjs/composition-api'
import PageComponent from '@/pages/foo/bar.vue'
const LayoutComponent = require(`@/layouts/${PageComponent.layout}.vue`).default
export default {
title: 'pages/foo/bar'
component: PageComponent
}
export const FooBar = () => defineComponent({
components: { LayoutComponent, PageComponent },
template: '<layout-component><page-component /><layout-component>'
}) But I could not deal with pages which can be shown after login process because a redirection after login avoided to display an expected pages. I ended up with the solution not to use /** .storybook/preview.js */
export * from '../.nuxt-storybook/storybook/preview.js'
/** pages/foo/bar.stories.ts */
import { defineComponent, useRouter } from '@nuxtjs/composition-api'
import PageComponent from '@/pages/foo/bar.vue'
const LayoutComponent = require(`@/layouts/${PageComponent.layout}.vue`).default
export default {
title: 'pages/foo/bar'
component: PageComponent
}
export const FooBar = () => defineComponent({
components: { LayoutComponent },
template: '<layout-component v-if="!fetchState.pending" />'
setup: () => {
const router = useRouter()
const { $auth } = useContext()
const { fetch, fetchState } = useFetch(async () => {
await $auth.logout()
await $auth.loginWith('local', {userId: 'xxx', password: 'xxx'}) // I use msw to simulate mock api server.
router.push({ path: '/foo/bar', query: { id: '1' } })
})
fetch()
return { fetchState }
}
}) |
Thanks to the @ishikawa-yuya-functional-inc comment above, I kinda manage to add pages to my storybook. However, I made a small change to the render function: import Vue from 'vue';
// My auth pages layout
import auth from '@/layouts/auth';
// Override the Nuxt component
Vue.component('Nuxt', {
render() {
return this.$parent.$slots.default;
},
});
export default {
title: 'Pages/Login',
decorators: [() => ({
components: {
auth,
},
// Surround stories with the layout
template: '<auth><story /></auth>',
})],
}; |
Is your feature request related to a problem? Please describe.
We often use storybook stories to allow users to see built out pages using components.
Describe the solution you'd like
Allow pages in the Nuxt Pages directory to be added to stories.
Describe alternatives you've considered
Make copies of the pages as components.
Additional context
The text was updated successfully, but these errors were encountered: