diff --git a/.github/workflows/deploy-vercel-production.yml b/.github/workflows/deploy-vercel-production.yml
index fadc2d24c..1dbb728db 100644
--- a/.github/workflows/deploy-vercel-production.yml
+++ b/.github/workflows/deploy-vercel-production.yml
@@ -21,7 +21,6 @@
# - See https://github.com/jwalton/gh-find-current-pr https://github.com/jwalton/gh-find-current-pr/tree/v1
# - See https://github.com/peter-evans/create-or-update-comment https://github.com/peter-evans/create-or-update-comment/tree/v1
# - See https://github.com/UnlyEd/github-action-await-vercel https://github.com/UnlyEd/github-action-await-vercel/tree/v1.1.1
-# - See https://github.com/rlespinasse/github-slug-action https://github.com/rlespinasse/github-slug-action/tree/v3.x
# - See https://github.com/cypress-io/github-action https://github.com/cypress-io/github-action/tree/v2
# - See https://github.com/foo-software/lighthouse-check-action https://github.com/foo-software/lighthouse-check-action/tree/v1.0.1
@@ -71,6 +70,7 @@ jobs:
# Workflow overview:
# - Resolve customer to deploy from github event input (falls back to resolving it from vercel.json file)
# - Deploy the customer in production
+ # - Creates multiple deployment aliases based on the "alias" property defined in the vercel.json file, and link them to the deployment
# XXX You can use https://jqplay.org/ if you want to play around with "jq" to manipulate JSON
run: |
# Print the version of the "vercel" CLI being used (helps debugging)
diff --git a/.github/workflows/deploy-vercel-staging.yml b/.github/workflows/deploy-vercel-staging.yml
index 076b9d011..95aff8faf 100644
--- a/.github/workflows/deploy-vercel-staging.yml
+++ b/.github/workflows/deploy-vercel-staging.yml
@@ -22,7 +22,6 @@
# - See https://github.com/peter-evans/create-or-update-comment https://github.com/peter-evans/create-or-update-comment/tree/v1
# - See https://github.com/UnlyEd/github-action-await-vercel https://github.com/UnlyEd/github-action-await-vercel/tree/v1.1.1
# - See https://github.com/UnlyEd/github-action-store-variable https://github.com/UnlyEd/github-action-store-variable/tree/v1.0.1
-# - See https://github.com/rlespinasse/github-slug-action https://github.com/rlespinasse/github-slug-action/tree/v3.x
# - See https://github.com/cypress-io/github-action https://github.com/cypress-io/github-action/tree/v2
# - See https://github.com/foo-software/lighthouse-check-action https://github.com/foo-software/lighthouse-check-action/tree/v1.0.1
@@ -75,6 +74,7 @@ jobs:
# - Get stdout from deploy command (stderr prints build steps and stdout prints deployment url, which is what we are really looking for)
# - Set the deployment url that will be included in the eventual PR comment
# - Create a deployment alias based on the branch name, and link it to the deployment (so that each branch has its own domain automatically aliased to the latest commit)
+ # - Creates multiple deployment aliases based on the "alias" property defined in the vercel.json file, and link them to the deployment
# XXX You can use https://jqplay.org/ if you want to play around with "jq" to manipulate JSON
run: |
# Print the version of the "vercel" CLI being used (helps debugging)
@@ -372,7 +372,7 @@ jobs:
with:
# XXX We disabled "wait-on" option, because it's useless. Cypress will fail anyway, because it gets redirected to some internal Vercel URL if the domain isn't yet available - See https://github.com/cypress-io/github-action/issues/270
# wait-on: '${{ env.VERCEL_DEPLOYMENT_URL }}' # Be sure that the endpoint is ready by pinging it before starting tests, using a default timeout of 60 seconds
- config-file: 'cypress/config-customer-ci-cd.json' # The config file itself doesn't matter because we will override most settings anyway. We just need `projectId` to run the tests.
+ config-file: 'cypress/config-customer-ci-cd.json' # Use Cypress config file for CI/CD, and override it below
config: baseUrl=${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }} # Overriding baseUrl provided by config file to test the new deployment
env:
# Enables Cypress debugging logs, very useful if Cypress crashes, like out-of-memory issues.
diff --git a/.github/workflows/deploy-vercel-storybook.yml b/.github/workflows/deploy-vercel-storybook.yml
new file mode 100644
index 000000000..2dc93c900
--- /dev/null
+++ b/.github/workflows/deploy-vercel-storybook.yml
@@ -0,0 +1,249 @@
+# Summary:
+# Builds a static version of the Storybook website and triggers a new deployment on Vercel's platform, when anything is pushed in any branch.
+#
+# LEARN MORE AT https://unlyed.github.io/next-right-now/guides/ci-cd/
+#
+# Dependencies overview:
+# - See https://github.com/actions/setup-node https://github.com/actions/setup-node/tree/v1
+# - See https://github.com/actions/checkout https://github.com/actions/checkout/tree/v1
+# - See https://github.com/actions/upload-artifact https://github.com/actions/upload-artifact/tree/v1
+# - See https://github.com/rlespinasse/github-slug-action https://github.com/rlespinasse/github-slug-action/tree/3.x
+# - See https://github.com/jwalton/gh-find-current-pr https://github.com/jwalton/gh-find-current-pr/tree/v1
+# - See https://github.com/peter-evans/create-or-update-comment https://github.com/peter-evans/create-or-update-comment/tree/v1
+# - See https://github.com/UnlyEd/github-action-await-vercel https://github.com/UnlyEd/github-action-await-vercel/tree/v1.1.1
+# - See https://github.com/UnlyEd/github-action-store-variable https://github.com/UnlyEd/github-action-store-variable/tree/v1.0.1
+# - See https://github.com/cypress-io/github-action https://github.com/cypress-io/github-action/tree/v2
+
+name: Deploy Storybook static site to Vercel
+
+on:
+ # There are several ways to trigger Github actions - See https://help.github.com/en/actions/reference/events-that-trigger-workflows#example-using-a-single-event for a comprehensive list:
+ # - "push": Triggers each time a commit is pushed
+ # - "pull_request": Triggers each time a commit is pushed within a pull request, it makes it much easier to write comments within the PR, but it suffers some strong limitations:
+ # - There is no way to trigger when a PR is merged into another - See https://github.community/t/pull-request-action-does-not-run-on-merge/16092?u=vadorequest
+ # - It won't trigger when the PR is conflicting with its base branch - See https://github.community/t/run-actions-on-pull-requests-with-merge-conflicts/17104/2?u=vadorequest
+ push: # Triggers on each pushed commit
+ branches:
+ - '*'
+
+jobs:
+ # Configures the deployment environment, install dependencies (like node, npm, etc.) that are requirements for the upcoming jobs
+ # Ex: Necessary to run `yarn deploy`
+ setup-environment:
+ name: Setup deployment environment (Ubuntu 18.04 - Node 12.x)
+ runs-on: ubuntu-18.04
+ steps:
+ - name: Installing node.js
+ uses: actions/setup-node@v1 # Used to install node environment - https://github.com/actions/setup-node
+ with:
+ node-version: '12.x' # Use the same node.js version as the one Vercel's uses (currently node12.x)
+
+ # Starts a Vercel deployment, using the storybook configuration file
+ # N.B: It's Vercel that will perform the actual deployment
+ start-deployment:
+ name: Starts Vercel deployment (Ubuntu 18.04)
+ runs-on: ubuntu-18.04
+ needs: setup-environment
+ steps:
+ - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout
+
+ - name: Expose GitHub slug/short variables # See https://github.com/rlespinasse/github-slug-action#exposed-github-environment-variables
+ uses: rlespinasse/github-slug-action@v3.x # See https://github.com/rlespinasse/github-slug-action
+
+ - name: Deploying on Vercel
+ # Workflow overview:
+ # - Install yarn dependencies (necessary to build the Storybook static site)
+ # - Starts a Vercel deployment, using vercel.storybook.json
+ # - Creates multiple deployment aliases based on the "alias" property defined in the vercel.json file, and link them to the deployment
+ run: |
+ # Print the version of the "vercel" CLI being used (helps debugging)
+ vercel --version
+ echo "Current branch: ${GITHUB_REF_SLUG}"
+
+ echo "Installing dependencies"
+ yarn install
+
+ echo "Building and deploying StoryBook static site"
+
+ # Deploy the customer on Vercel using the customer ref
+ # Store the output in a variable so we can extract metadata from it
+ VERCEL_DEPLOYMENT_OUTPUT=`yarn deploy:sb:gha --token $VERCEL_TOKEN`
+
+ # Extract the Vercel deployment url from the deployment output
+ VERCEL_DEPLOYMENT_URL=`echo $VERCEL_DEPLOYMENT_OUTPUT | egrep -o 'https?://[^ ]+.vercel.app'`
+ echo "Deployment url: " $VERCEL_DEPLOYMENT_URL
+ echo "VERCEL_DEPLOYMENT_URL=$VERCEL_DEPLOYMENT_URL" >> $GITHUB_ENV
+ echo "VERCEL_DEPLOYMENT_DOMAIN=${VERCEL_DEPLOYMENT_URL#https://}" >> $GITHUB_ENV
+
+ # Find all custom aliases configured in the customer deployment configuration file (vercel.json)
+ VERCEL_DEPLOYMENT_ALIASES_JSON=$(cat vercel.storybook.json | jq --raw-output '.alias')
+ echo "Custom aliases: " $VERCEL_DEPLOYMENT_ALIASES_JSON
+
+ # Convert the JSON array into a bash array - See https://unix.stackexchange.com/a/615717/60329
+ readarray -t VERCEL_DEPLOYMENT_ALIASES < <(jq --raw-output '.alias[]' < vercel.storybook.json)
+
+ # Count the number of element in the array, will be 0 if it's an empty array, or if the "alias" key wasn't defined
+ VERCEL_DEPLOYMENT_ALIASES_COUNT=${#VERCEL_DEPLOYMENT_ALIASES[@]}
+
+ # Check if there are no aliases configured
+ if [ "$VERCEL_DEPLOYMENT_ALIASES" > 0 ]
+ then
+ echo "$VERCEL_DEPLOYMENT_ALIASES_COUNT alias(es) found. Aliasing them now..."
+
+ # For each alias configured, then assign it to the deployed domain
+ for DEPLOYMENT_ALIAS in "${VERCEL_DEPLOYMENT_ALIASES[@]}"; do
+ echo "npx vercel alias "$VERCEL_DEPLOYMENT_URL $DEPLOYMENT_ALIAS
+ npx vercel alias $VERCEL_DEPLOYMENT_URL $DEPLOYMENT_ALIAS --token $VERCEL_TOKEN || echo "Aliasing failed for '$DEPLOYMENT_ALIAS', but the build will continue regardless."
+ done
+ else
+ # $VERCEL_DEPLOYMENT_ALIASES is null, this happens when it was not defined in the vercel.json file
+ echo "There are no more aliases to configure. You can add more aliases from your vercel.json 'alias' property. See https://vercel.com/docs/configuration?query=alias%20domain#project/alias"
+ echo "$VERCEL_DEPLOYMENT_ALIASES"
+ fi
+ env:
+ VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} # Passing github's secret to the worker
+ # Passing exposed GitHub environment variables - See https://github.com/rlespinasse/github-slug-action#exposed-github-environment-variables
+ GITHUB_REF_SLUG: ${{ env.GITHUB_REF_SLUG }}
+
+ # We need to find the PR id. Will be used later to comment on that PR.
+ - name: Finding Pull Request ID
+ uses: jwalton/gh-find-current-pr@v1 # See https://github.com/jwalton/gh-find-current-pr
+ id: pr_id_finder
+ if: always() # It forces the job to be always executed, even if a previous job fail.
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
+ # On deployment failure, add a comment to the PR, if there is an open PR for the current branch
+ - name: Comment PR (Deployment failure)
+ uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
+ if: steps.pr_id_finder.outputs.number && failure()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ issue-number: ${{ steps.pr_id_finder.outputs.number }}
+ body: |
+ :x: Deployment **FAILED**
+ Commit ${{ github.sha }} failed to deploy **Storybook static site** to [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
+ [click to see logs](https://github.com/UnlyEd/next-right-now/pull/${{ steps.pr_id_finder.outputs.number }}/checks)
+
+ # On deployment success, add a comment to the PR, if there is an open PR for the current branch
+ - name: Comment PR (Deployment success)
+ uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
+ if: steps.pr_id_finder.outputs.number && success()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ issue-number: ${{ steps.pr_id_finder.outputs.number }}
+ body: |
+ :white_check_mark: Deployment **SUCCESS**
+ Commit ${{ github.sha }} successfully deployed **Storybook static site** to [${{ env.VERCEL_DEPLOYMENT_URL }}](${{ env.VERCEL_DEPLOYMENT_URL }})
+ Deployment aliased as [nrn-v2-mst-aptd-gcms-lcz-sty-storybook](https://nrn-v2-mst-aptd-gcms-lcz-sty-storybook.vercel.app)
+
+ # At the end of the job, store all variables we will need in the following jobs
+ # The variables will be stored in and retrieved from a GitHub Artifact (each variable is stored in a different file)
+ - name: Store variables for next jobs
+ uses: UnlyEd/github-action-store-variable@v1.0.1 # See https://github.com/UnlyEd/github-action-store-variable
+ with:
+ variables: |
+ VERCEL_DEPLOYMENT_URL=${{ env.VERCEL_DEPLOYMENT_URL }}
+ VERCEL_DEPLOYMENT_DOMAIN=${{ env.VERCEL_DEPLOYMENT_DOMAIN }}
+ GITHUB_PULL_REQUEST_ID=${{ steps.pr_id_finder.outputs.number }}
+
+ # Waits for the Vercel deployment to reach "READY" state, so that other actions will be applied on a domain that is really online
+ await-for-vercel-deployment:
+ name: Await current deployment to be ready (Ubuntu 18.04)
+ runs-on: ubuntu-18.04
+ needs: start-deployment
+ steps:
+ - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout
+
+ # Restore variables stored by previous jobs
+ - name: Restore variables
+ uses: UnlyEd/github-action-store-variable@v1.0.1 # See https://github.com/UnlyEd/github-action-store-variable
+ id: restore-variable
+ with:
+ variables: |
+ VERCEL_DEPLOYMENT_DOMAIN
+
+ # Wait for deployment to be ready, before running E2E (otherwise Cypress might start testing too early, and gets redirected to Vercel's "Login page", and tests fail)
+ - name: Awaiting Vercel deployment to be ready
+ uses: UnlyEd/github-action-await-vercel@v1.1.1 # See https://github.com/UnlyEd/github-action-await-vercel
+ id: await-vercel
+ env:
+ VERCEL_TOKEN: ${{ secrets.VERCEl_TOKEN }}
+ with:
+ deployment-url: ${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_DOMAIN }} # Must only contain the domain name (no http prefix, etc.)
+ timeout: 90 # Wait for 90 seconds before failing
+
+ - name: Display deployment status
+ run: "echo The deployment is ${{ fromJson(steps.await-vercel.outputs.deploymentDetails).readyState }}"
+
+ # Runs E2E tests against the Vercel deployment
+ run-2e2-tests:
+ name: Run end to end (E2E) tests (Ubuntu 18.04)
+ runs-on: ubuntu-18.04
+ # Docker image with Cypress pre-installed
+ # https://github.com/cypress-io/cypress-docker-images/tree/master/included
+ container: cypress/included:3.8.3
+ needs: await-for-vercel-deployment
+ steps:
+ - uses: actions/checkout@v1 # Get last commit pushed - See https://github.com/actions/checkout
+
+ # Restore variables stored by previous jobs
+ - name: Restore variables
+ uses: UnlyEd/github-action-store-variable@v1.0.1 # See https://github.com/UnlyEd/github-action-store-variable
+ id: restore-variable
+ with:
+ variables: |
+ VERCEL_DEPLOYMENT_URL
+ GITHUB_PULL_REQUEST_ID
+
+ # Runs the E2E tests against the new Vercel deployment
+ - name: Run E2E tests (Cypress)
+ uses: cypress-io/github-action@v2 # See https://github.com/cypress-io/github-action
+ with:
+ # XXX We disabled "wait-on" option, because it's useless. Cypress will fail anyway, because it gets redirected to some internal Vercel URL if the domain isn't yet available - See https://github.com/cypress-io/github-action/issues/270
+ # wait-on: '${{ env.VERCEL_DEPLOYMENT_URL }}' # Be sure that the endpoint is ready by pinging it before starting tests, using a default timeout of 60 seconds
+ config-file: 'cypress/config-storybook.json' # Use Cypress config file for Storybook, and override it below
+ config: baseUrl=${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }} # Overriding baseUrl provided by config file to test the new deployment
+ env:
+ # Enables Cypress debugging logs, very useful if Cypress crashes, like out-of-memory issues.
+ # DEBUG: "cypress:*" # Enable all logs. See https://docs.cypress.io/guides/references/troubleshooting.html#Print-DEBUG-logs
+ DEBUG: "cypress:server:util:process_profiler" # Enable logs for "memory and CPU usage". See https://docs.cypress.io/guides/references/troubleshooting.html#Log-memory-and-CPU-usage
+
+ # On E2E failure, upload screenshots
+ - name: Upload screenshots artifacts (E2E failure)
+ uses: actions/upload-artifact@v1 # On failure we upload artifacts, https://help.github.com/en/actions/automating-your-workflow-with-github-actions/persisting-workflow-data-using-artifacts
+ if: failure()
+ with:
+ name: screenshots
+ path: cypress/screenshots/
+
+ # On E2E failure, upload videos
+ - name: Upload videos artifacts (E2E failure)
+ uses: actions/upload-artifact@v1 # On failure we upload artifacts, https://help.github.com/en/actions/automating-your-workflow-with-github-actions/persisting-workflow-data-using-artifacts
+ if: failure()
+ with:
+ name: videos
+ path: cypress/videos/
+
+ # On E2E failure, add a comment to the PR with additional information, if there is an open PR for the current branch
+ - name: Comment PR (E2E failure)
+ uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
+ if: fromJson(steps.restore-variable.outputs.variables).GITHUB_PULL_REQUEST_ID && failure()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ issue-number: ${{ fromJson(steps.restore-variable.outputs.variables).GITHUB_PULL_REQUEST_ID }}
+ body: |
+ :x: E2E tests **FAILED** for commit ${{ github.sha }} previously deployed **Storybook static site** at [${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }}](${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }})
+ Download artifacts (screenshots + videos) from [`checks`](https://github.com/UnlyEd/next-right-now/pull/${{ fromJson(steps.restore-variable.outputs.variables).GITHUB_PULL_REQUEST_ID }}/checks) section
+
+ # On E2E success, add a comment to the PR, if there is an open PR for the current branch
+ - name: Comment PR (E2E success)
+ uses: peter-evans/create-or-update-comment@v1 # See https://github.com/peter-evans/create-or-update-comment
+ if: fromJson(steps.restore-variable.outputs.variables).GITHUB_PULL_REQUEST_ID && success()
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ issue-number: ${{ fromJson(steps.restore-variable.outputs.variables).GITHUB_PULL_REQUEST_ID }}
+ body: |
+ :white_check_mark: E2E tests **SUCCESS** for commit ${{ github.sha }} previously deployed **Storybook static site** at [${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }}](${{ fromJson(steps.restore-variable.outputs.variables).VERCEL_DEPLOYMENT_URL }})
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index e58d8bedc..f943449c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -149,4 +149,5 @@ _site
# Tmp files (cache, etc.)
*.cache
-.vercel
+# Storybook
+storybook-static/
diff --git a/.storybook/.gitignore b/.storybook/.gitignore
new file mode 100644
index 000000000..f3e842096
--- /dev/null
+++ b/.storybook/.gitignore
@@ -0,0 +1 @@
+*.cache*
diff --git a/.storybook/babel.config.js b/.storybook/babel.config.js
new file mode 100644
index 000000000..ff1dbcd83
--- /dev/null
+++ b/.storybook/babel.config.js
@@ -0,0 +1,13 @@
+/**
+ * Babel configuration for Storybook
+ *
+ * Doesn't affect Next.js babel configuration, specific file for Storybook only.
+ * Need to apply Emotion babel configuration, otherwise Emotion "css" cannot be used in Storybook.
+ *
+ * XXX We use the "classic" way instead of the "automatic" way for Storybook, that's because MDX isn't compatible with "automatic".
+ *
+ * @see https://emotion.sh/docs/css-prop#babel-preset Configuring Emotion 11
+ */
+module.exports = {
+ "presets": ["@emotion/babel-preset-css-prop"]
+};
diff --git a/.storybook/main.js b/.storybook/main.js
new file mode 100644
index 000000000..2fcb96e75
--- /dev/null
+++ b/.storybook/main.js
@@ -0,0 +1,223 @@
+const { promises: fs } = require('fs');
+const path = require('path');
+const fetch = require('node-fetch');
+
+const toPath = (_path) => path.join(process.cwd(), _path);
+
+/**
+ * Fetches translations from Locize and store them in the filesystem.
+ * They will be loaded in preview.js, which will configure Locize so that components can display their translations.
+ *
+ * @param environment
+ */
+const fetchLocizeTranslation = async (environment) => {
+ const cacheFileName = '.sb-translations.cache.json';
+ const version = environment === 'development' ? 'latest' : 'production';
+ const languages = ['en', 'fr'];
+ const namespaces = ['common'];
+ const allI18nTranslations = {};
+
+ for (let i = 0; i < languages.length; i++) {
+ const lang = languages[i];
+ for (let j = 0; j < namespaces.length; j++) {
+ const namespace = namespaces[j];
+ const locizeAPIEndpoint = `https://api.locize.app/${process.env.NEXT_PUBLIC_LOCIZE_PROJECT_ID}/${version}/${lang}/${namespace}`;
+ console.log('Fetching translations from:', locizeAPIEndpoint);
+ const defaultI18nTranslationsResponse = await fetch(locizeAPIEndpoint);
+ const i18nTranslations = await defaultI18nTranslationsResponse.json();
+
+ allI18nTranslations[lang] = allI18nTranslations[lang] || {};
+ allI18nTranslations[lang][namespace] = i18nTranslations;
+ }
+ }
+
+ // Store translations
+ const translationCacheFile = path.join(__dirname, cacheFileName);
+ console.log('Writing translations cache to:', translationCacheFile);
+
+ await fs.writeFile(translationCacheFile, JSON.stringify(allI18nTranslations, null, 2), 'utf8');
+};
+
+module.exports = {
+ stories: [
+ '../src/**/*.stories.mdx',
+ '../src/**/*.stories.@(js|jsx|ts|tsx)',
+ ],
+ addons: [
+ /**
+ * The Storybook Links addon can be used to create links that navigate between stories in Storybook.
+ *
+ * @see https://www.npmjs.com/package/@storybook/addon-links
+ */
+ '@storybook/addon-links',
+
+ /**
+ * Present including "essential" Storybook addons, such as:
+ *
+ * - Actions - Storybook Addon Actions can be used to display data received by event handlers in Storybook.
+ * It's where the action you do are being logged.
+ *
+ * - Backgrounds - Storybook Addon Backgrounds can be used to change background colors inside the preview in Storybook.
+ *
+ * - Controls - Controls gives you a graphical UI to interact with a component's arguments dynamically, without needing to code.
+ * It creates an addon panel next to your component examples ("stories"), so you can edit them live.
+ *
+ * - Docs - Storybook Docs transforms your Storybook stories into world-class component documentation.
+ * - DocsPage: Out of the box, all your stories get a DocsPage. DocsPage is a zero-config aggregation
+ * of your component stories, text descriptions, docgen comments, props tables, and code examples into clean, readable pages.
+ * - MDX: If you want more control, MDX allows you to write long-form markdown documentation and stories in one file.
+ * You can also use it to write pure documentation pages and embed them inside your Storybook alongside your stories.
+ *
+ * - Viewport - Storybook Viewport Addon allows your stories to be displayed in different sizes and layouts in Storybook.
+ * This helps build responsive components inside of Storybook.
+ *
+ * - Toolbars - The Toolbars addon controls global story rendering options from Storybook's toolbar UI. It's a general purpose addon that can be used to:
+ * - set a theme for your components
+ * - set your components' internationalization (i18n) locale
+ * - configure just about anything in Storybook that makes use of a global variable
+ *
+ * @see https://storybook.js.org/addons/essentials
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/essentials
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/actions
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/backgrounds
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/controls
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/docs
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/viewport
+ * @see https://github.com/storybookjs/storybook/tree/next/addons/toolbars
+ *
+ * You can disable addons you don't want through configuration.
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/essentials#disabling-addons
+ */
+ {
+ name: '@storybook/addon-essentials',
+ options: {
+ actions: true,
+ backgrounds: true,
+ controls: true,
+ docs: true,
+ viewport: true,
+ toolbars: true,
+ },
+ },
+
+ /**
+ * Storybook Addon Knobs has been replaced by Controls and is being deprecated, it will be removed in v7.
+ *
+ * It is listed below for documentation purpose and help you avoid using it thinking it's still legit.
+ *
+ * @see https://github.com/storybookjs/storybook/blob/next/addons/controls/README.md#how-will-this-replace-addon-knobs
+ */
+ // '@storybook/addon-knobs',
+
+ /**
+ * We use Google Analytics for tracking analytics usage.
+ *
+ * It's much easier to setup than Amplitude, because there is an official dedicated plugin for this.
+ * See ".storybook/manager.js" for Google Analytics configuration.
+ *
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/google-analytics
+ */
+ '@storybook/addon-google-analytics',
+
+ /**
+ * Shows stories source in the addon panel. (display the source code of the story in a dedicated panel)
+ *
+ * Adds an "Story" tab.
+ *
+ * XXX Disabled for now, because of https://github.com/storybookjs/storybook/issues/13657 (brings no useful information at the moment)
+ * Better to use the Docs panel and display source code, that's a good workaround for now.
+ *
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/storysource
+ */
+ // '@storybook/addon-storysource',
+
+ /**
+ * This storybook addon can be helpful to make your UI components more accessible.
+ *
+ * Adds an "Accessibility" tab.
+ *
+ * @see https://www.npmjs.com/package/@storybook/addon-a11y
+ */
+ '@storybook/addon-a11y',
+
+ // ------------------- Non official addons below ------------------
+
+ /**
+ * Adds support for CSS Modules.
+ *
+ * Even though Next Right Now doesn't encourage the use of CSS Modules,
+ * we thought it's an interesting feature to support, which is natively supported by Next.js.
+ *
+ * @see https://www.npmjs.com/package/storybook-css-modules-preset How to configure Storybook to support CSS Modules
+ * @see https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css How to use CSS Modules with Next.js
+ */
+ 'storybook-css-modules-preset',
+
+ /**
+ * A storybook addon to help better understand and debug performance for React components.
+ *
+ * Adds a "Performance" tab.
+ *
+ * @see https://github.com/atlassian-labs/storybook-addon-performance
+ */
+ 'storybook-addon-performance/register',
+
+ /**
+ * Offers suggestions on how you can improve the HTML, CSS and UX of your components to be more mobile-friendly.
+ *
+ * Adds a "Mobile" tab.
+ *
+ * @see https://github.com/aholachek/storybook-mobile
+ */
+ 'storybook-mobile',
+
+ /**
+ * A Storybook addon that embed Figma, websites, PDF or images in the addon panel.
+ *
+ * Adds a "Design" tab.
+ *
+ * @see https://github.com/pocka/storybook-addon-designs
+ */
+ 'storybook-addon-designs',
+ ],
+
+ /**
+ * Customize webpack configuration for Storybook.
+ *
+ * This doesn't affect the Next.js application, only the Storybook compilation.
+ *
+ * @param config
+ * @see https://storybook.js.org/docs/react/configure/overview#configure-your-storybook-project
+ */
+ webpackFinal: async (config) => {
+ const {
+ mode: environment,
+ plugins,
+ module,
+ } = config;
+ await fetchLocizeTranslation(environment);
+
+ return {
+ ...config,
+ resolve: {
+ ...config.resolve,
+ alias: {
+ ...config.resolve.alias,
+
+ /**
+ * Map Emotion 10 libraries to Emotion 11 libraries.
+ *
+ * Otherwise Storybook fails to compile with "Module not found: Error: Can't resolve '@emotion/styled/base'", etc.
+ * It wasn't necessary to do this until we imported React component using "@emotion/styled".
+ * This issue is probably caused because Storybook uses Emotion 10 while we have Emotion 11 used by the Next.js app.
+ *
+ * @see https://github.com/storybookjs/storybook/issues/13277#issuecomment-751747964
+ */
+ '@emotion/core': toPath('node_modules/@emotion/react'),
+ '@emotion/styled': toPath('node_modules/@emotion/styled'),
+ 'emotion-theming': toPath('node_modules/@emotion/react'),
+ },
+ },
+ };
+ },
+};
diff --git a/.storybook/manager.js b/.storybook/manager.js
new file mode 100644
index 000000000..2df85ffaa
--- /dev/null
+++ b/.storybook/manager.js
@@ -0,0 +1,36 @@
+import { addons } from '@storybook/addons';
+import { themes } from '@storybook/theming';
+
+/**
+ * Configure Storybook UI layout.
+ *
+ * XXX The Storybook manager seems to suffer from a cache invalidation issue, which forces us to run with `--no-manager-cache` option.
+ * @see https://github.com/storybookjs/storybook/issues/13649#issuecomment-761076960
+ * @see https://github.com/storybookjs/storybook/issues/13200
+ *
+ * @see https://storybook.js.org/docs/react/configure/features-and-behavior
+ */
+addons.setConfig({
+ theme: themes.dark,
+});
+
+/**
+ * Your Google Analytics tracking ID.
+ *
+ * If you're creating a dedicated Google Analytics property for this (you should),
+ * Then make sure to create a "Universal Analytics property", not a Google Analytics 4 property (default since 2021).
+ *
+ * @see https://support.google.com/analytics/answer/10269537
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/google-analytics Google Analytic addon for Storybook
+ */
+window.STORYBOOK_GA_ID = 'UA-89785688-10'; // Replace by your own "UA-XXXXXXX-XX"
+
+/**
+ * React-ga options object
+ *
+ * @example { debug: true, gaOptions: { userId: 123 }}
+ * @see https://github.com/react-ga/react-ga#api
+ * @see https://github.com/storybookjs/storybook/blob/4f5ab9fe9e590da7b841ec37cb1bed8d6327ea4b/addons/google-analytics/src/register.ts#L8
+ * @see https://github.com/storybookjs/storybook/tree/master/addons/google-analytics Google Analytic addon for Storybook
+ */
+window.STORYBOOK_REACT_GA_OPTIONS = {};
diff --git a/.storybook/mock/sb-dataset.js b/.storybook/mock/sb-dataset.js
new file mode 100644
index 000000000..826f344b2
--- /dev/null
+++ b/.storybook/mock/sb-dataset.js
@@ -0,0 +1,239 @@
+/**
+ * Dataset used by Storybook stories.
+ *
+ * Copied from a NRN instance "window.__CYPRESS_DATA__" and pasted there.
+ */
+const dataset = {
+ 'reci9HYsoqd1xScsi': {
+ '__typename': 'Customer',
+ 'id': 'reci9HYsoqd1xScsi',
+ 'ref': 'customer1',
+ 'label': 'Client 1',
+ 'availableLanguages': ['en', 'fr'],
+ 'theme': {
+ '__typename': 'Theme',
+ 'id': 'recrcZANU6L73OA9v',
+ 'primaryColor': '#00536F',
+ 'primaryColorVariant1': null,
+ 'onPrimaryColor': null,
+ 'secondaryColor': '#C90016',
+ 'secondaryColorVariant1': null,
+ 'onSecondaryColor': null,
+ 'backgroundColor': null,
+ 'onBackgroundColor': null,
+ 'surfaceColor': null,
+ 'onSurfaceColor': null,
+ 'errorColor': null,
+ 'onErrorColor': null,
+ 'fonts': null,
+ 'logo': {
+ 'id': 'attlGNQqFXvhDYOrR',
+ 'url': 'https://dl.airtable.com/.attachments/a16bd38af1f3fea3f894dd2a37dbf4bd/baa538c3/apple-touch-icon.png',
+ 'filename': 'apple-touch-icon.png',
+ 'size': 11769,
+ 'type': 'image/png',
+ 'thumbnails': {
+ 'small': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/c8528519fa364ebc6c01a35834a06975/1720e171',
+ 'width': 36,
+ 'height': 36,
+ },
+ 'large': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/f0f1a95475af253ef157f36faf598c99/2da93bc7',
+ 'width': 180,
+ 'height': 180,
+ },
+ 'full': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/26551c4457369ea157cab82a2ac24368/8ea162cf',
+ 'width': 3000,
+ 'height': 3000,
+ },
+ },
+ },
+ 'logoTitle': 'Awesome-looking Logo',
+ },
+ 'products': [
+ {
+ '__typename': 'Product',
+ 'id': 'recFSrY2znI6Z8Dbj',
+ 'ref': 'hellur',
+ 'title': 'Hellur',
+ 'images': [
+ {
+ 'id': 'att6JU52f5PlMuiRu',
+ 'url': 'https://dl.airtable.com/Uvg7ldEEQpqKhR3NKTGt_348s.jpg',
+ 'filename': '348s.jpg',
+ 'size': 17866,
+ 'type': 'image/jpeg',
+ 'thumbnails': {
+ 'small': {
+ 'url': 'https://dl.airtable.com/8C4cVNCES89lt6PnFH5W_348s.jpg',
+ 'width': 36,
+ 'height': 36,
+ },
+ 'large': {
+ 'url': 'https://dl.airtable.com/TdSPVnVQISc0P0EdiiQw_348s.jpg',
+ 'width': 256,
+ 'height': 256,
+ },
+ },
+ },
+ ],
+ 'imagesTitle': ['Big City'],
+ 'description': 'Super longue **description**\n\nVous pouvez même [utiliser des liens](https://bluebottlecoffee.com/releases/costa-rica-vista-al-valle-honey)\n',
+ 'price': 25,
+ 'status': 'DRAFT',
+ },
+ {
+ '__typename': 'Product',
+ 'id': 'recXxSwjiehedMFPf',
+ 'ref': 'wow',
+ 'title': 'wow',
+ 'images': [
+ {
+ 'id': 'attIQzHRvFMgmdytF',
+ 'url': 'https://dl.airtable.com/.attachments/00f7560832b1500d06d169233424ccd0/c5d69a9e/lXL1TfOBTiikTCW8DPT2',
+ 'filename': 'lXL1TfOBTiikTCW8DPT2',
+ 'size': 64273,
+ 'type': 'image/jpeg',
+ 'thumbnails': {
+ 'small': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/8e2ab049c04e918ccf068eeb2363a24d/88511a89',
+ 'width': 54,
+ 'height': 36,
+ },
+ 'large': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/6897834d90716b4221e88de8a7e5d17b/beacabda',
+ 'width': 729,
+ 'height': 486,
+ },
+ 'full': {
+ 'url': 'https://dl.airtable.com/.attachmentThumbnails/d10c2858cbdd091db8ea5eb283d15ff5/8a483a20',
+ 'width': 3000,
+ 'height': 3000,
+ },
+ },
+ },
+ ],
+ 'imagesTitle': ['wow'],
+ 'description': 'w\n',
+ 'price': null,
+ 'status': 'PUBLISHED',
+ },
+ ],
+ 'serviceLabel': 'NRN demo 1',
+ 'termsDescription': '
\nYou can edit this through Stacker, see "Go to CMS" nav link.\n
Tooltip
component: I18nLink
component: I18nBtnChangeLocale
component:onClick
event for instance. You\'ll need to find workarounds for this kinds of things.I18nBtnChangeLocale
is a great example of that. No props, but changes the language for the whole app anyway, it\'s quite a powerful integration and very simple to use.\nvoid; } diff --git a/src/components/i18n/I18nLink.tsx b/src/components/i18n/I18nLink.tsx index 539267242..d6ebdb2a7 100644 --- a/src/components/i18n/I18nLink.tsx +++ b/src/components/i18n/I18nLink.tsx @@ -12,26 +12,102 @@ import { type ParamValueToForward = string | number | Array; -type Props = { +export type Props = { + /** + * Optional decorator for the path that will be shown in the browser URL bar. + */ as?: string; + + /** + * React node as children. + */ children: React.ReactNode; + + /** + * Additional CSS classes. + */ className?: string; + + /** + * The path or URL to navigate to. + */ href: string; + + /** + * The active locale is automatically prepended. locale allows for providing a different locale. + * + * @default current locale + */ locale?: string; // The locale can be specified, but it'll fallback to the current locale if unspecified + + /** + * Parameters to inject into the url, necessary when using route params (other than `locale`). + * + * Example: + * + * `/products/[id]` with `params={{ id: 5 }}` becomes `/products/5` + */ params?: { [key: string]: ParamValueToForward }; + + /** + * Forces Link to send the href property to its child. + * + * @default false + */ passHref?: boolean; + + /** + * Prefetch the page in the background. + * Any that is in the viewport (initially or through scroll) will be preloaded. + * Prefetch can be disabled by passing prefetch={false}. + * Pages using Static Generation will preload JSON files with the data for faster page transitions. + * + * @default true + */ prefetch?: boolean; + + /** + * Query to inject to the url, necessary when using route query param. + * + * Example: + * + * `/products` with `query={{ userId: 1 }}` becomes `/products?userId=1` + */ query?: { [key: string]: ParamValueToForward }; + + /** + * Replace the current history state instead of adding a new url into the stack. + * + * @default false + */ replace?: boolean; + + /** + * Scroll to the top of the page after a navigation. + * + * @default true + */ scroll?: boolean; + + /** + * Update the path of the current page without rerunning `getStaticProps`, `getServerSideProps` or `getInitialProps`. + * + * @default false + */ shallow?: boolean; + + /** + * Disabled on Storybook, as it crashes the UI. + */ wrapChildrenAsLink?: boolean; // Helper to avoid writing redundant code }; /** * Wrapper around the native Next.js component. Handles localised links. * - * Use the current active locale by default + * Uses the current active locale by default. + * + * [Read why we don't use the official Next.js `Link` component](https://unlyed.github.io/next-right-now/guides/i18n/#official-i18n-routing-implementation) Tip * * @example Recommended usage * Homepage diff --git a/src/components/pageLayouts/Footer.tsx b/src/components/pageLayouts/Footer.tsx index e11dba8d1..8f2f7b14b 100644 --- a/src/components/pageLayouts/Footer.tsx +++ b/src/components/pageLayouts/Footer.tsx @@ -1,21 +1,21 @@ -import { css } from '@emotion/react'; -import { useTheme } from '@emotion/react'; +import { + css, + useTheme, +} from '@emotion/react'; import React from 'react'; import { useTranslation } from 'react-i18next'; - import { NRN_CO_BRANDING_LOGO_URL } from '../../constants'; import useCustomer from '../../hooks/useCustomer'; import { CSSStyles } from '../../types/CSSStyles'; import { Asset } from '../../types/data/Asset'; import { Customer } from '../../types/data/Customer'; -import { CustomerTheme } from '../../types/data/CustomerTheme'; import { SIZE_XS } from '../../utils/assets/logo'; import GraphCMSAsset from '../assets/GraphCMSAsset'; import Logo from '../assets/Logo'; import I18nBtnChangeLocale from '../i18n/I18nBtnChangeLocale'; import I18nLink from '../i18n/I18nLink'; -type Props = { +export type Props = { style?: CSSStyles; }; diff --git a/src/components/pageLayouts/Head.tsx b/src/components/pageLayouts/Head.tsx index 42d5596d6..3599d9543 100644 --- a/src/components/pageLayouts/Head.tsx +++ b/src/components/pageLayouts/Head.tsx @@ -24,7 +24,7 @@ export type HeadProps = { * https://github.com/vercel/next.js#populating-head */ const Head: React.FunctionComponent= (props): JSX.Element => { - const defaultDescription = 'Flexible production-grade boilerplate with Next.js 9, Vercel and TypeScript. Includes multiple opt-in presets using Airtable, Analytics, CSS-in-JS, Monitoring, End-to-end testing, Internationalization, CI/CD and SaaS B2B multiple single-tenants (monorepo) support'; + const defaultDescription = 'Flexible production-grade boilerplate with Next.js 9, Vercel and TypeScript. Includes multiple opt-in presets using Storybook, GraphQL, Analytics, CSS-in-JS, Monitoring, End-to-end testing, Internationalization, CI/CD and SaaS B2B multiple single-tenants (monorepo) support'; const defaultMetaURL = 'https://github.com/UnlyEd/next-right-now'; const defaultMetaImage = ''; const defaultFavicon = ''; diff --git a/src/components/pageLayouts/Nav.tsx b/src/components/pageLayouts/Nav.tsx index 999bea851..c6f1a745a 100644 --- a/src/components/pageLayouts/Nav.tsx +++ b/src/components/pageLayouts/Nav.tsx @@ -1,8 +1,10 @@ import { Amplitude } from '@amplitude/react-amplitude'; -import { css } from '@emotion/react'; +import { + css, + useTheme, +} from '@emotion/react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classnames from 'classnames'; -import { useTheme } from '@emotion/react'; import kebabCase from 'lodash.kebabcase'; import map from 'lodash.map'; import { @@ -24,10 +26,8 @@ import { UncontrolledDropdown, } from 'reactstrap'; import useI18n, { I18n } from '../../hooks/useI18n'; -import customerContext, { CustomerContext } from '../../stores/customerContext'; import { LogEvent } from '../../types/Amplitude'; import { Asset } from '../../types/data/Asset'; -import { CustomerTheme } from '../../types/data/CustomerTheme'; import { SidebarLink } from '../../types/SidebarLink'; import { isActive, @@ -40,14 +40,17 @@ import { NATIVE_FEATURES_SIDEBAR_LINKS } from '../doc/NativeFeaturesSidebar'; import I18nLink from '../i18n/I18nLink'; import Tooltip from '../utils/Tooltip'; -type Props = {}; +export type Props = {}; const Nav: React.FunctionComponent = () => { const { t } = useTranslation(); const router: NextRouter = useRouter(); const theme = useTheme(); const { locale }: I18n = useI18n(); - const { primaryColor, logo } = theme; + const { + primaryColor, + logo, + } = theme; return ( @@ -83,12 +86,12 @@ const Nav: React.FunctionComponent = () => { } .navItemsMenu { - padding:0 10px; + padding: 0 10px; @media (max-width: 991.98px) { a { font-size: 12px; - color: rgba(0,0,0,0.30) !important; + color: rgba(0, 0, 0, 0.30) !important; } } } @@ -150,7 +153,11 @@ const Nav: React.FunctionComponent = () => { = () => { Native features { map(NATIVE_FEATURES_SIDEBAR_LINKS, (link: SidebarLink) => { - const { label, href, params = null } = link; + const { + label, + href, + params = null, + } = link; + return (@@ -206,7 +218,12 @@ const Nav: React.FunctionComponent = () => { Built-in features { map(BUILT_IN_FEATURES_SIDEBAR_LINKS, (link: SidebarLink) => { - const { label, href, params = null } = link; + const { + label, + href, + params = null, + } = link; + return (@@ -223,7 +240,12 @@ const Nav: React.FunctionComponent = () => { Built-in utilities { map(BUILT_IN_UTILITIES_SIDEBAR_LINKS, (link: SidebarLink) => { - const { label, href, params = null } = link; + const { + label, + href, + params = null, + } = link; + return (diff --git a/src/components/pageLayouts/PreviewModeBanner.tsx b/src/components/pageLayouts/PreviewModeBanner.tsx index 6706e8989..f20afdc2f 100644 --- a/src/components/pageLayouts/PreviewModeBanner.tsx +++ b/src/components/pageLayouts/PreviewModeBanner.tsx @@ -1,6 +1,8 @@ -import { css } from '@emotion/react'; +import { + css, + useTheme, +} from '@emotion/react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useTheme } from '@emotion/react'; import { NextRouter, useRouter, @@ -10,21 +12,19 @@ import { Trans, useTranslation, } from 'react-i18next'; - import usePreviewMode, { PreviewMode } from '../../hooks/usePreviewMode'; -import { CustomerTheme } from '../../types/data/CustomerTheme'; import { stringifyQueryParameters } from '../../utils/app/router'; import { startPreviewMode, stopPreviewMode, } from '../../utils/nextjs/previewMode'; -import ExternalLink from '../utils/ExternalLink'; import Btn from '../utils/Btn'; +import ExternalLink from '../utils/ExternalLink'; import Tooltip from '../utils/Tooltip'; -type Props = {} +export type Props = {} -const ExplanationTooltipOverlay: React.FunctionComponent = (): JSX.Element => { +export const ExplanationTooltipOverlay: React.FunctionComponent = (): JSX.Element => { return ( = (props): JSX.Element = const queryParameters: string = stringifyQueryParameters(router); const { t } = useTranslation(); const { - secondaryColor, secondaryColorVariant1, onSecondaryColor, + secondaryColor, + secondaryColorVariant1, + onSecondaryColor, } = useTheme(); if (process.env.NEXT_PUBLIC_APP_STAGE === 'production') { diff --git a/src/components/pageLayouts/QuickPreviewBanner.tsx b/src/components/pageLayouts/QuickPreviewBanner.tsx index b1be9944b..979bee6a9 100644 --- a/src/components/pageLayouts/QuickPreviewBanner.tsx +++ b/src/components/pageLayouts/QuickPreviewBanner.tsx @@ -1,7 +1,9 @@ -import { css } from '@emotion/react'; +import { + css, + useTheme, +} from '@emotion/react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { createLogger } from '@unly/utils-simple-logger'; -import { useTheme } from '@emotion/react'; import { NextRouter, useRouter, @@ -10,7 +12,6 @@ import React, { Fragment } from 'react'; import { useTranslation } from 'react-i18next'; import useCustomer from '../../hooks/useCustomer'; import { Customer } from '../../types/data/Customer'; -import { CustomerTheme } from '../../types/data/CustomerTheme'; import I18nBtnChangeLocale from '../i18n/I18nBtnChangeLocale'; import Btn from '../utils/Btn'; import Tooltip from '../utils/Tooltip'; @@ -20,7 +21,7 @@ const logger = createLogger({ label: fileLabel, }); -type Props = { +export type Props = { ExplanationTooltipOverlay?: React.FunctionComponent; LeftActions?: React.FunctionComponent; quickPreviewTitle?: string; @@ -44,7 +45,9 @@ const QuickPreviewBanner: React.FunctionComponent = (props): JSX.Element quickPreviewTitle, } = props; const { - secondaryColor, secondaryColorVariant1, onSecondaryColor, + secondaryColor, + secondaryColorVariant1, + onSecondaryColor, } = useTheme(); const { t } = useTranslation(); const router: NextRouter = useRouter(); @@ -87,7 +90,7 @@ const QuickPreviewBanner: React.FunctionComponent = (props): JSX.Element align-items: center; } } - `} + `} > { diff --git a/src/components/rehydration/DisplayOnBrowserMount.tsx b/src/components/rehydration/DisplayOnBrowserMount.tsx index 7d444e7e7..100f38665 100644 --- a/src/components/rehydration/DisplayOnBrowserMount.tsx +++ b/src/components/rehydration/DisplayOnBrowserMount.tsx @@ -6,7 +6,7 @@ import React, { useState, } from 'react'; -type Props = { +export type Props = { children: React.ReactNode; deps?: DependencyList; }; diff --git a/src/components/svg/Animated3Dots.tsx b/src/components/svg/Animated3Dots.tsx index 41c4e04a4..09050a368 100644 --- a/src/components/svg/Animated3Dots.tsx +++ b/src/components/svg/Animated3Dots.tsx @@ -1,5 +1,9 @@ import React from 'react'; +export type Props = { + fill: string; +}; + /** * An animated composant featuring 3 animated dots "...". * @@ -8,7 +12,7 @@ import React from 'react'; * * @see https://animate.style */ -const Animated3Dots = (props): JSX.Element => { +const Animated3Dots = (props: Props): JSX.Element => { return (