diff --git a/.eslintrc.js b/.eslintrc.js index 66c1bb990..a62eee29b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,19 @@ module.exports = { - extends: '@mate-academy/eslint-config', + extends: [ + '@mate-academy/eslint-config', + 'plugin:react/recommended', + 'plugin:react-hooks/recommended', + ], + parserOptions: { + ecmaVersion: 2021, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + settings: { + react: { + version: 'detect', + }, + }, }; diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 000000000..c2d320c59 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,44 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review, reopened] + # Optional: Only run on specific file changes + # paths: + # - "src/**/*.ts" + # - "src/**/*.tsx" + # - "src/**/*.js" + # - "src/**/*.jsx" + +jobs: + claude-review: + # Optional: Filter by PR author + # if: | + # github.event.pull_request.user.login == 'external-contributor' || + # github.event.pull_request.user.login == 'new-developer' || + # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' + + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + plugin_marketplaces: 'https://github.com/anthropics/claude-code.git' + plugins: 'code-review@claude-code-plugins' + prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}' + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 000000000..79fe05647 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,50 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude'))) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + actions: read # Required for Claude to read CI results on PRs + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + + # This is an optional setting that allows Claude to read CI results on PRs + additional_permissions: | + actions: read + + # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it. + # prompt: 'Update the pull request description to include a summary of changes.' + + # Optional: Add claude_args to customize behavior and configuration + # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md + # or https://code.claude.com/docs/en/cli-reference for available options + # claude_args: '--allowed-tools Bash(gh pr:*)' + diff --git a/.github/workflows/test.yml-template b/.github/workflows/test.yml-template new file mode 100644 index 000000000..8b5743ecb --- /dev/null +++ b/.github/workflows/test.yml-template @@ -0,0 +1,29 @@ +name: Test + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test + - name: Upload HTML report(backstop data) + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: report + path: backstop_data diff --git a/.gitignore b/.gitignore index 1558091fd..a371b2e59 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ backstop_data dist .cache .parcel-cache +CLAUDE.md \ No newline at end of file diff --git a/.parcelrc b/.parcelrc new file mode 100644 index 000000000..ec5e2dd2d --- /dev/null +++ b/.parcelrc @@ -0,0 +1,8 @@ +{ + "extends": "@parcel/config-default", + "transformers": { + "*.svg": ["@parcel/transformer-raw"], + "*.{png,jpg,jpeg,gif,webp,avif}": ["@parcel/transformer-raw"] + } +} + diff --git a/index.html b/index.html index d339e6856..010e9eeab 100644 --- a/index.html +++ b/index.html @@ -6,14 +6,43 @@ name="viewport" content="width=device-width, initial-scale=1.0" /> - Title + + + + + + NAMU -

Hello Mate Academy

