From b24259ce7450ff0068d985c8d379593a6d057dd8 Mon Sep 17 00:00:00 2001 From: Paul Gascou-Vaillancourt Date: Sat, 12 Jun 2021 14:35:26 -0400 Subject: [PATCH] chore: add LinkToSource docs block Adds the LinkToSource docs block to render links to components' source code in their Storybook docs page. --- .storybook/docs/blocks/ImportInfo.js | 2 +- .storybook/docs/blocks/LinkToSource.js | 57 ++++++++++++++++++++++++++ .storybook/docs/blocks/index.js | 3 ++ .storybook/docs/page.js | 8 ++-- 4 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 .storybook/docs/blocks/LinkToSource.js create mode 100644 .storybook/docs/blocks/index.js diff --git a/.storybook/docs/blocks/ImportInfo.js b/.storybook/docs/blocks/ImportInfo.js index c58cec75cd..b099480c01 100644 --- a/.storybook/docs/blocks/ImportInfo.js +++ b/.storybook/docs/blocks/ImportInfo.js @@ -2,7 +2,7 @@ import React, { useContext } from 'react'; import { DocsContext } from '@storybook/addon-docs'; import { SyntaxHighlighter } from '@storybook/components'; -export const ImportInfo = ({ children }) => { +export const ImportInfo = () => { const context = useContext(DocsContext); const componentName = context.parameters?.component?.name; if (!componentName) { diff --git a/.storybook/docs/blocks/LinkToSource.js b/.storybook/docs/blocks/LinkToSource.js new file mode 100644 index 0000000000..3ba4cafdc1 --- /dev/null +++ b/.storybook/docs/blocks/LinkToSource.js @@ -0,0 +1,57 @@ +import React, { useContext } from 'react'; +import { DocsContext } from '@storybook/addon-docs/blocks'; +import { Button } from '@storybook/components'; +import * as modules from '../../../index'; + +const BASE_URL = 'https://gitlab.com/gitlab-org/gitlab-ui/-/tree/main'; + +/** + * Returns a source path given the current story path, if it exists. This works + * by assuming the story's filename is of the form `.../{basename}.stories.js`, + * and returns the source path of `.../{basename}.vue` or `{basename}.js`, + * whichever exists. + * + * For example: + * + * sourcePathFromStoryPath('./src/components/base/alert/alert.stories.js') + * // => './src/components/base/alert/alert.vue' + * + * @param {string} Story file path, relative to the root directory of the repo. + * @returns {string} Source file path for component or directive, relative to + * the root of the repo. + */ +const sourcePathFromStoryPath = (storyPath) => { + const sourcePaths = require + .context( + '../../../src', + true, + /^(?!.*(?:(spec|documentation|stories).js$|examples|utils)).*\.(vue|js)$/ + ) + .keys() + .map((path) => path.replace(/^\.\//, './src/')); + + const sourcePathRegex = new RegExp(`${storyPath.replace(/\.stories\.js$/, '')}\.(vue|js)$`); + + return sourcePaths.find((path, i, arr) => sourcePathRegex.test(path)); +}; + +export const LinkToSource = (props) => { + const context = useContext(DocsContext); + // There is a context.parameters.component.__file property that points to the + // source file if it's a component, but it does not exist for directives and isn't available + // in the production bundle. + const storyFileName = context?.parameters?.fileName; + if (!storyFileName) { + return null; + } + const sourcePath = sourcePathFromStoryPath(storyFileName); + if (!sourcePath) { + return null; + } + const href = `${BASE_URL}/${sourcePath.replace(/^\.\//, '')}`; + return ( + + ); +}; diff --git a/.storybook/docs/blocks/index.js b/.storybook/docs/blocks/index.js new file mode 100644 index 0000000000..9a38373e8e --- /dev/null +++ b/.storybook/docs/blocks/index.js @@ -0,0 +1,3 @@ +export { ImportInfo } from './ImportInfo'; +export { BootstrapComponent } from './BootstrapComponent'; +export { LinkToSource } from './LinkToSource'; diff --git a/.storybook/docs/page.js b/.storybook/docs/page.js index b36301134a..515abd9600 100644 --- a/.storybook/docs/page.js +++ b/.storybook/docs/page.js @@ -8,12 +8,14 @@ import { Stories, PRIMARY_STORY, } from '@storybook/addon-docs'; -import { ImportInfo } from './blocks/ImportInfo'; -import { BootstrapComponent } from './blocks/BootstrapComponent'; +import { ImportInfo, BootstrapComponent, LinkToSource } from './blocks'; export const page = () => ( <> - + <div className="gl-display-flex gl-align-items-center"> + <Title /> + <LinkToSource className="gl-ml-auto!" /> + </div> <Subtitle /> <ImportInfo /> <Description /> -- GitLab