From ee8a9d9cafdf8307a4c9e7822f983f16552aed50 Mon Sep 17 00:00:00 2001 From: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:31:11 +0200 Subject: [PATCH] Create Storybook guideline and add addon-designs to embed Figma (#27310) * Add foundations and migrations docs * Add storybook/addon-designs version 8.2.1 * Test Figma link * Refactor Modal stories * Create figmaDesignUrl * Create foundations * Create feature flags docs * Create Storybook builds docs * Add storybook/addon-designs version 8.2.1 * Test Figma link * Add an example of Story with split-tests within the Storybook guidelines (#27260) * Add FormatCurrency demo in feature-flags.mdx * Add syntax highlight to code samples * Update stories with figmaDesignUrl * Figma access token * Use OLButton * Hide control for children and footer * Add primitive colors * Use useSplitTest instead * Update cloud builds docs with `storybook-push-trigger` * Make Foundations the default story --------- Co-authored-by: Antoine Clausse GitOrigin-RevId: 0729759803f190d89cf543d087eea86265b725f1 --- package-lock.json | 120 ++++- services/web/.storybook/main.ts | 3 + services/web/.storybook/preview.tsx | 6 +- .../web/.storybook/utils/figma-design-url.ts | 20 + .../web/.storybook/utils/with-split-tests.tsx | 11 +- .../frontend/stories/docs/cloud-builds.mdx | 24 + .../frontend/stories/docs/feature-flags.mdx | 40 ++ .../stories/docs/format-currency.stories.tsx | 44 ++ .../web/frontend/stories/docs/foundations.mdx | 234 +++++++++ .../frontend/stories/modals/modal.stories.tsx | 197 +++----- .../web/frontend/stories/ui/badge.stories.tsx | 35 +- .../frontend/stories/ui/button.stories.tsx | 23 +- .../foundations/tokens/borderRadius.json | 24 + .../foundations/tokens/colors.json | 449 ++++++++++++++++++ .../foundations/tokens/spacing.json | 72 +++ .../foundations/tokens/typography.json | 133 ++++++ services/web/package.json | 1 + 17 files changed, 1285 insertions(+), 151 deletions(-) create mode 100644 services/web/.storybook/utils/figma-design-url.ts create mode 100644 services/web/frontend/stories/docs/cloud-builds.mdx create mode 100644 services/web/frontend/stories/docs/feature-flags.mdx create mode 100644 services/web/frontend/stories/docs/format-currency.stories.tsx create mode 100644 services/web/frontend/stories/docs/foundations.mdx create mode 100644 services/web/frontend/stylesheets/bootstrap-5/foundations/tokens/borderRadius.json create mode 100644 services/web/frontend/stylesheets/bootstrap-5/foundations/tokens/colors.json create mode 100644 services/web/frontend/stylesheets/bootstrap-5/foundations/tokens/spacing.json create mode 100644 services/web/frontend/stylesheets/bootstrap-5/foundations/tokens/typography.json diff --git a/package-lock.json b/package-lock.json index 6efa0a68bc..9b21f9326d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4912,6 +4912,30 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@figspec/components": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@figspec/components/-/components-1.0.3.tgz", + "integrity": "sha512-fBwHzJ4ouuOUJEi+yBZIrOy+0/fAjB3AeTcIHTT1PRxLz8P63xwC7R0EsIJXhScIcc+PljGmqbbVJCjLsnaGYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lit": "^2.1.3" + } + }, + "node_modules/@figspec/react": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@figspec/react/-/react-1.0.4.tgz", + "integrity": "sha512-jaPvkIef4d6NjsRiw91OZabrfdPH9FtoPGYcY5mpXjYEcdUqIq1aHtLq3SkMVyVysEapTEJ6yS8amy93MyXBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@figspec/components": "^1.0.1", + "@lit-labs/react": "^1.0.2" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@google-cloud/bigquery": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/@google-cloud/bigquery/-/bigquery-5.10.0.tgz", @@ -6543,6 +6567,30 @@ "@lezer/highlight": "^1.0.0" } }, + "node_modules/@lit-labs/react": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-1.2.1.tgz", + "integrity": "sha512-DiZdJYFU0tBbdQkfwwRSwYyI/mcWkg3sWesKRsHUd4G+NekTmmeq9fzsurvcKTNVa0comNljwtg4Hvi1ds3V+A==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", + "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -10288,6 +10336,40 @@ "storybook": "^8.6.12" } }, + "node_modules/@storybook/addon-designs": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@storybook/addon-designs/-/addon-designs-8.2.1.tgz", + "integrity": "sha512-orwihs1D5alhh4Qu3BSJKbSgQOdSagvRX/25m5fYZQAaqVErBY0lRR4vCAU/G/STkcdv+MHwIQ5U+0kX5Tm2+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@figspec/react": "^1.0.0" + }, + "peerDependencies": { + "@storybook/blocks": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", + "@storybook/components": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", + "@storybook/theming": "^8.0.0 || ^8.1.0-0 || ^8.2.0-0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + }, + "peerDependenciesMeta": { + "@storybook/blocks": { + "optional": true + }, + "@storybook/components": { + "optional": true + }, + "@storybook/theming": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/@storybook/addon-docs": { "version": "8.6.12", "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-8.6.12.tgz", @@ -12605,8 +12687,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "dev": true, - "optional": true + "dev": true }, "node_modules/@types/uuid": { "version": "9.0.8", @@ -27787,6 +27868,40 @@ } } }, + "node_modules/lit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz", + "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-element": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz", + "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.8.0" + } + }, + "node_modules/lit-html": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz", + "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/load-script": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", @@ -44516,6 +44631,7 @@ "@replit/codemirror-vim": "overleaf/codemirror-vim#1bef138382d948018f3f9b8a4d7a70ab61774e4b", "@sentry/browser": "7.46.0", "@storybook/addon-a11y": "^8.6.12", + "@storybook/addon-designs": "^8.2.1", "@storybook/addon-essentials": "^8.6.12", "@storybook/addon-interactions": "^8.6.12", "@storybook/addon-links": "^8.6.12", diff --git a/services/web/.storybook/main.ts b/services/web/.storybook/main.ts index 6c7c4e892a..ad07cd5345 100644 --- a/services/web/.storybook/main.ts +++ b/services/web/.storybook/main.ts @@ -19,12 +19,15 @@ const config: StorybookConfig = { stories: [ path.join(rootDir, 'frontend/stories/**/*.stories.{js,jsx,ts,tsx}'), path.join(rootDir, 'modules/**/stories/**/*.stories.{js,jsx,ts,tsx}'), + path.join(rootDir, 'frontend/stories/**/*.mdx'), + path.join(rootDir, 'modules/**/stories/**/*.mdx'), ], addons: [ getAbsolutePath('@storybook/addon-links'), getAbsolutePath('@storybook/addon-essentials'), getAbsolutePath('@storybook/addon-interactions'), getAbsolutePath('@storybook/addon-a11y'), + getAbsolutePath('@storybook/addon-designs'), getAbsolutePath('@storybook/addon-webpack5-compiler-babel'), { name: getAbsolutePath('@storybook/addon-styling-webpack'), diff --git a/services/web/.storybook/preview.tsx b/services/web/.storybook/preview.tsx index 6e1032afab..591f38b4ab 100644 --- a/services/web/.storybook/preview.tsx +++ b/services/web/.storybook/preview.tsx @@ -131,7 +131,11 @@ const preview: Preview = { options: { storySort: { method: 'alphabetical', - order: ['Shared'], + order: [ + 'Storybook Guideline', + ['Foundations', 'Storybook builds', 'Feature Flags'], + 'Shared', + ], }, }, }, diff --git a/services/web/.storybook/utils/figma-design-url.ts b/services/web/.storybook/utils/figma-design-url.ts new file mode 100644 index 0000000000..570b7cd88e --- /dev/null +++ b/services/web/.storybook/utils/figma-design-url.ts @@ -0,0 +1,20 @@ +/** Creates design parameters for a Storybook story conditionally. + * Helper function to generate design parameters based on the presence of a Figma access token. + * The benefit of the token is that it allows component inspection directly in Storybook. + * If token is not available, it defaults to a basic Figma URL. + * Token can be generated in your Figma account settings. + * To copy URL: In your Figma file, click to select the specific component frame you want to display in Storybook. + * It's important to select the outer frame of the component, not just a single layer inside it. + */ + +export const figmaDesignUrl = (url: string) => { + const accessToken = process.env.STORYBOOK_FIGMA_ACCESS_TOKEN + + const designConfig = accessToken + ? { type: 'figspec', url, accessToken } + : { type: 'figma', url } + + return { + design: designConfig, + } +} diff --git a/services/web/.storybook/utils/with-split-tests.tsx b/services/web/.storybook/utils/with-split-tests.tsx index 0d85afc9a6..083b3d49ca 100644 --- a/services/web/.storybook/utils/with-split-tests.tsx +++ b/services/web/.storybook/utils/with-split-tests.tsx @@ -1,8 +1,8 @@ import type { Meta } from '@storybook/react' import _ from 'lodash' -import { SplitTestContext } from '../../frontend/js/shared/context/split-test-context' +import { SplitTestContext } from '@/shared/context/split-test-context' -export const splitTestsArgTypes = { +export const defaultSplitTestsArgTypes = { // to be able to use this utility, you need to add the argTypes for each split test in this object // Check the original implementation for an example: https://github.com/overleaf/internal/pull/17809 'editor-redesign': { @@ -14,10 +14,13 @@ export const splitTestsArgTypes = { }, } -export const withSplitTests = ( +export const withSplitTests = ( story: Meta, - splitTests: (keyof typeof splitTestsArgTypes)[] = [] + splitTests: (keyof ArgTypes)[] = [], + /** @deprecated For demo purposes only. Add actual split tests in defaultSplitTestsArgTypes */ + _splitTestsArgTypes?: ArgTypes ): Meta => { + const splitTestsArgTypes = _splitTestsArgTypes ?? defaultSplitTestsArgTypes return { ...story, argTypes: { ...story.argTypes, ..._.pick(splitTestsArgTypes, splitTests) }, diff --git a/services/web/frontend/stories/docs/cloud-builds.mdx b/services/web/frontend/stories/docs/cloud-builds.mdx new file mode 100644 index 0000000000..815240d8a4 --- /dev/null +++ b/services/web/frontend/stories/docs/cloud-builds.mdx @@ -0,0 +1,24 @@ +import { Meta } from '@storybook/blocks'; + + + + +# Cloud Builds + +Storybook builds can be used to share your development work. They can be found at [https://storybook.dev-overleaf.com/](https://storybook.dev-overleaf.com/). + +The naming scheme is predictable, i.e.: `https://storybook.dev-overleaf.com//`. + +# Triggers + +Storybook builds are automatically triggered for the main branch. For ad hoc builds of feature branches, the commits must be pushed to branches prefixed with `storybook-`. + +For example, you may temporarily push your branch to a `storybook-` branch: `git push origin my-example-feature:storybook-my-example-feature` + +You can delete it shortly after: `git push origin :storybook-my-example-feature` + +Alternatively, **if you already have a branch**, but you would like to create a Storybook, you can manually trigger the `storybook-push-trigger` on your branch via [Google Cloud Build triggers](https://console.cloud.google.com/cloud-build/triggers?project=overleaf-dev). + +Storybook builds take about 10 minutes to finish. + +**Source:** [Storybook in the developer manual](https://manual.dev-overleaf.com/development/code/storybook/) diff --git a/services/web/frontend/stories/docs/feature-flags.mdx b/services/web/frontend/stories/docs/feature-flags.mdx new file mode 100644 index 0000000000..c34b4d422f --- /dev/null +++ b/services/web/frontend/stories/docs/feature-flags.mdx @@ -0,0 +1,40 @@ +import { Canvas, Controls, Meta } from '@storybook/blocks'; +import * as FormatCurrency from './format-currency.stories' + + + +# Feature flags + +You can wrap your story with the `withSplitTests` utility to add split test variants to your Storybook stories, so you can toggle feature flags directly in the Storybook UI. See [withSplitTests on GitHub](https://github.com/overleaf/internal/blob/main/services/web/.storybook/utils/with-split-tests.tsx). + +1. Define your split test argTypes: +Add your split test configurations to the `splitTestsArgTypes` object. + +```js +export const splitTestsArgTypes = { + 'local-ccy-format': { + description: 'Use local currency formatting', + control: { type: 'radio' }, + options: ['default', 'enabled'], + }, +} +``` +2. Wrap your story with `withSplitTests`. + +Import `withSplitTests` and `Meta` from '@storybook/react' in your stories. + +```js +export default { + ...config, + ...withSplitTests(config, ['local-ccy-format']), +} +``` + +## Example + +Resulting stories will have added controls to define the variants of the split tests. + +
+ + +
diff --git a/services/web/frontend/stories/docs/format-currency.stories.tsx b/services/web/frontend/stories/docs/format-currency.stories.tsx new file mode 100644 index 0000000000..da0d0de7ca --- /dev/null +++ b/services/web/frontend/stories/docs/format-currency.stories.tsx @@ -0,0 +1,44 @@ +import React from 'react' +import { useSplitTest } from '@/shared/context/split-test-context' +import { withSplitTests } from '../../../.storybook/utils/with-split-tests' + +const FormatCurrency = () => { + const { variant } = useSplitTest('local-ccy-format') + const formatCurrency = (amount: number, narrowSymbol: boolean) => { + return variant === 'enabled' + ? new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + currencyDisplay: narrowSymbol ? 'narrowSymbol' : 'name', + }).format(amount) + : `USD ${amount}` + } + return ( +
+ Variant: {JSON.stringify(variant)} +
+ Long: {formatCurrency(1234.56, false)} +
+ Short: {formatCurrency(1234.56, true)} +
+ ) +} + +const config = { + title: 'Storybook Guideline / Feature Flags', // Must match MDX title exactly + component: FormatCurrency, +} + +export default { + ...config, + ...withSplitTests(config, ['local-ccy-format'], { + 'local-ccy-format': { + description: 'Use local currency formatting', + control: { type: 'radio' as const }, + options: ['default', 'enabled'], + }, + }), + tags: ['!dev'], // hides in the sidebar +} + +export const Story = {} diff --git a/services/web/frontend/stories/docs/foundations.mdx b/services/web/frontend/stories/docs/foundations.mdx new file mode 100644 index 0000000000..b83212683b --- /dev/null +++ b/services/web/frontend/stories/docs/foundations.mdx @@ -0,0 +1,234 @@ +import { Meta, ColorItem, ColorPalette, Title, Typeset } from '@storybook/blocks'; +import colors from '../../stylesheets/bootstrap-5/foundations/tokens/colors.json'; +import typography from '../../stylesheets/bootstrap-5/foundations/tokens/typography.json'; +import borderRadius from '../../stylesheets/bootstrap-5/foundations/tokens/borderRadius.json'; +import spacing from '../../stylesheets/bootstrap-5/foundations/tokens/spacing.json'; + + + +# Foundations + +Foundations in UX design are the basic rules and core elements, like colors, fonts, and spacing, that ensure consistency across the design. +

+ These palettes are generated from our token files. The tokens were exported from Figma and split into separate files to categorise: Token files on GitHub +

+ +**Table of Contents** +- [Primitive colors](#primitive-colors) +- [Background colors](#background-colors) +- [Content colors](#content-colors) +- [Border colors](#border-colors) +- [Link colors](#link-colors) +- [Special colors](#special-colors) +- [Font weight](#font-weight) +- [Font size](#font-size) +- [Border radius](#border-radius) +- [Spacing](#spacing) + +# Colors +
+ +## Primitive colors + + + {Object.entries(colors.PrimitiveColor).map(([name, color]) => ( + + ))} + + +## Background colors + +Colors used for page and component backgrounds. + + + {Object.entries(colors) + .filter(([name]) => name.startsWith('bg-')) + .map(([name, colors]) => ( + + ))} + + +## Content colors + +Colors used for text and icons. + + + {Object.entries(colors) + .filter(([name]) => name.startsWith('content-')) + .map(([name, colors]) => ( + + ))} + + +## Border colors + +Colors used for borders and dividers. + + + {Object.entries(colors) + .filter(([name]) => name.startsWith('border-')) + .map(([name, colors]) => ( + + ))} + + +## Link colors + +Colors used for hyperlink states. + + + {Object.entries(colors) + .filter(([name]) => name.startsWith('link-')) + .map(([name, colors]) => ( + + ))} + + +## Special colors + +Colors used for specific UI elements like color pickers. + + + {Object.entries(colors) + .filter(([name]) => name.startsWith('special-')) + .map(([name, colors]) => ( + + ))} + + +# Typography +
+ +## Font weight +
+ +{Object.entries(typography.Fontweight).map(([name, typography]) => ( +
+ {name} + +
+))} + +## Font size +
+ +{Object.entries(typography['Fontsize']).map(([name, typography]) => { + const mixins = typography.$mixin ? [].concat(typography.$mixin) : []; + + return ( +
+ + {name} + {mixins.map(mixin => ( + / @mixin {mixin} + ))} + + +
+ ); +})} + +## Border radius +
+ + + + + + + + + + + {Object.entries(borderRadius['BorderRadius']).map(([name, borderRadius]) => ( + + + + + + ))} + +
Variable nameValueExample
+ {name} + {borderRadius.$value}px +
+
+ +## Spacing +
+ + + + + + + + + + + {Object.entries(spacing.Spacing) + .filter(([, spacing]) => spacing.$value > 0) + .map(([name, spacing]) => ( + + + + + + ))} + +
Variable NameValueExample
+ {name} + {spacing.$value}px +
+
diff --git a/services/web/frontend/stories/modals/modal.stories.tsx b/services/web/frontend/stories/modals/modal.stories.tsx index 0ad6eea215..b31e9acc1b 100644 --- a/services/web/frontend/stories/modals/modal.stories.tsx +++ b/services/web/frontend/stories/modals/modal.stories.tsx @@ -1,140 +1,80 @@ -import Button from '@/shared/components/button/button' import type { Meta, StoryObj } from '@storybook/react' +import { figmaDesignUrl } from './../../../.storybook/utils/figma-design-url' import OLModal, { OLModalHeader, OLModalBody, OLModalFooter, OLModalTitle, } from '@/shared/components/ol/ol-modal' +import OLButton from '@/shared/components/ol/ol-button' type Story = StoryObj export const Default: Story = { - render: args => { - return ( - - - Heading - - -

- Lorem ipsum dolor sit lorem a amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut - enim ad minim veniam. -

-
- - - - -
- ) + args: { + title: 'Heading', + children: ( +

+ Always use the modal actions in the footer and use descriptive words for + them. +

+ ), + footer: ( + <> + Cancel + Primary + + ), + }, + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?m=auto&node-id=3488-82657&m=dev' + ), +} + +export const Informative: Story = { + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?m=auto&node-id=3488-86576&m=dev' + ), + args: { + title: 'Informative', + children: ( +

+ Presents information for the user to be aware of and doesn’t require any + action. +

+ ), }, } -export const ModalWithAcknowledgment: Story = { - render: args => { - return ( - - - Acknowledgment - - -

- System requires an acknowledgment from the user. Usually contains - only one primary button. -

-
- - - -
- ) +export const Acknowledgment: Story = { + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?m=auto&node-id=3488-86581&m=dev' + ), + args: { + title: 'Acknowledgment', + children: ( +

+ System requires an acknowledgment from the user. Usually contains only + one primary button. +

+ ), + footer: Accept, }, } -export const ModalWithSecondary: Story = { - render: args => { - return ( - - - Heading - - -

- Lorem ipsum dolor sit lorem a amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut - enim ad minim veniam. -

-
- - - -
- ) - }, -} - -export const ModalWithTertiary: Story = { - render: args => { - return ( - - - Heading - - -

Used for destructive or irreversible actions.

-
- - - - - -
- ) - }, -} - -export const ModalInformative: Story = { - render: args => { - return ( - - - Informative - - -

- Presents information for the user to be aware of and doesn’t require - any action. -

-
-
- ) - }, -} - -export const ModalDanger: Story = { - render: args => { - return ( - - - Danger - - -

- Lorem ipsum dolor sit lorem a amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut - enim ad minim veniam. -

-
- - - - -
- ) +export const Danger: Story = { + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?m=auto&node-id=3488-86586&m=dev' + ), + args: { + title: 'Danger', + children:

Used for destructive or irreversible actions.

, + footer: ( + <> + Cancel + Delete + + ), }, } @@ -146,7 +86,24 @@ const meta: Meta = { control: 'radio', options: ['lg', 'md', 'sm'], }, + title: { control: 'text' }, + children: { control: false }, + footer: { control: false }, }, + args: { + show: true, + size: 'sm', + onHide: () => {}, + }, + render: ({ title, children, footer, ...args }) => ( + + + {title} + + {children} + {footer && {footer}} + + ), } export default meta diff --git a/services/web/frontend/stories/ui/badge.stories.tsx b/services/web/frontend/stories/ui/badge.stories.tsx index f7826aad27..9a7822faf8 100644 --- a/services/web/frontend/stories/ui/badge.stories.tsx +++ b/services/web/frontend/stories/ui/badge.stories.tsx @@ -1,7 +1,8 @@ -import Badge from '@/shared/components/badge/badge' -import MaterialIcon from '@/shared/components/material-icon' import type { Meta, StoryObj } from '@storybook/react' import classnames from 'classnames' +import { figmaDesignUrl } from '../../../.storybook/utils/figma-design-url' +import Badge from '@/shared/components/badge/badge' +import MaterialIcon from '@/shared/components/material-icon' const meta: Meta = { title: 'Shared / Components / Badge', @@ -31,20 +32,27 @@ export default meta type Story = StoryObj export const BadgeDefault: Story = { - render: args => { - return ( - - ) + args: { + bg: meta.argTypes!.bg!.options![0], }, -} -BadgeDefault.args = { - bg: meta.argTypes!.bg!.options![0], + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?node-id=3458-9502&m=dev' + ), + render: args => ( + + ), } export const BadgePrepend: Story = { + args: { + bg: meta.argTypes!.bg!.options![0], + }, + parameters: figmaDesignUrl( + 'https://www.figma.com/design/V7Ogph1Ocs4ux2A4WMNAh7/Overleaf---Components?node-id=3458-11319&m=dev' + ), render: args => { return ( +type Args = React.ComponentProps export const NewButton = (args: Args) => { - return