Skip to content

Commit

Permalink
Merge pull request #459 from netgroup-polito/gbf/fix_tail_storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
kingmakerbot authored May 6, 2021
2 parents d694b99 + d665487 commit 88ac0c0
Show file tree
Hide file tree
Showing 13 changed files with 15,804 additions and 43 deletions.
1 change: 0 additions & 1 deletion frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ yarn-debug.log*
yarn-error.log*

storybook-static
yarn.lock
.env
54 changes: 54 additions & 0 deletions frontend/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// include tailwind classes in the storybook
import '../src/includeTailwind.css';
const TAILWIND_TEXT_MATCH = 'TAILWIND_STYLE_IMPORT';

export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
Expand All @@ -10,3 +11,56 @@ export const parameters = {
},
},
};

// this functions is a logic to handle the case where there are multiple potential local css files
const findCorrectCssFile = async (cssLinkElements, match) => {
for (let i = 0; i < cssLinkElements.length; i++) {
const cssHref = cssLinkElements[i].href;
try {
const res = await fetch(cssHref);
const text = await res.text();

if (text.includes(match)) {
cssLinkElements[i].remove();
const styleElemToAppend = document.createElement('style');
styleElemToAppend.innerText = text;
document.head.appendChild(styleElemToAppend);
console.info('TAILWIND CSS LOADED');
break;
}
} catch (err) {
if (i === cssLinkElements.length - 1) {
console.error(`Last css href for tailwind tried was ${cssHref}`);
throw new Error('NO CSS LINK FOUND FOR TAILWIND');
} else {
console.info(
`Error when looking for tailwind css for path ${cssHref}, continuing to next link`,
err
);
}
}
}
};

// this decorator is to prioritize the tailwind css over antd for each story
// by brutally moving the style tag of tailwind to the bottom of the head
const tailwindPrioritizerDec = Story => {
if (process.env.NODE_ENV === 'development') {
const styleTail = Array.from(
document.querySelectorAll('style')
).find(elem => elem.innerText.includes(TAILWIND_TEXT_MATCH));

styleTail.remove();
document.head.appendChild(styleTail);
} else {
const potentialLinks = Array.from(
document.querySelectorAll("link[rel='stylesheet'][href$='.css']")
);

findCorrectCssFile(potentialLinks, TAILWIND_TEXT_MATCH);
}

return <Story />;
};

export const decorators = [tailwindPrioritizerDec];
3 changes: 2 additions & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ RUN mkdir --parent /tmp/frontend
WORKDIR /tmp/frontend

COPY --chown=node:node ./package.json /tmp/frontend/package.json
RUN yarn install --frozen-lockfile
COPY --chown=node:node ./yarn.lock /tmp/frontend/yarn.lock
RUN yarn install

ARG BUILD_TARGET
ARG SUBROUTE="/"
Expand Down
49 changes: 48 additions & 1 deletion frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Each component needs to have its own folder with the following structure, e.g. f

### File structure

Refer to the [Example component](./src/components/Example/) for a demo
Refer to the [Example component](./src/components/Examples/ExampleButton/) for a demo.

#### Component

Expand All @@ -66,6 +66,51 @@ Each component file needs to host a single component and needs to have the follo
- component props interface with the name `${ComponentName}Props` (if needed)
- functional component declaration

Additionally:

- if a task (like manipulating dynamic elements, animations, resizing) can be **_easily_** implemented using tailwind/css follow that implementation instead of relying on React/TS
- have jsx only inside the return statement of the component

- Invalid:

```ts
const Example: FC<IExampleProps> = ({ ...props }) => {
const { text, disabled, onClick, size, specialCSS } = props;
// do not have jsx outside the return
const content = <h5 className={specialCSS ? 'rainbow-text' : ''}>{text}</h5>

return (
<Button
disabled={disabled}
size={size}
onClick={onClick}
type="primary"
className="p-10"
>
{content}
</Button>
);
```
- Accepted:
```tsx
const Example: FC<IExampleProps> = ({ ...props }) => {
const { text, disabled, onClick, size, specialCSS } = props;

return (
<Button
disabled={disabled}
size={size}
onClick={onClick}
type="primary"
className="p-10"
>
<h5 className={specialCSS ? 'rainbow-text' : ''}>{text}</h5>
</Button>
);
```
#### Storybook
Each storybook file needs to have the following structure:
Expand All @@ -76,6 +121,8 @@ Each storybook file needs to have the following structure:
- template declaration
- component stories
Include in the `title` of the export default the path to create a hierarchy for your components. The path should be `Components/${subComponentsFolders}/${ComponentName}`
## Useful links
- [Useful answer for deploying react app on subroute](https://stackoverflow.com/a/58508562/11143279)
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@
"warn",
{
"allow": [
"error"
"error",
"info"
]
}
],
Expand Down
29 changes: 0 additions & 29 deletions frontend/src/components/Example/Example.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions frontend/src/components/Example/index.ts

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import Example, { IExampleProps } from './Example';
import ExampleButton, { IExampleButtonProps } from './ExampleButton';
import { Story, Meta } from '@storybook/react';
import { someKeysOf } from '../../utils';
import { someKeysOf } from '../../../utils';

export default {
title: 'Components/Example',
component: Example,
argTypes: { onClick: { action: 'clicked' } },
title: 'Components/Examples/ExampleButton',
component: ExampleButton,
argTypes: {
onClick: { action: 'clicked' },
},
} as Meta;

const defaultArgs: someKeysOf<IExampleProps> = {
text: 'Example',
const defaultArgs: someKeysOf<IExampleButtonProps> = {
text: 'Example Button',
disabled: false,
specialCSS: false,
};

const Template: Story<IExampleProps> = args => <Example {...args} />;
const Template: Story<IExampleButtonProps> = args => (
<ExampleButton {...args} />
);

export const Default = Template.bind({});

Expand Down
31 changes: 31 additions & 0 deletions frontend/src/components/Examples/ExampleButton/ExampleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FC } from 'react';
import { Button } from 'antd';
import { SizeType } from 'antd/lib/config-provider/SizeContext';
import './ExampleButton.css';

export interface IExampleButtonProps {
text: string;
disabled: boolean;
onClick: () => void;
specialCSS: boolean;
size: SizeType;
}

const Example: FC<IExampleButtonProps> = ({ ...props }) => {
const { text, disabled, onClick, size, specialCSS } = props;
return (
<div className="p-10">
<Button
disabled={disabled}
size={size}
onClick={onClick}
type="primary"
className="m-10 rounded-xl"
>
<h5 className={specialCSS ? 'rainbow-text' : ''}>{text}</h5>
</Button>
</div>
);
};

export default Example;
2 changes: 2 additions & 0 deletions frontend/src/components/Examples/ExampleButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Example from './ExampleButton';
export default Example;
3 changes: 3 additions & 0 deletions frontend/src/includeTailwind.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* DO NOT REMOTE THE NEXT LINE -> 💥 */
/* TAILWIND_STYLE_IMPORT */

/* This file serve the only purpose to not include the tailwind import in the less file, to allow its use in storybook */

@tailwind utilities;
Loading

0 comments on commit 88ac0c0

Please sign in to comment.