[Angular | Storybook] Tailwind, Directives, Content Projection, Icons and i18n
Install packages
npm i -D @nx/storybook
npm i -D @storybook/angular
Create config
nx g @nx/storybook:configuration <project-name>
I created the config inside the main app to share some configs/modules. My stories are located at libs/shared/ui
. That's why I had to add these lines to the config files.
// .storybook/main.ts
const config: StorybookConfig = {
stories: [
'../src/app/**/*.stories.@(js|jsx|ts|tsx|mdx)',
'../../../libs/shared/**/*.stories.@(js|jsx|ts|tsx|mdx)', 👈
],
...
};
// .storybook/tsconfig.json
{
...
"include": [
"../../../libs/shared/**/*.stories.ts", 👈
"../src/**/*.stories.ts",
]
}
Switch to the preview.ts file - this file is like the root module. I would recommend importing all your global available modules - like translation or icons. I'm using ngx-translate and fontawesome - so I imported them here to use it in any story.
import { Preview, moduleMetadata } from '@storybook/angular';
const preview: Preview = {
decorators: [
moduleMetadata({
imports: [
ImportFontawesomeModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
}),
],
providers: [TranslateService],
}),
],
};
export default preview;
Tailwind
To get tailwind working you have to import the default tailwind directives.
@tailwind base;
@tailwind components;
@tailwind utilities;
If you imported the directives in the global styles.scss you can refernce this file in the project.json storybook sections.
Directives
The easiest way to describe the story for a directive is to look at the code:
import { Meta, StoryFn, moduleMetadata } from '@storybook/angular';
import { GhButtonDirective } from './gh-button.directive';
import { GhButtonContentComponent } from './gh-button-content/gh-button-content.component';
export default {
title: 'GhButtonDirective',
decorators: [
moduleMetadata({
// import the directive itself and etc.
imports: [GhButtonDirective, GhButtonContentComponent],
}),
],
argTypes: {
// define input controls
btnStyle: {
options: ['primary', 'secondary', 'soft', 'circular'],
control: {
type: 'radio',
},
},
btnLabel: {
control: 'text',
},
prefixIcon: {
control: 'text',
},
suffixIcon: {
control: 'text',
},
},
args: {
btnLabel: 'Save',
btnStyle: 'primary',
},
} as Meta<GhButtonDirective>;
const customizable = (): StoryFn => (args) => ({
props: args,
// use your directive in the template
// inputs can be used with the variables defined in the args above
template: `
<button ghButton [btnStyle]="btnStyle">
<gh-button-content [prefixIcon]="prefixIcon" [suffixIcon]="suffixIcon">
{{ btnLabel | translate }}
</gh-button-content>
</button>`,
});
export const Primary = customizable();
Content Projection
Found this working answer in the storybook github issue section:
If you have further questions about this topic or need help with a problem in general, please write a comment or simply contact me at yesreply@georghoeller.dev :)
Georg Hoeller Newsletter
Join the newsletter to receive the latest updates in your inbox.