diff --git a/.eslintrc.json b/.eslintrc.json index 6bb2a68c4..4e13dedff 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,7 +20,8 @@ }, "globals": { "React": "writable", - "NodeJS": "writable" + "NodeJS": "writable", + "JSX": "writable" }, "rules": { "react/no-unescaped-entities": "off", @@ -33,7 +34,7 @@ "jsx-a11y/label-has-associated-control": 1, "react/jsx-no-target-blank": 1, "no-unreachable": 1, - "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-assignment": "off", "react-hooks/exhaustive-deps": "error" diff --git a/.github/workflows/check-links-validity.yaml b/.github/workflows/check-links-validity.yaml new file mode 100644 index 000000000..e48b0046f --- /dev/null +++ b/.github/workflows/check-links-validity.yaml @@ -0,0 +1,22 @@ +name: Check links validity +on: + workflow_dispatch: + schedule: + # https://crontab.guru/#0_11_*_*_2 + - cron: '0 11 * * 2' +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/install + - name: Install RipGrep + run: sudo apt install -y ripgrep + - id: invalid_links + run: node ./scripts/check-links-validity.mjs --ci + timeout-minutes: 15 + - if: steps.invalid_links.outputs.comment + uses: ./.github/actions/reopen-issue-with-comment + with: + issue-number: 225 + comment: ${{ steps.invalid_links.outputs.comment }} diff --git a/.github/workflows/e2e-snapshots.yaml b/.github/workflows/e2e-snapshots.yaml index 2cbb7e0c4..24d2f7fdc 100644 --- a/.github/workflows/e2e-snapshots.yaml +++ b/.github/workflows/e2e-snapshots.yaml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest needs: sleep container: - image: cypress/browsers:node18.12.0-chrome107 + image: cypress/browsers:latest options: --user 1001 strategy: fail-fast: false diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 83aff50c3..2df3efde1 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -13,23 +13,26 @@ on: jobs: sleep: - name: Wait 3 min for the Vercel preview to be deployed + name: Wait for the vercel build to complete runs-on: ubuntu-latest steps: - - name: Sleep for 90s - run: sleep 90s - shell: bash + - name: Waiting for Vercel Preview + uses: patrickedqvist/wait-for-vercel-preview@v1.3.1 + id: waitForVercel + with: + token: ${{ secrets.GITHUB_TOKEN }} + max_timeout: 300 - e2e: + cypress-run: runs-on: ubuntu-latest - needs: sleep + needs: [sleep] container: - image: cypress/browsers:node18.12.0-chrome107 + image: cypress/browsers:latest options: --user 1001 strategy: fail-fast: false matrix: - containers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] + containers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] name: Testing e2e in worker ${{ matrix.containers }} if: github.event.pull_request.draft == false steps: @@ -55,7 +58,6 @@ jobs: - name: Test - e2e [${{ env.MODE }}] uses: cypress-io/github-action@v5.6.1 with: - install: true build: yarn run e2e:generate:personas browser: chrome parallel: true diff --git a/.gitignore b/.gitignore index d5327099e..b33e33861 100644 --- a/.gitignore +++ b/.gitignore @@ -43,9 +43,6 @@ yarn-error.log node_modules/ .env -# Local Netlify folder -.netlify - /cypress/videos/* /cypress/screenshots/* /cypress/snapshots/__all/__diff_output__/**/* @@ -55,3 +52,5 @@ dist # Sentry Config File .sentryclirc + +.vscode diff --git a/.nvmrc b/.nvmrc index 25bf17fc5..aacb51810 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18 \ No newline at end of file +18.17 diff --git a/config/redirects.js b/config/redirects.js new file mode 100644 index 000000000..84804adae --- /dev/null +++ b/config/redirects.js @@ -0,0 +1,64 @@ +const redirects = [ + { + source: '/actions/liste', + destination: '/actions', + permanent: true, + }, + { + source: '/groupes/:path*', + destination: '/amis/:path*', + permanent: true, + }, + { + source: '/conférence/:path*', + destination: 'https://sondages.nosgestesclimat.fr/conférence/:path*', + permanent: true, + }, + { + source: '/sondage/:path*', + destination: 'https://sondages.nosgestesclimat.fr/sondage/:path*', + permanent: true, + }, + { + source: '/mon-empreinte-carbone/:path*', + destination: '/fin/:path*', + permanent: true, + }, + { + source: '/nouveaut%C3%A9s/:path*', + destination: '/nouveautes/:path*', + permanent: true, + }, + { + source: '/vie-priv%C3%A9e', + destination: '/vie-privee', + permanent: true, + }, + { + source: '/partenaires', + destination: '/diffuser', + permanent: true, + }, + { + source: '/blog/journée-mondial-environnement', + destination: '/blog/journee-mondial-environnement', + permanent: true, + }, + { + source: '/mod%C3%A8le', + destination: '/modele', + permanent: true, + }, + { + source: '/%C3%A0-propos', + destination: '/a-propos', + permanent: true, + }, + { + source: '/groupe/:path*', + destination: 'https://sondages.nosgestesclimat.fr/', + permanent: true, + }, +] + +module.exports = redirects diff --git a/cypress.config.js b/cypress.config.js index 0693444e4..61bf54156 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -20,7 +20,6 @@ export default defineConfig({ experimentalRunAllSpecs: true, specPattern: 'cypress/e2e/**/*.cy.js', }, - component: { devServer: { framework: 'next', diff --git a/cypress/e2e/integration/pages/groupes.cy.js b/cypress/e2e/integration/pages/groupes.cy.js index 7faa57568..57e8784d9 100644 --- a/cypress/e2e/integration/pages/groupes.cy.js +++ b/cypress/e2e/integration/pages/groupes.cy.js @@ -8,8 +8,6 @@ describe( 'The Group creation page /amis/creer', { testIsolation: false }, () => { - let groupURL = '' - it('allows to create a new group and displays it afterwards', () => { cy.visit('/amis') @@ -22,14 +20,10 @@ describe( ) cy.get('[data-cypress-id="button-create-group"]').click() - cy.wait(2000) - // Fill simulation clickSkipTutorialButton() recursivelyFillSimulation(null, 'group') - cy.wait(2000) - cy.get('[data-cypress-id="group-name"]') // Check that we can create a second group @@ -59,18 +53,12 @@ describe( cy.clearLocalStorage() cy.reload() - cy.wait(2000) - cy.get('[data-cypress-id="member-name"]').type('Jean-Claude') cy.get('[data-cypress-id="button-join-group"]').click() - cy.wait(2000) - clickSkipTutorialButton() recursivelyFillSimulation(null, 'group') - cy.wait(2000) - cy.get('[data-cypress-id="group-name"]') // Check that the main sections are displayed diff --git a/cypress/helpers/elements/buttons.js b/cypress/helpers/elements/buttons.js index 0d408ae98..56eecf04d 100644 --- a/cypress/helpers/elements/buttons.js +++ b/cypress/helpers/elements/buttons.js @@ -54,5 +54,5 @@ export function clickDoTheTestLink() { } export function clickAmisLink() { - click(AMIS_LINK) + cy.get(`[data-cypress-id="${AMIS_LINK}"]`).eq(1).click() } diff --git a/cypress/helpers/interactions/click.js b/cypress/helpers/interactions/click.js index 25e4013e5..962f7ed57 100644 --- a/cypress/helpers/interactions/click.js +++ b/cypress/helpers/interactions/click.js @@ -1,3 +1,3 @@ -export function click(elementId) { - cy.get(`[data-cypress-id="${elementId}"]`).click() +export function click(elementId, options = {}) { + cy.get(`[data-cypress-id="${elementId}"]`).first().click() } diff --git a/cypress/helpers/simulation/recursivelyFillSimulation.js b/cypress/helpers/simulation/recursivelyFillSimulation.js index 54469be14..4fa8ff1a7 100644 --- a/cypress/helpers/simulation/recursivelyFillSimulation.js +++ b/cypress/helpers/simulation/recursivelyFillSimulation.js @@ -30,8 +30,6 @@ export async function recursivelyFillSimulation(persona = {}) { function skipQuestion() { clickNextButton() - cy.wait(1000) - answerCurrentQuestion() } @@ -39,8 +37,6 @@ export async function recursivelyFillSimulation(persona = {}) { if (dottedName === LAST_QUESTION_ID) { clickNextButton() - cy.wait(1000) - return resolve() } @@ -54,8 +50,6 @@ export async function recursivelyFillSimulation(persona = {}) { const [dottedNameWithoutValueSuffix, value] = dottedName.split('-') if (persona?.situation?.[dottedNameWithoutValueSuffix] === value) { cy.get(`label[data-cypress-id="${dottedName}-label"]`).click() - - cy.wait(1000) } else if (!dottedName === LAST_QUESTION_ID) { skipQuestion() } @@ -72,8 +66,6 @@ export async function recursivelyFillSimulation(persona = {}) { cy.get(`input[data-cypress-id="${dottedName}"]`).type( persona.situation[dottedName] ) - - cy.wait(1000) } const mosaicChildren = Object.keys(persona?.situation ?? {}).filter( @@ -86,17 +78,11 @@ export async function recursivelyFillSimulation(persona = {}) { cy.get( `input[data-cypress-id="${mosaicItemDottedName}---${mosaicDottedName}"]` ).type(persona.situation[mosaicItemDottedName]) - - cy.wait(1000) } } - cy.wait(1000) - clickNextButton() - cy.wait(1000) - // Call itself recursively to go to the next question answerCurrentQuestion() }) diff --git a/cypress/helpers/simulation/setupSimulation.js b/cypress/helpers/simulation/setupSimulation.js index 180cc2594..c368c5a04 100644 --- a/cypress/helpers/simulation/setupSimulation.js +++ b/cypress/helpers/simulation/setupSimulation.js @@ -5,10 +5,5 @@ import { export function setupSimulation() { clickDoTheTestLink() - - cy.wait(2000) - clickSkipTutorialButton() - - cy.wait(2000) } diff --git a/i18nConfig.js b/i18nConfig.js deleted file mode 100644 index 9d93370b3..000000000 --- a/i18nConfig.js +++ /dev/null @@ -1,6 +0,0 @@ -const i18nConfig = { - locales: ['fr', 'en'], - defaultLocale: 'fr', -} - -module.exports = i18nConfig diff --git a/next.config.js b/next.config.js index 3bb10b1cc..80f8f9065 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,11 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + const withMDX = require('@next/mdx')({ extension: /\.mdx$/, }) +const redirects = require('./config/redirects.js') + /** @type {import('next').NextConfig} */ const nextConfig = { // Configure pageExtensions to include md and mdx @@ -13,6 +17,10 @@ const nextConfig = { test: /\.ya?ml$/, use: 'js-yaml-loader', }) + config.module.rules.push({ + test: /\.publicodes$/, + use: 'js-yaml-loader', + }) config.resolve.fallback = { // if you miss it, all the other options in fallback, specified @@ -53,53 +61,7 @@ const nextConfig = { ], }, async redirects() { - return [ - { - source: '/actions/liste', - destination: '/actions', - permanent: true, - }, - { - source: '/groupes/:path*', - destination: '/amis/:path*', - permanent: true, - }, - { - source: '/conférence/:path*', - destination: 'https://sondages.nosgestesclimat.fr/conférence/:path*', - permanent: true, - }, - { - source: '/sondage/:path*', - destination: 'https://sondages.nosgestesclimat.fr/sondage/:path*', - permanent: true, - }, - { - source: '/mon-empreinte-carbone/:path*', - destination: '/fin/:path*', - permanent: true, - }, - { - source: '/nouveaut%C3%A9s', - destination: '/nouveautes', - permanent: true, - }, - { - source: '/vie-priv%C3%A9e', - destination: '/vie-privee', - permanent: true, - }, - { - source: '/partenaires', - destination: '/diffuser', - permanent: true, - }, - { - source: '/blog/journée-mondial-environnement', - destination: '/blog/journee-mondial-environnement', - permanent: true, - }, - ] + return redirects }, experimental: { mdxRs: true, diff --git a/package.json b/package.json index 58aaf2d36..236f2d786 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ "url": "https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs.git" }, "engines": { - "node": "18.x" + "node": "<20" }, "scripts": { "dev": "next dev", - "dev:model": "NEXT_PUBLIC_LOCAL_DATA_SERVER=http://localhost:9000 next dev", + "dev:model": "NEXT_PUBLIC_LOCAL_DATA=nosgestesclimat next dev", "build": "next build", "start": "next start", "lint": "next lint", @@ -23,41 +23,42 @@ "ui:translate": "node scripts/i18n/translate-ui.js", "faq:translate": "node scripts/i18n/translate-faq.js", "faq:check": "node scripts/i18n/check-faq.js", - "pages:translate": "node scripts/i18n/translate-pages.js", + "pages:translate": "node scripts/i18n/translate-pages.cjs", + "nouveautes:translate": "node scripts/i18n/translate-nouveautes.cjs", "releases:fetch": "node scripts/fetch-releases.js", "releases:translate": "node scripts/i18n/translate-release.js" }, "dependencies": { "@babel/runtime": "^7.23.1", - "@mdx-js/loader": "^2.3.0", - "@mdx-js/react": "^2.3.0", - "@next/mdx": "^13.5.4", - "@sentry/nextjs": "^7.73.0", - "@sentry/react": "^7.73.0", + "@mdx-js/loader": "^3.0.0", + "@mdx-js/react": "^3.0.0", + "@next/mdx": "^14.0.2", + "@sentry/nextjs": "^7.80.0", + "@sentry/react": "^7.80.0", "@svgr/webpack": "8.1.0", - "@tanstack/react-query": "^4.35.7", - "axios": "^1.5.1", + "@tanstack/react-query": "^5.8.3", + "axios": "^1.6.0", "buffer": "^6.0.3", "chrome-aws-lambda": "^10.1.0", - "core-js": "^3.33.0", + "core-js": "^3.33.2", "framer-motion": "^10.16.4", "fuse.js": "6.6.2", "gray-matter": "^4.0.3", "html-to-image": "^1.11.11", "html-webpack-plugin": "^5.5.3", - "i18next": "^23.5.1", - "i18next-browser-languagedetector": "^7.1.0", + "i18next": "^23.7.6", + "i18next-browser-languagedetector": "^7.2.0", "i18next-parser": "^8.8.0", - "i18next-resources-to-backend": "^1.1.4", + "i18next-resources-to-backend": "^1.2.0", "js-yaml-loader": "^1.2.2", "markdown-to-jsx": "^7.3.2", - "next": "^13.5.4", + "next": "14.0.2", "next-i18n-router": "^4.1.1", "postcss": "8.4.31", "process": "^0.11.10", "publicodes": "^1.0.0-beta.77", "publicodes-react": "^1.0.0-beta.76", - "puppeteer-core": "^21.3.8", + "puppeteer-core": "^21.5.1", "qrcode.react": "^3.1.0", "ramda": "^0.29.1", "react": "18.2.0", @@ -65,23 +66,24 @@ "react-dom": "18.2.0", "react-easy-emoji": "^1.8.1", "react-flip-toolkit": "^7.1.0", - "react-i18next": "^13.2.2", + "react-i18next": "^13.4.1", + "react-markdown": "^9.0.1", "react-number-format": "^5.3.1", "react-query": "^3.39.3", "react-refresh": "^0.14.0", "react-signature-pad-wrapper": "^3.3.3", "react-slick": "^0.29.0", - "recharts": "^2.8.0", + "recharts": "^2.9.3", "regenerator-runtime": "^0.14.0", "remark-embed-images": "^4.0.0", "remark-footnotes": "^4.0.1", "reselect": "^4.1.8", "sharp": "^0.32.6", "socket.io-client": "^4.7.2", - "tailwind-merge": "^1.14.0", - "tailwindcss": "3.3.3", + "tailwind-merge": "^2.0.0", + "tailwindcss": "3.3.5", "tinygradient": "^1.1.5", - "translation-check": "^1.0.3", + "translation-check": "^1.1.0", "twemoji": "^14.0.2", "uuid": "^9.0.1", "yaml": "^2.3.2", @@ -92,49 +94,49 @@ "> 1% in FR" ], "devDependencies": { - "@babel/eslint-parser": "^7.22.15", + "@babel/eslint-parser": "^7.23.3", "@incubateur-ademe/nosgestesclimat-scripts": "^0.2.2", "@simonsmith/cypress-image-snapshot": "^9.0.1", "@svgr/cli": "^8.1.0", - "@types/cheerio": "^0.22.32", - "@types/crypto-js": "^4.1.2", - "@types/mdx": "^2.0.8", - "@types/node": "^20.8.2", - "@types/react": "^18.2.25", - "@types/react-color": "^3.0.7", - "@types/react-dom": "^18.2.10", - "@types/react-slick": "^0.23.10", - "@types/uuid": "^9.0.4", - "@types/webpack": "^5.28.3", - "@typescript-eslint/eslint-plugin": "^6.7.4", - "@typescript-eslint/parser": "^6.7.4", + "@types/cheerio": "^0.22.34", + "@types/crypto-js": "^4.2.1", + "@types/mdx": "^2.0.10", + "@types/node": "^20.9.0", + "@types/react": "^18.2.37", + "@types/react-color": "^3.0.10", + "@types/react-dom": "^18.2.15", + "@types/react-slick": "^0.23.12", + "@types/uuid": "^9.0.7", + "@types/webpack": "^5.28.5", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", "autoprefixer": "^10.4.16", "cli-progress": "^3.12.0", "csv-loader": "^3.0.5", - "cypress": "13.3.0", + "cypress": "13.5.0", "cypress-plugin-tab": "^1.0.5", "cypress-recurse": "^1.35.2", "deepl-node": "^1.10.2", "dotenv": "^16.3.1", - "eslint": "^8.50.0", - "eslint-config-next": "13.5.4", + "eslint": "^8.52.0", + "eslint-config-next": "14.0.2", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.28.1", - "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "file-loader": "^6.2.0", "intl-locales-supported": "^1.8.11", "isomorphic-fetch": "^3.0.0", - "json-stable-stringify": "^1.0.2", + "json-stable-stringify": "^1.1.0", "node-pandoc-promise": "^0.0.6", "nodemon": "^3.0.1", "postcss-loader": "^7.3.3", - "prettier": "^3.0.3", - "prettier-plugin-organize-imports": "^3.2.3", - "prettier-plugin-tailwindcss": "0.5.5", + "prettier": "^3.1.0", + "prettier-plugin-organize-imports": "^3.2.4", + "prettier-plugin-tailwindcss": "0.5.7", "prompt-sync": "^4.2.0", "toml-loader": "^1.0.0", "ts-node": "^10.9.1", diff --git a/public/demo-iframe.html b/public/demo-iframe.html new file mode 100644 index 000000000..63c61e839 --- /dev/null +++ b/public/demo-iframe.html @@ -0,0 +1,20 @@ + + + + + + Demo Iframe + + +
+

iframe paramétré

+

Ci-dessous, nosgestesclimat.fr intégré comme un iframe paramétré.

+
+
+ +
+ + diff --git a/public/demo-iframeSimulation.html b/public/demo-iframeSimulation.html new file mode 100644 index 000000000..61b2486bb --- /dev/null +++ b/public/demo-iframeSimulation.html @@ -0,0 +1,27 @@ + + + + + + Demo Iframe Simulation + + +
+

+ Exemple d'intégration du test avec région fixée par l'intégrateur. +

+

+ Ci-dessous, nosgestesclimat.fr intégré comme un iframe paramétré ne + contenant que la partie simulation du test. Dans cet exemple, la Suisse + a été définie comme étant la région par défaut du test. +

+
+
+ +
+ + diff --git a/public/iframe.js b/public/iframe.js index 4c0ed890d..520f3db86 100644 --- a/public/iframe.js +++ b/public/iframe.js @@ -9,7 +9,6 @@ const hostname = srcURL.origin || 'nosgestesclimat.fr' const possibleOptions = [ { key: 'shareData', legacy: 'partagedatafinsimulation' }, - { key: 'lang' }, ] const optionFragments = possibleOptions.map(({ key, legacy }) => { diff --git a/public/iframeSimulation.js b/public/iframeSimulation.js index afd92cbd7..536c1924f 100644 --- a/public/iframeSimulation.js +++ b/public/iframeSimulation.js @@ -21,7 +21,11 @@ const optionFragments = possibleOptions.map(({ key, legacy }) => { return value != null ? `&${key === 'pr' ? 'PR' : key}=${value}` : '' }) -const src = `${hostname}/simulateur/bilan/?iframe&integratorUrl=${integratorUrl}${optionFragments.join( +const lang = script.dataset.lang + +const src = `${hostname}/${ + lang && lang + '/' +}simulateur/bilan/?iframe&integratorUrl=${integratorUrl}${optionFragments.join( '' )}` diff --git a/public/images/blog/alexandre-lecocq-climatiseurs.jpg b/public/images/blog/alexandre-lecocq-climatiseurs.jpg new file mode 100644 index 000000000..8f42da3c7 Binary files /dev/null and b/public/images/blog/alexandre-lecocq-climatiseurs.jpg differ diff --git a/public/images/blog/matt-benson-chien-baignade.jpg b/public/images/blog/matt-benson-chien-baignade.jpg new file mode 100644 index 000000000..8650a765f Binary files /dev/null and b/public/images/blog/matt-benson-chien-baignade.jpg differ diff --git a/public/images/misc/challenge-v2.png b/public/images/misc/challenge-v2.png new file mode 100755 index 000000000..a07ef064a Binary files /dev/null and b/public/images/misc/challenge-v2.png differ diff --git a/public/images/misc/challenge.png b/public/images/misc/challenge.png deleted file mode 100644 index 291b28ed0..000000000 Binary files a/public/images/misc/challenge.png and /dev/null differ diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index 363c5d8e6..671c815ce 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -3,7 +3,7 @@ "description": "Calcule ton empreinte sur le climat", "display": "standalone", "lang": "fr", - "orientation": "portrait-primary", + "orientation": "portrait-primary-500", "theme_color": "#532fc5", "icons": [ { diff --git a/scripts/check-links-validity.mjs b/scripts/check-links-validity.mjs new file mode 100644 index 000000000..e1ea100b7 --- /dev/null +++ b/scripts/check-links-validity.mjs @@ -0,0 +1,120 @@ +import { exec } from 'child_process' +import { promisify } from 'util' + +import * as core from '@actions/core' +import dotenv from 'dotenv' + +dotenv.config() + +const whiteList = [ + 'http://localhost', + 'https://data.nosgestesclimat.fr', + 'https://api.github.com/repos/', + 'https://deploy-preview-', + 'https://xxx.png/jpg', + 'https://ogimager.osc-fr1.scalingo.io/capture/', +] + +// Extrait la liste des liens référencés dans la base de code +const { stdout, stderr } = await promisify(exec)( + "rg -oNI -e 'https?://([\\w/_\\-?=%+@]|\\.\\w)+' -g '*.{yaml,ts,tsx,js,jsx}' -g '!*-en.yaml' ./ | sort | uniq" +) +if (stderr) { + throw new Error(stderr) +} + +const links = stdout + .split('\n') + .filter(Boolean) + .filter((link) => !whiteList.some((item) => link.startsWith(item))) + +// Certains sites référencés ont des problèmes de certificats, mais ce n'est pas +// ce que nous cherchons à détecter ici. +process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0 + +// Création d'une queue permettant de paralléliser la vérification des liens +const queue = [...links] +const detectedErrors = [] +const simultaneousItems = 5 + +async function processNextQueueItem() { + if (queue.length !== 0) { + await fetchAndReport(queue.shift()) + await processNextQueueItem() + } +} + +async function fetchAndReport(link) { + let status = await getHTTPStatus(link) + + // Retries in case of timeout + let remainingRetries = 3 + while (status === 499 && remainingRetries > 0) { + remainingRetries-- + await sleep(15_000) + status = await getHTTPStatus(link) + } + report({ status, link }) +} + +async function getHTTPStatus(link) { + const maxTime = 15_000 + const controller = new AbortController() + setTimeout(() => controller.abort(), maxTime) + + try { + const res = await fetch(link, { signal: controller.signal }) + return res.status + } catch (err) { + return 499 + } +} + +function report({ status, link }) { + console.log(status >= 404 ? '❌' : status >= 400 ? '⬛' : '✅', status, link) + if (status >= 404 && status !== 499) { + detectedErrors.push({ status, link }) + } +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +await Promise.allSettled( + Array.from({ length: simultaneousItems }).map(processNextQueueItem) +) + +console.log('Terminé') + +if (detectedErrors.length > 0) { + // Formattage spécifique pour récupérer le résultat avec l'action Github + if (process.argv.slice(2).includes('--ci')) { + const message = ` + + Certains liens référencés ne semblent plus fonctionner : + + | Status HTTP | Lien | + |---|---| + ${detectedErrors + .map(({ status, link }) => `| ${status} | ${link} |`) + .join('\n')}` + + const format = (msg) => + msg + .trim() + .split('\n') + .map((line) => line.trim()) + .join('
') + core.setOutput('comment', format(message)) + } else if (detectedErrors) { + core.setFailed( + 'Liens invalides :' + + detectedErrors + .map(({ status, link }) => `\n- [${status}] ${link}`) + .join('') + ) + } +} + +process.exit(0) diff --git a/scripts/i18n/translate-nouveautes.cjs b/scripts/i18n/translate-nouveautes.cjs new file mode 100644 index 000000000..fcbb5e2f7 --- /dev/null +++ b/scripts/i18n/translate-nouveautes.cjs @@ -0,0 +1,65 @@ +/* + Calls the DeepL API to translate the Markdown files. + + Command: yarn translate:md [options] +*/ + +const fs = require('fs') +const glob = require('glob') + +const deepl = require('@incubateur-ademe/nosgestesclimat-scripts/deepl') +const cli = require('@incubateur-ademe/nosgestesclimat-scripts/cli') + +const { srcLang, destLangs, srcFile, force } = cli.getArgs( + 'Calls the DeepL API to translate the Markdown files.', + { + file: true, + source: true, + force: true, + target: true, + } +) + +const fileGlob = srcFile ?? '*.{md,mdx}' + +const translateTo = async (src, destPath, destLang) => { + console.log(`Translating to ${cli.yellow(destPath)}...`) + const translation = await deepl.fetchTranslationMarkdown( + src, + srcLang.toUpperCase(), + destLang.toUpperCase() + ) + fs.writeFileSync(destPath, translation, 'utf8', { flag: 'w' }) +} + +console.log( + `Translating Markdown files from ${cli.yellow( + `src/locales/nouveautes/${srcLang}/${fileGlob}` + )}...` +) +glob(`src/locales/nouveautes/${srcLang}/${fileGlob}`, (err, files) => { + cli.exitIfError(err, 'ERROR: an error occured while fetching the files:') + console.log( + `Found ${cli.withStyle( + cli.colors.fgGreen, + files.length + )} files to translate.` + ) + + console.log('files', files) + files.forEach((file) => { + const src = fs.readFileSync(file, 'utf8') + destLangs.forEach((destLang) => { + const destPath = file.replace(srcLang, destLang) + if (!fs.existsSync(destPath) || force) { + translateTo(src, destPath, destLang) + } else { + console.log( + `The file ${cli.yellow(destPath)} already exists, ${cli.yellow( + 'skipping' + )}... (use the -f to force the translation)` + ) + } + }) + }) +}) diff --git a/scripts/i18n/translate-pages.js b/scripts/i18n/translate-pages.cjs similarity index 97% rename from scripts/i18n/translate-pages.js rename to scripts/i18n/translate-pages.cjs index 5ab928188..7f649c1a9 100644 --- a/scripts/i18n/translate-pages.js +++ b/scripts/i18n/translate-pages.cjs @@ -34,7 +34,7 @@ const translateTo = async (src, destPath, destLang) => { console.log( `Translating Markdown files from ${cli.yellow( - `source/locales/pages/${srcLang}/${fileGlob}` + `src/locales/pages/${srcLang}/${fileGlob}` )}...` ) glob(`src/locales/pages/${srcLang}/${fileGlob}`, (err, files) => { diff --git a/sentry.client.config.ts b/sentry.client.config.ts index 42f1a110a..d3b710595 100644 --- a/sentry.client.config.ts +++ b/sentry.client.config.ts @@ -28,6 +28,6 @@ Sentry.init({ }), ], - // Disable sentry for development based on local data server - enabled: !process.env.NEXT_PUBLIC_LOCAL_DATA_SERVER, + // Disable sentry for development based on local data + enabled: !process.env.NEXT_PUBLIC_LOCAL_DATA, }) diff --git a/sentry.server.config.ts b/sentry.server.config.ts index 0560449da..bbfc2554b 100644 --- a/sentry.server.config.ts +++ b/sentry.server.config.ts @@ -13,6 +13,6 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, - // Disable sentry for development based on local data server - enabled: !process.env.NEXT_PUBLIC_LOCAL_DATA_SERVER, + // Disable sentry for development based on local data + enabled: !process.env.NEXT_PUBLIC_LOCAL_DATA, }) diff --git a/src/app/(iframe)/demo-iframe/page.tsx b/src/app/(iframe)/demo-iframe/page.tsx deleted file mode 100644 index a111289fd..000000000 --- a/src/app/(iframe)/demo-iframe/page.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import Script from 'next/script' - -export default function DemoIframePage() { - return ( -
-
-

iframe paramétré

- -

Ci-dessous, nosgestesclimat.fr intégré comme un iframe paramétré.

-
- -
-
) } diff --git a/src/app/(layout-with-navigation)/(pages-statiques)/international/page.tsx b/src/app/(layout-with-navigation)/(pages-statiques)/international/page.tsx index ea78db624..dccad2784 100644 --- a/src/app/(layout-with-navigation)/(pages-statiques)/international/page.tsx +++ b/src/app/(layout-with-navigation)/(pages-statiques)/international/page.tsx @@ -64,7 +64,7 @@ export default async function International() { /> -
+

@@ -124,14 +124,14 @@ export default async function International() { Explorez en détail les spécificités de chaque pays.   - + ⏳️ À venir !

-
+
+
    {demoDottedNames.map((el) => (
  • diff --git a/src/app/(layout-with-navigation)/(pages-statiques)/questions-frequentes/page.tsx b/src/app/(layout-with-navigation)/(pages-statiques)/questions-frequentes/page.tsx index 52bc88705..58ed3a62a 100644 --- a/src/app/(layout-with-navigation)/(pages-statiques)/questions-frequentes/page.tsx +++ b/src/app/(layout-with-navigation)/(pages-statiques)/questions-frequentes/page.tsx @@ -1,10 +1,12 @@ +import Link from '@/components/Link' import Trans from '@/components/translation/Trans' +import Card from '@/design-system/layout/Card' import Title from '@/design-system/layout/Title' +import Emoji from '@/design-system/utils/Emoji' import { getServerTranslation } from '@/helpers/getServerTranslation' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' import { getCurrentLangInfos } from '@/locales/translation' import FAQListItem from './_components/FAQListItem' -import GithubContributionCard from './_components/GithubContributionCard' import Scroller from './_components/Scroller' type FAQType = { @@ -97,13 +99,20 @@ export default async function FAQPage() { })}
-

- 🙋‍♀️ - - J'ai une autre question - -

- + +

+ + Je ne trouve pas réponse à ma question{' '} + 🙋‍♀️ + +

+

+ + Vous pouvez nous contacter via notre page de contact :{' '} + accéder à notre page de contact. + +

+
) } diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/_components/ActionsTutorial.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/_components/ActionsTutorial.tsx index 428179ac0..4c97d3b3c 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/_components/ActionsTutorial.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/_components/ActionsTutorial.tsx @@ -20,7 +20,7 @@ export default function ActionsTutorial() { const [value, unit] = getCarbonFootprint({ t, i18n }, bilan.nodeValue) return ( - +

diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/_components/PetrolFilter.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/_components/PetrolFilter.tsx index 884f6c0ba..1c6da0884 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/_components/PetrolFilter.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/_components/PetrolFilter.tsx @@ -23,7 +23,7 @@ export default function PetrolFilter() { return ( diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionForm.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionForm.tsx index bce8a6f10..14d23f6ca 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionForm.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionForm.tsx @@ -44,7 +44,7 @@ export default function ActionForm({ category, onComplete }: Props) { initial={{ opacity: 0, scale: 0 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.3 }} - className="mb-4 rounded-lg bg-primaryLight p-4 text-left"> + className="bg-primary-100 mb-4 rounded-lg p-4 text-left"> diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionValue.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionValue.tsx index 460fef0f0..7a7c2d997 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionValue.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/_components/actions/_components/ActionValue.tsx @@ -66,7 +66,7 @@ export default function ActionValue({ return (
@@ -76,7 +76,7 @@ export default function ActionValue({ {total && relativeValue > 0 && ( - + {relativeValue}% )} diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/_components/categoryFilters/_components/Filter.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/_components/categoryFilters/_components/Filter.tsx index 2f0e529b5..f1e0bd5c7 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/_components/categoryFilters/_components/Filter.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/_components/categoryFilters/_components/Filter.tsx @@ -1,4 +1,5 @@ 'use client' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useRule } from '@/publicodes-state' import { useRouter, useSearchParams } from 'next/navigation' @@ -8,7 +9,7 @@ type Props = { } export default function Filter({ dottedName, countByCategory }: Props) { - const rule = useRule(dottedName) + const { title } = useRule(dottedName) const router = useRouter() @@ -17,16 +18,6 @@ export default function Filter({ dottedName, countByCategory }: Props) { const isSelected = categorySelected === dottedName - const getBackgroundColor = () => { - switch (true) { - case categorySelected && !isSelected: - return '#aaa' - case categorySelected === dottedName: - default: - return rule.color - } - } - const buildURL = () => { const siteURL = `${window.location.origin}${window.location.pathname}` @@ -43,7 +34,11 @@ export default function Filter({ dottedName, countByCategory }: Props) { return (
  • @@ -54,8 +49,8 @@ export default function Filter({ dottedName, countByCategory }: Props) { scroll: false, }) }}> - {rule.title}{' '} - + {title}{' '} + {countByCategory[dottedName] || 0} diff --git a/src/app/(layout-with-navigation)/(simulation)/actions/page.tsx b/src/app/(layout-with-navigation)/(simulation)/actions/page.tsx index 3106b1297..5334c5d85 100644 --- a/src/app/(layout-with-navigation)/(simulation)/actions/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/actions/page.tsx @@ -4,9 +4,8 @@ import ActionPageContent from './_components/ActionPageContent' export async function generateMetadata() { return getMetadataObject({ title: - "Actions, suite à votre simulation d'empreinte climat - Nos Gestes Climat", - description: - 'Découvrez les actions que vous pouvez mettre en place pour réduire votre empreinte carbone.', + 'Actions : comment réduire votre empreinte climat ? - Nos Gestes Climat', + description: 'Quelles sont les actions les plus efficaces ?', }) } diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/_components/CreateOtherGroupsSection.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/_components/CreateOtherGroupsSection.tsx index 2a9c17305..a090fb896 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/_components/CreateOtherGroupsSection.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/_components/CreateOtherGroupsSection.tsx @@ -25,12 +25,14 @@ export default function CreateOtherGroupsSection({ Vous pouvez créer un nouveau groupe avec d’autres amis.

    - - Créer un autre groupe - +
    + + Créer un autre groupe + +
    ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/_hooks/usFetchGroups.ts b/src/app/(layout-with-navigation)/(simulation)/amis/_hooks/usFetchGroups.ts index 4663bd369..924f08a85 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/_hooks/usFetchGroups.ts +++ b/src/app/(layout-with-navigation)/(simulation)/amis/_hooks/usFetchGroups.ts @@ -3,9 +3,11 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' export function useFetchGroups(userId: string) { - return useQuery(['groups'], () => - axios.get(`${GROUP_URL}/user-groups/${userId}`).then((response) => { - return response.data - }) - ) + return useQuery({ + queryKey: ['groups'], + queryFn: () => + axios.get(`${GROUP_URL}/user-groups/${userId}`).then((response) => { + return response.data + }), + }) } diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/creer/_component/GroupCreationForm.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/creer/_component/GroupCreationForm.tsx index 12b8c601f..32f80eda9 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/creer/_component/GroupCreationForm.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/creer/_component/GroupCreationForm.tsx @@ -48,7 +48,7 @@ export default function GroupCreationForm() { const router = useRouter() - const { mutateAsync: createGroup, isLoading } = useCreateGroup() + const { mutateAsync: createGroup, isPending } = useCreateGroup() const { mutateAsync: sendGroupEmail } = useSendGroupConfirmationEmail() @@ -141,7 +141,7 @@ export default function GroupCreationForm() { type="submit" data-cypress-id="button-create-group" onClick={handleSubmit} - aria-disabled={!prenom && !isLoading}> + aria-disabled={!prenom && !isPending}> {hasCompletedTest ? ( Créer le groupe ) : ( diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/page.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/page.tsx index 038800aee..a26da9c25 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/page.tsx @@ -3,15 +3,13 @@ import AutoCanonicalTag from '@/design-system/utils/AutoCanonicalTag' import { getServerTranslation } from '@/helpers/getServerTranslation' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' import Groups from './_components/Groups' -import FeedbackBlock from './resultats/_components/FeedbackBlock' import SondagesBlock from './resultats/_components/SondagesBlock' export async function generateMetadata() { return getMetadataObject({ - title: - "Groupes d'ami·e·s, simulateur d’empreinte carbone - Nos Gestes Climat", + title: 'Calculer votre empreinte carbone avec vos amis - Nos Gestes Climat', description: - 'Calculez votre empreinte carbone en groupe et comparez la avec l’empreinte de vos proches grâce au simulateur de bilan carbone personnel Nos Gestes Climat.', + 'Comparez vos résultats avec votre famille ou un groupe d’amis.', }) } @@ -19,7 +17,7 @@ export default async function GroupesPage() { const { t } = await getServerTranslation() return ( -
    + <> - <FeedbackBlock /> - <Groups /> <SondagesBlock /> - </div> + </> ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Classement.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Classement.tsx index 02ddacce5..43649ed51 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Classement.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Classement.tsx @@ -30,7 +30,7 @@ export default function Classement({ group }: { group: Group }) { return ( <> - <ul className="mt-2 rounded-md bg-primary px-3 py-4 text-white"> + <ul className="bg-primary-500 mt-2 rounded-md px-3 py-4 text-white"> {topThreeMembers.map((member, index) => { let rank switch (index) { @@ -114,7 +114,7 @@ export default function Classement({ group }: { group: Group }) { {group.members.length > 5 && !isExpanded && ( <button onClick={() => setIsExpanded(true)} - className="bg-Transparent mt-4 w-full border-none text-center text-sm text-primary underline"> + className="bg-Transparent text-primary-500 mt-4 w-full border-none text-center text-sm underline"> <Trans> Voir les {String(group.members.length - 5)} autre{withS} participant {withS} diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/FeedbackBlock.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/FeedbackBlock.tsx index e68326e51..f9ffa14f2 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/FeedbackBlock.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/FeedbackBlock.tsx @@ -37,71 +37,71 @@ function Flask() { className="mt-1 flex-none"> <path d="M6.72601 0.75H17.226" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M15.726 8.25V0.75H8.226V8.25L1.489 18.615C1.19487 19.0675 1.02825 19.5909 1.0067 20.1302C0.985142 20.6694 1.10945 21.2045 1.36652 21.679C1.62359 22.1535 2.0039 22.5499 2.46737 22.8264C2.93085 23.1029 3.46032 23.2492 4 23.25H19.948C20.488 23.2499 21.018 23.1041 21.482 22.8279C21.9461 22.5517 22.327 22.1554 22.5845 21.6808C22.8421 21.2061 22.9667 20.6708 22.9453 20.1312C22.9239 19.5916 22.7573 19.0678 22.463 18.615L15.726 8.25Z" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M5.30099 12.75H18.651" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M14.226 17.25H17.226" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M15.726 15.75V18.75" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M15.726 3.75H12.726" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M15.726 6.75H12.726" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" /> <path d="M6.72601 19.875C6.62656 19.875 6.53117 19.8355 6.46085 19.7652C6.39052 19.6948 6.35101 19.5995 6.35101 19.5C6.35101 19.4005 6.39052 19.3052 6.46085 19.2348C6.53117 19.1645 6.62656 19.125 6.72601 19.125" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" /> <path d="M6.72601 19.875C6.82547 19.875 6.92085 19.8355 6.99118 19.7652C7.0615 19.6948 7.10101 19.5995 7.10101 19.5C7.10101 19.4005 7.0615 19.3052 6.99118 19.2348C6.92085 19.1645 6.82547 19.125 6.72601 19.125" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" /> <path d="M9.72601 16.875C9.62656 16.875 9.53117 16.8355 9.46085 16.7652C9.39052 16.6948 9.35101 16.5995 9.35101 16.5C9.35101 16.4005 9.39052 16.3052 9.46085 16.2348C9.53117 16.1645 9.62656 16.125 9.72601 16.125" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" /> <path d="M9.72601 16.875C9.82547 16.875 9.92085 16.8355 9.99118 16.7652C10.0615 16.6948 10.101 16.5995 10.101 16.5C10.101 16.4005 10.0615 16.3052 9.99118 16.2348C9.92085 16.1645 9.82547 16.125 9.72601 16.125" - stroke="#5758BB" + className="stroke-primary-500" strokeWidth="1.5" /> </svg> diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/GroupResults.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/GroupResults.tsx index 1f240117e..0bcc0c71e 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/GroupResults.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/GroupResults.tsx @@ -20,7 +20,7 @@ export default function GroupResults({ groupId }: { groupId: string }) { const { data: group, refetch } = useFetchGroup(groupId) - const { user } = useUser() + const { user, setGroupToRedirectToAfterTest } = useUser() const userId = user?.id @@ -37,6 +37,10 @@ export default function GroupResults({ groupId }: { groupId: string }) { groupId, }) + useEffect(() => { + setGroupToRedirectToAfterTest(undefined) + }, [setGroupToRedirectToAfterTest]) + useEffect(() => { if (groupId && !group) { intervalRef.current = setInterval(() => refetch(), 60000) diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Results.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Results.tsx index ef2ad9a31..88a10d8fb 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Results.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/Results.tsx @@ -4,17 +4,20 @@ import Trans from '@/components/translation/Trans' import GoBackLink from '@/design-system/inputs/GoBackLink' import AutoCanonicalTag from '@/design-system/utils/AutoCanonicalTag' import { useRouter } from 'next/navigation' +import { useEffect } from 'react' import EditableGroupTitle from './EditableGroupTitle' -import FeedbackBlock from './FeedbackBlock' import Footer from './Footer' import GroupResults from './GroupResults' export default function Results({ groupId }: { groupId: string }) { const router = useRouter() - if (!groupId) { - router.push('/amis') - } + useEffect(() => { + if (!groupId) { + router.push('/amis') + } + }, [groupId, router]) + return ( <> <div className="p-4 pb-0"> @@ -24,8 +27,6 @@ export default function Results({ groupId }: { groupId: string }) { <EditableGroupTitle groupId={groupId} /> - <FeedbackBlock /> - <div className="mt-4"> <h2 className="m-0 text-lg font-bold"> <Trans>Le classement</Trans> diff --git a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/VotreEmpreinte.tsx b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/VotreEmpreinte.tsx index 3d78cbdec..af95934d9 100644 --- a/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/VotreEmpreinte.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/amis/resultats/_components/VotreEmpreinte.tsx @@ -73,7 +73,7 @@ export default function VotreEmpreinte({ )} </div> <div className="flex items-center gap-4"> - <div className="rounded-[5px] border-[1px] border-solid border-primaryBorder bg-primaryLight p-1 text-sm text-primary"> + <div className="bg-primary-100 text-primary-500 border-primary-800 rounded-[5px] border-[1px] border-solid p-1 text-sm"> <strong> {formatValue(categoryObject.value / 1000, { precision: 1, diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/FeedbackBanner.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/FeedbackBanner.tsx index b621601c3..279e12f16 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/FeedbackBanner.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/FeedbackBanner.tsx @@ -22,25 +22,30 @@ type Props = { export default function FeedbackBanner({ text, type, className }: Props) { const { t } = useClientTranslation() - const { user, updateNorthStarRatings } = useUser() + const { user, updateNorthStarRatings, currentSimulationId } = useUser() const { getNumericValue } = useEngine() const { categories, progression } = useForm() const hasJustAnswered = useRef(false) const { mutate: saveRating, - isLoading, + isPending, isSuccess, } = useMutation({ mutationKey: ['northstar', 'post'], mutationFn: () => axios .post(SIMULATION_URL, { - results: progression > 0 && { - categories: categories.map((category) => getNumericValue(category)), - total: getNumericValue('bilan'), + data: { + results: progression > 0 && { + categories: categories.map((category) => + getNumericValue(category) + ), + total: getNumericValue('bilan'), + }, + ratings: user.northStarRatings, }, - ratings: user.northStarRatings, + id: currentSimulationId, }) .then((response) => response.data) .catch((error) => captureException(error)), @@ -82,7 +87,7 @@ export default function FeedbackBanner({ text, type, className }: Props) { <p className="font-light">{text}</p> - <SmileyGrading onClick={handleGrading} disabled={isLoading} /> + <SmileyGrading onClick={handleGrading} disabled={isPending} /> </Card> ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/GetResultsByEmail.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/GetResultsByEmail.tsx index b361e580d..4db83855b 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/GetResultsByEmail.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/GetResultsByEmail.tsx @@ -25,7 +25,7 @@ export default function GetResultsByEmail({ const { mutate: subscribeUser, - isLoading, + isPending, isSuccess, isError, error, @@ -34,7 +34,7 @@ export default function GetResultsByEmail({ function handleSubmit(event: React.FormEvent<HTMLFormElement>) { event.preventDefault() - if (isLoading || !simulation) return + if (isPending || !simulation) return trackEvent(matomoSaveSimulationByGivingEmail) @@ -104,7 +104,7 @@ export default function GetResultsByEmail({ <Button onClick={() => null} type="submit" - disabled={isLoading} + disabled={isPending} className="mt-4"> <Trans>Envoyer</Trans> </Button> diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/GroupModePromotionBanner.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/GroupModePromotionBanner.tsx index a4b5d94eb..f9068c78c 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/GroupModePromotionBanner.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/GroupModePromotionBanner.tsx @@ -15,12 +15,12 @@ export default async function GroupModePromotionBanner({ return ( <Card className={twMerge( - 'w-full flex-row justify-center gap-4 border-none bg-primaryDark pb-0 text-white md:gap-8', + 'w-full flex-row justify-center gap-4 border-none bg-primary-700 pb-0 text-white md:gap-8', className )}> <div className="flex items-end justify-end md:items-center"> <Image - src="/images/misc/challenge.png" + src="/images/misc/challenge-v2.png" width="150" height="150" alt={t('Une capture du mode Groupe Nos Gestes Climat.')} diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/RedirectionIfNoResult.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/RedirectionIfNoResult.tsx new file mode 100644 index 000000000..4df7008c1 --- /dev/null +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/RedirectionIfNoResult.tsx @@ -0,0 +1,29 @@ +'use client' + +import { formatResultToDetailParam } from '@/helpers/url/formatResultToDetailParam' +import { useEngine, useForm, useSimulation } from '@/publicodes-state' +import { useRouter } from 'next/navigation' +import { useEffect } from 'react' + +export default function RedirectionIfNoResult({ + details, +}: { + details: string +}) { + const { categories } = useSimulation() + const { progression } = useForm() + const { getValue } = useEngine() + + const router = useRouter() + + const detailsParamString = formatResultToDetailParam({ categories, getValue }) + + useEffect(() => { + // The URL includes matching results, we assume the user has done the test + if (!detailsParamString.includes(details) && progression !== 1) { + router.push(progression > 0 ? '/simulateur/bilan' : '/tutoriel') + } + }, [categories, details, progression, router, detailsParamString]) + + return null +} diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/Results.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/Results.tsx index 634867f58..b47c2fa6d 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/Results.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/Results.tsx @@ -1,10 +1,26 @@ +'use client' + import Trans from '@/components/translation/Trans' import Separator from '@/design-system/layout/Separator' +import { useEngine, useSimulation } from '@/publicodes-state' +import { useMemo } from 'react' import CategoriesAccordion from './results/CategoriesAccordion' import CategoriesChart from './results/CategoriesChart' import TotalCard from './results/TotalCard' export default function Results() { + const { categories } = useSimulation() + const { getNumericValue } = useEngine() + + const sortedCategories = useMemo(() => { + return categories.sort((categoryA, categoryB) => { + const valueA = getNumericValue(categoryA) ?? 0 + const valueB = getNumericValue(categoryB) ?? 0 + + return valueB - valueA + }) + }, [categories, getNumericValue]) + return ( <> <h2 className="text-lg"> @@ -14,10 +30,10 @@ export default function Results() { <div className="flex flex-col items-stretch justify-center md:flex-row md:gap-4"> <TotalCard /> - <CategoriesChart /> + <CategoriesChart sortedCategories={sortedCategories} /> </div> - <CategoriesAccordion /> + <CategoriesAccordion sortedCategories={sortedCategories} /> <Separator className="mb-6 mt-8" /> </> diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesAccordion.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesAccordion.tsx index d15640280..9061ee6dd 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesAccordion.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesAccordion.tsx @@ -4,14 +4,18 @@ import Accordion from '@/design-system/layout/Accordion' import { useForm, useRule } from '@/publicodes-state' import AccordionItemWithRule from './categoriesAccordion/AccordionItemWithRule' -export default function CategoriesAccordion() { +type Props = { + sortedCategories: string[] +} + +export default function CategoriesAccordion({ sortedCategories }: Props) { const { categories } = useForm() const { numericValue: maxCategoryValue } = useRule(categories?.[0] ?? '') return ( <Accordion className="mt-8"> - {categories.map((categoryDottedName, index) => { + {sortedCategories.map((categoryDottedName, index) => { return ( <AccordionItemWithRule key={categoryDottedName} diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesChart.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesChart.tsx index e0531b8f3..6e97c8c9d 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesChart.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/CategoriesChart.tsx @@ -1,25 +1,18 @@ 'use client' import Card from '@/design-system/layout/Card' -import { useEngine, useForm, useRule } from '@/publicodes-state' -import { useMemo } from 'react' +import { useRule } from '@/publicodes-state' import { twMerge } from 'tailwind-merge' import CategoryChartItem from './categoriesChart/CategoryChartItem' -export default function CategoriesChart({ className }: { className?: string }) { - const { categories } = useForm() - - const { getNumericValue } = useEngine() - - const sortedCategories = useMemo(() => { - return categories.sort((categoryA, categoryB) => { - const valueA = getNumericValue(categoryA) ?? 0 - const valueB = getNumericValue(categoryB) ?? 0 - - return valueB - valueA - }) - }, [categories, getNumericValue]) - +type Props = { + sortedCategories: string[] + className?: string +} +export default function CategoriesChart({ + sortedCategories, + className, +}: Props) { const { numericValue: firstCategoryValue } = useRule(sortedCategories[0]) return ( diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/TotalCard.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/TotalCard.tsx index 031ef0b1e..769ae617c 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/TotalCard.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/TotalCard.tsx @@ -16,7 +16,7 @@ export default function TotalCard() { const { formattedValue, unit } = formatCarbonFootprint(numericValue) return ( - <Card className="w-full flex-row items-center rounded-lg bg-primaryDark p-6 text-white shadow-none md:px-10"> + <Card className="w-full flex-row items-center rounded-lg bg-primary-700 p-6 text-white shadow-none md:px-10"> <div className="flex-1"> <p className="mb-0 text-3xl md:text-4xl"> <strong>{formattedValue}</strong>{' '} @@ -24,8 +24,8 @@ export default function TotalCard() { </p> <p className="mb-0 md:text-lg"> - <span className="text-primaryLight">de </span>CO₂-e{' '} - <span className="text-primaryLight">chaque année</span> + <span className="text-primary-200">de </span>CO₂-e{' '} + <span className="text-primary-200">chaque année</span> </p> <Link @@ -34,9 +34,9 @@ export default function TotalCard() { aria-label={t( "Qu'est-ce que ça veut dire ? Cette page s'ouvrira dans un nouvel onglet." )} - className="mt-2 text-sm text-white hover:text-primaryLight" + className="mt-2 text-sm text-white hover:text-primary-200" href="https://nosgestesclimat.fr/blog/budget"> - Qu'est-ce que ça veut dire ?  + Qu'est-ce que ça veut dire ?  <ExternalLinkIcon className="stroke-white" /> </Link> </div> diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/AccordionItemWithRule.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/AccordionItemWithRule.tsx index 57e4e79cb..28c97090b 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/AccordionItemWithRule.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/AccordionItemWithRule.tsx @@ -18,8 +18,6 @@ export default function AccordionItemWithRule({ const percentageOfTotalValue = (1 - (maxValue - numericValue) / maxValue) * 0.9 - const isReadOnly = dottedName === 'services sociétaux' - return ( <AccordionItem title={ @@ -27,11 +25,7 @@ export default function AccordionItemWithRule({ <div className="flex min-w-[11rem] items-center gap-2"> <Emoji>{icons}</Emoji>{' '} <p - className={`mb-0 ${ - isReadOnly - ? '' - : 'underline decoration-dotted underline-offset-4' - }`}> + className={`mb-0 underline decoration-dotted underline-offset-4`}> {title} </p> </div> @@ -48,7 +42,6 @@ export default function AccordionItemWithRule({ icons={icons || ''} dottedName={dottedName} content={<SubcategoriesList category={dottedName} />} - isReadOnly={isReadOnly} /> ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/accordionItemWithRule/subcategoriesList/SubcategoryListItem.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/accordionItemWithRule/subcategoriesList/SubcategoryListItem.tsx index db7663f6c..b55daa248 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/accordionItemWithRule/subcategoriesList/SubcategoryListItem.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/_components/results/categoriesAccordion/accordionItemWithRule/subcategoriesList/SubcategoryListItem.tsx @@ -31,7 +31,7 @@ export default function SubcategoryListItem({ <div className="flex items-center justify-between text-sm md:text-base"> <p className="mb-0">{title}</p> - <div className="text-primaryDark"> + <div className="text-primary-700"> <strong> {formatValue(roundValue(numericValue), { precision: 0 })} </strong>{' '} @@ -41,7 +41,7 @@ export default function SubcategoryListItem({ <div className="mt-2"> <div> <div - className="h-[6px] rounded-lg bg-primary" + className="bg-primary-500 h-[6px] rounded-lg" style={{ width: `calc(${percentageOfCategoryValue} * 100%)`, }} diff --git a/src/app/(layout-with-navigation)/(simulation)/fin/page.tsx b/src/app/(layout-with-navigation)/(simulation)/fin/page.tsx index 5edb82bee..c7b97cda8 100644 --- a/src/app/(layout-with-navigation)/(simulation)/fin/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/fin/page.tsx @@ -1,5 +1,6 @@ import IframeDataShareModal from '@/components/iframe/IframeDataShareModal' import Trans from '@/components/translation/Trans' +import { noIndexObject } from '@/constants/metadata' import Separator from '@/design-system/layout/Separator' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' import { FormProvider } from '@/publicodes-state' @@ -8,6 +9,7 @@ import FeedbackBanner from './_components/FeedbackBanner' import GetResultsByEmail from './_components/GetResultsByEmail' import GroupModePromotionBanner from './_components/GroupModePromotionBanner' import HowToAct from './_components/HowToAct' +import RedirectionIfNoResult from './_components/RedirectionIfNoResult' import Results from './_components/Results' export async function generateMetadata() { @@ -15,14 +17,21 @@ export async function generateMetadata() { title: "Vos résultats, simulateur d'empreinte climat - Nos Gestes Climat", description: "Vos résultats de tests de notre simulateur d'empreinte carbone.", + robots: noIndexObject, }) } -export default function FinPage() { +export default function FinPage({ + searchParams, +}: { + searchParams: { details?: string } +}) { return ( <FormProvider> <IframeDataShareModal /> + <RedirectionIfNoResult details={searchParams?.details || ''} /> + <CongratulationsText /> <Results /> diff --git a/src/app/(layout-with-navigation)/(simulation)/plan-du-site/_components/LinkList.tsx b/src/app/(layout-with-navigation)/(simulation)/plan-du-site/_components/LinkList.tsx new file mode 100644 index 000000000..bcab43431 --- /dev/null +++ b/src/app/(layout-with-navigation)/(simulation)/plan-du-site/_components/LinkList.tsx @@ -0,0 +1,19 @@ +'use client' + +import Link from '@/components/Link' + +type LinkListProps = { + entries: Record<string, { title: string; href: string }> +} + +export default function LinkList({ entries }: LinkListProps) { + return ( + <ul className="m-0 list-none p-0"> + {Object.entries(entries).map(([linkKey, { title, href }]) => ( + <li key={linkKey}> + <Link href={href}>{title}</Link> + </li> + ))} + </ul> + ) +} diff --git a/src/app/(layout-with-navigation)/(simulation)/plan-du-site/page.tsx b/src/app/(layout-with-navigation)/(simulation)/plan-du-site/page.tsx index 7dfa22fbf..db540bbf1 100644 --- a/src/app/(layout-with-navigation)/(simulation)/plan-du-site/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/plan-du-site/page.tsx @@ -1,8 +1,9 @@ -import Link from '@/components/Link' import Trans from '@/components/translation/Trans' import Title from '@/design-system/layout/Title' +import { getServerTranslation } from '@/helpers/getServerTranslation' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' import Actions from './_components/Actions' +import LinkList from './_components/LinkList' export async function generateMetadata() { return getMetadataObject({ @@ -12,32 +13,82 @@ export async function generateMetadata() { }) } -const links = { - 'Nos outils': { - 'publicodes.planDuSite.bilan': '/simulateur/bilan', - 'publicodes.planDuSite.profil': '/profil', - 'publicodes.planDuSite.personas': '/personas', - 'publicodes.planDuSite.actions': '/actions', - 'publicodes.planDuSite.actionsPlus': '/actions/plus', - }, - Informations: { - 'publicodes.planDuSite.nouveautes': '/nouveautes', - 'publicodes.planDuSite.aPropos': '/a-propos', - 'publicodes.planDuSite.contact': '/contact', - 'publicodes.planDuSite.viePrivee': '/vie-privee', - 'publicodes.planDuSite.partenaires': '/partenaires', - 'publicodes.planDuSite.faq': '/questions-frequentes', - 'publicodes.planDuSite.stats': '/stats', - Blog: '/blog', - }, - Documentations: { - 'publicodes.planDuSite.guide': '/guide', - 'publicodes.planDuSite.modele': '/modele', - 'publicodes.planDuSite.documentation': '/documentation', - }, -} +export default async function PlanDuSitePage() { + const { t } = await getServerTranslation() + + const links = { + 'Nos outils': { + bilan: { + title: t('Le test'), + href: '/simulateur/bilan', + }, + profil: { + title: t('Votre profil'), + href: '/profil', + }, + personas: { + title: t('Nos utilisateurs types'), + href: '/personas', + }, + actions: { + title: t('Nos actions pour réduire votre empreinte'), + href: '/actions', + }, + actionsPlus: { + title: t('Les actions phares'), + href: '/actions-plus', + }, + }, + Informations: { + nouveautes: { + title: t('Nouveautés'), + href: '/nouveautes', + }, + aPropos: { + title: t('À propos'), + href: '/a-propos', + }, + contact: { + title: t('Contact'), + href: '/contact', + }, + viePrivee: { + title: t('Vie privée'), + href: '/vie-privee', + }, + partenaires: { + title: t('Partenaires'), + href: '/partenaires', + }, + faq: { + title: t('FAQ'), + href: '/faq', + }, + stats: { + title: t('Statistiques'), + href: '/stats', + }, + Blog: { + title: t('Blog'), + href: '/blog', + }, + }, + Documentations: { + guide: { + title: t('Nos guides thématiques'), + href: '/documentation/guide', + }, + modele: { + title: t('Le modèle Nos Gestes Climat'), + href: '/documentation/modele', + }, + documentation: { + title: t('Documentation'), + href: '/documentation', + }, + }, + } -export default function PlanDuSitePage() { return ( <div data-cypress-id="plan-links"> <Title @@ -46,28 +97,31 @@ export default function PlanDuSitePage() { } /> - {Object.entries(links).map(([categoryTitle, categoryLinks]) => ( - <section key={categoryTitle} className="mb-2"> - <h2> - <Trans i18nKey={`${categoryTitle}`}>{categoryTitle}</Trans> - </h2> - <ul className="m-0 list-none p-0"> - {Object.entries(categoryLinks).map(([linkKey, linkUrl]) => ( - <li key={linkKey}> - <Link href={linkUrl}> - <Trans i18nKey={`${linkKey}`}>{linkKey}</Trans> - </Link> - </li> - ))} - </ul> - </section> - ))} + <section className="mb-2"> + <h2> + <Trans>Nos outils</Trans> + </h2> + <LinkList entries={links['Nos outils']} /> + </section> + + <section className="mb-2"> + <h2> + <Trans>Informations</Trans> + </h2> + <LinkList entries={links['Informations']} /> + </section> + + <section className="mb-2"> + <h2> + <Trans>Documentations</Trans> + </h2> + <LinkList entries={links['Documentations']} /> + </section> <section> <h2> <Trans i18nKey="publicodes.planDuSite.actionsPlus">Les actions</Trans> </h2> - <Actions /> </section> </div> diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/SimulationBanner.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/SimulationBanner.tsx index f4acc2262..5a6699ba3 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/SimulationBanner.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/SimulationBanner.tsx @@ -15,5 +15,5 @@ export default function SimulationBanner() { return <SimulationNotStarted /> } - return <SimulationStarted currentSimulation={currentSimulation} /> + return <SimulationStarted /> } diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/Category.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/Category.tsx index 1b05f5123..0059a1b39 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/Category.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/Category.tsx @@ -1,6 +1,10 @@ 'use client' import formatCarbonFootprint from '@/helpers/formatCarbonFootprint' +import { + getBackgroundColor, + getTextColor, +} from '@/helpers/getCategoryColorClass' import { useForm, useRule } from '@/publicodes-state' import { useState } from 'react' import Subcategory from './category/Subcategory' @@ -10,7 +14,7 @@ type Props = { } export default function Category({ category }: Props) { - const { title, value, icons, color } = useRule(category) + const { title, value, icons } = useRule(category) const { subcategories } = useForm() const [isOpen, setIsOpen] = useState(false) @@ -23,12 +27,14 @@ export default function Category({ category }: Props) { className="block w-full" onClick={() => setIsOpen((prevIsOpen) => !prevIsOpen)}> <h2 - className="mb-0 flex w-full items-center justify-between gap-4 rounded-lg p-4 text-white" - style={{ backgroundColor: color }}> + className={`mb-0 flex w-full items-center justify-between gap-4 rounded-lg p-4 text-white ${getBackgroundColor( + category + )}`}> {icons} {title}{' '} <span - className="block rounded-lg bg-white px-4 py-2 text-lg" - style={{ color }}> + className={`block rounded-lg bg-white px-4 py-2 text-lg ${getTextColor( + category + )}`}> {formattedCarbonFootprint.formattedValue}{' '} {formattedCarbonFootprint.unit} </span> diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/Subcategory.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/Subcategory.tsx index eb2507322..a551b9f8f 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/Subcategory.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/Subcategory.tsx @@ -1,6 +1,7 @@ 'use client' import formatCarbonFootprint from '@/helpers/formatCarbonFootprint' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useForm, useRule } from '@/publicodes-state' import { useState } from 'react' import Question from './subcategory/Question' @@ -10,14 +11,14 @@ type Props = { } export default function SubCategory({ subcategory }: Props) { - const { title, value, icons, color } = useRule(subcategory) + const { title, value, icons, category } = useRule(subcategory) const { relevantAnsweredQuestions } = useForm() const [isOpen, setIsOpen] = useState(false) const formattedCarbonFootprint = formatCarbonFootprint(value) - //TODO: investigate why subcategory = repas and questions = plats + //TODO: Model shenanigans: investigate why subcategory = repas and questions = plats const answeredQuestionOfSubcategory = relevantAnsweredQuestions.filter( (question) => question.includes(subcategory) || @@ -26,10 +27,11 @@ export default function SubCategory({ subcategory }: Props) { if (!answeredQuestionOfSubcategory.length) return null return ( - <div className="relative mt-2 w-full overflow-hidden rounded-lg bg-primaryLight "> + <div className="relative mt-2 w-full overflow-hidden rounded-lg bg-primary-100 "> <div - className="absolute bottom-0 left-0 top-0 w-2" - style={{ backgroundColor: color }} + className={`absolute bottom-0 left-0 top-0 w-2 ${getBackgroundColor( + category + )}`} /> <button onClick={() => setIsOpen((prevIsOpen) => !prevIsOpen)} diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/Question.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/Question.tsx index cc5dac85f..8b4acb706 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/Question.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/Question.tsx @@ -13,8 +13,15 @@ type Props = { export default function Question({ question }: Props) { const { t } = useClientTranslation() - const { label, value, displayValue, unit, type, questionsOfMosaic } = - useRule(question) + const { + label, + value, + displayValue, + unit, + type, + questionsOfMosaic, + isMissing, + } = useRule(question) return ( <Link @@ -26,22 +33,28 @@ export default function Question({ question }: Props) { <span className={`flex w-full items-center justify-between gap-8 text-sm`}> <span className="flex-1">{label}</span> - <strong> - {type === 'number' && ( - <NumberValue displayValue={displayValue} unit={unit} /> - )} - {type === 'boolean' && ( - <span className="capitalize">{t(displayValue.toString())}</span> - )} - {type === 'choices' && ( - <ChoicesValue value={value} question={question} /> - )} - </strong> + {!isMissing ? ( + <strong> + {type === 'number' && ( + <NumberValue displayValue={displayValue} unit={unit} /> + )} + {type === 'boolean' && ( + <span className="capitalize">{t(displayValue.toString())}</span> + )} + {type === 'choices' && ( + <ChoicesValue value={value} question={question} /> + )} + </strong> + ) : null} </span> {questionsOfMosaic.length ? ( <div className="mt-2 grid gap-2 md:grid-cols-2"> {questionsOfMosaic.map((questionOfMosaic) => ( - <MosaicQuestion key={question} question={questionOfMosaic} /> + <MosaicQuestion + key={question} + question={questionOfMosaic} + isMissing={isMissing} + /> ))} </div> ) : null} diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/question/MosaicQuestion.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/question/MosaicQuestion.tsx index 61ec84df1..bda8606a1 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/question/MosaicQuestion.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/answerList/category/subcategory/question/MosaicQuestion.tsx @@ -5,29 +5,34 @@ import NumberValue from '@/components/misc/NumberValue' import { useClientTranslation } from '@/hooks/useClientTranslation' import { useRule } from '@/publicodes-state' -type Props = { question: string } +type Props = { + question: string + isMissing: boolean +} -export default function MosaicQuestion({ question }: Props) { +export default function MosaicQuestion({ question, isMissing }: Props) { const { t } = useClientTranslation() const { value, displayValue, unit, type, parent } = useRule(question) const { title, icons } = useRule(parent) return ( - <span className="relative flex justify-between rounded-lg bg-primaryLight p-4 text-sm"> + <span className="relative flex justify-between rounded-lg bg-primary-100 p-4 text-sm"> <span className="flex-1"> {icons} {title} </span> - <strong> - {type === 'number' && ( - <NumberValue displayValue={displayValue} unit={unit} /> - )} - {type === 'boolean' && ( - <span className="capitalize">{t(displayValue.toString())}</span> - )} - {type === 'choices' && ( - <ChoicesValue value={value} question={question} /> - )} - </strong> + {!isMissing ? ( + <strong> + {type === 'number' && ( + <NumberValue displayValue={displayValue} unit={unit} /> + )} + {type === 'boolean' && ( + <span className="capitalize">{t(displayValue.toString())}</span> + )} + {type === 'choices' && ( + <ChoicesValue value={value} question={question} /> + )} + </strong> + ) : null} </span> ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/localisation/RegionSelector.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/localisation/RegionSelector.tsx index 6d59d8b84..31f579458 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/localisation/RegionSelector.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/localisation/RegionSelector.tsx @@ -35,14 +35,13 @@ export default function RegionSelector({ const { isFetching } = useRules({ lang: locale, region: region?.code ?? 'FR', - isOptim: false, }) return ( <> <details open={isOpen}> <summary - className={`middle w-auto cursor-pointer rounded-md bg-primaryLight p-4 ${ + className={`middle w-auto cursor-pointer rounded-md bg-primary-100 p-4 ${ isFetching ? 'pointer-events-none opacity-60' : '' }`}> <span> diff --git a/src/app/(layout-with-navigation)/(simulation)/profil/_components/simulationBanner/SimulationStarted.tsx b/src/app/(layout-with-navigation)/(simulation)/profil/_components/simulationBanner/SimulationStarted.tsx index 4619e207b..5d24f0977 100644 --- a/src/app/(layout-with-navigation)/(simulation)/profil/_components/simulationBanner/SimulationStarted.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/profil/_components/simulationBanner/SimulationStarted.tsx @@ -3,23 +3,23 @@ import Trans from '@/components/translation/Trans' import Button from '@/design-system/inputs/Button' import ButtonLink from '@/design-system/inputs/ButtonLink' import Card from '@/design-system/layout/Card' +import Emoji from '@/design-system/utils/Emoji' import ProgressCircle from '@/design-system/utils/ProgressCircle' +import { formatResultToDetailParam } from '@/helpers/url/formatResultToDetailParam' import { useClientTranslation } from '@/hooks/useClientTranslation' -import { useForm, useUser } from '@/publicodes-state' -import { Simulation } from '@/publicodes-state/types' +import { useActions, useEngine, useForm, useUser } from '@/publicodes-state' import TutorialLink from './_components/TutorialLink' -type Props = { - currentSimulation: Simulation -} -export default function SimulationStarted({ currentSimulation }: Props) { +export default function SimulationStarted() { const { t } = useClientTranslation() - const { progression, relevantAnsweredQuestions } = useForm() + const { getValue } = useEngine() + + const { progression, relevantAnsweredQuestions, categories } = useForm() const { initSimulation } = useUser() - const actionChoicesLength = currentSimulation?.actionChoices?.length || 0 + const { chosenActions, declinedActions } = useActions() const isFinished = progression === 1 @@ -31,10 +31,12 @@ export default function SimulationStarted({ currentSimulation }: Props) { {t('publicodes.Profil.recap', { percentFinished: (progression * 100).toFixed(0), answeredQuestionsLength: relevantAnsweredQuestions.length, - actionChoicesLength, + chosenActions: chosenActions.length, + declinedActions: declinedActions.length, })}{' '} </p> </Card> + <details className="mt-3 max-w-full text-sm"> <Trans i18nKey={'publicodes.Profil.locationDonnées'}> <summary className="mb-2 cursor-pointer"> @@ -52,6 +54,20 @@ export default function SimulationStarted({ currentSimulation }: Props) { </div> <div className="my-4 flex w-full flex-col md:w-auto md:items-start"> + {isFinished && ( + <ButtonLink + color="primary" + href={`/fin?${formatResultToDetailParam({ + categories, + getValue, + })}`} + className="w-full"> + <Trans> + <Emoji className="mr-2">👀</Emoji> Voir mon résultat + </Trans> + </ButtonLink> + )} + {!isFinished && ( <ButtonLink color="primary" diff --git a/src/app/(layout-with-navigation)/(simulation)/questions/_components/Questions.tsx b/src/app/(layout-with-navigation)/(simulation)/questions/_components/Questions.tsx new file mode 100644 index 000000000..33a5daf01 --- /dev/null +++ b/src/app/(layout-with-navigation)/(simulation)/questions/_components/Questions.tsx @@ -0,0 +1,28 @@ +'use client' + +import { useEngine, useSimulation } from '@/publicodes-state' +import { useMemo } from 'react' +import Question from './questions/Question' + +export default function Questions() { + const { categories, everyQuestions } = useSimulation() + const { getCategory } = useEngine() + + const orderedQuestions = useMemo( + () => + everyQuestions.sort( + (a, b) => + categories.indexOf(getCategory(a)) - + categories.indexOf(getCategory(b)) + ), + [everyQuestions, categories, getCategory] + ) + + return ( + <ul> + {orderedQuestions.map((question) => ( + <Question key={question} question={question} /> + ))} + </ul> + ) +} diff --git a/src/app/(layout-with-navigation)/(simulation)/questions/_components/questions/Question.tsx b/src/app/(layout-with-navigation)/(simulation)/questions/_components/questions/Question.tsx new file mode 100644 index 000000000..82b3313a7 --- /dev/null +++ b/src/app/(layout-with-navigation)/(simulation)/questions/_components/questions/Question.tsx @@ -0,0 +1,10 @@ +'use client' + +import { useRule } from '@/publicodes-state' + +type Props = { question: string } + +export default function Question({ question }: Props) { + const { label } = useRule(question) + return <li>{label}</li> +} diff --git a/src/app/(layout-with-navigation)/(simulation)/questions/page.tsx b/src/app/(layout-with-navigation)/(simulation)/questions/page.tsx new file mode 100644 index 000000000..0407140a3 --- /dev/null +++ b/src/app/(layout-with-navigation)/(simulation)/questions/page.tsx @@ -0,0 +1,23 @@ +import Trans from '@/components/translation/Trans' +import Title from '@/design-system/layout/Title' +import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' +import Questions from './_components/Questions' + +export async function generateMetadata() { + return getMetadataObject({ + title: 'Liste des questions - Nos Gestes Climat', + description: + 'Calculez votre empreinte sur le climat en 10 minutes chrono. Découvrez les gestes qui comptent vraiment pour le climat.', + }) +} + +export default function QuestionsPage() { + return ( + <> + <Title> + <Trans>Questions</Trans> + + + + ) +} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/Faq.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/Faq.tsx index 96eb4266f..4af20cb3f 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/Faq.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/Faq.tsx @@ -11,7 +11,7 @@ export default function Faq() { if (isIframeOnlySimulation) return null return ( -
    +

    Une question, un problème ?

    diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Charts.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Charts.tsx index 9b96911c3..c2af2ca44 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Charts.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Charts.tsx @@ -1,38 +1,9 @@ -import { useForm } from '@/publicodes-state' -import { useState } from 'react' -import BarChart from './charts/BarChart' import InlineChart from './charts/InlineChart' export default function Charts() { - const { currentCategory } = useForm() - const [isBarChartVisible, setIsBarChartVisible] = useState(false) - if (!currentCategory) return return (
    - - {isBarChartVisible ? : null}
    ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx index 89e2892b3..886362d6e 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/Form.tsx @@ -73,7 +73,7 @@ export default function Form() { } return ( -
    +
    {questions[currentQuestion] ? ( questions[currentQuestion] @@ -93,7 +93,7 @@ export default function Form() { return } router.push( - `/fin?diapo=bilan&${formatResultToDetailParam({ + `/fin?${formatResultToDetailParam({ categories, getValue, })}` diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/BarChart.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/BarChart.tsx deleted file mode 100644 index 2f45f47bf..000000000 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/BarChart.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useEngine, useForm } from '@/publicodes-state' -import { useMemo, useState } from 'react' -import { Flipped, Flipper } from 'react-flip-toolkit' - -import Category from './barChart/Category' - -export default function BarChart() { - const { categories, currentCategory } = useForm() - - const { getNumericValue } = useEngine() - - const [isOpen, setIsOpen] = useState(null) - - const sortedCategories = useMemo( - () => - categories.sort((a: string, b: string) => { - const valueOfA = getNumericValue(a) || 0 - const valueOfB = getNumericValue(b) || 0 - return valueOfA > valueOfB ? -1 : 1 - }), - [categories, getNumericValue] - ) - - const max = useMemo(() => { - const maxValue = getNumericValue(sortedCategories[0]) || 0 - return maxValue > 5000 ? maxValue : 5000 - }, [sortedCategories, getNumericValue]) - - return ( - category).join('')}> - {sortedCategories.map((category: string) => ( - - - - ))} - - ) -} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/InlineChart.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/InlineChart.tsx index 4cf9a9756..709ef76d3 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/InlineChart.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/InlineChart.tsx @@ -1,10 +1,12 @@ +import { useForm } from '@/publicodes-state' import CategoriesChart from './inlineChart/CategoriesChart' import SubcategoriesChart from './inlineChart/SubcategoriesChart' export default function InlineChart() { + const { currentCategory } = useForm() return (
    - + {currentCategory ? : null}
    ) diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/Category.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/Category.tsx deleted file mode 100644 index da2338f6f..000000000 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/Category.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useRule } from '@/publicodes-state' - -import BarChartItem from '@/components/misc/BarChartItem' -import Subcategories from './category/Subcategories' - -type Props = { - category: string - max: number - current: boolean - isOpen: boolean - setIsOpen: any -} - -export default function Category({ - category, - max, - isOpen, - setIsOpen, - ...props -}: Props) { - const { title, icons, color, numericValue } = useRule(category) - - return ( -
    - { - setIsOpen((previsOpen: string | null) => - previsOpen === category ? null : category - ) - }} - /> - {isOpen ? : null} -
    - ) -} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/category/Subcategories.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/category/Subcategories.tsx deleted file mode 100644 index 084feaf51..000000000 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/barChart/category/Subcategories.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useEngine, useForm } from '@/publicodes-state' -import { useMemo } from 'react' -import { Flipped, Flipper } from 'react-flip-toolkit' - -import Subcategory from '@/components/misc/Subcategory' - -type Props = { - category: string - max: number -} -export default function Subcategories({ category, max }: Props) { - const { subcategories } = useForm() - - const { getNumericValue, checkIfValid } = useEngine() - - const sortedSubcategories = useMemo( - () => - subcategories[category] - .filter((subcategory: string) => checkIfValid(subcategory)) - .sort((a: string, b: string) => - getNumericValue(a) > getNumericValue(b) ? -1 : 1 - ), - [subcategories, category, getNumericValue, checkIfValid] - ) - - return ( - subcategory) - .join()}> - {sortedSubcategories.map((subcategory: string) => ( - - - - ))} - - ) -} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/inlineChart/SubcategoriesChart.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/inlineChart/SubcategoriesChart.tsx index 60f21f973..2af734e52 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/inlineChart/SubcategoriesChart.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/charts/inlineChart/SubcategoriesChart.tsx @@ -1,4 +1,5 @@ import ValueChangeDisplay from '@/components/misc/ValueChangeDisplay' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useEngine, useForm, useRule } from '@/publicodes-state' import { useMemo } from 'react' import Subcategory from './subcategoriesChart/Subcategory' @@ -6,8 +7,8 @@ import Subcategory from './subcategoriesChart/Subcategory' export default function SubcategoriesChart() { const { subcategories, currentCategory } = useForm() - const { numericValue: total } = useRule(currentCategory || '') - const { title, color } = useRule(currentCategory || '') + const { title, numericValue: total } = useRule(currentCategory || '') + const { checkIfValid } = useEngine() const filteredSubcategories = useMemo( @@ -30,7 +31,10 @@ export default function SubcategoriesChart() {
  • -
    +
    {filteredSubcategories.map((subcategory: string, index: number) => ( trackEvent(getMatomoEventClickCategoryGraph(category))}> {current ? ( ) : null} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/CategoryIntroduction.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/CategoryIntroduction.tsx deleted file mode 100644 index 3a8fe1e0d..000000000 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/CategoryIntroduction.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Trans from '@/components/translation/Trans' -import Button from '@/design-system/inputs/Button' -import { useRule } from '@/publicodes-state' -import Image from 'next/image' - -type Props = { - category: string - startCategory: any -} - -export default function CategoryIntroduction({ - category, - startCategory, -}: Props) { - const { title, color } = useRule(category) - return ( -
    -

    {title}

    - {title - -
    - ) -} diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/ColorIndicator.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/ColorIndicator.tsx index 647fb5bc3..759965f2d 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/ColorIndicator.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/ColorIndicator.tsx @@ -1,3 +1,4 @@ +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useRule } from '@/publicodes-state' type Props = { @@ -5,12 +6,13 @@ type Props = { } export default function ColorIndicator({ question }: Props) { - const { color } = useRule(question) + const { category } = useRule(question) return (
    ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/TestCompleted.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/TestCompleted.tsx index db8a720f9..ee9b61f4b 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/TestCompleted.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/TestCompleted.tsx @@ -12,7 +12,7 @@ export default function TestCompleted() { const detailsParamString = formatResultToDetailParam({ categories, getValue }) return ( -
    +

    Vous avez terminé le test  @@ -20,9 +20,7 @@ export default function TestCompleted() {

    + href={`/fin${detailsParamString ? `?${detailsParamString}` : ''}`}> Voir mon résultat

    diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/_hooks/useUpdateGroupAndRedirectToGroup.ts b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/_hooks/useUpdateGroupAndRedirectToGroup.ts index 7b0fa9f5d..c3c52f79b 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/_hooks/useUpdateGroupAndRedirectToGroup.ts +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/form/_hooks/useUpdateGroupAndRedirectToGroup.ts @@ -5,8 +5,7 @@ import { useRouter } from 'next/navigation' import { useFetchUpdateGroupMember } from './useFetchUpdateGroupMember' export function useUpdateGroupAndRedirectToGroup() { - const { setGroupToRedirectToAfterTest, user, getCurrentSimulation } = - useUser() + const { user, getCurrentSimulation } = useUser() const { getValue } = useEngine() @@ -21,8 +20,6 @@ export function useUpdateGroupAndRedirectToGroup() { }) { const groupId = group?._id - setGroupToRedirectToAfterTest(undefined) - const results = getSimulationResults({ getValue, }) @@ -35,8 +32,6 @@ export function useUpdateGroupAndRedirectToGroup() { }) router.push(`/amis/resultats?groupId=${groupId}`) - - return } return handleUpdateGroupAndRedirectToGroup diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx index 4ac79c1be..9a94960b1 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/_components/simulateur/summary/Question.tsx @@ -2,6 +2,8 @@ import ChoicesValue from '@/components/misc/ChoicesValue' import NumberValue from '@/components/misc/NumberValue' import Trans from '@/components/translation/Trans' import { getMatomoEventClickQuestionsListLink } from '@/constants/matomo' +import foldEveryQuestionsUntil from '@/helpers/foldEveryQuestionsUntil' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useDebug } from '@/hooks/useDebug' import { useForm, useRule } from '@/publicodes-state' import { trackEvent } from '@/utils/matomo/trackEvent' @@ -13,25 +15,41 @@ type Props = { const statusClassNames = { missing: 'bg-gray-100 text-gray-500', - current: 'border-2 border-primary', - default: 'bg-primaryLight', + current: 'border-2 border-primary-500 bg-primary-300', + default: 'bg-primary-200', } export default function Question({ question, toggleQuestionList }: Props) { - const { label, isMissing, value, displayValue, unit, type, color } = - useRule(question) + const { + label, + isMissing, + isFolded, + value, + displayValue, + unit, + type, + category, + addFoldedStep, + } = useRule(question) - const { currentQuestion, setCurrentQuestion } = useForm() + const { currentQuestion, setCurrentQuestion, relevantQuestions } = useForm() const isDebug = useDebug() const status = - currentQuestion === question ? 'current' : isMissing ? 'missing' : 'default' + currentQuestion === question ? 'current' : isFolded ? 'default' : 'missing' return ( ) } diff --git a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/page.tsx b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/page.tsx index 15b5fda6d..513538e97 100644 --- a/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/simulateur/[root]/page.tsx @@ -1,5 +1,3 @@ -import Trans from '@/components/translation/Trans' -import Title from '@/design-system/layout/Title' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' import { FormProvider } from '@/publicodes-state' import Faq from './_components/Faq' @@ -19,9 +17,6 @@ export async function generateMetadata() { export default function SimulateurPage({ params }: Props) { return ( -

    - Votre bilan climat personnel</Trans>} /> - </div> <Simulateur /> <Faq /> <Tracking /> diff --git a/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AutresQuestions.tsx b/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AutresQuestions.tsx index 22132b8db..cd6f9f48f 100644 --- a/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AutresQuestions.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AutresQuestions.tsx @@ -9,7 +9,7 @@ export default function AutresQuestions() { <ul className="mb-1 list-none p-0"> <li className="mb-2" id={'empreinte'}> <details> - <summary className="cursor-pointer text-sm font-bold text-primary md:text-lg"> + <summary className="text-primary-500 cursor-pointer text-sm font-bold md:text-lg"> <Trans>C’est quoi mon empreinte carbone ?</Trans> </summary> <div className="my-2 ml-3.5"> @@ -45,7 +45,7 @@ export default function AutresQuestions() { </li> <li className="mb-2" id={'mesure'}> <details> - <summary className="cursor-pointer text-sm font-bold text-primary md:text-lg"> + <summary className="text-primary-500 cursor-pointer text-sm font-bold md:text-lg"> <Trans>Comment on la mesure ?</Trans> </summary> <div className="my-2 ml-3.5"> @@ -114,7 +114,7 @@ export default function AutresQuestions() { </li> <li className="mb-4" id={'categories'}> <details id={'categories'}> - <summary className="cursor-pointer text-sm font-bold text-primary md:text-lg"> + <summary className="text-primary-500 cursor-pointer text-sm font-bold md:text-lg"> <Trans>D’où vient mon empreinte ?</Trans> </summary> <div className="my-2 ml-3.5"> diff --git a/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AvantDeCommencer.tsx b/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AvantDeCommencer.tsx index a0e6c3847..1115906e3 100644 --- a/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AvantDeCommencer.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/tutoriel/_components/AvantDeCommencer.tsx @@ -2,14 +2,14 @@ import Trans from '@/components/translation/Trans' export default function AvantDeCommencer() { return ( - <div className="relative mb-8 mt-6 flex flex-col bg-grey-100 p-7 md:mt-10"> + <div className="relative mb-8 mt-6 flex flex-col rounded-md bg-grey-100 p-7 md:mt-10"> <div role="presentation" aria-hidden className="absolute -top-8 inline-block rounded-full bg-grey-100 p-4 text-3xl"> 💡 </div> - <h3> + <h3 className="z-10"> <Trans>Avant de commencer</Trans> </h3> <div className="relative pl-8"> diff --git a/src/app/(layout-with-navigation)/(simulation)/tutoriel/page.tsx b/src/app/(layout-with-navigation)/(simulation)/tutoriel/page.tsx index cbb138905..9e532b159 100644 --- a/src/app/(layout-with-navigation)/(simulation)/tutoriel/page.tsx +++ b/src/app/(layout-with-navigation)/(simulation)/tutoriel/page.tsx @@ -10,7 +10,7 @@ import AvantDeCommencer from './_components/AvantDeCommencer' export async function generateMetadata() { return getMetadataObject({ - title: "Tutoriel du simulateur d'empreinte climat - Nos Gestes Climat", + title: 'Calculer votre empreinte carbone individuelle - Nos Gestes Climat', description: 'Comprenez comment calculer votre empreinte sur le climat en 10min chrono.', }) diff --git a/src/app/(layout-with-navigation)/_components/MobileHeader.tsx b/src/app/(layout-with-navigation)/_components/MobileHeader.tsx deleted file mode 100644 index 00e1983bc..000000000 --- a/src/app/(layout-with-navigation)/_components/MobileHeader.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Logo from '@/components/misc/Logo' - -export default function MobileHeader() { - return ( - <div className="flex justify-center lg:hidden"> - <Logo size="xs" className="" /> - </div> - ) -} diff --git a/src/app/(layout-with-navigation)/_components/Navigation.tsx b/src/app/(layout-with-navigation)/_components/Navigation.tsx deleted file mode 100644 index 1e9d522c9..000000000 --- a/src/app/(layout-with-navigation)/_components/Navigation.tsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client' - -// import { loadPreviousSimulation, resetLocalisation } from '@/actions/actions' -import ProgressCircle from '@/design-system/utils/ProgressCircle' -import CardGameIcon from '../../../components/icons/CardGameIcon' - -import Logo from '@/components/misc/Logo' -import Trans from '@/components/translation/Trans' - -import { useClientTranslation } from '@/hooks/useClientTranslation' -import { useDebug } from '@/hooks/useDebug' -import { useUser } from '@/publicodes-state' -import { capitalizeString } from '@/utils/capitalizeString' -import Image from 'next/image' -import NavLink from './navigation/NavLink' -import PRIndicator from './navigation/PRIndicator' - -const ActionsInteractiveIcon = ({ className = '' }) => { - const actionChoices = {} - const count = Object.values(actionChoices).filter((a) => a === true).length - return <CardGameIcon className={className} number={count} /> -} - -const openmojis = { - test: '25B6', - action: 'E10C', - conference: '1F3DF', - sondage: '1F4CA', - profile: 'silhouette', - silhouettes: 'silhouettes', - personas: '1F465', - github: 'E045', -} - -export const openmojiURL = (name: keyof typeof openmojis) => - `/images/misc/${openmojis[name]}.svg` - -export const actionImg = openmojiURL('action') -export const conferenceImg = openmojiURL('conference') - -export default function Navigation() { - const { t } = useClientTranslation() - - const isDebug = useDebug() - - const enquete = '' - - const { getCurrentSimulation } = useUser() - - const persona: string | undefined = getCurrentSimulation()?.persona - - return ( - <nav - id="mainNavigation" - className="z-50 my-2 flex h-auto flex-col justify-center pb-8 outline-none lg:sticky lg:top-0 lg:my-4 lg:w-[14rem] lg:shrink-0 lg:justify-start lg:overflow-hidden lg:border-0 lg:border-r-[1px] lg:border-solid lg:border-grey-200"> - <Logo size="sm" className="hidden lg:block" /> - <div className="z-100 fixed bottom-0 left-0 m-0 w-screen border-0 border-t-[1px] border-solid border-grey-200 lg:static lg:z-auto lg:mt-4 lg:w-auto lg:border-none"> - <ul className="m-0 flex h-20 w-full list-none justify-between bg-white py-1 shadow-md sm:px-4 lg:h-auto lg:flex-col lg:justify-start lg:gap-1 lg:bg-none lg:py-2 lg:shadow-none"> - <NavLink - href="/simulateur/bilan" - className="justify-end !p-0 lg:justify-start lg:!p-4"> - <ProgressCircle className="lg:mr-4" /> - <span className="text-base text-primaryDark md:text-lg"> - <Trans>Le test</Trans> - </span> - </NavLink> - - <NavLink - href="/actions" - className="justify-end !p-0 lg:justify-start lg:!p-4"> - <ActionsInteractiveIcon className="w-12 lg:mr-4" /> - - <span className="text-base text-primaryDark md:text-lg"> - <Trans>Agir</Trans> - </span> - </NavLink> - - {!enquete && ( - <NavLink href="/profil"> - <div className="relative"> - <Image - src="/images/misc/silhouette.svg" - alt="" - className="w-8 lg:mr-4" - aria-hidden="true" - width="25" - height="25" - /> - </div> - <span className="text-base text-primaryDark md:text-lg"> - {!persona ? ( - t('Profil') - ) : ( - <span className="rounded-md bg-primary px-4 py-2 text-white"> - {capitalizeString(persona.split(' . ')[1])} - </span> - )} - </span> - </NavLink> - )} - - {!enquete && ( - <NavLink href="/amis" data-cypress-id="amis-link"> - <Image - src="/images/misc/silhouettes.svg" - alt="" - className="w-8 lg:mr-4" - aria-hidden="true" - width="25" - height="25" - /> - - <span className="text-base text-primaryDark md:text-lg"> - <Trans>Amis</Trans> - </span> - </NavLink> - )} - <PRIndicator /> - {isDebug ? ( - <div className="mx-auto hidden rounded-lg bg-red-600 px-4 py-2 text-center font-bold uppercase text-white lg:block"> - Debug - </div> - ) : null} - </ul> - </div> - </nav> - ) -} diff --git a/src/app/(layout-with-navigation)/_components/navigation/NavLink.tsx b/src/app/(layout-with-navigation)/_components/navigation/NavLink.tsx deleted file mode 100644 index 91fa2f5c3..000000000 --- a/src/app/(layout-with-navigation)/_components/navigation/NavLink.tsx +++ /dev/null @@ -1,35 +0,0 @@ -'use client' - -import ButtonLink from '@/design-system/inputs/ButtonLink' -import { usePathname } from 'next/navigation' -import { ReactNode } from 'react' - -type Props = { - href: string - children: ReactNode - className?: string -} - -export default function NavLink({ - href, - children, - className, - ...props -}: Props) { - const pathName = usePathname() - const isActive = pathName.includes(href) - - return ( - <li className="w-full sm:min-w-[84px] md:w-auto"> - <ButtonLink - className={`flex h-full !w-full flex-col gap-1 py-2 focus-within:z-10 lg:flex-row lg:py-4 ${ - isActive ? ' !bg-primaryLight' : 'font-normal' - } ${className}`} - href={href} - {...props} - color="text"> - {children} - </ButtonLink> - </li> - ) -} diff --git a/src/app/(layout-with-navigation)/layout.tsx b/src/app/(layout-with-navigation)/layout.tsx index 0b35f3a19..d19007952 100644 --- a/src/app/(layout-with-navigation)/layout.tsx +++ b/src/app/(layout-with-navigation)/layout.tsx @@ -3,16 +3,11 @@ import { PropsWithChildren } from 'react' import Footer from '@/components/layout/Footer' -import MobileHeader from './_components/MobileHeader' -import Navigation from './_components/Navigation' - export default async function PageLayout({ children }: PropsWithChildren) { return ( <> <div className="m-auto flex max-w-7xl justify-start"> - <Navigation /> - <Main className="w-full max-w-4xl p-2 md:px-4 md:py-8"> - <MobileHeader /> + <Main className="w-full max-w-4xl p-4 md:mx-auto md:py-8"> {children} </Main> </div> diff --git a/src/app/(layout-with-navigation)/personas/page.tsx b/src/app/(layout-with-navigation)/personas/page.tsx index a4ee6959a..aca2f97fd 100644 --- a/src/app/(layout-with-navigation)/personas/page.tsx +++ b/src/app/(layout-with-navigation)/personas/page.tsx @@ -1,8 +1,7 @@ import Trans from '@/components/translation/Trans' -import { NGC_MODEL_API_URL } from '@/constants/urls' import Title from '@/design-system/layout/Title' +import fetchPersonas from '@/helpers/fetchPersonas' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' -import { currentLocale } from 'next-i18n-router' import Persona from './_components/Persona' import PersonaExplanations from './_components/PersonaExplanations' @@ -15,13 +14,7 @@ export async function generateMetadata() { } export default async function Personas() { - const locale = currentLocale() - - // TODO: endpoint should not be static (and should point to local if available) - const personas = await fetch( - `${NGC_MODEL_API_URL}/personas-${locale}.json` - ).then((res) => res.json()) - + const personas = await fetchPersonas() return ( <> <Title title={<Trans>Personas</Trans>} data-cypress-id="personas-title" /> diff --git a/src/app/(layout-with-navigation)/stats/_components/content/Chart.js b/src/app/(layout-with-navigation)/stats/_components/content/Chart.js index b21f59732..6b00db4e8 100644 --- a/src/app/(layout-with-navigation)/stats/_components/content/Chart.js +++ b/src/app/(layout-with-navigation)/stats/_components/content/Chart.js @@ -93,7 +93,7 @@ export default function Chart(props) { type="monotone" dataKey={'Visiteurs'} stroke={props.color ?? '#32337B'} - fill={props.color ?? '#5758BB'} + fill={props.color ?? '#491273'} fillOpacity={1} /> </AreaChart> diff --git a/src/app/(layout-with-navigation)/stats/_components/content/DurationChart.js b/src/app/(layout-with-navigation)/stats/_components/content/DurationChart.js index ec528a090..63e8c1b44 100644 --- a/src/app/(layout-with-navigation)/stats/_components/content/DurationChart.js +++ b/src/app/(layout-with-navigation)/stats/_components/content/DurationChart.js @@ -33,7 +33,7 @@ export default function visitDuration(props) { <XAxis dataKey="label" /> <YAxis /> <Tooltip content={<CustomTooltip label={duration} />} /> - <Bar dataKey="nb_visits" fill="#5758BB" /> + <Bar dataKey="nb_visits" fill="#491273" /> </BarChart> </ResponsiveContainer> </div> diff --git a/src/app/(layout-with-navigation)/stats/_components/content/TotalChart.js b/src/app/(layout-with-navigation)/stats/_components/content/TotalChart.js index 1aa9d2dfe..03380da32 100644 --- a/src/app/(layout-with-navigation)/stats/_components/content/TotalChart.js +++ b/src/app/(layout-with-navigation)/stats/_components/content/TotalChart.js @@ -26,7 +26,7 @@ export default function TotalChart(props) { style={{ left: `${((elt - minValue) / (maxScore - minValue)) * 100}%`, }} - className="absolute bottom-0 top-0 -ml-2 h-full w-2 bg-primary opacity-5" + className="bg-primary-500 absolute bottom-0 top-0 -ml-2 h-full w-2 opacity-5" title={humanWeight({ t, i18n }, elt, true, user?.region?.code).join( ' ' )} diff --git a/src/app/(layout-with-navigation)/stats/_components/content/sources/Table.js b/src/app/(layout-with-navigation)/stats/_components/content/sources/Table.js index 18c4d59c4..7fb5d272e 100644 --- a/src/app/(layout-with-navigation)/stats/_components/content/sources/Table.js +++ b/src/app/(layout-with-navigation)/stats/_components/content/sources/Table.js @@ -11,7 +11,7 @@ export default function Table(props) { {props.title}{' '} {props.setNewWebsites && ( <button - className="m-0 inline cursor-pointer border-none bg-none p-0 text-sm text-primary" + className="text-primary-500 m-0 inline cursor-pointer border-none bg-none p-0 text-sm" onClick={() => props.setNewWebsites( (prevNewWebsites) => !prevNewWebsites diff --git a/src/app/(layout-with-navigation)/stats/_components/utils/FancySelect.js b/src/app/(layout-with-navigation)/stats/_components/utils/FancySelect.js index 2faf2023d..d93a158cb 100644 --- a/src/app/(layout-with-navigation)/stats/_components/utils/FancySelect.js +++ b/src/app/(layout-with-navigation)/stats/_components/utils/FancySelect.js @@ -1,6 +1,6 @@ export default function FancySelect(props) { return ( - <div className="relative inline-block text-primary"> + <div className="text-primary-500 relative inline-block"> <span dangerouslySetInnerHTML={{ __html: props.options.find((option) => option.value === props.value) @@ -19,7 +19,7 @@ export default function FancySelect(props) { }}> {props.options.map((option, index) => ( <option - className="text-primary" + className="text-primary-500" key={option.value + '-' + index} value={option.value} disabled={option.disabled}> diff --git a/src/app/(layout-with-navigation)/stats/_components/utils/Tile.js b/src/app/(layout-with-navigation)/stats/_components/utils/Tile.js index 80e78dc87..ebbe1317f 100644 --- a/src/app/(layout-with-navigation)/stats/_components/utils/Tile.js +++ b/src/app/(layout-with-navigation)/stats/_components/utils/Tile.js @@ -8,7 +8,7 @@ export default function Tile(props) { return ( <section className={`mb-4 ${props?.className || ''}`}> <div className="relative flex h-full flex-col justify-between p-8"> - <div className="height-2 absolute bottom-0 left-0 right-0 bg-primary" /> + <div className="height-2 bg-primary-500 absolute bottom-0 left-0 right-0" /> <div className="flex flex-1 flex-col"> {props.title && <h3>{props.title}</h3>} {props.text && <p>{props.text}</p>} diff --git a/src/app/_components/ErrorFallback.tsx b/src/app/_components/ErrorFallback.tsx index 8e75fe4ad..39d5afee4 100644 --- a/src/app/_components/ErrorFallback.tsx +++ b/src/app/_components/ErrorFallback.tsx @@ -5,7 +5,7 @@ import Button from '@/design-system/inputs/Button' export const ErrorFallback = () => { return ( <div className="text-center"> - <Logo className="mb-4" size="sm" /> + <Logo className="mb-4" /> <h1> <Trans>Une erreur s'est produite</Trans> </h1> @@ -18,8 +18,7 @@ export const ErrorFallback = () => { <Button onClick={() => { window.location.reload() - }} - > + }}> <Trans>Recharger la page</Trans> </Button> </div> diff --git a/src/app/_components/IllustrationSVG.tsx b/src/app/_components/IllustrationSVG.tsx index 4326d1ef5..47bbbeee4 100644 --- a/src/app/_components/IllustrationSVG.tsx +++ b/src/app/_components/IllustrationSVG.tsx @@ -11,8 +11,7 @@ const IllustrationSVG = forwardRef( xmlnsXlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" ref={ref} - {...props} - > + {...props}> <defs> <linearGradient id="prefix__e"> <stop @@ -236,8 +235,7 @@ const IllustrationSVG = forwardRef( display: 'inline', opacity: 1, }} - className="prefix__ciel" - > + className="prefix__ciel"> <rect ry={0.438} y={-3.29} @@ -275,17 +273,16 @@ const IllustrationSVG = forwardRef( opacity: 1, }} transform="translate(44.653 1.13)" - className="prefix__infra" - > + className="prefix__infra"> <rect ry={0.42} y={118.585} x={-48.074} height={42.721} width={223.97} + className="fill-primary-500" style={{ opacity: 1, - fill: '#5758BB', fillOpacity: 1, fillRule: 'evenodd', stroke: 'none', @@ -293,32 +290,29 @@ const IllustrationSVG = forwardRef( }} /> <g + className="fill-primary-500" style={{ opacity: 1, - fill: '#5758BB', fillOpacity: 1, fillRule: 'evenodd', stroke: 'none', strokeWidth: 3.77953, strokeOpacity: 1, - }} - > + }}> <g style={{ fill: '#1600ff', fillOpacity: 1, fillRule: 'evenodd', strokeWidth: 4.18181, - }} - > + }}> <g style={{ fill: '#00ff16', fillOpacity: 1, fillRule: 'evenodd', strokeWidth: 3.77953, - }} - > + }}> <rect ry={0} y={127.174} @@ -353,8 +347,8 @@ const IllustrationSVG = forwardRef( </g> <path d="m68.216 115.968 17.633 21.599-18.612-.392-8.727-21.207z" + className="fill-primary-500" style={{ - fill: '#5758BB', fillOpacity: 1, stroke: 'none', strokeWidth: '.271997px', @@ -1288,8 +1282,7 @@ const IllustrationSVG = forwardRef( className="prefix__velo" style={{ display: 'inline', - }} - > + }}> <rect style={{ fill: '#ff002f', @@ -1331,8 +1324,7 @@ const IllustrationSVG = forwardRef( fillOpacity: 1, stroke: '#332d66', strokeOpacity: 1, - }} - > + }}> <path transform="translate(44.653 1.13)" style={{ @@ -2579,8 +2571,7 @@ const IllustrationSVG = forwardRef( style={{ display: 'inline', }} - className="prefix__avion" - > + className="prefix__avion"> <path d="M-146.11 22.912H37.051" style={{ @@ -2596,8 +2587,7 @@ const IllustrationSVG = forwardRef( style={{ fill: '#4b4586', fillOpacity: 1, - }} - > + }}> <path style={{ fill: '#4b4586', @@ -2617,8 +2607,7 @@ const IllustrationSVG = forwardRef( style={{ opacity: 1, }} - className="prefix__nuages" - > + className="prefix__nuages"> <path style={{ display: 'inline', @@ -2863,8 +2852,7 @@ const IllustrationSVG = forwardRef( display: 'inline', opacity: 1, }} - className="prefix__immeubles" - > + className="prefix__immeubles"> <path d="M137.135 58.11v61.484l-12.235-3.977V62.392Z" style={{ @@ -3154,8 +3142,7 @@ const IllustrationSVG = forwardRef( style={{ display: 'inline', }} - transform="translate(44.653 1.13)" - > + transform="translate(44.653 1.13)"> <rect ry={0} y={80.572} @@ -3195,10 +3182,10 @@ const IllustrationSVG = forwardRef( ry={0} /> <rect + className="fill-primary-500" style={{ display: 'inline', opacity: 1, - fill: '#5758BB', fillOpacity: 1, fillRule: 'evenodd', stroke: 'none', @@ -3498,8 +3485,7 @@ const IllustrationSVG = forwardRef( style={{ fill: '#cab4cd', fillOpacity: 0.682353, - }} - > + }}> <path style={{ fill: '#cab4cd', @@ -3590,8 +3576,7 @@ const IllustrationSVG = forwardRef( className="prefix__vache" style={{ display: 'inline', - }} - > + }}> <path style={{ fill: '#4b4586', diff --git a/src/app/_components/LandingExplanations.tsx b/src/app/_components/LandingExplanations.tsx index 28b11c2e0..ba91dea3d 100644 --- a/src/app/_components/LandingExplanations.tsx +++ b/src/app/_components/LandingExplanations.tsx @@ -30,7 +30,7 @@ export default function LandingExplanations() { return ( <> - <div className="bg-primaryLight px-4 py-10 xl:rounded-md"> + <div className="bg-grey-100 px-4 py-10 xl:rounded-md"> <div className="mx-auto w-full max-w-3xl"> <LandingContent /> </div> diff --git a/src/app/_components/MainLayoutProviders.tsx b/src/app/_components/MainLayoutProviders.tsx index 24a77a14f..86e4d783b 100644 --- a/src/app/_components/MainLayoutProviders.tsx +++ b/src/app/_components/MainLayoutProviders.tsx @@ -1,6 +1,7 @@ 'use client' import { IframeOptionsProvider } from '@/contexts/IframeOptionsContext' +import { useTrackSplitTesting } from '@/hooks/useTrackSplitTesting' import { UserProvider } from '@/publicodes-state' import { PropsWithChildren } from 'react' import CheckFixedRegion from './mainLayoutProviders/CheckFixedRegion' @@ -14,6 +15,9 @@ export default function MainLayoutProviders({ children, region, }: PropsWithChildren<{ region: { code: string; name: string } }>) { + // Handles sending split testing data to Matomo + useTrackSplitTesting() + return ( <QueryParamsProvider> <IframeOptionsProvider> diff --git a/src/app/_components/NewsBanner.tsx b/src/app/_components/NewsBanner.tsx index d7314ea79..7a0f1347a 100644 --- a/src/app/_components/NewsBanner.tsx +++ b/src/app/_components/NewsBanner.tsx @@ -5,7 +5,7 @@ export const localStorageKey = 'last-viewed-release' export default async function NewsBanner() { const locale = currentLocale() - const releases = await getPosts(`src/locales/nouveautes/${locale}/`) + const releases = await getPosts(`src/locales/nouveautes/${locale ?? 'fr'}/`) return <Banner releases={releases} /> } diff --git a/src/app/_components/mainLayoutProviders/QueryClientProviderWrapper.tsx b/src/app/_components/mainLayoutProviders/QueryClientProviderWrapper.tsx index 2f38047a1..4c28fa457 100644 --- a/src/app/_components/mainLayoutProviders/QueryClientProviderWrapper.tsx +++ b/src/app/_components/mainLayoutProviders/QueryClientProviderWrapper.tsx @@ -3,7 +3,13 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { PropsWithChildren } from 'react' -const queryClient = new QueryClient() +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, +}) export default function QueryClientProviderWrapper({ children, }: PropsWithChildren) { diff --git a/src/app/_components/mainLayoutProviders/QueryParamsProvider.tsx b/src/app/_components/mainLayoutProviders/QueryParamsProvider.tsx index 2684922c2..87e8b4171 100644 --- a/src/app/_components/mainLayoutProviders/QueryParamsProvider.tsx +++ b/src/app/_components/mainLayoutProviders/QueryParamsProvider.tsx @@ -1,9 +1,11 @@ import { useDebug } from '@/hooks/useDebug' +import useModelVersion from '@/hooks/useModelVersion' import { usePRNumber } from '@/hooks/usePRNumber' import { PropsWithChildren } from 'react' export default function QueryParamsProvider({ children }: PropsWithChildren) { useDebug() usePRNumber() + useModelVersion() return children } diff --git a/src/app/_components/mainLayoutProviders/SimulationFromUrlLoader.tsx b/src/app/_components/mainLayoutProviders/SimulationFromUrlLoader.tsx index 2e61d7c45..17464d9fc 100644 --- a/src/app/_components/mainLayoutProviders/SimulationFromUrlLoader.tsx +++ b/src/app/_components/mainLayoutProviders/SimulationFromUrlLoader.tsx @@ -21,14 +21,15 @@ export default function SimulationFromUrlLoader() { const idSimulationDecoded = decodeURIComponent(idSimulation || '') - const { data: simulationFromURL } = useQuery( - ['simulationFromURL'], - () => + const { data: simulationFromURL } = useQuery({ + queryKey: ['simulationFromURL'], + queryFn: () => axios .get(`${EMAIL_SIMULATION_URL}${idSimulationDecoded}`) .then((res) => res.data), - { enabled: idSimulationDecoded ? true : false, refetchOnWindowFocus: false } - ) + enabled: idSimulationDecoded ? true : false, + refetchOnWindowFocus: false, + }) useEffect(() => { const simulationReformated = simulationFromURL?.data && { diff --git a/src/app/_components/newsBanner/Banner.tsx b/src/app/_components/newsBanner/Banner.tsx index 5c4a566b8..54f438383 100644 --- a/src/app/_components/newsBanner/Banner.tsx +++ b/src/app/_components/newsBanner/Banner.tsx @@ -58,7 +58,7 @@ export default function Banner({ releases }: Props) { return ( <Card className="relative min-w-[20rem] p-8 text-left"> <h2 className="m-0 flex items-center"> - <span className="mr-2 inline-block h-3 w-3 rounded-2xl bg-primary"></span>{' '} + <span className="bg-primary-500 mr-2 inline-block h-3 w-3 rounded-2xl"></span>{' '} <Trans>Nouveautés</Trans> </h2> <div> @@ -75,7 +75,7 @@ export default function Banner({ releases }: Props) { </div> <button onClick={handleUpdateViewedRelease} - className="absolute right-2 top-2 h-8 w-8 border-none bg-transparent p-0 text-lg text-primaryDark" + className="text-primary-700 absolute right-2 top-2 h-8 w-8 border-none bg-transparent p-0 text-lg" title={t('Fermer la notification de nouveautés')}> × </button> diff --git a/src/app/api/email-service/route.ts b/src/app/api/email-service/route.ts index 335536ed1..635fd2bc8 100644 --- a/src/app/api/email-service/route.ts +++ b/src/app/api/email-service/route.ts @@ -38,14 +38,6 @@ export async function POST(request: NextRequest) { await axios.post( 'https://api.brevo.com/v3/smtp/email', { - sender: { - name: 'Nos Gestes Climat', - email: 'contact@nosgestesclimat.fr', - }, - replyTo: { - name: 'Nos Gestes Climat', - email: 'contact@nosgestesclimat.fr', - }, to: [ { name: email, diff --git a/src/app/api/send-group-email/route.ts b/src/app/api/send-group-email/route.ts index d57825f5b..5a5d9dffe 100644 --- a/src/app/api/send-group-email/route.ts +++ b/src/app/api/send-group-email/route.ts @@ -35,14 +35,6 @@ export async function POST(req: Request) { await axios.post( 'https://api.brevo.com/v3/smtp/email', { - sender: { - name: 'Nos Gestes Climat', - email: 'contact@nosgestesclimat.fr', - }, - replyTo: { - name: 'Nos Gestes Climat', - email: 'contact@nosgestesclimat.fr', - }, to: [ { name: email, diff --git a/src/app/documentation/[...slug]/_components/DocumentationRouter.tsx b/src/app/documentation/[...slug]/_components/DocumentationRouter.tsx new file mode 100644 index 000000000..3402bb2b4 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/DocumentationRouter.tsx @@ -0,0 +1,45 @@ +'use client' + +import Providers from '@/components/providers/Providers' +import { useUser } from '@/publicodes-state' +import { JSX, useContext, useEffect } from 'react' +import { IsDocumentationClientContext } from '../../_contexts/DocumentationStateContext' +import DocumentationClient from './documentationRouter/DocumentationClient' + +type Props = { + supportedRegions: any + slug: string[] + serverComponent: JSX.Element +} + +export default function DocumentationRouter({ + supportedRegions, + slug, + serverComponent, +}: Props) { + const { isDocumentationClient, setIsDocumentationClient } = useContext( + IsDocumentationClientContext + ) + + const { getCurrentSimulation } = useUser() + + const currentSimulation = getCurrentSimulation() + + // Switch to client side documentation if the simulation has been started + useEffect(() => { + if (!currentSimulation?.foldedSteps) return + + if (currentSimulation?.foldedSteps?.length > 0) { + setIsDocumentationClient(true) + } + }, [currentSimulation, setIsDocumentationClient]) + + if (isDocumentationClient) + return ( + <Providers supportedRegions={supportedRegions} isOptim={false}> + <DocumentationClient supportedRegions={supportedRegions} slugs={slug} /> + </Providers> + ) + + return serverComponent +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationClient.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationClient.tsx new file mode 100644 index 000000000..3aa597deb --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationClient.tsx @@ -0,0 +1,52 @@ +'use client' + +import Link from '@/components/Link' +import BilanChart from '@/components/charts/BilanChart' +import ServicesChart from '@/components/charts/ServicesChart' +import Markdown from '@/design-system/utils/Markdown' +import { useClientTranslation } from '@/hooks/useClientTranslation' +import { useEngine } from '@/publicodes-state' +import { SuppportedRegions } from '@/types/international' +import Head from 'next/head' +import Engine from 'publicodes' +import { RulePage } from 'publicodes-react' +import References from '../../../_components/References' + +type Props = { + supportedRegions: SuppportedRegions + slugs: string[] +} +export default function DocumentationClient({ slugs }: Props) { + const { i18n } = useClientTranslation() + + const path = decodeURI(slugs.join('/')) + + const { engine } = useEngine() + + const documentationPath = '/documentation' + + return ( + <div className="p-8"> + <RulePage + language={i18n.language as 'fr' | 'en'} + rulePath={(path as string) ?? ''} + engine={engine as Engine} + documentationPath={documentationPath} + renderers={{ + Head, + Link: ({ children, to }) => <Link href={to || ''}>{children}</Link>, + Text: ({ children }) => ( + <> + <Markdown>{children}</Markdown> + {children.includes('<RavijenChart/>') && <BilanChart />} + {children.includes('<RavijenChartSocietaux/>') && ( + <ServicesChart /> + )} + </> + ), + References: References as any, + }} + /> + </div> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationServer.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationServer.tsx new file mode 100644 index 000000000..631644758 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/DocumentationServer.tsx @@ -0,0 +1,88 @@ +import Trans from '@/components/translation/Trans' +import { NGC_MODEL_API_URL } from '@/constants/urls' +import Card from '@/design-system/layout/Card' +import Title from '@/design-system/layout/Title' +import Markdown from '@/design-system/utils/Markdown' +import { fetchModel } from '@/helpers/data/fetchModel' +import { Rules } from '@/publicodes-state/types' +import { SuppportedRegions } from '@/types/international' +import { capitalizeString } from '@/utils/capitalizeString' +import { decodeRuleNameFromPath } from '@/utils/decodeRuleNameFromPath' +import { redirect } from 'next/navigation' +import ButtonLaunch from './documentationServer/ButtonLaunch' +import CalculDetail from './documentationServer/CalculDetail' +import PagesProches from './documentationServer/PagesProches' +import QuestionSection from './documentationServer/QuestionSection' + +type Props = { + supportedRegions: SuppportedRegions + slugs: string[] + locale?: string +} +export default async function DocumentationServer({ + slugs, + // This is a hack, we should be able to use currentLocale() from the i18n package + // but it breaks the app when used in the server side + locale, +}: Props) { + const ruleName = decodeRuleNameFromPath(slugs.join('/')) + + if (!ruleName) { + redirect('/404') + } + + // We load the default rules to render the server side documentation + const rules: Rules = await fetchModel({ + dataServer: NGC_MODEL_API_URL, + regionCode: 'FR', + locale: locale ?? 'fr', + isOptim: false, + }) + + const rule = rules[ruleName] + + if (!rule) { + redirect('/404') + } + + return ( + <div className="mt-4 w-full max-w-4xl p-4 md:mx-auto md:py-8"> + <Title + title={`${rule.icônes ?? ''} ${capitalizeString( + rule?.titre ?? + ruleName?.split(' . ')[ruleName?.split(' . ').length - 1] + )}`} + /> + + {rule.question && <QuestionSection rule={rule} />} + + {!rule.question && rule.description && ( + <section className="mt-4"> + <Markdown>{rule.description}</Markdown> + </section> + )} + + {rule.note && ( + <section className="mt-4"> + <h2>Notes</h2> + <Markdown>{rule.note}</Markdown> + </section> + )} + + <CalculDetail rule={rule} ruleName={ruleName} rules={rules} /> + + <Card className="mb-4 mt-4 bg-primary-200"> + <p className="mb-0"> + <Trans> + Pour en savoir plus sur cette règle de notre modèle, lancer le + calcul en cliquant sur le bouton ci-dessous. + </Trans> + </p> + </Card> + + <ButtonLaunch /> + + <PagesProches rules={rules} ruleName={ruleName} /> + </div> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/ButtonLaunch.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/ButtonLaunch.tsx new file mode 100644 index 000000000..e4c3f3919 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/ButtonLaunch.tsx @@ -0,0 +1,15 @@ +'use client' + +import { IsDocumentationClientContext } from '@/app/documentation/_contexts/DocumentationStateContext' +import Button from '@/design-system/inputs/Button' +import { useContext } from 'react' + +export default function ButtonLaunch() { + const { setIsDocumentationClient } = useContext(IsDocumentationClientContext) + + return ( + <Button onClick={() => setIsDocumentationClient(true)}> + Lancer le calcul + </Button> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/CalculDetail.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/CalculDetail.tsx new file mode 100644 index 000000000..04dfb6e77 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/CalculDetail.tsx @@ -0,0 +1,26 @@ +import Trans from '@/components/translation/Trans' +import { Rules } from '@/publicodes-state/types' +import { Rule } from 'publicodes' +import RuleDetail from './calculDetail/RuleDetail' + +export default function CalculDetail({ + rule, + ruleName, + rules, +}: { + rule: Rule + ruleName: string + rules: Rules +}) { + return ( + <> + <h2> + <Trans>Comment cette donnée est-elle calculée ?</Trans> + </h2> + + <div className="rounded-md border border-gray-600 p-8"> + <RuleDetail ruleData={rule} context={{ dottedName: ruleName, rules }} /> + </div> + </> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/PagesProches.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/PagesProches.tsx new file mode 100644 index 000000000..7b63339a9 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/PagesProches.tsx @@ -0,0 +1,54 @@ +import Link from '@/components/Link' +import { getRuleTitle } from '@/helpers/publicodes/getRuleTitle' +import { Rules } from '@/publicodes-state/types' +import { utils } from 'publicodes' + +export default function PagesProches({ + rules, + ruleName, +}: { + rules: Rules + ruleName: string +}) { + const namespaceRules = Object.keys(rules).filter( + (key) => key.includes(ruleName) && key !== ruleName + ) + if (!namespaceRules.length) return null + return ( + <section className="mt-8"> + <h2>Pages proches</h2> + + <ul className="list-none"> + {namespaceRules.map((ruleName) => { + const item = { + ...rules[ruleName], + dottedName: ruleName, + espace: ruleName.split(' . ').reverse(), + } + + return ( + <li key={item.dottedName} className="border-b border-gray-300 p-2"> + <Link + href={`/documentation/${utils.encodeRuleName(item.dottedName)}`} + className="no-underline hover:underline"> + <small> + {item.espace + .slice(1) + .reverse() + .map((name: string) => ( + <span key={name}>{name} › </span> + ))} + <br /> + </small> + + <span className="mr-2">{rules[item.dottedName]?.icônes}</span> + + {getRuleTitle(item)} + </Link> + </li> + ) + })} + </ul> + </section> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/QuestionSection.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/QuestionSection.tsx new file mode 100644 index 000000000..fd592b641 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/QuestionSection.tsx @@ -0,0 +1,29 @@ +import Trans from '@/components/translation/Trans' +import Card from '@/design-system/layout/Card' +import Emoji from '@/design-system/utils/Emoji' +import Markdown from '@/design-system/utils/Markdown' +import { Rule } from 'publicodes' + +export default function QuestionSection({ rule }: { rule: Rule }) { + if (!rule.question) return null + return ( + <> + <Card> + <h2> + <Emoji>💬</Emoji> <Trans>Question pour l'utilisateur</Trans> + </h2> + + <p>{rule.question}</p> + </Card> + + {rule.description && ( + <section> + <h2> + <Emoji>ℹ️</Emoji> <Trans>Aide à la saisie</Trans> + </h2> + <Markdown>{rule.description}</Markdown> + </section> + )} + </> + ) +} diff --git a/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/calculDetail/RuleDetail.tsx b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/calculDetail/RuleDetail.tsx new file mode 100644 index 000000000..31ec1e428 --- /dev/null +++ b/src/app/documentation/[...slug]/_components/documentationRouter/documentationServer/calculDetail/RuleDetail.tsx @@ -0,0 +1,117 @@ +import Link from '@/components/Link' +import { Rules } from '@/publicodes-state/types' +import { capitalizeString } from '@/utils/capitalizeString' +import { encodeRuleName } from '@/utils/publicodes/encodeRuleName' +import { Rule, utils } from 'publicodes' + +const KEYS_TO_OMIT = [ + 'titre', + 'couleur', + 'abréviation', + 'icônes', + 'description', + 'résumé', + 'exposé', + 'unité', + 'question', + 'note', + 'références', + // specific to NGC actions + 'effort', + 'inactive', + // specific to NGC form generation, could be cool to visualize, but in a <details> tag, since it's big + 'mosaique', +] + +const getRuleFormatted = (rule: Rule) => { + const ruleFormatted = { ...rule } + + for (const key in ruleFormatted) { + if (KEYS_TO_OMIT.indexOf(key) >= 0) { + delete ruleFormatted[key as keyof typeof ruleFormatted] + } + } + + return ruleFormatted +} + +export default function RuleDetail({ + ruleData, + context, +}: { + ruleData: Rule | string | number + context: { + dottedName: string + rules: Rules + } +}) { + const isDataObject = + typeof ruleData !== 'string' && typeof ruleData !== 'number' + const ruleFormatted = isDataObject ? getRuleFormatted(ruleData) : ruleData + + const isArray = + ruleData && + isDataObject && + Object.keys(ruleData).every((key) => Number.isInteger(+key)) + + if (typeof ruleFormatted === 'string') { + try { + if (!context) return <span>{capitalizeString(ruleFormatted)}</span> + + const ruleString = utils.disambiguateReference( + context.rules, + context.dottedName, + ruleFormatted + ) + + return ( + <Link href={`/documentation/${encodeRuleName(String(ruleString))}`}> + {capitalizeString(ruleFormatted)} + </Link> + ) + } catch (e) { + return <span>{capitalizeString(ruleFormatted)}</span> + } + } + + if (typeof ruleFormatted === 'number') return <span>{ruleFormatted}</span> + + if (isArray) { + return ( + <ul className="list-disc pl-8"> + {Object.entries(ruleFormatted).map(([key, value]) => { + return ( + <li key={key}> + <RuleDetail ruleData={value} context={context} /> + </li> + ) + })} + </ul> + ) + } + + return ( + <ul className="mb-0 list-none"> + {Object.entries(ruleFormatted).map(([key, value]) => { + if (typeof value === 'string' || typeof value === 'number') { + return ( + <li key={key} className="list-disc"> + <span className="ml-4"> + <RuleDetail ruleData={value} context={context} /> + </span> + </li> + ) + } + + return ( + <li key={key}> + <div>{capitalizeString(key)}:</div> + <div className="ml-4"> + <RuleDetail ruleData={value} context={context} /> + </div> + </li> + ) + })} + </ul> + ) +} diff --git a/src/app/documentation/[...slug]/layout.tsx b/src/app/documentation/[...slug]/layout.tsx deleted file mode 100644 index 72916dd0b..000000000 --- a/src/app/documentation/[...slug]/layout.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import Providers from '@/components/providers/Providers' -import { getSupportedRegions } from '@/helpers/getSupportedRegions' -import { PropsWithChildren } from 'react' - -export default async function Layout({ children }: PropsWithChildren) { - const supportedRegions = await getSupportedRegions() - return ( - <Providers supportedRegions={supportedRegions} isOptim={false}> - {children} - </Providers> - ) -} diff --git a/src/app/documentation/[...slug]/page.tsx b/src/app/documentation/[...slug]/page.tsx index f95bb3e31..f9f529f15 100644 --- a/src/app/documentation/[...slug]/page.tsx +++ b/src/app/documentation/[...slug]/page.tsx @@ -1,6 +1,7 @@ import { getSupportedRegions } from '@/helpers/getSupportedRegions' import { getMetadataObject } from '@/helpers/metadata/getMetadataObject' -import DocumentationContent from '../_components/DocumentationContent' +import DocumentationRouter from './_components/DocumentationRouter' +import DocumentationServer from './_components/documentationRouter/DocumentationServer' export async function generateMetadata() { return getMetadataObject({ @@ -11,18 +12,22 @@ export async function generateMetadata() { }) } -type Props = { - params: { - slug: string[] - } -} -export default async function DocumentationPage({ params }: Props) { +// The page content is in layout.tsx in order to persist the state +// between the server and the client +export default async function DocumentationPage({ + params: { slug }, +}: { + params: { slug: string[] } +}) { const supportedRegions = await getSupportedRegions() return ( - <DocumentationContent + <DocumentationRouter supportedRegions={supportedRegions} - slugs={params.slug} + slug={slug} + serverComponent={ + <DocumentationServer supportedRegions={supportedRegions} slugs={slug} /> + } /> ) } diff --git a/src/app/documentation/_components/DocumentationContent.tsx b/src/app/documentation/_components/DocumentationContent.tsx index 12fb214ae..aa97ca745 100644 --- a/src/app/documentation/_components/DocumentationContent.tsx +++ b/src/app/documentation/_components/DocumentationContent.tsx @@ -22,45 +22,36 @@ type Props = { supportedRegions: SuppportedRegions slugs: string[] } -export default function DocumentationContent({ +export default function DocumentationClient({ supportedRegions, slugs, }: Props) { const { i18n } = useClientTranslation() const path = decodeURI(slugs.join('/')) - const { user, getCurrentSimulation } = useUser() - const lang = useLocale() - const { data: rules } = useRules({ lang: lang || 'fr', region: supportedRegions[user.region?.code] ? user.region.code : 'FR', isOptim: false, }) - const currentSimulation = getCurrentSimulation() const situation = currentSimulation?.situation - const engine = useMemo<Engine | null>( () => (rules ? new Engine(rules as Rules) : null), [rules] ) - //TODO: this is shit useEffect(() => { if (engine && situation) { const rules = Object.keys(engine.getParsedRules()) - const safeSituation: Situation = safeGetSituation({ situation, everyRules: rules, }) - engine.setSituation(safeSituation as any) } }, [engine, situation]) - const documentationPath = '/documentation' return ( diff --git a/src/app/documentation/_components/DocumentationLanding.tsx b/src/app/documentation/_components/DocumentationLanding.tsx index 456a8c692..d3b190a71 100644 --- a/src/app/documentation/_components/DocumentationLanding.tsx +++ b/src/app/documentation/_components/DocumentationLanding.tsx @@ -5,16 +5,20 @@ import Title from '@/design-system/layout/Title' import { useLocale } from '@/hooks/useLocale' import { useRules } from '@/hooks/useRules' import { useUser } from '@/publicodes-state' -import Markdown from 'markdown-to-jsx' -import { utils } from 'publicodes' import Link from '@/components/Link' -import Card from '@/design-system/layout/Card' -import { NGCRules } from '@/publicodes-state/types' -import editorialisedModels from '../_data/editorialisedModels.yaml' +import DocumentationLandingCard from './DocumentationLandingCard' import SearchBar from './SearchBar' -const EMOJIS = ['👤', '🏛️', '🍽️', '🌡️', '🚗', '🗑️'] +// We want to be able to define an order for the cards and their summary here +const FIXED_CARD_SUMMARIES = { + bilan: `Le coeur de Nos Gestes Climat, c'est **le bilan** d'empreinte climat personels`, + 'services sociétaux': `Les constantes de **services publics et marchands** calculées à partir des travaux du SDES`, + 'alimentation . plats': ` **6 repas** représentatifs de notre consommation`, + 'alimentation . déchets': `Un modèle inédit d'empreinte des **déchets**`, + 'logement . chauffage . empreinte par défaut': `Un calcul statistique du **chauffage** résidentiel français moyen`, + 'transport . voiture': `Le premier poste moyen d'empreinte, l'incontournable **voiture individuelle**`, +} as Record<string, string> export default function DocumentationLanding() { const locale = useLocale() @@ -23,26 +27,12 @@ export default function DocumentationLanding() { user: { region }, } = useUser() - const { data } = useRules({ + const { data: rules } = useRules({ lang: locale, region: region?.code ?? 'FR', }) - if (!data) return null - - const rules = data as NGCRules & { - [key: string]: { couleur: string; résumé: string } - } - - const editos = (editorialisedModels as unknown as string[]).map( - (dottedName: string) => ({ - ...rules[dottedName], - dottedName, - }) - ) - - const getColor = (dottedName: string) => - rules[dottedName.split(' . ')[0]].couleur + if (!rules) return null return ( <div> @@ -70,24 +60,14 @@ export default function DocumentationLanding() { </h2> <ul className="grid max-w-[60rem] grid-cols-1 flex-wrap gap-2 p-0 sm:grid-cols-2 md:grid-cols-3"> - {editos.map(({ dottedName, résumé }, index) => { + {Object.keys(FIXED_CARD_SUMMARIES).map((dottedName) => { return ( <li key={dottedName}> - <Card - tag={Link} - style={{ backgroundColor: getColor(dottedName) || '#5758BB' }} - href={'/documentation/' + utils.encodeRuleName(dottedName)} - className="relative !flex h-[12rem] flex-auto justify-center text-center text-base text-white no-underline" - > - <p className="-z-1 absolute bottom-0 left-0 right-0 top-0 text-center align-middle text-[8.5rem] opacity-20 grayscale"> - {EMOJIS[index]} - </p> - {résumé && ( - <h2 className="z-10 mb-0 text-base text-white"> - {<Markdown>{résumé}</Markdown>} - </h2> - )} - </Card> + <DocumentationLandingCard + dottedName={dottedName} + summary={FIXED_CARD_SUMMARIES[dottedName]} + rule={rules[dottedName]} + /> </li> ) })} diff --git a/src/app/documentation/_components/DocumentationLandingCard.tsx b/src/app/documentation/_components/DocumentationLandingCard.tsx new file mode 100644 index 000000000..ba1d7b361 --- /dev/null +++ b/src/app/documentation/_components/DocumentationLandingCard.tsx @@ -0,0 +1,41 @@ +'use client' + +import Link from '@/components/Link' +import Card from '@/design-system/layout/Card' +import Emoji from '@/design-system/utils/Emoji' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' +import { NGCRule } from '@/publicodes-state/types' +import Markdown from 'markdown-to-jsx' +import { utils } from 'publicodes' + +type Props = { + dottedName: string + summary: string + rule: NGCRule +} +export default function DocumentationLandingCard({ + dottedName, + summary, + rule, +}: Props) { + const category = dottedName.split(' . ')[0] + + return ( + <Card + tag={Link} + href={'/documentation/' + utils.encodeRuleName(dottedName)} + className={`relative h-[12rem] flex-auto justify-center rounded-lg text-center text-base text-white no-underline ${getBackgroundColor( + category + )}`}> + <div className="-z-1 absolute left-0 top-0 mb-0 flex h-full w-full items-center justify-center p-4 text-[8.5rem] opacity-20 grayscale"> + <Emoji className="inline-block h-full align-middle"> + {rule['icônes']} + </Emoji> + </div> + + <h2 className="z-10 mb-0 text-base text-white"> + {<Markdown>{summary}</Markdown>} + </h2> + </Card> + ) +} diff --git a/src/app/documentation/_components/RuleListIem.tsx b/src/app/documentation/_components/RuleListIem.tsx index 7cf3f84fb..6465af759 100644 --- a/src/app/documentation/_components/RuleListIem.tsx +++ b/src/app/documentation/_components/RuleListIem.tsx @@ -17,12 +17,10 @@ export default function RuleListItem({ return ( <li key={item.dottedName} - className="my-2 border-b border-solid border-primaryLight p-2" - > + className="border-primary-100 my-2 border-b border-solid p-2"> <Link href={`/documentation/${encodeRuleName(item.dottedName)}`} - className="decoration-none" - > + className="decoration-none"> <small className="block"> {item.espace .slice(1) diff --git a/src/app/documentation/_components/SearchBar.tsx b/src/app/documentation/_components/SearchBar.tsx index efd4df7f8..8a6ed55c9 100644 --- a/src/app/documentation/_components/SearchBar.tsx +++ b/src/app/documentation/_components/SearchBar.tsx @@ -81,14 +81,13 @@ export default function SearchBar({ rules }: { rules: NGCRules }) { return ( <> - <Card className="my-8 !bg-primaryLight"> + <Card className="my-8 !bg-primary-100"> <h2 className="text-xl"> <span role="img" aria-label="emoji search" aria-hidden - className="mr-3 inline-block " - > + className="mr-3 inline-block "> 🔍 </span> <Trans>Explorez nos modèles</Trans> @@ -96,13 +95,13 @@ export default function SearchBar({ rules }: { rules: NGCRules }) { <label title={t('Entrez des mots clefs')} - className="flex items-center py-2" - > + className="flex items-center py-2"> + {' '} <input type="search" value={input} placeholder={t('Entrez des mots-clefs de recherche')} - className="w-full rounded-md border border-solid border-primaryLight p-4" + className="w-full rounded-md border border-solid border-primary-100 p-4" onChange={(e) => { const input = e.target.value diff --git a/src/app/documentation/_contexts/DocumentationStateContext.tsx b/src/app/documentation/_contexts/DocumentationStateContext.tsx new file mode 100644 index 000000000..aae1eb844 --- /dev/null +++ b/src/app/documentation/_contexts/DocumentationStateContext.tsx @@ -0,0 +1,32 @@ +'use client' + +import { createContext, useState } from 'react' + +type IsDocumentationClientContextType = { + isDocumentationClient: boolean + setIsDocumentationClient: (isDocumentationClient: boolean) => void +} + +export const IsDocumentationClientContext = + createContext<IsDocumentationClientContextType>({ + isDocumentationClient: false, + setIsDocumentationClient: () => {}, + }) + +export const IsDocumentationClientProvider = ({ + children, +}: { + children: React.ReactNode +}) => { + const [isDocumentationClient, setIsDocumentationClient] = useState(false) + + return ( + <IsDocumentationClientContext.Provider + value={{ + isDocumentationClient, + setIsDocumentationClient, + }}> + {children} + </IsDocumentationClientContext.Provider> + ) +} diff --git a/src/app/documentation/_data/editorialisedModels.yaml b/src/app/documentation/_data/editorialisedModels.yaml deleted file mode 100644 index 219ef2264..000000000 --- a/src/app/documentation/_data/editorialisedModels.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- bilan -- services sociétaux -- alimentation . plats -- logement . chauffage . empreinte par défaut -- transport . voiture -- alimentation . déchets diff --git a/src/app/documentation/_helpers/highlightMatches.tsx b/src/app/documentation/_helpers/highlightMatches.tsx index 9842bcd3c..cc9f6f8f2 100644 --- a/src/app/documentation/_helpers/highlightMatches.tsx +++ b/src/app/documentation/_helpers/highlightMatches.tsx @@ -22,10 +22,7 @@ export default function highlightMatches(str: string, matches: Matches) { currentIndice, [ ...acc, - <span - className={highlight ? 'bg-primaryLight font-bold' : ''} - key={i} - > + <span className={highlight ? 'bg-primary-100 font-bold' : ''} key={i}> {currentStr} </span>, ], diff --git a/src/app/documentation/layout.tsx b/src/app/documentation/layout.tsx index fdf9bf713..a3e277cac 100644 --- a/src/app/documentation/layout.tsx +++ b/src/app/documentation/layout.tsx @@ -1,20 +1,18 @@ import Footer from '@/components/layout/Footer' -import Logo from '@/components/misc/Logo' import Main from '@/design-system/layout/Main' import { PropsWithChildren } from 'react' +import { IsDocumentationClientProvider } from './_contexts/DocumentationStateContext' -export default async function Layout({ children }: PropsWithChildren) { +export default function Layout({ children }: PropsWithChildren) { return ( - <> - <header> - <Logo /> - </header> + <IsDocumentationClientProvider> <Main> - <div className="mx-auto flex flex-col justify-center gap-4 px-4 pb-8 text-center md:mx-auto md:mt-6 md:w-full md:max-w-6xl md:p-10 md:px-8 md:text-left"> + <div className="mx-auto flex max-w-full flex-col items-center justify-center gap-4 px-4 pb-8 md:items-start md:px-8 md:pb-10 md:text-left"> {children} </div> </Main> + <Footer /> - </> + </IsDocumentationClientProvider> ) } diff --git a/src/app/documentation/page.tsx b/src/app/documentation/page.tsx index 97c3c9d4d..556f906a3 100644 --- a/src/app/documentation/page.tsx +++ b/src/app/documentation/page.tsx @@ -11,5 +11,9 @@ export async function generateMetadata() { } export default function Documentation() { - return <DocumentationLanding /> + return ( + <div className="w-full max-w-4xl p-4 md:mx-auto md:py-8"> + <DocumentationLanding /> + </div> + ) } diff --git a/src/app/globals.css b/src/app/globals.css index a663c4e42..10dddf9b8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -14,7 +14,6 @@ h1 { @apply text-2xl; - @apply md:text-3xl; @apply mb-6; @apply font-bold; } @@ -77,25 +76,10 @@ html, body { margin: 0; padding: 0; - @apply text-primaryDark; } a { - @apply inline-block text-primary underline transition-colors hover:text-primaryDark; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - @apply font-bold; - @apply text-primaryDark; -} - -h1 { - @apply text-2xl; + @apply inline-block text-primary-500 underline transition-colors hover:text-primary-400; } img { @@ -235,7 +219,7 @@ blockquote { @apply rounded-md; padding: 1rem 1rem 0.25rem; margin: 1rem 0; - @apply text-primaryDark; + @apply text-primary-700; } .news-page ul { padding-left: 1rem; @@ -250,10 +234,10 @@ blockquote { Gamecard */ .game-card-1 { - @apply fill-primary; + @apply fill-primary-500; fill-opacity: 0.996078; fill-rule: 'evenodd'; - @apply stroke-primaryDark; + @apply stroke-primary-700; stroke-width: 7.2062; stroke-linecap: 'round'; stroke-linejoin: 'round'; @@ -263,10 +247,10 @@ blockquote { } .game-card-2 { - @apply fill-primary; + @apply fill-primary-500; fill-opacity: 0.996078; fill-rule: 'evenodd'; - @apply stroke-primaryDark; + @apply stroke-primary-500; stroke-width: 7.2062; stroke-linecap: 'round'; stroke-linejoin: 'round'; @@ -279,7 +263,7 @@ blockquote { fill: white; fill-opacity: 0.997404; fill-rule: 'evenodd'; - @apply stroke-primaryDark; + @apply stroke-primary-700; stroke-width: 10.1932; stroke-linecap: 'round'; stroke-linejoin: 'round'; @@ -376,7 +360,6 @@ blockquote { /* Iframe */ -.iframeOnlySimulation header, .iframeOnlySimulation footer { display: none; } @@ -394,3 +377,54 @@ blockquote { clip: rect(0, 0, 0, 0); border: 0; } + +/* + Markdown +*/ +.markdown ul { + @apply pl-6; + @apply list-disc; + @apply mb-6; +} + +.markdown ul > li { + @apply mb-2; +} + +.markdown ol { + @apply pl-6; + list-style-type: decimal; + list-style-position: outside; + @apply mb-6; +} + +.markdown h1 { + @apply text-4xl; + @apply mb-6; + @apply font-bold; + @apply leading-10; +} + +.markdown h1, +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + @apply mt-8; + @apply mb-6; +} + +.markdown p { + @apply mb-6; +} + +.markdown blockquote { + @apply mb-6; +} + +.markdown img { + @apply border; + @apply border-gray-200; + @apply rounded-md; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4fa57a640..934a4f4f4 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,5 @@ // Initialise react-i18next +import Header from '@/components/layout/Header' import getGeolocation from '@/helpers/getGeolocation' import '@/locales/initClient' import '@/locales/initServer' @@ -55,10 +56,6 @@ export default async function RootLayout({ children }: PropsWithChildren) { return ( <html lang={lang ?? ''} dir={dir(lang ?? '')}> <head> - <meta charSet="utf-8" /> - - <meta name="viewport" content="initial-scale=1" /> - <link rel="icon" href="/images/misc/favicon.png" /> <link @@ -88,7 +85,7 @@ export default async function RootLayout({ children }: PropsWithChildren) { <link rel="manifest" href="../manifest.webmanifest" /> - <meta name="theme-color" content="#5758BB" /> + <meta name="theme-color" content="#491273" /> {process.env.NEXT_PUBLIC_MATOMO_ID === '1' ? ( <Script id="matomo"> @@ -128,7 +125,7 @@ export default async function RootLayout({ children }: PropsWithChildren) { )} </head> - <body className={marianne.className}> + <body className={`${marianne.className} text-default`}> <Script id="script-user-agent">{` const b = document.documentElement; b.setAttribute('data-useragent', navigator.userAgent); @@ -136,7 +133,11 @@ export default async function RootLayout({ children }: PropsWithChildren) { <Script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver" /> <ErrorBoundary showDialog fallback={ErrorFallback}> - <MainLayoutProviders region={region}>{children}</MainLayoutProviders> + <MainLayoutProviders region={region}> + <Header /> + + {children} + </MainLayoutProviders> </ErrorBoundary> </body> </html> diff --git a/src/app/page.tsx b/src/app/page.tsx index 91d869cbb..caf7ed843 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,4 @@ import Footer from '@/components/layout/Footer' -import Logo from '@/components/misc/Logo' import Trans from '@/components/translation/Trans' import Main from '@/design-system/layout/Main' import Title from '@/design-system/layout/Title' @@ -27,12 +26,8 @@ export default async function Landing() { return ( <> - <header> - <Logo /> - </header> - <Main> - <div className="mx-auto flex flex-col justify-center gap-4 px-4 pb-8 text-center md:mx-auto md:mt-6 md:w-full md:max-w-6xl md:p-10 md:px-8 md:text-left"> + <div className="mx-auto flex flex-col justify-center gap-4 px-4 pb-8 text-center md:mx-auto md:mt-6 md:w-full md:max-w-5xl md:p-0 md:pb-8 md:pt-12 md:text-left"> <div className="gap-10 md:flex"> <div className="my-12 flex flex-col md:my-0 md:flex-1"> <Title diff --git a/src/components/charts/RavijenChart.tsx b/src/components/charts/RavijenChart.tsx index cd25735cc..057c2b4bb 100644 --- a/src/components/charts/RavijenChart.tsx +++ b/src/components/charts/RavijenChart.tsx @@ -35,7 +35,7 @@ export default function RavijenChart({ <> <ul id="ravijen" - className="flex h-[40rem] w-[36rem] max-w-full items-end gap-1 bg-white p-4"> + className="flex h-[40rem] max-w-full items-end gap-1 bg-white py-4 md:w-[36rem] md:px-4"> {categories.map((category) => ( <li key={category} className="h-full flex-1"> <CategoryChart @@ -49,9 +49,10 @@ export default function RavijenChart({ </li> ))} </ul> - <div className="px-4"> + <div className="md:px-4"> <Button size="sm" + color="secondary" onClick={() => { trackEvent(matomoDownloadRavijenChart) diff --git a/src/components/charts/ravijenChart/categoryChart/SubcategoryChartBlock.tsx b/src/components/charts/ravijenChart/categoryChart/SubcategoryChartBlock.tsx index c1c0d327d..e41e797fe 100644 --- a/src/components/charts/ravijenChart/categoryChart/SubcategoryChartBlock.tsx +++ b/src/components/charts/ravijenChart/categoryChart/SubcategoryChartBlock.tsx @@ -4,6 +4,7 @@ import Link from '@/components/Link' import SafeImage from '@/components/images/SafeImage' import { DEFAULT_LIMIT_PERCENTAGE_TO_SQUASH } from '@/constants/ravijen' import formatCarbonFootprint from '@/helpers/formatCarbonFootprint' +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' import { useRule } from '@/publicodes-state' import { capitalizeString } from '@/utils/capitalizeString' import { removePercentageFromString } from '@/utils/removePercentageFromString' @@ -28,7 +29,7 @@ export default function SubcategoryChartBlock({ sumSquashedSubcategoriesPercentage, shouldAlwaysDisplayValue, }: Props) { - const { numericValue: categoryNumericvalue, color } = useRule(category) + const { numericValue: categoryNumericvalue } = useRule(category) const subcategoryObject = useRule(subcategory) const { title, abbreviatedTitle, numericValue } = subcategoryObject @@ -57,7 +58,7 @@ export default function SubcategoryChartBlock({ ) { return ( <EnigmaticMoreChartBlock - color={color ?? '#5758BB'} + category={category} percentageSquashed={sumSquashedSubcategoriesPercentage ?? 0} /> ) @@ -75,9 +76,8 @@ export default function SubcategoryChartBlock({ href={`/documentation/${subcategory.replaceAll(' . ', '/')}`} className={`relative flex items-center py-2 !text-white !no-underline hover:!underline ${ isSmall ? 'flex-row justify-center gap-1' : 'flex-col flex-wrap' - }`} + } ${getBackgroundColor(category)}`} style={{ - backgroundColor: color ?? '#32337B', height: `${heightPercentage}%`, }}> <SafeImage @@ -95,10 +95,9 @@ export default function SubcategoryChartBlock({ {!isSmall && !shouldAlwaysDisplayValue && ( <p - style={{ - backgroundColor: color ?? '#32337B', - }} - className="absolute bottom-0 right-1 z-10 mb-0 pl-1 text-[0.65rem]"> + className={`absolute bottom-0 right-1 z-10 mb-0 pl-1 text-[0.65rem] ${getBackgroundColor( + category + )}`}> <strong> {formattedValue} {unit} </strong> diff --git a/src/components/charts/ravijenChart/categoryChart/subcategoryChartBlock/EnigmaticMoreChartBlock.tsx b/src/components/charts/ravijenChart/categoryChart/subcategoryChartBlock/EnigmaticMoreChartBlock.tsx index 686cf7129..14305b4dc 100644 --- a/src/components/charts/ravijenChart/categoryChart/subcategoryChartBlock/EnigmaticMoreChartBlock.tsx +++ b/src/components/charts/ravijenChart/categoryChart/subcategoryChartBlock/EnigmaticMoreChartBlock.tsx @@ -1,9 +1,11 @@ 'use client' -type Props = { color?: string; percentageSquashed: number } +import { getBackgroundColor } from '@/helpers/getCategoryColorClass' + +type Props = { category: string; percentageSquashed: number } export default function EnigmaticMoreChartBlock({ - color, + category, percentageSquashed, }: Props) { return ( @@ -11,8 +13,10 @@ export default function EnigmaticMoreChartBlock({ title={`Autres, ${percentageSquashed.toFixed( 1 )}% du total de la catégorie`} - style={{ backgroundColor: color ?? '', height: `${percentageSquashed}%` }} - className="relative cursor-default font-bold text-white"> + style={{ height: `${percentageSquashed}%` }} + className={`relative cursor-default font-bold text-white ${getBackgroundColor( + category + )}`}> <div className="absolute left-1/2 top-1/2 h-8 -translate-x-1/2 -translate-y-1/2 transform"> ... </div> diff --git a/src/components/form/Navigation.tsx b/src/components/form/Navigation.tsx index 027a8a96f..81f6cbe3c 100644 --- a/src/components/form/Navigation.tsx +++ b/src/components/form/Navigation.tsx @@ -12,7 +12,7 @@ import { useClientTranslation } from '@/hooks/useClientTranslation' import { useMagicKey } from '@/hooks/useMagicKey' import { useForm, useRule } from '@/publicodes-state' import { trackEvent } from '@/utils/matomo/trackEvent' -import { MouseEvent, useCallback, useState } from 'react' +import { MouseEvent, useCallback } from 'react' type Props = { question: string @@ -32,9 +32,7 @@ export default function Navigation({ question, onComplete = () => '' }: Props) { const { gotoPrevQuestion, gotoNextQuestion, noPrevQuestion, noNextQuestion } = useForm() - const { isMissing, setDefaultAsValue, numericValue } = useRule(question) - - const [isSettingDefaultValue, setIsSettingDefaultValue] = useState(false) + const { isMissing, numericValue, addFoldedStep } = useRule(question) const nextDisabled = questionsThatCantBeZero.includes(question) && numericValue < 1 @@ -49,17 +47,14 @@ export default function Navigation({ question, onComplete = () => '' }: Props) { trackEvent(getMatomoEventClickNextQuestion(question)) } - setIsSettingDefaultValue(true) - - await setDefaultAsValue(question) - - setIsSettingDefaultValue(false) + if (isMissing) { + addFoldedStep(question) + } handleMoveFocus() if (!noNextQuestion) { gotoNextQuestion() - return } @@ -70,8 +65,8 @@ export default function Navigation({ question, onComplete = () => '' }: Props) { gotoNextQuestion, noNextQuestion, isMissing, - setDefaultAsValue, onComplete, + addFoldedStep, ] ) @@ -104,7 +99,6 @@ export default function Navigation({ question, onComplete = () => '' }: Props) { <div className="flex justify-end gap-4"> {!noPrevQuestion ? ( <Button - disabled={isSettingDefaultValue} onClick={() => { trackEvent(getMatomoEventClickPrevQuestion(question)) if (!noPrevQuestion) { @@ -112,17 +106,15 @@ export default function Navigation({ question, onComplete = () => '' }: Props) { } handleMoveFocus() }} - color="text" - > + color="text"> {'← ' + t('Précédent')} </Button> ) : null} <Button color={isMissing ? 'secondary' : 'primary'} - disabled={isSettingDefaultValue || nextDisabled} + disabled={nextDisabled} data-cypress-id="next-question-button" - onClick={handleGoToNextQuestion} - > + onClick={handleGoToNextQuestion}> {noNextQuestion ? t('Terminer') : isMissing diff --git a/src/components/form/question/Label.tsx b/src/components/form/question/Label.tsx index 9b3d2c422..aba5d5935 100644 --- a/src/components/form/question/Label.tsx +++ b/src/components/form/question/Label.tsx @@ -1,5 +1,6 @@ import { QUESTION_DESCRIPTION_BUTTON_ID } from '@/constants/accessibility' import { getMatomoEventClickHelp } from '@/constants/matomo' +import Button from '@/design-system/inputs/Button' import Markdown from '@/design-system/utils/Markdown' import { QuestionSize } from '@/types/values' import { trackEvent } from '@/utils/matomo/trackEvent' @@ -47,14 +48,14 @@ export default function Label({ )} aria-label={label} htmlFor={htmlFor}> - {label}{' '} + <h1 className="mb-0 inline text-lg">{label}</h1>{' '} {description ? ( <button onClick={() => { trackEvent(getMatomoEventClickHelp(question)) setIsOpen((previsOpen) => !previsOpen) }} - className={`inline-block ${buttonSizeClassNames[size]} rounded-full border-none bg-primary text-base font-bold text-white`} + className={`inline-block ${buttonSizeClassNames[size]} rounded-full border-none bg-primary-500 text-base font-bold text-white`} title={t("Voir plus d'informations")} id={QUESTION_DESCRIPTION_BUTTON_ID}> <code>i</code> @@ -66,14 +67,14 @@ export default function Label({ initial={{ opacity: 0, scale: 0 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.2 }} - className="mb-3 origin-top"> + className="mb-3 origin-top rounded-md bg-white p-2 text-sm"> <Markdown>{description}</Markdown>{' '} - <button + <Button + size="sm" onClick={() => setIsOpen(false)} - className="block text-primary underline" title={t('Fermer')}> <Trans>Fermer</Trans> - </button> + </Button> </motion.div> ) : null} </> diff --git a/src/components/form/question/Notification.tsx b/src/components/form/question/Notification.tsx index 88565c68c..d3f66b5f5 100644 --- a/src/components/form/question/Notification.tsx +++ b/src/components/form/question/Notification.tsx @@ -16,8 +16,7 @@ export default function Notification({ notification }: Props) { initial={{ opacity: 0, scale: 0 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.2 }} - className="mb-4 flex flex-col items-end rounded-md bg-grey-100 p-4 text-sm" - > + className="mb-4 flex flex-col items-end rounded-md bg-white p-4 text-sm"> <Markdown>{description}</Markdown> <Button size="sm" onClick={() => setValue(false)}> <Trans>J'ai compris</Trans> diff --git a/src/components/form/question/NumberInput.tsx b/src/components/form/question/NumberInput.tsx index fd0af5a78..987a5fc27 100644 --- a/src/components/form/question/NumberInput.tsx +++ b/src/components/form/question/NumberInput.tsx @@ -39,7 +39,7 @@ export default function NumberInput({ className )}> <input - className={`rounded border border-primary bg-grey-100 p-2 text-right transition-colors focus:border-primary focus:ring-2 focus:ring-primary`} + className={`border-primary-500 focus:border-primary-500 rounded border bg-grey-100 p-2 text-right transition-colors focus:ring-2 focus:ring-primary`} type="number" min={min} value={isMissing ? '' : value} diff --git a/src/components/form/question/mosaic/mosaicQuestion/MosaicBooleanInput.tsx b/src/components/form/question/mosaic/mosaicQuestion/MosaicBooleanInput.tsx index 9c16ddc00..ecd3b7f61 100644 --- a/src/components/form/question/mosaic/mosaicQuestion/MosaicBooleanInput.tsx +++ b/src/components/form/question/mosaic/mosaicQuestion/MosaicBooleanInput.tsx @@ -13,15 +13,22 @@ type Props = { } const buttonClassNames = { - inactive: 'border-grey-500 bg-gray-100 text-gray-400', - checked: 'border-primary bg-primary text-white', - unchecked: 'border-primary bg-grey-100 text-primary hover:bg-primaryLight', + inactive: 'border-grey-500 bg-gray-100 text-gray-400 cursor-default', + checked: 'border-primary-500 bg-primary-200 text-primary-500 border-2', + unchecked: 'border-gray-300 bg-white text-primary-500 hover:bg-primary-100', } const checkClassNames = { inactive: 'border-gray-300', - checked: 'border-white', - unchecked: 'border-primary', + checked: 'border-primary-500', + unchecked: 'border-gray-300', } + +const labelClassNames = { + inactive: 'text-gray-500', + checked: 'text-primary-700', + unchecked: 'text-gray-700', +} + export default function MosaicBooleanInput({ question, title, @@ -39,8 +46,7 @@ export default function MosaicBooleanInput({ : 'unchecked' return ( <label - className={`relative flex cursor-pointer items-center gap-2 rounded border px-4 py-2 text-left transition-colors ${buttonClassNames[status]}`} - > + className={`relative flex cursor-pointer items-center gap-2 rounded border px-4 py-2 text-left transition-colors ${buttonClassNames[status]}`}> <input type="checkbox" disabled={isInactive} @@ -52,14 +58,13 @@ export default function MosaicBooleanInput({ id={`${DEFAULT_FOCUS_ELEMENT_ID}-${index}`} /> <span - className={`${checkClassNames[status]} block h-5 w-5 items-center rounded-sm border-2 leading-4`} - > + className={`${checkClassNames[status]} flex h-5 w-5 items-center items-center justify-center rounded-sm border-2 leading-4`}> {status === 'checked' ? ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.2 }} - > + className={`font-mono text-2xl ${labelClassNames[status]}`}> ✓ </motion.div> ) : ( @@ -68,7 +73,7 @@ export default function MosaicBooleanInput({ </span> <div className="flex-1"> {title && icons ? ( - <span className="font-semibold md:text-xl"> + <span className={`font-medium md:text-xl ${labelClassNames[status]}`}> {title} {icons} </span> ) : null} diff --git a/src/components/form/question/mosaic/mosaicQuestion/MosaicNumberInput.tsx b/src/components/form/question/mosaic/mosaicQuestion/MosaicNumberInput.tsx index 7c4aabc7a..99b446696 100644 --- a/src/components/form/question/mosaic/mosaicQuestion/MosaicNumberInput.tsx +++ b/src/components/form/question/mosaic/mosaicQuestion/MosaicNumberInput.tsx @@ -26,9 +26,8 @@ export default function NumberInput({ return ( <div className={ - 'flex items-center justify-between gap-4 rounded bg-grey-100 px-4 py-2 md:py-4' - } - > + 'flex items-center justify-between gap-4 rounded bg-white px-4 py-2 md:py-4' + }> <div> {title && icons ? ( <span className="font-semibold md:text-xl"> @@ -48,8 +47,7 @@ export default function NumberInput({ <Button disabled={value === 0} onClick={() => setValue(Number(value) - 1)} - className="z-10 h-10 w-10" - > + className="z-10 h-10 w-10"> - </Button> <input @@ -63,8 +61,7 @@ export default function NumberInput({ /> <Button onClick={() => setValue(Number(value) + 1)} - className="z-10 h-10 w-10" - > + className="z-10 h-10 w-10"> + </Button> </div> diff --git a/src/components/icons/ActionsIcon.tsx b/src/components/icons/ActionsIcon.tsx new file mode 100644 index 000000000..87ad8dd10 --- /dev/null +++ b/src/components/icons/ActionsIcon.tsx @@ -0,0 +1,45 @@ +import { twMerge } from 'tailwind-merge' + +export default function ActionsIcon({ className }: { className?: string }) { + return ( + <svg + width="22" + height="22" + viewBox="0 0 22 22" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={twMerge('stroke-default inline-block', className)}> + <g> + <path + d="M6.41675 11.6875V2.0625C6.41675 1.69783 6.56161 1.34809 6.81948 1.09023C7.07734 0.832366 7.42708 0.6875 7.79175 0.6875H13.2917C13.6564 0.6875 14.0062 0.832366 14.264 1.09023C14.5219 1.34809 14.6667 1.69783 14.6667 2.0625V11.6875C14.6667 12.0522 14.5219 12.4019 14.264 12.6598C14.0062 12.9176 13.6564 13.0625 13.2917 13.0625H9.73417" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M14.7005 2.53003L18.4634 3.5512C18.6379 3.59818 18.8014 3.67908 18.9446 3.7893C19.0878 3.89951 19.2079 4.03687 19.2979 4.19351C19.388 4.35016 19.4463 4.52302 19.4695 4.70222C19.4928 4.88142 19.4804 5.06343 19.4333 5.23786L16.9106 14.5274C16.8145 14.8789 16.5828 15.178 16.2664 15.3588C15.9499 15.5396 15.5747 15.5874 15.223 15.4917L10.2812 14.1534" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M11.9167 21.3125V18.5625H3.66675V21.3125" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M6.41671 11.6875L7.99796 9.053C8.13439 8.82519 8.3445 8.65078 8.59352 8.5586C8.84255 8.46642 9.11558 8.46201 9.36746 8.54608C9.51805 8.59625 9.65683 8.67663 9.7753 8.78228C9.89377 8.88793 9.98944 9.01664 10.0565 9.16054C10.1235 9.30443 10.1604 9.46049 10.1651 9.61916C10.1697 9.77783 10.1419 9.93578 10.0834 10.0833L9.16671 12.375C10.047 13.2554 10.5416 14.4493 10.5417 15.6943V18.5625H5.04171L2.64737 12.914C2.29254 12.117 2.20009 11.2278 2.38337 10.3748L3.92246 4.07917C4.04474 3.50839 4.35907 2.99681 4.81299 2.6298C5.26692 2.26279 5.83297 2.06255 6.41671 2.0625" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </g> + <defs> + <clipPath id="clip0_2767_23355"> + <rect width="22" height="22" fill="white" /> + </clipPath> + </defs> + </svg> + ) +} diff --git a/src/components/icons/AmisIcon.tsx b/src/components/icons/AmisIcon.tsx new file mode 100644 index 000000000..9978c740f --- /dev/null +++ b/src/components/icons/AmisIcon.tsx @@ -0,0 +1,75 @@ +import { twMerge } from 'tailwind-merge' + +export default function AmisIcon({ className }: { className?: string }) { + return ( + <svg + width="22" + height="22" + viewBox="0 0 22 22" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={twMerge('stroke-default inline-block', className)}> + <g> + <path + d="M7.5625 15.8125H2.0625C1.69783 15.8125 1.34809 15.9574 1.09023 16.2152C0.832366 16.4731 0.6875 16.8228 0.6875 17.1875V21.3125H7.5625V15.8125Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M19.9375 15.8125H14.4375V21.3125H21.3125V17.1875C21.3125 16.8228 21.1676 16.4731 20.9098 16.2152C20.6519 15.9574 20.3022 15.8125 19.9375 15.8125Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M13.0625 10.3125H8.9375C8.57283 10.3125 8.22309 10.4574 7.96523 10.7152C7.70737 10.9731 7.5625 11.3228 7.5625 11.6875V21.3125H14.4375V11.6875C14.4375 11.3228 14.2926 10.9731 14.0348 10.7152C13.7769 10.4574 13.4272 10.3125 13.0625 10.3125Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M11 5.5C12.3289 5.5 13.4062 4.42269 13.4062 3.09375C13.4062 1.76481 12.3289 0.6875 11 0.6875C9.67106 0.6875 8.59375 1.76481 8.59375 3.09375C8.59375 4.42269 9.67106 5.5 11 5.5Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M13.9784 7.56256C13.611 7.13122 13.1543 6.7848 12.64 6.54724C12.1256 6.30968 11.5658 6.18665 10.9992 6.18665C10.4326 6.18665 9.87278 6.30968 9.35841 6.54724C8.84404 6.7848 8.38739 7.13122 8.02002 7.56256" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M18.3342 11.6875C19.6632 11.6875 20.7405 10.6102 20.7405 9.28125C20.7405 7.95231 19.6632 6.875 18.3342 6.875C17.0053 6.875 15.928 7.95231 15.928 9.28125C15.928 10.6102 17.0053 11.6875 18.3342 11.6875Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M21.3125 13.75C20.8178 13.1683 20.1633 12.7445 19.4301 12.5309C18.697 12.3173 17.9173 12.3233 17.1875 12.5483" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M3.66577 11.6875C4.99471 11.6875 6.07202 10.6102 6.07202 9.28125C6.07202 7.95231 4.99471 6.875 3.66577 6.875C2.33684 6.875 1.25952 7.95231 1.25952 9.28125C1.25952 10.6102 2.33684 11.6875 3.66577 11.6875Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M0.6875 13.75C1.05563 13.3196 1.51246 12.9739 2.02667 12.7366C2.54088 12.4993 3.10033 12.3759 3.66667 12.375C4.05354 12.3753 4.43821 12.4334 4.80792 12.5473" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </g> + <defs> + <clipPath id="clip0_2767_23362"> + <rect width="22" height="22" fill="white" /> + </clipPath> + </defs> + </svg> + ) +} diff --git a/src/components/icons/BilanIcon.tsx b/src/components/icons/BilanIcon.tsx new file mode 100644 index 000000000..c976dad9e --- /dev/null +++ b/src/components/icons/BilanIcon.tsx @@ -0,0 +1,80 @@ +import { twMerge } from 'tailwind-merge' + +export default function BilanIcon({ className }: { className?: string }) { + return ( + <svg + width="23" + height="23" + viewBox="0 0 23 23" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={twMerge('stroke-default inline-block', className)}> + <path + d="M16.0058 5.00586L19.6816 8.68169" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M9.195 6.10578L13.4758 4.96912" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M3.62165 2.96167L6.90332 5.52834" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M14.75 5.8125C13.9906 5.8125 13.375 5.19689 13.375 4.4375C13.375 3.67811 13.9906 3.0625 14.75 3.0625C15.5094 3.0625 16.125 3.67811 16.125 4.4375C16.125 5.19689 15.5094 5.8125 14.75 5.8125Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M2.375 3.75C1.61561 3.75 1 3.13439 1 2.375C1 1.61561 1.61561 1 2.375 1C3.13439 1 3.75 1.61561 3.75 2.375C3.75 3.13439 3.13439 3.75 2.375 3.75Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M7.875 7.875C7.11561 7.875 6.5 7.25939 6.5 6.5C6.5 5.74061 7.11561 5.125 7.875 5.125C8.63439 5.125 9.25 5.74061 9.25 6.5C9.25 7.25939 8.63439 7.875 7.875 7.875Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M20.25 11.3125C19.4906 11.3125 18.875 10.6969 18.875 9.9375C18.875 9.17811 19.4906 8.5625 20.25 8.5625C21.0094 8.5625 21.625 9.17811 21.625 9.9375C21.625 10.6969 21.0094 11.3125 20.25 11.3125Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M21.625 21.625H1" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M16.8125 16.5834H19.5625C19.7441 16.5857 19.9176 16.6589 20.046 16.7874C20.1744 16.9158 20.2476 17.0893 20.25 17.2709V21.625H16.125V17.2709C16.125 17.0885 16.1974 16.9137 16.3264 16.7847C16.4553 16.6558 16.6302 16.5834 16.8125 16.5834Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M9.9375 10.1666H12.6875C12.8691 10.169 13.0426 10.2422 13.171 10.3706C13.2994 10.499 13.3726 10.6725 13.375 10.8541V21.625H9.25V10.8541C9.25 10.6718 9.32243 10.4969 9.45136 10.368C9.5803 10.2391 9.75516 10.1666 9.9375 10.1666Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M3.0625 13.8334H5.8125C5.9941 13.8357 6.16759 13.9089 6.29601 14.0374C6.42443 14.1658 6.49763 14.3393 6.5 14.5209V21.625H2.375V14.5209C2.375 14.3385 2.44743 14.1637 2.57636 14.0347C2.70529 13.9058 2.88016 13.8334 3.0625 13.8334Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </svg> + ) +} diff --git a/src/components/icons/GroupIcon.tsx b/src/components/icons/GroupIcon.tsx new file mode 100644 index 000000000..d6371bbeb --- /dev/null +++ b/src/components/icons/GroupIcon.tsx @@ -0,0 +1,60 @@ +import { twMerge } from 'tailwind-merge' + +export default function GroupIcon({ className }: { className?: string }) { + return ( + <svg + id="emoji" + viewBox="0 0 72 72" + version="1.1" + className={twMerge('h-8 w-8', className)}> + <g + id="line-3" + transform="matrix(0.63135518,0,0,0.63135518,26.687336,7.6493331)" + className="fill-secondary stroke-secondary"> + <path + fill="none" + stroke="#000000" + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 59.146963,67.259747 c 0,0 1.710487,-3.75115 0.572876,-8.301594 C 58.342307,53.445633 55.061154,48.487086 48.23549,48.487086 H 23.208056 c -6.825664,0 -9.890331,4.958547 -11.267863,10.471067 -1.137611,4.550444 0.102219,8.253 0.102219,8.253 0,0 10.755322,3.261749 23.400772,3.239117 13.744885,0.05443 23.703779,-3.190523 23.703779,-3.190523 z" + id="path214-3-6" + className="fill-secondary stroke-secondary" + /> + <path + fill="none" + stroke="#000000" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 24.145981,24.669844 c 0,4.237145 0.613285,8.883147 2.27522,11.376107 2.117435,3.177346 5.708076,4.550443 9.100886,4.550443 3.521701,0 6.981175,-1.373097 9.100885,-4.550443 1.660911,-2.49296 2.275221,-7.138962 2.275221,-11.376107 0,-3.177914 -1.137611,-13.651327 -11.376106,-13.651327 -10.238496,0 -11.376106,8.35484 -11.376106,13.651327 z" + id="path216-5" + className="fill-secondary stroke-secondary" + /> + </g> + <g + id="line" + transform="matrix(0.83173336,0,0,0.83173336,-4.392222,2.8394662)" + className="fill-primary-500 stroke-primary-500"> + <path + fill="none" + stroke="#000000" + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 59.146963,68.170825 c 0,0 1.710487,-4.662228 0.572876,-9.212672 C 58.342307,53.445633 55.061154,48.487086 48.23549,48.487086 H 23.208056 c -6.825664,0 -9.890331,4.958547 -11.267863,10.471067 -1.137611,4.550444 0.102219,9.164078 0.102219,9.164078 0,0 10.447579,4.441591 23.093029,4.418959 13.744885,0.05443 24.011522,-4.370365 24.011522,-4.370365 z" + id="path214-3" + className="fill-primary-500" + /> + <path + fill="none" + stroke="#000000" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 24.145981,24.669844 c 0,4.237145 0.613285,8.883147 2.27522,11.376107 2.117435,3.177346 5.708076,4.550443 9.100886,4.550443 3.521701,0 6.981175,-1.373097 9.100885,-4.550443 1.660911,-2.49296 2.275221,-7.138962 2.275221,-11.376107 0,-3.177914 -1.137611,-13.651327 -11.376106,-13.651327 -10.238496,0 -11.376106,8.35484 -11.376106,13.651327 z" + id="path216" + className="fill-primary-500 stroke-primary-500" + /> + </g> + </svg> + ) +} diff --git a/src/components/icons/NewTabSvg.tsx b/src/components/icons/NewTabSvg.tsx index bc66d3e7d..9c630198c 100644 --- a/src/components/icons/NewTabSvg.tsx +++ b/src/components/icons/NewTabSvg.tsx @@ -1,11 +1,10 @@ export default function NewTabSvg({ className = '' }) { return ( <svg - className={`ml-2 inline-block h-auto w-3 fill-primary ${className}`} + className={`fill-primary-500 ml-2 inline-block h-auto w-3 ${className}`} x="0px" y="0px" - viewBox="0 0 283.178 283.178" - > + viewBox="0 0 283.178 283.178"> <path d="M254.812,140.713h-20c-4.142,0-7.5,3.358-7.5,7.5v91.186c0,4.84-3.939,8.778-8.779,8.778H43.776 c-4.839,0-8.775-3.938-8.775-8.778V64.645c0-4.841,3.936-8.78,8.775-8.78h95.855c4.142,0,7.5-3.358,7.5-7.5v-20 diff --git a/src/components/icons/OrganisationIcon.tsx b/src/components/icons/OrganisationIcon.tsx new file mode 100644 index 000000000..a99992339 --- /dev/null +++ b/src/components/icons/OrganisationIcon.tsx @@ -0,0 +1,139 @@ +import { twMerge } from 'tailwind-merge' + +export default function OrganisationIcon({ + className, +}: { + className?: string +}) { + return ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + className={twMerge('stroke-default inline-block', className)} + xmlns="http://www.w3.org/2000/svg"> + <g> + <path + d="M20.25 3.75V23.25" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M3.75 3.75H20.25" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M3.75 23.25V3.75" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M20.25 23.25H3.75" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M20.25 3.75H3.75L5.25 0.75H18.75L20.25 3.75Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M0.75 23.25H23.25" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M14.25 21C14.25 20.4033 14.0129 19.831 13.591 19.409C13.169 18.9871 12.5967 18.75 12 18.75C11.4033 18.75 10.831 18.9871 10.409 19.409C9.98705 19.831 9.75 20.4033 9.75 21V23.25H14.25V21Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M7.5 7.125C7.40054 7.125 7.30516 7.08549 7.23483 7.01517C7.16451 6.94484 7.125 6.84946 7.125 6.75C7.125 6.65054 7.16451 6.55516 7.23483 6.48483C7.30516 6.41451 7.40054 6.375 7.5 6.375" + strokeWidth="1.5" + /> + <path + d="M7.5 7.125C7.59946 7.125 7.69484 7.08549 7.76517 7.01517C7.83549 6.94484 7.875 6.84946 7.875 6.75C7.875 6.65054 7.83549 6.55516 7.76517 6.48483C7.69484 6.41451 7.59946 6.375 7.5 6.375" + strokeWidth="1.5" + /> + <path + d="M12 7.125C11.9005 7.125 11.8052 7.08549 11.7348 7.01517C11.6645 6.94484 11.625 6.84946 11.625 6.75C11.625 6.65054 11.6645 6.55516 11.7348 6.48483C11.8052 6.41451 11.9005 6.375 12 6.375" + strokeWidth="1.5" + /> + <path + d="M12 7.125C12.0995 7.125 12.1948 7.08549 12.2652 7.01517C12.3355 6.94484 12.375 6.84946 12.375 6.75C12.375 6.65054 12.3355 6.55516 12.2652 6.48483C12.1948 6.41451 12.0995 6.375 12 6.375" + strokeWidth="1.5" + /> + <path + d="M16.5 7.125C16.4005 7.125 16.3052 7.08549 16.2348 7.01517C16.1645 6.94484 16.125 6.84946 16.125 6.75C16.125 6.65054 16.1645 6.55516 16.2348 6.48483C16.3052 6.41451 16.4005 6.375 16.5 6.375" + strokeWidth="1.5" + /> + <path + d="M16.5 7.125C16.5995 7.125 16.6948 7.08549 16.7652 7.01517C16.8355 6.94484 16.875 6.84946 16.875 6.75C16.875 6.65054 16.8355 6.55516 16.7652 6.48483C16.6948 6.41451 16.5995 6.375 16.5 6.375" + strokeWidth="1.5" + /> + <path + d="M7.5 11.625C7.40054 11.625 7.30516 11.5855 7.23483 11.5152C7.16451 11.4448 7.125 11.3495 7.125 11.25C7.125 11.1505 7.16451 11.0552 7.23483 10.9848C7.30516 10.9145 7.40054 10.875 7.5 10.875" + strokeWidth="1.5" + /> + <path + d="M7.5 11.625C7.59946 11.625 7.69484 11.5855 7.76517 11.5152C7.83549 11.4448 7.875 11.3495 7.875 11.25C7.875 11.1505 7.83549 11.0552 7.76517 10.9848C7.69484 10.9145 7.59946 10.875 7.5 10.875" + strokeWidth="1.5" + /> + <path + d="M12 11.625C11.9005 11.625 11.8052 11.5855 11.7348 11.5152C11.6645 11.4448 11.625 11.3495 11.625 11.25C11.625 11.1505 11.6645 11.0552 11.7348 10.9848C11.8052 10.9145 11.9005 10.875 12 10.875" + strokeWidth="1.5" + /> + <path + d="M12 11.625C12.0995 11.625 12.1948 11.5855 12.2652 11.5152C12.3355 11.4448 12.375 11.3495 12.375 11.25C12.375 11.1505 12.3355 11.0552 12.2652 10.9848C12.1948 10.9145 12.0995 10.875 12 10.875" + strokeWidth="1.5" + /> + <path + d="M16.5 11.625C16.4005 11.625 16.3052 11.5855 16.2348 11.5152C16.1645 11.4448 16.125 11.3495 16.125 11.25C16.125 11.1505 16.1645 11.0552 16.2348 10.9848C16.3052 10.9145 16.4005 10.875 16.5 10.875" + strokeWidth="1.5" + /> + <path + d="M16.5 11.625C16.5995 11.625 16.6948 11.5855 16.7652 11.5152C16.8355 11.4448 16.875 11.3495 16.875 11.25C16.875 11.1505 16.8355 11.0552 16.7652 10.9848C16.6948 10.9145 16.5995 10.875 16.5 10.875" + strokeWidth="1.5" + /> + <path + d="M7.5 16.125C7.40054 16.125 7.30516 16.0855 7.23483 16.0152C7.16451 15.9448 7.125 15.8495 7.125 15.75C7.125 15.6505 7.16451 15.5552 7.23483 15.4848C7.30516 15.4145 7.40054 15.375 7.5 15.375" + strokeWidth="1.5" + /> + <path + d="M7.5 16.125C7.59946 16.125 7.69484 16.0855 7.76517 16.0152C7.83549 15.9448 7.875 15.8495 7.875 15.75C7.875 15.6505 7.83549 15.5552 7.76517 15.4848C7.69484 15.4145 7.59946 15.375 7.5 15.375" + strokeWidth="1.5" + /> + <path + d="M12 16.125C11.9005 16.125 11.8052 16.0855 11.7348 16.0152C11.6645 15.9448 11.625 15.8495 11.625 15.75C11.625 15.6505 11.6645 15.5552 11.7348 15.4848C11.8052 15.4145 11.9005 15.375 12 15.375" + strokeWidth="1.5" + /> + <path + d="M12 16.125C12.0995 16.125 12.1948 16.0855 12.2652 16.0152C12.3355 15.9448 12.375 15.8495 12.375 15.75C12.375 15.6505 12.3355 15.5552 12.2652 15.4848C12.1948 15.4145 12.0995 15.375 12 15.375" + strokeWidth="1.5" + /> + <path + d="M16.5 16.125C16.4005 16.125 16.3052 16.0855 16.2348 16.0152C16.1645 15.9448 16.125 15.8495 16.125 15.75C16.125 15.6505 16.1645 15.5552 16.2348 15.4848C16.3052 15.4145 16.4005 15.375 16.5 15.375" + strokeWidth="1.5" + /> + <path + d="M16.5 16.125C16.5995 16.125 16.6948 16.0855 16.7652 16.0152C16.8355 15.9448 16.875 15.8495 16.875 15.75C16.875 15.6505 16.8355 15.5552 16.7652 15.4848C16.6948 15.4145 16.5995 15.375 16.5 15.375" + strokeWidth="1.5" + /> + </g> + <defs> + <clipPath id="clip0_3151_11727"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + ) +} diff --git a/src/components/icons/PersonIcon.tsx b/src/components/icons/PersonIcon.tsx new file mode 100644 index 000000000..ceea7c97c --- /dev/null +++ b/src/components/icons/PersonIcon.tsx @@ -0,0 +1,53 @@ +import { twMerge } from 'tailwind-merge' + +export default function PersonIcon({ className }: { className?: string }) { + return ( + <svg + id="emoji" + viewBox="0 0 72 72" + version="1.1" + className={twMerge('h-8 w-8', className)}> + <defs id="defs222" /> + <g + id="line" + transform="matrix(1.1584183,0,0,1.1584183,-3.8887895,-6.8295539)" + className="stroke-primary-500"> + <path + fill="none" + stroke="#000000" + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 59.146963,64.24551 c 0,0 1.710487,-0.736913 0.572876,-5.287357 C 58.342307,53.445633 55.061154,48.487086 48.23549,48.487086 H 23.208056 c -6.825664,0 -9.890331,4.958547 -11.267863,10.471067 -1.137611,4.550444 0.102219,5.238763 0.102219,5.238763 0,0 10.60906,-1.496241 23.25451,-1.518873 13.744885,0.05443 23.850041,1.567467 23.850041,1.567467 z" + id="path214-3" + style={{ + // strokeWidth: 3.26266, + strokeLinecap: 'butt', + strokeDasharray: 'none', + strokeOpacity: 1, + }} + className="stroke fill-primary-200" + /> + <path + fill="none" + stroke="#000000" + strokeLinecap="round" + strokeLinejoin="round" + strokeWidth="2.27522" + className="stroke-primary-500" + d="m 60.549521,63.348606 c 0,0 0,-2.27522 -1.137611,-6.825664 -1.377532,-5.51252 -4.550442,-9.100884 -11.376106,-9.100884 -5.688053,0 -17.06416,0 -25.027434,0 -6.825664,0 -9.998574,3.588364 -11.376106,9.100884 -1.137611,4.550444 -1.137611,6.825664 -1.137611,6.825664" + id="path214" + /> + <path + fill="none" + stroke="#000000" + strokeLinejoin="round" + strokeWidth="2.27522" + d="m 24.145981,24.669844 c 0,4.237145 0.613285,8.883147 2.27522,11.376107 2.117435,3.177346 5.708076,4.550443 9.100886,4.550443 3.521701,0 6.981175,-1.373097 9.100885,-4.550443 1.660911,-2.49296 2.275221,-7.138962 2.275221,-11.376107 0,-3.177914 -1.137611,-13.651327 -11.376106,-13.651327 -10.238496,0 -11.376106,8.35484 -11.376106,13.651327 z" + id="path216" + className="fill-primary-200 stroke-primary-500" + /> + </g> + </svg> + ) +} diff --git a/src/components/icons/ProfileIcon.tsx b/src/components/icons/ProfileIcon.tsx new file mode 100644 index 000000000..b708adf4c --- /dev/null +++ b/src/components/icons/ProfileIcon.tsx @@ -0,0 +1,39 @@ +import { twMerge } from 'tailwind-merge' + +export default function ProfileIcon({ className }: { className?: string }) { + return ( + <svg + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className={twMerge('stroke-default inline-block', className)}> + <g> + <path + d="M12 15C14.8995 15 17.25 12.6495 17.25 9.75C17.25 6.85051 14.8995 4.5 12 4.5C9.10051 4.5 6.75 6.85051 6.75 9.75C6.75 12.6495 9.10051 15 12 15Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M18.9129 20.876C18.0071 19.9646 16.93 19.2412 15.7436 18.7476C14.5572 18.254 13.2849 17.9999 11.9999 17.9999C10.7149 17.9999 9.44261 18.254 8.25619 18.7476C7.06978 19.2412 5.9927 19.9646 5.08691 20.876" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + <path + d="M12 23.25C18.2132 23.25 23.25 18.2132 23.25 12C23.25 5.7868 18.2132 0.75 12 0.75C5.7868 0.75 0.75 5.7868 0.75 12C0.75 18.2132 5.7868 23.25 12 23.25Z" + strokeWidth="1.5" + strokeLinecap="round" + strokeLinejoin="round" + /> + </g> + <defs> + <clipPath id="clip0_3151_4681"> + <rect width="24" height="24" fill="white" /> + </clipPath> + </defs> + </svg> + ) +} diff --git a/src/components/layout/404.tsx b/src/components/layout/404.tsx index a047d3581..803a59080 100644 --- a/src/components/layout/404.tsx +++ b/src/components/layout/404.tsx @@ -4,7 +4,7 @@ import Trans from '../translation/Trans' export default async function Route404() { return ( - <div className="mx-auto my-16 text-center text-primaryDark"> + <div className="text-primary-700 mx-auto my-16 text-center"> <h1 className="flex items-center justify-center"> <Trans>Oups! Cette page n'existe pas ou n'existe plus</Trans>{' '} <span role="img" aria-label="Emoji no" aria-hidden> diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 54606613c..e37d1de91 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -1,75 +1,100 @@ import InlineLink from '@/design-system/inputs/InlineLink' -import { getServerPathname } from '@/helpers/getServerPathname' -import Image from 'next/image' +import Separator from '@/design-system/layout/Separator' +import Emoji from '@/design-system/utils/Emoji' +import Logo from '../misc/Logo' import LanguageSwitchButton from '../translation/LanguageSwitchButton' import Trans from '../translation/Trans' export default function Footer() { - const pathname = getServerPathname() as unknown as string + return ( + <footer className="flex flex-col items-center gap-4 bg-grey-100 p-4 pb-32 sm:p-8 md:mb-0 md:pb-24"> + <div className="flex w-full items-start gap-12 md:max-w-5xl"> + <Logo className="hidden scale-75 lg:block" /> - const isLandingPage = pathname === '/' + <div className="w-full"> + <div className="flex flex-col flex-wrap justify-start gap-6 pt-4 sm:flex-row md:items-center"> + <InlineLink + href="/nouveautes" + className="text-default no-underline hover:underline"> + <strong> + <Trans>Nouveautés</Trans> + </strong> + </InlineLink> - return ( - <footer className="flex flex-col gap-4 bg-primaryLight p-4 pb-32 sm:p-8 md:mb-0 md:pb-8"> - {isLandingPage && ( - <div className="m-4 flex flex-wrap items-center justify-center gap-4"> - <Image - src="/images/misc/logo-france-relance.svg" - alt="Logo de France Relance" - className="mr-2 h-auto w-[5rem]" - width="96" - height="86" - /> + <InlineLink + href="/a-propos" + className="text-default no-underline hover:underline"> + <strong> + <Trans>Qui sommes-nous ?</Trans> + </strong> + </InlineLink> + + <InlineLink + href="/blog" + className="text-default no-underline hover:underline"> + <strong> + <Trans>Blog</Trans> + </strong> + </InlineLink> + + <InlineLink + href="/documentation" + className="text-default no-underline hover:underline"> + <strong> + <Trans>Documentation</Trans> + </strong> + </InlineLink> - <div className="flex flex-col items-center justify-center font-bold"> - <Image - src="/images/misc/union-européenne.svg" - alt="Logo de l'Union Européenne" - className="mr-2 h-auto w-[5rem]" - width="96" - height="86" - /> - <span>NextGenerationEU</span> + <InlineLink + href="/ambassadeurs" + className="text-default no-underline hover:underline"> + <strong> + <Trans>Nos ambassadeurs</Trans> + </strong> + </InlineLink> + + <InlineLink + href="/plan-du-site" + className="font-bold text-default no-underline hover:underline"> + <Trans>Plan du site</Trans> + </InlineLink> </div> - </div> - )} - <div className="flex flex-col flex-wrap justify-start gap-2 md:flex-row md:items-center md:justify-center md:gap-3"> - <InlineLink href="/a-propos"> - <Trans>À propos</Trans> - </InlineLink> + <div className="mt-4 flex w-full flex-wrap items-baseline gap-4 text-default"> + <p className="mb-1 text-sm"> + <Trans>Diffuser le test :</Trans> + </p> + <div className="flex flex-wrap gap-6"> + <InlineLink + href="/diffuser" + className="font-bold text-default no-underline hover:underline"> + <Emoji className="mr-2">🏢</Emoji> + <Trans>Dans votre organisation</Trans> + </InlineLink> - <InlineLink href={'/documentation'}> - <Trans>Documentation</Trans> - </InlineLink> + <InlineLink + href="/international" + className="font-bold text-default no-underline hover:underline"> + <Emoji className="mr-2">🌍</Emoji> + <Trans>À l'international</Trans> + </InlineLink> + </div> + </div> - <InlineLink href="/partenaires"> - <Trans>Diffuser</Trans> - </InlineLink> - <InlineLink href="/nouveautes"> - <Trans>Nouveautés</Trans> - </InlineLink> - <InlineLink href="/international"> - <Trans>International</Trans> - </InlineLink> - <InlineLink href="/blog"> - <Trans>Blog</Trans> - </InlineLink> - <InlineLink href="/ambassadeurs"> - <Trans>Ambassadeurs</Trans> - </InlineLink> - <InlineLink href="/plan-du-site"> - <Trans i18nKey="publicodes.planDuSite.title">Plan du site</Trans> - </InlineLink> - </div> + <Separator className="mt-4" /> - <div className="flex w-full md:justify-center"> - <InlineLink href="/accessibilite"> - <Trans>Accessibilité : partiellement conforme</Trans> - </InlineLink> - </div> - <div className="mt-2 md:flex md:justify-center"> - <LanguageSwitchButton /> + <div className="mt-6 flex flex-wrap items-start justify-between gap-10"> + <LanguageSwitchButton /> + </div> + + <div className="mt-4 flex w-full flex-wrap gap-6 text-xs"> + <InlineLink + href="/accessibilite" + className="text-default no-underline hover:underline"> + <Trans>Accessibilité : partiellement conforme</Trans> + </InlineLink> + </div> + </div> </div> </footer> ) diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx new file mode 100644 index 000000000..a9113fd8e --- /dev/null +++ b/src/components/layout/Header.tsx @@ -0,0 +1,22 @@ +'use client' + +import { usePathname } from 'next/navigation' +import HeaderDesktop from './header/HeaderDesktop' +import HeaderMobile from './header/HeaderMobile' + +export default function Header() { + const pathname = usePathname() + + const shouldHideMostOfContent = + pathname.includes('/simulateur') || pathname.includes('/tutoriel') + + return ( + <> + {/* Displayed only on mobile (screens < 768px) */} + <HeaderMobile shouldHideMostOfContent={shouldHideMostOfContent} /> + + {/* Displayed only on desktop */} + <HeaderDesktop /> + </> + ) +} diff --git a/src/components/layout/header/HeaderDesktop.tsx b/src/components/layout/header/HeaderDesktop.tsx new file mode 100644 index 000000000..a8018c2b1 --- /dev/null +++ b/src/components/layout/header/HeaderDesktop.tsx @@ -0,0 +1,83 @@ +'use client' + +import ActionsIcon from '@/components/icons/ActionsIcon' +import AmisIcon from '@/components/icons/AmisIcon' +import BilanIcon from '@/components/icons/BilanIcon' +import ProfileIcon from '@/components/icons/ProfileIcon' +import PRIndicator from '@/components/layout/header/headerDesktop/PRIndicator' +import Logo from '@/components/misc/Logo' +import Trans from '@/components/translation/Trans' +import { useClientTranslation } from '@/hooks/useClientTranslation' +import NavLink from './NavLink' +import DebugIndicator from './headerDesktop/DebugIndicator' +import ModelVersionIndicator from './headerDesktop/ModelVersionIndicator' + +export default function HeaderDesktop() { + const { t } = useClientTranslation() + + return ( + <header className="sticky top-0 z-[500] hidden h-20 items-center lg:block"> + <div className="absolute bottom-0 left-0 right-0 top-0 flex h-20 w-full items-center border-b bg-white shadow-sm"> + <div className="mx-auto flex h-full w-full max-w-5xl justify-between gap-4 "> + <div className="flex items-center gap-16"> + <div className="flex origin-left items-center justify-center"> + <Logo /> + </div> + + <nav className="h-full"> + <ul className="flex h-full "> + <li className="px-4"> + <NavLink + href="/simulateur/bilan" + activeMatches={['/tutoriel', '/simulateur']} + icon={BilanIcon} + title={t('Le test')}> + <Trans>Le test</Trans> + </NavLink> + </li> + + <li className="px-4"> + <NavLink + href="/actions" + icon={ActionsIcon} + title={t('Actions')}> + <Trans>Actions</Trans> + </NavLink> + </li> + + <li className="px-4"> + <NavLink + href="/amis" + icon={AmisIcon} + title={t('Amis')} + data-cypress-id="amis-link"> + <Trans>Amis</Trans> + </NavLink> + </li> + </ul> + </nav> + </div> + <div className="flex items-center gap-4"> + <PRIndicator /> + <ModelVersionIndicator /> + <DebugIndicator /> + + <NavLink href="/profil" icon={ProfileIcon} title={t('Profil')}> + <Trans>Profil</Trans> + </NavLink> + {/* TODO : uncomment when organisations are ready + <div className="mb-2 h-3 w-[1px] bg-gray-300" /> + + <NavLink + href="https://sondages.nosgestesclimat.fr" + shouldUseDefaultLink + icon={OrganisationIcon}> + Organisations + </NavLink> + */} + </div> + </div> + </div> + </header> + ) +} diff --git a/src/components/layout/header/HeaderMobile.tsx b/src/components/layout/header/HeaderMobile.tsx new file mode 100644 index 000000000..980d777ce --- /dev/null +++ b/src/components/layout/header/HeaderMobile.tsx @@ -0,0 +1,29 @@ +'use client' + +import Logo from '@/components/misc/Logo' +import Trans from '@/components/translation/Trans' +import ButtonLink from '@/design-system/inputs/ButtonLink' +import BottomMenu from './headerMobile/BottomMenu' +import FoldableMenu from './headerMobile/FoldableMenu' + +export default function HeaderMobile({ + shouldHideMostOfContent, +}: { + shouldHideMostOfContent: boolean +}) { + return ( + <header className="sticky top-0 z-50 flex justify-between bg-white p-4 shadow-sm lg:hidden"> + <Logo /> + + {!shouldHideMostOfContent && <FoldableMenu />} + + {shouldHideMostOfContent && ( + <ButtonLink href="/" size="sm" color="text"> + ← <Trans>Revenir à l'accueil</Trans> + </ButtonLink> + )} + + {!shouldHideMostOfContent && <BottomMenu />} + </header> + ) +} diff --git a/src/components/layout/header/NavLink.tsx b/src/components/layout/header/NavLink.tsx new file mode 100644 index 000000000..80c9838b5 --- /dev/null +++ b/src/components/layout/header/NavLink.tsx @@ -0,0 +1,69 @@ +'use client' + +import Link from '@/components/Link' +import DefaultLink from 'next/link' +import { usePathname } from 'next/navigation' +import { HTMLAttributes, JSX, PropsWithChildren } from 'react' +import { twMerge } from 'tailwind-merge' + +type Props = { + href: string + shouldUseDefaultLink?: boolean + activeMatches?: string[] + icon?: ({ className }: { className?: string }) => JSX.Element + onClick?: () => void + className?: string + activeClassName?: string +} + +export default function NavLink({ + children, + href, + icon, + activeMatches, + shouldUseDefaultLink = false, + onClick, + className, + activeClassName, + ...props +}: PropsWithChildren<Props> & HTMLAttributes<HTMLAnchorElement>) { + const pathName = usePathname() + + const isActive = + activeMatches?.some((matchString) => pathName.includes(matchString)) || + pathName.includes(href) + + const Tag = shouldUseDefaultLink ? DefaultLink : Link + + const Icon = icon || (() => null) + + return ( + <Tag + href={href} + onClick={onClick} + className={twMerge( + 'group relative flex h-full items-center gap-2 px-4 text-sm text-default no-underline transition-colors hover:text-primary-500 lg:text-lg', + `${ + isActive + ? activeClassName || 'stroke-primary-500 font-bold text-primary-500' + : '' + } ${className}` + )} + {...props}> + {isActive && ( + <span className="absolute bottom-0 left-0 lg:h-[5px] lg:w-full lg:bg-primary-500"></span> + )} + + {icon && ( + <Icon + className={twMerge( + 'h-5 w-5 group-hover:stroke-primary-500', + `${isActive ? 'stroke-primary-500' : ''}` + )} + /> + )} + + {children} + </Tag> + ) +} diff --git a/src/components/layout/header/headerDesktop/DebugIndicator.tsx b/src/components/layout/header/headerDesktop/DebugIndicator.tsx new file mode 100644 index 000000000..40a19899b --- /dev/null +++ b/src/components/layout/header/headerDesktop/DebugIndicator.tsx @@ -0,0 +1,20 @@ +'use client' + +import { useDebug } from '@/hooks/useDebug' +import { useRouter } from 'next/navigation' + +export default function DebugIndicator() { + const isDebug = useDebug() + const router = useRouter() + if (!isDebug) return null + return ( + <button + className="flex items-center gap-2 rounded-lg bg-red-600 p-2 text-center text-sm font-bold uppercase text-white " + onClick={() => { + sessionStorage.removeItem('debug') + router.refresh() + }}> + Debug + </button> + ) +} diff --git a/src/components/layout/header/headerDesktop/ModelVersionIndicator.tsx b/src/components/layout/header/headerDesktop/ModelVersionIndicator.tsx new file mode 100644 index 000000000..2e78e2a71 --- /dev/null +++ b/src/components/layout/header/headerDesktop/ModelVersionIndicator.tsx @@ -0,0 +1,57 @@ +import Link from '@/components/Link' +import { + DEFAULT_MODEL_VERSION, + NIGHTLY_MODEL_VERSION, +} from '@/constants/modelAPI' +import Emoji from '@/design-system/utils/Emoji' +import { useIframe } from '@/hooks/useIframe' +import useModelVersion, { + clearModelVersionFromStorage, +} from '@/hooks/useModelVersion' +import { usePRNumber } from '@/hooks/usePRNumber' +import Image from 'next/image' +import { useRouter } from 'next/navigation' + +export default function ModelVersionIndicator() { + const router = useRouter() + const { iframeRegion } = useIframe() + const modelVersion = useModelVersion() + + const { PRNumber } = usePRNumber() + + if (PRNumber || modelVersion === DEFAULT_MODEL_VERSION || iframeRegion) { + return null + } + + return ( + <div className="flex items-center gap-2 rounded-lg bg-gray-100 p-2 text-center font-bold uppercase text-white "> + <Emoji>🏷️</Emoji> + <Link + className="font-base text-sm text-primary-700" + target="_blank" + href={ + 'https://github.com/incubateur-ademe/nosgestesclimat/' + + modelVersion === + NIGHTLY_MODEL_VERSION + ? '/tree/preprod' + : `/releases/${modelVersion}` + }> + {modelVersion} + </Link> + <button + onClick={(event) => { + event.stopPropagation() + clearModelVersionFromStorage() + router.refresh() + }}> + <Image + className="w-4" + src="/images/misc/close-plain.svg" + alt="" + width="1" + height="1" + /> + </button> + </div> + ) +} diff --git a/src/app/(layout-with-navigation)/_components/navigation/PRIndicator.tsx b/src/components/layout/header/headerDesktop/PRIndicator.tsx similarity index 80% rename from src/app/(layout-with-navigation)/_components/navigation/PRIndicator.tsx rename to src/components/layout/header/headerDesktop/PRIndicator.tsx index 4cf92d5f7..4e1a2b806 100644 --- a/src/app/(layout-with-navigation)/_components/navigation/PRIndicator.tsx +++ b/src/components/layout/header/headerDesktop/PRIndicator.tsx @@ -14,17 +14,17 @@ export default function PRIndicator() { if (!PRNumber || iframeRegion) return null return ( - <div className="mx-auto mb-4 hidden gap-2 rounded-lg bg-gray-100 px-4 py-2 text-center font-bold uppercase text-white lg:flex "> + <div className="flex items-center gap-2 rounded-lg bg-gray-100 p-2 text-center font-bold uppercase text-white "> <Image src="/images/misc/E045.svg" alt="" - className="w-8" + className="w-6" aria-hidden="true" width="20" height="20" /> <Link - className="font-base text-sm text-primaryDark md:text-lg" + className="font-base text-sm text-primary-700" target="_blank" href={'https://github.com/datagir/nosgestesclimat/pull/' + PRNumber}> #{PRNumber} @@ -36,7 +36,7 @@ export default function PRIndicator() { router.refresh() }}> <Image - className="w-6" + className="w-4" src="/images/misc/close-plain.svg" alt="" width="1" diff --git a/src/components/layout/header/headerMobile/BottomMenu.tsx b/src/components/layout/header/headerMobile/BottomMenu.tsx new file mode 100644 index 000000000..14d432a67 --- /dev/null +++ b/src/components/layout/header/headerMobile/BottomMenu.tsx @@ -0,0 +1,43 @@ +import ActionsIcon from '@/components/icons/ActionsIcon' +import AmisIcon from '@/components/icons/AmisIcon' +import BilanIcon from '@/components/icons/BilanIcon' +import Trans from '@/components/translation/Trans' +import NavLink from '../NavLink' + +export default function BottomMenu() { + return ( + <ul className="fixed bottom-0 left-0 z-50 flex w-screen justify-around border-t border-gray-200 border-t-gray-200 bg-grey-100 shadow-md"> + <li className="h-full w-full"> + <NavLink + href="/simulateur/bilan" + activeMatches={['/tutoriel', '/simulateur']} + icon={BilanIcon} + className="flex-col p-2 px-4" + activeClassName="bg-white border-r border-gray-200 text-primary-500 font-bold"> + <Trans>Test</Trans> + </NavLink> + </li> + + <li className="h-full w-full"> + <NavLink + className="flex-col p-2 px-4" + activeClassName="bg-white border-x border-gray-200 text-primary-500 font-bold" + href="/actions" + icon={ActionsIcon}> + <Trans>Actions</Trans> + </NavLink> + </li> + + <li className="h-full w-full"> + <NavLink + className="flex-col p-2 px-4" + activeClassName="bg-white border-l border-gray-200 text-primary-500 font-bold" + href="/amis" + icon={AmisIcon} + data-cypress-id="amis-link"> + <Trans>Amis</Trans> + </NavLink> + </li> + </ul> + ) +} diff --git a/src/components/layout/header/headerMobile/FoldableMenu.tsx b/src/components/layout/header/headerMobile/FoldableMenu.tsx new file mode 100644 index 000000000..017e40f9c --- /dev/null +++ b/src/components/layout/header/headerMobile/FoldableMenu.tsx @@ -0,0 +1,69 @@ +import ProfileIcon from '@/components/icons/ProfileIcon' +import BurgerMenu from '@/design-system/layout/BurgerMenu' +import NavLink from '../NavLink' + +export default function FoldableMenu() { + return ( + <BurgerMenu> + {({ closeMenu, onFocus }) => ( + <ul className="flex flex-col gap-4"> + <li> + <NavLink + onFocus={onFocus} + onClick={closeMenu} + href="/profil" + icon={ProfileIcon}> + Profil + </NavLink> + </li> + {/* + // TODO : uncomment when organisations are ready + <li> + <NavLink + onClick={closeMenu} + href="https://sondages.nogestesclimat.fr" + shouldUseDefaultLink + icon={OrganisationIcon}> + Organisations + </NavLink> + </li> + */} + + <li> + <div className="ml-2 h-[1px] w-4 bg-gray-400" /> + </li> + + <li> + <NavLink onFocus={onFocus} onClick={closeMenu} href="/blog"> + Blog + </NavLink> + </li> + + <li> + <NavLink + onFocus={onFocus} + onClick={closeMenu} + href="/questions-frequentes"> + FAQ + </NavLink> + </li> + + <li> + <NavLink + onFocus={onFocus} + onClick={closeMenu} + href="/documentation"> + Documentation + </NavLink> + </li> + + <li> + <NavLink onFocus={onFocus} onClick={closeMenu} href="/diffuser"> + Diffuser Nos Gestes Climat + </NavLink> + </li> + </ul> + )} + </BurgerMenu> + ) +} diff --git a/src/components/misc/BarChartItem.tsx b/src/components/misc/BarChartItem.tsx deleted file mode 100644 index e080b7b3c..000000000 --- a/src/components/misc/BarChartItem.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import DisplayValue from './barChartItem/DisplayValue' - -type Props = { - label: string - color?: string - value: number - max: number - onClick: (e: any) => void -} - -export default function BarChartItem({ - label, - color = '#ff0000', - value, - max, - onClick, -}: Props) { - const percentOfMax = (value / max) * 100 - - return ( - <button onClick={onClick} className="mb-4 block w-full text-left"> - <div className="mb-1 ml-2 text-sm leading-none text-black">{label}</div> - <div className="flex h-8 items-center justify-start gap-2 "> - <div - className="flex h-full origin-left items-center justify-end rounded-full transition-all" - style={{ - width: `${percentOfMax}%`, - backgroundColor: color, - }} - > - {percentOfMax > 70 ? ( - <DisplayValue color={color} value={value} white /> - ) : null} - </div> - {percentOfMax <= 70 ? ( - <DisplayValue color={color} value={value} /> - ) : null} - </div> - </button> - ) -} diff --git a/src/components/misc/ChoiceInput.tsx b/src/components/misc/ChoiceInput.tsx index 8a0eb002e..448e4921c 100644 --- a/src/components/misc/ChoiceInput.tsx +++ b/src/components/misc/ChoiceInput.tsx @@ -24,13 +24,12 @@ export default function ChoiceInput({ <> <div className="mb-2 flex items-center gap-2"> <label - className={`flex cursor-pointer items-center gap-2 rounded border border-primary px-4 py-2 text-right md:text-xl ${ + className={`flex cursor-pointer items-center gap-2 rounded border border-gray-300 px-4 py-2 text-right md:text-xl ${ active - ? 'bg-primary text-white' - : 'bg-grey-100 text-primary hover:bg-primaryLight' + ? 'border-2 border-primary-500 bg-primary-200 text-primary-500' + : 'bg-white text-default hover:bg-primary-100' } transition-colors`} - data-cypress-id={`${props['data-cypress-id']}-label`} - > + data-cypress-id={`${props['data-cypress-id']}-label`}> <input type="radio" className="hidden" @@ -40,8 +39,10 @@ export default function ChoiceInput({ /> <span className={`${ - active ? 'border-white' : 'border-primary' - } flex h-4 w-4 items-center justify-center rounded-full border-2 before:h-3 before:w-3 before:rounded-full before:bg-white md:h-5 md:w-5`} + active + ? 'border-primary-500 before:bg-primary-500' + : 'border-gray-300 before:bg-white' + } flex h-4 w-4 items-center justify-center rounded-full border-2 before:h-3 before:w-3 before:rounded-full md:h-5 md:w-5`} /> {label} </label> @@ -52,9 +53,9 @@ export default function ChoiceInput({ ) : null} </div> {description && isOpen ? ( - <Markdown className="mb-4 w-1/2 rounded-md bg-grey-100 p-2 text-sm"> - {description} - </Markdown> + <div className="mb-4 w-1/2 rounded-md bg-white p-2 text-sm"> + <Markdown className="mb-0">{description}</Markdown> + </div> ) : null} </> ) diff --git a/src/components/misc/CountryListItem.tsx b/src/components/misc/CountryListItem.tsx index 2013973d2..a7454f1f1 100644 --- a/src/components/misc/CountryListItem.tsx +++ b/src/components/misc/CountryListItem.tsx @@ -18,13 +18,12 @@ export default function CountryListItem({ return ( <Card tag={updateCurrentRegion ? 'button' : ''} - className={`flex h-16 w-24 items-center justify-center gap-2 px-3 py-2 text-center text-xs text-primaryDark sm:h-12 sm:!w-36 sm:flex-row sm:justify-start sm:py-0 sm:text-left ${ - isSelected ? 'border border-solid border-primary !bg-primaryLight' : '' + className={`text-primary-700 flex h-16 w-24 items-center justify-center gap-2 px-3 py-2 text-center text-xs sm:h-12 sm:!w-36 sm:flex-row sm:justify-start sm:py-0 sm:text-left ${ + isSelected ? '!bg-primary-100 border border-solid border-primary' : '' }`} onClick={ updateCurrentRegion ? () => updateCurrentRegion(code) : undefined - } - > + }> <CountryFlag code={code} /> {label} </Card> diff --git a/src/components/misc/Logo.tsx b/src/components/misc/Logo.tsx index 0ee8b40a0..624527ad0 100644 --- a/src/components/misc/Logo.tsx +++ b/src/components/misc/Logo.tsx @@ -2,59 +2,34 @@ import { useIframe } from '@/hooks/useIframe' import Image from 'next/image' +import { twMerge } from 'tailwind-merge' import Link from '../Link' -export default function Logo({ - size = 'lg', - className, -}: { - size?: 'xs' | 'sm' | 'lg' - className?: string -}) { +export default function Logo({ className }: { className?: string }) { const { isIframeOnlySimulation } = useIframe() - const classnames = { - xs: { - wrapper: 'pb-2', - image: 'h-auto w-8 md:w-[50px]', - text: 'text-xs md:text-xl', - }, - sm: { - wrapper: 'pb-4 pt-8', - image: 'h-auto w-[50px]', - text: 'text-xl', - }, - lg: { - wrapper: 'pb-4 pt-8', - image: 'h-auto w-[50px] md:w-[100px]', - text: 'md:text-3xl', - }, - } - return ( - <div - className={`flex w-full items-center justify-center ${classnames[size].wrapper} ${className}`} - > + <div className={twMerge('flex items-center', className)}> <Link href="/" data-cypress-id="home-logo-link" - className={`mx-auto my-1 flex items-center justify-center no-underline md:my-4 lg:mx-auto lg:my-4 ${ + className={`flex items-center justify-center no-underline ${ // @bjlaa : this is a hack to prevent the logo from being clickable in the iframe // not a recommended method a11y-wise, but in this case it's a good fit isIframeOnlySimulation ? 'pointer-events-none' : '' - }`} - > + }`}> <Image src="/images/misc/petit-logo@3x.png" alt="Logo Nos Gestes Climat" width="200" height="200" - className={classnames[size].image} + className={'h-auto w-[50px]'} /> <div - className={`ml-2 text-lg font-extrabold uppercase !leading-[0.85] text-primaryDark lg:block ${classnames[size].text}`} - > + className={ + 'ml-2 origin-left text-lg font-extrabold uppercase !leading-[0.85] text-primary-800 transition-all duration-500 lg:block' + }> <span className="block w-full !leading-[0.85]">Nos</span> <span className="block w-full !leading-[0.85]">Gestes</span> <span className="block w-full !leading-[0.85]">Climat</span> diff --git a/src/components/misc/NumberValue.tsx b/src/components/misc/NumberValue.tsx index dbac3e602..c3d57b8bc 100644 --- a/src/components/misc/NumberValue.tsx +++ b/src/components/misc/NumberValue.tsx @@ -12,11 +12,9 @@ export default function NumberValue({ displayValue, unit }: Props) { return ( <> - {displayValue - .toLocaleString(locale, { - maximumFractionDigits: 2, - }) - .replaceAll("'", '')}{' '} + {Number(displayValue).toLocaleString(locale, { + maximumFractionDigits: 2, + })}{' '} {t(unit ?? '')} </> ) diff --git a/src/components/misc/QuestionButton.tsx b/src/components/misc/QuestionButton.tsx index 0071fa593..c76250a0a 100644 --- a/src/components/misc/QuestionButton.tsx +++ b/src/components/misc/QuestionButton.tsx @@ -5,7 +5,7 @@ type Props = { } export const colorClassNames = { - primary: 'border-primary text-primary', + primary: 'border-primary-500 text-primary', white: 'border-white text-white', } export default function QuestionButton({ @@ -17,8 +17,7 @@ export default function QuestionButton({ <button onClick={onClick} title={title} - className={`${colorClassNames[color]} z-10 h-6 w-6 rounded-full border-2 bg-transparent text-sm font-bold leading-none md:h-7 md:w-7 md:text-lg md:leading-none`} - > + className={`${colorClassNames[color]} z-10 h-6 w-6 rounded-full border-2 bg-transparent text-sm font-bold leading-none md:h-7 md:w-7 md:text-lg md:leading-none`}> ? </button> ) diff --git a/src/components/misc/RegionGrid.tsx b/src/components/misc/RegionGrid.tsx index a3387cb6d..5b46042c2 100644 --- a/src/components/misc/RegionGrid.tsx +++ b/src/components/misc/RegionGrid.tsx @@ -35,7 +35,7 @@ export default function RegionGrid({ className={`region-grid mx-auto mt-4 grid max-w-[760px] gap-4 p-0 ${className}`} {...props}> {Object.entries(sortedSupportedRegions).map(([code, params]) => { - return ( + return typeof params !== 'string' ? ( <li className="my-2 flex list-none justify-center" key={code}> <CountryListItem code={code} @@ -45,7 +45,7 @@ export default function RegionGrid({ updateCurrentRegion={updateCurrentRegion} /> </li> - ) + ) : null })} </ul> ) diff --git a/src/components/misc/Subcategory.tsx b/src/components/misc/Subcategory.tsx deleted file mode 100644 index f8f5b4afd..000000000 --- a/src/components/misc/Subcategory.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import BarChartItem from '@/components/misc/BarChartItem' -import { useRule } from '@/publicodes-state' - -type Props = { - subcategory: string - max: number - onClick?: () => void -} - -export default function Subcategory({ - subcategory, - max, - onClick = () => null, - ...props -}: Props) { - const { category, title, icons, numericValue } = useRule(subcategory) - const { color } = useRule(category || '') - - if (!numericValue) return - - return ( - <div {...props}> - <BarChartItem - label={`${icons || ''} ${title}`} - value={numericValue} - max={max} - color={color} - onClick={onClick} - /> - </div> - ) -} diff --git a/src/components/misc/barChartItem/DisplayValue.tsx b/src/components/misc/barChartItem/DisplayValue.tsx deleted file mode 100644 index a46cfd954..000000000 --- a/src/components/misc/barChartItem/DisplayValue.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useLocale } from '@/hooks/useLocale' - -type Props = { - value: number - color: string - white?: boolean -} - -export default function DisplayValue({ value, color, white }: Props) { - const locale = useLocale() - - return ( - <div - className={` pr-4 leading-none ${white ? 'text-white' : ''}`} - style={white ? {} : { color }} - > - <strong className="text-lg"> - {value.toLocaleString(locale, { - maximumFractionDigits: 0, - })} - </strong>{' '} - <span className="text-xs font-light"> - kgCO<sub>2</sub>e - </span> - </div> - ) -} diff --git a/src/components/posts/list/Item.tsx b/src/components/posts/list/Item.tsx index 71761a9b9..812a62211 100644 --- a/src/components/posts/list/Item.tsx +++ b/src/components/posts/list/Item.tsx @@ -17,7 +17,7 @@ export default function Item({ item, path }: Props) { <Card tag={Link} href={`${path}/${item.slug}`} - className="h-full w-full justify-between p-4 text-primaryDark no-underline"> + className="text-primary-700 h-full w-full justify-between p-4 no-underline"> <div> {item.data.image ? ( <Image diff --git a/src/components/questions/Voiture.tsx b/src/components/questions/Voiture.tsx index 5714e55ca..e00addb22 100644 --- a/src/components/questions/Voiture.tsx +++ b/src/components/questions/Voiture.tsx @@ -7,7 +7,7 @@ import JourneysInput from './voiture/JourneysInput' type Props = { question: string } -export default function Voture({ question }: Props) { +export default function Voiture({ question }: Props) { const [isOpen, setIsOpen] = useState(false) return ( <> diff --git a/src/components/questions/avion/ThreeYearsInput.tsx b/src/components/questions/avion/ThreeYearsInput.tsx index d532a1d58..e0f4d3312 100644 --- a/src/components/questions/avion/ThreeYearsInput.tsx +++ b/src/components/questions/avion/ThreeYearsInput.tsx @@ -102,7 +102,7 @@ export default function ThreeYearsInput({ question }: Props) { size="sm" className="mb-2 justify-start" /> - <p className="mb-0 rounded-lg bg-primaryLight p-4 font-bold"> + <p className="bg-primary-200 mb-0 rounded-lg p-4 font-bold"> {t('Total\u202f:')}{' '} {( currentYearValue + diff --git a/src/components/questions/voiture/JourneysInput.tsx b/src/components/questions/voiture/JourneysInput.tsx index 4d4147db9..dce57f3de 100644 --- a/src/components/questions/voiture/JourneysInput.tsx +++ b/src/components/questions/voiture/JourneysInput.tsx @@ -75,7 +75,7 @@ export default function JourneysInput({ question }: Props) { useEffect(() => { if (prevTotalForOnePassenger.current !== totalForOnePassenger) { - setValue(totalForOnePassenger, question) + setValue(totalForOnePassenger.toFixed(1), question) } prevTotalForOnePassenger.current = totalForOnePassenger }, [totalForOnePassenger, setValue, question]) @@ -101,7 +101,7 @@ export default function JourneysInput({ question }: Props) { <th className="px-4 py-2 text-left text-sm"> <Trans>Passagers</Trans> </th> - <th className="px-4 py-2 text-left text-sm"></th> + <th className="px-4 py-2 text-left text-sm opacity-0">Options</th> </tr> {journeys.map((journey, index) => ( <JourneyItem diff --git a/src/components/questions/voiture/journeysInput/AddJourney.tsx b/src/components/questions/voiture/journeysInput/AddJourney.tsx index 9b7536486..1d5b01a38 100644 --- a/src/components/questions/voiture/journeysInput/AddJourney.tsx +++ b/src/components/questions/voiture/journeysInput/AddJourney.tsx @@ -25,7 +25,7 @@ export default function JourneyItem({ setJourneys }: Props) { return ( <tr className=""> - <td className="border-t border-primary py-4 pl-2 pr-2 text-sm md:pr-4"> + <td className="border-primary-500 border-t py-4 pl-2 pr-2 text-sm md:pr-4"> <Select className="p-2 text-sm" value={label} @@ -39,8 +39,8 @@ export default function JourneyItem({ setJourneys }: Props) { })} </Select> </td> - <td className="border-t border-primary px-2 py-4 text-sm md:px-4"> - <span className="flex items-center gap-2"> + <td className="border-primary-500 border-t px-2 py-4 text-sm md:px-4"> + <span className="flex items-center gap-4"> <TextInputGroup className="w-12 p-2 text-sm md:w-16" name="distance" @@ -51,8 +51,8 @@ export default function JourneyItem({ setJourneys }: Props) { km </span> </td> - <td className="border-t border-primary px-2 py-4 text-sm md:px-4"> - <span className="flex items-center gap-2"> + <td className="border-primary-500 border-t px-2 py-4 text-sm md:px-4"> + <span className="flex items-center gap-4"> <TextInputGroup className="w-12 p-2 text-sm md:w-16" name="distance" @@ -75,7 +75,7 @@ export default function JourneyItem({ setJourneys }: Props) { </Select> </span> </td> - <td className="border-t border-primary px-2 py-4 text-sm md:px-4"> + <td className="border-primary-500 border-t px-2 py-4 text-sm md:px-4"> <Select className="p-2 text-sm" value={passengers} @@ -89,7 +89,7 @@ export default function JourneyItem({ setJourneys }: Props) { })} </Select> </td> - <td className="border-t border-primary py-4 pl-2 pr-2 text-right text-sm md:pl-4"> + <td className="border-primary-500 border-t py-4 pl-2 pr-2 text-right text-sm md:pl-4"> <Button size="sm" onClick={() => diff --git a/src/components/questions/voiture/journeysInput/JourneyItem.tsx b/src/components/questions/voiture/journeysInput/JourneyItem.tsx index e5a66b2cb..58541ae46 100644 --- a/src/components/questions/voiture/journeysInput/JourneyItem.tsx +++ b/src/components/questions/voiture/journeysInput/JourneyItem.tsx @@ -31,22 +31,22 @@ export const labels: Record<string, string> = { export default function AddJourney({ journey, odd, setJourneys }: Props) { const { t } = useTranslation() return ( - <tr className={odd ? 'bg-primaryLight' : ''}> + <tr className={odd ? 'bg-primary-100' : ''}> <td - className={`border-x ${ - odd ? 'border-white' : 'border-primaryLight' + className={`border-r ${ + odd ? 'border-white' : 'border-primary-200' } px-4 py-2 text-left text-sm`}> {t(labels[journey.label])} </td> <td className={`border-x ${ - odd ? 'border-white' : 'border-primaryLight' + odd ? 'border-white' : 'border-primary-200' } px-4 py-2 text-left text-sm`}> {journey.distance || 0} km </td> <td className={`border-x ${ - odd ? 'border-white' : 'border-primaryLight' + odd ? 'border-white' : 'border-primary-200' } px-4 py-2 text-left text-sm`}> {journey.reccurrence} x {t(periods[journey.period])} </td> diff --git a/src/components/total/Total.tsx b/src/components/total/Total.tsx index d774c231a..6ed72c26f 100644 --- a/src/components/total/Total.tsx +++ b/src/components/total/Total.tsx @@ -49,22 +49,19 @@ export default function Total({ toggleQuestionList }: Props) { return ( <div className="md:mb-2"> - <div className="relative mb-2 flex items-center gap-4 overflow-hidden rounded-lg bg-primary px-4 py-2 text-white md:justify-center md:text-center "> + <div className="relative mb-2 flex items-center gap-4 overflow-hidden rounded-lg bg-primary-400 px-4 py-2 text-white md:justify-center md:text-center "> <Progress /> <Planet /> <Link - href={`/fin?diapo=bilan${ - detailsParamString ? `&${detailsParamString}` : '' - }`} - className="z-10 text-white no-underline hover:text-white" - > + href={`/fin${detailsParamString ? `?${detailsParamString}` : ''}`} + className="z-10 text-white no-underline hover:text-white"> <span className="block text-2xl font-bold md:text-3xl"> {formatCarbonFootprint(carbonFootprintValue).formattedValue}{' '} {formatCarbonFootprint(carbonFootprintValue).unit} </span> <span className="block text-sm md:text-base"> <Trans i18nKey="Total.unit"> - de CO<sub>2</sub>e / an + de CO<sub className="text-white">2</sub>e / an </Trans> </span> </Link> diff --git a/src/components/total/_components/Explanation.tsx b/src/components/total/_components/Explanation.tsx index a27aef39a..5af931281 100644 --- a/src/components/total/_components/Explanation.tsx +++ b/src/components/total/_components/Explanation.tsx @@ -19,24 +19,24 @@ export default function Explanation({ toggleOpen }: Props) { initial={{ opacity: 0, scale: 0 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.2 }} - className="relative mb-2 mt-6 rounded-lg border-4 border-primary p-4 pt-2" - > + className="border-primary-500 relative mb-2 mt-6 rounded-lg border-4 p-4 pt-2"> <svg width="28" height="24" viewBox="0 0 28 24" fill="none" xmlns="http://www.w3.org/2000/svg" - className="absolute bottom-full left-8 md:left-1/2 md:-translate-x-1/2 " - > - <path d="M14 0L27.8564 24H0.143594L14 0Z" className=" fill-primary" /> + className="absolute bottom-full left-8 md:left-1/2 md:-translate-x-1/2 "> + <path + d="M14 0L27.8564 24H0.143594L14 0Z" + className=" fill-primary-500" + /> </svg> <div className="flex justify-end"> <button onClick={toggleOpen} className="text-3xl leading-none" - title={t('Fermer')} - > + title={t('Fermer')}> × </button> </div> @@ -71,8 +71,7 @@ export default function Explanation({ toggleOpen }: Props) { <div className="flex justify-end"> <Button data-cypress-id="understood-explanation-button" - onClick={toggleOpen} - > + onClick={toggleOpen}> <Trans>J'ai compris</Trans> </Button> </div> diff --git a/src/components/total/_components/Progress.tsx b/src/components/total/_components/Progress.tsx index a31f1d42f..0d0cf6b45 100644 --- a/src/components/total/_components/Progress.tsx +++ b/src/components/total/_components/Progress.tsx @@ -5,7 +5,7 @@ export default function Progress() { return ( <div - className="absolute bottom-0 left-0 right-0 top-0 origin-left bg-primaryDark transition-transform" + className="bg-primary-500 absolute bottom-0 left-0 right-0 top-0 origin-left transition-transform" style={{ transform: `scaleX(${progression})` }} /> ) diff --git a/src/components/translation/LanguageSwitchButton.tsx b/src/components/translation/LanguageSwitchButton.tsx index dd6e42947..23679a43b 100644 --- a/src/components/translation/LanguageSwitchButton.tsx +++ b/src/components/translation/LanguageSwitchButton.tsx @@ -2,9 +2,11 @@ import Button from '@/design-system/inputs/Button' import { useClientTranslation } from '@/hooks/useClientTranslation' +import { useIframe } from '@/hooks/useIframe' import i18nConfig from '@/i18nConfig' import { useCurrentLocale } from 'next-i18n-router/client' import { usePathname, useRouter, useSearchParams } from 'next/navigation' +import { useCallback, useEffect } from 'react' export default function LanguageSwitchButton() { const { t } = useClientTranslation() @@ -17,30 +19,41 @@ export default function LanguageSwitchButton() { const currentLocale = useCurrentLocale(i18nConfig) - const handleChange = (newLocale: string) => { - // set cookie for next-i18n-router - const days = 30 - const date = new Date() - date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000) - const expires = '; expires=' + date.toUTCString() - document.cookie = `NEXT_LOCALE=${newLocale};expires=${expires};path=/` + const handleChange = useCallback( + (newLocale: string) => { + // set cookie for next-i18n-router + const days = 30 + const date = new Date() + date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000) + const expires = '; expires=' + date.toUTCString() + document.cookie = `NEXT_LOCALE=${newLocale};expires=${expires};path=/` - if (currentLocale === i18nConfig.defaultLocale) { - router.push( - '/' + - newLocale + - currentPathname + - (searchParams.length > 0 ? `?=${searchParams}` : '') - ) - } else { - router.push( - currentPathname.replace(`/${currentLocale}`, `/${newLocale}`) + - (searchParams.length > 0 ? `?=${searchParams}` : '') - ) - } + if (currentLocale === i18nConfig.defaultLocale) { + router.push( + '/' + + newLocale + + currentPathname + + (searchParams.length > 0 ? `?=${searchParams}` : '') + ) + } else { + router.push( + currentPathname.replace(`/${currentLocale}`, `/${newLocale}`) + + (searchParams.length > 0 ? `?=${searchParams}` : '') + ) + } + + router.refresh() + }, + [currentLocale, currentPathname, router, searchParams] + ) - router.refresh() - } + // If the lang is fixed by the iframe and is not the same as the current locale, we change it here + const { iframeLang } = useIframe() + useEffect(() => { + if (iframeLang && iframeLang !== currentLocale) { + handleChange(iframeLang) + } + }, [iframeLang, currentLocale, handleChange]) return ( <div className="flex gap-2"> @@ -51,8 +64,7 @@ export default function LanguageSwitchButton() { size="sm" aria-label={t('Passer en français')} className="flex gap-2 px-4 py-3" - data-cypress-id="language-switch-button-fr" - > + data-cypress-id="language-switch-button-fr"> <span>FR</span> <span aria-hidden>🇫🇷</span> </Button> <Button @@ -62,8 +74,7 @@ export default function LanguageSwitchButton() { size="sm" aria-label={t('Switch to english')} className="flex gap-2 px-4 py-3" - data-cypress-id="language-switch-button-en" - > + data-cypress-id="language-switch-button-en"> <span>EN</span> <span aria-hidden>🇬🇧</span> </Button> </div> diff --git a/src/constants/metadata.ts b/src/constants/metadata.ts new file mode 100644 index 000000000..c50b41432 --- /dev/null +++ b/src/constants/metadata.ts @@ -0,0 +1,13 @@ +export const noIndexObject = { + index: false, + follow: true, + nocache: true, + googleBot: { + index: true, + follow: false, + noimageindex: true, + 'max-video-preview': -1, + 'max-image-preview': 'large', + 'max-snippet': -1, + }, +} diff --git a/src/constants/modelAPI.ts b/src/constants/modelAPI.ts new file mode 100644 index 000000000..65df07a14 --- /dev/null +++ b/src/constants/modelAPI.ts @@ -0,0 +1,4 @@ +export const MODEL_VERSION_PARAM = 'version' +export const DEFAULT_MODEL_VERSION = + process.env.NEXT_PUBLIC_MODEL_VERSION ?? 'latest' +export const NIGHTLY_MODEL_VERSION = 'nightly' diff --git a/src/constants/split-testing.ts b/src/constants/split-testing.ts new file mode 100644 index 000000000..581954239 --- /dev/null +++ b/src/constants/split-testing.ts @@ -0,0 +1 @@ +export const splitTestingCookieName = `split-number-${process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH}` diff --git a/src/constants/urls.ts b/src/constants/urls.ts index 2c0ebe8a7..21105e29c 100644 --- a/src/constants/urls.ts +++ b/src/constants/urls.ts @@ -1,16 +1,3 @@ -const openmojis = { - test: '25B6', - action: 'E10C', - conference: '1F3DF', - sondage: '1F4CA', - profile: 'silhouette', - silhouettes: 'silhouettes', - personas: '1F465', - github: 'E045', -} as { [key: string]: string } - -export const getOpenmojiURL = (name: string) => `/images/${openmojis[name]}.svg` - const secure = process.env.NODE_ENV === 'development' ? '' : 's' const protocol = `http${secure}://` @@ -25,4 +12,11 @@ export const GROUP_URL = SERVER_URL + '/group' export const SAVE_SIMULATION_URL = SERVER_URL + '/email-simulation' -export const NGC_MODEL_API_URL = 'https://data.nosgestesclimat.fr' +export const NGC_MODEL_API_URL = + 'https://nosgestesclimat-api.osc-fr1.scalingo.io' + +// Use the fallback url if the NGC_MODEL_API_URL is not available +export const NGC_MODEL_API_URL_FALLBACK = `https://master--ecolab-data.netlify.app` + +export const getModelPRUrl = (PRNumber: string | number) => + `https://deploy-preview-${PRNumber}--ecolab-data.netlify.app` diff --git a/src/contexts/IframeOptionsContext.tsx b/src/contexts/IframeOptionsContext.tsx index fc7416bb9..b7951e5f2 100644 --- a/src/contexts/IframeOptionsContext.tsx +++ b/src/contexts/IframeOptionsContext.tsx @@ -11,6 +11,7 @@ export const IframeOptionsContext = createContext<{ isIframeShareData?: boolean iframeRegion?: string | null isIframeOnlySimulation?: boolean + iframeLang?: string | null }>({}) const nullDecode = (string: string) => @@ -61,6 +62,8 @@ export const IframeOptionsProvider = ({ children }: PropsWithChildren) => { const isIframeOnlySimulation = Boolean(urlParams.get('onlySimulation')) + const iframeLang = urlParams.get('lang') + if (isIframeOnlySimulation) { // Add class to body that hides the header and the footer document.body.classList.add('iframeOnlySimulation') @@ -72,6 +75,7 @@ export const IframeOptionsProvider = ({ children }: PropsWithChildren) => { isIframeShareData, iframeRegion, isIframeOnlySimulation, + iframeLang, } return ( diff --git a/src/design-system/alerts/NotificationBubble.tsx b/src/design-system/alerts/NotificationBubble.tsx index a91e705a0..db10fafd8 100644 --- a/src/design-system/alerts/NotificationBubble.tsx +++ b/src/design-system/alerts/NotificationBubble.tsx @@ -15,15 +15,13 @@ export default function NotificationBubble({ className={`absolute -top-3 right-4 h-10 w-10 rounded-sm text-center ${ onClick ? 'cursor-pointer' : '' }`} - {...props} - > + {...props}> <svg className="w-10" viewBox="0 0 72 72" - xmlns="http://www.w3.org/2000/svg" - > + xmlns="http://www.w3.org/2000/svg"> <path - fill="#5758BB" + className="fill-primary-500" d="M17.12 49.128A22.887 22.887 0 0 1 13 36c0-12.703 10.297-23 23-23s23 10.297 23 23-10.297 23-23 23c-3.758 0-7.302-.907-10.435-2.505l-4.814 2.052-5.728 2.443 1.084-6.132z" /> <path @@ -39,8 +37,7 @@ export default function NotificationBubble({ xmlSpace="preserve" className="text-center text-2xl" x={28.883} - y={45.06} - > + y={45.06}> <tspan x={28.883} y={45.06} className="fill-white font-bold"></tspan> </text> </svg> diff --git a/src/design-system/icons/ChevronRight.tsx b/src/design-system/icons/ChevronRight.tsx index 44d1f4ee6..2f4833194 100644 --- a/src/design-system/icons/ChevronRight.tsx +++ b/src/design-system/icons/ChevronRight.tsx @@ -9,7 +9,7 @@ export default function ChevronRight({ className = '' }) { className={className}> <path d="M1.3719 1.62842L7.62523 7.88175C7.66587 7.92233 7.6981 7.97052 7.7201 8.02357C7.7421 8.07662 7.75342 8.13349 7.75342 8.19092C7.75342 8.24835 7.7421 8.30521 7.7201 8.35826C7.6981 8.41131 7.66587 8.45951 7.62523 8.50008L1.37189 14.7534" - className="stroke-primaryDark" + className="stroke-primary-700" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" diff --git a/src/design-system/inputs/Button.tsx b/src/design-system/inputs/Button.tsx index 4c5da831a..7bdd4ad43 100644 --- a/src/design-system/inputs/Button.tsx +++ b/src/design-system/inputs/Button.tsx @@ -15,10 +15,10 @@ type Props = { export const colorClassNames = { primary: - 'transition-colors text-white bg-primary shadow-sm hover:text-white hover:bg-primaryDark', + 'transition-colors !text-white bg-primary-500 border-2 border-primary-500 shadow-sm hover:text-white hover:bg-primary-700', secondary: - 'bg-transparent border-solid border-primary border-2 text-primary shadow-sm hover:bg-primaryLight hover:border-primaryDark', - text: 'text-primary bg-transparent shadow-none hover:bg-primaryLight hover:text-primary hover:border-primary', + 'border-solid border-primary-500 border-2 text-primary-500 bg-transparent shadow-sm hover:text-primary-700 hover:bg-primary-200 hover:border-primary-700', + text: 'text-primary-500 bg-transparent border-2 border-transparent shadow-none hover:bg-primary-200 hover:text-primary-700 hover:border-primary-200', } export const sizeClassNames = { @@ -29,7 +29,7 @@ export const sizeClassNames = { } export const baseClassNames = - 'inline-flex items-center whitespace-nowrap rounded-md font-bold no-underline transition-colors focus:outline-none focus:ring-2 focus:ring-primaryDark focus:ring-offset-3 aria-disabled:opacity-50 transition-color ' + 'inline-flex items-center whitespace-nowrap rounded-md font-bold no-underline transition-colors focus:outline-none focus:ring-2 focus:ring-primary-700 focus:ring-offset-3 aria-disabled:opacity-50 transition-color ' export default function Button({ onClick, @@ -51,7 +51,10 @@ export default function Button({ title={title} id={id} className={twMerge( - `${baseClassNames} ${sizeClassNames[size]} ${colorClassNames[color]}`, + `${twMerge( + baseClassNames, + `${sizeClassNames[size]} ${colorClassNames[color]}` + )}`, className )} {...props}> diff --git a/src/design-system/inputs/CheckboxInputGroup.tsx b/src/design-system/inputs/CheckboxInputGroup.tsx index b6c5a5a6b..e60b40889 100644 --- a/src/design-system/inputs/CheckboxInputGroup.tsx +++ b/src/design-system/inputs/CheckboxInputGroup.tsx @@ -35,11 +35,9 @@ export default function CheckboxInputGroup({ name={name} id={name} type="checkbox" - className={`mr-2 ${ + className={`focus:border-primary-500 focus:ring-primary-500 mr-2 max-w-[30rem] rounded-md border-solid border-grey-200 bg-grey-100 !p-4 text-2xl transition-colors focus:ring-2 ${ sizesClassNames[size] - } cursor-pointer rounded-md border-solid border-grey-200 bg-grey-100 text-2xl transition-colors focus:border-primary focus:ring-2 focus:ring-primary ${ - error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : '' - }`} + } ${error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : ''}`} onChange={onChange} aria-describedby={`error-${name}`} checked={value} diff --git a/src/design-system/inputs/GoBackLink.tsx b/src/design-system/inputs/GoBackLink.tsx index defcaa35f..e0cedfe3c 100644 --- a/src/design-system/inputs/GoBackLink.tsx +++ b/src/design-system/inputs/GoBackLink.tsx @@ -5,8 +5,7 @@ export default function GoBackLink({ className }: { className?: string }) { return ( <Link href="/amis" - className={`${className} inline-block px-0 !text-[1rem] text-primary no-underline transition-opacity hover:opacity-80`} - > + className={`${className} text-primary-500 inline-block px-0 !text-[1rem] no-underline transition-opacity hover:opacity-80`}> ← <Trans>Retour</Trans> </Link> ) diff --git a/src/design-system/inputs/InfoLink.tsx b/src/design-system/inputs/InfoLink.tsx index d15602fb3..ae129aaf0 100644 --- a/src/design-system/inputs/InfoLink.tsx +++ b/src/design-system/inputs/InfoLink.tsx @@ -14,7 +14,10 @@ export default function InfoLink({ const { t } = useClientTranslation() return ( - <Link href={href} className="rounded-full bg-primary text-white" {...props}> + <Link + href={href} + className="bg-primary-500 rounded-full text-white" + {...props}> <Image src="/images/misc/info.svg" width={24} diff --git a/src/design-system/inputs/InlineLink.tsx b/src/design-system/inputs/InlineLink.tsx index 44a08345d..0b4b4f8df 100644 --- a/src/design-system/inputs/InlineLink.tsx +++ b/src/design-system/inputs/InlineLink.tsx @@ -1,5 +1,6 @@ import Link from '@/components/Link' import { PropsWithChildren } from 'react' +import { twMerge } from 'tailwind-merge' type Props = { href: string @@ -17,8 +18,10 @@ export default function InlineLink({ <Link href={href} title={title} - className={`inline-block text-primary underline transition-colors hover:!text-primaryDark ${className}`} - > + className={twMerge( + `inline-block text-primary-500 underline transition-colors hover:!text-primary-700`, + className + )}> {children} </Link> ) diff --git a/src/design-system/inputs/InlineTextInput.tsx b/src/design-system/inputs/InlineTextInput.tsx index 58d929209..f57d61ea8 100644 --- a/src/design-system/inputs/InlineTextInput.tsx +++ b/src/design-system/inputs/InlineTextInput.tsx @@ -52,14 +52,12 @@ export default function InlineTextInput({ return } // onClose() - }} - > + }}> <label htmlFor={name} className="mb-2"> <span className={`text-sm font-bold text-slate-900 ${ error ? '!text-red-700' : '' - }`} - > + }`}> {label} </span> </label> @@ -69,7 +67,7 @@ export default function InlineTextInput({ name={name} type={type} placeholder={placeholder} - className={`max-w-[30rem] flex-1 rounded-s-md border border-solid border-grey-200 bg-grey-100 !p-4 text-sm transition-colors focus:border-primary focus:ring-2 focus:ring-primary ${ + className={`focus:border-primary-500 focus:ring-primary-500 max-w-[30rem] flex-1 rounded-s-md border border-solid border-grey-200 bg-grey-100 !p-4 text-sm transition-colors focus:ring-2 ${ error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : '' }`} aria-describedby={`error-${name}`} @@ -82,13 +80,12 @@ export default function InlineTextInput({ {...props} /> <Button - className="rounded-s-none !border-2 !border-primary" + className="!border-primary-500 rounded-s-none !border-2" id="inline-input-button" onClick={handleSubmit} aria-label={t('Ok, sauvegarder la modification')} disabled={isLoading} - data-cypress-id="button-inline-input" - > + data-cypress-id="button-inline-input"> Ok </Button> </div> diff --git a/src/design-system/inputs/Select.tsx b/src/design-system/inputs/Select.tsx index 98ffdf11d..a60ab3b72 100644 --- a/src/design-system/inputs/Select.tsx +++ b/src/design-system/inputs/Select.tsx @@ -19,7 +19,7 @@ export default function Select({ value={value} onChange={onChange} className={twMerge( - `border-grey-300 max-w-[30rem] rounded-md border border-solid bg-grey-100 p-4 text-sm transition-colors focus:border-primary focus:ring-2 focus:ring-primary `, + `border-grey-300 focus:border-primary-700 focus:ring-primary-700 max-w-[30rem] rounded-md border border-solid bg-grey-100 p-4 text-sm transition-colors focus:ring-2 `, className )}> {children} diff --git a/src/design-system/inputs/TextAreaInputGroup.tsx b/src/design-system/inputs/TextAreaInputGroup.tsx index b9b0db724..365ef74d8 100644 --- a/src/design-system/inputs/TextAreaInputGroup.tsx +++ b/src/design-system/inputs/TextAreaInputGroup.tsx @@ -31,8 +31,7 @@ export default function TextAreaInputGroup({ <span className={`text-sm font-bold text-slate-900 ${ error ? '!text-red-700' : '' - }`} - > + }`}> {label} </span> </label> @@ -42,7 +41,7 @@ export default function TextAreaInputGroup({ <textarea name={name} placeholder={placeholder} - className={`mt-3 max-w-[30rem] rounded-md border-solid border-grey-200 bg-grey-100 !p-4 text-sm transition-colors focus:border-primary focus:ring-2 focus:ring-primary ${ + className={`focus:border-primary-500 focus:ring-primary-500 mt-3 max-w-[30rem] rounded-md border-solid border-grey-200 bg-grey-100 !p-4 text-sm transition-colors focus:ring-2 ${ error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : '' }`} onChange={onChange} diff --git a/src/design-system/inputs/TextInputGroup.tsx b/src/design-system/inputs/TextInputGroup.tsx index 1a1234f0c..30d9f6ec2 100644 --- a/src/design-system/inputs/TextInputGroup.tsx +++ b/src/design-system/inputs/TextInputGroup.tsx @@ -29,18 +29,15 @@ export default function TextInputGroup({ ...props }: HTMLAttributes<HTMLInputElement> & Props) { return ( - <div className="flex flex-col" aria-live="polite"> - {label && ( - <label htmlFor={name}> - <span - className={`text-sm font-bold text-slate-900 ${ - error ? '!text-red-700' : '' - }`}> - {label} - </span> - </label> - )} - + <div className={`flex flex-col ${className}`} aria-live="polite"> + <label htmlFor={name}> + <span + className={`text-sm font-bold text-slate-900 ${ + error ? '!text-red-700' : '' + }`}> + {label} + </span> + </label> {helperText && ( <span className="mt-1 text-xs text-slate-500">{helperText}</span> )} @@ -57,7 +54,7 @@ export default function TextInputGroup({ className={twMerge( `border-grey-300 ${ helperText || label ? ' mt-3' : '' - } max-w-[30rem] rounded-md border border-solid bg-grey-100 p-4 text-sm transition-colors focus:border-primary focus:ring-2 focus:ring-primary `, + } focus:border-primary-500 focus:ring-primary-500 max-w-[30rem] rounded-md border border-solid bg-grey-100 p-4 text-sm transition-colors focus:ring-2`, `${className} ${ error ? '!border-red-200 !bg-red-50 ring-2 !ring-red-700' : '' }` diff --git a/src/design-system/layout/Badge.tsx b/src/design-system/layout/Badge.tsx index 9f05e778c..6e4d52dcd 100644 --- a/src/design-system/layout/Badge.tsx +++ b/src/design-system/layout/Badge.tsx @@ -7,7 +7,7 @@ type Props = { } const colorClassNames = { - default: 'text-primary bg-primaryLight border-primaryBorder ', + default: 'text-primary-500 bg-primary-200 border-primary-700 ', green: 'text-green-800 bg-green-100 border-green-200 ', red: 'text-red-800 bg-red-100 border-red-200 ', } diff --git a/src/design-system/layout/BurgerMenu.tsx b/src/design-system/layout/BurgerMenu.tsx new file mode 100644 index 000000000..351d786ab --- /dev/null +++ b/src/design-system/layout/BurgerMenu.tsx @@ -0,0 +1,98 @@ +'use client' + +import { useClientTranslation } from '@/hooks/useClientTranslation' +import { KeyboardEvent, ReactNode, useEffect, useState } from 'react' +import { twMerge } from 'tailwind-merge' +import Button from '../inputs/Button' + +export default function BurgerMenu({ + children, +}: { + children: (args: { closeMenu: () => void; onFocus: () => void }) => ReactNode +}) { + const [isOpen, setIsOpen] = useState(false) + + const { t } = useClientTranslation() + + const genericHamburgerLine = `h-[2px] w-6 my-1 bg-default transition ease transform duration-300` + + const handleClickElsewhere = (event: MouseEvent) => { + const burger = document.getElementById('burger-menu') + + if (!burger || burger.contains(event.target as Node)) { + return + } + + setIsOpen(false) + } + + useEffect(() => { + if (isOpen) { + window.addEventListener('click', handleClickElsewhere) + } + + if (!isOpen) { + window.removeEventListener('click', handleClickElsewhere) + } + }, [isOpen]) + + const handleClickMask = ( + event: MouseEvent | KeyboardEvent<HTMLDivElement> + ) => { + event.stopPropagation() + setIsOpen(false) + } + + function handleToggleMenu() { + setIsOpen(!isOpen) + } + + return ( + <div id="burger-menu"> + <Button + color="text" + onClick={handleToggleMenu} + className="absolute right-4 top-4 z-[52] flex h-[44px] w-[44px] flex-col items-center justify-center p-0"> + <div + className={`${genericHamburgerLine} ${ + isOpen ? 'translate-y-2 rotate-45 ' : '' + }`} + /> + <div + className={`${genericHamburgerLine} ${isOpen ? 'opacity-0' : ''}`} + /> + <div + className={`${genericHamburgerLine} ${ + isOpen ? '-translate-y-3 -rotate-45 ' : '' + }`} + /> + </Button> + + <div className="fixed left-0 top-0 z-[51]"> + <> + {isOpen && ( + <div + className="fixed left-0 top-0 h-screen w-screen" + tabIndex={0} + onClick={handleClickMask as any} + onKeyDown={handleClickMask} + role="button" + aria-label={t('Fermer le menu')} + /> + )} + + <div + className={twMerge( + 'fixed right-0 top-0 z-[51] h-screen w-[90vw] max-w-[20rem] translate-x-full bg-grey-100 p-4 pt-16 opacity-0 shadow-md transition-all duration-300 ease-in-out', + isOpen ? 'opacity-1 translate-x-0' : '' + )}> + {children({ + closeMenu: () => setIsOpen(false), + onFocus: () => setIsOpen(true), + })} + </div> + </> + </div> + </div> + ) +} diff --git a/src/design-system/layout/Loader.tsx b/src/design-system/layout/Loader.tsx index c877a4c47..27015cb84 100644 --- a/src/design-system/layout/Loader.tsx +++ b/src/design-system/layout/Loader.tsx @@ -14,7 +14,7 @@ const sizesClassNames = { const colorsClassNames = { light: 'border-white border-b-transparent', - dark: 'border-primaryDark border-b-transparent', + dark: 'border-primary-700 border-b-transparent', } export default function Loader({ diff --git a/src/design-system/layout/Title.tsx b/src/design-system/layout/Title.tsx index ec6b073c7..a2f650ab2 100644 --- a/src/design-system/layout/Title.tsx +++ b/src/design-system/layout/Title.tsx @@ -20,7 +20,7 @@ export default function Title({ const Tag = tag return ( <div className="relative mb-4 sm:pb-5"> - <Tag className={`mb-1 text-primaryDark ${className}`} {...props}> + <Tag className={`mb-1 ${className}`} {...props}> {title ?? children} </Tag> diff --git a/src/design-system/layout/accordion/AccordionItem.tsx b/src/design-system/layout/accordion/AccordionItem.tsx index f925dad46..e5b4308c2 100644 --- a/src/design-system/layout/accordion/AccordionItem.tsx +++ b/src/design-system/layout/accordion/AccordionItem.tsx @@ -18,7 +18,7 @@ export default function AccordionItem({ dottedName, title, content, - isReadOnly, + isReadOnly = false, }: AccordionItemType) { const [isOpen, setIsOpen] = useState(false) @@ -34,7 +34,7 @@ export default function AccordionItem({ aria-disabled={isReadOnly}> <div className="flex flex-1 items-center gap-4">{title}</div> - <div className="flex items-center gap-4 text-primaryDark"> + <div className="flex items-center gap-4 text-primary-700"> <span> <strong> {formatValue(numericValue / 1000, { precision: 1 })} diff --git a/src/design-system/utils/Emoji.tsx b/src/design-system/utils/Emoji.tsx index 8bc54cd0b..27c8e3ab0 100644 --- a/src/design-system/utils/Emoji.tsx +++ b/src/design-system/utils/Emoji.tsx @@ -13,7 +13,7 @@ export default function Emoji({ <span aria-hidden alt="" - className={twMerge('inline', className)} + className={twMerge('inline-block', className)} {...props}> {emoji(children, { baseUrl: 'https://twemoji.maxcdn.com/2/svg', diff --git a/src/design-system/utils/Markdown.tsx b/src/design-system/utils/Markdown.tsx index b6911dedd..5728e0ff6 100644 --- a/src/design-system/utils/Markdown.tsx +++ b/src/design-system/utils/Markdown.tsx @@ -16,18 +16,19 @@ export default function Markdown({ ...otherProps }: MarkdownProps) { return ( - <MarkdownToJsx - {...otherProps} - options={{ - ...otherProps.options, - forceBlock: true, - overrides: { - a: Link, - ...components, - }, - }} - > - {children} - </MarkdownToJsx> + <div className="markdown"> + <MarkdownToJsx + {...otherProps} + options={{ + ...otherProps.options, + forceBlock: true, + overrides: { + a: Link, + ...components, + }, + }}> + {children} + </MarkdownToJsx> + </div> ) } diff --git a/src/design-system/utils/ProgressCircle.tsx b/src/design-system/utils/ProgressCircle.tsx index 1dc12e27b..9f1421e7f 100644 --- a/src/design-system/utils/ProgressCircle.tsx +++ b/src/design-system/utils/ProgressCircle.tsx @@ -11,12 +11,11 @@ const ProgressCircle = ({ role="progressbar" aria-valuenow={Math.round(progress * 100)} viewBox="0 0 50 50" - className={`w-8 ${className}`} - > + className={`w-8 ${className}`}> <motion.path fill="none" strokeWidth="5" - className="fill-none stroke-primary" + className="stroke-primary-500 fill-none" strokeDasharray="0 1" d="M 0, 20 a 20, 20 0 1,0 40,0 a 20, 20 0 1,0 -40,0" style={{ @@ -28,7 +27,7 @@ const ProgressCircle = ({ }} /> <motion.path - className={white ? 'fill-white' : 'fill-primary'} + className={white ? 'fill-white' : 'fill-primary-500'} d="m 18.534541,15.018064 c -1.58737,-0.861757 -3.518988,0.286942 -3.519769,2.093145 v 21.013545 c 1.92e-4,1.748524 1.82088,2.901392 3.401567,2.153887 l 19.119987,-9.943674 c 1.756746,-0.830534 1.834232,-3.301494 0.132976,-4.240468 -4.17354,-2.305026 -12.241434,-7.330221 -19.134761,-11.076435 z" strokeDasharray="0 1" transform="translate(-0 -3)" @@ -37,7 +36,7 @@ const ProgressCircle = ({ <motion.path fill="none" strokeWidth="5" - className="stroke-primary" + className="stroke-primary-500" d="M14,26 L 22,33 L 35,16" initial={false} strokeDasharray="0 1" diff --git a/src/helpers/data/fetchModel.ts b/src/helpers/data/fetchModel.ts new file mode 100644 index 000000000..28b0d8dcd --- /dev/null +++ b/src/helpers/data/fetchModel.ts @@ -0,0 +1,50 @@ +import { NGC_MODEL_API_URL, NGC_MODEL_API_URL_FALLBACK } from '@/constants/urls' +import { NGCRules } from '@/publicodes-state/types' + +import axios from 'axios' + +type Props = { + dataServer: string + regionCode: string + locale: string + isOptim?: boolean +} + +export async function fetchModel({ + dataServer, + regionCode, + locale, + isOptim = true, +}: Props) { + const URLToFetch = getURLToFetch(dataServer, locale, regionCode, isOptim) + + return axios + .get(URLToFetch) + .then((res) => res.data as NGCRules) + .catch((err) => { + console.warn(`Failed to fetch rules from: ${URLToFetch}`, err.message) + const fallbackURL = getURLToFetch( + NGC_MODEL_API_URL_FALLBACK, + locale, + regionCode, + isOptim + ) + console.warn(`Falling back to: ${fallbackURL}`) + return axios.get(fallbackURL).then(({ data }) => data as NGCRules) + }) +} + +function getURLToFetch( + dataServer: string, + locale: string, + regionCode: string, + isOptim: boolean +): string { + return dataServer.startsWith(NGC_MODEL_API_URL) + ? `${dataServer}/${locale}/${regionCode}/${ + isOptim ? 'optim-rules' : 'rules' + }` + : `${dataServer}/co2-model.${regionCode}-lang.${locale}${ + isOptim ? '-opti' : '' + }.json` +} diff --git a/src/helpers/fetchPersonas.ts b/src/helpers/fetchPersonas.ts new file mode 100644 index 000000000..c1b32a3b9 --- /dev/null +++ b/src/helpers/fetchPersonas.ts @@ -0,0 +1,20 @@ +import { DEFAULT_MODEL_VERSION } from '@/constants/modelAPI' +import { NGC_MODEL_API_URL } from '@/constants/urls' +import { Persona } from '@/publicodes-state/types' +import { currentLocale } from 'next-i18n-router' + +export default async function fetchPersonas(): Promise< + Record<string, Persona> +> { + const locale = currentLocale() + // FIXME(@florianpanchout): endpoint should not be static (and should point + // to local if available) + const serverURL = NGC_MODEL_API_URL + const isOldAPI = !serverURL.startsWith(NGC_MODEL_API_URL) + + return await fetch( + isOldAPI + ? `${serverURL}/personas-${locale}.json` + : `${NGC_MODEL_API_URL}/${DEFAULT_MODEL_VERSION}/${locale}/personas` + ).then((res) => res.json()) +} diff --git a/src/helpers/foldEveryQuestionsUntil.ts b/src/helpers/foldEveryQuestionsUntil.ts new file mode 100644 index 000000000..45e929f04 --- /dev/null +++ b/src/helpers/foldEveryQuestionsUntil.ts @@ -0,0 +1,17 @@ +type Props = { + question: string + relevantQuestions: string[] + addFoldedStep: (question: string) => void +} + +function foldEveryQuestionsUntil({ + question, + relevantQuestions, + addFoldedStep, +}: Props) { + const indexOfQuestion = relevantQuestions.indexOf(question) + const questionsToAnswer = relevantQuestions.slice(0, indexOfQuestion) + questionsToAnswer.map((question) => addFoldedStep(question)) +} + +export default foldEveryQuestionsUntil diff --git a/src/helpers/getCategoryColorClass.ts b/src/helpers/getCategoryColorClass.ts new file mode 100644 index 000000000..6a89db38b --- /dev/null +++ b/src/helpers/getCategoryColorClass.ts @@ -0,0 +1,64 @@ +export function getTextColor(category?: string | null) { + switch (category) { + case 'transport': + return `text-categories-transport` + case 'alimentation': + return `text-categories-alimentation` + case 'logement': + return `text-categories-logement` + case 'divers': + return `text-categories-divers` + case 'services sociétaux': + return `text-categories-servicessocietaux` + default: + return 'text-primary-500' + } +} +export function getBackgroundColor(category?: string | null) { + switch (category) { + case 'transport': + return `bg-categories-transport` + case 'alimentation': + return `bg-categories-alimentation` + case 'logement': + return `bg-categories-logement` + case 'divers': + return `bg-categories-divers` + case 'services sociétaux': + return `bg-categories-servicessocietaux` + default: + return 'bg-primary-500' + } +} +export function getBorderColor(category?: string | null) { + switch (category) { + case 'transport': + return `border-categories-transport` + case 'alimentation': + return `border-categories-alimentation` + case 'logement': + return `border-categories-logement` + case 'divers': + return `border-categories-divers` + case 'services sociétaux': + return `border-categories-servicessocietaux` + default: + return 'border-primary-500' + } +} +export function getFillColor(category?: string | null) { + switch (category) { + case 'transport': + return `fill-categories-transport` + case 'alimentation': + return `fill-categories-alimentation` + case 'logement': + return `fill-categories-logement` + case 'divers': + return `fill-categories-divers` + case 'services sociétaux': + return `fill-categories-servicessocietaux` + default: + return 'fill-primary-500' + } +} diff --git a/src/helpers/getGeolocation.ts b/src/helpers/getGeolocation.ts index 8364346cf..7a04243ac 100644 --- a/src/helpers/getGeolocation.ts +++ b/src/helpers/getGeolocation.ts @@ -1,8 +1,11 @@ export default async function useGeolocation() { const region = await fetch( - `${process.env.NODE_ENV === 'development' ? 'http' : 'https'}://${ - process.env.VERCEL_URL || 'localhost:3000' - }/api/geolocation` + `${ + process.env.VERCEL_ENV === 'preview' || + process.env.VERCEL_ENV === 'production' + ? 'https' + : 'http' + }://${process.env.VERCEL_URL || 'localhost:3000'}/api/geolocation` ) .then((res) => res.json()) .then( diff --git a/src/helpers/getSupportedRegions.ts b/src/helpers/getSupportedRegions.ts index dfd5fabdf..dae2662b5 100644 --- a/src/helpers/getSupportedRegions.ts +++ b/src/helpers/getSupportedRegions.ts @@ -1,8 +1,13 @@ //TODO: should check if PR is in query params but it is kind of difficult to do in a server component +import { DEFAULT_MODEL_VERSION } from '@/constants/modelAPI' import { NGC_MODEL_API_URL } from '@/constants/urls' +import { SuppportedRegions } from '@/types/international' -export const getSupportedRegions = () => - fetch(`${NGC_MODEL_API_URL}/supportedRegions.json`).then((response) => - response.json() - ) +export const getSupportedRegions = async (): Promise<SuppportedRegions> => { + return fetch(`${NGC_MODEL_API_URL}/${DEFAULT_MODEL_VERSION}`) + .then((response) => { + return response.json() + }) + .then((response) => response.regions) +} diff --git a/src/helpers/importLocalRules.ts b/src/helpers/importLocalRules.ts new file mode 100644 index 000000000..e98e46d28 --- /dev/null +++ b/src/helpers/importLocalRules.ts @@ -0,0 +1,23 @@ +import { NGCRules } from '@/publicodes-state/types' + +async function importLocalRules({ + regionCode, + locale, + isOptim, +}: { + regionCode?: string + locale: string + isOptim: boolean +}) { + try { + return (await import( + `../../../nosgestesclimat/public/co2-model.${regionCode}-lang.${locale}${ + isOptim ? '-opti' : '' + }.json` + )) as NGCRules + } catch (e) { + console.error(e) + } +} + +export default importLocalRules diff --git a/src/helpers/localisation/getLocalisedURL.ts b/src/helpers/localisation/getLocalisedURL.ts index 4d65f459c..331c57c5a 100644 --- a/src/helpers/localisation/getLocalisedURL.ts +++ b/src/helpers/localisation/getLocalisedURL.ts @@ -9,7 +9,7 @@ export function getLocalisedURL({ }) { // French is the default language, so it isn't included in the URL const activeLanguageOtherThanFrench = languages.find((language) => - href.includes(language) + href.startsWith(language) ) if (activeLanguageOtherThanFrench) { diff --git a/src/helpers/metadata/getMetadataObject.ts b/src/helpers/metadata/getMetadataObject.ts index b94bfe14e..2accb5b56 100644 --- a/src/helpers/metadata/getMetadataObject.ts +++ b/src/helpers/metadata/getMetadataObject.ts @@ -8,6 +8,19 @@ type Props = { params?: Record<string, string> searchParams?: Record<string, string> noImage?: boolean + robots?: { + index: boolean + follow: boolean + nocache: boolean + googleBot: { + index: boolean + follow: boolean + noimageindex: boolean + 'max-video-preview': number + 'max-image-preview': string + 'max-snippet': number + } + } } const BASE_URL = @@ -52,6 +65,7 @@ export function getMetadataObject({ params, searchParams, noImage = false, + ...props }: Props) { const locale = currentLocale() const url = buildURL({ @@ -76,5 +90,6 @@ export function getMetadataObject({ ? generateOGImageURL(url) : 'https://nosgestesclimat.vercel.app/images/misc/dessin-nosgestesclimat_thumbnail.png', }, + ...props, } } diff --git a/src/helpers/publicodes/getRuleTitle.ts b/src/helpers/publicodes/getRuleTitle.ts index 542bfb9e0..1df79c37f 100644 --- a/src/helpers/publicodes/getRuleTitle.ts +++ b/src/helpers/publicodes/getRuleTitle.ts @@ -2,6 +2,11 @@ import { NGCRule } from '@/publicodes-state/types' export const getRuleTitle = ( rule: NGCRule & { dottedName: string; titre: string } -) => - rule.titre ?? - rule.dottedName.split(' . ')[rule.dottedName.split(' . ').length - 1] +) => { + if (!rule) return '' + + return ( + rule?.titre ?? + rule?.dottedName?.split(' . ')[rule?.dottedName.split(' . ').length - 1] + ) +} diff --git a/src/hooks/useDataServer.ts b/src/hooks/useDataServer.ts index 4ed0ef1bc..dc3c800d6 100644 --- a/src/hooks/useDataServer.ts +++ b/src/hooks/useDataServer.ts @@ -1,11 +1,16 @@ -import { NGC_MODEL_API_URL } from '@/constants/urls' +import { NGC_MODEL_API_URL, getModelPRUrl } from '@/constants/urls' +import useModelVersion from '@/hooks/useModelVersion' import { usePRNumber } from './usePRNumber' export const useDataServer = () => { const { PRNumber } = usePRNumber() + const modelVersion = useModelVersion() + if (PRNumber) { - return `https://deploy-preview-${PRNumber}--ecolab-data.netlify.app` + const previewURL = getModelPRUrl(PRNumber) + console.debug(`[useDataServer] using preview URL: ${previewURL}`) + return previewURL } - return process.env.NEXT_PUBLIC_LOCAL_DATA_SERVER ?? NGC_MODEL_API_URL + return `${NGC_MODEL_API_URL}/${modelVersion}` } diff --git a/src/hooks/useModelAPI.ts b/src/hooks/useModelAPI.ts new file mode 100644 index 000000000..deb2ea40d --- /dev/null +++ b/src/hooks/useModelAPI.ts @@ -0,0 +1,7 @@ +import { NGC_MODEL_API_URL } from '@/constants/urls' +import useModelVersion from '@/hooks/useModelVersion' + +export default function useModelAPI() { + const modelVersion = useModelVersion() + return `${NGC_MODEL_API_URL}/${modelVersion}` +} diff --git a/src/hooks/useModelVersion.ts b/src/hooks/useModelVersion.ts new file mode 100644 index 000000000..028b07d4f --- /dev/null +++ b/src/hooks/useModelVersion.ts @@ -0,0 +1,31 @@ +import { + DEFAULT_MODEL_VERSION, + MODEL_VERSION_PARAM, +} from '@/constants/modelAPI' +import { useIsClient } from '@/hooks/useIsClient' +import { useSearchParams } from 'next/navigation' + +export function clearModelVersionFromStorage() { + sessionStorage.removeItem(MODEL_VERSION_PARAM) +} + +function useModelVersion(): string { + const isClient = useIsClient() + const searchParams = useSearchParams() + + if (!isClient) { + return DEFAULT_MODEL_VERSION + } + + const modelVersionFromURL = searchParams.get(MODEL_VERSION_PARAM) + const savedModelVersion = sessionStorage.getItem(MODEL_VERSION_PARAM) + + if (modelVersionFromURL) { + sessionStorage.setItem(MODEL_VERSION_PARAM, modelVersionFromURL) + return modelVersionFromURL + } + + return savedModelVersion ?? DEFAULT_MODEL_VERSION +} + +export default useModelVersion diff --git a/src/hooks/useNumberSubscriber.ts b/src/hooks/useNumberSubscriber.ts index ff456a665..7fd216149 100644 --- a/src/hooks/useNumberSubscriber.ts +++ b/src/hooks/useNumberSubscriber.ts @@ -1,17 +1,15 @@ -import { useQuery } from '@tanstack/react-query' +import { keepPreviousData, useQuery } from '@tanstack/react-query' import axios from 'axios' export function useNumberSubscribers(): { data: number | undefined } { - return useQuery( - ['number subscribers'], - () => + return useQuery({ + queryKey: ['number subscribers'], + queryFn: () => axios .get('/api/get-newsletter-subscribers-number') .then((res) => res.data as string), - { - keepPreviousData: true, - } - ) + placeholderData: keepPreviousData, + }) } diff --git a/src/hooks/useRules.ts b/src/hooks/useRules.ts index 8f1392c74..63a58728e 100644 --- a/src/hooks/useRules.ts +++ b/src/hooks/useRules.ts @@ -1,20 +1,28 @@ +import { fetchModel } from '@/helpers/data/fetchModel' +import importLocalRules from '@/helpers/importLocalRules' import { useUser } from '@/publicodes-state' -import { useQuery } from '@tanstack/react-query' -import axios from 'axios' +import { NGCRules } from '@/publicodes-state/types' +import { + UseQueryResult, + keepPreviousData, + useQuery, +} from '@tanstack/react-query' import { useDataServer } from './useDataServer' import { useLocale } from './useLocale' type Props = { - lang?: string - region?: string + lang: string + region: string isOptim?: boolean } -export function useRules({ lang, region, isOptim = true }: Props) { +export function useRules({ + lang, + region, + isOptim = true, +}: Props): UseQueryResult<NGCRules, Error> { const dataServer = useDataServer() - const locale = useLocale() - const { user } = useUser() const regionCode = @@ -22,22 +30,23 @@ export function useRules({ lang, region, isOptim = true }: Props) { ? user?.region?.code : region - return useQuery( - ['rules', dataServer, lang, region, isOptim], - () => - axios - .get( - `${dataServer}/co2-model.${regionCode}-lang.${locale}${ - isOptim ? '-opti' : '' - }.json` - ) - .then((res) => res.data as unknown), - { - keepPreviousData: true, - // When we work locally on the model we want the rules to be updated as much as possible (on window focus and every 3 seconds) - refetchOnWindowFocus: process.env.NEXT_PUBLIC_LOCAL_DATA_SERVER - ? true - : false, - } - ) + return useQuery({ + queryKey: ['rules', dataServer, lang, region, isOptim], + queryFn: () => { + console.log( + `⚙️ requesting ${ + isOptim ? 'optimized' : '' + } rules for ${regionCode} ${locale}` + ) + return process.env.NEXT_PUBLIC_LOCAL_DATA === 'nosgestesclimat' + ? importLocalRules({ regionCode, locale, isOptim }) + : fetchModel({ + dataServer: dataServer || '', + regionCode: regionCode || 'FR', + locale, + isOptim, + }) + }, + placeholderData: keepPreviousData, + }) } diff --git a/src/hooks/useSubscribeUser.ts b/src/hooks/useSubscribeUser.ts index a3d0aeb9a..f9fbe922c 100644 --- a/src/hooks/useSubscribeUser.ts +++ b/src/hooks/useSubscribeUser.ts @@ -11,8 +11,9 @@ type Props = { optIn: boolean } export function useSubscribeUser() { - return useMutation( - async ({ simulation, email, optIn }: Props): Promise<any> => { + return useMutation({ + mutationKey: ['subscribe user'], + mutationFn: async ({ simulation, email, optIn }: Props): Promise<any> => { const idSimulationSaved: string = await saveSimulationInDB( simulation as unknown as Simulation ) @@ -31,8 +32,8 @@ export function useSubscribeUser() { // URL already contains the query param details shareURL: location.toString() + '&mtm_campaign=partage-email', }) - } - ) + }, + }) } const saveSimulationInDB = async (data: Simulation) => { diff --git a/src/hooks/useTrackSplitTesting.ts b/src/hooks/useTrackSplitTesting.ts new file mode 100644 index 000000000..0f228ade0 --- /dev/null +++ b/src/hooks/useTrackSplitTesting.ts @@ -0,0 +1,23 @@ +import { splitTestingCookieName } from '@/constants/split-testing' +import { getCookie } from '@/utils/getCookies' +import { useEffect } from 'react' + +export function useTrackSplitTesting() { + useEffect(() => { + if (!process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH) return + + const splitTestingPercentage = getCookie(splitTestingCookieName) + + if (splitTestingPercentage !== undefined) { + window._paq.push([ + 'trackEvent', + 'abtesting', + process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH, + Number(splitTestingPercentage) < + Number(process.env.NEXT_PUBLIC_SPLIT_TESTING_PERCENTAGE ?? 0.5) + ? process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH + : 'original', + ]) + } + }, []) +} diff --git a/src/locales/blog/fr/journee-mondial-environnement.mdx b/src/locales/blog/fr/journee-mondial-environnement.mdx index 9b273ca48..c68202d56 100644 --- a/src/locales/blog/fr/journee-mondial-environnement.mdx +++ b/src/locales/blog/fr/journee-mondial-environnement.mdx @@ -5,7 +5,7 @@ description: 'Entre les actuelles 9 tonnes de l’empreinte moyenne d’un citoy image: '/images/blog/WED.jpg' --- - # À l'occasion de la Journée mondiale de l’environnement, explosons le million ! +# À l'occasion de la Journée mondiale de l’environnement, explosons le million ! ## Faites comme Emmanuelle en devenant ambassadeur ou ambassadrice diff --git a/src/locales/blog/fr/maladaptation.mdx b/src/locales/blog/fr/maladaptation.mdx index fb3c08bb3..8bd8f8e05 100644 --- a/src/locales/blog/fr/maladaptation.mdx +++ b/src/locales/blog/fr/maladaptation.mdx @@ -5,9 +5,10 @@ description: "L'été est un moment particulièrement propice à la mise en plac image: '/images/blog/william-bossen-fonte-glaces.jpg' --- - # Avez-vous déjà entendu parler de "maladaptation" ? +# Avez-vous déjà entendu parler de "maladaptation" ? + +![La fonte des glaces, par William Bossen](/images/blog/william-bossen-fonte-glaces.jpg) -![La fonte des glaces, par William Bossen](/images/william-bossen-fonte-glaces.jpg) Connaissez-vous le concept de “**maladaptation**” ? Voici la définition qu’en ont donnée un groupe de 16 experts qui se sont réunis autour du sujet en novembre 2012 : > “_La maladaptation désigne un processus d’adaptation qui résulte directement en un accroissement de la vulnérabilité à la variabilité et au changement climatiques et/ou en une altération des capacités et des opportunités actuelles et futures d’adaptation.”_ @@ -20,7 +21,7 @@ Face à ces bouleversements, [beaucoup sont démunis](https://www.novethic.fr/ac ## Pour rafraîchir son logement -![Climatiseurs contre un mur, une photo d'Alexandre Lecoq](/images/alexandre-lecocq-climatiseurs.jpg) +![Climatiseurs contre un mur, une photo d'Alexandre Lecoq](/images/blog/alexandre-lecocq-climatiseurs.jpg) ### Attention au climatiseur @@ -54,7 +55,8 @@ Et puis il y a tous les **bons gestes** à faire pour préserver le frais à l ## Pour se rafraîchir soi-même -![Un chien court dans l'eau, heureux, par Matt Benson](/images/matt-benson-chien-baignade.jpg) +![Un chien court dans l'eau, heureux, par Matt Benson](/images/blog/matt-benson-chien-baignade.jpg) + Ah, que l’été est plus supportable quand nous pouvons faire trempette régulièrement ! ### La solution maladaptée : faire construire une piscine privée diff --git a/src/locales/nouveautes/en/theodule.mdx b/src/locales/nouveautes/en/theodule.mdx new file mode 100644 index 000000000..045ccee90 --- /dev/null +++ b/src/locales/nouveautes/en/theodule.mdx @@ -0,0 +1,144 @@ +--- +title: Theodule +date: 2023-11-23T16:50:31Z +image: https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Materhorno_de_Gornergrato.jpg/800px-Materhorno_de_Gornergrato.jpg +--- + +#Theodule Glacier + +What's new in November 2023 + +![Glacier du Théodule](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/b9d6ccef-2a61-403e-a424-798d80c89843) + +> 🧊 The Théodule glacier, located on the border between Switzerland and Italy, is at the heart of a scandal in the confederation: in anticipation of the Ski World Cup in the Swiss town of Zermatt, one of the new slopes created partially encroaches on an area outside the ski area, and therefore on part of the Théodule glacier, which would therefore have been damaged (with a shovel). +> +> If you are interested in this subject, we recommend these 2 resources: +> - <a href="https://www.futura-sciences.com/sciences/actualites/satellite-scandaleux-pillage-glacier-pelleteuses-vu-espace-108546/">The FuturaSciences article</a> +> - <a href="https://information.tv5monde.com/environnement/video/suisse-le-glacier-du-theodule-eventre-par-les-pelleteuses-2672970" target="_blank" rel="noopener noreferrer">A TV5Monde mini-report on the subject</a> + + + +**The latest changes in brief :** + +- ⚡ A faster, more flexible site +- 🏁 A new test completion page +- 🗣️ Pages dedicated to our partners +- 🇨🇭 Nos Gestes Climat arrives in Switzerland! +- 🪡 An increasingly accurate calculation model +- 🤖 Some technical improvements + + + + +## ⚡ A faster, more flexible site + +It's a small step for you, but a big step for the team: the Nos Gestes Climat website has been rewritten using a new <a href="https://fr.wikipedia.org/wiki/Framework_Web">framework*</a> <a href="https://nextjs.org/">Next</a>), which will allow us to: + +- limit loading time for you (you're happy!) +- develop it much more easily (the developers are happy too!) + + + +## 🏁 A new end page for the test + +We are now proposing a new, simplified end page, in order to : + +- *value the overall result*, without displaying the 2T target corresponding to the Paris agreements, which gave most of you the impression that it was unachievable. This objective remains, but we would like to present it in a different light, to re-explain the importance of implementing these changes from a societal and global point of view in order to achieve this objective. + +new end page](https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/9339dfe1-41b7-4c4e-ae18-5ee644c7908a) + + + +- be able to go into the sub-categories of each main emission item, with the aim of providing you with *the best possible orders of magnitude*: what weighs most heavily on my transport today? etc. + +sub-categories in the end page](https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/405402e7-f5b5-4040-8c66-6e730781a1ba) + + + +- support you for the rest*: you can still receive your results by email, but we also want to invite you to create a group to compare your results with your friends, convinced that it's through the group that we'll get everyone on board for this historic cause. + +subscribe to our newsletter and challenge your friends](https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/79595c60-5a44-492e-878d-d30445135058) + + + +- always *give you ideas for impactful actions* to put in place to reduce your footprint as effectively as possible. + +actions page](https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/4a6b35fc-ddac-45b3-9085-bed0cab3d112) + + +This page will continue to evolve, so don't hesitate to give us your opinion on <a href="https://www.notion.so/Th-odule-891ecde9619d445d9c7462751dfde7c1?pvs=21">our contact page</a>. Your feedback is invaluable in helping NGC to evolve even further! + + + + +## 🗣️ Pages dedicated to our partners + + +### 📢 Update of the <a href="https://nosgestesclimat.fr/diffuser">Distribute</a>page + +This page provides all the information you need to use Nos Gestes Climat as a company, school or organisation: + +- integrate Nos Gestes Climat into your own website +- mobilise a group or organisation and compare the results +- run conferences or workshops +- talk about Nos Gestes Climat in the media + + + + +### 👯 Create an <a href="https://nosgestesclimat.fr/ambassadeurs">ambassador gallery</a>page + +As Nos Gestes Climat is already a reference simulator for many media and personalities, we wanted to make the list of these reusers accessible. + +<img width="480" alt="Capture_decran_2023-11-21_a_17 04 33" src="https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/adec08ab-6ad1-447e-9736-ce441913b6db"> + + + + +## 🇨🇭 Nos Gestes Climat arrives in Switzerland! + +Since 13 November, thanks to an exclusive partnership with the canton of Geneva and <a href="https://2050today.org/">2050 today</a>, the people of Geneva have been able to calculate their carbon footprint on a dedicated website featuring the Nos Gestes Climat simulator. + +This required a great deal of work on the part of the team to : + +- meet the technical requirements for integrating the simulator into an iframe +- support the creation and review of the Geneva carbon model, in order to adapt it from the French model + + + + +<a href="https://geneve.nosgestesclimat.ch/">The site can be accessed via this link.</a> + +<img width="1008" alt="Capture_decran_2023-11-21_a_17 08 54" src="https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/fde7fbdd-f5d2-4d47-a617-313ccd032441"> + + + + +## 🪡 An increasingly accurate calculation model + +Our team in charge of the carbon model, Clément and Julie, are constantly working on the accuracy and updating of the carbon calculation data, thanks in particular to in-depth research work, and feedback from our partner <a href="https://abc-transitionbascarbone.fr/">ABC</a>. + +In recent weeks, they have been working on : + +- updating all the 'default' values: if I click on 'I don't know', which value is taken into account, and what does it represent? +- standardising the units used in the model +- accuracy of data concerning the car: air conditioning, maintenance and repair of the car, use of a single car or several cars, etc +- fixing a bug in the calculation of biogas consumption with the invoice +- various optimisations to ensure the model works properly + + + + + +## 🤖 Technical + +- Review of the translation model (from en-us to en) +- Review of markdown content management +- Correction of a few typos and minor bugs + + + + +💡 As a reminder, all development of the Nos Gestes Climat public service is done transparently on the Github platform, on the <a href="https://github.com/incubateur-ademe/nosgestesclimat-site/">site side</a> and <a href="https://github.com/incubateur-ademe/nosgestesclimat">on the calculation model side</a>. + +See you soon for more news! diff --git a/src/locales/nouveautes/fr/theodule.mdx b/src/locales/nouveautes/fr/theodule.mdx new file mode 100644 index 000000000..d38f7b502 --- /dev/null +++ b/src/locales/nouveautes/fr/theodule.mdx @@ -0,0 +1,144 @@ +--- +title: Théodule +date: 2023-11-23T16:50:31Z +image: https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Materhorno_de_Gornergrato.jpg/800px-Materhorno_de_Gornergrato.jpg +--- + +#Le Glacier du Théodule + +Les nouveautés du mois de novembre 2023 + +![Glacier du Théodule](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/b9d6ccef-2a61-403e-a424-798d80c89843) + +> 🧊 Le glacier du Théodule, situé à la frontière de la Suisse et de l’Italie, est au coeur d’un scandale dans la confédération : en prévision de la coupe du monde de ski dans la ville suisse de Zermatt, l’une des nouvelles pistes créées empiète partiellement sur une zone en dehors du domaine skiable, et donc sur une partie du glacier de Théodule, qui aurait donc été endommagée (à la pelleteuse). +> +> Si le sujet vous intéresse, nous vous recommandons ces 2 ressources : +> - [L'article sur FuturaSciences](https://www.futura-sciences.com/sciences/actualites/satellite-scandaleux-pillage-glacier-pelleteuses-vu-espace-108546/) +> - <a href="https://information.tv5monde.com/environnement/video/suisse-le-glacier-du-theodule-eventre-par-les-pelleteuses-2672970" target="_blank" rel="noopener noreferrer">Un mini-reportage TV5Monde sur le sujet</a> + + + +**Les derniers changements en bref :** + +- ⚡ Un site plus rapide et flexible +- 🏁 Une nouvelle page de fin de test +- 🗣️ Des pages dédiées à nos partenaires +- 🇨🇭 Nos Gestes Climat arrive en Suisse ! +- 🪡 Un modèle de calcul toujours plus précis +- 🤖 Quelques optimisations techniques + + + + +## ⚡ Un site plus rapide et flexible + +C’est un petit pas pour vous, mais un grand pas pour l’équipe : le site Nos Gestes Climat a été réécrit en utilisant un nouveau *[framework](https://fr.wikipedia.org/wiki/Framework_Web)* ([Next](https://nextjs.org/)), qui va nous permettre : + +- de limiter le temps de chargement pour vous (vous êtes heureux·ses !) +- de le faire évoluer beaucoup plus facilement (les développeurs aussi sont heureux !) + + + +## 🏁 Une nouvelle page de fin pour le test + +Nous proposons désormais une nouvelle page de fin simplifiée, afin de : + +- *valoriser le résultat global*, sans afficher l’objectif de 2T correspondant aux accords de Paris qui donnait une impression d’irréalisable à la plupart d’entre vous. Cet objectif demeure mais nous souhaitons le présenter sous un autre jour, pour réexpliquer l’importance de mettre en oeuvre ces changements d’un point de vue sociétal et global pour atteindre cet objectif. + +![Nouvelle page de fin](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/09004245-e05e-40d4-ab0f-cbf6c0a78abf) + + + +- pouvoir entrer dans les sous-catégories de chaque poste d’émission principal, dans l’objectif de vous fournir *les meilleurs ordres de grandeur possible* : qu’est-ce qui pèse le plus dans mes transports aujourd’hui ? etc. + +![Sous catégories dans la page de fin](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/88786e32-e31d-4bbd-ace9-806e184660c1) + + + +- vous *accompagner pour la suite* : vous pouvez toujours recevoir vos résultats par mail, mais nous voulons aussi vous inviter à créer un groupe pour comparer vos résultats avec vos amis, convaincus que c’est par le groupe que nous embarquerons tout le monde dans cette cause historique. + +![Inscription newsletter et challenge tes amis](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/b7b5e21f-7cb9-40c8-97f3-692028409e1a) + + + +- toujours vous *donner des idées d’actions impactantes* à mettre en place pour réduire votre empreinte au plus efficace. + +![Page Actions](https://github.com/incubateur-ademe/nosgestesclimat-site/assets/144152881/12fd267d-ad39-4c60-b665-5fb124213727) + + +Cette page est amenée à évoluer encore et encore, alors n’hésitez pas à nous donner votre avis sur [notre page contact](https://nosgestesclimat.fr/contact), vos retours sont précieux pour faire évoluer NGC au mieux ! + + + + +## 🗣️ Des pages dédiées à nos partenaires + + +### 📢 Mise à jour de la la page [Diffuser](https://nosgestesclimat.fr/diffuser) + +Cette page nous permet de fournir toutes les informations nécessaires pour utiliser Nos Gestes Climat en tant qu’entreprise, école ou organisation : + +- intégrer Nos Gestes Climat dans votre propre site +- mobiliser un groupe ou une organisation et comparer les résultats +- animer des conférences ou des ateliers +- parler de Nos Gestes Climat dans un média + + + + +### 👯 Création d’une page de [galerie des ambassadeurs](https://nosgestesclimat.fr/ambassadeurs) + +Car Nos Gestes Climat est aujourd’hui déjà un simulateur de référence pour de nombreux medias ou personnalités, nous avons souhaité rendre accessible la liste de ces réutilisateur·ices. + +<img width="480" alt="Capture_decran_2023-11-21_a_17 04 33" src="https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/adec08ab-6ad1-447e-9736-ce441913b6db"> + + + + +## 🇨🇭 Nos Gestes Climat arrive en Suisse ! + +Grâce à un partenariat exclusif avec le canton de Genève, et [2050 today](https://2050today.org/), depuis le 13 novembre, les Genevois·e·s peuvent calculer leur empreinte carbone sur un site dédié intégrant le simulateur Nos Gestes Climat. + +Cela a demandé un travail conséquent de l’équipe pour : + +- répondre aux besoins techniques pour l’intégration du simulateur en iframe +- accompagner à la création et la revue du modèle carbone Genevois, afin de l'adapter depuis le modèle Français + + + + +[Le site est accessible via ce lien.](https://geneve.nosgestesclimat.ch/) + +<img width="1008" alt="Capture_decran_2023-11-21_a_17 08 54" src="https://github.com/incubateur-ademe/nosgestesclimat-site-nextjs/assets/144152881/fde7fbdd-f5d2-4d47-a617-313ccd032441"> + + + + +## 🪡 Un modèle de calcul toujours plus précis + +Notre équipe en charge du modèle carbone, Clément et Julie, travaille en permanence à la précision et la mise à jour des données de calcul carbone, notamment grâce à un travail approfondi de recherche, et aux retours de notre partenaire [l’ABC](https://abc-transitionbascarbone.fr/). + +Ces dernières semaines, ils ont travaillé sur : + +- la remise à jour de toutes les valeurs “par défaut” : si je clique sur “je ne sais pas”, quelle valeur est prise en compte, et que représente-t-elle ? +- l’uniformisation des unités utilisées dans le modèle +- la précision de données concernant la voiture : climatisation, entretien et réparation de la voiture, usage d’une voiture unique ou de plusieurs voitures… +- la réparation d’un bug sur le calcul de consommation de biogaz avec la facture +- des optimisations variées pour le bon fonctionnement du modèle + + + + + +## 🤖 Technique + +- Revue du modèle de traduction (de en-us à en) +- Revue gestion des contenus markdown +- Correction de quelques coquilles et petits bugs + + + + +💡 Pour rappel, tous les développements du service public Nos Gestes Climat sont faits en transparence sur la plateforme Github, [côté site](https://github.com/incubateur-ademe/nosgestesclimat-site/) et [côté modèle de calcul](https://github.com/incubateur-ademe/nosgestesclimat). + +À bientôt pour d'autres nouveautés ! diff --git a/src/locales/pages/en/about.mdx b/src/locales/pages/en/about.mdx index ac0ec5f61..ea957be49 100644 --- a/src/locales/pages/en/about.mdx +++ b/src/locales/pages/en/about.mdx @@ -52,8 +52,7 @@ We tell you everything on our <a href="/partenaires">partnerships</a> page. ## Contact us -You can contact us via <a href="/contact">our contact form</a> or directly at contact@nosgestesclimat.fr. - +You can contact us via <a href="/contact">our contact form</a>. ## Budget The team budget is available on our <a href="/budget">"Budget" page</a>. @@ -80,13 +79,12 @@ The publication director is Mr. Boris RAVIGNON, Acting Chairman and CEO of ADEME ### Platform hosting This platform is hosted by : -Netlify -Inc 2325 3rd Street, Suite 296 -San Francisco, California 94107 +Vercel Inc. +440 N Barranca Ave #4133 +Covina, CA 91723 United States -The site is hosted on Netlify. It's a static site served via a CDN: despite being domiciled in California, the site will be served to you [from -europe](https://answers.netlify.com/t/is-there-a-list-of-where-netlifys-cdn-pops-are-located/855/2). +The site is hosted on Vercel. It's a static site served via a CDN. ### Accessibility @@ -107,7 +105,6 @@ content or functionality, please let us know: - <a href="/contact">via our contact form</a> - via rgaa@ademe.fr -- via contact@nosgestesclimat.fr If you do not receive a prompt response from us, you have the right to send your grievances to the Défenseur des droits. diff --git a/src/locales/pages/en/privacy.mdx b/src/locales/pages/en/privacy.mdx index d5e1f2f27..2b26dda2d 100644 --- a/src/locales/pages/en/privacy.mdx +++ b/src/locales/pages/en/privacy.mdx @@ -179,7 +179,7 @@ data protection. ### Web site hosting -The website is hosted by Netlify, as indicated in the legal notice on +The website is hosted by Vercel, as indicated in the legal notice on the [about](/à-propos) page. The survey data storage server is hosted by diff --git a/src/locales/pages/fr/about.mdx b/src/locales/pages/fr/about.mdx index 76fd8d5c9..b4d72610c 100644 --- a/src/locales/pages/fr/about.mdx +++ b/src/locales/pages/fr/about.mdx @@ -50,7 +50,7 @@ On vous dit tout sur notre page [partenaires](/partenaires). ## Nous contacter -Vous pouvez nous contacter via [via notre formulaire de contact](/contact) ou directement à l'adresse contact@nosgestesclimat.fr. +Vous pouvez nous contacter via [via notre formulaire de contact](/contact). ## Budget @@ -78,13 +78,12 @@ Le directeur de la publication est Monsieur Boris RAVIGNON, Président-directeur ### Hébergement de la Plateforme Cette plateforme est hébergée par : -Netlify -Inc 2325 3rd Street, Suite 296 -San Francisco, California 94107 +Vercel Inc. +440 N Barranca Ave #4133 +Covina, CA 91723 États-Unis -Le site est hébergé sur Netlify. C'est un site statique servi via un CDN : malgré la domiciliation en Californie, le site vous sera servi [depuis -l'Europe](https://answers.netlify.com/t/is-there-a-list-of-where-netlifys-cdn-pops-are-located/855/2). +Le site est hébergé sur Vercel. C'est un site statique servi via un CDN. ### Accessibilité @@ -105,7 +104,6 @@ un contenu ou une fonctionnalité du site, merci de nous en faire part : - [via notre formulaire de contact](/contact) - via rgaa@ademe.fr -- via contact@nosgestesclimat.fr Si vous n’obtenez pas de réponse rapide de notre part, vous êtes en droit de faire parvenir vos doléances ou une demande de saisine au Défenseur des droits. diff --git a/src/locales/pages/fr/budgetBottom.mdx b/src/locales/pages/fr/budgetBottom.mdx index da19bbeff..3020f324f 100644 --- a/src/locales/pages/fr/budgetBottom.mdx +++ b/src/locales/pages/fr/budgetBottom.mdx @@ -10,7 +10,7 @@ Notre modèle open-source nous permet d’accéder gratuitement à la majorité des outils que nous utilisons (hébergement de code, serveurs de tests, etc.). Le - site est hébergé sur [Netlify](https://www.netlify.com). + site est hébergé sur [Vercel](https://www.vercel.com). > #### À propos de la TVA > diff --git a/src/locales/pages/fr/landing.mdx b/src/locales/pages/fr/landing.mdx index ede4c647c..3cf14f986 100644 --- a/src/locales/pages/fr/landing.mdx +++ b/src/locales/pages/fr/landing.mdx @@ -1,6 +1,6 @@ ## Le simulateur de référence -Avec **plus d'[un million de tests complétés](/statistiques)**, nosgestesclimat.fr est le calculateur d'empreinte carbone personnel de référence. +Avec **plus d'[un million de tests complétés](/stats)**, nosgestesclimat.fr est le calculateur d'empreinte carbone personnel de référence. ## L'empreinte climat, qu'est-ce que c'est ? diff --git a/src/locales/pages/fr/privacy.mdx b/src/locales/pages/fr/privacy.mdx index 189a93741..5f551e1ba 100644 --- a/src/locales/pages/fr/privacy.mdx +++ b/src/locales/pages/fr/privacy.mdx @@ -25,8 +25,8 @@ Le responsable de l’utilisation des données est l’Agence de la transition ## Qui héberge Nos Gestes Climat ? -L’entreprise Netlify héberge Nos Gestes Climat. Netlify est une entreprise américaine dont le siège social est situé à San Francisco en Californie : https://www.netlify.com/gdpr-ccpa/ -Scalingo héberge les données du sondage : https://scalingo.com/fr/contrat-gestion-traitements-donnees-personnelles +L’entreprise Vercel héberge Nos Gestes Climat. Vercel est une entreprise américaine dont le siège social est situé à Covina en Californie : https://vercel.com/legal/privacy-policy +Scalingo héberge les données du sondage : https://scalingo.com/fr/contrat-gestion-traitements-donnees-personnelles ## Cookies diff --git a/src/locales/ui/ui-en.yaml b/src/locales/ui/ui-en.yaml index bb0d99dc2..1d12c65e4 100644 --- a/src/locales/ui/ui-en.yaml +++ b/src/locales/ui/ui-en.yaml @@ -182,8 +182,8 @@ entries: publicodes.Personas.description.lock: 'Nous les avons définis pour qu’ils représentent la diversité des cas d’usage du simulateur.<1>Toute ressemblance avec une personne existant ou ayant existé serait purement fortuite !</1>En aucune mesure, on ne peut dire qu’ils sont représentatifs de la distribution de la population française : il ne s’agit pas de coller aux statistiques de la population, mais de retrouver parmi nos dix personas au moins un qui représente chaque usage majeur et différenciant pour le simulateur. Ainsi, nous avons fait varier pour chacun d’entre eux :<3><0>Leur genre : même s’il n’influe pas sur l’empreinte, il serait étonnant de n’avoir que des personas “femmes”</0><1>Leur âge et situation personnelle / professionnelle : au moins un étudiant, un retraité, un adulte au foyer, un actif</1><2>La taille de leur foyer : de 1 personne à famille nombreuse</2><3>Leur lieu de vie : de l’urbain, du rural et du péri-urbain, dans le nord, dans le sud, les plaines, la montagne et sur une île</3><4>Leur logement : de l’appartement à la maison, du neuf à l’ancien</4><5>Leurs modes de transport : de la marche à la voiture en passant par le ferry et l’avion</5><6>Leur régime alimentaire : au moins un végétalien, un végétarien, une personne ne mangeant que du poisson, et un amateur de viande rouge</6><7>Leur tendance à l’achat : du tout occasion au tout neuf, de l’acheteur compulsif à celui ou celle qui n’achète presque rien</7><8>Leur façon de partir en vacances : mode de transport, hébergement, on trouve de tout</8><9>Leurs loisirs : de la culture, du sport, du bien-être…</9></3>' publicodes.Profil.locationDonnées: <0>Where is my data stored? </0><1>Your data is stored in your browser, so you have complete control over it.</1> publicodes.Profil.locationDonnées.lock: <0>Où sont mes données ? </0><1>Vos données sont stockées dans votre navigateur, vous avez donc le contrôle total sur elles.</1> - publicodes.Profil.recap: You have completed the test at {{percentFinished}} % ({{answeredQuestionsLength}} questions) and chose {{actionChoicesLength}} actions. - publicodes.Profil.recap.lock: Vous avez terminé le test à {{percentFinished}} % ({{answeredQuestionsLength}} questions) et choisi {{actionChoicesLength}} actions. + publicodes.Profil.recap: You have completed the test at {{percentFinished}} % ({{answeredQuestionsLength}} questions), choisi {{chosenActions}} action(s) et décliné {{declinedActions}} action(s). + publicodes.Profil.recap.lock: Vous avez terminé le test à {{percentFinished}} % ({{answeredQuestionsLength}} questions), choisi {{chosenActions}} action(s) et décliné {{declinedActions}} action(s). publicodes.Profil.simulations: Every simulation you make is saved in your web browser. Only you have access to it. publicodes.Profil.simulations.lock: Chaque simulation que vous faite est sauvegardée dans votre navigateur Web. Vous êtes le seul à y avoir accès. publicodes.SimulationMissing.personnas: You can also continue with a <2>typical profile</2>. @@ -479,3 +479,36 @@ entries: Domicile-Travail: Home-Work RDV médicaux: Medical appointments Sport ou Loisir: Sport or Leisure + Nos outils: Our tools + Documentations: Documentation + Informations: Information + Questions: Questions + ← Revenir au test: ← Back to test + Test: Test + Actions: Actions + Question pour l'utilisateur: Question for the user + Fermer le menu: Close menu + <0>👀</0> Voir mon résultat: 👀 <0>S</0> ee my result + Qui sommes-nous ?: Who are we? + Plan du site: Site map + Nos ambassadeurs: Our ambassadors + À l'international: Internationally + 'Diffuser le test :': 'Distribute the test:' + Je ne trouve pas réponse à ma question <2>🙋‍♀️</2>: I can't find the answer to my question <2>🙋‍‍♀️</2> + 'Vous pouvez nous contacter via notre page de contact : <2>accéder à notre page de contact</2>.': 'You can contact us via our contact page: <2>go to our contact page</2>.' + Pour toute autre remarque ou question, vous pouvez nous envoyer un message via le formulaire de contact ci-dessous.: If you have any other comments or questions, please send us a message using the contact form below. + N'hésitez pas à consulter notre <2>FAQ</2> avant de nous écrire, vous y trouverez sans doute la réponse à votre question !: Don't hesitate to consult our <2>FAQ</2> before writing to us - you're sure to find the answer to your question there! + Dans votre organisation: In your organisation + Nos guides thématiques: Our theme guides + Le modèle Nos Gestes Climat: The Nos Gestes Climat model + Les actions phares: Key actions + Votre profil: Your profile + Vie privée: Privacy policy + Nos actions pour réduire votre empreinte: Our actions to reduce your footprint + Statistiques: Statistics + Nos utilisateurs types: Our typical users + FAQ: FAQ + Partenaires: Partners + Aide à la saisie: Input help + Revenir à l'accueil: Back to home page + Pour en savoir plus sur cette règle de notre modèle, lancer le calcul en cliquant sur le bouton ci-dessous.: To find out more about this rule in our model, run the calculation by clicking on the button below. diff --git a/src/locales/ui/ui-fr.yaml b/src/locales/ui/ui-fr.yaml index 22c42c5c7..4aad0f5cd 100644 --- a/src/locales/ui/ui-fr.yaml +++ b/src/locales/ui/ui-fr.yaml @@ -136,7 +136,7 @@ entries: publicodes.Landing.question: Connaissez-vous votre empreinte sur le climat ? publicodes.Personas.description: 'Nous les avons définis pour qu’ils représentent la diversité des cas d’usage du simulateur.<1>Toute ressemblance avec une personne existant ou ayant existé serait purement fortuite !</1>En aucune mesure, on ne peut dire qu’ils sont représentatifs de la distribution de la population française : il ne s’agit pas de coller aux statistiques de la population, mais de retrouver parmi nos dix personas au moins un qui représente chaque usage majeur et différenciant pour le simulateur. Ainsi, nous avons fait varier pour chacun d’entre eux :<3><0>Leur genre : même s’il n’influe pas sur l’empreinte, il serait étonnant de n’avoir que des personas “femmes”</0><1>Leur âge et situation personnelle / professionnelle : au moins un étudiant, un retraité, un adulte au foyer, un actif</1><2>La taille de leur foyer : de 1 personne à famille nombreuse</2><3>Leur lieu de vie : de l’urbain, du rural et du péri-urbain, dans le nord, dans le sud, les plaines, la montagne et sur une île</3><4>Leur logement : de l’appartement à la maison, du neuf à l’ancien</4><5>Leurs modes de transport : de la marche à la voiture en passant par le ferry et l’avion</5><6>Leur régime alimentaire : au moins un végétalien, un végétarien, une personne ne mangeant que du poisson, et un amateur de viande rouge</6><7>Leur tendance à l’achat : du tout occasion au tout neuf, de l’acheteur compulsif à celui ou celle qui n’achète presque rien</7><8>Leur façon de partir en vacances : mode de transport, hébergement, on trouve de tout</8><9>Leurs loisirs : de la culture, du sport, du bien-être…</9></3>' publicodes.Profil.locationDonnées: <0>Où sont mes données ? </0><1>Vos données sont stockées dans votre navigateur, vous avez donc le contrôle total sur elles.</1> - publicodes.Profil.recap: Vous avez terminé le test à {{percentFinished}} % ({{answeredQuestionsLength}} questions) et choisi {{actionChoicesLength}} actions. + publicodes.Profil.recap: Vous avez terminé le test à {{percentFinished}} % ({{answeredQuestionsLength}} questions), choisi {{chosenActions}} action(s) et décliné {{declinedActions}} action(s). publicodes.Profil.simulations: Chaque simulation que vous faite est sauvegardée dans votre navigateur Web. Vous êtes le seul à y avoir accès. publicodes.SimulationMissing.personnas: Vous pouvez aussi continuer avec un <2>profil type</2>. publicodes.SimulationMissing.simulationManquante: Pour débloquer ce parcours, vous devez d'abord terminer le test. @@ -399,3 +399,37 @@ entries: Visite familiale: Visite familiale Week-end: Week-end '{displayValue}': '{displayValue}' + Documentations: Documentations + Informations: Informations + Nos outils: Nos outils + Questions: Questions + '{periods[journey.period]}': '{periods[journey.period]}' + ← Revenir au test: ← Revenir au test + <0>👀</0> Voir mon résultat: <0>👀</0> Voir mon résultat + Actions: Actions + Aide à la saisie: Aide à la saisie + Fermer le menu: Fermer le menu + Pour en savoir plus sur cette règle de notre modèle, lancer le calcul en cliquant sur le bouton ci-dessous.: Pour en savoir plus sur cette règle de notre modèle, lancer le calcul en cliquant sur le bouton ci-dessous. + Question pour l'utilisateur: Question pour l'utilisateur + Revenir à l'accueil: Revenir à l'accueil + Test: Test + À l'international: À l'international + Dans votre organisation: Dans votre organisation + 'Diffuser le test :': 'Diffuser le test :' + Je ne trouve pas réponse à ma question <2>🙋‍♀️</2>: Je ne trouve pas réponse à ma question <2>🙋‍♀️</2> + N'hésitez pas à consulter notre <2>FAQ</2> avant de nous écrire, vous y trouverez sans doute la réponse à votre question !: N'hésitez pas à consulter notre <2>FAQ</2> avant de nous écrire, vous y trouverez sans doute la réponse à votre question ! + Nos ambassadeurs: Nos ambassadeurs + Plan du site: Plan du site + Pour toute autre remarque ou question, vous pouvez nous envoyer un message via le formulaire de contact ci-dessous.: Pour toute autre remarque ou question, vous pouvez nous envoyer un message via le formulaire de contact ci-dessous. + Qui sommes-nous ?: Qui sommes-nous ? + 'Vous pouvez nous contacter via notre page de contact : <2>accéder à notre page de contact</2>.': 'Vous pouvez nous contacter via notre page de contact : <2>accéder à notre page de contact</2>.' + FAQ: FAQ + Le modèle Nos Gestes Climat: Le modèle Nos Gestes Climat + Les actions phares: Les actions phares + Nos actions pour réduire votre empreinte: Nos actions pour réduire votre empreinte + Nos guides thématiques: Nos guides thématiques + Nos utilisateurs types: Nos utilisateurs types + Partenaires: Partenaires + Statistiques: Statistiques + Vie privée: Vie privée + Votre profil: Votre profil diff --git a/src/middleware.ts b/src/middleware.ts index d8b739e65..8d4fa9689 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,13 +1,58 @@ -import i18nConfig from '@/i18nConfig' -import { i18nRouter } from 'next-i18n-router' -import { NextRequest } from 'next/server' +import { splitTestingCookieName } from '@/constants/split-testing' +import type { NextRequest } from 'next/server' +import { NextResponse } from 'next/server' +import i18nMiddleware from './middlewares/i18nMiddleware' +import splitTestingMiddleware from './middlewares/splitTestingMiddleware' -export function middleware(request: NextRequest) { - return i18nRouter(request, i18nConfig) +export const middlewares = [splitTestingMiddleware, i18nMiddleware] + +export async function middleware(request: NextRequest) { + const response = NextResponse.next() + let splitNumber = null + for await (const middlewareFunction of middlewares) { + const middlewareResponse = await middlewareFunction(request) + + // Even if we don't redirect, we still need to keep the split cookie for the next response + if (!splitNumber) { + splitNumber = getSplitCookieFromResponse(middlewareResponse) + } + if (splitNumber) { + response.cookies.set(splitTestingCookieName, splitNumber) + middlewareResponse.cookies.set(splitTestingCookieName, splitNumber) + } + + if (isRedirecting(middlewareResponse)) { + return middlewareResponse + } + if (isRewriting(middlewareResponse)) { + return middlewareResponse + } + if (isI18n(middlewareResponse)) { + return middlewareResponse + } + } + return response +} +function isRedirecting(response: NextResponse): boolean { + return response.status === 307 || response.status === 308 } +function isRewriting(response: NextResponse): boolean { + return response.headers.has('x-middleware-rewrite') +} +function isI18n(response: NextResponse): boolean { + return response.headers.has('x-next-i18n-router-locale') +} + +function getSplitCookieFromResponse(response: NextResponse) { + const cookie = response.headers + .getSetCookie() + .find((cookie) => cookie.includes(splitTestingCookieName)) + + if (!cookie) return null -// only applies this middleware to files in the app directory -export const config = { - matcher: - '/((?!api|_next/static|_next/image|favicon.ico|images|.*\\..*|_next).*)', + const cookieNumber = cookie + .replace(splitTestingCookieName, '') + .replace('=', '') + .replace('; Path=/', '') + return cookieNumber } diff --git a/src/middlewares/i18nMiddleware.ts b/src/middlewares/i18nMiddleware.ts new file mode 100644 index 000000000..d6f26b777 --- /dev/null +++ b/src/middlewares/i18nMiddleware.ts @@ -0,0 +1,13 @@ +import i18nConfig from '@/i18nConfig' +import { i18nRouter } from 'next-i18n-router' +import { NextRequest } from 'next/server' + +function i18nMiddleware(request: NextRequest) { + // TODO: bring back route exclusion for i18n + // if (!request.nextUrl.href.match('/((?!api|static|.*\\..*|_next).*)')) { + // return NextResponse.next() + // } + return i18nRouter(request, i18nConfig) +} + +export default i18nMiddleware diff --git a/src/middlewares/splitTestingMiddleware.ts b/src/middlewares/splitTestingMiddleware.ts new file mode 100644 index 000000000..6540a6ebd --- /dev/null +++ b/src/middlewares/splitTestingMiddleware.ts @@ -0,0 +1,46 @@ +import { splitTestingCookieName } from '@/constants/split-testing' +import type { NextRequest } from 'next/server' +import { NextResponse } from 'next/server' + +const redirectUrl = `https://nosgestesclimat-git-${process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH}-nos-gestes-climat.vercel.app` + +export default function splitTestingMiddleware(request: NextRequest) { + if (!process.env.NEXT_PUBLIC_SPLIT_TESTING_BRANCH) { + return NextResponse.next() + } + + let splitNumber = getSplitCookieFromRequest(request) + if (!splitNumber) { + const randomNumber = Math.random() + splitNumber = String(randomNumber) + } + + const shouldRedirectToChallenger = + Number(splitNumber) < + Number(process.env.NEXT_PUBLIC_SPLIT_TESTING_PERCENTAGE ?? 0.5) + + if (!shouldRedirectToChallenger || redirectUrl === request.nextUrl.origin) { + const response = NextResponse.next() + response.cookies.set(splitTestingCookieName, splitNumber) + return response + } else { + const rewriteTo = `${redirectUrl}${request.nextUrl.href.replace( + request.nextUrl.origin, + '' + )}` + const response = NextResponse.rewrite(rewriteTo) + response.cookies.set(splitTestingCookieName, splitNumber) + return response + } +} + +function getSplitCookieFromRequest(request: NextRequest) { + const cookieString = request.headers + .get('cookie') + ?.split('; ') + .find((cookieString) => cookieString.includes(splitTestingCookieName)) + + if (!cookieString) return null + + return cookieString.replace(splitTestingCookieName, '').replace('=', '') +} diff --git a/src/publicodes-state/hooks/useActions/index.ts b/src/publicodes-state/hooks/useActions/index.ts index 500f09b56..c9b0110d3 100644 --- a/src/publicodes-state/hooks/useActions/index.ts +++ b/src/publicodes-state/hooks/useActions/index.ts @@ -1,7 +1,7 @@ 'use client' import { useContext, useMemo } from 'react' -import { useEngine } from '../..' +import { useEngine, useUser } from '../..' import simulationContext from '../../providers/simulationProvider/context' type ActionObject = { @@ -18,6 +18,10 @@ export default function useActions() { const { getValue } = useEngine() + const { getCurrentSimulation } = useUser() + + const currentSimulation = getCurrentSimulation() + const orderedActions = useMemo<string[]>( () => engine @@ -33,10 +37,39 @@ export default function useActions() { [engine, getValue] ) + const { chosenActions, declinedActions } = + Object.keys(currentSimulation?.actionChoices ?? {})?.reduce( + (accActions, currentAction) => { + const actionChoice = currentSimulation?.actionChoices[currentAction] + + if (actionChoice) { + { + accActions.chosenActions = [ + ...accActions.chosenActions, + currentAction, + ] + } + } else { + accActions.declinedActions = [ + ...accActions.declinedActions, + currentAction, + ] + } + + return accActions + }, + { chosenActions: [], declinedActions: [] } as { + chosenActions: string[] + declinedActions: string[] + } + ) || 0 + return { /** * Every relevant actions, ordered by value */ orderedActions, + chosenActions, + declinedActions, } } diff --git a/src/publicodes-state/hooks/useForm/index.ts b/src/publicodes-state/hooks/useForm/index.ts index b2c9d9528..e9968c11e 100644 --- a/src/publicodes-state/hooks/useForm/index.ts +++ b/src/publicodes-state/hooks/useForm/index.ts @@ -40,7 +40,7 @@ export default function useForm() { /** * Every relevant categories ordered as needed for the simulation root (default: bilan) */ - categories, + categories: [...categories], /** * Every relevant subcategories sorted by category */ diff --git a/src/publicodes-state/hooks/useRule/index.ts b/src/publicodes-state/hooks/useRule/index.ts index eb6629b61..0cae29bc5 100644 --- a/src/publicodes-state/hooks/useRule/index.ts +++ b/src/publicodes-state/hooks/useRule/index.ts @@ -25,6 +25,7 @@ export default function useRule(dottedName: string) { situation, updateSituation, addFoldedStep, + foldedSteps, everyNotifications, everyMosaicChildWhoIsReallyInMosaic, } = useContext(simulationContext) @@ -71,19 +72,23 @@ export default function useRule(dottedName: string) { description, icons, unit, - color, assistance, isInactive, suggestions, + excerpt, } = useContent({ dottedName, rule, - safeGetRule, }) const choices = useChoices({ rule, type }) - const { isMissing } = useMissing({ dottedName, questionsOfMosaic, situation }) + const { isMissing, isFolded } = useMissing({ + dottedName, + questionsOfMosaic, + situation, + foldedSteps, + }) const { value, displayValue, numericValue, setValue, setDefaultAsValue } = useValue({ @@ -130,14 +135,14 @@ export default function useRule(dottedName: string) { * The unit of the rule ("rawNode.unité" in Publicodes) */ unit, - /** - * The color of the parent category ("rawNode.couleur" in Publicodes) - */ - color, /** * The question used to help answer ("rawNode.aide" in Publicodes) */ assistance, + /** + * Attribut use to briefly explain a rule + */ + excerpt, /** * True if the rule is not yet active ("rawNode.inactif" in Publicodes) */ @@ -182,6 +187,10 @@ export default function useRule(dottedName: string) { * True if the question is not answered */ isMissing, + /** + * True if the question is in the folded steps (answered or not) + */ + isFolded, /** * Setter for the value of the rule, with the possibility to add a dottedName in the foldedSteps */ diff --git a/src/publicodes-state/hooks/useRule/useContent.ts b/src/publicodes-state/hooks/useRule/useContent.ts index 72c5d48bb..88be17eb1 100644 --- a/src/publicodes-state/hooks/useRule/useContent.ts +++ b/src/publicodes-state/hooks/useRule/useContent.ts @@ -6,10 +6,9 @@ import { NGCRuleNode, Suggestion } from '../../types' type Props = { dottedName: string rule: NGCRuleNode | null - safeGetRule: (rule: string) => NGCRuleNode | null } -export default function useContent({ dottedName, rule, safeGetRule }: Props) { +export default function useContent({ dottedName, rule }: Props) { const category = useMemo<string>( () => dottedName.split(' . ')[0], [dottedName] @@ -35,10 +34,7 @@ export default function useContent({ dottedName, rule, safeGetRule }: Props) { [rule] ) const unit = useMemo<string | undefined>(() => rule?.rawNode['unité'], [rule]) - const color = useMemo<string | undefined>( - () => safeGetRule(category)?.rawNode['couleur'], - [category, safeGetRule] - ) + const assistance = useMemo<string | undefined>( () => rule?.rawNode['aide'], [rule] @@ -59,6 +55,11 @@ export default function useContent({ dottedName, rule, safeGetRule }: Props) { : [] }, [rule]) + const excerpt = useMemo<string | undefined>( + () => rule?.rawNode['résumé'], + [rule] + ) + return { category, title, @@ -67,9 +68,9 @@ export default function useContent({ dottedName, rule, safeGetRule }: Props) { description, icons, unit, - color, assistance, isInactive, suggestions, + excerpt, } } diff --git a/src/publicodes-state/hooks/useRule/useMissing.ts b/src/publicodes-state/hooks/useRule/useMissing.ts index 64e2dfff0..e26b9dd6b 100644 --- a/src/publicodes-state/hooks/useRule/useMissing.ts +++ b/src/publicodes-state/hooks/useRule/useMissing.ts @@ -8,12 +8,14 @@ type Props = { dottedName: string questionsOfMosaic: string[] situation: Situation + foldedSteps: string[] } export default function useValue({ dottedName, situation, questionsOfMosaic, + foldedSteps, }: Props) { const isMissing = useMemo( () => @@ -25,7 +27,13 @@ export default function useValue({ [dottedName, situation, questionsOfMosaic] ) + const isFolded = useMemo( + () => foldedSteps.indexOf(dottedName) >= 0, + [dottedName, foldedSteps] + ) + return { isMissing, + isFolded, } } diff --git a/src/publicodes-state/hooks/useRule/useValue.ts b/src/publicodes-state/hooks/useRule/useValue.ts index eeeac3681..83bdecd5b 100644 --- a/src/publicodes-state/hooks/useRule/useValue.ts +++ b/src/publicodes-state/hooks/useRule/useValue.ts @@ -31,7 +31,7 @@ export default function useValue({ }: Props) { const value = useMemo<NodeValue>(() => evaluation?.nodeValue, [evaluation]) - const displayValue = useMemo<string | number>(() => { + const displayValue = useMemo<string>(() => { if (type === 'choices') { const stringValue = String(value) return stringValue.startsWith("'") @@ -39,14 +39,19 @@ export default function useValue({ : stringValue } if (type === 'boolean') { - return value === null || value === false || value === 'non' // Model shenanigans + return value === true + ? 'oui' + : value === false || value === null // `value` is null when `ruleDisabledByItsParent` knowing that the parent becomes `null` according to this value. ? 'non' - : 'oui' + : '' } if (type === 'mosaic') { return 'mosaic' } - return Number(value) + if (Number(value) === value) { + return String(value) + } + return '' }, [value, type]) const numericValue = useMemo<number>( @@ -116,9 +121,11 @@ const checkValueValidity = ({ } return value.startsWith("'") ? value : `'${value}'` case 'boolean': - return value === null || value === false || value === 'non' // Model shenanigans + return value === 'oui' + ? 'oui' + : value === 'non' || value === null ? 'non' - : 'oui' + : undefined case 'mosaic': return 'mosaic' default: diff --git a/src/publicodes-state/hooks/useSimulation/index.ts b/src/publicodes-state/hooks/useSimulation/index.ts index ecc5bde9d..15a69263f 100644 --- a/src/publicodes-state/hooks/useSimulation/index.ts +++ b/src/publicodes-state/hooks/useSimulation/index.ts @@ -5,10 +5,12 @@ import { useContext } from 'react' * A hook that make available some information on the current instanciated simulation. */ export default function useSimulation() { - const { categories, subcategories } = useContext(SimulationContext) + const { categories, subcategories, everyQuestions } = + useContext(SimulationContext) return { - categories, + categories: [...categories], subcategories, + everyQuestions, } } diff --git a/src/publicodes-state/hooks/useUser/useSimulations.ts b/src/publicodes-state/hooks/useUser/useSimulations.ts index 3f7bb7065..6d25fa9e1 100644 --- a/src/publicodes-state/hooks/useUser/useSimulations.ts +++ b/src/publicodes-state/hooks/useUser/useSimulations.ts @@ -16,6 +16,17 @@ export default function useSimulations({ currentSimulationId, setCurrentSimulationId, }: Props) { + const resetAideSaisie = () => { + localStorage.removeItem('transport . voiture . km') + localStorage.removeItem( + 'transport . avion . court courrier . heures de vol' + ) + localStorage.removeItem( + 'transport . avion . moyen courrier . heures de vol' + ) + localStorage.removeItem('transport . avion . long courrier . heures de vol') + } + const initSimulation = ({ situation = {}, persona, @@ -27,6 +38,8 @@ export default function useSimulations({ } = {}) => { const id = uuidv4() + resetAideSaisie() + setSimulations((prevSimulations: Simulation[]) => [ ...prevSimulations, { diff --git a/src/publicodes-state/providers/formProvider/useQuestions.ts b/src/publicodes-state/providers/formProvider/useQuestions.ts index c6cc8af33..033322345 100644 --- a/src/publicodes-state/providers/formProvider/useQuestions.ts +++ b/src/publicodes-state/providers/formProvider/useQuestions.ts @@ -43,13 +43,15 @@ export default function useQuestions({ () => // We take every questions everyQuestions - // We remove all that are in mosaics + // We remove all that are in mosaics, .filter( (question) => !everyMosaicChildWhoIsReallyInMosaic.find( (mosaic) => mosaic === question ) ) + // all that are in folded steps + .filter((question) => foldedSteps.indexOf(question) === -1) // and all that are not missing .filter((question) => Object.keys(missingVariables).find((missingVariable) => @@ -127,6 +129,7 @@ export default function useQuestions({ return missingVariables[b] - missingVariables[a] }), [ + foldedSteps, categories, subcategories, missingVariables, diff --git a/src/publicodes-state/providers/simulationProvider/useEngine.ts b/src/publicodes-state/providers/simulationProvider/useEngine.ts index 87b4fe2fe..d60d3453d 100644 --- a/src/publicodes-state/providers/simulationProvider/useEngine.ts +++ b/src/publicodes-state/providers/simulationProvider/useEngine.ts @@ -11,17 +11,19 @@ import { NGCEvaluatedNode, NGCRuleNode, Rules } from '../../types' * And a pristine engine wich can be used to assess rules without any situation (for exemple, we can reliably sort the subcategories this way) */ export default function useEngine(rules: Rules) { - const engine = useMemo<Engine>( - () => - new Engine(rules, { - logger: { - log: console.log, - warn: () => null, - error: console.error, - }, - }), - [rules] - ) + const engine = useMemo<Engine>(() => { + const nbRules = Object.keys(rules).length + console.time(`⚙️ Parsing ${nbRules}`) + const engine = new Engine(rules, { + logger: { + log: console.log, + warn: () => null, + error: console.error, + }, + }) + console.timeEnd(`⚙️ Parsing ${nbRules}`) + return engine + }, [rules]) const pristineEngine = useMemo(() => engine.shallowCopy(), [engine]) diff --git a/src/publicodes-state/types.d.ts b/src/publicodes-state/types.d.ts index 62eba0ff1..4b62f211d 100644 --- a/src/publicodes-state/types.d.ts +++ b/src/publicodes-state/types.d.ts @@ -96,7 +96,7 @@ type MosaicInfos = { type Formule = any -type NGCRule = { +type NGCRule = Rule & { abréviation?: string couleur?: Color mosaique?: MosaiqueNode @@ -106,10 +106,12 @@ type NGCRule = { icônes?: string sévérité?: 'avertissement' | 'information' | 'invalide' dottedName?: string + question?: string plus?: boolean formule?: Formule aide?: string inactif?: string + résumé?: string } export type NGCRules = Record<string, NGCRule> diff --git a/src/types/international.ts b/src/types/international.ts index 9630edaeb..8d595d710 100644 --- a/src/types/international.ts +++ b/src/types/international.ts @@ -27,4 +27,6 @@ export type SupportedRegionType = { [currentLang: string]: { nom: string; authors: RegionAuthor[] } } -export type SuppportedRegions = { [key: string]: SupportedRegionType } +export type SuppportedRegions = { [key: string]: SupportedRegionType } & { + version: string +} diff --git a/src/types/journey.d.ts b/src/types/journey.d.ts index 5691524b6..817ce514a 100644 --- a/src/types/journey.d.ts +++ b/src/types/journey.d.ts @@ -3,6 +3,6 @@ export type Journey = { label: string distance: number reccurrence: number - period: JourneyPeriod + period: string passengers: number } diff --git a/src/utils/decodeRuleNameFromPath.ts b/src/utils/decodeRuleNameFromPath.ts new file mode 100644 index 000000000..99acde677 --- /dev/null +++ b/src/utils/decodeRuleNameFromPath.ts @@ -0,0 +1,6 @@ +export function decodeRuleNameFromPath(path: string) { + return decodeURI(path) + ?.replaceAll('/', ' . ') + .replaceAll('\u2011', '-') // replace with a insecable tiret to differenciate from space + .replaceAll('-', ' ') +} diff --git a/src/utils/getCookies.ts b/src/utils/getCookies.ts new file mode 100644 index 000000000..9b9d66ef2 --- /dev/null +++ b/src/utils/getCookies.ts @@ -0,0 +1,10 @@ +export function getCookie(name: string) { + const nameEQ = name + '=' + const ca = document.cookie.split(';') + for (let i = 0; i < ca.length; i++) { + let c = ca[i] + while (c.charAt(0) == ' ') c = c.substring(1, c.length) + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length) + } + return null +} diff --git a/tailwind.config.js b/tailwind.config.js index eb8542329..7070ff981 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -11,23 +11,45 @@ module.exports = { sans: 'var(--font-marianne)', }, colors: { - // primary: '#491273', - primary: '#5758BB', - // primaryLight: '#E8DFEE', - primaryLight: '#e6e6f5', - primaryDark: '#32337B', - primaryBorder: 'rgba(73, 18, 115, 0.1)', - title: '#32337B', - secondary: '#3496E0', - lightGrey: '#F8F8F7', + primary: { + /** + * Background neutral + */ + 100: '#F6F3F8', + /** + * Background element point of interest + */ + 200: '#E8DFEE', + /** + * Background element point of interest darker + */ + 300: '#AA90BF', + /** + * Hover + */ + 400: '#6D418F', + /** + * Main elements or text + */ + 500: '#491273', + /** + * Darker text + */ + 700: '#3A0E5B', + 800: '#2A0A42', + }, + secondary: '#D40983', + default: '#1A1A1A', grey: { 100: '#F8F8F7', 200: '#E3E3DB', }, - pink: { - 100: '#FAF0FA', - 200: '#FEDEF1', - 500: '#D40983', + categories: { + transport: '#bc0b69', + alimentation: '#e58e26', + logement: '#04a4ac', + divers: '#006ccb', + servicessocietaux: '#0c2461', }, }, keyframes: { @@ -43,5 +65,27 @@ module.exports = { }, }, }, + safelist: [ + 'text-categories-transport', + 'text-categories-alimentation', + 'text-categories-logement', + 'text-categories-divers', + 'text-categories-servicessocietaux', + 'bg-categories-transport', + 'bg-categories-alimentation', + 'bg-categories-logement', + 'bg-categories-divers', + 'bg-categories-servicessocietaux', + 'fill-categories-transport', + 'fill-categories-alimentation', + 'fill-categories-logement', + 'fill-categories-divers', + 'fill-categories-servicessocietaux', + 'border-categories-transport', + 'border-categories-alimentation', + 'border-categories-logement', + 'border-categories-divers', + 'border-categories-servicessocietaux', + ], plugins: [], } diff --git a/tsconfig.json b/tsconfig.json index 6496f8c10..6016183d9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,5 +32,5 @@ "src/app/(layout-with-navigation)/statistiques/_components/StatsContent.js", "src/app/(layout-with-navigation)/statistiques/_components/content/Chart.js" ], - "exclude": ["node_modules", "cypress/**/*"] + "exclude": ["node_modules", "cypress/**/*", "scripts/**/*"] } diff --git a/yarn.lock b/yarn.lock index 01d44c62a..1d9b3b6b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,10 +54,10 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz#263f059c476e29ca4972481a17b8b660cb025a34" - integrity sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg== +"@babel/eslint-parser@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz#7bf0db1c53b54da0c8a12627373554a0828479ca" + integrity sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" @@ -1006,7 +1006,7 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.1", "@babel/runtime@^7.23.2", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== @@ -1238,14 +1238,14 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.9.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" - integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" + integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1257,10 +1257,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.51.0": - version "8.51.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" - integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== +"@eslint/js@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" + integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w== "@formatjs/intl-localematcher@^0.2.32": version "0.2.32" @@ -1288,12 +1288,12 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -1302,10 +1302,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@icons/material@^0.2.4": version "0.2.4" @@ -1398,108 +1398,113 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@mdx-js/loader@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-2.3.0.tgz#56a6b07eb0027b6407e953a97c52bd8619601161" - integrity sha512-IqsscXh7Q3Rzb+f5DXYk0HU71PK+WuFsEhf+mSV3fOhpLcEpgsHvTQ2h0T6TlZ5gHOaBeFjkXwB52by7ypMyNg== +"@mdx-js/loader@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-3.0.0.tgz#87ccefb0cd9d37be2aecf939be0a8d3f364eec84" + integrity sha512-9kLv83YtgxpoXVYHaf0ygx1dmhCffo0MQCv6KtNG67jy/JlBK/2Q0dSWfuuyStP3jnZKABHfbjv8zsiT1buu6A== dependencies: - "@mdx-js/mdx" "^2.0.0" + "@mdx-js/mdx" "^3.0.0" source-map "^0.7.0" -"@mdx-js/mdx@^2.0.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.3.0.tgz#d65d8c3c28f3f46bb0e7cb3bf7613b39980671a9" - integrity sha512-jLuwRlz8DQfQNiUCJR50Y09CGPq3fLtmtUQfVrj79E0JWu3dvsVcxVIcfhR5h0iXu+/z++zDrYeiJqifRynJkA== +"@mdx-js/mdx@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-3.0.0.tgz#37ef87685143fafedf1165f0a79e9fe95fbe5154" + integrity sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw== dependencies: + "@types/estree" "^1.0.0" "@types/estree-jsx" "^1.0.0" + "@types/hast" "^3.0.0" "@types/mdx" "^2.0.0" - estree-util-build-jsx "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - estree-util-to-js "^1.1.0" + collapse-white-space "^2.0.0" + devlop "^1.0.0" + estree-util-build-jsx "^3.0.0" + estree-util-is-identifier-name "^3.0.0" + estree-util-to-js "^2.0.0" estree-walker "^3.0.0" - hast-util-to-estree "^2.0.0" - markdown-extensions "^1.0.0" + hast-util-to-estree "^3.0.0" + hast-util-to-jsx-runtime "^2.0.0" + markdown-extensions "^2.0.0" periscopic "^3.0.0" - remark-mdx "^2.0.0" - remark-parse "^10.0.0" - remark-rehype "^10.0.0" - unified "^10.0.0" - unist-util-position-from-estree "^1.0.0" - unist-util-stringify-position "^3.0.0" - unist-util-visit "^4.0.0" - vfile "^5.0.0" + remark-mdx "^3.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + source-map "^0.7.0" + unified "^11.0.0" + unist-util-position-from-estree "^2.0.0" + unist-util-stringify-position "^4.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" -"@mdx-js/react@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-2.3.0.tgz#4208bd6d70f0d0831def28ef28c26149b03180b3" - integrity sha512-zQH//gdOmuu7nt2oJR29vFhDv88oGPmVw6BggmrHeMI+xgEkp1B2dX9/bMBSYtK0dyLX/aOmesKS09g222K1/g== +"@mdx-js/react@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.0.0.tgz#eaccaa8d6a7736b19080aff5a70448a7ba692271" + integrity sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ== dependencies: "@types/mdx" "^2.0.0" - "@types/react" ">=16" -"@next/env@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.6.tgz#c1148e2e1aa166614f05161ee8f77ded467062bc" - integrity sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw== +"@next/env@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.2.tgz#c1fb535983bca768e7eccd7b9cf4636127fc6d25" + integrity sha512-HAW1sljizEaduEOes/m84oUqeIDAUYBR1CDwu2tobNlNDFP3cSm9d6QsOsGeNlIppU1p/p1+bWbYCbvwjFiceA== -"@next/eslint-plugin-next@13.5.4": - version "13.5.4" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.4.tgz#ec70af509f07dc4e545df25834ac94d2c341c36a" - integrity sha512-vI94U+D7RNgX6XypSyjeFrOzxGlZyxOplU0dVE5norIfZGn/LDjJYPHdvdsR5vN1eRtl6PDAsOHmycFEOljK5A== +"@next/eslint-plugin-next@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.0.2.tgz#421799f46116d8032f1739ce5ce89822453c8f03" + integrity sha512-APrYFsXfAhnysycqxHcpg6Y4i7Ukp30GzVSZQRKT3OczbzkqGjt33vNhScmgoOXYBU1CfkwgtXmNxdiwv1jKmg== dependencies: glob "7.1.7" -"@next/mdx@^13.5.4": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-13.5.6.tgz#c70c96b2f7078c312bb18a29979476b74708d382" - integrity sha512-2AMyCrz1SxSWNUpADyLz3RbPbq0GHrchbO7Msvg7IsH8MrTw3VYaZSI1KNa6JzZIoykwtNVSEL+uBmPZi106Jw== +"@next/mdx@^14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/mdx/-/mdx-14.0.2.tgz#6c6639bf7500edd6a8f079f37e371040267bc92e" + integrity sha512-MFjfSeGDmjwLLRHojlyaDIs2dQz5kFBQh/jcTIb57VIlbOvRjJsgnwLTH3DzUT25dUaX0QaR6t+ITNcdyfwozQ== dependencies: source-map "^0.7.0" -"@next/swc-darwin-arm64@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz#b15d139d8971360fca29be3bdd703c108c9a45fb" - integrity sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA== - -"@next/swc-darwin-x64@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz#9c72ee31cc356cb65ce6860b658d807ff39f1578" - integrity sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA== - -"@next/swc-linux-arm64-gnu@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz#59f5f66155e85380ffa26ee3d95b687a770cfeab" - integrity sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg== - -"@next/swc-linux-arm64-musl@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz#f012518228017052736a87d69bae73e587c76ce2" - integrity sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q== - -"@next/swc-linux-x64-gnu@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz#339b867a7e9e7ee727a700b496b269033d820df4" - integrity sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw== - -"@next/swc-linux-x64-musl@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz#ae0ae84d058df758675830bcf70ca1846f1028f2" - integrity sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ== - -"@next/swc-win32-arm64-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz#a5cc0c16920485a929a17495064671374fdbc661" - integrity sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg== - -"@next/swc-win32-ia32-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz#6a2409b84a2cbf34bf92fe714896455efb4191e4" - integrity sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg== - -"@next/swc-win32-x64-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz#4a3e2a206251abc729339ba85f60bc0433c2865d" - integrity sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ== +"@next/swc-darwin-arm64@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.2.tgz#eba35a1425fee5d305903c85ae0d6d2b0d512c7b" + integrity sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ== + +"@next/swc-darwin-x64@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.2.tgz#8adb4dfc3d596c0816da67df9b75603218cf2a42" + integrity sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg== + +"@next/swc-linux-arm64-gnu@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.2.tgz#1f88d066d44c9229a861815e3d449b0037dae14e" + integrity sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA== + +"@next/swc-linux-arm64-musl@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.2.tgz#de9b2708abc35dd19429a662a11785d0c54d1ec7" + integrity sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA== + +"@next/swc-linux-x64-gnu@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.2.tgz#64bd555dcbc7fd6c38cb86028baf7d7fc80bd4ac" + integrity sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q== + +"@next/swc-linux-x64-musl@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.2.tgz#69e6abf0f516df69acbf663eeb8ed6fd8eebcc38" + integrity sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ== + +"@next/swc-win32-arm64-msvc@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.2.tgz#82bc49af0986f4b2c113b5f223a559fc51b49b9d" + integrity sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ== + +"@next/swc-win32-ia32-msvc@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.2.tgz#2f1958ad82b7f7ec5da8ad8ac2f18ef7a8e7757f" + integrity sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q== + +"@next/swc-win32-x64-msvc@14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.2.tgz#629174f587beb640a431a4a3fe4e26d5d4f8de52" + integrity sha512-Ut4LXIUvC5m8pHTe2j0vq/YDnTEyq6RSR9vHYPqnELrDapPhLNz9Od/L5Ow3J8RNDWpEnfCiQXuVdfjlNEJ7ug== "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" @@ -1529,10 +1534,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@puppeteer/browsers@1.7.1": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.1.tgz#04f1e3aec4b87f50a7acc8f64be2149bda014f0a" - integrity sha512-nIb8SOBgDEMFY2iS2MdnUZOg2ikcYchRrBoF+wtdjieRFKR2uGRipHY/oFLo+2N6anDualyClPzGywTHRGrLfw== +"@puppeteer/browsers@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.8.0.tgz#fb6ee61de15e7f0e67737aea9f9bab1512dbd7d8" + integrity sha512-TkRHIV6k2D8OlUe8RtG+5jgOF/H98Myx0M6AOafC8DdNVOFiBSFa5cpRDtpm8LXOa9sVwe0+e6Q3FC56X/DZfg== dependencies: debug "4.3.4" extract-zip "2.0.1" @@ -1540,7 +1545,7 @@ proxy-agent "6.3.1" tar-fs "3.0.4" unbzip2-stream "1.4.3" - yargs "17.7.1" + yargs "17.7.2" "@rollup/plugin-commonjs@24.0.0": version "24.0.0" @@ -1568,32 +1573,30 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== -"@sentry-internal/tracing@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.74.1.tgz#55ff387e61d2c9533a9a0d099d376332426c8e08" - integrity sha512-nNaiZreQxCitG2PzYPaC7XtyA9OMsETGYMKAtiK4p62/uTmeYbsBva9BoNx1XeiHRwbrVQYRMKQ9nV5e2jS4/A== +"@sentry-internal/tracing@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.80.0.tgz#f9a6c0456b3cbf4a53c986a0b9208572d80e0756" + integrity sha512-P1Ab9gamHLsbH9D82i1HY8xfq9dP8runvc4g50AAd6OXRKaJ45f2KGRZUmnMEVqBQ7YoPYp2LFMkrhNYbcZEoQ== dependencies: - "@sentry/core" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - tslib "^2.4.1 || ^1.9.3" + "@sentry/core" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" -"@sentry/browser@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.74.1.tgz#9302d440bbdcb018abd5fee5959dab4b2fe97383" - integrity sha512-OYWNne/KO60lOvkIpIlJUyiJt/9j8DGI57thSDFEYSmmbNqMitczUTBOaEStouvHKyfchqLZm1CZfWKt+z0VOA== +"@sentry/browser@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.80.0.tgz#385fb59ac1d52b67919087f3d7044575ae0abbdd" + integrity sha512-Ngwjc+yyf/aH5q7iQM1LeDNlhM1Ilt4ZLUogTghZR/guwNWmCtk3OHcjOLz7fxBBj9wGFUc2pHPyeYM6bQhrEw== dependencies: - "@sentry-internal/tracing" "7.74.1" - "@sentry/core" "7.74.1" - "@sentry/replay" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - tslib "^2.4.1 || ^1.9.3" + "@sentry-internal/tracing" "7.80.0" + "@sentry/core" "7.80.0" + "@sentry/replay" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" "@sentry/cli@^1.74.6": - version "1.75.2" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.75.2.tgz#2c38647b38300e52c9839612d42b7c23f8d6455b" - integrity sha512-CG0CKH4VCKWzEaegouWfCLQt9SFN+AieFESCatJ7zSuJmzF05ywpMusjxqRul6lMwfUhRKjGKOzcRJ1jLsfTBw== + version "1.76.0" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.76.0.tgz#3d48248a4fec2fee7c4d30320c563c91c75290ec" + integrity sha512-56bVyUJoi52dop/rFEaSoU4AfVRXpR6M+nZBwN1iGUAwdfBrarNbtmIOjfgPi+tVzVB5ck09PzVXG6zeBqJJcA== dependencies: https-proxy-agent "^5.0.0" mkdirp "^0.5.5" @@ -1602,102 +1605,94 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.74.1.tgz#9e33cf59b754a994e4054c47c74df1d3fbd30d3c" - integrity sha512-LvEhOSfdIvwkr+PdlrT/aA/iOLhkXrSkvjqAQyogE4ddCWeYfS0NoirxNt1EaxMBAWKhYZRqzkA7WA4LDLbzlA== +"@sentry/core@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.80.0.tgz#7b8a460c19160b81ade20080333189f1a80c1410" + integrity sha512-nJiiymdTSEyI035/rdD3VOq6FlOZ2wWLR5bit9LK8a3rzHU3UXkwScvEo6zYgs0Xp1sC0yu1S9+0BEiYkmi29A== dependencies: - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - tslib "^2.4.1 || ^1.9.3" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" -"@sentry/integrations@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.74.1.tgz#a49b8e0de5ce7d1cf41db25dd0c4192cda527d4a" - integrity sha512-Q7chPehHpHB4WOQ1J/X6NiN2ptiqJMmxtL+6wHumzIAyrjup3c9XekR83qEs8zpqYJAlb/4MUlwd9fPbkhGXnQ== +"@sentry/integrations@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.80.0.tgz#d81dc3b357d4efd4368471b39496494ab221a64a" + integrity sha512-9xI+jtqSBrAG/Y2f4OyeJhl6WZR3i0qCXRwqCZoCFCDgN4ZQORc4VBwaC3nW2s9jgfb13FC2FQToGOVrRnsetg== dependencies: - "@sentry/core" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" + "@sentry/core" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" localforage "^1.8.1" - tslib "^2.4.1 || ^1.9.3" -"@sentry/nextjs@^7.73.0": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.74.1.tgz#6688b5f88576cf55a7f7faa94cf3dd7c63c84687" - integrity sha512-1RySEs3WBEqlpQCAFQ/XwV+oW4wEAtpYglvAyDBwPen/s6KnkkZ0za0l3Ug0O6S9HvMiNll1rPhvnkH5nM37Tg== +"@sentry/nextjs@^7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.80.0.tgz#65a9d41994becb1baa397d0be7da5649a9a54fb4" + integrity sha512-4KZVZV1U/1ldmVKS85n31MSKIWJElcy9gZW+PTyQnrlCxbQnnhXBde95+TXmvO1DKTNhVphv/2DXq7bmxBW9bA== dependencies: "@rollup/plugin-commonjs" "24.0.0" - "@sentry/core" "7.74.1" - "@sentry/integrations" "7.74.1" - "@sentry/node" "7.74.1" - "@sentry/react" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - "@sentry/vercel-edge" "7.74.1" + "@sentry/core" "7.80.0" + "@sentry/integrations" "7.80.0" + "@sentry/node" "7.80.0" + "@sentry/react" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" + "@sentry/vercel-edge" "7.80.0" "@sentry/webpack-plugin" "1.20.0" chalk "3.0.0" resolve "1.22.8" rollup "2.78.0" stacktrace-parser "^0.1.10" - tslib "^2.4.1 || ^1.9.3" - -"@sentry/node@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.74.1.tgz#6d3b2e3483eb3b379d8d51759a079934eabb2bef" - integrity sha512-aMUQ2LFZF64FBr+cgjAqjT4OkpYBIC9lyWI8QqjEHqNho5+LGu18/iVrJPD4fgs4UhGdCuAiQjpC36MbmnIDZA== - dependencies: - "@sentry-internal/tracing" "7.74.1" - "@sentry/core" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - cookie "^0.5.0" + +"@sentry/node@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.80.0.tgz#7e060bc934a58a442b786246d46a5a0dd822ae44" + integrity sha512-J35fqe8J5ac/17ZXT0ML3opYGTOclqYNE9Sybs1y9n6BqacHyzH8By72YrdI03F7JJDHwrcGw+/H8hGpkCwi0Q== + dependencies: + "@sentry-internal/tracing" "7.80.0" + "@sentry/core" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^2.4.1 || ^1.9.3" -"@sentry/react@7.74.1", "@sentry/react@^7.73.0": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.74.1.tgz#43517f8e42cfab917ed909d2fce76b265febb9c7" - integrity sha512-16oTsNi2hl/S5AL/e5bo9DQZDwXPkX0nC8ajrpU0z2pH4cwjQZUZt/9Xq1+MKqDIEZkqDcMwpTmBptOvy1Pvkw== +"@sentry/react@7.80.0", "@sentry/react@^7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.80.0.tgz#ee589ff202174ced45e77dc2714237031ca9c726" + integrity sha512-xoX7fqgY0NZR9Fud/IJ4a3b8Z/HsdwU5SLILi46lV+CWaXS6eFM1E81jG2Vd2EeYIpkH+bMA//XHMEod8LAJcQ== dependencies: - "@sentry/browser" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" + "@sentry/browser" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" hoist-non-react-statics "^3.3.2" - tslib "^2.4.1 || ^1.9.3" -"@sentry/replay@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.74.1.tgz#dcb5040a3b0a9bda160b70cde5368ecbb4f0e782" - integrity sha512-qmbOl+jYdyhoHFbPp9WemKx8UojID5hVmuVLxNIP0ANqAwmE9OQEK9YFg2cf7L/TpKb1tqz0qLgi5MYIdcdpgQ== +"@sentry/replay@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.80.0.tgz#0626d85af1d8573038d52ae9e244e3e95fa47385" + integrity sha512-wWnpuJq3OaDLp1LutE4oxWXnau04fvwuzBjuaFvOXOV+pB/kn+pDPuVOC5+FH/RMRZ5ftwX5+dF6fojfcLVGCg== dependencies: - "@sentry/core" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" + "@sentry-internal/tracing" "7.80.0" + "@sentry/core" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" -"@sentry/types@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.74.1.tgz#b6f9b1bd266254f1f8b55fbcc92fa649ba2100ed" - integrity sha512-2jIuPc+YKvXqZETwr2E8VYnsH1zsSUR/wkIvg1uTVeVNyoowJv+YsOtCdeGyL2AwiotUBSPKu7O1Lz0kq5rMOQ== +"@sentry/types@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.80.0.tgz#f6896de2d231a7f8d814cf1c981c474240e96d8a" + integrity sha512-4bpMO+2jWiWLDa8zbTASWWNLWe6yhjfPsa7/6VH5y9x1NGtL8oRbqUsTgsvjF3nmeHEMkHQsC8NHPaQ/ibFmZQ== -"@sentry/utils@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.74.1.tgz#e9a8453c954d02ebed2fd3dbe7588483d8f6d3cb" - integrity sha512-qUsqufuHYcy5gFhLZslLxA5kcEOkkODITXW3c7D+x+8iP/AJqa8v8CeUCVNS7RetHCuIeWAbbTClC4c411EwQg== +"@sentry/utils@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.80.0.tgz#5bd682fa9a382eea952d4fa3628f0f33e4240ff3" + integrity sha512-XbBCEl6uLvE50ftKwrEo6XWdDaZXHXu+kkHXTPWQEcnbvfZKLuG9V0Hxtxxq3xQgyWmuF05OH1GcqYqiO+v5Yg== dependencies: - "@sentry/types" "7.74.1" - tslib "^2.4.1 || ^1.9.3" + "@sentry/types" "7.80.0" -"@sentry/vercel-edge@7.74.1": - version "7.74.1" - resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.74.1.tgz#6bfaa33789d9a56c24e31d18250a955bf3eeb66d" - integrity sha512-E2lTfEtDFSh57EkjVe4EcgcdjOM8UvfZVsmANBqG4bnwRKrNX9GouClzKU2Ckd5vQnOiCH9r8x2aJ/dTqyBswQ== +"@sentry/vercel-edge@7.80.0": + version "7.80.0" + resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.80.0.tgz#674f77e820db066f408d4aab7887f964361706bb" + integrity sha512-Jh7Kg1+zrSbOqPcLmMQGaGWE2ieJcaCVrvuRgVxUCinZlHB2r5RUlXKLqR6GXV+LVqv8NQDIv1wrKfLSHdSKJA== dependencies: - "@sentry/core" "7.74.1" - "@sentry/types" "7.74.1" - "@sentry/utils" "7.74.1" - tslib "^2.4.1 || ^1.9.3" + "@sentry/core" "7.80.0" + "@sentry/types" "7.80.0" + "@sentry/utils" "7.80.0" "@sentry/webpack-plugin@1.20.0": version "1.20.0" @@ -1880,18 +1875,17 @@ dependencies: tslib "^2.4.0" -"@tanstack/query-core@4.36.1": - version "4.36.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524" - integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA== +"@tanstack/query-core@5.8.3": + version "5.8.3" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.8.3.tgz#7c6d62721518223e8b27f1a0b5e9bd4e3bb7ecd8" + integrity sha512-SWFMFtcHfttLYif6pevnnMYnBvxKf3C+MHMH7bevyYfpXpTMsLB9O6nNGBdWSoPwnZRXFNyNeVZOw25Wmdasow== -"@tanstack/react-query@^4.35.7": - version "4.36.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.36.1.tgz#acb589fab4085060e2e78013164868c9c785e5d2" - integrity sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw== +"@tanstack/react-query@^5.8.3": + version "5.8.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.8.3.tgz#3d5db417a4c62b0e04a9b4091ac748cac1bac06c" + integrity sha512-EDRrsMgUtKM+SjVmhDYBd4jwWWyHAw3kCaurKLIO90OfPQr/UhpwcqM2l/eQOaUYon9lfDB2ejQi1edHK7zEdA== dependencies: - "@tanstack/query-core" "4.36.1" - use-sync-external-store "^1.2.0" + "@tanstack/query-core" "5.8.3" "@tootallnate/quickjs-emscripten@^0.23.0": version "0.23.0" @@ -1930,22 +1924,22 @@ dependencies: "@types/estree" "*" -"@types/cheerio@^0.22.32": - version "0.22.33" - resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.33.tgz#e4792408b107384d7d7469e3b4d31408078ec620" - integrity sha512-XUlu2BK4q3xJsccRLK69m/cABZd7m60o+cDEPUTG6jTpuG2vqN35UioeF99MQ/HoSOEPq0Bgil8g3jtzE0oH9A== +"@types/cheerio@^0.22.34": + version "0.22.34" + resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.34.tgz#a2becca3fff0b33697a0e8db20b77d0f8b65894f" + integrity sha512-uoi5gQGpH5vdNrGOexnNm+19YZLdIRMF/IW8V6w1kIeoXaO1m2mVUMV4dl76tvRRKoIp9d/Z97ZYeIE4lacEsA== dependencies: "@types/node" "*" -"@types/crypto-js@^4.1.2": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.3.tgz#7f2fa22857ae2b5d3221edcba9644f67f8ea984c" - integrity sha512-YP1sYYayLe7Eg5oXyLLvOLfxBfZ5Fgpz6sVWkpB18wDMywCLPWmqzRz+9gyuOoLF0fzDTTFwlyNbx7koONUwqA== +"@types/crypto-js@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.2.1.tgz#480edd76991a63050cb88db1a8840758c55a7135" + integrity sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw== "@types/d3-array@^3.0.3": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.9.tgz#54feabd29d1f15940d422c16008c63c1e4e3d188" - integrity sha512-mZowFN3p64ajCJJ4riVYlOjNlBJv3hctgAY01pjw3qTnJePD8s9DZmYDzhHKvzfCYvdjwylkU38+Vdt7Cu2FDA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.0.tgz#603b85d0072962bdecaf8391f60eea465c8dc282" + integrity sha512-tjU8juPSfhMnu6mJZPOCVVGba4rZoE0tjHDPb81PYwA8CzbaFscGjgkUM7juUJu6iWA1cCVWNEVwxZ5HN9Jj8Q== "@types/d3-color@*": version "3.1.2" @@ -2024,16 +2018,16 @@ "@types/estree" "*" "@types/estree@*", "@types/estree@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.3.tgz#2be19e759a3dd18c79f9f436bd7363556c1a73dd" - integrity sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.4.tgz#d9748f5742171b26218516cf1828b8eafaf8a9fa" + integrity sha512-2JwWnHK9H+wUZNorf2Zr6ves96WHoWDJIftkcxPKsS7Djta6Zu519LarhRNljPXkpsZR2ZMwNCPeW7omW07BJw== -"@types/hast@^2.0.0": - version "2.3.7" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.7.tgz#5e9bd7ab4452d5313aeec9d38fbc193a70f8d810" - integrity sha512-EVLigw5zInURhzfXUM65eixfadfsHKomGKUakToXo84t8gGIJuTcD2xooM2See7GyQ7DRtYjhCHnSUQez8JaLw== +"@types/hast@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.2.tgz#e6c1126a33955cb9493a5074ddf1873fb48248c7" + integrity sha512-B5hZHgHsXvfCoO3xgNJvBnX7N8p86TqQeGKXcokW4XXi+qY4vxxPSFYofytvVmpFxzPv7oxDQzjg5Un5m2/xiw== dependencies: - "@types/unist" "^2" + "@types/unist" "*" "@types/html-minifier-terser@^6.0.0": version "6.1.0" @@ -2100,11 +2094,16 @@ dependencies: "@types/unist" "*" -"@types/mdx@^2.0.0", "@types/mdx@^2.0.8": +"@types/mdx@^2.0.0": version "2.0.9" resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.9.tgz#80971e367bb884350ab5b2ce8fc06b34960170e7" integrity sha512-OKMdj17y8Cs+k1r0XFyp59ChSOwf8ODGtMQ4mnpfz5eFDk1aO41yN3pSKGuvVzmWAkFp37seubY1tzOVpwfWwg== +"@types/mdx@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.10.tgz#0d7b57fb1d83e27656156e4ee0dfba96532930e4" + integrity sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg== + "@types/minimatch@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" @@ -2115,17 +2114,26 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.33.tgz#80bf1da64b15f21fd8c1dc387c31929317d99ee9" integrity sha512-AuHIyzR5Hea7ij0P9q7vx7xu4z0C28ucwjAZC0ja7JhINyCnOw8/DnvAPQQ9TfOlCtZAmCERKQX9+o1mgQhuOQ== -"@types/node@*", "@types/node@>=12.0", "@types/node@^20.8.2": - version "20.8.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25" - integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ== +"@types/node@*", "@types/node@>=12.0": + version "20.8.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.10.tgz#a5448b895c753ae929c26ce85cab557c6d4a365e" + integrity sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w== dependencies: - undici-types "~5.25.1" + undici-types "~5.26.4" "@types/node@^18.11.18", "@types/node@^18.17.5": - version "18.18.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.6.tgz#26da694f75cdb057750f49d099da5e3f3824cb3e" - integrity sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w== + version "18.18.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" + integrity sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ== + dependencies: + undici-types "~5.26.4" + +"@types/node@^20.9.0": + version "20.9.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298" + integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw== + dependencies: + undici-types "~5.26.4" "@types/pixelmatch@*": version "5.2.5" @@ -2139,32 +2147,41 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" integrity sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g== -"@types/react-color@^3.0.7": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.9.tgz#8dbb0d798f2979c3d7e2e26dd46321e80da950b4" - integrity sha512-Ojyc6jySSKvM6UYQrZxaYe0JZXtgHHXwR2q9H4MhcNCswFdeZH1owYZCvPtdHtMOfh7t8h1fY0Gd0nvU1JGDkQ== +"@types/react-color@^3.0.10": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/react-color/-/react-color-3.0.10.tgz#f869ab3a46938fb97a5c2ee568bc6469f82b14dd" + integrity sha512-6K5BAn3zyd8lW8UbckIAVeXGxR82Za9jyGD2DBEynsa7fKaguLDVtjfypzs7fgEV7bULgs7uhds8A8v1wABTvQ== dependencies: "@types/react" "*" "@types/reactcss" "*" -"@types/react-dom@^18.2.10": - version "18.2.14" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.14.tgz#c01ba40e5bb57fc1dc41569bb3ccdb19eab1c539" - integrity sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ== +"@types/react-dom@^18.2.15": + version "18.2.15" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.15.tgz#921af67f9ee023ac37ea84b1bc0cc40b898ea522" + integrity sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg== dependencies: "@types/react" "*" -"@types/react-slick@^0.23.10": - version "0.23.11" - resolved "https://registry.yarnpkg.com/@types/react-slick/-/react-slick-0.23.11.tgz#d349fee6709218e7a4b7839ccf80a070862373b6" - integrity sha512-52AbNhYN7u0ATqAUvap2MXNG3znUsJslAWgebUHrovvnJ6EG6oic+TZyC82XiwwvijRMyL2V0C2wPJbzsSwllw== +"@types/react-slick@^0.23.12": + version "0.23.12" + resolved "https://registry.yarnpkg.com/@types/react-slick/-/react-slick-0.23.12.tgz#41db46f837a453770123ebd84b0adc773ab8a583" + integrity sha512-WjY/wIjzgXCh6gXRZL75OC9n/Hn4MwKWI7ZJ4iA2OxavN9eKvkV5MPFjSgH5sofabq78Ucrl6u3okiBUNNIrDQ== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@>=16", "@types/react@^18.2.25": - version "18.2.29" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.29.tgz#88b48a287e00f6fdcd6f95662878fb701ae18b27" - integrity sha512-Z+ZrIRocWtdD70j45izShRwDuiB4JZqDegqMFW/I8aG5DxxLKOzVNoq62UIO82v9bdgi+DO1jvsb9sTEZUSm+Q== +"@types/react@*": + version "18.2.36" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.36.tgz#bc68ffb4408e5d0c419b0760b2eaeec70aeeedb3" + integrity sha512-o9XFsHYLLZ4+sb9CWUYwHqFVoG61SesydF353vFMMsQziiyRu8np4n2OYMUSDZ8XuImxDr9c5tR7gidlH29Vnw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/react@^18.2.37": + version "18.2.37" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.37.tgz#0f03af69e463c0f19a356c2660dbca5d19c44cae" + integrity sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2227,15 +2244,15 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.9.tgz#72e164381659a49557b0a078b28308f2c6a3e1ce" integrity sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ== -"@types/uuid@^9.0.4": - version "9.0.6" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.6.tgz#c91ae743d8344a54b2b0c691195f5ff5265f6dfb" - integrity sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew== +"@types/uuid@^9.0.7": + version "9.0.7" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.7.tgz#b14cebc75455eeeb160d5fe23c2fcc0c64f724d8" + integrity sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g== -"@types/webpack@^5.28.3": - version "5.28.4" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.4.tgz#2dcbf8afb238a3d25123649fc4946849fe029279" - integrity sha512-sVIGIQdg0bNruxwQvpiNXaIXndScf+qTfYULLo2DI8urXgxC7f8Rw8aNHjjckdI3QaV3cRHqoHdCuBMMyUtGiw== +"@types/webpack@^5.28.5": + version "5.28.5" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.5.tgz#0e9d9a15efa09bbda2cef41356ca4ac2031ea9a2" + integrity sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw== dependencies: "@types/node" "*" tapable "^2.2.0" @@ -2260,16 +2277,16 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^6.7.4": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz#06abe4265e7c82f20ade2dcc0e3403c32d4f148b" - integrity sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw== +"@typescript-eslint/eslint-plugin@^6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz#52aae65174ff526576351f9ccd41cea01001463f" + integrity sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/type-utils" "6.8.0" - "@typescript-eslint/utils" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/type-utils" "6.11.0" + "@typescript-eslint/utils" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -2277,74 +2294,124 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^5.4.2 || ^6.0.0", "@typescript-eslint/parser@^6.7.4": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" - integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== +"@typescript-eslint/parser@^5.4.2 || ^6.0.0": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.9.1.tgz#4f685f672f8b9580beb38d5fb99d52fc3e34f7a3" + integrity sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg== dependencies: - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.9.1" + "@typescript-eslint/types" "6.9.1" + "@typescript-eslint/typescript-estree" "6.9.1" + "@typescript-eslint/visitor-keys" "6.9.1" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" - integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== +"@typescript-eslint/parser@^6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.11.0.tgz#9640d9595d905f3be4f278bf515130e6129b202e" + integrity sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/typescript-estree" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" + debug "^4.3.4" -"@typescript-eslint/type-utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz#50365e44918ca0fd159844b5d6ea96789731e11f" - integrity sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g== +"@typescript-eslint/scope-manager@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz#621f603537c89f4d105733d949aa4d55eee5cea8" + integrity sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A== dependencies: - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/utils" "6.8.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" + +"@typescript-eslint/scope-manager@6.9.1": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz#e96afeb9a68ad1cd816dba233351f61e13956b75" + integrity sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg== + dependencies: + "@typescript-eslint/types" "6.9.1" + "@typescript-eslint/visitor-keys" "6.9.1" + +"@typescript-eslint/type-utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz#d0b8b1ab6c26b974dbf91de1ebc5b11fea24e0d1" + integrity sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA== + dependencies: + "@typescript-eslint/typescript-estree" "6.11.0" + "@typescript-eslint/utils" "6.11.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" - integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== +"@typescript-eslint/types@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.11.0.tgz#8ad3aa000cbf4bdc4dcceed96e9b577f15e0bf53" + integrity sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA== -"@typescript-eslint/typescript-estree@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" - integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== +"@typescript-eslint/types@6.9.1": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.1.tgz#a6cfc20db0fcedcb2f397ea728ef583e0ee72459" + integrity sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ== + +"@typescript-eslint/typescript-estree@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz#7b52c12a623bf7f8ec7f8a79901b9f98eb5c7990" + integrity sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/visitor-keys" "6.11.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.8.0.tgz#d42939c2074c6b59844d0982ce26a51d136c4029" - integrity sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q== +"@typescript-eslint/typescript-estree@6.9.1": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz#8c77910a49a04f0607ba94d78772da07dab275ad" + integrity sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw== + dependencies: + "@typescript-eslint/types" "6.9.1" + "@typescript-eslint/visitor-keys" "6.9.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.11.0.tgz#11374f59ef4cea50857b1303477c08aafa2ca604" + integrity sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" + "@typescript-eslint/scope-manager" "6.11.0" + "@typescript-eslint/types" "6.11.0" + "@typescript-eslint/typescript-estree" "6.11.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" - integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== +"@typescript-eslint/visitor-keys@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz#d991538788923f92ec40d44389e7075b359f3458" + integrity sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ== dependencies: - "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/types" "6.11.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@6.9.1": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz#6753a9225a0ba00459b15d6456b9c2780b66707d" + integrity sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw== + dependencies: + "@typescript-eslint/types" "6.9.1" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": version "1.11.6" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" @@ -2492,14 +2559,14 @@ acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + version "8.3.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" + integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== acorn@^8.0.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== agent-base@6: version "6.0.2" @@ -2627,7 +2694,7 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-query@^5.1.3: +aria-query@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== @@ -2642,7 +2709,7 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-includes@^3.1.6: +array-includes@^3.1.6, array-includes@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== @@ -2658,7 +2725,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.2: +array.prototype.findlastindex@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== @@ -2669,7 +2736,7 @@ array.prototype.findlastindex@^1.2.2: es-shim-unscopables "^1.0.0" get-intrinsic "^1.2.1" -array.prototype.flat@^1.3.1: +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== @@ -2679,7 +2746,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -2725,10 +2792,10 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== ast-types@^0.13.4: version "0.13.4" @@ -2748,9 +2815,9 @@ astring@^1.8.0: integrity sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg== async@^3.2.0: - version "3.2.4" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + version "3.2.5" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== asynciterator.prototype@^1.0.0: version "1.0.0" @@ -2796,15 +2863,15 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axe-core@^4.6.2: - version "4.8.2" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" - integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== +axe-core@=4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -"axios@>=0.21.2 <1.2.0 || >=1.2.1", axios@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" - integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A== +"axios@>=0.21.2 <1.2.0 || >=1.2.2", axios@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -2818,7 +2885,7 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axobject-query@^3.1.1: +axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== @@ -2840,12 +2907,12 @@ babel-plugin-polyfill-corejs2@^0.4.6: semver "^6.3.1" babel-plugin-polyfill-corejs3@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz#a75fa1b0c3fc5bd6837f9ec465c0f48031b8cab1" - integrity sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA== + version "0.8.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.6.tgz#25c2d20002da91fe328ff89095c85a391d6856cf" + integrity sha512-leDIc4l4tUgU7str5BWLS2h8q2N4Nf6lGZP6UrNDxdtfF2g69eJ5L0H7S8A5Ln/arfFAfHor5InAdZuIOwZdgQ== dependencies: "@babel/helper-define-polyfill-provider" "^0.4.3" - core-js-compat "^3.32.2" + core-js-compat "^3.33.1" babel-plugin-polyfill-regenerator@^0.5.3: version "0.5.3" @@ -3045,13 +3112,14 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" callsites@^3.0.0: version "3.1.0" @@ -3082,9 +3150,9 @@ camelize@^1.0.0: integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: - version "1.0.30001551" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz#1f2cfa8820bd97c971a57349d7fd8f6e08664a3e" - integrity sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg== + version "1.0.30001561" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" + integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== caseless@~0.12.0: version "0.12.0" @@ -3203,10 +3271,10 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -chromium-bidi@0.4.31: - version "0.4.31" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.31.tgz#a28c4329880706e61ff07ed49aed22e6d04e17d1" - integrity sha512-OtvEg2JMRQrHsmLx4FV3u1Hf9waYxB5PmL+yM0HkFpc9H2x3TMbUqS+GP2/fC4399hzOO+EQF8uVU43By9ILag== +chromium-bidi@0.4.33: + version "0.4.33" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.33.tgz#9a9aba5a5b07118c8e7d6405f8ee79f47418dd1d" + integrity sha512-IxoFM5WGQOIAd95qrSXzJUv4eXIrh+RvU3rwwqIiwYuvfE7U/Llj4fejbsJnjJMUYCuGtVQsY2gv7oGl4aTNSQ== dependencies: mitt "3.0.1" urlpattern-polyfill "9.0.0" @@ -3288,6 +3356,11 @@ clone@^2.1.2: resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== +collapse-white-space@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-2.1.0.tgz#640257174f9f42c740b40f3b55ee752924feefca" + integrity sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -3405,22 +3478,17 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - -core-js-compat@^3.31.0, core-js-compat@^3.32.2: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.0.tgz#24aa230b228406450b2277b7c8bfebae932df966" - integrity sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw== +core-js-compat@^3.31.0, core-js-compat@^3.33.1: + version "3.33.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.2.tgz#3ea4563bfd015ad4e4b52442865b02c62aba5085" + integrity sha512-axfo+wxFVxnqf8RvxTzoAlzW4gRoacrHeoFlc9n0x50+7BEyZL/Rt3hicaED1/CEd7I6tPCPVUYcJwCMO5XUYw== dependencies: browserslist "^4.22.1" -core-js@^3.33.0: - version "3.33.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40" - integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw== +core-js@^3.33.2: + version "3.33.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.2.tgz#312bbf6996a3a517c04c99b9909cdd27138d1ceb" + integrity sha512-XeBzWI6QL3nJQiHmdzbAOiMYqjrb7hwU7A39Qhvd/POSa/t9E1AeZyEZx3fNvp/vtM8zXwhoL0FsiS0hD0pruQ== core-util-is@1.0.2: version "1.0.2" @@ -3564,10 +3632,10 @@ cypress-recurse@^1.35.2: dependencies: humanize-duration "^3.27.3" -cypress@13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.3.0.tgz#d00104661b337d662c5a4280a051ee59f8aa1e31" - integrity sha512-mpI8qcTwLGiA4zEQvTC/U1xGUezVV4V8HQCOYjlEOrVmU1etVvxOjkCXHGwrlYdZU/EPmUiWfsO3yt1o+Q2bgw== +cypress@13.5.0: + version "13.5.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.5.0.tgz#8c149074186130972f08b2cdce6ded41f014bacd" + integrity sha512-oh6U7h9w8wwHfzNDJQ6wVcAeXu31DlIYlNOBvfd6U4CcB8oe4akawQmH+QJVOMZlM42eBoCne015+svVqdwdRQ== dependencies: "@cypress/request" "^3.0.0" "@cypress/xvfb" "^1.2.4" @@ -3767,12 +3835,12 @@ deep-is@^0.1.3: integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepl-node@^1.10.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/deepl-node/-/deepl-node-1.10.2.tgz#35d8af9b54b5a1026685bfbe9f7f7667599f1c12" - integrity sha512-MWif2j54Cb0284FFNO8hJSGB2W9xfF0dfRICYicVtfM2FF1ClSU7Fqdf4ct27i5H9YLe32PLvbcwxVaaT+BiQQ== + version "1.11.0" + resolved "https://registry.yarnpkg.com/deepl-node/-/deepl-node-1.11.0.tgz#69f90e8938eff34b86637afd5ff353186621c269" + integrity sha512-PLz38WIfWzVScbz4S+32vI9yCUAXy3cpkKSMPC+IDpvrwKrQ2TSzwkoBh7CJOkPjaX8ZMvjwAc+C5eTCPamQTg== dependencies: "@types/node" ">=12.0" - axios ">=0.21.2 <1.2.0 || >=1.2.1" + axios ">=0.21.2 <1.2.0 || >=1.2.2" form-data "^3.0.0" loglevel ">=1.6.2" @@ -3781,7 +3849,7 @@ deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-data-property@^1.0.1: +define-data-property@^1.0.1, define-data-property@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== @@ -3828,10 +3896,17 @@ detect-node@^2.0.4, detect-node@^2.1.0: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -devtools-protocol@0.0.1179426: - version "0.0.1179426" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1179426.tgz#c4c3ee671efae868395569123002facbbbffa267" - integrity sha512-KKC7IGwdOr7u9kTGgjUvGTov/z1s2H7oHi3zKCdR9eSDyCPia5CBi4aRhtp7d8uR7l0GS5UTDw3TjKGu5CqINg== +devlop@^1.0.0, devlop@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" + +devtools-protocol@0.0.1203626: + version "0.0.1203626" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1203626.tgz#4366a4c81a7e0d4fd6924e9182c67f1e5941e820" + integrity sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g== didyoumean@^1.2.2: version "1.2.2" @@ -3970,9 +4045,9 @@ ecc-jsbn@~0.1.1: safer-buffer "^2.1.0" electron-to-chromium@^1.4.535: - version "1.4.559" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.559.tgz#050483c22c5eb2345017a8976a67b060559a33f4" - integrity sha512-iS7KhLYCSJbdo3rUSkhDTVuFNCV34RKs2UaB9Ecr7VlqzjjWW//0nfsFF5dtDmyXlZQaDYYtID5fjtC/6lpRug== + version "1.4.576" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz#0c6940fdc0d60f7e34bd742b29d8fa847c9294d1" + integrity sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA== emoji-regex@^8.0.0: version "8.0.0" @@ -4061,25 +4136,25 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.22.1: - version "1.22.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" - integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== dependencies: array-buffer-byte-length "^1.0.0" arraybuffer.prototype.slice "^1.0.2" available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.5" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" function.prototype.name "^1.1.6" - get-intrinsic "^1.2.1" + get-intrinsic "^1.2.2" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" internal-slot "^1.0.5" is-array-buffer "^3.0.2" is-callable "^1.2.7" @@ -4089,7 +4164,7 @@ es-abstract@^1.22.1: is-string "^1.0.7" is-typed-array "^1.1.12" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.5.1" @@ -4103,9 +4178,9 @@ es-abstract@^1.22.1: typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.11" + which-typed-array "^1.1.13" -es-iterator-helpers@^1.0.12: +es-iterator-helpers@^1.0.12, es-iterator-helpers@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== @@ -4131,20 +4206,20 @@ es-module-lexer@^1.2.1: integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q== es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" + get-intrinsic "^1.2.2" has-tostringtag "^1.0.0" + hasown "^2.0.0" es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: - has "^1.0.3" + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -4214,12 +4289,12 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-config-next@13.5.4: - version "13.5.4" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.5.4.tgz#e50bb157d8346b63426f4b36bf53c2e46ccbc938" - integrity sha512-FzQGIj4UEszRX7fcRSJK6L1LrDiVZvDFW320VVntVKh3BSU8Fb9kpaoxQx0cdFgf3MQXdeSbrCXJ/5Z/NndDkQ== +eslint-config-next@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.0.2.tgz#bbcd7af62ed9700d9dd74c1b8538fdb9495d46ce" + integrity sha512-CasWThlsyIcg/a+clU6KVOMTieuDhTztsrqvniP6AsRki9v7FnojTa7vKQOYM8QSOsQdZ/aElLD1Y2Oc8/PsIg== dependencies: - "@next/eslint-plugin-next" "13.5.4" + "@next/eslint-plugin-next" "14.0.2" "@rushstack/eslint-patch" "^1.3.3" "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" eslint-import-resolver-node "^0.3.6" @@ -4239,7 +4314,7 @@ eslint-import-resolver-alias@^1.1.2: resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97" integrity sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w== -eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -4275,50 +4350,50 @@ eslint-plugin-cypress@^2.15.1: dependencies: globals "^13.20.0" -eslint-plugin-import@^2.28.1: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== +eslint-plugin-import@^2.28.1, eslint-plugin-import@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" + eslint-import-resolver-node "^0.3.9" eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" semver "^6.3.1" tsconfig-paths "^3.14.2" -eslint-plugin-jsx-a11y@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== - dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" +eslint-plugin-jsx-a11y@^6.7.1, eslint-plugin-jsx-a11y@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== + dependencies: + "@babel/runtime" "^7.23.2" + aria-query "^5.3.0" + array-includes "^3.1.7" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "=4.7.0" + axobject-query "^3.2.1" damerau-levenshtein "^1.0.8" emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" + es-iterator-helpers "^1.0.15" + hasown "^2.0.0" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" + object.entries "^1.1.7" + object.fromentries "^2.0.7" "eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705", eslint-plugin-react-hooks@^4.6.0: version "4.6.0" @@ -4373,18 +4448,19 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.50.0: - version "8.51.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" - integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== +eslint@^8.52.0: + version "8.53.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce" + integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.51.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/eslintrc" "^2.1.3" + "@eslint/js" "8.53.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -4454,43 +4530,44 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-util-attach-comments@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-2.1.1.tgz#ee44f4ff6890ee7dfb3237ac7810154c94c63f84" - integrity sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w== +estree-util-attach-comments@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz#344bde6a64c8a31d15231e5ee9e297566a691c2d" + integrity sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw== dependencies: "@types/estree" "^1.0.0" -estree-util-build-jsx@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-2.2.2.tgz#32f8a239fb40dc3f3dca75bb5dcf77a831e4e47b" - integrity sha512-m56vOXcOBuaF+Igpb9OPAy7f9w9OIkb5yhjsZuaPm7HoGi4oTOQi0h2+yZ+AtKklYFZ+rPC4n0wYCJCEU1ONqg== +estree-util-build-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz#b6d0bced1dcc4f06f25cf0ceda2b2dcaf98168f1" + integrity sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ== dependencies: "@types/estree-jsx" "^1.0.0" - estree-util-is-identifier-name "^2.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" estree-walker "^3.0.0" -estree-util-is-identifier-name@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.1.0.tgz#fb70a432dcb19045e77b05c8e732f1364b4b49b2" - integrity sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ== +estree-util-is-identifier-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz#0b5ef4c4ff13508b34dcd01ecfa945f61fce5dbd" + integrity sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg== -estree-util-to-js@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/estree-util-to-js/-/estree-util-to-js-1.2.0.tgz#0f80d42443e3b13bd32f7012fffa6f93603f4a36" - integrity sha512-IzU74r1PK5IMMGZXUVZbmiu4A1uhiPgW5hm1GjcOfr4ZzHaMPpLNJjR7HjXiIOzi25nZDrgFTobHTkV5Q6ITjA== +estree-util-to-js@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz#10a6fb924814e6abb62becf0d2bc4dea51d04f17" + integrity sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg== dependencies: "@types/estree-jsx" "^1.0.0" astring "^1.8.0" source-map "^0.7.0" -estree-util-visit@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.2.1.tgz#8bc2bc09f25b00827294703835aabee1cc9ec69d" - integrity sha512-xbgqcrkIVbIG+lI/gzbvd9SGTJL4zqJKBFttUl5pP27KhAjtMKbX/mQXJ7qgyXpMgVy/zvpm0xoQQaGL8OloOw== +estree-util-visit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-2.0.0.tgz#13a9a9f40ff50ed0c022f831ddf4b58d05446feb" + integrity sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww== dependencies: "@types/estree-jsx" "^1.0.0" - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" estree-walker@^2.0.2: version "2.0.2" @@ -4610,10 +4687,10 @@ fast-fifo@^1.1.0, fast-fifo@^1.2.0: resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -4834,7 +4911,7 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -4869,15 +4946,15 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + function-bind "^1.1.2" has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-stdin@^5.0.1: version "5.0.1" @@ -5108,11 +5185,11 @@ has-flag@^4.0.0: integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== dependencies: - get-intrinsic "^1.1.1" + get-intrinsic "^1.2.2" has-proto@^1.0.1: version "1.0.1" @@ -5131,36 +5208,56 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" - integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" -hast-util-to-estree@^2.0.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz#da60142ffe19a6296923ec222aba73339c8bf470" - integrity sha512-ihhPIUPxN0v0w6M5+IiAZZrn0LH2uZomeWwhn7uP7avZC6TE7lIiEh2yBMPr5+zi1aUCXq6VoYRgs2Bw9xmycQ== +hast-util-to-estree@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz#f2afe5e869ddf0cf690c75f9fc699f3180b51b19" + integrity sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw== dependencies: "@types/estree" "^1.0.0" "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/unist" "^2.0.0" + "@types/hast" "^3.0.0" comma-separated-tokens "^2.0.0" - estree-util-attach-comments "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - hast-util-whitespace "^2.0.0" - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdxjs-esm "^1.0.0" + devlop "^1.0.0" + estree-util-attach-comments "^3.0.0" + estree-util-is-identifier-name "^3.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" property-information "^6.0.0" space-separated-tokens "^2.0.0" - style-to-object "^0.4.1" - unist-util-position "^4.0.0" + style-to-object "^0.4.0" + unist-util-position "^5.0.0" zwitch "^2.0.0" -hast-util-whitespace@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz#0ec64e257e6fc216c7d14c8a1b74d27d650b4557" - integrity sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng== +hast-util-to-jsx-runtime@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.2.0.tgz#ffd59bfcf0eb8321c6ed511bfc4b399ac3404bc2" + integrity sha512-wSlp23N45CMjDg/BPW8zvhEi3R+8eRE1qFbjEyAUzMCzu2l1Wzwakq+Tlia9nkCtEl5mDxa7nKHsvYJ6Gfn21A== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-whitespace "^3.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.4.0" + unist-util-position "^5.0.0" + vfile-message "^4.0.0" + +hast-util-whitespace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz#7778ed9d3c92dd9e8c5c8f648a49c21fc51cb621" + integrity sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw== + dependencies: + "@types/hast" "^3.0.0" he@^1.2.0: version "1.2.0" @@ -5214,6 +5311,11 @@ html-to-image@^1.11.11: resolved "https://registry.yarnpkg.com/html-to-image/-/html-to-image-1.11.11.tgz#c0f8a34dc9e4b97b93ff7ea286eb8562642ebbea" integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA== +html-url-attributes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" + integrity sha512-/sXbVCWayk6GDVg3ctOX6nxaVj7So40FcFAnWlWGNAB1LpYKcV5Cd10APjPjW80O7zYW2MsjBV4zZ7IZO5fVow== + html-webpack-plugin@^5.5.3: version "5.5.3" resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" @@ -5288,12 +5390,12 @@ humanize-duration@^3.27.3: resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.30.0.tgz#9be623d331116583ff90aeb6ccfdc2e79d6d7372" integrity sha512-NxpT0fhQTFuMTLnuu1Xp+ozNpYirQnbV3NlOjEKBYlE3uvMRu3LDuq8EPc3gVXxVYnchQfqVM4/+T9iwHPLLeA== -i18next-browser-languagedetector@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz#01876fac51f86b78975e79b48ccb62e2313a2d7d" - integrity sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA== +i18next-browser-languagedetector@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.0.tgz#de0321cba6881be37d82e20e4d6f05aa75f6e37f" + integrity sha512-U00DbDtFIYD3wkWsr2aVGfXGAj2TgnELzOX9qv8bT0aJtvPV9CRO77h+vgmHFBMe7LAxdwvT/7VkCWGya6L3tA== dependencies: - "@babel/runtime" "^7.19.4" + "@babel/runtime" "^7.23.2" i18next-parser@^8.8.0: version "8.9.0" @@ -5318,12 +5420,12 @@ i18next-parser@^8.8.0: vinyl-fs "^4.0.0" vue-template-compiler "^2.6.11" -i18next-resources-to-backend@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/i18next-resources-to-backend/-/i18next-resources-to-backend-1.1.4.tgz#d139ca0cacc270dcc90b7926e192f4cd5aa4db60" - integrity sha512-hMyr9AOmIea17AOaVe1srNxK/l3mbk81P7Uf3fdcjlw3ehZy3UNTd0OP3EEi6yu4J02kf9jzhCcjokz6AFlEOg== +i18next-resources-to-backend@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/i18next-resources-to-backend/-/i18next-resources-to-backend-1.2.0.tgz#4e0ea0c093bf1acb3eb47972a3002b84a1fec3b2" + integrity sha512-8f1l03s+QxDmCfpSXCh9V+AFcxAwIp0UaroWuyOx+hmmv8484GcELHs+lnu54FrNij8cDBEXvEwhzZoXsKcVpg== dependencies: - "@babel/runtime" "^7.21.5" + "@babel/runtime" "^7.23.2" i18next@^23.5.1: version "23.6.0" @@ -5332,6 +5434,13 @@ i18next@^23.5.1: dependencies: "@babel/runtime" "^7.22.5" +i18next@^23.7.6: + version "23.7.6" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.7.6.tgz#7328e76c899052d5d33d930164612dd21e575f74" + integrity sha512-O66BhXBw0fH4bEJMA0/klQKPEbcwAp5wjXEL803pdAynNbg2f4qhLIYlNHJyE7icrL6XmSZKPYaaXwy11kJ6YQ== + dependencies: + "@babel/runtime" "^7.23.2" + iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -5406,12 +5515,12 @@ inline-style-parser@0.1.1: integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + get-intrinsic "^1.2.2" + hasown "^2.0.0" side-channel "^1.0.4" "internmap@1 - 2": @@ -5517,12 +5626,12 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-core-module@^2.11.0, is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -5848,12 +5957,12 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jiti@^1.18.2: - version "1.20.0" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" - integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== +jiti@^1.18.2, jiti@^1.19.1: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== -joi@^17.7.0: +joi@^17.11.0: version "17.11.0" resolved "https://registry.yarnpkg.com/joi/-/joi-17.11.0.tgz#aa9da753578ec7720e6f0ca2c7046996ed04fc1a" integrity sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ== @@ -5938,12 +6047,15 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" - integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== +json-stable-stringify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz#43d39c7c8da34bfaf785a61a56808b0def9f747d" + integrity sha512-zfA+5SuwYN2VWqN1/5HZaDzQKLJHaBVMZIIM+wuYjdptkaQsqzDdqjqf+lZZJUuJq1aanHiY8LhH8LmH+qBYJA== dependencies: + call-bind "^1.0.5" + isarray "^2.0.5" jsonify "^0.0.1" + object-keys "^1.1.1" json-stringify-safe@~5.0.1: version "5.0.1" @@ -6009,7 +6121,7 @@ jsprim@^2.0.2: json-schema "0.4.0" verror "1.10.0" -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== @@ -6043,17 +6155,17 @@ lambdafs@^2.0.3: dependencies: tar-fs "^2.1.1" -language-subtag-registry@~0.3.2: +language-subtag-registry@^0.3.20: version "0.3.22" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== dependencies: - language-subtag-registry "~0.3.2" + language-subtag-registry "^0.3.20" lazy-ass@^1.6.0: version "1.6.0" @@ -6234,11 +6346,6 @@ lru-cache@^7.14.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== -lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - magic-string@^0.27.0: version "0.27.0" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" @@ -6251,10 +6358,10 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -markdown-extensions@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-1.1.1.tgz#fea03b539faeaee9b4ef02a3769b455b189f7fc3" - integrity sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q== +markdown-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-2.0.0.tgz#34bebc83e9938cae16e0e017e4a9814a8330d3c4" + integrity sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q== markdown-to-jsx@^7.3.2: version "7.3.2" @@ -6282,15 +6389,6 @@ material-colors@^1.2.1: resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== -mdast-util-definitions@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz#9910abb60ac5d7115d6819b57ae0bcef07a3f7a7" - integrity sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" - mdast-util-footnote@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/mdast-util-footnote/-/mdast-util-footnote-1.1.1.tgz#6105aa168ebfd14e2c4f86ae9252b1f063ca8050" @@ -6300,74 +6398,77 @@ mdast-util-footnote@^1.0.0: mdast-util-to-markdown "^1.0.0" micromark-util-normalize-identifier "^1.0.0" -mdast-util-from-markdown@^1.0.0, mdast-util-from-markdown@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0" - integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww== +mdast-util-from-markdown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz#52f14815ec291ed061f2922fd14d6689c810cb88" + integrity sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA== dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" decode-named-character-reference "^1.0.0" - mdast-util-to-string "^3.1.0" - micromark "^3.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-decode-string "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-stringify-position "^3.0.0" - uvu "^0.5.0" + devlop "^1.0.0" + mdast-util-to-string "^4.0.0" + micromark "^4.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-decode-string "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-stringify-position "^4.0.0" -mdast-util-mdx-expression@^1.0.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.3.2.tgz#d027789e67524d541d6de543f36d51ae2586f220" - integrity sha512-xIPmR5ReJDu/DHH1OoIT1HkuybIfRGYRywC+gJtI7qHjCJp/M9jrmBEJW22O8lskDWm562BX2W8TiAwRTb0rKA== +mdast-util-mdx-expression@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz#4968b73724d320a379110d853e943a501bfd9d87" + integrity sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw== dependencies: "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-mdx-jsx@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.1.4.tgz#7c1f07f10751a78963cfabee38017cbc8b7786d1" - integrity sha512-DtMn9CmVhVzZx3f+optVDF8yFgQVt7FghCRNdlIaS3X5Bnym3hZwPbg/XW86vdpKjlc1PVj26SpnLGeJBXD3JA== +mdast-util-mdx-jsx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.0.0.tgz#f73631fa5bb7a36712ff1e9cedec0cafed03401c" + integrity sha512-XZuPPzQNBPAlaqsTTgRrcJnyFbSOBovSadFgbFu8SnuNgm+6Bdx1K+IWoitsmj6Lq6MNtI+ytOqwN70n//NaBA== dependencies: "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" ccount "^2.0.0" - mdast-util-from-markdown "^1.1.0" - mdast-util-to-markdown "^1.3.0" + devlop "^1.1.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" parse-entities "^4.0.0" stringify-entities "^4.0.0" - unist-util-remove-position "^4.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" + unist-util-remove-position "^5.0.0" + unist-util-stringify-position "^4.0.0" + vfile-message "^4.0.0" -mdast-util-mdx@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.1.tgz#49b6e70819b99bb615d7223c088d295e53bb810f" - integrity sha512-38w5y+r8nyKlGvNjSEqWrhG0w5PmnRA+wnBvm+ulYCct7nsGYhFVb0lljS9bQav4psDAS1eGkP2LMVcZBi/aqw== +mdast-util-mdx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz#792f9cf0361b46bee1fdf1ef36beac424a099c41" + integrity sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w== dependencies: - mdast-util-from-markdown "^1.0.0" - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdx-jsx "^2.0.0" - mdast-util-mdxjs-esm "^1.0.0" - mdast-util-to-markdown "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-mdx-expression "^2.0.0" + mdast-util-mdx-jsx "^3.0.0" + mdast-util-mdxjs-esm "^2.0.0" + mdast-util-to-markdown "^2.0.0" -mdast-util-mdxjs-esm@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.3.1.tgz#645d02cd607a227b49721d146fd81796b2e2d15b" - integrity sha512-SXqglS0HrEvSdUEfoXFtcg7DRl7S2cwOXc7jkuusG472Mmjag34DUDeOJUZtl+BVnyeO1frIgVpHlNRWc2gk/w== +mdast-util-mdxjs-esm@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz#019cfbe757ad62dd557db35a695e7314bcc9fa97" + integrity sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg== dependencies: "@types/estree-jsx" "^1.0.0" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" mdast-util-phrasing@^3.0.0: version "3.0.1" @@ -6377,21 +6478,29 @@ mdast-util-phrasing@^3.0.0: "@types/mdast" "^3.0.0" unist-util-is "^5.0.0" -mdast-util-to-hast@^12.1.0: - version "12.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz#045d2825fb04374e59970f5b3f279b5700f6fb49" - integrity sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw== +mdast-util-phrasing@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-4.0.0.tgz#468cbbb277375523de807248b8ad969feb02a5c7" + integrity sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA== dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-definitions "^5.0.0" - micromark-util-sanitize-uri "^1.1.0" + "@types/mdast" "^4.0.0" + unist-util-is "^6.0.0" + +mdast-util-to-hast@^13.0.0: + version "13.0.2" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.0.2.tgz#74c0a9f014bb2340cae6118f6fccd75467792be7" + integrity sha512-U5I+500EOOw9e3ZrclN3Is3fRpw8c19SMyNZlZ2IS+7vLsNzb2Om11VpIVOR+/0137GhZsFEF6YiKD5+0Hr2Og== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@ungap/structured-clone" "^1.0.0" + devlop "^1.0.0" + micromark-util-sanitize-uri "^2.0.0" trim-lines "^3.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" -mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: +mdast-util-to-markdown@^1.0.0: version "1.5.0" resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz#c13343cb3fc98621911d33b5cd42e7d0731171c6" integrity sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A== @@ -6405,13 +6514,34 @@ mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: unist-util-visit "^4.0.0" zwitch "^2.0.0" -mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: +mdast-util-to-markdown@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz#9813f1d6e0cdaac7c244ec8c6dabfdb2102ea2b4" + integrity sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + longest-streak "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-string "^4.0.0" + micromark-util-decode-string "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + +mdast-util-to-string@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789" integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg== dependencies: "@types/mdast" "^3.0.0" +mdast-util-to-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814" + integrity sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg== + dependencies: + "@types/mdast" "^4.0.0" + mdn-data@2.0.28: version "2.0.28" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" @@ -6432,7 +6562,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: +micromark-core-commonmark@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8" integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw== @@ -6454,6 +6584,28 @@ micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: micromark-util-types "^1.0.1" uvu "^0.5.0" +micromark-core-commonmark@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz#50740201f0ee78c12a675bf3e68ffebc0bf931a3" + integrity sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA== + dependencies: + decode-named-character-reference "^1.0.0" + devlop "^1.0.0" + micromark-factory-destination "^2.0.0" + micromark-factory-label "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-factory-title "^2.0.0" + micromark-factory-whitespace "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-classify-character "^2.0.0" + micromark-util-html-tag-name "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-extension-footnote@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/micromark-extension-footnote/-/micromark-extension-footnote-1.0.2.tgz#534c42211315406b43625fa29573c7094d5122c2" @@ -6468,71 +6620,71 @@ micromark-extension-footnote@^1.0.0: micromark-util-symbol "^1.0.0" uvu "^0.5.0" -micromark-extension-mdx-expression@^1.0.0: - version "1.0.8" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.8.tgz#5bc1f5fd90388e8293b3ef4f7c6f06c24aff6314" - integrity sha512-zZpeQtc5wfWKdzDsHRBY003H2Smg+PUi2REhqgIhdzAa5xonhP03FcXxqFSerFiNUr5AWmHpaNPQTBVOS4lrXw== +micromark-extension-mdx-expression@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz#1407b9ce69916cf5e03a196ad9586889df25302a" + integrity sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ== dependencies: "@types/estree" "^1.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - -micromark-extension-mdx-jsx@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.5.tgz#e72d24b7754a30d20fb797ece11e2c4e2cae9e82" - integrity sha512-gPH+9ZdmDflbu19Xkb8+gheqEDqkSpdCEubQyxuz/Hn8DOXiXvrXeikOoBA71+e8Pfi0/UYmU3wW3H58kr7akA== + devlop "^1.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-extension-mdx-jsx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz#4aba0797c25efb2366a3fd2d367c6b1c1159f4f5" + integrity sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w== dependencies: "@types/acorn" "^4.0.0" "@types/estree" "^1.0.0" - estree-util-is-identifier-name "^2.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + devlop "^1.0.0" + estree-util-is-identifier-name "^3.0.0" + micromark-factory-mdx-expression "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" -micromark-extension-mdx-md@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.1.tgz#595d4b2f692b134080dca92c12272ab5b74c6d1a" - integrity sha512-7MSuj2S7xjOQXAjjkbjBsHkMtb+mDGVW6uI2dBL9snOBCbZmoNgDAeZ0nSn9j3T42UE/g2xVNMn18PJxZvkBEA== +micromark-extension-mdx-md@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz#1d252881ea35d74698423ab44917e1f5b197b92d" + integrity sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ== dependencies: - micromark-util-types "^1.0.0" + micromark-util-types "^2.0.0" -micromark-extension-mdxjs-esm@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.5.tgz#e4f8be9c14c324a80833d8d3a227419e2b25dec1" - integrity sha512-xNRBw4aoURcyz/S69B19WnZAkWJMxHMT5hE36GtDAyhoyn/8TuAeqjFJQlwk+MKQsUD7b3l7kFX+vlfVWgcX1w== +micromark-extension-mdxjs-esm@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz#de21b2b045fd2059bd00d36746081de38390d54a" + integrity sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A== dependencies: "@types/estree" "^1.0.0" - micromark-core-commonmark "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.1.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" -micromark-extension-mdxjs@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.1.tgz#f78d4671678d16395efeda85170c520ee795ded8" - integrity sha512-7YA7hF6i5eKOfFUzZ+0z6avRG52GpWR8DL+kN47y3f2KhxbBZMhmxe7auOeaTBrW2DenbbZTf1ea9tA2hDpC2Q== +micromark-extension-mdxjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz#b5a2e0ed449288f3f6f6c544358159557549de18" + integrity sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ== dependencies: acorn "^8.0.0" acorn-jsx "^5.0.0" - micromark-extension-mdx-expression "^1.0.0" - micromark-extension-mdx-jsx "^1.0.0" - micromark-extension-mdx-md "^1.0.0" - micromark-extension-mdxjs-esm "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" + micromark-extension-mdx-expression "^3.0.0" + micromark-extension-mdx-jsx "^3.0.0" + micromark-extension-mdx-md "^2.0.0" + micromark-extension-mdxjs-esm "^3.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-types "^2.0.0" micromark-factory-destination@^1.0.0: version "1.1.0" @@ -6543,6 +6695,15 @@ micromark-factory-destination@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-destination@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz#857c94debd2c873cba34e0445ab26b74f6a6ec07" + integrity sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-label@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68" @@ -6553,19 +6714,29 @@ micromark-factory-label@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" -micromark-factory-mdx-expression@^1.0.0: - version "1.0.9" - resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.9.tgz#57ba4571b69a867a1530f34741011c71c73a4976" - integrity sha512-jGIWzSmNfdnkJq05c7b0+Wv0Kfz3NJ3N4cBjnbO4zjXIlxJr+f8lk+5ZmwFvqdAbUy2q6B5rCY//g0QAAaXDWA== +micromark-factory-label@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz#17c5c2e66ce39ad6f4fc4cbf40d972f9096f726a" + integrity sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw== + dependencies: + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-factory-mdx-expression@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz#f2a9724ce174f1751173beb2c1f88062d3373b1b" + integrity sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg== dependencies: "@types/estree" "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + devlop "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-events-to-acorn "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + unist-util-position-from-estree "^2.0.0" + vfile-message "^4.0.0" micromark-factory-space@^1.0.0: version "1.1.0" @@ -6575,6 +6746,14 @@ micromark-factory-space@^1.0.0: micromark-util-character "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-space@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz#5e7afd5929c23b96566d0e1ae018ae4fcf81d030" + integrity sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-title@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1" @@ -6585,6 +6764,16 @@ micromark-factory-title@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-title@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz#726140fc77892af524705d689e1cf06c8a83ea95" + integrity sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-factory-whitespace@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705" @@ -6595,6 +6784,16 @@ micromark-factory-whitespace@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-factory-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz#9e92eb0f5468083381f923d9653632b3cfb5f763" + integrity sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA== + dependencies: + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-character@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc" @@ -6603,6 +6802,14 @@ micromark-util-character@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" +micromark-util-character@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.0.1.tgz#52b824c2e2633b6fb33399d2ec78ee2a90d6b298" + integrity sha512-3wgnrmEAJ4T+mGXAUfMvMAbxU9RDG43XmGce4j6CwPtVxB3vfwXSZ6KhFwDzZ3mZHhmPimMAXg71veiBGzeAZw== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-chunked@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b" @@ -6610,6 +6817,13 @@ micromark-util-chunked@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-chunked@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz#e51f4db85fb203a79dbfef23fd41b2f03dc2ef89" + integrity sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-classify-character@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d" @@ -6619,13 +6833,22 @@ micromark-util-classify-character@^1.0.0: micromark-util-symbol "^1.0.0" micromark-util-types "^1.0.0" -micromark-util-combine-extensions@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84" - integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA== +micromark-util-classify-character@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz#8c7537c20d0750b12df31f86e976d1d951165f34" + integrity sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw== dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-types "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + +micromark-util-combine-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz#75d6ab65c58b7403616db8d6b31315013bfb7ee5" + integrity sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ== + dependencies: + micromark-util-chunked "^2.0.0" + micromark-util-types "^2.0.0" micromark-util-decode-numeric-character-reference@^1.0.0: version "1.1.0" @@ -6634,6 +6857,13 @@ micromark-util-decode-numeric-character-reference@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-decode-numeric-character-reference@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz#2698bbb38f2a9ba6310e359f99fcb2b35a0d2bd5" + integrity sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-decode-string@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c" @@ -6644,30 +6874,45 @@ micromark-util-decode-string@^1.0.0: micromark-util-decode-numeric-character-reference "^1.0.0" micromark-util-symbol "^1.0.0" -micromark-util-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5" - integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw== +micromark-util-decode-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz#7dfa3a63c45aecaa17824e656bcdb01f9737154a" + integrity sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-symbol "^2.0.0" -micromark-util-events-to-acorn@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.3.tgz#a4ab157f57a380e646670e49ddee97a72b58b557" - integrity sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w== +micromark-util-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1" + integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA== + +micromark-util-events-to-acorn@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz#4275834f5453c088bd29cd72dfbf80e3327cec07" + integrity sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA== dependencies: "@types/acorn" "^4.0.0" "@types/estree" "^1.0.0" - "@types/unist" "^2.0.0" - estree-util-visit "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + estree-util-visit "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + vfile-message "^4.0.0" micromark-util-html-tag-name@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588" integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q== +micromark-util-html-tag-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz#ae34b01cbe063363847670284c6255bb12138ec4" + integrity sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw== + micromark-util-normalize-identifier@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7" @@ -6675,6 +6920,13 @@ micromark-util-normalize-identifier@^1.0.0: dependencies: micromark-util-symbol "^1.0.0" +micromark-util-normalize-identifier@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz#91f9a4e65fe66cc80c53b35b0254ad67aa431d8b" + integrity sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w== + dependencies: + micromark-util-symbol "^2.0.0" + micromark-util-resolve-all@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188" @@ -6682,14 +6934,21 @@ micromark-util-resolve-all@^1.0.0: dependencies: micromark-util-types "^1.0.0" -micromark-util-sanitize-uri@^1.0.0, micromark-util-sanitize-uri@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d" - integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A== +micromark-util-resolve-all@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz#189656e7e1a53d0c86a38a652b284a252389f364" + integrity sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA== dependencies: - micromark-util-character "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-symbol "^1.0.0" + micromark-util-types "^2.0.0" + +micromark-util-sanitize-uri@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de" + integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw== + dependencies: + micromark-util-character "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-symbol "^2.0.0" micromark-util-subtokenize@^1.0.0: version "1.1.0" @@ -6701,38 +6960,58 @@ micromark-util-subtokenize@^1.0.0: micromark-util-types "^1.0.0" uvu "^0.5.0" +micromark-util-subtokenize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz#9f412442d77e0c5789ffdf42377fa8a2bcbdf581" + integrity sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg== + dependencies: + devlop "^1.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" + micromark-util-symbol@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142" integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== +micromark-util-symbol@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044" + integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw== + micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283" integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== -micromark@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9" - integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA== +micromark-util-types@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e" + integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w== + +micromark@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-4.0.0.tgz#84746a249ebd904d9658cfabc1e8e5f32cbc6249" + integrity sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ== dependencies: "@types/debug" "^4.0.0" debug "^4.0.0" decode-named-character-reference "^1.0.0" - micromark-core-commonmark "^1.0.1" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" + devlop "^1.0.0" + micromark-core-commonmark "^2.0.0" + micromark-factory-space "^2.0.0" + micromark-util-character "^2.0.0" + micromark-util-chunked "^2.0.0" + micromark-util-combine-extensions "^2.0.0" + micromark-util-decode-numeric-character-reference "^2.0.0" + micromark-util-encode "^2.0.0" + micromark-util-normalize-identifier "^2.0.0" + micromark-util-resolve-all "^2.0.0" + micromark-util-sanitize-uri "^2.0.0" + micromark-util-subtokenize "^2.0.0" + micromark-util-symbol "^2.0.0" + micromark-util-types "^2.0.0" micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" @@ -6788,7 +7067,7 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -6852,9 +7131,9 @@ nano-time@1.0.0: big-integer "^1.6.16" nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== napi-build-utils@^1.0.1: version "1.0.2" @@ -6889,12 +7168,12 @@ next-i18n-router@^4.1.1: "@formatjs/intl-localematcher" "^0.2.32" negotiator "^0.6.3" -next@^13.5.4: - version "13.5.6" - resolved "https://registry.yarnpkg.com/next/-/next-13.5.6.tgz#e964b5853272236c37ce0dd2c68302973cf010b1" - integrity sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw== +next@14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/next/-/next-14.0.2.tgz#02ba6a1656edf14d3913c7a3553026e9d6e083c7" + integrity sha512-jsAU2CkYS40GaQYOiLl9m93RTv2DA/tTJ0NRlmZIBIL87YwQ/xR8k796z7IqgM3jydI8G25dXvyYMC9VDIevIg== dependencies: - "@next/env" "13.5.6" + "@next/env" "14.0.2" "@swc/helpers" "0.5.2" busboy "1.6.0" caniuse-lite "^1.0.30001406" @@ -6902,15 +7181,15 @@ next@^13.5.4: styled-jsx "5.1.1" watchpack "2.4.0" optionalDependencies: - "@next/swc-darwin-arm64" "13.5.6" - "@next/swc-darwin-x64" "13.5.6" - "@next/swc-linux-arm64-gnu" "13.5.6" - "@next/swc-linux-arm64-musl" "13.5.6" - "@next/swc-linux-x64-gnu" "13.5.6" - "@next/swc-linux-x64-musl" "13.5.6" - "@next/swc-win32-arm64-msvc" "13.5.6" - "@next/swc-win32-ia32-msvc" "13.5.6" - "@next/swc-win32-x64-msvc" "13.5.6" + "@next/swc-darwin-arm64" "14.0.2" + "@next/swc-darwin-x64" "14.0.2" + "@next/swc-linux-arm64-gnu" "14.0.2" + "@next/swc-linux-arm64-musl" "14.0.2" + "@next/swc-linux-x64-gnu" "14.0.2" + "@next/swc-linux-x64-musl" "14.0.2" + "@next/swc-win32-arm64-msvc" "14.0.2" + "@next/swc-win32-ia32-msvc" "14.0.2" + "@next/swc-win32-x64-msvc" "14.0.2" no-case@^3.0.4: version "3.0.4" @@ -7013,10 +7292,10 @@ object-hash@^3.0.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.0.tgz#42695d3879e1cd5bda6df5062164d80c996e23e2" - integrity sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-keys@^1.1.1: version "1.1.1" @@ -7033,7 +7312,7 @@ object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6: +object.entries@^1.1.6, object.entries@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.7.tgz#2b47760e2a2e3a752f39dd874655c61a7f03c131" integrity sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA== @@ -7042,7 +7321,7 @@ object.entries@^1.1.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.fromentries@^2.0.6: +object.fromentries@^2.0.6, object.fromentries@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== @@ -7051,7 +7330,7 @@ object.fromentries@^2.0.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.groupby@^1.0.0: +object.groupby@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== @@ -7069,7 +7348,7 @@ object.hasown@^1.1.2: define-properties "^1.2.0" es-abstract "^1.22.1" -object.values@^1.1.6: +object.values@^1.1.6, object.values@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== @@ -7401,25 +7680,25 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-plugin-organize-imports@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz#6b0141ac71f7ee9a673ce83e95456319e3a7cf0d" - integrity sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg== +prettier-plugin-organize-imports@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e" + integrity sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog== -prettier-plugin-tailwindcss@0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.5.tgz#2860de31772235231339ca5e8c745969532fab95" - integrity sha512-voy0CjWv/CM8yeaduv5ZwovovpTGMR5LbzlhGF+LtEvMJt9wBeVTVnW781hL38R/RcDXCJwN2rolsgr94B/n0Q== +prettier-plugin-tailwindcss@0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.7.tgz#d05dc42c6f2167e3bf2c20e9f71a1fff4232b5d9" + integrity sha512-4v6uESAgwCni6YF6DwJlRaDjg9Z+al5zM4JfngcazMy4WEf/XkPS5TEQjbD+DZ5iNuG6RrKQLa/HuX2SYzC3kQ== prettier@^2.8.7: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" - integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== +prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== pretty-bytes@^5.6.0: version "5.6.0" @@ -7480,9 +7759,9 @@ prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: react-is "^16.13.1" property-information@^6.0.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.3.0.tgz#ba4a06ec6b4e1e90577df9931286953cdf4282c3" - integrity sha512-gVNZ74nqhRMiIUYWGQdosYetaKc83x8oT41a0LlV3AAFCAZwCpg4vmGkq8t34+cUhp3cnM4XDiU/7xlgK7HGrg== + version "6.4.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.4.0.tgz#6bc4c618b0c2d68b3bb8b552cbb97f8e300a0f82" + integrity sha512-9t5qARVofg2xQqKtytzt+lZ4d1Qvj8t5B8fEwXK6qOfgRLgH/b13QlgEyDh033NOS31nXeFbYv7CLUDG1CeifQ== proxy-agent@6.3.1: version "6.3.1" @@ -7539,20 +7818,20 @@ pump@^3.0.0: once "^1.3.1" punycode@^2.1.0, punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -puppeteer-core@^21.3.8: - version "21.3.8" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.3.8.tgz#7ac4879c9f73e8426431d8ca4c58680e517a4b08" - integrity sha512-yv12E/+zZ7Lei5tJB4sUkSrsuqKibuYpYxLGbmtLUjjYIqGE5HKz9OUI2I/RFHEvF+pHi2bTbv5bWydeCGJ6Mw== +puppeteer-core@^21.5.1: + version "21.5.1" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.5.1.tgz#36b0a4b3838f9109423b6e4cb56e1f21f8fbca4f" + integrity sha512-u6c3SZKAOaOQogaTkQvllxT/o2PP16wkbrUWINtMhfvrB4ko+xwqC1pb+vyCPMmNUh3N/CX5YGqb3DWx2fUPSQ== dependencies: - "@puppeteer/browsers" "1.7.1" - chromium-bidi "0.4.31" + "@puppeteer/browsers" "1.8.0" + chromium-bidi "0.4.33" cross-fetch "4.0.0" debug "4.3.4" - devtools-protocol "0.0.1179426" + devtools-protocol "0.0.1203626" ws "8.14.2" qrcode.react@^3.1.0: @@ -7649,10 +7928,10 @@ react-flip-toolkit@^7.1.0: flip-toolkit "7.1.0" prop-types "^15.8.1" -react-i18next@^13.2.2: - version "13.3.0" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.3.0.tgz#8e39c0101f654db7eb971f159bb55067a78925c3" - integrity sha512-FlR9xjYHSPIJfQspEmkN0yOlxgRyNuiJKJ8gCaZH08UJ7SZHG+VrptEPcpEMEchjNoCOZdKcvJ3PnmHEZhkeXg== +react-i18next@^13.4.1: + version "13.4.1" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-13.4.1.tgz#cc1fc0422b4652524c8f2f7856fa9b3db4c4dfae" + integrity sha512-z02JvLbt6Gavbuhr4CBOI6vasLypo+JSLvMgUOGeOMPv1g6spngfAb9jWAPwvuavPlKYU4dro9yRduflwyBeyA== dependencies: "@babel/runtime" "^7.22.5" html-parse-stringify "^3.0.1" @@ -7672,6 +7951,22 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-markdown@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-9.0.1.tgz#c05ddbff67fd3b3f839f8c648e6fb35d022397d1" + integrity sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.0.0" + hast-util-to-jsx-runtime "^2.0.0" + html-url-attributes "^3.0.0" + mdast-util-to-hast "^13.0.0" + remark-parse "^11.0.0" + remark-rehype "^11.0.0" + unified "^11.0.0" + unist-util-visit "^5.0.0" + vfile "^6.0.0" + react-number-format@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.3.1.tgz#840c257da9cb4b248990d8db46e4d23e8bac67ff" @@ -7793,10 +8088,10 @@ recharts-scale@^0.4.4: dependencies: decimal.js-light "^2.4.1" -recharts@^2.8.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.9.0.tgz#dde7531298cffe8677b1206967830d34f7972ea6" - integrity sha512-cVgiAU3W5UrA8nRRV/N0JrudgZzY/vjkzrlShbH+EFo1vs4nMlXgshZWLI0DfDLmn4/p4pF7Lq7F5PU+K94Ipg== +recharts@^2.9.3: + version "2.9.3" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.9.3.tgz#cb96105ba9c0b8d0fdb44613cbcbf8e0e5b505b3" + integrity sha512-B61sKrDlTxHvYwOCw8eYrD6rTA2a2hJg0avaY8qFI1ZYdHKvU18+J5u7sBMFg//wfJ/C5RL5+HsXt5e8tcJNLg== dependencies: classnames "^2.2.5" eventemitter3 "^4.0.1" @@ -7903,32 +8198,34 @@ remark-footnotes@^4.0.1: micromark-extension-footnote "^1.0.0" unified "^10.0.0" -remark-mdx@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.3.0.tgz#efe678025a8c2726681bde8bf111af4a93943db4" - integrity sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g== +remark-mdx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-3.0.0.tgz#146905a3925b078970e05fc89b0e16b9cc3bfddd" + integrity sha512-O7yfjuC6ra3NHPbRVxfflafAj3LTwx3b73aBvkEFU5z4PsD6FD4vrqJAkE5iNGLz71GdjXfgRqm3SQ0h0VuE7g== dependencies: - mdast-util-mdx "^2.0.0" - micromark-extension-mdxjs "^1.0.0" + mdast-util-mdx "^3.0.0" + micromark-extension-mdxjs "^3.0.0" -remark-parse@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.2.tgz#ca241fde8751c2158933f031a4e3efbaeb8bc262" - integrity sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw== +remark-parse@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-11.0.0.tgz#aa60743fcb37ebf6b069204eb4da304e40db45a1" + integrity sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA== dependencies: - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - unified "^10.0.0" + "@types/mdast" "^4.0.0" + mdast-util-from-markdown "^2.0.0" + micromark-util-types "^2.0.0" + unified "^11.0.0" -remark-rehype@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" - integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== +remark-rehype@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-11.0.0.tgz#7f21c08738bde024be5f16e4a8b13e5d7a04cf6b" + integrity sha512-vx8x2MDMcxuE4lBmQ46zYUDfcFMmvg80WYX+UNLeG6ixjdCCLcw1lrgAukwBTuOFsS78eoAedHGn9sNM0w7TPw== dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-to-hast "^12.1.0" - unified "^10.0.0" + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + mdast-util-to-hast "^13.0.0" + unified "^11.0.0" + vfile "^6.0.0" rematrix@0.2.2: version "0.2.2" @@ -8079,7 +8376,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.5.1, rxjs@^7.8.0: +rxjs@^7.5.1, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -8151,7 +8448,7 @@ section-matter@^1.0.0: extend-shallow "^2.0.1" kind-of "^6.0.0" -semver@^6.3.0, semver@^6.3.1: +semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -8170,6 +8467,16 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + set-function-name@^2.0.0, set-function-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" @@ -8374,9 +8681,9 @@ sprintf-js@~1.0.2: integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== sshpk@^1.14.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -8419,15 +8726,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.2, streamx@^2.14.0: - version "2.15.2" - resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.2.tgz#680eacebdc9c43ede7362c2e6695b34dd413c741" - integrity sha512-b62pAV/aeMjUoRN2C/9F0n+G8AfcJjNC0zw/ZmOHeFsIe4m4GzjVW9m6VHXVjk536NbdU9JRwKMJRfkc+zUFTg== - dependencies: - fast-fifo "^1.1.0" - queue-tick "^1.0.1" - -streamx@^2.15.0: +streamx@^2.12.0, streamx@^2.12.5, streamx@^2.13.2, streamx@^2.14.0, streamx@^2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" integrity sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA== @@ -8557,7 +8856,7 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -style-to-object@^0.4.1: +style-to-object@^0.4.0: version "0.4.4" resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.4.4.tgz#266e3dfd56391a7eefb7770423612d043c3f33ec" integrity sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg== @@ -8652,25 +8951,27 @@ symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1: resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== -tailwind-merge@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz#e677f55d864edc6794562c63f5001f45093cdb8b" - integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ== +tailwind-merge@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.0.0.tgz#a0f3a8c874ebae5feec5595614d08245a5f88a39" + integrity sha512-WO8qghn9yhsldLSg80au+3/gY9E4hFxIvQ3qOmlpXnqpDKoMruKfi/56BbbMg6fHTQJ9QD3cc79PoWqlaQE4rw== + dependencies: + "@babel/runtime" "^7.23.1" -tailwindcss@3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" - integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== +tailwindcss@3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8" + integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA== dependencies: "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.2.12" + fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - jiti "^1.18.2" + jiti "^1.19.1" lilconfig "^2.1.0" micromatch "^4.0.5" normalize-path "^3.0.0" @@ -8748,9 +9049,9 @@ terser-webpack-plugin@^5.3.7: terser "^5.16.8" terser@^5.10.0, terser@^5.16.8: - version "5.22.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.22.0.tgz#4f18103f84c5c9437aafb7a14918273310a8a49d" - integrity sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw== + version "5.24.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.24.0.tgz#4ae50302977bca4831ccc7b4fef63a3c04228364" + integrity sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -8872,10 +9173,10 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -translation-check@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/translation-check/-/translation-check-1.0.3.tgz#060d6110d600d8d223a44d606b50be91bd51a973" - integrity sha512-5xDwQIBEiNpndwB4nZlBW+iZeo7Pwd0f+ky3YIwCc8xmrvQIPjeVdHNHw8z9BjBYq68Gs+lrbFXwMy0dgtWmlw== +translation-check@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/translation-check/-/translation-check-1.1.0.tgz#6bf6c3e45a39ed7626a50e5438301d63b7c697c6" + integrity sha512-01WpBwJp+kKHBTME2bRHt4wXpMVwi6orEAV1pnuSneBrUJq0k/JO5kKQycvrb224/FFbkNlL3hw8gIiu7fwPvg== dependencies: "@babel/runtime" "7.21.0" @@ -8928,7 +9229,7 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3", tslib@^2.5.0, tslib@^2.6.2: +tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -9062,10 +9363,10 @@ underscore.string@~3.3.4: sprintf-js "^1.1.1" util-deprecate "^1.0.2" -undici-types@~5.25.1: - version "5.25.3" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" - integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" @@ -9103,10 +9404,18 @@ unified@^10.0.0: trough "^2.0.0" vfile "^5.0.0" -unist-util-generated@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" - integrity sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A== +unified@^11.0.0: + version "11.0.4" + resolved "https://registry.yarnpkg.com/unified/-/unified-11.0.4.tgz#f4be0ac0fe4c88cb873687c07c64c49ed5969015" + integrity sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ== + dependencies: + "@types/unist" "^3.0.0" + bail "^2.0.0" + devlop "^1.0.0" + extend "^3.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^6.0.0" unist-util-is@^5.0.0: version "5.2.1" @@ -9122,27 +9431,27 @@ unist-util-is@^6.0.0: dependencies: "@types/unist" "^3.0.0" -unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.2.tgz#8ac2480027229de76512079e377afbcabcfcce22" - integrity sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww== +unist-util-position-from-estree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz#d94da4df596529d1faa3de506202f0c9a23f2200" + integrity sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" -unist-util-position@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.4.tgz#93f6d8c7d6b373d9b825844645877c127455f037" - integrity sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg== +unist-util-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4" + integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA== dependencies: - "@types/unist" "^2.0.0" + "@types/unist" "^3.0.0" -unist-util-remove-position@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-4.0.2.tgz#a89be6ea72e23b1a402350832b02a91f6a9afe51" - integrity sha512-TkBb0HABNmxzAcfLf4qsIbFbaPDvMO6wa3b3j4VcEzFVaw1LBKwnW4/sRJ/atSLSzoIg41JWEdnE7N6DIhGDGQ== +unist-util-remove-position@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz#fea68a25658409c9460408bc6b4991b965b52163" + integrity sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q== dependencies: - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" + "@types/unist" "^3.0.0" + unist-util-visit "^5.0.0" unist-util-stringify-position@^3.0.0: version "3.0.3" @@ -9257,11 +9566,6 @@ urlpattern-polyfill@9.0.0: resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz#bc7e386bb12fd7898b58d1509df21d3c29ab3460" integrity sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g== -use-sync-external-store@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" - integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -9347,9 +9651,9 @@ vfile@^6.0.0: vfile-message "^4.0.0" victory-vendor@^36.6.8: - version "36.6.11" - resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.6.11.tgz#acae770717c2dae541a54929c304ecab5ab6ac2a" - integrity sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg== + version "36.6.12" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.6.12.tgz#17fa4d79d266a6e2bde0291c60c5002c55008164" + integrity sha512-pJrTkNHln+D83vDCCSUf0ZfxBvIaVrFHmrBOsnnLAbdqfudRACAj51He2zU94/IWq9464oTADcPVkmWAfNMwgA== dependencies: "@types/d3-array" "^3.0.3" "@types/d3-ease" "^3.0.0" @@ -9431,15 +9735,15 @@ vue-template-compiler@^2.6.11: he "^1.2.0" wait-on@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-7.0.1.tgz#5cff9f8427e94f4deacbc2762e6b0a489b19eae9" - integrity sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog== + version "7.1.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-7.1.0.tgz#3184ccfff7eb8a4d62ef3dfa6a4ff3675617ff60" + integrity sha512-U7TF/OYYzAg+OoiT/B8opvN48UHt0QYMi4aD3PjRFpybQ+o6czQF8Ig3SKCCMJdxpBrCalIJ4O00FBof27Fu9Q== dependencies: axios "^0.27.2" - joi "^17.7.0" + joi "^17.11.0" lodash "^4.17.21" - minimist "^1.2.7" - rxjs "^7.8.0" + minimist "^1.2.8" + rxjs "^7.8.1" walk-sync@^2.2.0: version "2.2.0" @@ -9551,13 +9855,13 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.11, which-typed-array@^1.1.9: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== dependencies: available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + call-bind "^1.0.4" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" @@ -9645,29 +9949,16 @@ yaml-loader@^0.8.0: yaml "^2.0.0" yaml@^2.0.0, yaml@^2.1.1, yaml@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" - integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - -yargs@^17.7.2: +yargs@17.7.2, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==