- +
+ diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 000000000..e2720c00c --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@components/*": ["src/components/*"], + "@assets/*": ["src/assets/*"], + "@hooks/*": ["src/hooks/*"], + "@styles/*": ["src/styles/*"], + "@utils/*": ["src/utils/*"] + }, + "jsx": "react", + "module": "esnext", + "target": "esnext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "checkJs": false + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/package-lock.json b/package-lock.json index 5d3b07d5a..7d30ea6dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,20 @@ "version": "1.0.0", "hasInstallScript": true, "license": "GPL-3.0", + "dependencies": { + "chalk": "^5.6.2", + "i18next": "^25.7.2", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "react-i18next": "^16.4.0", + "react-router-dom": "^6.30.2" + }, "devDependencies": { "@linthtml/linthtml": "^0.9.6", "@mate-academy/eslint-config": "latest", "@mate-academy/jest-mochawesome-reporter": "^1.0.0", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^2.1.1", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/stylelint-config": "latest", "cypress": "^13.13.0", "eslint": "^8.57.0", @@ -460,6 +468,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -1455,6 +1472,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/core": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", @@ -1502,19 +1536,21 @@ } } }, - "node_modules/@jest/core/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/@jest/environment": { @@ -1632,6 +1668,23 @@ } } }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -1714,6 +1767,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", @@ -1731,6 +1801,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1798,6 +1885,23 @@ "table-layout": "1.0.1" } }, + "node_modules/@linthtml/cli/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/@linthtml/dom-utils": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@linthtml/dom-utils/-/dom-utils-0.9.5.tgz", @@ -1875,10 +1979,11 @@ "dev": true }, "node_modules/@mate-academy/scripts": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.2.tgz", - "integrity": "sha512-gUXFdqqOfYzF9R3RSx2pCa5GLdOkxB9bFbF+dpUpzucdgGAANqOGdqpmNnMj+e3xA9YHraUWq3xo9cwe5vD9pQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.3.tgz", + "integrity": "sha512-a07wHTj/1QUK2Aac5zHad+sGw4rIvcNl5lJmJpAD7OxeSbnCdyI6RXUHwXhjF5MaVo9YHrJ0xVahyERS2IIyBQ==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", @@ -2592,395 +2697,100 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, + "node_modules/@remix-run/router": { + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz", + "integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==", + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" + "node": ">=14.0.0" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", - "cpu": [ - "arm64" - ], + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "type-detect": "4.0.8" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", - "cpu": [ - "arm64" - ], + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", - "cpu": [ - "x64" - ], + "node_modules/@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", "dev": true, - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", - "cpu": [ - "arm64" - ], + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "type-detect": "4.0.8" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", + "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", + "dev": true }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", - "cpu": [ - "arm" - ], + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 10" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", - "cpu": [ - "arm" - ], + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", - "cpu": [ - "arm64" - ], + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@babel/types": "^7.0.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", - "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", - "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", - "dev": true - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -3588,6 +3398,23 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -4010,16 +3837,12 @@ "dev": true }, "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -4338,6 +4161,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -4486,6 +4326,51 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, + "node_modules/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/ci-info": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", + "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/cypress/node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -5568,52 +5453,124 @@ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">= 8" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "ms": "2.1.2" }, "engines": { - "node": ">=6" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -6756,6 +6713,15 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", @@ -6837,6 +6803,37 @@ "node": ">=8.12.0" } }, + "node_modules/i18next": { + "version": "25.7.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.7.2.tgz", + "integrity": "sha512-58b4kmLpLv1buWUEwegMDUqZVR5J+rT+WTRFaBGL7lxDuJQQ0NrJFrq+eT2N94aYVR1k1Sr13QITNOL88tZCuw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", @@ -6999,6 +6996,23 @@ "node": ">=12.0.0" } }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -7746,10 +7760,27 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { "@jest/core": "^29.7.0", @@ -7824,19 +7855,21 @@ } } }, - "node_modules/jest-config/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-diff": { @@ -7854,6 +7887,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-docblock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", @@ -7882,6 +7932,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-environment-jsdom": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", @@ -7988,6 +8055,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-message-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", @@ -8008,6 +8092,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", @@ -8081,6 +8182,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-runner": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", @@ -8113,6 +8231,38 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", @@ -8146,6 +8296,32 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", @@ -8177,16 +8353,21 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-util": { @@ -8206,19 +8387,21 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/jest-validate": { @@ -8250,6 +8433,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-watcher": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", @@ -8269,6 +8469,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jest-worker": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", @@ -8299,6 +8516,56 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8701,6 +8968,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/log-update": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", @@ -9756,6 +10040,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ordered-binary": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.3.tgz", + "integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==", + "dev": true + }, "node_modules/os-name": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", @@ -10436,12 +10743,101 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/react": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", + "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.1" + } + }, + "node_modules/react-i18next": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.4.0.tgz", + "integrity": "sha512-bxVeBA8Ky2UeItNhF4JRxHCFIrpEJHGFG/mOAa4CR0JkqaDEYSLmlEgmC4Os63SBlZ+E5U0YyrNJOSVl2mtVqQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "i18next": ">= 25.6.2", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, + "node_modules/react-refresh": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.16.0.tgz", + "integrity": "sha512-FPvF2XxTSikpJxcr+bHut2H4gJ17+18Uy20D5/F+SKzFap62R3cM5wH6b8WN3LyGSYeQilLEcJcR1fjBSI2S1A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz", + "integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz", + "integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.1", + "react-router": "6.30.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -10948,6 +11344,12 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -12423,6 +12825,15 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -12480,107 +12891,13 @@ "extsprintf": "^1.2.0" } }, - "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", - "dev": true, - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=0.10.0" } }, "node_modules/w3c-xmlserializer": { diff --git a/package.json b/package.json index 9e79dfff1..8fca7ed05 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,13 @@ "name": "museum_2", "version": "1.0.0", "description": "museum_2", - "homepage": "Museum_2", + "alias": { + "@components/*": "./src/components/$1", + "@assets/*": "./src/assets/$1", + "@hooks/*": "./src/hooks/$1", + "@styles/*": "./src/styles/$1", + "@utils/*": "./src/utils/$1" + }, "scripts": { "init": "mate-scripts init", "start": "mate-scripts start", @@ -24,7 +30,7 @@ "@mate-academy/eslint-config": "latest", "@mate-academy/jest-mochawesome-reporter": "^1.0.0", "@mate-academy/linthtml-config": "latest", - "@mate-academy/scripts": "^2.1.1", + "@mate-academy/scripts": "^2.1.3", "@mate-academy/stylelint-config": "latest", "cypress": "^13.13.0", "eslint": "^8.57.0", @@ -55,5 +61,13 @@ "backstop": false, "cypress": true } + }, + "dependencies": { + "chalk": "^5.6.2", + "i18next": "^25.7.2", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "react-i18next": "^16.4.0", + "react-router-dom": "^6.30.2" } } diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 000000000..71fc99070 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import Home from './pages/Home/Home'; + +function App() { + return ( + + + } /> + + + ); +} + +export default App; diff --git a/src/assets/HeroImages/HeroImageDesktop.png b/src/assets/HeroImages/HeroImageDesktop.png new file mode 100644 index 000000000..945e333d8 Binary files /dev/null and b/src/assets/HeroImages/HeroImageDesktop.png differ diff --git a/src/assets/HeroImages/HeroImageDesktop.webp b/src/assets/HeroImages/HeroImageDesktop.webp new file mode 100644 index 000000000..414fb5e2c Binary files /dev/null and b/src/assets/HeroImages/HeroImageDesktop.webp differ diff --git a/src/assets/HeroImages/HeroImageMobile.png b/src/assets/HeroImages/HeroImageMobile.png new file mode 100644 index 000000000..f0d9a75ab Binary files /dev/null and b/src/assets/HeroImages/HeroImageMobile.png differ diff --git a/src/assets/HeroImages/HeroImageMobile.webp b/src/assets/HeroImages/HeroImageMobile.webp new file mode 100644 index 000000000..742208cf6 Binary files /dev/null and b/src/assets/HeroImages/HeroImageMobile.webp differ diff --git a/src/assets/HeroImages/HeroImageTablet.png b/src/assets/HeroImages/HeroImageTablet.png new file mode 100644 index 000000000..3338f9b62 Binary files /dev/null and b/src/assets/HeroImages/HeroImageTablet.png differ diff --git a/src/assets/HeroImages/HeroImageTablet.webp b/src/assets/HeroImages/HeroImageTablet.webp new file mode 100644 index 000000000..4e7c94fd9 Binary files /dev/null and b/src/assets/HeroImages/HeroImageTablet.webp differ diff --git a/src/assets/HeroImages/SideBarImageDesktop.png b/src/assets/HeroImages/SideBarImageDesktop.png new file mode 100644 index 000000000..854771e46 Binary files /dev/null and b/src/assets/HeroImages/SideBarImageDesktop.png differ diff --git a/src/assets/icons/close.svg b/src/assets/icons/close.svg new file mode 100644 index 000000000..ef3e96fa3 --- /dev/null +++ b/src/assets/icons/close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/expand-down.svg b/src/assets/icons/expand-down.svg new file mode 100644 index 000000000..cba2a18c6 --- /dev/null +++ b/src/assets/icons/expand-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/expand-up.svg b/src/assets/icons/expand-up.svg new file mode 100644 index 000000000..04260dd82 --- /dev/null +++ b/src/assets/icons/expand-up.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/menu.svg b/src/assets/icons/menu.svg new file mode 100644 index 000000000..0cb275019 --- /dev/null +++ b/src/assets/icons/menu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/namu.svg b/src/assets/icons/namu.svg new file mode 100644 index 000000000..4fc1cb264 --- /dev/null +++ b/src/assets/icons/namu.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/layout/Header/Header.jsx b/src/components/layout/Header/Header.jsx new file mode 100644 index 000000000..a86eab95d --- /dev/null +++ b/src/components/layout/Header/Header.jsx @@ -0,0 +1,56 @@ +import React from 'react'; +import './Header.scss'; +import '@components/ui/LanguageSwitcher/LanguageSwitcher.scss'; +import { useNavigate } from 'react-router-dom'; +import BrendLogo from '@assets/icons/namu.svg'; +import LanguageSwitcher from '@components/ui/LanguageSwitcher/LanguageSwitcher'; +import useScreenSize from '@hooks/useScreenSize'; + +const Header = ({ variant, onOpen = () => {}, onClose = () => {} }) => { + const navigate = useNavigate(); + const screenSize = useScreenSize(); + + return ( +
+
+
+
+ { + e.preventDefault(); + navigate('/'); + }} + > + NAMU + +
+
+ {variant === 'main' ? ( + + ) : ( + <> + + {screenSize.width < 640 && } + + )} + {screenSize.width > 640 && } +
+
+
+
+ ); +}; + +export default Header; diff --git a/src/components/layout/Header/Header.scss b/src/components/layout/Header/Header.scss new file mode 100644 index 000000000..c78551526 --- /dev/null +++ b/src/components/layout/Header/Header.scss @@ -0,0 +1,84 @@ +@import '@styles/utils/vars'; +@import '@styles/utils/mixins'; +@import '@styles/utils/extends'; + +.header { + display: flex; + align-items: center; + background-color: $c-background; + width: 100%; + z-index: 11; + flex-shrink: 0; + + @include header-height; + + &__content { + @include page-padding; + + width: 100%; + } + + &__nav { + @extend %flex-between; + + width: 100%; + } + + // &__brand { + // // Brand container styles if needed + // } + + // &__logo { + // // Logo link styles if needed + // } + + &__actions { + @extend %flex-center; + + gap: 30px; + + @include mobile { + .header__btn { + order: 2; + } + + .language-switcher { + order: 1; + } + } + } + + &__btn { + @extend %button-reset; + @extend %flex-center; + + height: 100%; + z-index: 100; + } + + &__icon { + display: block; + height: 22px; + width: 22px; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; + + &--close { + background-image: url('../../../assets/icons/close.svg'); + } + + &--menu { + background-image: url('../../../assets/icons/menu.svg'); + } + + @include desktop { + width: 30px; + height: 30px; + } + + @include transition(all); + @include hover(transform, scale(1.2)); + } +} diff --git a/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.jsx b/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.jsx new file mode 100644 index 000000000..c38cb5ef6 --- /dev/null +++ b/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import './LandingHomeBlock.scss'; +import P from '@components/ui/StyleBlocks/P/P'; +import H from '@components/ui/StyleBlocks/H/H'; +import Button from '@components/ui/Button/Button'; +import ResponsiveImage from '@components/ui/ResponsiveImage/ResponsiveImage'; +import HeroImageMobile from '@assets/HeroImages/HeroImageMobile.webp'; +import HeroImageTablet from '@assets/HeroImages/HeroImageTablet.webp'; +import HeroImageDesktop from '@assets/HeroImages/HeroImageDesktop.webp'; +import { useTranslation } from 'react-i18next'; + +const LandingHomeBlock = () => { + const { t } = useTranslation(); + return ( +
+
+
+
+

+ {t('home.period')} +

+ + + {t('home.title')} + + +

+ {t('home.description')} +

+ +
+ +
+ +
+

+ {t('home.shortDate')} +

+
+
+
+ +
+ +
+
+
+
+ ); +}; + +export default LandingHomeBlock; diff --git a/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.scss b/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.scss new file mode 100644 index 000000000..6397bb1cc --- /dev/null +++ b/src/components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock.scss @@ -0,0 +1,148 @@ +@import '@styles/utils/vars'; +@import '@styles/utils/mixins'; + +.landing-home-block { + width: 100%; + background-color: $c-background; + display: flex; + + @include viewport-height-minus-header; + + &__container { + position: relative; + width: 100%; + + @include page-padding; + } + + &__content { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + + @include desktop { + flex-direction: row; + justify-content: space-between; + gap: 30px; + } + } + + &__info { + display: flex; + flex-direction: column; + flex-shrink: 0; + + @include desktop { + max-width: 570px; + } + } + + &__period { + margin-top: 50px; + + @include tablet { + margin-top: 100px; + } + + @include desktop { + margin-top: 90px; + } + } + + &__heading { + display: inline-block; + margin-top: 10px; + } + + &__description { + margin-top: 30px; + + @include tablet { + margin-top: 20px; + } + + @include desktop { + margin-top: 30px; + } + } + + &__actions { + margin-top: 40px; + + @include tablet { + margin-top: 50px; + } + + @include desktop { + margin-top: 81px; + } + } + + &__date { + display: none; + + &-text { + white-space: nowrap; + } + + @include desktop { + display: flex; + margin-top: auto; + margin-bottom: 50px; + gap: 20px; + align-items: center; + + &-line { + position: relative; + width: 100%; + + &::after { + content: ''; + position: absolute; + width: 100%; + + left: 0; + top: 0; + height: 1px; + background-color: $c-white; + } + } + } + } + + &__img-container { + display: flex; + justify-content: center; + margin-top: 40px; + width: 100%; + + @include tablet { + margin-top: 70px; + width: 100%; + } + + @include desktop { + position: absolute; + margin: 0; + right: 0; + bottom: 0; + padding: 0; + justify-content: flex-end; + align-items: flex-end; + width: 45%; + } + } + + &__image { + margin-top: 40px; + max-width: 443px; + max-height: 493px; + width: 100%; + + @include desktop { + max-width: 625px; + max-height: 663px; + } + } +} diff --git a/src/components/layout/MainLayout/MainLayout.jsx b/src/components/layout/MainLayout/MainLayout.jsx new file mode 100644 index 000000000..81a901c44 --- /dev/null +++ b/src/components/layout/MainLayout/MainLayout.jsx @@ -0,0 +1,20 @@ +import React, { useState, lazy, Suspense } from 'react'; +import Header from '../Header/Header'; + +const SideMenu = lazy(() => import('@components/ui/SideMenu/SideMenu')); + +const MainLayout = ({ children }) => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + return ( +
+
setIsMenuOpen(true)} /> + + setIsMenuOpen(false)} /> + + {children} +
+ ); +}; + +export default MainLayout; diff --git a/src/components/ui/Button/Button.jsx b/src/components/ui/Button/Button.jsx new file mode 100644 index 000000000..fb5303763 --- /dev/null +++ b/src/components/ui/Button/Button.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import './Button.scss'; + +const Button = ({ + children, + variant = 'primary', + size = 'xs', + fullWidth = false, + disabled = false, + onClick, + type = 'button', + className = '', + to, + href, + ...props +}) => { + const classes = [ + 'button', + `button--${variant}`, + `button--${size}`, + fullWidth && 'button--full-width', + disabled && 'button--disabled', + className, + ] + .filter(Boolean) + .join(' '); + + if (to) { + return ( + + {children} + + ); + } + + if (href) { + return ( + + {children} + + ); + } + + return ( + + ); +}; + +export default Button; diff --git a/src/components/ui/Button/Button.scss b/src/components/ui/Button/Button.scss new file mode 100644 index 000000000..3027bb504 --- /dev/null +++ b/src/components/ui/Button/Button.scss @@ -0,0 +1,73 @@ +@use 'sass:color'; +@import '../../../styles/utils/vars'; +@import '../../../styles/utils/mixins'; + +.button { + display: inline-flex; + justify-content: center; + align-items: center; + font-weight: 500; + font-family: $font-raleway; + transition: all 0.3s ease; + white-space: nowrap; + border: none; + height: $button-height; + z-index: 222; + cursor: pointer; + + &--primary { + background-color: $c-main; + color: $c-white; + width: $button-width-md; + + @include tablet { + width: $button-width-lg; + } + + @include desktop { + width: $button-width-sm; + } + + &:hover:not(&--disabled) { + background-color: $c-main-hover; + border-color: $c-main-hover; + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + } + + &:active:not(&--disabled) { + background-color: $c-main-pressed; + transform: translate(0); + } + + &--disabled { + background-color: $c-main-disabled; + } + } + + &--secondary { + background-color: transparent; + color: $c-main; + border: 1px solid $c-main; + width: $button-width-md; + + @include tablet { + width: $button-width-xs; + } + + @include desktop { + width: $button-width-sm; + } + + &:hover:not(&--disabled) { + color: $c-main-hover; + border: 1px solid $c-main-hover; + } + + &:active:not(&--disabled) { + color: $c-main-pressed; + border: 1px solid $c-main-pressed; + transform: translate(0); + } + } +} diff --git a/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.jsx b/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.jsx new file mode 100644 index 000000000..ad542937f --- /dev/null +++ b/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import CloseIcon from '@assets/icons/close.svg'; +import './BurgerMenu.scss'; + +const BurgerMenu = ({ isOpen, onClose }) => { + const { t } = useTranslation(); + + return ( + <> +
+ + + + ); +}; + +export default BurgerMenu; diff --git a/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.scss b/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.scss new file mode 100644 index 000000000..bed958101 --- /dev/null +++ b/src/components/ui/LanguageSwitcher/BurgerMenu/BurgerMenu.scss @@ -0,0 +1,56 @@ +@import '../../../../styles/utils/vars'; + +.burger-menu { + position: fixed; + top: 0; + right: 0; + width: 100%; + height: 100%; + background: $c-background; + transform: translateX(100%); + transition: transform 0.3s ease; + z-index: 999; + padding: 20px; + display: flex; + flex-direction: column; + + &--open { + transform: translateX(0); + } + + &__overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + opacity: 0; + visibility: hidden; + transition: + opacity 0.3s ease, + visibility 0.3s ease; + z-index: 998; + + &--open { + opacity: 1; + visibility: visible; + } + } + + &__header { + display: flex; + justify-content: flex-end; + } + + &__close-btn { + background: transparent; + border: none; + padding: 0; + } + + &__close-icon { + width: 22px; + height: 22px; + } +} diff --git a/src/components/ui/LanguageSwitcher/LanguageSwitcher.jsx b/src/components/ui/LanguageSwitcher/LanguageSwitcher.jsx new file mode 100644 index 000000000..f0d45c07a --- /dev/null +++ b/src/components/ui/LanguageSwitcher/LanguageSwitcher.jsx @@ -0,0 +1,52 @@ +import './LanguageSwitcher.scss'; +import React, { useState } from 'react'; +import ExpandDown from '@assets/icons/expand-down.svg'; +import ExpandUp from '@assets/icons/expand-up.svg'; +import { useTranslation } from 'react-i18next'; + +const languages = [ + { code: 'ua', label: 'UA' }, + { code: 'en', label: 'EN' }, +]; + +const LanguageSwitcher = () => { + const { i18n } = useTranslation(); + const [isOpen, setIsOpen] = useState(false); + + const currentLanguage = + languages.find((l) => l.code === i18n.language) || languages[0]; + + const handleSelect = (langCode) => { + i18n.changeLanguage(langCode); + setIsOpen(false); + }; + + return ( +
+ + + +
+ ); +}; + +export default LanguageSwitcher; diff --git a/src/components/ui/LanguageSwitcher/LanguageSwitcher.scss b/src/components/ui/LanguageSwitcher/LanguageSwitcher.scss new file mode 100644 index 000000000..70561adad --- /dev/null +++ b/src/components/ui/LanguageSwitcher/LanguageSwitcher.scss @@ -0,0 +1,68 @@ +@import '../../../styles/utils'; + +.language-switcher { + position: relative; + display: flex; + align-items: center; + z-index: 100; + + &__toggle { + display: flex; + align-items: center; + gap: 5px; + background: transparent; + color: $c-white; + border: none; + font-family: $font-raleway; + font-weight: 500; + font-size: 1rem; + line-height: 150%; + letter-spacing: 0%; + cursor: pointer; + } + + &__dropdown { + position: absolute; + top: 100%; + left: 0; + visibility: hidden; + max-height: 0; + min-width: 80%; + opacity: 0; + pointer-events: none; + overflow: hidden; + transition: + opacity 0.3s ease-in-out, + max-height 0.3s ease-in-out, + visibility 0s linear 0.3s; + + &--open { + visibility: visible; + opacity: 1; + pointer-events: auto; + transition: + opacity 0.3s ease-in-out, + max-height 0.3s ease-in-out, + visibility 0s linear 0s; + max-height: 200px; + } + } + + &__item { + list-style-type: none; + background-color: $c-background; + } + + &__btn { + background-color: $c-background; + border: none; + color: $c-white; + font-family: $font-raleway; + + font-size: 1rem; + cursor: pointer; + width: 100%; + text-align: left; + padding: 8px 6px; + } +} diff --git a/src/components/ui/ResponsiveImage/ResponsiveImage.jsx b/src/components/ui/ResponsiveImage/ResponsiveImage.jsx new file mode 100644 index 000000000..2ddd841dc --- /dev/null +++ b/src/components/ui/ResponsiveImage/ResponsiveImage.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import './ResponsiveImage.scss'; + +const ResponsiveImage = ({ + mobile, + tablet, + desktop, + alt, + className = '', + lazy = true, + ...props +}) => { + if (!tablet && !desktop) { + return ( + {alt} + ); + } + + return ( + + {desktop && } + + {tablet && } + + {alt} + + ); +}; + +export default ResponsiveImage; diff --git a/src/components/ui/ResponsiveImage/ResponsiveImage.scss b/src/components/ui/ResponsiveImage/ResponsiveImage.scss new file mode 100644 index 000000000..99b69da4f --- /dev/null +++ b/src/components/ui/ResponsiveImage/ResponsiveImage.scss @@ -0,0 +1,8 @@ +.responsive-image { + &__img { + width: 100%; + height: auto; + object-fit: cover; + object-position: center; + } +} diff --git a/src/components/ui/SideMenu/SideMenu.jsx b/src/components/ui/SideMenu/SideMenu.jsx new file mode 100644 index 000000000..0162f76ac --- /dev/null +++ b/src/components/ui/SideMenu/SideMenu.jsx @@ -0,0 +1,71 @@ +import Header from '@components/layout/Header/Header'; +import './SideMenu.scss'; +import { useTranslation } from 'react-i18next'; +import P from '../StyleBlocks/P/P'; +import H from '../StyleBlocks/H/H'; + +const SideMenu = ({ isOpen, onClose }) => { + const { t } = useTranslation(); + const linkList = [ + { href: '#exhibitions', translation: 'menu.exhibitions' }, + { href: '#events', translation: 'menu.events' }, + { href: '#news', translation: 'menu.news' }, + ]; + + const handleLinkClick = (e, href) => { + e.preventDefault(); + onClose(); + window.location.hash = href; + }; + + return ( + + ); +}; + +export default SideMenu; diff --git a/src/components/ui/SideMenu/SideMenu.scss b/src/components/ui/SideMenu/SideMenu.scss new file mode 100644 index 000000000..829a30a40 --- /dev/null +++ b/src/components/ui/SideMenu/SideMenu.scss @@ -0,0 +1,113 @@ +@import '../../../styles//utils/vars'; +@import '../../../styles//utils/mixins'; + +.side-menu { + position: fixed; + top: 0; + right: 0; + width: 100%; + height: 100%; + background-color: $c-background; + transform: translateX(100%); + z-index: 999; + overflow: hidden; + display: flex; + flex-direction: column; + scrollbar-width: none; + + @include transition(all); + + &--open { + transform: translateX(0%); + display: flex; + scrollbar-width: none; + overflow-y: hidden; + } + + &__content { + display: flex; + flex-direction: column; + margin-top: 10px; + + width: 100%; + height: 100%; + + @include page-padding; + } + + &__info { + display: flex; + flex-direction: column; + gap: 20px; + + @include tablet { + margin-top: 30px; + flex-direction: row; + gap: 123px; + } + + @include desktop { + margin-top: 40px; + flex-direction: row; + gap: 83px; + } + } + + &__schedule { + display: flex; + flex-direction: column; + } + + &__navigation { + display: flex; + gap: 20px; + + margin-top: 30px; + + @include tablet { + margin-top: 40px; + } + + @include desktop { + margin-top: 70px; + } + } + + &__navigation-list { + display: flex; + flex-direction: column; + gap: 20px; + + @include tablet { + gap: 30px; + } + + @include desktop { + gap: 60px; + } + } + + &__navigation-link { + position: relative; + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 1px; + background-color: red; + transform: scaleX(0); + transform-origin: center; + + @include transition(transform); + } + + &:hover { + &::after { + transform: scaleX(1); + } + } + } +} diff --git a/src/components/ui/StyleBlocks/H/H.jsx b/src/components/ui/StyleBlocks/H/H.jsx new file mode 100644 index 000000000..5b0a07666 --- /dev/null +++ b/src/components/ui/StyleBlocks/H/H.jsx @@ -0,0 +1,62 @@ +import React from 'react'; +import './H.scss'; + +const H = ({ + size = 'm', + children, + textAlign = 'center', + as = 'h2', + className = '', +}) => { + // let fontSize, lineHeight; + + // switch (size) { + // case 'h1': + // case 'xxl': + // fontSize = isMobile ? '3rem' : isTablet ? '4.5rem' : '6rem'; + // lineHeight = '100%'; + // break; + // case 'h2': + // case 'xl': + // fontSize = isMobile ? '2.375rem' : isTablet ? '3.875rem' : '5rem'; + // lineHeight = '100%'; + // break; + // case 'h3': + // case 'l': + // fontSize = isMobile ? '1.75rem' : isTablet ? '2.5rem' : '3.625rem'; + // lineHeight = isMobile ? '125%' : isTablet ? '125%' : '120%'; + // break; + // case 'h4': + // case 'm': + // fontSize = isMobile ? '1.25rem' : '1.5rem'; + // lineHeight = '125%'; + // break; + // case 'h5': + // case 's': + // fontSize = '1.25rem'; + // lineHeight = '150%'; + // break; + // case 'h6': + // case 'xs': + // fontSize = '0.875rem'; + // lineHeight = '125%'; + // break; + // } + + const Tag = as; + + const classes = [ + 'heading', + `heading--${size}`, + textAlign !== 'center' && `heading--align-${textAlign}`, + className, + ] + .filter(Boolean) + .join(' '); + + return ( + {children} + ); +}; + +export default H; diff --git a/src/components/ui/StyleBlocks/H/H.scss b/src/components/ui/StyleBlocks/H/H.scss new file mode 100644 index 000000000..24d10fc7e --- /dev/null +++ b/src/components/ui/StyleBlocks/H/H.scss @@ -0,0 +1,98 @@ +@import '../../../../styles/utils/vars'; +@import '../../../../styles/utils/mixins'; + +.heading { + font-family: $font-playfair; + font-weight: 700; + font-style: normal; + letter-spacing: 0; + margin: 0; + color: $c-white; + + // Alignment modifiers + &--align-start { + text-align: start; + } + &--align-center { + text-align: center; + } + &--align-end { + text-align: end; + } + + &--h1, + &--xxl { + font-size: 3rem; + line-height: 100%; + + @include tablet { + font-size: 4.5rem; + } + + @include desktop { + font-size: 6rem; + } + } + + &--h2, + &--xl { + font-size: 2.38rem; + line-height: 100%; + + @include tablet { + font-size: 3.88rem; + } + + @include desktop { + font-size: 5rem; + } + } + + &--h3, + &--l { + font-size: 1.75rem; + line-height: 125%; + + @include tablet { + font-size: 2.5rem; + line-height: 125%; + } + + @include desktop { + font-size: 3.63rem; + line-height: 120%; + } + } + + &--h4, + &--m { + font-size: 1.25rem; + line-height: 125%; + + @include tablet { + font-size: 1.5rem; + } + } + + &--h5, + &--s { + font-size: 1.25rem; + line-height: 150%; + + @include tablet { + font-size: 3rem; + line-height: 120%; + } + + @include desktop { + font-size: 3rem; + line-height: 120%; + } + } + + &--h6, + &--xs { + font-size: 0.88rem; + line-height: 125%; + } +} diff --git a/src/components/ui/StyleBlocks/P/P.jsx b/src/components/ui/StyleBlocks/P/P.jsx new file mode 100644 index 000000000..24ec42e4e --- /dev/null +++ b/src/components/ui/StyleBlocks/P/P.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import './P.scss'; +import { colors } from '@styles/colors'; + +const P = ({ + fsize = '16px', + lineHeight = 'normal', + children, + color = colors.white, + textAlign = 'center', + fontWeight = '400', + className = '', +}) => { + return ( +
+

+ {children} +

+
+ ); +}; + +export default P; diff --git a/src/components/ui/StyleBlocks/P/P.scss b/src/components/ui/StyleBlocks/P/P.scss new file mode 100644 index 000000000..b743d392d --- /dev/null +++ b/src/components/ui/StyleBlocks/P/P.scss @@ -0,0 +1,13 @@ +@import '../../../../styles/utils/vars'; + +.p-container { + font-weight: 400; + font-family: $font-raleway; + display: flex; + justify-content: center; + align-items: center; +} + +.p-container p { + width: 100%; +} diff --git a/src/hooks/useScreenSize.jsx b/src/hooks/useScreenSize.jsx new file mode 100644 index 000000000..3776284e9 --- /dev/null +++ b/src/hooks/useScreenSize.jsx @@ -0,0 +1,41 @@ +const { useState, useEffect } = require('react'); + +const useScreenSize = (delay = 200) => { + const [screenSize, setScreenSize] = useState(() => { + if (typeof window === 'undefined') + return { + width: 0, + height: 0, + }; + + return { + width: window.innerWidth, + height: window.innerHeight, + }; + }); + + useEffect(() => { + let timeOut; + + const handleResize = () => { + clearTimeout(timeOut); + timeOut = setTimeout(() => { + setScreenSize({ + width: window.innerWidth, + height: window.innerHeight, + }); + }, delay); + }; + + window.addEventListener('resize', handleResize); + + return () => { + clearTimeout(timeOut); + window.removeEventListener('resize', handleResize); + }; + }, [delay]); + + return screenSize; +}; + +export default useScreenSize; diff --git a/src/i18next/i18next.jsx b/src/i18next/i18next.jsx new file mode 100644 index 000000000..41d103382 --- /dev/null +++ b/src/i18next/i18next.jsx @@ -0,0 +1,25 @@ +import i18next from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import translationEN from './locales/en/translation.json'; +import translationUA from './locales/ua/translation.json'; + +const resources = { + en: { + translation: translationEN, + }, + ua: { + translation: translationUA, + }, +}; + +i18next.use(initReactI18next).init({ + resources, + lng: 'en', + fallbackLng: 'en', + debug: false, + interpolation: { + escapeValue: false, // React already escapes + }, +}); + +export default i18next; diff --git a/src/i18next/locales/en/translation.json b/src/i18next/locales/en/translation.json new file mode 100644 index 000000000..d74d16258 --- /dev/null +++ b/src/i18next/locales/en/translation.json @@ -0,0 +1,22 @@ +{ + "header": { + "language": "EN" + }, + "menu": { + "schedule": "Schedule today:", + "scheduleTime": "12:00 - 19:00", + "address": "Address:", + "addressValue": "Kyiv, 6 M. Hrushevskoho St.", + "exhibitions": "Current exhibitions", + "events": "Upcoming events", + "news": "News", + "buyTicket": "Buy ticket" + }, + "home": { + "period": "August 10 - November 10", + "title": "Art of the 19th - 20th century", + "description": "Contribution of Ukrainian artists to world culture of the 19th-20th century", + "buyTicket": "Buy ticket", + "shortDate": "10.08 - 10.10" + } +} diff --git a/src/i18next/locales/ua/translation.json b/src/i18next/locales/ua/translation.json new file mode 100644 index 000000000..29c116cfc --- /dev/null +++ b/src/i18next/locales/ua/translation.json @@ -0,0 +1,22 @@ +{ + "header": { + "language": "UA" + }, + "menu": { + "schedule": "Розклад сьогодні:", + "scheduleTime": "12:00 - 19:00", + "address": "Адреса:", + "addressValue": "Київ, вул. М. Грушевського, 6", + "exhibitions": "Актуальні виставки", + "events": "Найближчі події", + "news": "Новини", + "buyTicket": "Купити квиток" + }, + "home": { + "period": "10 серпня - 10 листопада", + "title": "Мистецтво ХІХ - ХХ ст.", + "description": "Внесок українських митців у світову культуру 19-20 ст.", + "buyTicket": "Купити квиток", + "shortDate": "10.08 - 10.10" + } +} diff --git a/src/images/.gitkeep b/src/images/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/pages/Home/Home.jsx b/src/pages/Home/Home.jsx new file mode 100644 index 000000000..13f5143f2 --- /dev/null +++ b/src/pages/Home/Home.jsx @@ -0,0 +1,19 @@ +import React, { useEffect } from 'react'; +import MainLayout from '@components/layout/MainLayout/MainLayout'; +import LandingHomeBlock from '@components/layout/MainLayout/LandingSection/LandingHomeBlock/LandingHomeBlock'; + +const Home = () => { + useEffect(() => { + window.scrollTo(0, 0); + }, []); + + return ( + +
+ +
+
+ ); +}; + +export default Home; diff --git a/src/scripts/main.js b/src/scripts/main.js deleted file mode 100644 index ad9a93a7c..000000000 --- a/src/scripts/main.js +++ /dev/null @@ -1 +0,0 @@ -'use strict'; diff --git a/src/scripts/main.jsx b/src/scripts/main.jsx new file mode 100644 index 000000000..7841a390a --- /dev/null +++ b/src/scripts/main.jsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from '../App'; +import '../i18next/i18next'; + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); diff --git a/src/styles/_fonts.scss b/src/styles/_fonts.scss index 33c3ed2b3..c863c1b84 100644 --- a/src/styles/_fonts.scss +++ b/src/styles/_fonts.scss @@ -1 +1,16 @@ // put fonts here +@import 'utils/vars'; + +body { + font-family: $font-playfair; + font-weight: 400; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: $font-playfair; +} diff --git a/src/styles/_normalize.scss b/src/styles/_normalize.scss new file mode 100644 index 000000000..445ae2b84 --- /dev/null +++ b/src/styles/_normalize.scss @@ -0,0 +1,44 @@ +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6, +p, +ul, +ol, +li { + margin: 0; + padding: 0; +} + +ul, +ol { + list-style: none; +} + +a { + text-decoration: none; + color: inherit; +} + +button { + font: inherit; + cursor: pointer; +} + +img { + display: block; + max-width: 100%; +} diff --git a/src/styles/colors.js b/src/styles/colors.js new file mode 100644 index 000000000..db081b541 --- /dev/null +++ b/src/styles/colors.js @@ -0,0 +1,8 @@ +// Colors matching SCSS variables in utils/_vars.scss +export const colors = { + main: '#cd4d31', + white: '#f1f5f4', + background: '#3f5252', + black: '#1c1b29', + gray: '#504f5e', +}; diff --git a/src/styles/main.scss b/src/styles/main.scss index fb9195d12..ea6829aa8 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -1,7 +1,38 @@ @import 'utils'; @import 'fonts'; +@import 'normalize'; @import 'typography'; +html { + font-size: 16px; + scroll-behavior: smooth; +} + body { - background: $c-gray; + background-color: $c-white; + font-family: $font-playfair; + color: $c-black; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body:has(.side-menu--open) { + overflow-y: hidden; +} + +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.container { + max-width: 1440px; + margin-inline: auto; } diff --git a/src/styles/utils/_extends.scss b/src/styles/utils/_extends.scss index d7201e7b3..ad23539a5 100644 --- a/src/styles/utils/_extends.scss +++ b/src/styles/utils/_extends.scss @@ -1,4 +1,31 @@ +// Typography placeholders +%heading { + font-family: $font-playfair; + font-weight: 700; + margin: 0; +} + %h1 { - font-family: Roboto, sans-serif; - font-weight: 400; + @extend %heading; +} + +// Layout placeholders +%flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +%flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +// Button reset placeholder +%button-reset { + background: transparent; + border: none; + padding: 0; + cursor: pointer; } diff --git a/src/styles/utils/_mixins.scss b/src/styles/utils/_mixins.scss index 80c79780d..ca4f2c445 100644 --- a/src/styles/utils/_mixins.scss +++ b/src/styles/utils/_mixins.scss @@ -1,6 +1,94 @@ +@import 'vars'; + +@mixin mobile { + @media (max-width: $breakpoint-mobile) { + @content; + } +} + +@mixin tablet { + @media (min-width: $breakpoint-tablet) and (max-width: $breakpoint-desktop) { + @content; + } +} + +@mixin desktop { + @media (min-width: $breakpoint-desktop) { + @content; + } +} + +// Header height mixin + +@mixin header-height { + height: $header-height-mobile; + + @include tablet { + height: $header-height-tablet; + } + + @include desktop { + height: $header-height-desktop; + } +} + +// Viewport height minus header mixin +@mixin viewport-height-minus-header { + min-height: calc(100vh - #{$header-height-mobile}); + + @include tablet { + min-height: calc(100vh - #{$header-height-tablet}); + } + + @include desktop { + min-height: calc(100vh - #{$header-height-desktop}); + } +} + +// Content padding mixin +@mixin page-padding($mobile-h: 20px, $tablet-h: 40px, $desktop-h: 55px) { + padding-inline: $mobile-h; + + @include tablet { + padding-inline: $tablet-h; + } + + @include desktop { + padding-inline: $desktop-h; + } +} + +// Hover transition @mixin hover($_property, $_toValue) { transition: #{$_property} 0.3s; + &:hover { #{$_property}: $_toValue; } } + +// Transition shorthand +@mixin transition($property) { + transition: $property 0.3s ease; +} + +// LAYOUT MIXINS + +@mixin flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +@mixin flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +@mixin button-reset { + background: transparent; + border: none; + padding: 0; + cursor: pointer; +} diff --git a/src/styles/utils/_vars.scss b/src/styles/utils/_vars.scss index aeb006ffb..72b20c107 100644 --- a/src/styles/utils/_vars.scss +++ b/src/styles/utils/_vars.scss @@ -1 +1,49 @@ -$c-gray: #eee; +// FONTS +$font-playfair: 'Playfair Display', serif; +$font-raleway: 'Raleway', sans-serif; + +// COLORS +$c-main: #cd4d31; +$c-main-hover: #af3419; +$c-main-pressed: #ea340d; +$c-main-disabled: #dd836f; +$c-white: #f1f5f4; +$c-background: #3f5252; +$c-black: #1c1b29; +$c-gray: #504f5e; + +// BREAKPOINTS + +$breakpoint-mobile: 639px; +$breakpoint-tablet: 640px; +$breakpoint-desktop: 1280px; + +// SPACING SYSTEM +$spacing-xs: 8px; +$spacing-sm: 16px; +$spacing-md: 24px; +$spacing-lg: 32px; +$spacing-xl: 40px; +$spacing-2xl: 48px; +$spacing-3xl: 64px; +$spacing-4xl: 80px; +$spacing-5xl: 96px; + +// PAGE PADDING +$page-padding-mobile: 20px; +$page-padding-tablet: 40px; +$page-padding-desktop: 55px; + +// HEADER +$header-height-mobile: 80px; +$header-height-tablet: 77px; +$header-height-desktop: 90px; + +// Button dimensions +$button-height: 60px; + +// Button width (mobile, table, desktop) +$button-width-xs: 210px; +$button-width-sm: 270px; +$button-width-md: 280px; +$button-width-lg: 330px;