diff --git a/.github/workflows/generate-llms.yml b/.github/workflows/generate-llms.yml new file mode 100644 index 0000000..0b0ade6 --- /dev/null +++ b/.github/workflows/generate-llms.yml @@ -0,0 +1,55 @@ +name: Generate LLMs files + +on: + workflow_dispatch: + inputs: + environment: + description: 'Environment' + required: true + default: 'dev' + type: choice + options: + - dev + - prod + +permissions: + contents: write + +jobs: + generate: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Copy env file + run: | + if [ "${{ inputs.environment }}" = "prod" ]; then + echo "${{ secrets.ENV_PROD }}" | base64 -d > .env + else + echo "${{ secrets.ENV_DEV }}" | base64 -d > .env + fi + rm -f .env.local + + - name: Generate llms-full-pages + run: yarn generate:llms:pages + + - name: Commit and push generated files + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git add public/keepsimple_/ + if ! git diff --cached --quiet; then + git commit -m "chore: regenerate llms pages" + git push + fi diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index b08d65b..b2a28f8 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1,6 +1,5 @@ // Import custom commands import './commands'; -import 'cypress-real-events'; // Suppress Next.js route cancellation errors (thrown during rapid navigation) Cypress.on('uncaught:exception', err => { diff --git a/next.config.js b/next.config.js index 6e94a65..b83d844 100644 --- a/next.config.js +++ b/next.config.js @@ -62,6 +62,15 @@ module.exports = async () => { 'staging-strapi.keepsimple.io', ], }, + webpack(config) { + config.module.rules.push({ + test: /\.svg$/i, + issuer: /\.[jt]sx?$/, + use: ['@svgr/webpack'], + }); + + return config; + }, productionBrowserSourceMaps: true, }; diff --git a/package.json b/package.json index d4e27f7..1cd2ff2 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "scripts": { "dev": "cross-env NODE_ENV=development APP_ENV=local next dev -p 3005", "build": "cross-env NODE_ENV=production APP_ENV=prod next build", + "generate:llms": "cross-env LLMS_MODE=curated ts-node --compiler-options '{\"module\":\"commonjs\",\"target\":\"es2020\"}' scripts/generate-llms.ts", + "generate:llms:full": "cross-env LLMS_MODE=full ts-node --compiler-options '{\"module\":\"commonjs\",\"target\":\"es2020\"}' scripts/generate-llms.ts", + "generate:llms:pages": "ts-node --compiler-options '{\"module\":\"commonjs\",\"target\":\"es2020\"}' scripts/generate-llms-pages.ts", "start": "cross-env NODE_ENV=production APP_ENV=production yarn build && next start -p 4033", "start:staging": "cross-env NODE_ENV=production APP_ENV=staging next start -p 3005", "build:staging": "cross-env NODE_ENV=production APP_ENV=staging next build", @@ -18,6 +21,7 @@ "prepare": "husky install" }, "dependencies": { + "@svgr/webpack": "^8.1.0", "classnames": "2.3.1", "cookie": "0.6.0", "cross-env": "7.0.3", @@ -76,7 +80,6 @@ "@types/swiper": "6.0.0", "@types/uuid": "8.3.1", "babel-loader": "8.2.5", - "cypress-real-events": "^1.15.0", "eslint": "^9.32.0", "eslint-config-next": "^15.4.4", "husky": "^9.1.7", diff --git a/public/keepsimple_/assets/icons/oxford.svg b/public/keepsimple_/assets/icons/oxford.svg new file mode 100644 index 0000000..8c035f7 --- /dev/null +++ b/public/keepsimple_/assets/icons/oxford.svg @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/public/keepsimple_/assets/tools/bob.skill b/public/keepsimple_/assets/tools/bob.skill new file mode 100644 index 0000000..20bb1ad Binary files /dev/null and b/public/keepsimple_/assets/tools/bob.skill differ diff --git a/public/keepsimple_/assets/tools/bob.skill:Zone.Identifier b/public/keepsimple_/assets/tools/bob.skill:Zone.Identifier new file mode 100644 index 0000000..be537eb Binary files /dev/null and b/public/keepsimple_/assets/tools/bob.skill:Zone.Identifier differ diff --git a/public/keepsimple_/assets/tools/contaier-bg-dark.png b/public/keepsimple_/assets/tools/contaier-bg-dark.png new file mode 100644 index 0000000..b358c48 Binary files /dev/null and b/public/keepsimple_/assets/tools/contaier-bg-dark.png differ diff --git a/public/keepsimple_/assets/tools/container/dark-bg.svg b/public/keepsimple_/assets/tools/container/dark-bg.svg new file mode 100644 index 0000000..0abec44 --- /dev/null +++ b/public/keepsimple_/assets/tools/container/dark-bg.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/public/keepsimple_/assets/tools/container/white-bg.svg b/public/keepsimple_/assets/tools/container/white-bg.svg new file mode 100644 index 0000000..98bda4f --- /dev/null +++ b/public/keepsimple_/assets/tools/container/white-bg.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/keepsimple_/assets/tools/hero/black.png b/public/keepsimple_/assets/tools/hero/black.png new file mode 100644 index 0000000..395d8cf Binary files /dev/null and b/public/keepsimple_/assets/tools/hero/black.png differ diff --git a/public/keepsimple_/assets/tools/hero/default-dark.png b/public/keepsimple_/assets/tools/hero/default-dark.png new file mode 100644 index 0000000..1c20f17 Binary files /dev/null and b/public/keepsimple_/assets/tools/hero/default-dark.png differ diff --git a/public/keepsimple_/assets/tools/hero/default.png b/public/keepsimple_/assets/tools/hero/default.png new file mode 100644 index 0000000..e964c0d Binary files /dev/null and b/public/keepsimple_/assets/tools/hero/default.png differ diff --git a/public/keepsimple_/assets/tools/hero/green.png b/public/keepsimple_/assets/tools/hero/green.png new file mode 100644 index 0000000..fa79ab7 Binary files /dev/null and b/public/keepsimple_/assets/tools/hero/green.png differ diff --git a/public/keepsimple_/assets/tools/hero/white.png b/public/keepsimple_/assets/tools/hero/white.png new file mode 100644 index 0000000..2831eeb Binary files /dev/null and b/public/keepsimple_/assets/tools/hero/white.png differ diff --git a/public/keepsimple_/assets/tools/logo/black.svg b/public/keepsimple_/assets/tools/logo/black.svg new file mode 100644 index 0000000..1c9e0bc --- /dev/null +++ b/public/keepsimple_/assets/tools/logo/black.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/keepsimple_/assets/tools/logo/default-dark.svg b/public/keepsimple_/assets/tools/logo/default-dark.svg new file mode 100644 index 0000000..e1cc8a6 --- /dev/null +++ b/public/keepsimple_/assets/tools/logo/default-dark.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/keepsimple_/assets/tools/logo/default.svg b/public/keepsimple_/assets/tools/logo/default.svg new file mode 100644 index 0000000..d076efc --- /dev/null +++ b/public/keepsimple_/assets/tools/logo/default.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/keepsimple_/assets/tools/logo/green.svg b/public/keepsimple_/assets/tools/logo/green.svg new file mode 100644 index 0000000..109e089 --- /dev/null +++ b/public/keepsimple_/assets/tools/logo/green.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/keepsimple_/assets/tools/logo/white.svg b/public/keepsimple_/assets/tools/logo/white.svg new file mode 100644 index 0000000..66d26cf --- /dev/null +++ b/public/keepsimple_/assets/tools/logo/white.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/keepsimple_/llms-full-pages/article/all-about-user-stories-brand-new.md b/public/keepsimple_/llms-full-pages/article/all-about-user-stories-brand-new.md new file mode 100644 index 0000000..68591f3 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/all-about-user-stories-brand-new.md @@ -0,0 +1,4 @@ +# #8. How to write user stories + +- URL: https://staging.keepsimple.io/articles/all-about-user-stories-brand-new +- Description: This article describes how to write user stories. The author uses real-world example based on the real feature developed for a major online platform. diff --git a/public/keepsimple_/llms-full-pages/article/awareness-test.md b/public/keepsimple_/llms-full-pages/article/awareness-test.md new file mode 100644 index 0000000..bfe024a --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/awareness-test.md @@ -0,0 +1,4 @@ +# Introducing uxCAT: A Science-Backed Tool to Help You Think Smarter + +- URL: https://staging.keepsimple.io/articles/awareness-test +- Description: Article describing the creation of the first self-awareness online test built on top of cognitive biases diff --git a/public/keepsimple_/llms-full-pages/article/career-path-of-a-manager-and-a-few-universal-tips.md b/public/keepsimple_/llms-full-pages/article/career-path-of-a-manager-and-a-few-universal-tips.md new file mode 100644 index 0000000..f2b2bfa --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/career-path-of-a-manager-and-a-few-universal-tips.md @@ -0,0 +1,4 @@ +# #11. Career path of a manager and a few tips + +- URL: https://staging.keepsimple.io/articles/career-path-of-a-manager-and-a-few-universal-tips +- Description: The article summarizes what was described in all previous articles and what are the possible ways of a project manager's career development. diff --git a/public/keepsimple_/llms-full-pages/article/client-dev-company-workflow-birds-eye-view.md b/public/keepsimple_/llms-full-pages/article/client-dev-company-workflow-birds-eye-view.md new file mode 100644 index 0000000..e4db02d --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/client-dev-company-workflow-birds-eye-view.md @@ -0,0 +1,4 @@ +# #10. Cooperation between customer and development company + +- URL: https://staging.keepsimple.io/articles/client-dev-company-workflow-birds-eye-view +- Description: This article illustrates what the common cooperation process between the customer and the software development company looks like. diff --git a/public/keepsimple_/llms-full-pages/article/create-behavioral-user-personas.md b/public/keepsimple_/llms-full-pages/article/create-behavioral-user-personas.md new file mode 100644 index 0000000..007f8bc --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/create-behavioral-user-personas.md @@ -0,0 +1,4 @@ +# How to Create Behavioral User Personas That Drive Better UX Decisions + +- URL: https://staging.keepsimple.io/articles/create-behavioral-user-personas +- Description: Want to build better user personas? Here are the most comprehensive insights about how to create behavioral user personas using cognitive biases diff --git a/public/keepsimple_/llms-full-pages/article/explain-to-learn.md b/public/keepsimple_/llms-full-pages/article/explain-to-learn.md new file mode 100644 index 0000000..f2e8af3 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/explain-to-learn.md @@ -0,0 +1,4 @@ +# Explain to Others - Learn Yourself + +- URL: https://staging.keepsimple.io/uxcore/explain-to-learn +- Description: Read how explaining can be the best skill to boost your learning and communication skills. diff --git a/public/keepsimple_/llms-full-pages/article/friendship-explained.md b/public/keepsimple_/llms-full-pages/article/friendship-explained.md new file mode 100644 index 0000000..70dd85d --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/friendship-explained.md @@ -0,0 +1,4 @@ +# The Friendship Index: A Practical Framework for Measuring Relationships + +- URL: https://staging.keepsimple.io/uxcore/friendship-explained +- Description: Learn how to quantify your relationships with the Friendship Index. A practical framework to measure loyalty, balance, and sacrifice in friendships. diff --git a/public/keepsimple_/llms-full-pages/article/overengineering_and_demo_readiness.md b/public/keepsimple_/llms-full-pages/article/overengineering_and_demo_readiness.md new file mode 100644 index 0000000..baab0f9 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/overengineering_and_demo_readiness.md @@ -0,0 +1,4 @@ +# Solving overengineering and DEMO readiness problems with PS+ + +- URL: https://staging.keepsimple.io/articles/overengineering_and_demo_readiness +- Description: How to solve overengineering issues in engineering teams, and how to always be ready for important DEMOs and milestones. diff --git a/public/keepsimple_/llms-full-pages/article/philosophies-methodologies-and-frameworks.md b/public/keepsimple_/llms-full-pages/article/philosophies-methodologies-and-frameworks.md new file mode 100644 index 0000000..8e4f0ea --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/philosophies-methodologies-and-frameworks.md @@ -0,0 +1,4 @@ +# #4. Project management philosophies methodologies and frameworks + +- URL: https://staging.keepsimple.io/articles/philosophies-methodologies-and-frameworks +- Description: The article describes the fundamental differences between project management philosophies, methodologies, and frameworks. diff --git a/public/keepsimple_/llms-full-pages/article/practical-longevity-protocol.md b/public/keepsimple_/llms-full-pages/article/practical-longevity-protocol.md new file mode 100644 index 0000000..eb4dbce --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/practical-longevity-protocol.md @@ -0,0 +1,4 @@ +# Longevity as UX: Designing a Life That Performs + +- URL: https://staging.keepsimple.io/uxcore/practical-longevity-protocol +- Description: Why Longevity is the most important trend nowadays and beyond diff --git a/public/keepsimple_/llms-full-pages/article/project-approval-and-further-workflow.md b/public/keepsimple_/llms-full-pages/article/project-approval-and-further-workflow.md new file mode 100644 index 0000000..842eca9 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/project-approval-and-further-workflow.md @@ -0,0 +1,4 @@ +# #7. Project approval and development workflow + +- URL: https://staging.keepsimple.io/articles/project-approval-and-further-workflow +- Description: This article describes the process of project requirements analysis, documentation writing, user stories evaluation and other mandatory steps. diff --git a/public/keepsimple_/llms-full-pages/article/project-artifacts-and-their-importance.md b/public/keepsimple_/llms-full-pages/article/project-artifacts-and-their-importance.md new file mode 100644 index 0000000..f748bcf --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/project-artifacts-and-their-importance.md @@ -0,0 +1,4 @@ +# #2. Project artifacts and their importance + +- URL: https://staging.keepsimple.io/articles/project-artifacts-and-their-importance +- Description: A clear guide to software project artifacts. Understand the difference between Epics, User Stories, Tasks, and Bugs to improve team efficiency. diff --git a/public/keepsimple_/llms-full-pages/article/project-management-environment.md b/public/keepsimple_/llms-full-pages/article/project-management-environment.md new file mode 100644 index 0000000..94d09c6 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/project-management-environment.md @@ -0,0 +1,4 @@ +# #3. Project management environment + +- URL: https://staging.keepsimple.io/articles/project-management-environment +- Description: This article describes the environment of modern project manager, the tools they use, and the best practices for solving communication and collaboration issues. diff --git a/public/keepsimple_/llms-full-pages/article/scrum-framework-artifacts-rituals-and-roles.md b/public/keepsimple_/llms-full-pages/article/scrum-framework-artifacts-rituals-and-roles.md new file mode 100644 index 0000000..b851efc --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/scrum-framework-artifacts-rituals-and-roles.md @@ -0,0 +1,4 @@ +# #6. SCRUM Framework - artifacts, rituals, and roles + +- URL: https://staging.keepsimple.io/articles/scrum-framework-artifacts-rituals-and-roles +- Description: This article describes all SCRUM Framework artifacts, rituals, and roles, including nuanced details such as the definition of Done, Increment, and others. diff --git a/public/keepsimple_/llms-full-pages/article/software-development-life-cycles.md b/public/keepsimple_/llms-full-pages/article/software-development-life-cycles.md new file mode 100644 index 0000000..ba5e704 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/software-development-life-cycles.md @@ -0,0 +1,4 @@ +# #5. Software development life cycles + +- URL: https://staging.keepsimple.io/articles/software-development-life-cycles +- Description: The article describes all actual software development life cycles (SDLCs), in particular Predictive, Iterative, Incremental, and Agile. diff --git a/public/keepsimple_/llms-full-pages/article/summarize-like-your-job-depends-on-it.md b/public/keepsimple_/llms-full-pages/article/summarize-like-your-job-depends-on-it.md new file mode 100644 index 0000000..33ed644 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/summarize-like-your-job-depends-on-it.md @@ -0,0 +1,4 @@ +# Summarize like your job depends on it (Because It Does) + +- URL: https://staging.keepsimple.io/uxcore/summarize-like-your-job-depends-on-it +- Description: The article describes the importance of summarization, making quality executive summaries and its impact on career. diff --git a/public/keepsimple_/llms-full-pages/article/table-of-contents.md b/public/keepsimple_/llms-full-pages/article/table-of-contents.md new file mode 100644 index 0000000..6427d72 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/table-of-contents.md @@ -0,0 +1,4 @@ +# Project Management table of contents + +- URL: https://staging.keepsimple.io/articles/table-of-contents +- Description: This page describes the data presented in all project management articles on KeepSimple website. diff --git a/public/keepsimple_/llms-full-pages/article/technical-components-of-the-project.md b/public/keepsimple_/llms-full-pages/article/technical-components-of-the-project.md new file mode 100644 index 0000000..9a05ef8 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/technical-components-of-the-project.md @@ -0,0 +1,4 @@ +# #9. Technical components of the software project + +- URL: https://staging.keepsimple.io/articles/technical-components-of-the-project +- Description: A brief introduction of the main technical components and terms used in the infrastructure of any software project diff --git a/public/keepsimple_/llms-full-pages/article/uiux.md b/public/keepsimple_/llms-full-pages/article/uiux.md new file mode 100644 index 0000000..fd8a347 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/uiux.md @@ -0,0 +1,4 @@ +# UI-UX Design Case Study + +- URL: https://staging.keepsimple.io/uxcore/uiux +- Description: UI-UX design case study on a real-world multi-million $ project. The study includes examples of work in Figma and the PRD standard used for the project. diff --git a/public/keepsimple_/llms-full-pages/article/ux-core-in-education.md b/public/keepsimple_/llms-full-pages/article/ux-core-in-education.md new file mode 100644 index 0000000..54421f0 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/ux-core-in-education.md @@ -0,0 +1,4 @@ +# Implementation of UX Core in Educational Systems + +- URL: https://staging.keepsimple.io/articles/ux-core-in-education +- Description: The article describes a few offline games that can be embedded into the existing education programs to increase self-awareness and knowledge of cognitive biases diff --git a/public/keepsimple_/llms-full-pages/article/uxcgdiy.md b/public/keepsimple_/llms-full-pages/article/uxcgdiy.md new file mode 100644 index 0000000..16801e8 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/uxcgdiy.md @@ -0,0 +1,4 @@ +# How UXCG was built + +- URL: https://staging.keepsimple.io/articles/uxcgdiy +- Description: This article describes how the UXCG tool was built from concept to release. It illustrates in detail all the author's thoughts while researching the topic. diff --git a/public/keepsimple_/llms-full-pages/article/uxcgstory.md b/public/keepsimple_/llms-full-pages/article/uxcgstory.md new file mode 100644 index 0000000..74733f3 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/uxcgstory.md @@ -0,0 +1,4 @@ +# UX Core Guide introduction + +- URL: https://staging.keepsimple.io/articles/uxcgstory +- Description: This article describes a tool called "UX Core Guide", that allows you to look at common management-related questions from the perspective of cognitive biases. diff --git a/public/keepsimple_/llms-full-pages/article/what-is-a-project.md b/public/keepsimple_/llms-full-pages/article/what-is-a-project.md new file mode 100644 index 0000000..79fb889 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/what-is-a-project.md @@ -0,0 +1,4 @@ +# #1. What is a project? + +- URL: https://staging.keepsimple.io/articles/what-is-a-project +- Description: The article describes what can be considered as a project. diff --git a/public/keepsimple_/llms-full-pages/article/what-is-ux-core.md b/public/keepsimple_/llms-full-pages/article/what-is-ux-core.md new file mode 100644 index 0000000..fc3ded2 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/what-is-ux-core.md @@ -0,0 +1,4 @@ +# Reintroduction to UX Core - the world’s biggest open-source library of nudging strategies and cognitive biases. + +- URL: https://staging.keepsimple.io/articles/what-is-ux-core +- Description: Introduction of UX Core - World's biggest free library of cognitive biases and nudging strategies. diff --git a/public/keepsimple_/llms-full-pages/article/why-study-management.md b/public/keepsimple_/llms-full-pages/article/why-study-management.md new file mode 100644 index 0000000..a1305d2 --- /dev/null +++ b/public/keepsimple_/llms-full-pages/article/why-study-management.md @@ -0,0 +1,4 @@ +# Why study management? + +- URL: https://staging.keepsimple.io/articles/why-study-management +- Description: This article describes the importance of management and why everyone should study management basics regardless of their specialty and interests. diff --git a/public/keepsimple_/llms-full.txt b/public/keepsimple_/llms-full.txt new file mode 100644 index 0000000..4da9cd6 --- /dev/null +++ b/public/keepsimple_/llms-full.txt @@ -0,0 +1,226 @@ +# Keep Simple | Cognitive Science & UX Leadership +> Elevate your leadership with applied cognitive science. Explore behavioral psychology and cognitive frameworks designed for modern managers. + +## Pages & Resources +- [Home](https://keepsimple.io/): KeepSimple home page. +- [Slug](https://keepsimple.io/[page]): No description available. +- [Articles](https://keepsimple.io/articles): Browse all KeepSimple articles and categories. +- [Articles All About User Stories Brand New](https://keepsimple.io/articles/all-about-user-stories-brand-new): This article describes how to write user stories. The author uses real-world example based on the real feature developed for a major online platform. +- [Articles Awareness Test](https://keepsimple.io/articles/awareness-test): Article describing the creation of the first self-awareness online test built on top of cognitive biases +- [Articles Career Path Of A Manager And A Few Universal Tips](https://keepsimple.io/articles/career-path-of-a-manager-and-a-few-universal-tips): The article summarizes what was described in all previous articles and what are the possible ways of a project manager's career development. +- [Articles Client Dev Company Workflow Birds Eye View](https://keepsimple.io/articles/client-dev-company-workflow-birds-eye-view): This article illustrates what the common cooperation process between the customer and the software development company looks like. +- [Articles Create Behavioral User Personas](https://keepsimple.io/articles/create-behavioral-user-personas): Want to build better user personas? Here are the most comprehensive insights about how to create behavioral user personas using cognitive biases +- [Articles Explain To Learn](https://keepsimple.io/articles/explain-to-learn): Read how explaining can be the best skill to boost your learning and communication skills. +- [Articles Friendship Explained](https://keepsimple.io/articles/friendship-explained): Learn how to quantify your relationships with the Friendship Index. A practical framework to measure loyalty, balance, and sacrifice in friendships. +- [Articles Https: Academic.oup.com Oxford Law Pro Edited Volume 59931 Chapter Abstract 558539856?redirectedFrom=fulltext&login=false](https://keepsimple.io/articles/https://academic.oup.com/oxford-law-pro/edited-volume/59931/chapter-abstract/558539856?redirectedFrom=fulltext&login=false): Bias amplification: how social media makes users more vulnerable to sub-optimal decisions +- [Articles Overengineering And Demo Readiness](https://keepsimple.io/articles/overengineering_and_demo_readiness): How to solve overengineering issues in engineering teams, and how to always be ready for important DEMOs and milestones. +- [Articles Philosophies Methodologies And Frameworks](https://keepsimple.io/articles/philosophies-methodologies-and-frameworks): The article describes the fundamental differences between project management philosophies, methodologies, and frameworks. +- [Articles Practical Longevity Protocol](https://keepsimple.io/articles/practical-longevity-protocol): Why Longevity is the most important trend nowadays and beyond +- [Articles Project Approval And Further Workflow](https://keepsimple.io/articles/project-approval-and-further-workflow): This article describes the process of project requirements analysis, documentation writing, user stories evaluation and other mandatory steps. +- [Articles Project Artifacts And Their Importance](https://keepsimple.io/articles/project-artifacts-and-their-importance): A clear guide to software project artifacts. Understand the difference between Epics, User Stories, Tasks, and Bugs to improve team efficiency. +- [Articles Project Management Environment](https://keepsimple.io/articles/project-management-environment): This article describes the environment of modern project manager, the tools they use, and the best practices for solving communication and collaboration issues. +- [Articles Scrum Framework Artifacts Rituals And Roles](https://keepsimple.io/articles/scrum-framework-artifacts-rituals-and-roles): This article describes all SCRUM Framework artifacts, rituals, and roles, including nuanced details such as the definition of Done, Increment, and others. +- [Articles Software Development Life Cycles](https://keepsimple.io/articles/software-development-life-cycles): The article describes all actual software development life cycles (SDLCs), in particular Predictive, Iterative, Incremental, and Agile. +- [Articles Summarize Like Your Job Depends On It](https://keepsimple.io/articles/summarize-like-your-job-depends-on-it): The article describes the importance of summarization, making quality executive summaries and its impact on career. +- [Articles Table Of Contents](https://keepsimple.io/articles/table-of-contents): This page describes the data presented in all project management articles on KeepSimple website. +- [Articles Technical Components Of The Project](https://keepsimple.io/articles/technical-components-of-the-project): A brief introduction of the main technical components and terms used in the infrastructure of any software project +- [Articles Uiux](https://keepsimple.io/articles/uiux): UI-UX design case study on a real-world multi-million $ project. The study includes examples of work in Figma and the PRD standard used for the project. +- [Articles Ux Core In Education](https://keepsimple.io/articles/ux-core-in-education): The article describes a few offline games that can be embedded into the existing education programs to increase self-awareness and knowledge of cognitive biases +- [Articles Uxcgdiy](https://keepsimple.io/articles/uxcgdiy): This article describes how the UXCG tool was built from concept to release. It illustrates in detail all the author's thoughts while researching the topic. +- [Articles Uxcgstory](https://keepsimple.io/articles/uxcgstory): This article describes a tool called "UX Core Guide", that allows you to look at common management-related questions from the perspective of cognitive biases. +- [Articles What Is A Project](https://keepsimple.io/articles/what-is-a-project): The article describes what can be considered as a project. +- [Articles What Is Ux Core](https://keepsimple.io/articles/what-is-ux-core): Introduction of UX Core - World's biggest free library of cognitive biases and nudging strategies. +- [Articles Why Study Management](https://keepsimple.io/articles/why-study-management): This article describes the importance of management and why everyone should study management basics regardless of their specialty and interests. +- [Auth](https://keepsimple.io/auth): Authentication page for KeepSimple. +- [Company Management](https://keepsimple.io/company-management): Explore company management resources. +- [Contributors](https://keepsimple.io/contributors): Meet the KeepSimple contributors. +- [Tools](https://keepsimple.io/tools): No description available. +- [Tools Longevity Protocol About Project](https://keepsimple.io/tools/longevity-protocol/about-project): No description available. +- [Tools Longevity Protocol Environment](https://keepsimple.io/tools/longevity-protocol/environment): No description available. +- [Tools Longevity Protocol Habits Diet](https://keepsimple.io/tools/longevity-protocol/habits/diet): No description available. +- [Tools Longevity Protocol Habits Lifestyle](https://keepsimple.io/tools/longevity-protocol/habits/lifestyle): No description available. +- [Tools Longevity Protocol Habits Sleep](https://keepsimple.io/tools/longevity-protocol/habits/sleep): No description available. +- [Tools Longevity Protocol Habits Study](https://keepsimple.io/tools/longevity-protocol/habits/study): No description available. +- [Tools Longevity Protocol Habits Supplements](https://keepsimple.io/tools/longevity-protocol/habits/supplements): No description available. +- [Tools Longevity Protocol Habits Workout](https://keepsimple.io/tools/longevity-protocol/habits/workout): No description available. +- [Tools Longevity Protocol Results](https://keepsimple.io/tools/longevity-protocol/results): No description available. +- [See All Articles](https://keepsimple.io/articles): Browse all KeepSimple articles and categories. +- [Auth](https://keepsimple.io/auth) +- [Certificate](https://keepsimple.io/user/[userId]/certificate) +- [User Profile](https://keepsimple.io/user/username) +- [Uxcat](https://keepsimple.io/uxcat): First of its kind online test to measure and increase self-awareness +- [Ongoing](https://keepsimple.io/uxcat/ongoing): First of its kind online test to measure and increase self-awareness +- [Start Test](https://keepsimple.io/uxcat/start-test): First of its kind online test to measure and increase self-awareness +- [Test Result](https://keepsimple.io/uxcat/test-result): First of its kind online test to measure and increase self-awareness +- [Why our company has reputation issue?](https://keepsimple.io/uxcg/why-our-company-is-having-reputation-issue): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why users aren't happy with product quality?](https://keepsimple.io/uxcg/why-our-users-are-not-happy-with-product): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why users don't use requested features?](https://keepsimple.io/uxcg/why-users-do-not-use-requested-features): The following 13 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why did we fail to create the right product associations in the market?](https://keepsimple.io/uxcg/we-could-not-create-needed-associations-on-the-market): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do users complain about product updates?](https://keepsimple.io/uxcg/why-users-complain-about-product-updates): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why didn’t our product meet user expectations?](https://keepsimple.io/uxcg/why-our-product-did-not-meet-user-expectations): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why don’t users like the product anymore?](https://keepsimple.io/uxcg/why-dont-users-like-the-product-anymore): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why are users so sensitive to product changes?](https://keepsimple.io/uxcg/why-users-so-sensitive-to-product-changes): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do our users find our communication overwhelming?](https://keepsimple.io/uxcg/users-find-our-communication-overwhelming): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do users complain about the quality of our support?](https://keepsimple.io/uxcg/users-do-not-like-our-customer-support): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Users blame us for their own mistakes](https://keepsimple.io/uxcg/users-blame-us-for-their-own-mistakes): The following 4 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do potential users overstate the risks of using the product?](https://keepsimple.io/uxcg/users-overstate-product-risks): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why don’t our users follow the safety rules?](https://keepsimple.io/uxcg/users-dont-follow-safety-rules): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why were we accused of being careless in business?](https://keepsimple.io/uxcg/we-were-accused-of-being-careless): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do users say our product is boring?](https://keepsimple.io/uxcg/users-call-our-product-boring): The following 5 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why aren’t our promotions working?](https://keepsimple.io/uxcg/why-arent-our-promotions-working): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why don’t users use most of our product features?](https://keepsimple.io/uxcg/why-users-dont-use-most-of-our-product-features): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why don’t users pay attention to the most important parts of the product?](https://keepsimple.io/uxcg/users-ignore-most-important-parts-of-the-product): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do potential users mainly notice the flaws in our product?](https://keepsimple.io/uxcg/users-mainly-notice-flaws-in-our-product): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we boost sales on our project?](https://keepsimple.io/uxcg/how-can-we-boost-sales): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Users don’t like how we talk to them — where did we mess up?](https://keepsimple.io/uxcg/users-dont-like-our-communication): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why didn’t users like or appreciate the recent product update?](https://keepsimple.io/uxcg/users-didnt-like-recent-update): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we make one of our products stand out among the rest?](https://keepsimple.io/uxcg/how-to-popularize-one-product-among-others): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How do we nudge users to take the actions we want with minimal cost?](https://keepsimple.io/uxcg/how-to-nudge-users): The following 21 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we reduce the amount of money withdrawn by project users?](https://keepsimple.io/uxcg/how-to-reduce-widrawn-money-amount): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to make bonuses and promotions more attractive to users?](https://keepsimple.io/uxcg/how-to-make-bonuses-and-promotions-more-attractive): The following 16 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to launch in a market with strong negative associations?](https://keepsimple.io/uxcg/how-to-launch-in-a-market-with-strong-negative-associations): The following 13 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What mistakes do we make when evaluating our marketing strategies?](https://keepsimple.io/uxcg/marketing-strategies-evaluation-mistakes): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to provide the best purchasing experience for users?](https://keepsimple.io/uxcg/how-to-provide-best-purchasing-experience-for-users): The following 14 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What common mistakes do we make when dealing with product analytics?](https://keepsimple.io/uxcg/common-mistakes-in-product-analytics): The following 25 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to protect yourself from fake news (or other information warfare)](https://keepsimple.io/uxcg/how-to-protect-yourself-from-fake-news): The following 14 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we maximize the comfort of the product?](https://keepsimple.io/uxcg/how-can-we-ensure-comfort-in-our-product): The following 25 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to do if a user reports an event the system doesn't show?](https://keepsimple.io/uxcg/user-reported-nonexistent-event): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we make the product look more modern without spending much?](https://keepsimple.io/uxcg/how-to-make-product-look-modern-at-lowest-cost): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to work with gambling in a product?](https://keepsimple.io/uxcg/how-to-work-with-gambling): The following 22 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we establish a sense of trust within a social project?](https://keepsimple.io/uxcg/how-to-establish-trust-within-a-social-project): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What are the risks of major changes to the product’s ideology or functionality?](https://keepsimple.io/uxcg/risks-of-major-changes-in-product-functionality-or-ideology): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when creating moderation/arbitrage features?](https://keepsimple.io/uxcg/how-to-build-moderation-features-in-produkt): The following 15 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we make our product users more responsible?](https://keepsimple.io/uxcg/how-to-make-users-more-responsible): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we show content to users more effectively?](https://keepsimple.io/uxcg/how-to-show-content-to-users-more-effectively): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we do if our colleagues’ stubbornness is hurting teamwork?](https://keepsimple.io/uxcg/our-stubborn-colleague-is-hurting-teamwork): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we generate new products "out of thin air" while keeping costs minimal?](https://keepsimple.io/uxcg/how-to-create-new-products-out-of-thin-air): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when planning product releases?](https://keepsimple.io/uxcg/what-to-consider-when-planning-product-releases): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when working with user feedback?](https://keepsimple.io/uxcg/what-to-consider-when-working-with-user-feedback): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to do if our team members do not share their opinion?](https://keepsimple.io/uxcg/what-if-our-team-members-dont-share-their-opinion): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to simplify our product?](https://keepsimple.io/uxcg/how-to-simplify-our-product): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we keep in mind when reaching out to a user directly?](https://keepsimple.io/uxcg/what-to-consider-when-reaching-out-to-the-user-directly): The following 24 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when involving users in product development](https://keepsimple.io/uxcg/involving-users-in-product-development): The following 5 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we do when users ask for things we can’t deliver?](https://keepsimple.io/uxcg/users-ask-things-we-cant-deliver): The following 8 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to deal with an incompetent colleague/manager?](https://keepsimple.io/uxcg/how-to-deal-with-incompetent-colleague): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What causes users to make mistakes when using our product?](https://keepsimple.io/uxcg/what-causes-users-to-make-mistakes-when-using-our-product): The following 5 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How to involve users into our product testing?](https://keepsimple.io/uxcg/how-to-involve-users-into-product-testing): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we consider when removing unnecessary product features?](https://keepsimple.io/uxcg/what-to-consider-when-removing-unnecessary-product-features): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should be considered when adding new product functionality?](https://keepsimple.io/uxcg/what-to-consider-when-adding-new-functionality-into-product): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Which product components are most sensitive to change?](https://keepsimple.io/uxcg/which-product-components-are-most-sensitive-to-changes): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when working with lists (any)?](https://keepsimple.io/uxcg/what-to-consider-when-working-with-lists): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we add extra value to a product at minimal cost?](https://keepsimple.io/uxcg/how-to-add-extra-value-to-a-product-at-minimal-cost): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [How can we make sure users notice the information that matters most to us?](https://keepsimple.io/uxcg/how-to-ensure-users-noticed-the-information-that-matters): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we consider when referencing political, social, or economic events in our messages?](https://keepsimple.io/uxcg/referring-to-political-social-or-economic-events): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we do if users are struggling on the product or service selection page?](https://keepsimple.io/uxcg/users-struggle-on-product-or-service-selection-page): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What should we do if our team wastes too much time on minor details?](https://keepsimple.io/uxcg/team-wastes-too-much-time-on-minor-details): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to consider when creating a “Persona” for a product?](https://keepsimple.io/uxcg/creating-product-persona): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [What to do if a significant mistake occurred in the latest release?](https://keepsimple.io/uxcg/we-made-a-mistake-in-last-release): The following 11 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [See All UXCG](https://keepsimple.io/uxcg): An extensive knowledge base containing over 1,000 practical examples of applying cognitive biases in business - from idea generation to product launch +- [Availability heuristics](https://keepsimple.io/uxcore/1-availability-heuristics): Explore Availability Heuristics Bias in our UX Core project. Learn how this cognitive bias influences decision-making in product management and HR for free. +- [Attentional bias](https://keepsimple.io/uxcore/2-attentional-bias): Discover attentional bias – a cognitive quirk shaping human focus. Learn how to leverage it in UX and HR for better decision-making. Explore at UX Core. +- [Illusory truth effect](https://keepsimple.io/uxcore/3-illusory-truth-effect): "Elevate your management skills with an understanding of the illusory truth effect! Explore practical applications in HR and product management at UX Core." +- [Mere-exposure effect](https://keepsimple.io/uxcore/4-mere-exposure-effect): Learn how to utilize this bias in software development, applications, product management, and HR activities. Explore all this and more for free, only at UX Core +- [Context effect](https://keepsimple.io/uxcore/5-context-effect): Learn how to use Context Effect in software development, team, and company management. Hands-on examples of use and a lot more for free, only at UX Core project +- [ Cue-dependent forgetting](https://keepsimple.io/uxcore/6-cue-dependent-forgetting): Explore Cue-Dependent Forgetting: Uncover how memory retrieval cues affect information recall. Learn its impact on UX and HR strategies for free at UX Core. +- [Mood-congruent memory bias](https://keepsimple.io/uxcore/7-mood-congruent-memory-bias): Harness Mood-Congruent Memory Bias: Enhance user experiences and HR practices by understanding how emotions influence memory recall. Explore insights at UX Core +- [Frequency illusion](https://keepsimple.io/uxcore/8-frequency-illusion): Master Frequency Illusion Bias: Elevate UX and HR techniques through strategic utilization of cognitive biases. Learn practical applications at UX Core for free +- [Empathy gap](https://keepsimple.io/uxcore/9-empathy-gap): Discover how the empathy gap can be used when developing a product or working in HR team. Harness cognitive bias for improved decision-making. Free at UX Core. +- [Omission bias](https://keepsimple.io/uxcore/10-omission-bias): Explore omission bias: a cognitive inclination to favor inaction over action. Learn how to address it in product management and HR strategies. #UXCore +- [Base rate fallacy](https://keepsimple.io/uxcore/11-base-rate-fallacy): Dive into the base rate fallacy, a common cognitive bias affecting decision-making. Discover its impact on HR and product management. #UXCore free project. +- [Bizarreness effect](https://keepsimple.io/uxcore/12-bizarreness-effect): People tend to remember bizarre material better than common material. But how can we use this in product management and UX design? Hands-on examples at UX Core. +- [Humor effect](https://keepsimple.io/uxcore/13-humor-effect): Humorous items are more easily remembered than non-humorous ones. Discover how we can use this bias in product development, company management and HR at UX Core +- [Picture superiority effect](https://keepsimple.io/uxcore/14-picture-superiority-effect): What to use - images or words? What will be more efficient? Learn with us how to use picture superiority effect in product management, UX design, and HR works. +- [Von Restorff effect](https://keepsimple.io/uxcore/15-von-restorff-effect): Learn how to use isolation effect in ux design, corporate communication and company management. Hands-on examples of use in product management and HR. +- [Self-reference effect](https://keepsimple.io/uxcore/16-self-reference-effect): Learn how to develop more engaging content using self-reference effect. Hands-on examples for product and HR teams. This and a lot more for free at UX Core. +- [Negativity bias](https://keepsimple.io/uxcore/17-negativity-bias): Negativity isn't something to avoid, but rather to learn and understand. Discover how to use negativity effect in product management, HR, and company management +- [Anchoring effect](https://keepsimple.io/uxcore/18-anchoring-effect): Mastering Anchoring Effect Bias: Boost UX and HR decisions. Learn practical insights for effective product management. Explore UX Core's comprehensive guide! +- [Conservatism (belief revision)](https://keepsimple.io/uxcore/19-conservatism-belief-revision): Learn how to work with people beliefs, and how to influence their decisions. Real-world hands-on examples of use in product management, HR, and business. +- [Contrast effect](https://keepsimple.io/uxcore/20-contrast-effect): Unlocking the Mind: Explore the Contrast Effect cognitive bias. Understand how perception skews based on surrounding stimuli. Learn more for free at UX Core. +- [Distinction bias](https://keepsimple.io/uxcore/21-distinction-bias): Learn how to use this bias in your app's information architecture. Hands-on examples of use in product management (feature development) and HR (interviews). +- [Framing effect](https://keepsimple.io/uxcore/22-framing-effect): Learn how to use one of the most ubiquitous biases. Real-world examples for product and HR teams. Enhance your communication skills and your app's messages. +- [Money illusion](https://keepsimple.io/uxcore/23-money-illusion): Be it in-game or real money, there are very interesting techniques on how we can nudge our users or colleagues towards certain decisions. Learn how at UX Core. +- [Weber-Fechner Law](https://keepsimple.io/uxcore/24-weber-fechner-law): Discover how the Weber-Fechner Law affects user perception. Learn cognitive strategies to manage pricing, product updates, and user experience. +- [Confirmation bias](https://keepsimple.io/uxcore/25-confirmation-bias): Learn how to work with people's expectations when designing a new feature, developing a new product, or screening potential hiring candidates for your company. +- [Congruence bias](https://keepsimple.io/uxcore/26-congruence-bias): Learn how congruence bias affects your decision-making and data analysis skills. Real-world examples of use on software product A/B tests and HR teamwork focus. +- [Post-purchase rationalization](https://keepsimple.io/uxcore/27-post-purchase-rationalization): Discover how your brain tricks you after some heavy decision. Real-world examples of this bias in product purchase workflow and workplace change decisions. +- [Selective perception](https://keepsimple.io/uxcore/28-selective-perception): Learn how this bias can damage our decision-making process. Real-world examples of use in software products and its damage to in-house culture and HR practices. +- [Observer-expectancy effect](https://keepsimple.io/uxcore/29-observer-expectancy-effect): You can distort your own experiment simply because you don't know this bias. Learn how to defend against it and how to use it in product development and HR. +- [Ostrich effect](https://keepsimple.io/uxcore/30-ostrich-effect): Spend 30 seconds to learn how we hide uncomfortable thoughts and how damaging that habit is. Real-world examples of using this bias in product management and HR +- [Subjective validation](https://keepsimple.io/uxcore/31-subjective-validation): Combat subjective validation bias in UX & HR. Discover its impact on decision-making. Explore solutions & examples on UX Core. Free resource for bias awareness +- [Continued influence effect](https://keepsimple.io/uxcore/32-continued-influence-effect): Propaganda influence is continued even when people expose it. Learn for free how to defend yourself as well as use this bias in product and company management. +- [Bias blind spot](https://keepsimple.io/uxcore/33-bias-blind-spot): People tend to think they're not biased. Explore how you can get value out of this bias in product management and HR activities, for free, at UX Core project. +- [Clustering Illusion](https://keepsimple.io/uxcore/34-clustering-illusion): Discover Clustering Illusion: Uncover cognitive bias in product management & HR. Explore 105 biases in the UX Core project. Free tool for better decisions. +- [Insensitivity to sample size](https://keepsimple.io/uxcore/35-insensitivity-to-sample-size): Learn how to work with this bias affecting our sample size understanding when working with statistics and data. Real-world examples of use in product and HR. +- [Neglect of probability](https://keepsimple.io/uxcore/36-neglect-of-probability): Neglect of Probability Bias: Explore this cognitive bias in the UX Core project. See how overlooked odds lead to flawed decisions for free at UX Core project. +- [Anecdotal evidence](https://keepsimple.io/uxcore/37-anecdotal-evidence): Learn how to work with anecdotal evidence when communicating with your company employees or product customers. This and many other insights at UX Core. +- [Illusion of validity](https://keepsimple.io/uxcore/38-illusion-of-validity): Illusion of Validity Bias: Uncover cognitive bias in UX Core project. Overestimate data's reliability, impacting decisions. Free tool for clarity & insight. +- [Recency illusion](https://keepsimple.io/uxcore/39-recency-illusion): Learn how to use Recency Illusion bias in UX & HR. Enhance decision-making. Explore this and more than 100 cognitive biases in our free tool, UX Core. +- [Gambler’s fallacy](https://keepsimple.io/uxcore/40-gamblers-fallacy): Learn how to use Gambler's fallacy in any software product, and see how the same bias affects your company's in-house atmosphere. This and a lot more at UX Core +- [Hot hand fallacy](https://keepsimple.io/uxcore/41-hot-hand-fallacy): Learn how to use this and 100 of other cognitive biases in product and company management, exclusively at UX Core free educational project. #uxcore #science +- [Illusory correlation](https://keepsimple.io/uxcore/42-illusory-correlation): Discovering Illusory correlation and how to use this cognitive bias in product management and HR. This and 100 other biases are explained for free at UX Core. +- [Group attribution error](https://keepsimple.io/uxcore/43-group-attribution-error): Learn how to use this bias in product management and HR. This and 100 other cognitive biases explained for free, exclusively at UX Core educational project. +- [Fundamental attribution error](https://keepsimple.io/uxcore/44-fundamental-attribution-error): Learn how we tend to explain our successes and losses. This and more than 100 other cognitive biases illustrated in product management and HR only at UX Core. +- [Stereotype](https://keepsimple.io/uxcore/45-stereotype): A stereotype is not something we can avoid. It's how our brain works. Learn how to use it in product management and HR, exclusively at UX Core free project. +- [Functional fixedness](https://keepsimple.io/uxcore/46-functional-fixedness): Using an object in one quality prevents its subsequent use in different quality in the same current situation. Learn how to use it in product management and HR. +- [Just-world fallacy](https://keepsimple.io/uxcore/47-just-world-fallacy): We tend to believe that the world is fair but we don't know this is a cognitive bias rooted in all humans. Learn how to work with it for free at UX Core project +- [Authority bias](https://keepsimple.io/uxcore/48-authority-bias): Have you ever thought of authority in the context of cognitive biases? Learn why people become victims of authorities and how to use this bias in product and HR +- [Automation bias](https://keepsimple.io/uxcore/49-automation-bias): Learn how to avoid confusing automation reliability when designing a complex product. The higher the impact, the more important this cognitive bias becomes. +- [Bandwagon effect](https://keepsimple.io/uxcore/50-bandwagon-effect): This bias is the cornerstone of any propaganda machine, as well as top-notch product marketing and brand development. Learn how to use it for free at UX Core +- [Placebo](https://keepsimple.io/uxcore/51-placebo): Everyone heard of a placebo, but do you know how to generate value using it in management and HR? Learn this and 100 more cognitive biases for free at UX Core. +- [Out-group homogeneity](https://keepsimple.io/uxcore/52-out-group-homogeneity): Learn the roots of stereotype forming, and discover new ways of working with these cognitive biases in product management and HR. Forever free, at UX Core. +- [In-group favoritism](https://keepsimple.io/uxcore/53-in-group-favoritism): This bias describes the tendency to somehow help members of our own group as opposed to another. Learn how to use this in product management and HR activities. +- [Halo effect](https://keepsimple.io/uxcore/54-halo-effect): Our impressions of a person influence our decision-making. Learn how to leverage this cognitive bias in product management and HR activities. Free at UX Core. +- [Positivity effect](https://keepsimple.io/uxcore/55-positivity-effect): Learn the importance of this bias and how to use it in product management and HR. This and 100 other cognitive biases explained for free, only at UX Core. +- [Not invented here](https://keepsimple.io/uxcore/56-not-invented-here): Sometimes the stubbornness we see in our colleagues is a cognitive bias that might damage our company and product. Learn how to work with it for free at UX Core +- [Mental accounting](https://keepsimple.io/uxcore/57-mental-accounting): Learn this and 100 other cognitive biases on real-world software product development and HR examples. Forever free at UX Core educational project. +- [Normality bias](https://keepsimple.io/uxcore/58-normality-bias): People believe that the future will be like the past and underestimate the chances and consequences of a disaster. Learn how to use this in product and HR. +- [Survival bias](https://keepsimple.io/uxcore/59-survival-bias): Our tendency to focus only on successful data can significantly distort our decision-making. Learn how to secure yourself from this for free, only at UX Core. +- [Subadditivity effect](https://keepsimple.io/uxcore/60-subadditivity-effect): Learn everything about this and 100 other cognitive biases for free only at the UX Core project. Real-world examples of use in product management and HR fields. +- [The Magical Number 7±2](https://keepsimple.io/uxcore/61-the-magical-number-72): Get insights into how human memory works and how to use this knowledge in product management, UX design, and HR. This and 100 other cognitive biases at UX Core +- [Illusion of transparency](https://keepsimple.io/uxcore/62-illusion-of-transparency): This is a tendency of people to overestimate the ability of others to understand them. Spend a minute to learn how to use this in product management and HR. +- [Curse of knowledge](https://keepsimple.io/uxcore/63-curse-of-knowledge): The more we are informed, the more challenging it is to understand a less informed person's point of view. Learn how to use this knowledge in management. +- [Spotlight effect](https://keepsimple.io/uxcore/64-spotlight-effect): People tend to believe that others pay more attention to them than they actually do. Learn how to generate value out of this bias in product and HR management. +- [Illusion of asymmetric insight](https://keepsimple.io/uxcore/65-illusion-of-asymmetric-insight): We tend to believe that we can see through every person (while they can't). Learn how to use this and 100 other cognitive biases in product management and HR. +- [Hindsight bias](https://keepsimple.io/uxcore/66-hindsight-bias): People perceive events that have already been established as obvious. Learn how to use this cognitive bias when building a product or managing a company. +- [Planning fallacy](https://keepsimple.io/uxcore/67-planning-fallacy): Underestimation of the time required to complete the task is a natural thing for humans. Learn how to use this cognitive bias in product management and HR team. +- [Pro-innovation bias](https://keepsimple.io/uxcore/68-pro-innovation-bias): Discover the power of Pro-Innovation Bias - Embrace change, foster growth, and drive success. Learn how to use this bias for your organization's success today! +- [Overconfidence effect](https://keepsimple.io/uxcore/69-overconfidence-effect): Navigate with caution: Uncover the Overconfidence Effect - Explore its impact on decision-making and how to make smarter choices. Learn more for free at UX Core +- [Social desirability bias](https://keepsimple.io/uxcore/70-social-desirability-bias): People tend to give answers that they think are socially acceptable or desirable rather than providing their true beliefs or behaviors. Learn how to use it. +- [Third-person effect](https://keepsimple.io/uxcore/71-third-person-effect): People tend to believe that different marketing tricks and advertisements do not affect them. Learn how to use this bias in your product management and HR team. +- [Consensus bias](https://keepsimple.io/uxcore/72-consensus-bias): This cognitive bias shows how we can use people's tendency to believe that everyone else thinks exactly like they do—real product management and HR examples. +- [Hard-easy effect](https://keepsimple.io/uxcore/73-hard-easy-effect): People are prone to overestimate and underestimate their powers in task-solving. Learn how this bias can be used when designing a product or working in HR team. +- [Dunning-Kruger effect](https://keepsimple.io/uxcore/74-dunning-kruger-effect): This cognitive bias is vital to understand by everyone. Learn how to alleviate its effect on your decision-making and how to use it in product management and HR +- [Barnum effect](https://keepsimple.io/uxcore/75-barnum-effect): This cognitive bias explains the popularity of horoscopes and many other topics related to metaphysics. Learn real-world examples of how to use it in management +- [Illusion of control](https://keepsimple.io/uxcore/76-illusion-of-control): This bias is about people thinking they can control or significantly impact events that are beyond their control. This knowledge can help us to generate value. +- [Illusory superiority](https://keepsimple.io/uxcore/77-illusory-superiority): Learn how to use this cognitive bias in real-world examples in product management and the HR team. This and 100 other biases are explained for free at UX Core. +- [Risk compensation](https://keepsimple.io/uxcore/78-risk-compensation): The more complex the software you build, the more this bias becomes. Too many protective devices and safety measures increase the risk of accidents. Learn why. +- [Hyperbolic discounting](https://keepsimple.io/uxcore/79-hyperbolic-discounting): We often prefer immediate rewards instead of waiting a bit for more valuable ones. Learn how to use this cognitive bias in product management and HR for free. +- [Appeal to novelty](https://keepsimple.io/uxcore/80-appeal-to-novelty): An important bias when building marketing strategies for your product. A real-world example of this and 100 other cognitive biases for free, only at UX Core. +- [Escalation of commitment](https://keepsimple.io/uxcore/81-escalation-of-commitment): People continue to invest time, money, or resources into a failing decision or course of action, even when it's clear that the situation is not going well. +- [Generation effect](https://keepsimple.io/uxcore/82-generation-effect): If one's mind has made up some "facts", reassuring them of something else doesn't make sense. Learn how to work with this bias and use it in product management. +- [Loss aversion](https://keepsimple.io/uxcore/83-loss-aversion): As one of the most popular cognitive biases, loss aversion can generate a lot of value for us when used properly in product development or HR management. +- [IKEA effect](https://keepsimple.io/uxcore/84-ikea-effect): Explore how to use this and 100 other cognitive biases in product management, design and HR for FREE. No registration is needed. Exclusively at UX Core project. +- [Unit bias](https://keepsimple.io/uxcore/85-unit-bias): This is a tendency for people to want to complete their assigned tasks. Learn how this cognitive bias can be used in product management, UI-UX design and HR. +- [Zero-risk bias](https://keepsimple.io/uxcore/86-zero-risk-bias): This bias helps us to understand how we make decisions when there are risks involved. Learn how to use it in product management and HR for free at UX Core. +- [Processing difficulty effect](https://keepsimple.io/uxcore/87-processing-difficulty-effect): It’s easier for people to remember information that requires more time to read and understand. Learn how to balance cognitive load in product management and HR. +- [Endowment effect](https://keepsimple.io/uxcore/88-endowment-effect): We often place a higher value on things we possess simply because we possess them. This and 100 other cognitive biases with examples of use only at UX Core! +- [Backfire effect](https://keepsimple.io/uxcore/89-backfire-effect): Instead of questioning our beliefs when we encounter challenges, we may become even more steadfast in them. Learn how to use this cognitive bias in management. +- [System justification](https://keepsimple.io/uxcore/90-system-justification): This is a tendency to protect and preserve the current state of things. Learn real-world examples of how to use this bias in product management and HR for free. +- [Reactance](https://keepsimple.io/uxcore/91-reactance): Behavioral bias the primary goal of which is to regain the freedom that has been lost or limited. Learn how to use this in product management and HR for FREE. +- [Decoy effect](https://keepsimple.io/uxcore/92-decoy-effect): Also known as the effect of asymmetric superiority. Learn how to generate value out of this bias when building a product or managing a company. Free at UX Core. +- [Ambiguity effect](https://keepsimple.io/uxcore/93-ambiguity-effect): People naturally prefer things they can understand and predict. Learn how you can use this when building a product or managing a company. Free at UX Core. +- [Information bias](https://keepsimple.io/uxcore/94-information-bias): This is a tendency to seek information when it does not influence actions. Learn how your product and company can benefit from understanding this for free. +- [Law of triviality](https://keepsimple.io/uxcore/95-law-of-triviality): This cognitive bias emphasizes that the members of the organization attach excessive importance to trivial issues. Learn how to deal with this in management. +- [Conjunction fallacy](https://keepsimple.io/uxcore/96-conjunction-fallacy): This bias is associated with giving greater credibility to joint events than to events separately. Learn how to use this in product management and HR for free! +- [Less-is-better effect](https://keepsimple.io/uxcore/97-less-is-better-effect): People prefer small or less expensive items but a little better quality. Learn how to use this and 100 other cognitive biases in product management and HR. +- [Implicit stereotypes](https://keepsimple.io/uxcore/98-implicit-stereotypes): Implicit stereotypes, also known as implicit associations, are when we unconsciously attribute certain qualities to people based on their social group. +- [Prejudice](https://keepsimple.io/uxcore/99-prejudice): Prejudice involves such aspects as stereotypes, superstitions, and biased views. Learn how to lower its impact on our decision-making process in product and HR. +- [Fading affect bias](https://keepsimple.io/uxcore/100-fading-affect-bias): A psychological phenomenon, according to which we tend to forget the memories associated with negative emotions faster than those associated with positive ones. +- [Peak-end rule](https://keepsimple.io/uxcore/101-peak-end-rule): We tend to remember overall experience based on how it felt at its most intense point and how it ended rather than considering the entire duration. Learn more. +- [Serial recall](https://keepsimple.io/uxcore/102-serial-recall): This is the ability to recall elements or events in the order in which they occurred. Learn how to use this when designing a product or managing an HR team. +- [List-length effect](https://keepsimple.io/uxcore/103-list-length-effect): According to this effect, the possibility of serial recall decreases with the increasing list length. Learn real-world use cases from product and HR management. +- [Primacy effect](https://keepsimple.io/uxcore/104-primacy-effect): The primacy effect is a natural tendency in humans to remember things that happen at the start of a process more easily than the rest. Learn how to use it. +- [Serial-position effect](https://keepsimple.io/uxcore/105-serial-position-effect): A person tends to recall the first and last items in a series better than the rest. Learn this and 100 other bias use cases in product and HR management. +- [See All UXCore](https://keepsimple.io/uxcore): Apply UX cognitive biases and behavioral patterns to improve product management and team leadership. +- [Uxcore Api](https://keepsimple.io/uxcore-api): Here is the list of all available API details, including the ability to fetch data about all cognitive biases on the project. +- [Uxcp](https://keepsimple.io/uxcp): This tool helps to create a Persona using cognitive biases for sales, marketing, other business teams, and educational purposes. diff --git a/public/keepsimple_/llms.txt b/public/keepsimple_/llms.txt new file mode 100644 index 0000000..b2fb9fc --- /dev/null +++ b/public/keepsimple_/llms.txt @@ -0,0 +1,62 @@ +# Keep Simple | Cognitive Science & UX Leadership +> Elevate your leadership with applied cognitive science. Explore behavioral psychology and cognitive frameworks designed for modern managers. + +## Pages & Resources +- [Home](https://keepsimple.io/): KeepSimple home page. +- [Slug](https://keepsimple.io/[page]): No description available. +- [Articles](https://keepsimple.io/articles): Browse all KeepSimple articles and categories. +- [Articles All About User Stories Brand New](https://keepsimple.io/articles/all-about-user-stories-brand-new): This article describes how to write user stories. The author uses real-world example based on the real feature developed for a major online platform. +- [Articles Career Path Of A Manager And A Few Universal Tips](https://keepsimple.io/articles/career-path-of-a-manager-and-a-few-universal-tips): The article summarizes what was described in all previous articles and what are the possible ways of a project manager's career development. +- [Articles Overengineering And Demo Readiness](https://keepsimple.io/articles/overengineering_and_demo_readiness): How to solve overengineering issues in engineering teams, and how to always be ready for important DEMOs and milestones. +- [Articles Philosophies Methodologies And Frameworks](https://keepsimple.io/articles/philosophies-methodologies-and-frameworks): The article describes the fundamental differences between project management philosophies, methodologies, and frameworks. +- [Articles Scrum Framework Artifacts Rituals And Roles](https://keepsimple.io/articles/scrum-framework-artifacts-rituals-and-roles): This article describes all SCRUM Framework artifacts, rituals, and roles, including nuanced details such as the definition of Done, Increment, and others. +- [Articles Software Development Life Cycles](https://keepsimple.io/articles/software-development-life-cycles): The article describes all actual software development life cycles (SDLCs), in particular Predictive, Iterative, Incremental, and Agile. +- [Articles Summarize Like Your Job Depends On It](https://keepsimple.io/articles/summarize-like-your-job-depends-on-it): The article describes the importance of summarization, making quality executive summaries and its impact on career. +- [Articles Technical Components Of The Project](https://keepsimple.io/articles/technical-components-of-the-project): A brief introduction of the main technical components and terms used in the infrastructure of any software project +- [Articles What Is A Project](https://keepsimple.io/articles/what-is-a-project): The article describes what can be considered as a project. +- [Articles Why Study Management](https://keepsimple.io/articles/why-study-management): This article describes the importance of management and why everyone should study management basics regardless of their specialty and interests. +- [Auth](https://keepsimple.io/auth): Authentication page for KeepSimple. +- [Company Management](https://keepsimple.io/company-management): Explore company management resources. +- [Contributors](https://keepsimple.io/contributors): Meet the KeepSimple contributors. +- [Tools](https://keepsimple.io/tools): No description available. +- [Tools Longevity Protocol About Project](https://keepsimple.io/tools/longevity-protocol/about-project): No description available. +- [Tools Longevity Protocol Environment](https://keepsimple.io/tools/longevity-protocol/environment): No description available. +- [Tools Longevity Protocol Habits Diet](https://keepsimple.io/tools/longevity-protocol/habits/diet): No description available. +- [Tools Longevity Protocol Habits Lifestyle](https://keepsimple.io/tools/longevity-protocol/habits/lifestyle): No description available. +- [Tools Longevity Protocol Habits Sleep](https://keepsimple.io/tools/longevity-protocol/habits/sleep): No description available. +- [Tools Longevity Protocol Habits Study](https://keepsimple.io/tools/longevity-protocol/habits/study): No description available. +- [Tools Longevity Protocol Habits Supplements](https://keepsimple.io/tools/longevity-protocol/habits/supplements): No description available. +- [Tools Longevity Protocol Habits Workout](https://keepsimple.io/tools/longevity-protocol/habits/workout): No description available. +- [Tools Longevity Protocol Results](https://keepsimple.io/tools/longevity-protocol/results): No description available. +- [See All Articles](https://keepsimple.io/articles): Browse all KeepSimple articles and categories. +- [Auth](https://keepsimple.io/auth) +- [Certificate](https://keepsimple.io/user/[userId]/certificate) +- [User Profile](https://keepsimple.io/user/username) +- [Uxcat](https://keepsimple.io/uxcat): First of its kind online test to measure and increase self-awareness +- [Ongoing](https://keepsimple.io/uxcat/ongoing): First of its kind online test to measure and increase self-awareness +- [Start Test](https://keepsimple.io/uxcat/start-test): First of its kind online test to measure and increase self-awareness +- [Test Result](https://keepsimple.io/uxcat/test-result): First of its kind online test to measure and increase self-awareness +- [Why our company has reputation issue?](https://keepsimple.io/uxcg/why-our-company-is-having-reputation-issue): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why users aren't happy with product quality?](https://keepsimple.io/uxcg/why-our-users-are-not-happy-with-product): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why users don't use requested features?](https://keepsimple.io/uxcg/why-users-do-not-use-requested-features): The following 13 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why did we fail to create the right product associations in the market?](https://keepsimple.io/uxcg/we-could-not-create-needed-associations-on-the-market): The following 12 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do users complain about product updates?](https://keepsimple.io/uxcg/why-users-complain-about-product-updates): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why didn’t our product meet user expectations?](https://keepsimple.io/uxcg/why-our-product-did-not-meet-user-expectations): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why don’t users like the product anymore?](https://keepsimple.io/uxcg/why-dont-users-like-the-product-anymore): The following 9 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why are users so sensitive to product changes?](https://keepsimple.io/uxcg/why-users-so-sensitive-to-product-changes): The following 10 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do our users find our communication overwhelming?](https://keepsimple.io/uxcg/users-find-our-communication-overwhelming): The following 6 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [Why do users complain about the quality of our support?](https://keepsimple.io/uxcg/users-do-not-like-our-customer-support): The following 7 cognitive biases can address this issue. Find the reason and learn how to secure your team's and company's future. Free and only at UX Core. +- [See All UXCG](https://keepsimple.io/uxcg): An extensive knowledge base containing over 1,000 practical examples of applying cognitive biases in business - from idea generation to product launch +- [Availability heuristics](https://keepsimple.io/uxcore/1-availability-heuristics): Explore Availability Heuristics Bias in our UX Core project. Learn how this cognitive bias influences decision-making in product management and HR for free. +- [Attentional bias](https://keepsimple.io/uxcore/2-attentional-bias): Discover attentional bias – a cognitive quirk shaping human focus. Learn how to leverage it in UX and HR for better decision-making. Explore at UX Core. +- [Illusory truth effect](https://keepsimple.io/uxcore/3-illusory-truth-effect): "Elevate your management skills with an understanding of the illusory truth effect! Explore practical applications in HR and product management at UX Core." +- [Mere-exposure effect](https://keepsimple.io/uxcore/4-mere-exposure-effect): Learn how to utilize this bias in software development, applications, product management, and HR activities. Explore all this and more for free, only at UX Core +- [Context effect](https://keepsimple.io/uxcore/5-context-effect): Learn how to use Context Effect in software development, team, and company management. Hands-on examples of use and a lot more for free, only at UX Core project +- [ Cue-dependent forgetting](https://keepsimple.io/uxcore/6-cue-dependent-forgetting): Explore Cue-Dependent Forgetting: Uncover how memory retrieval cues affect information recall. Learn its impact on UX and HR strategies for free at UX Core. +- [Mood-congruent memory bias](https://keepsimple.io/uxcore/7-mood-congruent-memory-bias): Harness Mood-Congruent Memory Bias: Enhance user experiences and HR practices by understanding how emotions influence memory recall. Explore insights at UX Core +- [Frequency illusion](https://keepsimple.io/uxcore/8-frequency-illusion): Master Frequency Illusion Bias: Elevate UX and HR techniques through strategic utilization of cognitive biases. Learn practical applications at UX Core for free +- [Empathy gap](https://keepsimple.io/uxcore/9-empathy-gap): Discover how the empathy gap can be used when developing a product or working in HR team. Harness cognitive bias for improved decision-making. Free at UX Core. +- [Omission bias](https://keepsimple.io/uxcore/10-omission-bias): Explore omission bias: a cognitive inclination to favor inaction over action. Learn how to address it in product management and HR strategies. #UXCore +- [See All UXCore](https://keepsimple.io/uxcore): Apply UX cognitive biases and behavioral patterns to improve product management and team leadership. +- [Uxcore Api](https://keepsimple.io/uxcore-api): Here is the list of all available API details, including the ability to fetch data about all cognitive biases on the project. +- [Uxcp](https://keepsimple.io/uxcp): This tool helps to create a Persona using cognitive biases for sales, marketing, other business teams, and educational purposes. diff --git a/scripts/generate-llms-pages.ts b/scripts/generate-llms-pages.ts new file mode 100644 index 0000000..3ef3bfa --- /dev/null +++ b/scripts/generate-llms-pages.ts @@ -0,0 +1,176 @@ +import * as dotenv from 'dotenv'; +import * as fs from 'fs/promises'; +import * as http from 'http'; +import * as https from 'https'; +import * as path from 'path'; + +dotenv.config({ path: path.join(process.cwd(), '.env'), override: true }); +dotenv.config({ path: path.join(process.cwd(), '.env.local'), override: true }); + +const PUBLIC_DIR = path.join(process.cwd(), 'public'); +const OUTPUT_DIR = path.join( + PUBLIC_DIR, + 'keepsimple_', + 'llms-full-pages', + 'article', +); +const SITE_BASE_URL = ( + process.env.NEXT_PUBLIC_DOMAIN || 'https://keepsimple.io' +).replace(/\/+$/, ''); + +const STRAPI_BASE = + process.env.STRAPI_URL || process.env.NEXT_PUBLIC_STRAPI || ''; + +// ───────────────────────────────────────────── +// Helpers +// ───────────────────────────────────────────── + +const stripHtml = (value: any): string => + String(value || '') + .replace(/<[^>]*>/g, ' ') + .replace(/ /g, ' ') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/\s+/g, ' ') + .trim(); + +function getJson(url: string): Promise { + return new Promise((resolve, reject) => { + const client = url.startsWith('https://') ? https : http; + const req = client.request(url, { method: 'GET' }, res => { + const status = res.statusCode ?? 0; + let raw = ''; + res.setEncoding('utf8'); + res.on('data', (chunk: string) => { + raw += chunk; + }); + res.on('end', () => { + if (status < 200 || status >= 300) { + reject(new Error(`HTTP ${status} for ${url}`)); + return; + } + try { + resolve(JSON.parse(raw)); + } catch (err) { + reject( + new Error(`Invalid JSON for ${url}: ${(err as Error).message}`), + ); + } + }); + }); + req.on('error', reject); + req.end(); + }); +} + +async function strapiGet(endpoint: string): Promise { + const url = `${STRAPI_BASE}/api/${endpoint}`; + return getJson(url); +} + +// ───────────────────────────────────────────── +// Fetch all articles with content +// ───────────────────────────────────────────── + +async function fetchArticles(): Promise { + try { + const data = await strapiGet( + 'articles?locale=en&pagination[pageSize]=1000&populate=*', + ); + return data?.data || []; + } catch (error: any) { + console.log( + `[strapi] failed to fetch articles: ${error?.message || error}`, + ); + return []; + } +} + +// ───────────────────────────────────────────── +// Build markdown for a single article +// ───────────────────────────────────────────── + +function buildArticleMarkdown(attributes: any, slug: string): string { + const title = attributes?.title || slug; + const description = stripHtml( + attributes?.seoDescription || attributes?.shortDescription || '', + ); + const url = `${SITE_BASE_URL}/articles/${slug}`; + + const lines: string[] = []; + lines.push(`# ${title}`); + lines.push(`- URL: ${url}`); + if (description) { + lines.push(`- Description: ${description}`); + } + lines.push(''); + return lines.join('\n'); +} + +// ───────────────────────────────────────────── +// Main +// ───────────────────────────────────────────── + +async function main(): Promise { + console.log('=== generate-llms-pages.ts ===\n'); + + if (!STRAPI_BASE) { + console.error( + '[error] STRAPI_URL or NEXT_PUBLIC_STRAPI must be set in .env', + ); + process.exit(1); + } + + console.log('[step 1] Fetching articles from Strapi...'); + const records = await fetchArticles(); + console.log(` found ${records.length} articles\n`); + + if (!records.length) { + console.log('[done] no articles to write'); + return; + } + + await fs.mkdir(OUTPUT_DIR, { recursive: true }); + + let written = 0; + let skipped = 0; + + console.log('[step 2] Writing markdown pages...\n'); + for (const record of records) { + const attributes = record?.attributes || {}; + const slug = String(attributes?.newUrl || '') + .replace(/^\/+/, '') + .replace(/\/+$/, ''); + + if (!slug) { + skipped++; + continue; + } + + const markdown = buildArticleMarkdown(attributes, slug); + const filePath = path.join(OUTPUT_DIR, `${slug}.md`); + + try { + await fs.writeFile(filePath, markdown, 'utf8'); + console.log(` ✓ ${slug}`); + written++; + } catch (error: any) { + console.log(` ✗ ${slug}: ${error?.message || error}`); + skipped++; + } + } + + console.log(`\nSuccessfully wrote ${written} article pages to ${OUTPUT_DIR}`); + if (skipped > 0) { + console.log(`Skipped ${skipped} articles (no slug or write error)`); + } +} + +main().catch(error => { + console.error( + `[fatal] generate-llms-pages failed: ${(error as Error).message || error}`, + ); + process.exit(1); +}); diff --git a/scripts/generate-llms.ts b/scripts/generate-llms.ts new file mode 100644 index 0000000..31aa1e5 --- /dev/null +++ b/scripts/generate-llms.ts @@ -0,0 +1,417 @@ +import * as dotenv from 'dotenv'; +import * as fs from 'fs/promises'; +import * as http from 'http'; +import * as https from 'https'; +import * as path from 'path'; + +import { getLlmsMeta } from '../src/api/llmsMeta'; + +dotenv.config({ path: path.join(process.cwd(), '.env'), override: true }); +dotenv.config({ path: path.join(process.cwd(), '.env.local'), override: true }); + +const ROOT_DIR = process.cwd(); +const PAGES_DIR = path.join(ROOT_DIR, 'src', 'pages'); +const PUBLIC_DIR = path.join(ROOT_DIR, 'public'); +const DEFAULT_TITLE = 'KeepSimple'; +const DEFAULT_DESCRIPTION = 'Practical resources and articles from KeepSimple.'; + +const STRAPI_BASE = + process.env.STRAPI_URL || process.env.NEXT_PUBLIC_STRAPI || ''; + +const seoDescriptions: Record = { + '/': 'KeepSimple home page.', + '/articles': 'Browse all KeepSimple articles and categories.', + '/contributors': 'Meet the KeepSimple contributors.', + '/company-management': 'Explore company management resources.', + '/auth': 'Authentication page for KeepSimple.', +}; + +const MODE_CONFIG: Record = { + curated: { + outputFile: path.join(PUBLIC_DIR, 'keepsimple_', 'llms.txt'), + slugLimit: 10, + modeLabel: 'curated', + }, + full: { + outputFile: path.join(PUBLIC_DIR, 'keepsimple_', 'llms-full.txt'), + slugLimit: Infinity, + modeLabel: 'full', + }, +}; + +const appConfig = { + mode: process.env.LLMS_MODE === 'full' ? 'full' : 'curated', +}; + +// ───────────────────────────────────────────── +// Helpers +// ───────────────────────────────────────────── + +const stripHtml = (value: any): string => + String(value || '') + .replace(/<[^>]*>/g, ' ') + .replace(/ /g, ' ') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/\s+/g, ' ') + .trim(); + +function getJson(url: string): Promise { + return new Promise((resolve, reject) => { + const client = url.startsWith('https://') ? https : http; + const req = client.request(url, { method: 'GET' }, res => { + const status = res.statusCode ?? 0; + let raw = ''; + res.setEncoding('utf8'); + res.on('data', (chunk: string) => { + raw += chunk; + }); + res.on('end', () => { + if (status < 200 || status >= 300) { + reject(new Error(`HTTP ${status} for ${url}`)); + return; + } + try { + resolve(JSON.parse(raw)); + } catch (err) { + reject( + new Error(`Invalid JSON for ${url}: ${(err as Error).message}`), + ); + } + }); + }); + req.on('error', reject); + req.end(); + }); +} + +async function strapiGet(endpoint: string): Promise { + const url = `${STRAPI_BASE}/api/${endpoint}`; + return getJson(url); +} + +// ───────────────────────────────────────────── +// Site meta from /api/llms-meta +// ───────────────────────────────────────────── + +async function fetchSiteMeta(): Promise<{ + title: string; + description: string; +}> { + // Try getLlmsMeta (uses fetch) + try { + const attrs = await getLlmsMeta(); + if (attrs?.title) { + console.log('[meta] found llms-meta via getLlmsMeta'); + return { + title: stripHtml(String(attrs?.title)), + description: stripHtml(String(attrs?.description)), + }; + } + } catch (err) { + console.log(`[meta] getLlmsMeta failed: ${(err as Error).message}`); + } + + // Fallback: strapiGet with auth token (uses http/https) + try { + const data = await strapiGet('llms-meta'); + const attrs = data?.data?.attributes ?? data?.data ?? data ?? {}; + if (attrs?.title) { + console.log('[meta] found llms-meta via strapiGet'); + return { + title: stripHtml(String(attrs.title)), + description: stripHtml(String(attrs?.description)), + }; + } + } catch (err) { + console.log(`[meta] strapiGet failed: ${(err as Error).message}`); + } + + console.log('[meta] using defaults'); + return { title: DEFAULT_TITLE, description: DEFAULT_DESCRIPTION }; +} + +// ───────────────────────────────────────────── +// Route scanning +// ───────────────────────────────────────────── + +const formatPageName = (route: string): string => { + if (route === '/') return 'Home'; + const parts = route.split('/').filter(Boolean); + if (parts.length === 0) return 'Home'; + const words = parts + .join(' ') + .replace(/\[.*?\]/g, 'Slug') + .replace(/[-_]/g, ' ') + .split(/\s+/) + .filter(Boolean) + .map(word => word.charAt(0).toUpperCase() + word.slice(1)); + return words.join(' '); +}; + +const toAbsoluteUrl = (baseUrl: string, route: string): string => { + const normalizedBase = String(baseUrl || 'https://keepsimple.io').replace( + /\/+$/, + '', + ); + const normalizedRoute = route.startsWith('/') ? route : `/${route}`; + return `${normalizedBase}${normalizedRoute}`; +}; + +const shouldSkipEntry = (entryName: string): boolean => + entryName.startsWith('_'); + +const isRouteFile = (fileName: string): boolean => + /\.(tsx|ts|jsx|js)$/.test(fileName) && + !/^(404|500)\.(tsx|ts|jsx|js)$/.test(fileName); + +const routeFromFilePath = (filePath: string): string | null => { + const rel = path.relative(PAGES_DIR, filePath).replace(/\\/g, '/'); + const noExt = rel.replace(/\.(tsx|ts|jsx|js)$/, ''); + const segments = noExt.split('/').filter(Boolean); + if (segments[0] === 'api') return null; + if (segments.length === 0) return null; + if (segments[segments.length - 1] === 'index') segments.pop(); + const route = `/${segments.join('/')}` || '/'; + return route === '' ? '/' : route; +}; + +const scanRoutes = async (dir: string): Promise => { + const entries = await fs.readdir(dir, { withFileTypes: true }); + const routeSet = new Set(); + + for (const entry of entries) { + if (shouldSkipEntry(entry.name)) { + console.log(`[scan] skipped ${entry.name} (leading underscore)`); + continue; + } + + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name === 'api') { + console.log(`[scan] skipped ${entryPath} (api folder)`); + continue; + } + const nested = await scanRoutes(entryPath); + nested.forEach(route => routeSet.add(route)); + continue; + } + + if (!isRouteFile(entry.name)) { + console.log(`[scan] skipped ${entryPath} (not route file)`); + continue; + } + + const route = routeFromFilePath(entryPath); + if (!route) { + console.log(`[scan] skipped ${entryPath} (route normalization)`); + continue; + } + + routeSet.add(route); + console.log(`[scan] found route ${route}`); + } + + return Array.from(routeSet).sort((a, b) => a.localeCompare(b)); +}; + +// ───────────────────────────────────────────── +// Article expansion +// ───────────────────────────────────────────── + +const getArticleRecords = async (): Promise => { + try { + const data = await strapiGet( + 'articles?locale=en&pagination[pageSize]=1000&populate=*', + ); + return data?.data || []; + } catch (error: any) { + console.log( + `[strapi] failed to fetch articles: ${error?.message || error}`, + ); + return []; + } +}; + +const toArticleSlugRecord = (record: any) => { + const attributes = record?.attributes || {}; + const newUrl = String(attributes?.newUrl || '') + .replace(/^\/+/, '') + .replace(/\/+$/, ''); + + if (!newUrl) return null; + + return { + slug: newUrl, + title: attributes?.title || newUrl, + seoDescription: stripHtml( + attributes?.seoDescription || attributes?.shortDescription, + ), + }; +}; + +const applyDynamicExpansions = async ({ routes, modeConfig }: any) => { + const records = (await getArticleRecords()) + .map(toArticleSlugRecord) + .filter(Boolean); + + if (!records.length) { + console.log('[expand] skipped all dynamic expansions (no article records)'); + return { + routes, + expandedArticleEntries: [], + }; + } + + const limit = modeConfig.slugLimit; + const articleEntries = records.slice(0, limit).map((record: any) => ({ + route: `/articles/${record.slug}`, + title: record.title, + seoDescription: record.seoDescription, + slug: record.slug, + })); + + const nextRoutes = routes.filter( + (route: string) => + route !== '/articles/[slug]' && route !== '/articles/[page]', + ); + + articleEntries.forEach((item: any) => { + nextRoutes.push(item.route); + console.log(`[expand] found article slug ${item.route}`); + }); + + return { + routes: Array.from(new Set(nextRoutes)).sort((a, b) => + a.localeCompare(b), + ), + expandedArticleEntries: articleEntries, + }; +}; + +// ───────────────────────────────────────────── +// Build output +// ───────────────────────────────────────────── + +const routeToDescription = ( + route: string, + dynamicLookup: Record, +): string => { + if (seoDescriptions[route]) return stripHtml(seoDescriptions[route]); + if (dynamicLookup[route]) return stripHtml(dynamicLookup[route]); + return 'No description available.'; +}; + +const buildContent = ({ + title, + description, + routes, + baseUrl, + dynamicLookup, + customEntries = [], +}: any): string => { + const lines: string[] = []; + lines.push(`# ${title}`); + lines.push(`> ${description}`); + lines.push('## Pages & Resources'); + + routes.forEach((route: string) => { + const name = formatPageName(route); + const absoluteUrl = toAbsoluteUrl(baseUrl, route); + const seoDescription = routeToDescription(route, dynamicLookup); + lines.push(`- [${name}](${absoluteUrl}): ${seoDescription}`); + }); + + customEntries.forEach((entry: any) => { + lines.push( + `- [${entry.name}](${toAbsoluteUrl(baseUrl, entry.route)}): ${entry.description}`, + ); + }); + + return `${lines.join('\n')}\n`; +}; + +// ───────────────────────────────────────────── +// Main +// ───────────────────────────────────────────── + +const run = async () => { + const modeConfig = MODE_CONFIG[appConfig.mode]; + const baseUrl = process.env.NEXT_PUBLIC_DOMAIN || 'https://keepsimple.io'; + + if (!STRAPI_BASE) { + console.log( + '[config] STRAPI_URL / NEXT_PUBLIC_STRAPI is missing, dynamic and meta fetches may be skipped.', + ); + } + + // Ensure NEXT_PUBLIC_STRAPI is set for getLlmsMeta + process.env.NEXT_PUBLIC_STRAPI = + process.env.NEXT_PUBLIC_STRAPI || STRAPI_BASE; + + console.log('[step 1] Fetching site meta...'); + const { title, description } = await fetchSiteMeta(); + console.log(` title: "${title}"`); + + console.log('[step 2] Scanning src/pages...'); + const routes = await scanRoutes(PAGES_DIR); + console.log(`[scan] discovered route count: ${routes.length}`); + + // Preserve placeholder routes if they are not in current pages shape. + if (!routes.includes('/articles/[page]')) { + routes.push('/articles/[slug]'); + } + + console.log('[step 3] Expanding dynamic routes...'); + const { routes: expandedRoutes, expandedArticleEntries } = + await applyDynamicExpansions({ routes, modeConfig }); + + const seeAllArticlesRoute = '/articles'; + if (!expandedRoutes.includes(seeAllArticlesRoute)) { + expandedRoutes.push(seeAllArticlesRoute); + } + console.log('[expand] found See All Articles -> /articles'); + + const dynamicLookup: Record = {}; + expandedArticleEntries.forEach((entry: any) => { + dynamicLookup[entry.route] = entry.seoDescription; + }); + + const content = buildContent({ + title, + description, + routes: expandedRoutes.sort((a: string, b: string) => a.localeCompare(b)), + baseUrl, + dynamicLookup, + customEntries: [ + { + name: 'See All Articles', + route: '/articles', + description: stripHtml( + seoDescriptions['/articles'] || + 'Browse all KeepSimple articles and categories.', + ), + }, + ], + }); + + try { + await fs.mkdir(path.dirname(modeConfig.outputFile), { recursive: true }); + await fs.writeFile(modeConfig.outputFile, content, 'utf8'); + } catch (error: any) { + console.log(`[write] skipped llms output: ${error?.message || error}`); + } + + console.log( + `\nSuccessfully mapped ${expandedRoutes.length} routes to ${modeConfig.outputFile}`, + ); +}; + +run().catch(error => { + console.error( + `[fatal] generator failed: ${(error as Error).message || error}`, + ); + process.exit(1); +}); diff --git a/src/api/llmsMeta.ts b/src/api/llmsMeta.ts new file mode 100644 index 0000000..b86f9ce --- /dev/null +++ b/src/api/llmsMeta.ts @@ -0,0 +1,8 @@ +export const getLlmsMeta = async () => { + const url = `${process.env.NEXT_PUBLIC_STRAPI}/api/llms-meta`; + return await fetch(url, { + method: 'GET', + }) + .then(data => data.json()) + .then(data => data?.data?.attributes); +}; diff --git a/src/api/tools.ts b/src/api/tools.ts new file mode 100644 index 0000000..4d873e0 --- /dev/null +++ b/src/api/tools.ts @@ -0,0 +1,6 @@ +export const getTools = async (locale: string) => { + const url = `${process.env.NEXT_PUBLIC_STRAPI}/api/tool-setting?populate[tools_list][populate]=*&populate[Seo]=*&locale=${locale}`; + return await fetch(url) + .then(resp => resp.json()) + .then(json => json?.data?.attributes || null); +}; diff --git a/src/assets/icons/ToolsDarkIcon.tsx b/src/assets/icons/ToolsDarkIcon.tsx deleted file mode 100644 index 218b21c..0000000 --- a/src/assets/icons/ToolsDarkIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -const ToolsDarkIcon = () => ( - - - - - - - - - - - -); - -export default ToolsDarkIcon; diff --git a/src/assets/icons/ToolsIocn.tsx b/src/assets/icons/ToolsIocn.tsx deleted file mode 100644 index 2fb0ede..0000000 --- a/src/assets/icons/ToolsIocn.tsx +++ /dev/null @@ -1,24 +0,0 @@ -const ToolsIcon = () => ( - - - - - - - - - - - -); - -export default ToolsIcon; diff --git a/src/assets/icons/articles/oxford.svg b/src/assets/icons/articles/oxford.svg new file mode 100644 index 0000000..e30768d --- /dev/null +++ b/src/assets/icons/articles/oxford.svg @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/navbar/longevity-dark.svg b/src/assets/icons/navbar/longevity-dark.svg new file mode 100644 index 0000000..c3bcf87 --- /dev/null +++ b/src/assets/icons/navbar/longevity-dark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/navbar/longevity.svg b/src/assets/icons/navbar/longevity.svg new file mode 100644 index 0000000..333123f --- /dev/null +++ b/src/assets/icons/navbar/longevity.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/navbar/tools-dark.svg b/src/assets/icons/navbar/tools-dark.svg new file mode 100644 index 0000000..23023eb --- /dev/null +++ b/src/assets/icons/navbar/tools-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icons/navbar/tools.svg b/src/assets/icons/navbar/tools.svg new file mode 100644 index 0000000..4303274 --- /dev/null +++ b/src/assets/icons/navbar/tools.svg @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/bob-medal.svg b/src/assets/icons/tools/bob-medal.svg new file mode 100644 index 0000000..4cab7f2 --- /dev/null +++ b/src/assets/icons/tools/bob-medal.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/tools/btn-vg.svg b/src/assets/icons/tools/btn-vg.svg new file mode 100644 index 0000000..9853809 --- /dev/null +++ b/src/assets/icons/tools/btn-vg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/claude.svg b/src/assets/icons/tools/claude.svg new file mode 100644 index 0000000..bbf42f6 --- /dev/null +++ b/src/assets/icons/tools/claude.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/tools/company-management.svg b/src/assets/icons/tools/company-management.svg new file mode 100644 index 0000000..6c451a1 --- /dev/null +++ b/src/assets/icons/tools/company-management.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/gpt.svg b/src/assets/icons/tools/gpt.svg new file mode 100644 index 0000000..a12ec54 --- /dev/null +++ b/src/assets/icons/tools/gpt.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/tools/open.svg b/src/assets/icons/tools/open.svg new file mode 100644 index 0000000..c9289b2 --- /dev/null +++ b/src/assets/icons/tools/open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/tools/star-dark.svg b/src/assets/icons/tools/star-dark.svg new file mode 100644 index 0000000..1b1fcea --- /dev/null +++ b/src/assets/icons/tools/star-dark.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/star.svg b/src/assets/icons/tools/star.svg new file mode 100644 index 0000000..c2e35f3 --- /dev/null +++ b/src/assets/icons/tools/star.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/tools/tool-icons/bob.svg b/src/assets/icons/tools/tool-icons/bob.svg new file mode 100644 index 0000000..9913151 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/bob.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/tool-icons/claude-bob.svg b/src/assets/icons/tools/tool-icons/claude-bob.svg new file mode 100644 index 0000000..5dba1e9 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/claude-bob.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/tool-icons/ema.svg b/src/assets/icons/tools/tool-icons/ema.svg new file mode 100644 index 0000000..8819a1c --- /dev/null +++ b/src/assets/icons/tools/tool-icons/ema.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/tool-icons/github.svg b/src/assets/icons/tools/tool-icons/github.svg new file mode 100644 index 0000000..bc93bad --- /dev/null +++ b/src/assets/icons/tools/tool-icons/github.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/tool-icons/mosaic.svg b/src/assets/icons/tools/tool-icons/mosaic.svg new file mode 100644 index 0000000..8811596 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/mosaic.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/tools/tool-icons/tom.svg b/src/assets/icons/tools/tool-icons/tom.svg new file mode 100644 index 0000000..9b1a44e --- /dev/null +++ b/src/assets/icons/tools/tool-icons/tom.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index e735103..6d45801 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -1,4 +1,5 @@ import cn from 'classnames'; +import Image from 'next/image'; import { useRouter } from 'next/router'; import type { FC } from 'react'; @@ -55,7 +56,7 @@ const Accordion: FC = ({ onClick={isMobile ? null : onToggleClick} data-cy={'open-close-accordion-button'} > - arrow down = ({ onClick={e => e.stopPropagation()} target="_blank" > - download icon {downloadButtonLabel} diff --git a/src/components/ArticleInfo/ArticleInfo.tsx b/src/components/ArticleInfo/ArticleInfo.tsx index 06ea817..1bc68da 100644 --- a/src/components/ArticleInfo/ArticleInfo.tsx +++ b/src/components/ArticleInfo/ArticleInfo.tsx @@ -54,14 +54,21 @@ const ArticleInfo: FC = ({ }, 800); }; + const isExternal = + slug?.startsWith('http://') || slug?.startsWith('https://'); + return ( { - e.preventDefault(); - handleClick(e); - }} - rel="noopener noreferrer" + href={isExternal ? slug : `/articles/${slug}`} + {...(isExternal + ? { target: '_blank', rel: 'noopener noreferrer' } + : { + onClick: e => { + e.preventDefault(); + handleClick(e); + }, + rel: 'noopener noreferrer', + })} className={cn(styles.articleInfoLink, { [styles.russianVersion]: locale === 'ru', [styles.darkTheme]: darkTheme, diff --git a/src/components/ArticleSection/ArticleSection.module.scss b/src/components/ArticleSection/ArticleSection.module.scss index 3b26764..99f081b 100644 --- a/src/components/ArticleSection/ArticleSection.module.scss +++ b/src/components/ArticleSection/ArticleSection.module.scss @@ -50,7 +50,8 @@ align-items: center; background-color: #f4f1eb80; padding: 0 0 40px 0; - margin-top: 80px; + padding-top: 80px; + padding-bottom: 60px; .underline { width: 100% !important; @@ -60,6 +61,10 @@ } .darkTheme { + &.recommended { + background-color: #1b1e26; + } + .showMoreButtonWrapper { .showMore { color: #ffffffd9; @@ -83,6 +88,7 @@ .articlesSection { margin: 0 15px; } + .featured { margin: unset; @@ -105,6 +111,7 @@ gap: 16px; } } + .articlesSection:last-child { padding-bottom: 88px; } diff --git a/src/components/ContentGenerator/ContentGenerator.tsx b/src/components/ContentGenerator/ContentGenerator.tsx index cc96700..62b5035 100644 --- a/src/components/ContentGenerator/ContentGenerator.tsx +++ b/src/components/ContentGenerator/ContentGenerator.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { Collection, Image, Link, List, P, Span } from './elements'; +import { ArticleImage, Collection, Link, List, P, Span } from './elements'; type ContentGeneratorProps = { data: any; @@ -59,7 +59,7 @@ const ContentGenerator: FC = ({ data, styles = {} }) => { ); case 'image': return ( - = ({ styles, src, alt }) => { +const ArticleImage: FC = ({ styles, src, alt }) => { const router = useRouter(); const { locale } = router as TRouter; @@ -53,9 +54,18 @@ const Image: FC = ({ styles, src, alt }) => { title={newWindowTitle} /> - {alt} + {alt} ); }; -export default Image; +export default ArticleImage; diff --git a/src/components/ContentGenerator/elements/ArticleImage/index.ts b/src/components/ContentGenerator/elements/ArticleImage/index.ts new file mode 100644 index 0000000..58ed3e1 --- /dev/null +++ b/src/components/ContentGenerator/elements/ArticleImage/index.ts @@ -0,0 +1,3 @@ +import ArticleImage from './ArticleImage'; + +export default ArticleImage; diff --git a/src/components/ContentGenerator/elements/Image/index.ts b/src/components/ContentGenerator/elements/Image/index.ts deleted file mode 100644 index 646d1ca..0000000 --- a/src/components/ContentGenerator/elements/Image/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Image from './Image'; - -export default Image; diff --git a/src/components/ContentGenerator/elements/index.ts b/src/components/ContentGenerator/elements/index.ts index 1069114..683bcbe 100644 --- a/src/components/ContentGenerator/elements/index.ts +++ b/src/components/ContentGenerator/elements/index.ts @@ -1,11 +1,11 @@ +import ArticleImage from './ArticleImage'; import Collection from './Collection'; import Div from './Div'; import H1 from './H1'; -import Image from './Image'; import Italic from './Italic'; import Link from './Link'; import List from './List'; import P from './P'; import Span from './Span'; -export { Collection, Div, H1, Image, Italic, Link, List, P, Span }; +export { ArticleImage, Collection, Div, H1, Italic, Link, List, P, Span }; diff --git a/src/components/Heading/Heading.tsx b/src/components/Heading/Heading.tsx index 04d4e1c..0599ce5 100644 --- a/src/components/Heading/Heading.tsx +++ b/src/components/Heading/Heading.tsx @@ -21,6 +21,7 @@ const Heading: FC = ({ locale, isBold, isBig, + textColor, }) => { return (
= ({ [styles.big]: isBig, [styles.bold]: isBold, })} + style={textColor ? { color: textColor } : undefined} > {text} diff --git a/src/components/Heading/Heading.types.ts b/src/components/Heading/Heading.types.ts index f0b60ab..9340ae4 100644 --- a/src/components/Heading/Heading.types.ts +++ b/src/components/Heading/Heading.types.ts @@ -13,4 +13,5 @@ export type HeadingProps = { locale?: string; isBig?: boolean; isBold?: boolean; + textColor?: string; }; diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 0d37929..f7b5449 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -12,8 +12,10 @@ import navbar from '@data/navbar'; import ArticlesDarkIcon from '@icons/ArticlesDarkIcon'; import ArticlesIcon from '@icons/ArticlesIcon'; import CompanyManagementIcon from '@icons/CompanyManagementIcon'; -import ToolsDarkIcon from '@icons/ToolsDarkIcon'; -import ToolsIcon from '@icons/ToolsIocn'; +import LongevityIcon from '@icons/navbar/longevity.svg'; +import LongevityDarkIcon from '@icons/navbar/longevity-dark.svg'; +import ToolsIcon from '@icons/navbar/tools.svg'; +import ToolsDarkIcon from '@icons/navbar/tools-dark.svg'; import UXCoreIcon from '@icons/UXCoreIcon'; import { GlobalContext } from '@components/Context/GlobalContext'; @@ -33,8 +35,22 @@ const Navbar: FC = ({ handleToggleSidebar, handleClick }) => { const { isDarkTheme, isOpenedSidebar } = useGlobals()[1]; const { accountData } = useContext(GlobalContext); - const { about, companyManagement, articles, contributorsTxt, tools } = - navbar[locale]; + const { + about, + companyManagement, + articles, + contributorsTxt, + tools, + longevity, + } = navbar[locale]; + + const normalizePath = (p: string) => { + const noQueryOrHash = p.split('?')[0].split('#')[0]; + if (noQueryOrHash.length > 1 && noQueryOrHash.endsWith('/')) { + return noQueryOrHash.slice(0, -1); + } + return noQueryOrHash; + }; const routes = [ { name: about, path: '/', logo: '', target: '' }, @@ -54,12 +70,21 @@ const Navbar: FC = ({ handleToggleSidebar, handleClick }) => { }, { - name: tools, + name: longevity, path: '/tools/longevity-protocol/about-project', + logo: isDarkTheme ? : , + target: '', + id: 'longevity', + activeMatch: '/tools/longevity-protocol', + }, + { + name: tools, + path: '/tools', logo: isDarkTheme ? : , target: '', id: 'tools', - activeMatch: '/tools/longevity-protocol', + activeMatch: '/tools', + exact: true, }, { name: articles, @@ -82,37 +107,43 @@ const Navbar: FC = ({ handleToggleSidebar, handleClick }) => { [styles.authorized]: !!accountData, })} > - {routes.map(({ name, path, target, logo, id, activeMatch }, index) => { - const match = activeMatch ?? path; - - const isActive = - match === '/' - ? router.asPath === '/' - : router.asPath.startsWith(match); - - return ( - { - if (target === '_blank') return; - e.preventDefault(); - if (isSmallScreen) handleToggleSidebar(); - handleClick(e, path); - }} - className={cn(styles.url, { - [styles.active]: isActive, - [styles.uxcoreIcon]: id === 'uxcore', - [styles.companyManagementIcon]: id === 'companyManagement', - [styles.articlesIcon]: id === 'articles', - [styles.ruUrl]: locale === 'ru', - })} - > - {logo} {name} - - ); - })} + {routes.map( + ({ name, path, target, logo, id, activeMatch, exact }, index) => { + const match = activeMatch ?? path; + const currentPath = normalizePath(router.asPath); + const matchPath = normalizePath(match); + + const isActive = + matchPath === '/' + ? currentPath === '/' + : exact + ? currentPath === matchPath + : currentPath.startsWith(matchPath); + + return ( + { + if (target === '_blank') return; + e.preventDefault(); + if (isSmallScreen) handleToggleSidebar(); + handleClick(e, path); + }} + className={cn(styles.url, { + [styles.active]: isActive, + [styles.uxcoreIcon]: id === 'uxcore', + [styles.companyManagementIcon]: id === 'companyManagement', + [styles.articlesIcon]: id === 'articles', + [styles.ruUrl]: locale === 'ru', + })} + > + {logo} {name} + + ); + }, + )} = ({ className }) => { data-cy="zoomed-image" >
- + wtd + {'zoomed
); diff --git a/src/components/articles/ArticleTag/ArticleTag.module.scss b/src/components/articles/ArticleTag/ArticleTag.module.scss index e65ade0..557de9d 100644 --- a/src/components/articles/ArticleTag/ArticleTag.module.scss +++ b/src/components/articles/ArticleTag/ArticleTag.module.scss @@ -14,17 +14,43 @@ height: 100%; } + .content { + position: relative; + z-index: 22; + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + } + .title { writing-mode: vertical-rl; text-orientation: upright; - position: relative; - z-index: 22; text-transform: uppercase; font-size: 12px; color: #fff; font-family: 'Source-Serif-Regular', sans-serif; padding: 5px 0 27px 0; letter-spacing: -0.15em; + z-index: 55; + } + + .titleOxford { + padding-bottom: 0; + } + + .oxfordIcon { + width: 20px; + height: 23px; + min-width: 20px; + min-height: 23px; + flex-shrink: 0; + + img { + display: block; + width: 100%; + height: 100%; + } } } @@ -42,6 +68,12 @@ display: flex; align-items: center; + .content { + flex-direction: row; + align-items: center; + padding: 0 5px; + } + .title { writing-mode: horizontal-tb; text-orientation: initial; @@ -50,5 +82,16 @@ font-size: 9px; line-height: 1; } + + .titleOxford { + padding: 0; + } + + .oxfordIcon { + width: 9px; + height: 10px; + min-width: 9px; + min-height: 10px; + } } } diff --git a/src/components/articles/ArticleTag/ArticleTag.tsx b/src/components/articles/ArticleTag/ArticleTag.tsx index 6808c8d..7dcb2eb 100644 --- a/src/components/articles/ArticleTag/ArticleTag.tsx +++ b/src/components/articles/ArticleTag/ArticleTag.tsx @@ -1,3 +1,4 @@ +import Image from 'next/image'; import { FC } from 'react'; import { useIsWidthLessThan } from '@hooks/useScreenSize'; @@ -21,6 +22,7 @@ const DEFAULT_COLOR = '#4F6B4F'; export const ArticleTag: FC = ({ title }) => { const color = TAG_COLORS[title] ?? DEFAULT_COLOR; const isSmallScreen = useIsWidthLessThan(768); + const isOxford = title === 'Oxford'; return (
@@ -29,7 +31,23 @@ export const ArticleTag: FC = ({ title }) => { ) : ( )} - {title} + {isOxford ? ( + + + {title} + + + Oxford icon + + + ) : ( + {title} + )}
); }; diff --git a/src/components/longevity/BorderedPill/BorderedPill.types.ts b/src/components/longevity/BorderedPill/BorderedPill.types.ts index e65d5d7..6fe0e0f 100644 --- a/src/components/longevity/BorderedPill/BorderedPill.types.ts +++ b/src/components/longevity/BorderedPill/BorderedPill.types.ts @@ -1,6 +1,6 @@ -import type { ElementType, ReactNode } from 'react'; +import type { ComponentPropsWithoutRef, ElementType, ReactNode } from 'react'; -type CommonProps = { +type OwnProps = { as?: T; text?: string; leftIcon?: ReactNode; @@ -11,17 +11,5 @@ type CommonProps = { dataCy?: string; }; -type ButtonOnlyProps = { - onClick?: React.ButtonHTMLAttributes['onClick']; - type?: 'button' | 'submit' | 'reset'; - disabled?: boolean; -}; - -type NonButtonProps = { - onClick?: never; - type?: never; - disabled?: never; -}; - -export type BorderedPillProps = - CommonProps & (T extends 'button' ? ButtonOnlyProps : NonButtonProps); +export type BorderedPillProps = OwnProps & + Omit, keyof OwnProps>; diff --git a/src/components/longevity/DNACanvas/DNACanvas.module.scss b/src/components/longevity/DNACanvas/DNACanvas.module.scss new file mode 100644 index 0000000..d0c9780 --- /dev/null +++ b/src/components/longevity/DNACanvas/DNACanvas.module.scss @@ -0,0 +1,65 @@ +.videoLayer { + position: absolute; + inset: 0; + overflow: hidden; + pointer-events: none; + display: flex; + justify-content: flex-end; + padding-top: 40px; + opacity: 0; + transition: opacity 0.35s ease; +} + +.videoLayerOn { + opacity: 1; +} + +.canvas { + width: 175px !important; + height: 100%; + display: block; + position: absolute; + z-index: 2; +} + +.hiddenVideo { + position: absolute; + width: 1px; + height: 1px; + opacity: 0; + pointer-events: none; +} + +.canvasTransitionOn { + transition: opacity 700ms ease; + will-change: opacity; +} + +.canvasTransitionOff { + transition: none; +} + +.canvasOn { + animation: smooth-fadeIn 700ms ease; + will-change: opacity; +} + +.canvasOff { + opacity: 80%; +} + +@media (max-width: 965px) { + .canvas { + display: none; + } +} + +@keyframes smooth-fadeIn { + from { + opacity: 50%; + } + + to { + opacity: 100%; + } +} diff --git a/src/components/longevity/DNACanvas/DNACanvas.tsx b/src/components/longevity/DNACanvas/DNACanvas.tsx new file mode 100644 index 0000000..48ab083 --- /dev/null +++ b/src/components/longevity/DNACanvas/DNACanvas.tsx @@ -0,0 +1,348 @@ +import cn from 'classnames'; +import { useRouter } from 'next/router'; +import { + FC, + useContext, + useEffect, + useLayoutEffect, + useRef, + useState, +} from 'react'; + +// import {useIsWidthLessThan} from "@hooks/useScreenSize"; +import { GlobalContext } from '@components/Context/GlobalContext'; + +import styles from './DNACanvas.module.scss'; + +type LayerKey = 'default' | 'red' | 'blue' | 'red-and-blue'; + +const SOURCES: Record = { + default: '/keepsimple_/assets/longevity/dna/default.mp4', + red: '/keepsimple_/assets/longevity/dna/red.mp4', + blue: '/keepsimple_/assets/longevity/dna/blue.mp4', + 'red-and-blue': '/keepsimple_/assets/longevity/dna/red-and-blue.mp4', +}; + +function pickLayer(pathname: string): LayerKey { + const base = '/tools/longevity-protocol'; + if (!pathname.startsWith(base)) return 'default'; + + const rest = pathname.slice(base.length); + if (rest === '/about-project' || rest === '' || rest === '/') + return 'default'; + if (rest === '/environment') return 'blue'; + if (rest === '/results') return 'red-and-blue'; + if (rest === '/habits' || rest.startsWith('/habits/')) return 'red'; + return 'default'; +} + +const DNACanvas: FC = () => { + const router = useRouter(); + + const videoLayerRef = useRef(null); + + const videosRef = useRef>>( + {}, + ); + + const [isLongevityProtocolPage, setIsLongevityProtocolPage] = useState(false); + const [activeLayer, setActiveLayer] = useState('default'); + const canvasRef = useRef(null); + const { setVideosReady, videosReady } = useContext(GlobalContext); + // const { overlayOn } = useContext(GlobalContext); + const [transitionsOn, setTransitionsOn] = useState(false); + const [canvasVisible, setCanvasVisible] = useState(true); + const [canvasAnimating, setCanvasAnimating] = useState(false); + + // const isMobile = useIsWidthLessThan(956); + + useEffect(() => { + if (router.pathname.startsWith('/tools/longevity-protocol')) { + setIsLongevityProtocolPage(true); + } else { + setIsLongevityProtocolPage(false); + } + }, [router.pathname]); + + useLayoutEffect(() => { + if (!router.pathname.startsWith('/tools/longevity-protocol')) return; + + const initial = pickLayer(router.pathname); + setTransitionsOn(false); + setCanvasVisible(true); + setActiveLayer(initial); + + const id = requestAnimationFrame(() => setTransitionsOn(true)); + return () => cancelAnimationFrame(id); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useLayoutEffect(() => { + if (!isLongevityProtocolPage) return; + + const next = pickLayer(router.pathname); + if (next === activeLayer) return; + + setCanvasVisible(false); + setCanvasAnimating(false); + + const FADE_MS = 250; + const t = window.setTimeout(() => { + setActiveLayer(next); + setCanvasVisible(true); + setCanvasAnimating(true); + }, FADE_MS); + + return () => window.clearTimeout(t); + }, [router.pathname, isLongevityProtocolPage, activeLayer]); + + useEffect(() => { + if (!isLongevityProtocolPage) return; + + const layer = videoLayerRef.current; + const canvas = canvasRef.current; + if (!layer || !canvas) return; + + const getActiveVideo = () => videosRef.current[activeLayer] ?? null; + + const ctx = canvas.getContext('2d', { alpha: true }); + if (!ctx) return; + + ctx.imageSmoothingEnabled = true; + // @ts-ignore + if (ctx.imageSmoothingQuality) ctx.imageSmoothingQuality = 'high'; + + let raf = 0; + let stopped = false; + let visible = true; + + const dpr = Math.min(2, window.devicePixelRatio || 1); + + const canvasCSS = 175; + const getSizes = () => { + const rect = layer.getBoundingClientRect(); + const h = Math.max(1, Math.ceil(rect.height)); + const w = canvasCSS; + return { w, h }; + }; + + let needsResize = true; + const scheduleResize = () => { + needsResize = true; + }; + + const applyResizeIfNeeded = () => { + if (!needsResize) return; + needsResize = false; + + const rect = layer.getBoundingClientRect(); + if (rect.height <= 2 || layer.offsetParent === null) { + needsResize = true; + return; + } + + const w = canvasCSS; + const h = Math.max(1, Math.ceil(rect.height)); + + canvas.style.width = `${w}px`; + canvas.style.height = `${h}px`; + + const bw = Math.max(1, Math.round(w * dpr)); + const bh = Math.max(1, Math.round(h * dpr)); + + if (canvas.width !== bw) canvas.width = bw; + if (canvas.height !== bh) canvas.height = bh; + + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + }; + + const draw = () => { + if (stopped) return; + + if (!visible || layer.offsetParent === null) { + raf = requestAnimationFrame(draw); + return; + } + + applyResizeIfNeeded(); + + const { w, h } = getSizes(); + const video = getActiveVideo(); + + if (!video) { + raf = requestAnimationFrame(draw); + return; + } + + const vw = video.videoWidth; + const vh = video.videoHeight; + + if (!vw || !vh || video.paused) { + raf = requestAnimationFrame(draw); + return; + } + + const scale = w / vw; + const tileH = Math.max(1, Math.round(vh * scale)); + + ctx.clearRect(0, 0, w, h); + for (let y = 0; y < h + tileH; y += tileH) { + ctx.drawImage(video, 0, y, w, tileH); + } + + raf = requestAnimationFrame(draw); + }; + + const ro = new ResizeObserver(() => scheduleResize()); + ro.observe(layer); + + const io = new IntersectionObserver( + entries => { + visible = entries.some(e => e.isIntersecting); + }, + { threshold: 0.01 }, + ); + io.observe(layer); + + const onVis = () => { + if (document.visibilityState === 'visible') scheduleResize(); + }; + document.addEventListener('visibilitychange', onVis); + + scheduleResize(); + raf = requestAnimationFrame(draw); + + return () => { + stopped = true; + cancelAnimationFrame(raf); + ro.disconnect(); + io.disconnect(); + document.removeEventListener('visibilitychange', onVis); + }; + }, [isLongevityProtocolPage, activeLayer]); + + useEffect(() => { + if (!isLongevityProtocolPage) return; + + (Object.keys(SOURCES) as LayerKey[]).forEach(k => { + const v = videosRef.current[k]; + v?.play?.().catch(() => {}); + }); + }, [isLongevityProtocolPage]); + + useEffect(() => { + if (!isLongevityProtocolPage) return; + + let cancelled = false; + setVideosReady(false); + + const keys = Object.keys(SOURCES) as LayerKey[]; + + const readyByKey: Record = {}; + keys.forEach(k => (readyByKey[k] = false)); + + const checkAll = () => { + if (cancelled) return; + const allReady = keys.every(k => readyByKey[k]); + if (allReady) setVideosReady(true); + }; + + const cleanupFns: Array<() => void> = []; + + keys.forEach(k => { + const v = videosRef.current[k]; + if (!v) return; + + const markReady = () => { + readyByKey[k] = true; + checkAll(); + }; + + if (v.readyState >= 2) { + markReady(); + return; + } + + const onCanPlay = () => markReady(); + const onError = () => markReady(); // don't deadlock if one fails + + v.addEventListener('canplay', onCanPlay, { once: true }); + v.addEventListener('error', onError, { once: true }); + + v.load?.(); + v.play?.().catch(() => {}); + + cleanupFns.push(() => { + v.removeEventListener('canplay', onCanPlay); + v.removeEventListener('error', onError); + }); + }); + + const t = window.setTimeout(() => { + if (!cancelled) setVideosReady(true); + }, 2500); + + return () => { + cancelled = true; + window.clearTimeout(t); + cleanupFns.forEach(fn => fn()); + }; + }, [isLongevityProtocolPage, setVideosReady]); + + useEffect(() => { + if (!canvasAnimating) return; + const t = window.setTimeout(() => setCanvasAnimating(false), 350); + return () => window.clearTimeout(t); + }, [canvasAnimating]); + + useEffect(() => { + if (!videosReady) return; + const base = videosRef.current['default']; + if (!base) return; + + const t = base.currentTime || 0; + (Object.keys(SOURCES) as LayerKey[]).forEach(k => { + const v = videosRef.current[k]; + if (!v) return; + try { + if (v.duration) v.currentTime = t % v.duration; + } catch {} + }); + }, [videosReady]); + + return ( +
+ + {(Object.keys(SOURCES) as LayerKey[]).map(k => ( +
+ ); +}; + +export default DNACanvas; diff --git a/src/components/longevity/DNACanvas/index.ts b/src/components/longevity/DNACanvas/index.ts new file mode 100644 index 0000000..d3b1133 --- /dev/null +++ b/src/components/longevity/DNACanvas/index.ts @@ -0,0 +1,3 @@ +import DNACanvas from './DNACanvas'; + +export default DNACanvas; diff --git a/src/components/tools/BobAchievements/BobAchievements.module.scss b/src/components/tools/BobAchievements/BobAchievements.module.scss new file mode 100644 index 0000000..02847bf --- /dev/null +++ b/src/components/tools/BobAchievements/BobAchievements.module.scss @@ -0,0 +1,72 @@ +.root { + margin-top: 10px; + + .title { + border-top: 1px solid #afc0ae; + border-bottom: 1px solid #afc0ae; + padding: 1px 0; + text-transform: uppercase; + font-size: 14px; + display: flex; + margin-bottom: 14px; + justify-content: center; + align-items: center; + gap: 8px; + } + + .achievements { + display: flex; + gap: 14px; + } + + .rating, + .productivity, + .conversations { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + text-transform: uppercase; + flex-direction: column; + + .category { + color: #000000a6; + text-transform: none; + } + + .value { + color: #000000d9; + font-weight: 700; + text-transform: none; + display: flex; + justify-content: center; + align-items: center; + gap: 4px; + } + } +} + +.darkTheme { + .title { + border-top: 1px solid #6c756c; + border-bottom: 1px solid #6c756c; + } + + .rating, + .productivity, + .conversations { + .category { + color: #ffffff; + } + + .value { + color: #ffffff; + } + } + + .title svg { + path { + fill: #add19a; + } + } +} diff --git a/src/components/tools/BobAchievements/BobAchievements.tsx b/src/components/tools/BobAchievements/BobAchievements.tsx new file mode 100644 index 0000000..4ffe5c2 --- /dev/null +++ b/src/components/tools/BobAchievements/BobAchievements.tsx @@ -0,0 +1,50 @@ +import cn from 'classnames'; +import { useRouter } from 'next/router'; +import { FC } from 'react'; + +import toolsData from '@data/tools'; + +import BobMedal from '@icons/tools/bob-medal.svg'; +import Star from '@icons/tools/star.svg'; +import StarDark from '@icons/tools/star-dark.svg'; + +import { BobAchievementsProps } from './BobAchievements.types'; + +import styles from './BobAchievements.module.scss'; + +const BobAchievements: FC = ({ + className, + darkTheme, +}) => { + const { locale } = useRouter(); + const t = toolsData[locale as keyof typeof toolsData] ?? toolsData.en; + + return ( +
+ + {t.firstBehaviorAgent} + +
+
+ + {' '} + {darkTheme ? : } 4.7 + + {t.ratings} (40+) +
+
+ {t.productivity} + {t.category} +
+
+ 3906 + {t.conversations} +
+
+
+ ); +}; + +export default BobAchievements; diff --git a/src/components/tools/BobAchievements/BobAchievements.types.ts b/src/components/tools/BobAchievements/BobAchievements.types.ts new file mode 100644 index 0000000..f5e3143 --- /dev/null +++ b/src/components/tools/BobAchievements/BobAchievements.types.ts @@ -0,0 +1,4 @@ +export type BobAchievementsProps = { + className?: string; + darkTheme?: boolean; +}; diff --git a/src/components/tools/BobAchievements/index.ts b/src/components/tools/BobAchievements/index.ts new file mode 100644 index 0000000..7009623 --- /dev/null +++ b/src/components/tools/BobAchievements/index.ts @@ -0,0 +1,2 @@ +export { default } from './BobAchievements'; +export * from './BobAchievements.types'; diff --git a/src/components/tools/DevToolsEasterEgg/DevToolsEasterEgg.tsx b/src/components/tools/DevToolsEasterEgg/DevToolsEasterEgg.tsx new file mode 100644 index 0000000..8eb664b --- /dev/null +++ b/src/components/tools/DevToolsEasterEgg/DevToolsEasterEgg.tsx @@ -0,0 +1,91 @@ +import { FC, useEffect, useRef } from 'react'; + +const DEVTOOLS_THRESHOLD = 160; +const CONSOLE_IMAGE_URL = '/keepsimple_/assets/tools/console/angel-ascii.png'; +const LOG_STYLE = + 'color: #f4c16b; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-weight: 600;'; + +const FRAME_LINES = [ + '+~+~~+~+~~+~+~~+~+~~+~+~~+~+~~+~+~~+~+', + '+ +', + '~ Angels on the sideline, ~', + '+ Baffled and confused. +', + '~ Father blessed them all with reason, ~', + '+ And this is what they choose? +', +]; + +const FINAL_TEXT_LINE = + '~ Monkey ' + + 'kil' + + 'ling monkey ' + + 'kil' + + 'ling monkey over pieces of the ground. ~'; + +const logConsoleImage = () => { + const image = new window.Image(); + + image.onload = () => { + const width = Math.min(720, image.width); + const height = Math.round((image.height / image.width) * width); + const imageStyle = [ + `font-size: 1px`, + `padding: ${Math.max(1, Math.round(height / 2))}px ${Math.max(1, Math.round(width / 2))}px`, + `line-height: ${height}px`, + `background-image: url("${CONSOLE_IMAGE_URL}")`, + 'background-repeat: no-repeat', + 'background-size: contain', + 'background-position: center center', + 'display: inline-block', + ].join(';'); + + console.log('%c ', imageStyle); + }; + + image.src = CONSOLE_IMAGE_URL; +}; + +const DevToolsEasterEgg: FC = () => { + const hasLoggedRef = useRef(false); + + useEffect(() => { + const printFramedText = () => { + if (hasLoggedRef.current) { + return; + } + + hasLoggedRef.current = true; + FRAME_LINES.forEach(line => { + console.log('%c' + line, LOG_STYLE); + }); + console.log('%c' + FINAL_TEXT_LINE, LOG_STYLE); + console.log('%c+ +', LOG_STYLE); + console.log('%c+~+~~+~+~~+~+~~+~+~~+~+~~+~+~~+~+~~+~+', LOG_STYLE); + logConsoleImage(); + }; + + const isDevToolsOpen = () => { + const widthDiff = window.outerWidth - window.innerWidth; + const heightDiff = window.outerHeight - window.innerHeight; + return widthDiff > DEVTOOLS_THRESHOLD || heightDiff > DEVTOOLS_THRESHOLD; + }; + + const checkDevTools = () => { + if (isDevToolsOpen()) { + printFramedText(); + } + }; + + checkDevTools(); + window.addEventListener('resize', checkDevTools); + const intervalId = window.setInterval(checkDevTools, 1000); + + return () => { + window.removeEventListener('resize', checkDevTools); + window.clearInterval(intervalId); + }; + }, []); + + return null; +}; + +export default DevToolsEasterEgg; diff --git a/src/components/tools/ToolContainer/ToolContainer.module.scss b/src/components/tools/ToolContainer/ToolContainer.module.scss new file mode 100644 index 0000000..d14e9b1 --- /dev/null +++ b/src/components/tools/ToolContainer/ToolContainer.module.scss @@ -0,0 +1,287 @@ +@import '@styles/_variables.scss'; + +.container { + --hover-color: #3f4a7a; + --border-hover-color: #c1d6ff; + --button-color: #494949; + --text-color: #000000d9; + position: relative; + width: 100%; + max-width: 359px; + border: 1px solid #dad6d4; + overflow: hidden; + transition: border-color 240ms ease; +} + +.darkTheme { + --hover-color: #c1d6ff; + --border-hover-color: #c1d6ff; + --text-color: #ffffff; + --button-color: #000000d9; + border: 1px solid #454a55; + + .backgroundSvg path { + fill: var(--dark-icon-fill) !important; + opacity: 20%; + } + + .content { + background-image: url('/keepsimple_/assets/tools/container/dark-bg.svg'); + } + + .primaryButton { + color: var(--button-color); + } + + .poweredIcon path { + fill: #f1f1f1 !important; + } + + .blankIcon path { + fill: #000000d9 !important; + } + + .buttonBg path { + fill: #ececec !important; + } + + .primaryButton.inDevelopment .buttonBg path { + fill: #acacac !important; + fill-opacity: 1 !important; + } + + .secondaryButton { + color: #ececec; + } + + .secondaryButton > svg path { + fill: #ececec !important; + } + + .secondaryButton:hover > svg path { + fill: var(--hover-color) !important; + } + + .secondaryButtonContent { + color: #ececec; + } + + .secondaryButton .blankIcon path { + fill: #ececec !important; + } +} + +.container:not(.inDevelopment):hover { + border-color: var(--border-hover-color); +} + +.content { + position: relative; + z-index: 1; + height: 374px; + padding: 16px 20px 0 20px; + display: flex; + flex-direction: column; + align-items: center; + background-image: url('/keepsimple_/assets/tools/container/white-bg.svg'); + text-align: center; + background-size: contain; +} + +.contentRu { + height: 430px; +} + +.backgroundSvg { + position: absolute; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 1; + left: 48px; + top: 32px; + opacity: 50%; +} + +.title { + margin: 0; + font-family: 'Source Serif 4', 'Source-Serif-SemiBold', serif; + font-weight: 600; + font-size: 20px; + line-height: 150%; + letter-spacing: 0; + text-align: center; + color: var(--text-color); +} + +.description { + margin: 16px 0 0; + font-family: 'Source Serif 4', 'Source-Serif-Regular', serif; + font-weight: 400; + font-size: 16px; + line-height: 150%; + letter-spacing: -0.01em; + text-align: center; + color: var(--text-color); +} + +.actions { + margin-top: auto; + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + padding-bottom: 40px; +} + +.primaryButton { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + width: 210px; + height: 48px; + border: 0; + background: transparent; + color: #fff; + cursor: pointer; + padding: 0; + text-decoration: none; +} + +.primaryButton:disabled, +.primaryButton[aria-disabled='true'] { + cursor: default; + pointer-events: none; +} + +.primaryButton.inDevelopment { + pointer-events: none; + cursor: default; +} + +.buttonBg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.buttonBg path { + fill: var(--button-color); + transition: fill 240ms ease; +} + +.primaryButton:hover:not(:disabled) .buttonBg path { + fill: var(--hover-color) !important; +} + +.primaryButton.inDevelopment .buttonBg { + opacity: 1; + background-color: #acacac; +} + +.primaryButton.inDevelopment .buttonBg path { + opacity: 1; + fill: #acacac !important; + fill-opacity: 1 !important; +} + +.primaryButton.inDevelopment:hover .buttonBg path { + fill: #acacac !important; + fill-opacity: 1 !important; +} + +.primaryButtonLabel { + position: relative; + z-index: 1; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + font-family: 'Source Serif 4', 'Source-Serif-Regular', serif; + font-weight: 500; + font-size: 16px; + line-height: 1; +} + +.secondaryButton { + width: 212px; + max-width: 100%; + background: transparent !important; + padding: 3px 0px; + text-decoration: none; +} + +.secondaryButtonContent { + gap: 3px !important; +} + +.secondaryButton > svg path { + fill: #494949 !important; + transition: fill 240ms ease; +} + +.secondaryButton:hover > svg path { + fill: var(--hover-color) !important; +} + +.secondaryButton span svg path { + fill: currentColor !important; +} + +.poweredBy { + margin-top: 8px; + display: inline-flex; + align-items: center; + gap: 4px; + color: var(--text-color); + font-family: 'Source Serif 4', 'Source-Serif-Regular', serif; + font-size: 14px; + line-height: 1.4; + position: absolute; + bottom: 11px; +} + +.poweredIcon { + width: 13px; + height: 12px; +} + +.blankIcon { + width: 17px; + height: 17px; +} + +.tooltip { + @extend .defaultTooltip; + background: #fff !important; + color: #0b0921 !important; +} + +@media (max-width: 768px) { + .container { + max-width: 100%; + min-height: 360px; + margin: 0 16px 20px 16px; + } + + .backgroundSvg { + top: 32px; + } + + .content { + min-height: 360px; + padding: 24px 16px 28px; + background-size: cover; + } + + .title { + font-size: 18px; + } + + .description { + font-size: 15px; + } +} diff --git a/src/components/tools/ToolContainer/ToolContainer.tsx b/src/components/tools/ToolContainer/ToolContainer.tsx new file mode 100644 index 0000000..293e15f --- /dev/null +++ b/src/components/tools/ToolContainer/ToolContainer.tsx @@ -0,0 +1,138 @@ +import cn from 'classnames'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { FC } from 'react'; + +import { TOOL_CONFIG } from '@constants/tools'; + +import { useEffectiveDarkTheme } from '@hooks/useEffectiveDarkTheme'; +import useGlobals from '@hooks/useGlobals'; + +import toolsData from '@data/tools'; + +import BtnBg from '@icons/tools/btn-vg.svg'; +import ClaudeIcon from '@icons/tools/claude.svg'; +import GptIcon from '@icons/tools/gpt.svg'; +import OpenIcon from '@icons/tools/open.svg'; + +import BorderedPill from '@components/longevity/BorderedPill'; +import BobAchievements from '@components/tools/BobAchievements'; + +import { ToolContainerProps } from './ToolContainer.types'; + +import styles from './ToolContainer.module.scss'; + +const ToolContainer: FC = ({ + id, + title = 'Pyramids of Operational Needs', + description = 'Modular management framework for remote-first software development companies, distilled from founding four successful software firms.', + poweredBy, + link, + isBlank = false, + isDarkTheme = false, + isInDevelopment = false, +}) => { + const { locale } = useRouter(); + const { isDarkTheme: globalDarkTheme } = useGlobals()[1]; + const darkTheme = useEffectiveDarkTheme(isDarkTheme || globalDarkTheme); + const t = toolsData[locale as keyof typeof toolsData] ?? toolsData.en; + + const config = id ? TOOL_CONFIG[id] : undefined; + const { Icon, hoverColor, darkHoverColor, darkIconFill } = config ?? {}; + + const isClaude = poweredBy === 'Claude'; + const isChatGPT = poweredBy === 'ChatGPT'; + /** Bob vs Tom both use ChatGPT; achievements are Bob-only (see TOOL_CONFIG id 5 vs 6). */ + const isBob = id === 5; + + return ( + <> +
+ {Icon && } +
+

{title}

+

{description}

+ + {isChatGPT && isBob && } + +
+ {isClaude ? ( + + + {t.download} + + ) : ( + + + + {isBlank && } + {isInDevelopment ? t.inDevelopment : t.open} + + + )} + + {isClaude && ( + } + className={styles.secondaryButton} + contentClassName={styles.secondaryButtonContent} + /> + )} + + {(isClaude || isChatGPT) && ( + + {isClaude ? ( + <> + + {t.poweredBy} Claude + + ) : ( + <> + + {t.poweredBy} ChatGPT + + )} + + )} +
+
+
+ + ); +}; + +export default ToolContainer; diff --git a/src/components/tools/ToolContainer/ToolContainer.types.ts b/src/components/tools/ToolContainer/ToolContainer.types.ts new file mode 100644 index 0000000..6336e59 --- /dev/null +++ b/src/components/tools/ToolContainer/ToolContainer.types.ts @@ -0,0 +1,10 @@ +export type ToolContainerProps = { + id?: number; + title?: string; + description?: string; + poweredBy?: 'Claude' | 'ChatGPT' | string; + isBlank?: boolean; + isDarkTheme?: boolean; + isInDevelopment?: boolean; + link?: string; +}; diff --git a/src/components/tools/ToolContainer/index.ts b/src/components/tools/ToolContainer/index.ts new file mode 100644 index 0000000..d936613 --- /dev/null +++ b/src/components/tools/ToolContainer/index.ts @@ -0,0 +1,2 @@ +export { default } from './ToolContainer'; +export * from './ToolContainer.types'; diff --git a/src/components/tools/ToolHero/ToolHero.module.scss b/src/components/tools/ToolHero/ToolHero.module.scss new file mode 100644 index 0000000..00c8a63 --- /dev/null +++ b/src/components/tools/ToolHero/ToolHero.module.scss @@ -0,0 +1,157 @@ +.hero { + position: relative; + width: 100%; + min-height: 280px; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; +} + +.backgroundLayer { + position: absolute; + inset: 0; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + opacity: 1; + transition: opacity 350ms ease-in-out; +} + +@keyframes heroBackgroundFade { + 0% { + opacity: 0; + transform: scale(1.02); + } + + 100% { + opacity: 1; + transform: scale(1); + } +} + +@keyframes logoDustReveal { + 0% { + opacity: 0; + clip-path: inset(0 100% 0 0); + filter: blur(4px); + } + + 60% { + opacity: 1; + } + + 100% { + opacity: 1; + clip-path: inset(0 0 0 0); + filter: blur(0); + } +} + +.darkBackground { + opacity: 0; +} + +.content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + padding: 56px 16px 48px; +} + +.logoRow { + display: flex; + align-items: center; + gap: 24px; +} + +.diamond { + width: 10px; + height: 10px; + background-color: #df382e; + transform: rotate(45deg); + display: inline-flex; + flex-shrink: 0; +} + +.logoBox { + position: relative; + width: 662px; + height: 80px; +} + +.logoLayer { + position: absolute; + inset: 0; + opacity: 1; + transition: opacity 350ms ease-in-out; +} + +.darkLogo { + opacity: 0; +} + +.lightBackgroundAnimated { + animation: heroBackgroundFade 900ms cubic-bezier(0.22, 1, 0.36, 1) both; +} + +.lightLogoReveal, +.darkLogoReveal { + animation: logoDustReveal 950ms cubic-bezier(0.2, 0.9, 0.2, 1) both; + will-change: clip-path, opacity, filter; +} + +.subtitle { + text-transform: uppercase; + + h2 { + margin: 0; + font-family: Aboreto-Regular, sans-serif; + font-weight: 400; + font-size: 24px; + line-height: 100%; + letter-spacing: 0; + } +} + +.isDarkTheme { + .darkBackground, + .darkLogo { + opacity: 1; + } + + .lightBackground, + .lightLogo { + opacity: 0; + } + + .subtitle { + color: #fff; + } +} + +@media (max-width: 956px) { + .hero { + min-height: 200px; + } + + .content { + padding: 44px 16px 36px; + } + + .logoBox { + width: 304px; + height: 37px; + } + + .subtitle { + h2 { + font-size: 16px; + line-height: 100%; + } + } +} diff --git a/src/components/tools/ToolHero/ToolHero.tsx b/src/components/tools/ToolHero/ToolHero.tsx new file mode 100644 index 0000000..beddbcb --- /dev/null +++ b/src/components/tools/ToolHero/ToolHero.tsx @@ -0,0 +1,112 @@ +import cn from 'classnames'; +import Image from 'next/image'; +import { FC, useEffect, useState } from 'react'; + +import Heading from '@components/Heading'; + +import { ToolHeroProps } from './ToolHero.types'; + +import styles from './ToolHero.module.scss'; + +const ToolHero: FC = ({ + backgroundImage, + darkBackgroundImage, + logoImage, + darkLogoImage, + subtitle, + subtitleColor, + isDarkTheme, + transitionKey = 0, +}) => { + const [isTransitioning, setIsTransitioning] = useState(false); + + useEffect(() => { + if (transitionKey === 0) { + return; + } + + setIsTransitioning(true); + const timeout = window.setTimeout(() => { + setIsTransitioning(false); + }, 950); + + return () => { + window.clearTimeout(timeout); + }; + }, [transitionKey, backgroundImage, logoImage]); + + return ( +
+
+
+
+
+ +
+
+ {'tools +
+
+ {'tools +
+
+ +
+
+ +
+
+
+ ); +}; + +export default ToolHero; diff --git a/src/components/tools/ToolHero/ToolHero.types.ts b/src/components/tools/ToolHero/ToolHero.types.ts new file mode 100644 index 0000000..4968d7e --- /dev/null +++ b/src/components/tools/ToolHero/ToolHero.types.ts @@ -0,0 +1,10 @@ +export type ToolHeroProps = { + backgroundImage: string; + darkBackgroundImage: string; + logoImage: string; + darkLogoImage: string; + subtitle: string; + subtitleColor?: string; + isDarkTheme?: boolean; + transitionKey?: number; +}; diff --git a/src/components/tools/ToolHero/index.ts b/src/components/tools/ToolHero/index.ts new file mode 100644 index 0000000..0ad2106 --- /dev/null +++ b/src/components/tools/ToolHero/index.ts @@ -0,0 +1,2 @@ +export { default } from './ToolHero'; +export * from './ToolHero.types'; diff --git a/src/constants/tools.ts b/src/constants/tools.ts new file mode 100644 index 0000000..9cf5a23 --- /dev/null +++ b/src/constants/tools.ts @@ -0,0 +1,68 @@ +import { FC, SVGProps } from 'react'; + +import CompanyManagementIcon from '@icons/tools/company-management.svg'; +import BobIcon from '@icons/tools/tool-icons/bob.svg'; +import ClaudeBobIcon from '@icons/tools/tool-icons/claude-bob.svg'; +import EmaIcon from '@icons/tools/tool-icons/ema.svg'; +import GithubIcon from '@icons/tools/tool-icons/github.svg'; +import MosaicIcon from '@icons/tools/tool-icons/mosaic.svg'; +import TomIcon from '@icons/tools/tool-icons/tom.svg'; + +export type ToolConfig = { + Icon: FC>; + hoverColor: string; + darkHoverColor: string; + darkIconFill: string; +}; + +export const TOOL_CONFIG: Record = { + 1: { + Icon: CompanyManagementIcon, + hoverColor: '#3F4A7A', + darkHoverColor: '#C1D6FF', + darkIconFill: '#C1D6FF', + }, + 2: { + Icon: EmaIcon, + hoverColor: '#0A3D3D', + darkHoverColor: '#95CCCC', + darkIconFill: '#95CCCC', + }, + 3: { + Icon: MosaicIcon, + hoverColor: '#3F4A7A', + darkHoverColor: '#C1D6FF', + darkIconFill: '#E08080', + }, + 4: { + Icon: GithubIcon, + hoverColor: '#4A2F63', + darkHoverColor: '#E9D3FF', + darkIconFill: '#E9D3FF', + }, + 5: { + Icon: BobIcon, + hoverColor: '#2F4A3E', + darkHoverColor: '#ADD19A', + darkIconFill: '#ADD19A', + }, + 6: { + Icon: TomIcon, + hoverColor: '#6A3A2A', + darkHoverColor: '#EACCAA', + darkIconFill: '#EACCAA', + }, + 7: { + Icon: ClaudeBobIcon, + hoverColor: '#B06A3A', + darkHoverColor: '#FFB366', + darkIconFill: '#FFB366', + }, +}; + +export const DEFAULT_CONFIG: ToolConfig = { + Icon: CompanyManagementIcon, + hoverColor: '#3F4A7A', + darkHoverColor: '#C1D6FF', + darkIconFill: '#C1D6FF', +}; diff --git a/src/context/LongevityContext.tsx b/src/context/LongevityContext.tsx new file mode 100644 index 0000000..7bfe7b4 --- /dev/null +++ b/src/context/LongevityContext.tsx @@ -0,0 +1,125 @@ +import { useRouter } from 'next/router'; +import React, { + createContext, + useContext, + useEffect, + useLayoutEffect, + useRef, + useState, +} from 'react'; + +const LONGEVITY_BASE_URL = '/tools/longevity-protocol'; + +type LongevityContextValue = { + videoRef: React.RefObject; + audioRef: React.RefObject; + isAudioPlaying: boolean; + setIsAudioPlaying: React.Dispatch>; + videosReady: boolean; + setVideosReady: React.Dispatch>; + heroReady: boolean; + setHeroReady: React.Dispatch>; + routeLoading: boolean; + longevityTransition: boolean; + overlayOn: boolean; + isLongevityUrl: (url: string) => boolean; +}; + +const LongevityContext = createContext(null); + +export function LongevityProvider({ children }: { children: React.ReactNode }) { + const router = useRouter(); + const videoRef = useRef(null); + const audioRef = useRef(null); + const [isAudioPlaying, setIsAudioPlaying] = useState(false); + const [videosReady, setVideosReady] = useState(false); + const [heroReady, setHeroReady] = useState(true); + const [routeLoading, setRouteLoading] = useState(false); + const [longevityTransition, setLongevityTransition] = useState(false); + + const isLongevityUrl = (url: string) => { + const normalizedUrl = url.split('?')[0].split('#')[0].replace(/\/+$/, ''); + return normalizedUrl.startsWith(LONGEVITY_BASE_URL); + }; + + useEffect(() => { + const onStart = (url: string) => { + const fromLongevity = isLongevityUrl(router.asPath); + const toLongevity = isLongevityUrl(url); + const shouldGate = fromLongevity && toLongevity; + + setLongevityTransition(shouldGate); + + if (shouldGate) { + setHeroReady(false); + setRouteLoading(true); + } + + if (fromLongevity && !toLongevity && audioRef.current) { + audioRef.current.pause(); + audioRef.current.currentTime = 0; + setIsAudioPlaying(false); + } + }; + + const onDone = () => { + setRouteLoading(false); + setLongevityTransition(false); + }; + + router.events.on('routeChangeStart', onStart); + router.events.on('routeChangeComplete', onDone); + router.events.on('routeChangeError', onDone); + + return () => { + router.events.off('routeChangeStart', onStart); + router.events.off('routeChangeComplete', onDone); + router.events.off('routeChangeError', onDone); + }; + }, [router.events, router.asPath]); + + useLayoutEffect(() => { + const initialIsLongevity = isLongevityUrl(router.asPath); + if (!initialIsLongevity) return; + + setHeroReady(false); + setRouteLoading(true); + + const id = requestAnimationFrame(() => setRouteLoading(false)); + return () => cancelAnimationFrame(id); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const isLongevityNow = isLongevityUrl(router.asPath); + //TODO: Fix heroReady logic + const overlayOn = isLongevityNow && (routeLoading || !videosReady); + + return ( + + {children} + + ); +} + +export function useLongevity(): LongevityContextValue { + const context = useContext(LongevityContext); + if (!context) { + throw new Error('useLongevity must be used within a LongevityProvider'); + } + return context; +} diff --git a/src/data/navbar/en.ts b/src/data/navbar/en.ts index 37cf83e..b612026 100644 --- a/src/data/navbar/en.ts +++ b/src/data/navbar/en.ts @@ -3,7 +3,8 @@ const en = { companyManagement: 'Company Management', articles: 'Articles', contributorsTxt: 'contributors', - tools: 'Longevity Protocol', + tools: 'Tools', + longevity: 'Longevity Protocol', }; export default en; diff --git a/src/data/navbar/hy.ts b/src/data/navbar/hy.ts index daf35ad..8814738 100644 --- a/src/data/navbar/hy.ts +++ b/src/data/navbar/hy.ts @@ -4,6 +4,7 @@ const hy = { articles: 'Articles', contributorsTxt: 'contributors', tools: 'Tools', + longevity: 'Longevity Protocol', }; export default hy; diff --git a/src/data/navbar/ru.ts b/src/data/navbar/ru.ts index f8357a6..70cee07 100644 --- a/src/data/navbar/ru.ts +++ b/src/data/navbar/ru.ts @@ -3,7 +3,8 @@ const ru = { companyManagement: 'Управление Компанией', articles: 'Статьи', contributorsTxt: 'участники', - tools: 'Протокол Долголетия', + tools: 'Инструменты', + longevity: 'Протокол Долголетия', }; export default ru; diff --git a/src/data/tools/en.ts b/src/data/tools/en.ts new file mode 100644 index 0000000..c8627d9 --- /dev/null +++ b/src/data/tools/en.ts @@ -0,0 +1,13 @@ +const en = { + poweredBy: 'Powered by', + firstBehaviorAgent: 'First Behavior + UX Agent on OpenAI', + ratings: 'Ratings', + productivity: 'Productivity', + category: 'Category', + conversations: 'Conversations', + download: 'Download', + inDevelopment: 'In Development', + open: 'Open', +}; + +export default en; diff --git a/src/data/tools/hy.ts b/src/data/tools/hy.ts new file mode 100644 index 0000000..ddc966d --- /dev/null +++ b/src/data/tools/hy.ts @@ -0,0 +1,13 @@ +const hy = { + poweredBy: 'Powered by', + firstBehaviorAgent: 'First Behavior + UX Agent on OpenAI', + ratings: 'Ratings', + productivity: 'Productivity', + category: 'Category', + conversations: 'Conversations', + download: 'Download', + inDevelopment: 'In Development', + open: 'Open', +}; + +export default hy; diff --git a/src/data/tools/index.ts b/src/data/tools/index.ts new file mode 100644 index 0000000..f4c2aa3 --- /dev/null +++ b/src/data/tools/index.ts @@ -0,0 +1,5 @@ +import en from './en'; +import hy from './hy'; +import ru from './ru'; + +export default { en, ru, hy }; diff --git a/src/data/tools/ru.ts b/src/data/tools/ru.ts new file mode 100644 index 0000000..337b89b --- /dev/null +++ b/src/data/tools/ru.ts @@ -0,0 +1,13 @@ +const ru = { + poweredBy: 'Работает на', + firstBehaviorAgent: 'Первый агент по поведению и UX на OpenAI', + ratings: 'Оценки', + productivity: 'Продуктивность', + category: 'Категория', + conversations: 'Разговоры', + download: 'Скачать', + inDevelopment: 'В разработке', + open: 'Открыть', +}; + +export default ru; diff --git a/src/hooks/useContentType.tsx b/src/hooks/useContentType.tsx index 0bc64b8..e3922bf 100644 --- a/src/hooks/useContentType.tsx +++ b/src/hooks/useContentType.tsx @@ -1,12 +1,13 @@ import cn from 'classnames'; +import Image from 'next/image'; import { useCallback, useMemo, useState } from 'react'; import ReactDomServer from 'react-dom/server'; import Accordion from '@components/Accordion'; import { + ArticleImage, Div, H1, - Image, Link, P, Span, @@ -95,12 +96,12 @@ const useContentType = (styles: any, usePTag: boolean) => { ul: (props: any) =>
    {props.children}
, img: (props: any) => { return ( - {props.alt} @@ -123,8 +124,14 @@ const useContentType = (styles: any, usePTag: boolean) => { [styles.darkTheme]: isDarkTheme, })} > - {/* change this image */} - theme + {'theme'} {children}
); @@ -139,7 +146,14 @@ const useContentType = (styles: any, usePTag: boolean) => { [styles.darkTheme]: isDarkTheme, })} > - trello icon + {'trello {children} ); diff --git a/src/hooks/useCookieBox.ts b/src/hooks/useCookieBox.ts new file mode 100644 index 0000000..d2a0037 --- /dev/null +++ b/src/hooks/useCookieBox.ts @@ -0,0 +1,46 @@ +import { useEffect, useState } from 'react'; + +const COOKIE_NAME = 'cookieBoxIsSeen'; +const COOKIE_MAX_AGE = 60 * 60 * 24 * 365; + +function getCookie(name: string) { + return document.cookie + .split('; ') + .find(row => row.startsWith(`${name}=`)) + ?.split('=')[1]; +} + +function getBaseDomain(hostname: string) { + const parts = hostname.split('.'); + if (parts.length <= 2) return hostname; + return `.${parts.slice(-2).join('.')}`; +} + +export default function useCookieBox() { + const [cookieBoxIsSeen, setCookieBoxIsSeen] = useState(false); + const [isCookieStateLoaded, setIsCookieStateLoaded] = useState(false); + + useEffect(() => { + const isSeen = getCookie(COOKIE_NAME); + if (isSeen === 'true') setCookieBoxIsSeen(true); + setIsCookieStateLoaded(true); + }, []); + + const handleAccept = () => { + setCookieBoxIsSeen(true); + + const hostname = window.location.hostname; + const shouldShareAcrossSubdomains = true; + const cookieDomain = shouldShareAcrossSubdomains + ? getBaseDomain(hostname) + : null; + let cookieString = `${COOKIE_NAME}=true; Path=/; Max-Age=${COOKIE_MAX_AGE}; SameSite=Lax`; + + if (cookieDomain) cookieString += `; Domain=${cookieDomain}`; + if (window.location.protocol === 'https:') cookieString += '; Secure'; + + document.cookie = cookieString; + }; + + return { isCookieStateLoaded, cookieBoxIsSeen, handleAccept }; +} diff --git a/src/hooks/useGlobals.ts b/src/hooks/useGlobals.ts index ee79e32..2b08736 100644 --- a/src/hooks/useGlobals.ts +++ b/src/hooks/useGlobals.ts @@ -134,7 +134,9 @@ const initUseGlobals = (articleRef: HTMLElement) => { const isDarkTheme = localStorage.getItem('darkTheme') === 'true'; if (isDarkTheme) { document.body.classList.add('darkTheme'); - articleRef.classList.add('darkTheme'); + if (articleRef) { + articleRef.classList.add('darkTheme'); + } reducer({ isDarkTheme: true }); } diff --git a/src/layouts/Layout.module.scss b/src/layouts/Layout.module.scss index 5f9856c..82291df 100644 --- a/src/layouts/Layout.module.scss +++ b/src/layouts/Layout.module.scss @@ -14,46 +14,6 @@ filter: blur(2px); z-index: 2; } - - .videoLayer { - position: absolute; - inset: 0; - overflow: hidden; - pointer-events: none; - display: flex; - justify-content: flex-end; - padding-top: 40px; - } - - .canvas { - width: 175px !important; - height: 100%; - display: block; - position: absolute; - z-index: 2; - } - - .hiddenVideo { - position: absolute; - width: 1px; - height: 1px; - opacity: 0; - pointer-events: none; - } -} - -.canvasTransitionOn { - transition: opacity 700ms ease; - will-change: opacity; -} - -.canvasOn { - animation: smooth-fadeIn 700ms ease; - will-change: opacity; -} - -.canvasOff { - opacity: 80%; } @media (max-width: 965px) { @@ -61,18 +21,5 @@ .section { gap: 0; } - - .canvas { - display: none; - } - } -} - -@keyframes smooth-fadeIn { - from { - opacity: 50%; - } - to { - opacity: 100%; } } diff --git a/src/layouts/Layout.tsx b/src/layouts/Layout.tsx index f3db12c..7c909aa 100644 --- a/src/layouts/Layout.tsx +++ b/src/layouts/Layout.tsx @@ -1,17 +1,14 @@ import cn from 'classnames'; import { useRouter } from 'next/router'; -import { - useContext, - useEffect, - useLayoutEffect, - useRef, - useState, -} from 'react'; +import { useContext, useEffect, useState } from 'react'; +import useCookieBox from '@hooks/useCookieBox'; import { useIsWidthLessThan } from '@hooks/useScreenSize'; +import Box from '@components/Box'; import { GlobalContext } from '@components/Context/GlobalContext'; import Header from '@components/Header'; +import DNACanvas from '@components/longevity/DNACanvas'; import Hero from '@components/longevity/Hero'; import Loader from '@components/longevity/Loader'; import MobileNavigation from '@components/longevity/MobileNavigation'; @@ -19,47 +16,12 @@ import Navigation from '@components/longevity/Navigation'; import styles from './Layout.module.scss'; -type LayerKey = 'default' | 'red' | 'blue' | 'red-and-blue'; - -const SOURCES: Record = { - default: '/keepsimple_/assets/longevity/dna/default.mp4', - red: '/keepsimple_/assets/longevity/dna/red.mp4', - blue: '/keepsimple_/assets/longevity/dna/blue.mp4', - 'red-and-blue': '/keepsimple_/assets/longevity/dna/red-and-blue.mp4', -}; - -function pickLayer(pathname: string): LayerKey { - const base = '/tools/longevity-protocol'; - if (!pathname.startsWith(base)) return 'default'; - - const rest = pathname.slice(base.length); - if (rest === '/about-project' || rest === '' || rest === '/') - return 'default'; - if (rest === '/environment') return 'blue'; - if (rest === '/results') return 'red-and-blue'; - if (rest === '/habits' || rest.startsWith('/habits/')) return 'red'; - return 'default'; -} - export default function Layout({ children }: { children: React.ReactNode }) { const router = useRouter(); - const { setVideosReady, videosReady } = useContext(GlobalContext); const { overlayOn } = useContext(GlobalContext); - - const sectionRef = useRef(null); - const canvasRef = useRef(null); - const videoLayerRef = useRef(null); - - const videosRef = useRef>>( - {}, - ); + const { isCookieStateLoaded, cookieBoxIsSeen, handleAccept } = useCookieBox(); const [isLongevityProtocolPage, setIsLongevityProtocolPage] = useState(false); - const [activeLayer, setActiveLayer] = useState('default'); - - const [transitionsOn, setTransitionsOn] = useState(false); - const [canvasVisible, setCanvasVisible] = useState(true); - const [canvasAnimating, setCanvasAnimating] = useState(false); const isMobile = useIsWidthLessThan(956); @@ -71,252 +33,13 @@ export default function Layout({ children }: { children: React.ReactNode }) { } }, [router.pathname]); - useLayoutEffect(() => { - if (!router.pathname.startsWith('/tools/longevity-protocol')) return; - - const initial = pickLayer(router.pathname); - setTransitionsOn(false); - setCanvasVisible(true); - setActiveLayer(initial); - - const id = requestAnimationFrame(() => setTransitionsOn(true)); - return () => cancelAnimationFrame(id); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useLayoutEffect(() => { - if (!isLongevityProtocolPage) return; - - const next = pickLayer(router.pathname); - if (next === activeLayer) return; - - setCanvasVisible(false); - setCanvasAnimating(false); - - const FADE_MS = 250; - const ANIM_MS = 350; - const t = window.setTimeout(() => { - setActiveLayer(next); - setCanvasVisible(true); - setCanvasAnimating(true); - window.setTimeout(() => setCanvasAnimating(false), ANIM_MS); - }, FADE_MS); - - return () => window.clearTimeout(t); - }, [router.pathname, isLongevityProtocolPage, activeLayer]); - - useEffect(() => { - if (!isLongevityProtocolPage) return; - - const layer = videoLayerRef.current; - const canvas = canvasRef.current; - if (!layer || !canvas) return; - - const getActiveVideo = () => videosRef.current[activeLayer] ?? null; - - const ctx = canvas.getContext('2d', { alpha: true }); - if (!ctx) return; - - ctx.imageSmoothingEnabled = true; - // @ts-ignore - if (ctx.imageSmoothingQuality) ctx.imageSmoothingQuality = 'high'; - - let raf = 0; - let stopped = false; - let visible = true; - - const dpr = Math.min(2, window.devicePixelRatio || 1); - - const canvasCSS = 175; - const getSizes = () => { - const rect = layer.getBoundingClientRect(); - const h = Math.max(1, Math.ceil(rect.height)); - const w = canvasCSS; - return { w, h }; - }; - - let needsResize = true; - const scheduleResize = () => { - needsResize = true; - }; - - const applyResizeIfNeeded = () => { - if (!needsResize) return; - needsResize = false; - - const rect = layer.getBoundingClientRect(); - if (rect.height <= 2 || layer.offsetParent === null) { - needsResize = true; - return; - } - - const w = canvasCSS; - const h = Math.max(1, Math.ceil(rect.height)); - - canvas.style.width = `${w}px`; - canvas.style.height = `${h}px`; - - const bw = Math.max(1, Math.round(w * dpr)); - const bh = Math.max(1, Math.round(h * dpr)); - - if (canvas.width !== bw) canvas.width = bw; - if (canvas.height !== bh) canvas.height = bh; - - ctx.setTransform(dpr, 0, 0, dpr, 0, 0); - }; - - const draw = () => { - if (stopped) return; - - if (!visible || layer.offsetParent === null) { - raf = requestAnimationFrame(draw); - return; - } - - applyResizeIfNeeded(); - - const { w, h } = getSizes(); - const video = getActiveVideo(); - - if (!video) { - raf = requestAnimationFrame(draw); - return; - } - - const vw = video.videoWidth; - const vh = video.videoHeight; - - if (!vw || !vh || video.paused) { - raf = requestAnimationFrame(draw); - return; - } - - const scale = w / vw; - const tileH = Math.max(1, Math.round(vh * scale)); - - ctx.clearRect(0, 0, w, h); - for (let y = 0; y < h + tileH; y += tileH) { - ctx.drawImage(video, 0, y, w, tileH); - } - - raf = requestAnimationFrame(draw); - }; - - const ro = new ResizeObserver(() => scheduleResize()); - ro.observe(layer); - - const io = new IntersectionObserver( - entries => { - visible = entries.some(e => e.isIntersecting); - }, - { threshold: 0.01 }, - ); - io.observe(layer); - - const onVis = () => { - if (document.visibilityState === 'visible') scheduleResize(); - }; - document.addEventListener('visibilitychange', onVis); - - scheduleResize(); - raf = requestAnimationFrame(draw); - - return () => { - stopped = true; - cancelAnimationFrame(raf); - ro.disconnect(); - io.disconnect(); - document.removeEventListener('visibilitychange', onVis); - }; - }, [isLongevityProtocolPage, activeLayer]); - - useEffect(() => { - if (!isLongevityProtocolPage) return; - - (Object.keys(SOURCES) as LayerKey[]).forEach(k => { - const v = videosRef.current[k]; - v?.play?.().catch(() => {}); - }); - }, [isLongevityProtocolPage]); - - useEffect(() => { - if (!isLongevityProtocolPage) return; - - let cancelled = false; - setVideosReady(false); - - const keys = Object.keys(SOURCES) as LayerKey[]; - - const readyByKey: Record = {}; - keys.forEach(k => (readyByKey[k] = false)); - - const checkAll = () => { - if (cancelled) return; - const allReady = keys.every(k => readyByKey[k]); - if (allReady) setVideosReady(true); - }; - - const cleanupFns: Array<() => void> = []; - - keys.forEach(k => { - const v = videosRef.current[k]; - if (!v) return; - - const markReady = () => { - readyByKey[k] = true; - checkAll(); - }; - - if (v.readyState >= 2) { - markReady(); - return; - } - - const onCanPlay = () => markReady(); - const onError = () => markReady(); // don't deadlock if one fails - - v.addEventListener('canplay', onCanPlay, { once: true }); - v.addEventListener('error', onError, { once: true }); - - v.load?.(); - v.play?.().catch(() => {}); - - cleanupFns.push(() => { - v.removeEventListener('canplay', onCanPlay); - v.removeEventListener('error', onError); - }); - }); - - const t = window.setTimeout(() => { - if (!cancelled) setVideosReady(true); - }, 2500); - - return () => { - cancelled = true; - window.clearTimeout(t); - cleanupFns.forEach(fn => fn()); - }; - }, [isLongevityProtocolPage, setVideosReady]); - - useEffect(() => { - if (!videosReady) return; - const base = videosRef.current['default']; - if (!base) return; - - const t = base.currentTime || 0; - (Object.keys(SOURCES) as LayerKey[]).forEach(k => { - const v = videosRef.current[k]; - if (!v) return; - try { - if (v.duration) v.currentTime = t % v.duration; - } catch {} - }); - }, [videosReady]); - return ( <>
{isLongevityProtocolPage && } + {isCookieStateLoaded && !cookieBoxIsSeen && ( + + )}
@@ -329,41 +52,8 @@ export default function Layout({ children }: { children: React.ReactNode }) { ) : null} {isLongevityProtocolPage ? ( -
-
- - {(Object.keys(SOURCES) as LayerKey[]).map(k => ( -
+
+
); } -// 375 diff --git a/src/layouts/ToolsLayout/ToolsLayout.module.scss b/src/layouts/ToolsLayout/ToolsLayout.module.scss new file mode 100644 index 0000000..311e0fd --- /dev/null +++ b/src/layouts/ToolsLayout/ToolsLayout.module.scss @@ -0,0 +1,108 @@ +.layout { + width: 100%; +} + +.content { + position: relative; + max-width: 1140px; + margin: 0 auto; + margin-top: 40px; + margin-bottom: 40px; +} + +.contentInner { + position: relative; + z-index: 1; + display: flex; + gap: 28px; + flex-wrap: wrap; +} + +.decorTexts { + position: absolute; + inset: 0; + z-index: 0; + pointer-events: none; +} + +.decorText1, +.decorText2, +.decorText3, +.decorText4 { + position: absolute; + font-size: 14px; + line-height: 1.2; + color: #00000033; +} + +.dark .decorText1, +.dark .decorText2, +.dark .decorText3, +.dark .decorText4 { + color: #ffffff33; +} + +.decorText1 { + top: -17px; + right: -107px; +} + +.decorText2 { + top: 326px; + left: -61px; +} + +.decorText3 { + top: 823px; + left: -80px; +} + +.decorText4 { + top: 823px; + right: -131px; +} + +@media (max-width: 1140px) { + .contentInner { + justify-content: center; + } +} + +@media (max-width: 768px) { + .layout { + margin-top: 54px; + } + + .decorText1, + .decorText2, + .decorText3, + .decorText4 { + width: max-content; + } + + .decorText1 { + top: 431px; + left: 16px; + } + + .decorText2 { + left: unset; + top: 884px; + right: 20px; + } + + .decorText3 { + top: 1335px; + left: 6px; + } + + .decorText4 { + top: unset; + bottom: 451px; + right: 93px; + } + + .contentInner { + gap: 4px; + } +} diff --git a/src/layouts/ToolsLayout/ToolsLayout.tsx b/src/layouts/ToolsLayout/ToolsLayout.tsx new file mode 100644 index 0000000..ecc0c68 --- /dev/null +++ b/src/layouts/ToolsLayout/ToolsLayout.tsx @@ -0,0 +1,168 @@ +import cn from 'classnames'; +import { FC, useEffect, useMemo, useRef, useState } from 'react'; + +import { useEffectiveDarkTheme } from '@hooks/useEffectiveDarkTheme'; +import useGlobals from '@hooks/useGlobals'; + +import ToolContainer from '@components/tools/ToolContainer'; +import ToolHero from '@components/tools/ToolHero'; + +import { ToolsLayoutProps } from './ToolsLayout.types'; + +import styles from './ToolsLayout.module.scss'; + +const FIBONACCI_CODE = '1 1 2 3 5 8 13'; +const FIBONACCI_CODE_NORMALIZED = FIBONACCI_CODE.replace(/\s+/g, ''); +const EASTER_SUBSEQUENT_CODE_NORMALIZED = '21'; + +const ToolsLayout: FC = ({ + children, + subtitle = 'on the sidelines', + backgroundImage = '/keepsimple_/assets/tools/hero/default.png', + darkBackgroundImage = '/keepsimple_/assets/tools/hero/default-dark.png', + logoImage = '/keepsimple_/assets/tools/logo/default.svg', + darkLogoImage = '/keepsimple_/assets/tools/logo/default-dark.svg', + isDarkTheme, +}) => { + const { isDarkTheme: globalDarkTheme } = useGlobals()[1]; + const effectiveDarkTheme = useEffectiveDarkTheme( + isDarkTheme ?? globalDarkTheme, + ); + const [easterThemeIndex, setEasterThemeIndex] = useState(0); + const [transitionKey, setTransitionKey] = useState(0); + const typedBufferRef = useRef(''); + const easterThemeIndexRef = useRef(0); + + useEffect(() => { + easterThemeIndexRef.current = easterThemeIndex; + }, [easterThemeIndex]); + + useEffect(() => { + const handleSequence = (event: KeyboardEvent) => { + const target = event.target as HTMLElement | null; + const isEditable = + target?.tagName === 'INPUT' || + target?.tagName === 'TEXTAREA' || + target?.isContentEditable; + + if (isEditable) { + return; + } + + const key = event.key === 'Spacebar' ? ' ' : event.key; + const isDigit = /^[0-9]$/.test(key); + const isSpace = key === ' '; + + if (!isDigit && !isSpace) { + return; + } + + const nextBuffer = `${typedBufferRef.current}${key}`.slice(-64); + + typedBufferRef.current = nextBuffer; + + const normalizedBuffer = nextBuffer.replace(/\s+/g, ''); + const idx = easterThemeIndexRef.current; + + if (idx === 0 && normalizedBuffer.endsWith(FIBONACCI_CODE_NORMALIZED)) { + typedBufferRef.current = ''; + setEasterThemeIndex(1); + setTransitionKey(prev => prev + 1); + return; + } + + if (normalizedBuffer.endsWith(EASTER_SUBSEQUENT_CODE_NORMALIZED)) { + typedBufferRef.current = ''; + setEasterThemeIndex(prev => (prev + 1) % 4); + setTransitionKey(prev => prev + 1); + } + }; + + window.addEventListener('keydown', handleSequence); + + return () => { + window.removeEventListener('keydown', handleSequence); + }; + }, []); + + const visualAssets = useMemo(() => { + const easterAssets = [ + { + background: backgroundImage, + logo: logoImage, + darkBackground: darkBackgroundImage, + darkLogo: darkLogoImage, + }, + { + background: '/keepsimple_/assets/tools/hero/green.png', + logo: '/keepsimple_/assets/tools/logo/green.svg', + darkBackground: '/keepsimple_/assets/tools/hero/green.png', + darkLogo: '/keepsimple_/assets/tools/logo/green.svg', + }, + { + background: '/keepsimple_/assets/tools/hero/white.png', + logo: '/keepsimple_/assets/tools/logo/white.svg', + darkBackground: '/keepsimple_/assets/tools/hero/white.png', + darkLogo: '/keepsimple_/assets/tools/logo/white.svg', + }, + { + background: '/keepsimple_/assets/tools/hero/black.png', + logo: '/keepsimple_/assets/tools/logo/black.svg', + darkBackground: '/keepsimple_/assets/tools/hero/black.png', + darkLogo: '/keepsimple_/assets/tools/logo/black.svg', + }, + ]; + + return easterAssets[easterThemeIndex]; + }, [ + backgroundImage, + logoImage, + darkBackgroundImage, + darkLogoImage, + easterThemeIndex, + ]); + + const easterSubtitle = + easterThemeIndex === 1 + ? { text: 'RIGHT IN TWO', color: '#BAFFC5' as const } + : easterThemeIndex === 2 + ? { text: '46 & 2', color: '#FFFFFF' as const } + : easterThemeIndex === 3 + ? { text: 'Schism', color: '#FFBC81' as const } + : null; + + const resolvedSubtitle = easterSubtitle?.text ?? subtitle; + const subtitleColor = easterSubtitle?.color; + + return ( +
+ +
+
+ learn to swim + 46 & 2 + right in two + I know the pieces fit +
+
+ {children ?? } +
+
+
+ ); +}; + +export default ToolsLayout; diff --git a/src/layouts/ToolsLayout/ToolsLayout.types.ts b/src/layouts/ToolsLayout/ToolsLayout.types.ts new file mode 100644 index 0000000..8229e0c --- /dev/null +++ b/src/layouts/ToolsLayout/ToolsLayout.types.ts @@ -0,0 +1,11 @@ +import { ReactNode } from 'react'; + +export type ToolsLayoutProps = { + children?: ReactNode; + subtitle?: string; + backgroundImage?: string; + darkBackgroundImage?: string; + logoImage?: string; + darkLogoImage?: string; + isDarkTheme?: boolean; +}; diff --git a/src/layouts/ToolsLayout/index.ts b/src/layouts/ToolsLayout/index.ts new file mode 100644 index 0000000..b5ac8c2 --- /dev/null +++ b/src/layouts/ToolsLayout/index.ts @@ -0,0 +1,2 @@ +export { default } from './ToolsLayout'; +export * from './ToolsLayout.types'; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index bcbd07a..b61edde 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -72,6 +72,7 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { intl, locale, }, + revalidate: 10, }; }; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 404090e..e6b8de6 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,7 +1,6 @@ import { useRouter } from 'next/router'; import { SessionProvider } from 'next-auth/react'; -import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; -import ReactGA from 'react-ga4'; +import React, { useEffect, useRef, useState } from 'react'; import useGlobals from '@hooks/useGlobals'; import useMobile from '@hooks/useMobile'; @@ -15,9 +14,7 @@ import { GlobalContext } from '@components/Context/GlobalContext'; import Layout from '@layouts/Layout'; -import Box from 'src/components/Box'; - -import mixpanel, { initMixpanel, trackPageView } from '../../lib/mixpanel'; +import { LongevityProvider, useLongevity } from '../context/LongevityContext'; import '../styles/globals.scss'; @@ -26,31 +23,35 @@ type TApp = { pageProps: any; }; -function App({ Component, pageProps: { session, ...pageProps } }: TApp) { - const [cookieBoxIsSeen, setCookieBoxIsSeen] = useState(false); - const [isCookieStateLoaded, setIsCookieStateLoaded] = useState(false); +function AppContent({ Component, pageProps: { session, ...pageProps } }: TApp) { const [showLoader, setShowLoader] = useState(false); - const videoRef = useRef(null); const router = useRouter(); const loadingTimer = useRef(null); const [accountData, setAccountData] = useState(null); const [token, setToken] = useState(null); - const [heroReady, setHeroReady] = useState(true); - const [routeLoading, setRouteLoading] = useState(false); - const [longevityTransition, setLongevityTransition] = useState(false); - const [videosReady, setVideosReady] = useState(false); - const audioRef = useRef(null); - const [isAudioPlaying, setIsAudioPlaying] = useState(false); const isIndexingOn = process.env.NEXT_PUBLIC_INDEXING === 'on'; const isProduction = process.env.NEXT_PUBLIC_ENV === 'prod'; - const longevityBaseUrl = '/tools/longevity-protocol'; const { initUseMobile } = useMobile()[0]; const { events } = useRouter(); const { setIsVisible } = useSpinner()[0]; const isSmallScreen = useIsWidthLessThan(768); const { isDarkTheme } = useGlobals()[1]; + const { + videoRef, + audioRef, + isAudioPlaying, + setIsAudioPlaying, + videosReady, + setVideosReady, + heroReady, + setHeroReady, + routeLoading, + longevityTransition, + overlayOn, + } = useLongevity(); + useEffect(() => { const authenticateUser = async () => { if (session?.user && session.accessToken) { @@ -67,6 +68,7 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { useEffect(() => { const getData = async () => { + if (!session?.user) return; try { const data = await getMyInfo(); if (data) { @@ -80,45 +82,7 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { }; getData(); - }, []); - - const COOKIE_NAME = 'cookieBoxIsSeen'; - const COOKIE_MAX_AGE = 60 * 60 * 24 * 365; - - const getCookie = (name: string) => { - return document.cookie - .split('; ') - .find(row => row.startsWith(`${name}=`)) - ?.split('=')[1]; - }; - - function getBaseDomain(hostname: string) { - const parts = hostname.split('.'); - if (parts.length <= 2) return hostname; - return `.${parts.slice(-2).join('.')}`; - } - - const handleAccept = () => { - setCookieBoxIsSeen(true); - - const hostname = window.location.hostname; - const shouldShareAcrossSubdomains = true; - const cookieDomain = shouldShareAcrossSubdomains - ? getBaseDomain(hostname) - : null; - let cookieString = `${COOKIE_NAME}=true; Path=/; Max-Age=${COOKIE_MAX_AGE}; SameSite=Lax`; - - if (cookieDomain) cookieString += `; Domain=${cookieDomain}`; - if (window.location.protocol === 'https:') cookieString += '; Secure'; - - document.cookie = cookieString; - }; - - useEffect(() => { - const isSeen = getCookie(COOKIE_NAME); - if (isSeen === 'true') setCookieBoxIsSeen(true); - setIsCookieStateLoaded(true); - }, []); + }, [session]); useEffect(() => { events.on('routeChangeStart', () => { @@ -130,8 +94,10 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { events.on('routeChangeComplete', url => { if (isIndexingOn && isProduction) { - ReactGA.set({ page: url }); - ReactGA.send(url); + import('react-ga4').then(({ default: ReactGA }) => { + ReactGA.set({ page: url }); + ReactGA.send(url); + }); } clearTimeout(loadingTimer.current); @@ -148,11 +114,13 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { initUseMobile(); if (isIndexingOn && isProduction) { - ReactGA.initialize(process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID); - setTimeout(() => { - ReactGA.set({ page: window.location.pathname }); - ReactGA.send(window.location.pathname); - }, 0); + import('react-ga4').then(({ default: ReactGA }) => { + ReactGA.initialize(process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID); + setTimeout(() => { + ReactGA.set({ page: window.location.pathname }); + ReactGA.send(window.location.pathname); + }, 0); + }); } }, []); @@ -179,7 +147,9 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { const isPage = router.pathname === '/' || router.pathname === '/articles' || - router.pathname === '/contributors'; + router.pathname === '/contributors' || + router.pathname === '/tools'; + document.body.classList.toggle('keepsimplePages', isPage && !isDarkTheme); document.body.classList.toggle( 'keepsimplePagesDark', @@ -199,90 +169,50 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { }, [isDarkTheme, router]); useEffect(() => { - initMixpanel(); - trackPageView(window.location.pathname); - - const handleRouteChange = (url: string) => { - trackPageView(url); - }; - - router.events.on('routeChangeComplete', handleRouteChange); - return () => router.events.off('routeChangeComplete', handleRouteChange); - }, []); - - useEffect(() => { - if (!accountData?.id || !accountData?.createdAt) return; - - mixpanel.identify(accountData.id); - - const isNewUser = new Date(accountData.createdAt) >= new Date('2025-06-01'); - - if (isNewUser) { - mixpanel.track('New User', { - id: accountData.id, - username: accountData.username, - createdAt: accountData.createdAt, - }); + let handleRouteChange: (url: string) => void; - mixpanel.people.set({ - $name: accountData.username, - $created: accountData.createdAt, - id: accountData.id, - }); - } - }, [accountData?.id, accountData?.createdAt]); - - const isLongevityUrl = (url: string) => { - const normalizedUrl = url.split('?')[0].split('#')[0].replace(/\/+$/, ''); - return normalizedUrl.startsWith(longevityBaseUrl); - }; - - useEffect(() => { - const onStart = (url: string) => { - const fromLongevity = isLongevityUrl(router.asPath); - const toLongevity = isLongevityUrl(url); + import('../../lib/mixpanel').then(({ initMixpanel, trackPageView }) => { + initMixpanel(); + trackPageView(window.location.pathname); - const shouldGate = fromLongevity && toLongevity; + handleRouteChange = (url: string) => { + trackPageView(url); + }; - setLongevityTransition(shouldGate); + router.events.on('routeChangeComplete', handleRouteChange); + }); - if (shouldGate) { - setHeroReady(false); - setRouteLoading(true); + return () => { + if (handleRouteChange) { + router.events.off('routeChangeComplete', handleRouteChange); } }; + }, []); - const onDone = () => { - setRouteLoading(false); - setLongevityTransition(false); - }; - - router.events.on('routeChangeStart', onStart); - router.events.on('routeChangeComplete', onDone); - router.events.on('routeChangeError', onDone); - - return () => { - router.events.off('routeChangeStart', onStart); - router.events.off('routeChangeComplete', onDone); - router.events.off('routeChangeError', onDone); - }; - }, [router.events, router.asPath]); + useEffect(() => { + if (!accountData?.id || !accountData?.createdAt) return; - useLayoutEffect(() => { - const initialIsLongevity = isLongevityUrl(router.asPath); - if (!initialIsLongevity) return; + import('../../lib/mixpanel').then(({ default: mixpanel }) => { + mixpanel.identify(accountData.id); - setHeroReady(false); - setRouteLoading(true); + const isNewUser = + new Date(accountData.createdAt) >= new Date('2025-06-01'); - const id = requestAnimationFrame(() => setRouteLoading(false)); - return () => cancelAnimationFrame(id); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + if (isNewUser) { + mixpanel.track('New User', { + id: accountData.id, + username: accountData.username, + createdAt: accountData.createdAt, + }); - const isLongevityNow = isLongevityUrl(router.asPath); - //TODO: Fix heroReady logic - const overlayOn = isLongevityNow && (routeLoading || !videosReady); + mixpanel.people.set({ + $name: accountData.username, + $created: accountData.createdAt, + id: accountData.id, + }); + } + }); + }, [accountData?.id, accountData?.createdAt]); return ( @@ -329,12 +259,17 @@ function App({ Component, pageProps: { session, ...pageProps } }: TApp) { - {isCookieStateLoaded && !cookieBoxIsSeen && ( - - )} ); } +function App({ Component, pageProps }: TApp) { + return ( + + + + ); +} + export default App; diff --git a/src/pages/articles.tsx b/src/pages/articles.tsx index 6f46d9d..b15aaa3 100644 --- a/src/pages/articles.tsx +++ b/src/pages/articles.tsx @@ -152,6 +152,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { props: { articleBlog, }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/articles/[page].tsx b/src/pages/articles/[page].tsx index 0d27a41..364cd80 100644 --- a/src/pages/articles/[page].tsx +++ b/src/pages/articles/[page].tsx @@ -59,6 +59,7 @@ const Article = ({ const router = useRouter(); const currentLocale = locale === 'ru' ? 'ru' : 'en'; const currentUrl = router.asPath; + const [{}, { isDarkTheme }] = useGlobals(); const articleRef = useRef(null); const [{ initUseGlobals, unmountUseGlobals }] = useGlobals(); @@ -126,6 +127,7 @@ const Article = ({ locale === 'ru' ? 'Рекомендуемые статьи' : 'Recommended articles' } locale={locale} + darkTheme={isDarkTheme} /> )} {data?.footerImage?.data?.attributes?.url && ( diff --git a/src/pages/articles/page.module.scss b/src/pages/articles/page.module.scss index bec5c48..9d01750 100644 --- a/src/pages/articles/page.module.scss +++ b/src/pages/articles/page.module.scss @@ -7,10 +7,6 @@ object-position: center; object-fit: cover; } - - .footerImage { - margin-top: 64px; - } } @media (max-width: 960px) { diff --git a/src/pages/company-management.tsx b/src/pages/company-management.tsx index 867ad69..8f814bc 100644 --- a/src/pages/company-management.tsx +++ b/src/pages/company-management.tsx @@ -74,6 +74,6 @@ export const getStaticProps: GetStaticProps = async ({ companyManagementData, pyramidStatistics, }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 4926923..94de81e 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -37,6 +37,6 @@ export const getStaticProps: GetStaticProps = async ({ locale, landingData, }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/index.tsx b/src/pages/tools/index.tsx new file mode 100644 index 0000000..85d78e6 --- /dev/null +++ b/src/pages/tools/index.tsx @@ -0,0 +1,101 @@ +import { GetStaticProps } from 'next'; +import React, { FC, useEffect } from 'react'; + +import { TStaticProps } from '@local-types/data'; + +import useGlobals from '@hooks/useGlobals'; + +import { getTools } from '@api/tools'; + +import SeoGenerator from '@components/SeoGenerator'; +import DevToolsEasterEgg from '@components/tools/DevToolsEasterEgg/DevToolsEasterEgg'; +import ToolContainer from '@components/tools/ToolContainer'; + +import ToolsLayout from '@layouts/ToolsLayout'; + +export type ToolsPageProps = { + tools?: any | null; +}; +const ToolsPage: FC = ({ tools }) => { + const [{ initUseGlobals, unmountUseGlobals }, { isDarkTheme }] = useGlobals(); + + useEffect(() => { + initUseGlobals(null); + + return () => { + unmountUseGlobals(); + }; + }, []); + + const toolsList = tools?.tools_list?.data ?? tools?.tools_list ?? []; + const sortedToolsList = [...toolsList].sort((a, b) => { + const attrsA = a?.attributes ?? a; + const attrsB = b?.attributes ?? b; + const isInDevelopmentA = Boolean(attrsA?.isInDevelopment); + const isInDevelopmentB = Boolean(attrsB?.isInDevelopment); + if (isInDevelopmentA === isInDevelopmentB) return 0; + // Ready tools first; in-development tools last + return isInDevelopmentA ? 1 : -1; + }); + function stripHTML(input: string): string { + return input?.replace(/<[^>]*>/g, '') ?? ''; + } + const seoContent = tools?.Seo; + + return ( + <> + + + + {sortedToolsList.map((tool: any) => { + const attrs = tool?.attributes ?? tool; + const title = attrs?.title; + const description = stripHTML(attrs?.description); + + return ( + + ); + })} + + + ); +}; + +export default ToolsPage; + +export const getStaticProps: GetStaticProps = async ({ + locale, +}: TStaticProps) => { + const tools = await getTools(locale); + return { + props: { + locale, + tools: tools, + }, + revalidate: 10, + }; +}; diff --git a/src/pages/tools/longevity-protocol/environment.tsx b/src/pages/tools/longevity-protocol/environment.tsx index f4ce0f7..388d04d 100644 --- a/src/pages/tools/longevity-protocol/environment.tsx +++ b/src/pages/tools/longevity-protocol/environment.tsx @@ -57,6 +57,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { environment }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/diet.tsx b/src/pages/tools/longevity-protocol/habits/diet.tsx index b1ab6be..5a9c994 100644 --- a/src/pages/tools/longevity-protocol/habits/diet.tsx +++ b/src/pages/tools/longevity-protocol/habits/diet.tsx @@ -61,6 +61,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { dietData }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/lifestyle.tsx b/src/pages/tools/longevity-protocol/habits/lifestyle.tsx index bdd1be3..97796d2 100644 --- a/src/pages/tools/longevity-protocol/habits/lifestyle.tsx +++ b/src/pages/tools/longevity-protocol/habits/lifestyle.tsx @@ -61,6 +61,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { habitsData }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/sleep.tsx b/src/pages/tools/longevity-protocol/habits/sleep.tsx index 0ea6528..9ddbf4a 100644 --- a/src/pages/tools/longevity-protocol/habits/sleep.tsx +++ b/src/pages/tools/longevity-protocol/habits/sleep.tsx @@ -62,6 +62,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { sleepData, locale: locale ?? 'en', sleepSupplements }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/study.tsx b/src/pages/tools/longevity-protocol/habits/study.tsx index 3447265..d275e2c 100644 --- a/src/pages/tools/longevity-protocol/habits/study.tsx +++ b/src/pages/tools/longevity-protocol/habits/study.tsx @@ -59,6 +59,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { studyData }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/supplements.tsx b/src/pages/tools/longevity-protocol/habits/supplements.tsx index b1f7af0..9d1a196 100644 --- a/src/pages/tools/longevity-protocol/habits/supplements.tsx +++ b/src/pages/tools/longevity-protocol/habits/supplements.tsx @@ -58,6 +58,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { supplements }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/pages/tools/longevity-protocol/habits/workout.tsx b/src/pages/tools/longevity-protocol/habits/workout.tsx index 1009823..9458a98 100644 --- a/src/pages/tools/longevity-protocol/habits/workout.tsx +++ b/src/pages/tools/longevity-protocol/habits/workout.tsx @@ -59,6 +59,6 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => { return { props: { workoutData }, - revalidate: 5, + revalidate: 10, }; }; diff --git a/src/svg.d.ts b/src/svg.d.ts new file mode 100644 index 0000000..c007e73 --- /dev/null +++ b/src/svg.d.ts @@ -0,0 +1,7 @@ +declare module '*.svg' { + import { FC, SVGProps } from 'react'; + + const SVGComponent: FC>; + + export default SVGComponent; +} diff --git a/tsconfig.json b/tsconfig.json index 136913c..2ca26e8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "allowJs": true, "skipLibCheck": true, "strict": false, - "forceConsistentCasingInFileNames": true, + "forceConsistentCasingInFileNames": false, "noEmit": true, "esModuleInterop": true, "preserveValueImports": false, diff --git a/yarn.lock b/yarn.lock index 991f809..bfe6ecf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,7 +19,7 @@ js-tokens "^4.0.0" picocolors "^1.1.1" -"@babel/compat-data@^7.28.6": +"@babel/compat-data@^7.28.6", "@babel/compat-data@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== @@ -45,6 +45,27 @@ json5 "^2.2.1" semver "^6.3.0" +"@babel/core@^7.21.3": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@^7.19.3", "@babel/generator@^7.29.0": version "7.29.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" @@ -56,7 +77,14 @@ "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.19.3": +"@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" + integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/helper-compilation-targets@^7.19.3", "@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== @@ -67,11 +95,52 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz#611ff5482da9ef0db6291bcd24303400bca170fb" + integrity sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-member-expression-to-functions" "^7.28.5" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.28.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.27.1", "@babel/helper-create-regexp-features-plugin@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz#7c1ddd64b2065c7f78034b25b43346a7e19ed997" + integrity sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + regexpu-core "^6.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz#cf1e4462b613f2b54c41e6ff758d5dfcaa2c85d1" + integrity sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA== + dependencies: + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + debug "^4.4.3" + lodash.debounce "^4.0.8" + resolve "^1.22.11" + "@babel/helper-globals@^7.28.0": version "7.28.0" resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== +"@babel/helper-member-expression-to-functions@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz#f3e07a10be37ed7a63461c63e6929575945a6150" + integrity sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg== + dependencies: + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + "@babel/helper-module-imports@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" @@ -80,7 +149,7 @@ "@babel/traverse" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/helper-module-transforms@^7.19.0": +"@babel/helper-module-transforms@^7.19.0", "@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== @@ -89,6 +158,44 @@ "@babel/helper-validator-identifier" "^7.28.5" "@babel/traverse" "^7.28.6" +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@babel/helper-remap-async-to-generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz#4601d5c7ce2eb2aea58328d43725523fcd362ce6" + integrity sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-wrap-function" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-replace-supers@^7.27.1", "@babel/helper-replace-supers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz#94aa9a1d7423a00aead3f204f78834ce7d53fe44" + integrity sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.28.5" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.28.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + "@babel/helper-string-parser@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" @@ -104,6 +211,15 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== +"@babel/helper-wrap-function@^7.27.1": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz#4e349ff9222dab69a93a019cc296cdd8442e279a" + integrity sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ== + dependencies: + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + "@babel/helpers@^7.19.0": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" @@ -112,6 +228,14 @@ "@babel/template" "^7.28.6" "@babel/types" "^7.28.6" +"@babel/helpers@^7.28.6": + version "7.29.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.2.tgz#9cfbccb02b8e229892c0b07038052cc1a8709c49" + integrity sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + "@babel/parser@^7.19.3", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" @@ -119,6 +243,642 @@ dependencies: "@babel/types" "^7.29.0" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz#fbde57974707bbfa0376d34d425ff4fa6c732421" + integrity sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.5" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz#43f70a6d7efd52370eefbdf55ae03d91b293856d" + integrity sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz#beb623bd573b8b6f3047bd04c32506adc3e58a72" + integrity sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz#e134a5479eb2ba9c02714e8c1ebf1ec9076124fd" + integrity sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-optional-chaining" "^7.27.1" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz#0e8289cec28baaf05d54fd08d81ae3676065f69f" + integrity sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/traverse" "^7.28.6" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-import-assertions@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz#ae9bc1923a6ba527b70104dd2191b0cd872c8507" + integrity sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-import-attributes@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-jsx@^7.27.1", "@babel/plugin-syntax-jsx@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-typescript@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz#6e2061067ba3ab0266d834a9f94811196f2aba9a" + integrity sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-async-generator-functions@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz#63ed829820298f0bf143d5a4a68fb8c06ffd742f" + integrity sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/traverse" "^7.29.0" + +"@babel/plugin-transform-async-to-generator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz#bd97b42237b2d1bc90d74bcb486c39be5b4d7e77" + integrity sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-remap-async-to-generator" "^7.27.1" + +"@babel/plugin-transform-block-scoped-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz#558a9d6e24cf72802dd3b62a4b51e0d62c0f57f9" + integrity sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-block-scoping@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz#e1ef5633448c24e76346125c2534eeb359699a99" + integrity sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-class-properties@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz#d274a4478b6e782d9ea987fda09bdb6d28d66b72" + integrity sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-class-static-block@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz#1257491e8259c6d125ac4d9a6f39f9d2bf3dba70" + integrity sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-classes@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz#8f6fb79ba3703978e701ce2a97e373aae7dda4b7" + integrity sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-globals" "^7.28.0" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-replace-supers" "^7.28.6" + "@babel/traverse" "^7.28.6" + +"@babel/plugin-transform-computed-properties@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz#936824fc71c26cb5c433485776d79c8e7b0202d2" + integrity sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/template" "^7.28.6" + +"@babel/plugin-transform-destructuring@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz#b8402764df96179a2070bb7b501a1586cf8ad7a7" + integrity sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.5" + +"@babel/plugin-transform-dotall-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz#def31ed84e0fb6e25c71e53c124e7b76a4ab8e61" + integrity sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-duplicate-keys@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz#f1fbf628ece18e12e7b32b175940e68358f546d1" + integrity sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz#8014b8a6cfd0e7b92762724443bf0d2400f26df1" + integrity sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-dynamic-import@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz#4c78f35552ac0e06aa1f6e3c573d67695e8af5a4" + integrity sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-explicit-resource-management@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz#dd6788f982c8b77e86779d1d029591e39d9d8be7" + integrity sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-destructuring" "^7.28.5" + +"@babel/plugin-transform-exponentiation-operator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz#5e477eb7eafaf2ab5537a04aaafcf37e2d7f1091" + integrity sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-export-namespace-from@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz#71ca69d3471edd6daa711cf4dfc3400415df9c23" + integrity sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-for-of@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz#bc24f7080e9ff721b63a70ac7b2564ca15b6c40a" + integrity sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-function-name@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz#4d0bf307720e4dce6d7c30fcb1fd6ca77bdeb3a7" + integrity sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ== + dependencies: + "@babel/helper-compilation-targets" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/plugin-transform-json-strings@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz#4c8c15b2dc49e285d110a4cf3dac52fd2dfc3038" + integrity sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz#baaefa4d10a1d4206f9dcdda50d7d5827bb70b24" + integrity sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-logical-assignment-operators@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz#53028a3d77e33c50ef30a8fce5ca17065936e605" + integrity sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-member-expression-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz#37b88ba594d852418e99536f5612f795f23aeaf9" + integrity sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-amd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz#a4145f9d87c2291fe2d05f994b65dba4e3e7196f" + integrity sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-commonjs@^7.27.1", "@babel/plugin-transform-modules-commonjs@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz#c0232e0dfe66a734cc4ad0d5e75fc3321b6fdef1" + integrity sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA== + dependencies: + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-modules-systemjs@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz#e458a95a17807c415924106a3ff188a3b8dee964" + integrity sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ== + dependencies: + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.29.0" + +"@babel/plugin-transform-modules-umd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz#63f2cf4f6dc15debc12f694e44714863d34cd334" + integrity sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz#a26cd51e09c4718588fc4cce1c5d1c0152102d6a" + integrity sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-new-target@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz#259c43939728cad1706ac17351b7e6a7bea1abeb" + integrity sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz#9bc62096e90ab7a887f3ca9c469f6adec5679757" + integrity sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-numeric-separator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz#1310b0292762e7a4a335df5f580c3320ee7d9e9f" + integrity sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-object-rest-spread@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz#fdd4bc2d72480db6ca42aed5c051f148d7b067f7" + integrity sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA== + dependencies: + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-destructuring" "^7.28.5" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/traverse" "^7.28.6" + +"@babel/plugin-transform-object-super@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz#1c932cd27bf3874c43a5cac4f43ebf970c9871b5" + integrity sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + +"@babel/plugin-transform-optional-catch-binding@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz#75107be14c78385978201a49c86414a150a20b4c" + integrity sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-optional-chaining@^7.27.1", "@babel/plugin-transform-optional-chaining@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz#926cf150bd421fc8362753e911b4a1b1ce4356cd" + integrity sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-parameters@^7.27.7": + version "7.27.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz#1fd2febb7c74e7d21cf3b05f7aebc907940af53a" + integrity sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-private-methods@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz#c76fbfef3b86c775db7f7c106fff544610bdb411" + integrity sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-private-property-in-object@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz#4fafef1e13129d79f1d75ac180c52aafefdb2811" + integrity sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-property-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz#07eafd618800591e88073a0af1b940d9a42c6424" + integrity sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-constant-elements@^7.21.3": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz#6c6b50424e749a6e48afd14cf7b92f98cb9383f9" + integrity sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-display-name@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz#6f20a7295fea7df42eb42fed8f896813f5b934de" + integrity sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-development@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz#47ff95940e20a3a70e68ad3d4fcb657b647f6c98" + integrity sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.27.1" + +"@babel/plugin-transform-react-jsx@^7.27.1": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz#f51cb70a90b9529fbb71ee1f75ea27b7078eed62" + integrity sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-syntax-jsx" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/plugin-transform-react-pure-annotations@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz#339f1ce355eae242e0649f232b1c68907c02e879" + integrity sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-regenerator@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz#dec237cec1b93330876d6da9992c4abd42c9d18b" + integrity sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-regexp-modifiers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz#7ef0163bd8b4a610481b2509c58cf217f065290b" + integrity sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-reserved-words@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz#40fba4878ccbd1c56605a4479a3a891ac0274bb4" + integrity sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-shorthand-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz#532abdacdec87bfee1e0ef8e2fcdee543fe32b90" + integrity sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-spread@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz#40a2b423f6db7b70f043ad027a58bcb44a9757b6" + integrity sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-sticky-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz#18984935d9d2296843a491d78a014939f7dcd280" + integrity sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-template-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz#1a0eb35d8bb3e6efc06c9fd40eb0bcef548328b8" + integrity sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-typeof-symbol@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz#70e966bb492e03509cf37eafa6dcc3051f844369" + integrity sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-typescript@^7.28.5": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz#1e93d96da8adbefdfdade1d4956f73afa201a158" + integrity sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-syntax-typescript" "^7.28.6" + +"@babel/plugin-transform-unicode-escapes@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz#3e3143f8438aef842de28816ece58780190cf806" + integrity sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-property-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz#63a7a6c21a0e75dae9b1861454111ea5caa22821" + integrity sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-unicode-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz#25948f5c395db15f609028e370667ed8bae9af97" + integrity sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-sets-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz#924912914e5df9fe615ec472f88ff4788ce04d4e" + integrity sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/preset-env@^7.20.2": + version "7.29.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.29.2.tgz#5a173f22c7d8df362af1c9fe31facd320de4a86c" + integrity sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw== + dependencies: + "@babel/compat-data" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.28.5" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.27.1" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.27.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.27.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.28.6" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.28.6" + "@babel/plugin-syntax-import-attributes" "^7.28.6" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.27.1" + "@babel/plugin-transform-async-generator-functions" "^7.29.0" + "@babel/plugin-transform-async-to-generator" "^7.28.6" + "@babel/plugin-transform-block-scoped-functions" "^7.27.1" + "@babel/plugin-transform-block-scoping" "^7.28.6" + "@babel/plugin-transform-class-properties" "^7.28.6" + "@babel/plugin-transform-class-static-block" "^7.28.6" + "@babel/plugin-transform-classes" "^7.28.6" + "@babel/plugin-transform-computed-properties" "^7.28.6" + "@babel/plugin-transform-destructuring" "^7.28.5" + "@babel/plugin-transform-dotall-regex" "^7.28.6" + "@babel/plugin-transform-duplicate-keys" "^7.27.1" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.29.0" + "@babel/plugin-transform-dynamic-import" "^7.27.1" + "@babel/plugin-transform-explicit-resource-management" "^7.28.6" + "@babel/plugin-transform-exponentiation-operator" "^7.28.6" + "@babel/plugin-transform-export-namespace-from" "^7.27.1" + "@babel/plugin-transform-for-of" "^7.27.1" + "@babel/plugin-transform-function-name" "^7.27.1" + "@babel/plugin-transform-json-strings" "^7.28.6" + "@babel/plugin-transform-literals" "^7.27.1" + "@babel/plugin-transform-logical-assignment-operators" "^7.28.6" + "@babel/plugin-transform-member-expression-literals" "^7.27.1" + "@babel/plugin-transform-modules-amd" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.28.6" + "@babel/plugin-transform-modules-systemjs" "^7.29.0" + "@babel/plugin-transform-modules-umd" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.29.0" + "@babel/plugin-transform-new-target" "^7.27.1" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.28.6" + "@babel/plugin-transform-numeric-separator" "^7.28.6" + "@babel/plugin-transform-object-rest-spread" "^7.28.6" + "@babel/plugin-transform-object-super" "^7.27.1" + "@babel/plugin-transform-optional-catch-binding" "^7.28.6" + "@babel/plugin-transform-optional-chaining" "^7.28.6" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/plugin-transform-private-methods" "^7.28.6" + "@babel/plugin-transform-private-property-in-object" "^7.28.6" + "@babel/plugin-transform-property-literals" "^7.27.1" + "@babel/plugin-transform-regenerator" "^7.29.0" + "@babel/plugin-transform-regexp-modifiers" "^7.28.6" + "@babel/plugin-transform-reserved-words" "^7.27.1" + "@babel/plugin-transform-shorthand-properties" "^7.27.1" + "@babel/plugin-transform-spread" "^7.28.6" + "@babel/plugin-transform-sticky-regex" "^7.27.1" + "@babel/plugin-transform-template-literals" "^7.27.1" + "@babel/plugin-transform-typeof-symbol" "^7.27.1" + "@babel/plugin-transform-unicode-escapes" "^7.27.1" + "@babel/plugin-transform-unicode-property-regex" "^7.28.6" + "@babel/plugin-transform-unicode-regex" "^7.27.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.28.6" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.15" + babel-plugin-polyfill-corejs3 "^0.14.0" + babel-plugin-polyfill-regenerator "^0.6.6" + core-js-compat "^3.48.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.18.6": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.28.5.tgz#6fcc0400fa79698433d653092c3919bb4b0878d9" + integrity sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-transform-react-display-name" "^7.28.0" + "@babel/plugin-transform-react-jsx" "^7.27.1" + "@babel/plugin-transform-react-jsx-development" "^7.27.1" + "@babel/plugin-transform-react-pure-annotations" "^7.27.1" + +"@babel/preset-typescript@^7.21.0": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz#540359efa3028236958466342967522fd8f2a60c" + integrity sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.27.1" + "@babel/plugin-transform-typescript" "^7.28.5" + "@babel/runtime@^7.15.4", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.3", "@babel/runtime@^7.9.2": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" @@ -133,7 +893,7 @@ "@babel/parser" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/traverse@^7.19.3", "@babel/traverse@^7.28.6": +"@babel/traverse@^7.19.3", "@babel/traverse@^7.27.1", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== @@ -146,7 +906,7 @@ "@babel/types" "^7.29.0" debug "^4.3.1" -"@babel/types@^7.19.3", "@babel/types@^7.28.6", "@babel/types@^7.29.0": +"@babel/types@^7.19.3", "@babel/types@^7.21.3", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.4.4": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== @@ -508,6 +1268,14 @@ "@jridgewell/sourcemap-codec" "^1.5.0" "@jridgewell/trace-mapping" "^0.3.24" +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" @@ -736,6 +1504,112 @@ resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== +"@svgr/babel-plugin-add-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" + integrity sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g== + +"@svgr/babel-plugin-remove-jsx-attribute@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz#69177f7937233caca3a1afb051906698f2f59186" + integrity sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA== + +"@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz#c2c48104cfd7dcd557f373b70a56e9e3bdae1d44" + integrity sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz#8fbb6b2e91fa26ac5d4aa25c6b6e4f20f9c0ae27" + integrity sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ== + +"@svgr/babel-plugin-svg-dynamic-title@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz#1d5ba1d281363fc0f2f29a60d6d936f9bbc657b0" + integrity sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og== + +"@svgr/babel-plugin-svg-em-dimensions@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz#35e08df300ea8b1d41cb8f62309c241b0369e501" + integrity sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g== + +"@svgr/babel-plugin-transform-react-native-svg@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz#90a8b63998b688b284f255c6a5248abd5b28d754" + integrity sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q== + +"@svgr/babel-plugin-transform-svg-component@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz#013b4bfca88779711f0ed2739f3f7efcefcf4f7e" + integrity sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw== + +"@svgr/babel-preset@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-8.1.0.tgz#0e87119aecdf1c424840b9d4565b7137cabf9ece" + integrity sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute" "8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value" "8.0.0" + "@svgr/babel-plugin-svg-dynamic-title" "8.0.0" + "@svgr/babel-plugin-svg-em-dimensions" "8.0.0" + "@svgr/babel-plugin-transform-react-native-svg" "8.1.0" + "@svgr/babel-plugin-transform-svg-component" "8.0.0" + +"@svgr/core@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-8.1.0.tgz#41146f9b40b1a10beaf5cc4f361a16a3c1885e88" + integrity sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + camelcase "^6.2.0" + cosmiconfig "^8.1.3" + snake-case "^3.0.4" + +"@svgr/hast-util-to-babel-ast@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz#6952fd9ce0f470e1aded293b792a2705faf4ffd4" + integrity sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q== + dependencies: + "@babel/types" "^7.21.3" + entities "^4.4.0" + +"@svgr/plugin-jsx@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz#96969f04a24b58b174ee4cd974c60475acbd6928" + integrity sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA== + dependencies: + "@babel/core" "^7.21.3" + "@svgr/babel-preset" "8.1.0" + "@svgr/hast-util-to-babel-ast" "8.0.0" + svg-parser "^2.0.4" + +"@svgr/plugin-svgo@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz#b115b7b967b564f89ac58feae89b88c3decd0f00" + integrity sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA== + dependencies: + cosmiconfig "^8.1.3" + deepmerge "^4.3.1" + svgo "^3.0.2" + +"@svgr/webpack@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-8.1.0.tgz#16f1b5346f102f89fda6ec7338b96a701d8be0c2" + integrity sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA== + dependencies: + "@babel/core" "^7.21.3" + "@babel/plugin-transform-react-constant-elements" "^7.21.3" + "@babel/preset-env" "^7.20.2" + "@babel/preset-react" "^7.18.6" + "@babel/preset-typescript" "^7.21.0" + "@svgr/core" "8.1.0" + "@svgr/plugin-jsx" "8.1.0" + "@svgr/plugin-svgo" "8.1.0" + "@swc/counter@0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" @@ -1463,6 +2337,30 @@ babel-loader@8.2.5: make-dir "^3.1.0" schema-utils "^2.6.5" +babel-plugin-polyfill-corejs2@^0.4.15: + version "0.4.17" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz#198f970f1c99a856b466d1187e88ce30bd199d91" + integrity sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-define-polyfill-provider" "^0.6.8" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.14.0: + version "0.14.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz#6ac08d2f312affb70c4c69c0fbba4cb417ee5587" + integrity sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.8" + core-js-compat "^3.48.0" + +babel-plugin-polyfill-regenerator@^0.6.6: + version "0.6.8" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz#8a6bfd5dd54239362b3d06ce47ac52b2d95d7721" + integrity sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.8" + bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -1595,7 +2493,7 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.24.0: +browserslist@^4.24.0, browserslist@^4.28.1: version "4.28.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== @@ -1662,6 +2560,11 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001759: version "1.0.30001774" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz#0e576b6f374063abcd499d202b9ba1301be29b70" @@ -1827,6 +2730,11 @@ commander@^6.2.1: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -1847,6 +2755,11 @@ convert-source-map@^1.7.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" @@ -1857,11 +2770,28 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +core-js-compat@^3.48.0: + version "3.49.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.49.0.tgz#06145447d92f4aaf258a0c44f24b47afaeaffef6" + integrity sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA== + dependencies: + browserslist "^4.28.1" + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== +cosmiconfig@^8.1.3: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + cosmiconfig@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" @@ -1927,6 +2857,33 @@ css-select@^4.2.1: domutils "^2.8.0" nth-check "^2.0.1" +css-select@^5.1.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.2.2.tgz#01b6e8d163637bb2dd6c982ca4ed65863682786e" + integrity sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + +css-tree@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +css-tree@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.2.1.tgz#36115d382d60afd271e377f9c5f67d02bd48c032" + integrity sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA== + dependencies: + mdn-data "2.0.28" + source-map-js "^1.0.1" + css-vendor@^2.0.8: version "2.0.8" resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" @@ -1935,11 +2892,18 @@ css-vendor@^2.0.8: "@babel/runtime" "^7.8.3" is-in-browser "^1.0.2" -css-what@^6.0.1: +css-what@^6.0.1, css-what@^6.1.0: version "6.2.2" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.2.2.tgz#cdcc8f9b6977719fdfbd1de7aec24abf756b9dea" integrity sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA== +csso@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/csso/-/csso-5.0.5.tgz#f9b7fe6cc6ac0b7d90781bb16d5e9874303e2ca6" + integrity sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ== + dependencies: + css-tree "~2.2.0" + csstype@^3.0.2, csstype@^3.2.2: version "3.2.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" @@ -2097,6 +3061,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -2170,7 +3139,16 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" -domelementtype@^2.0.1, domelementtype@^2.2.0: +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== @@ -2182,6 +3160,13 @@ domhandler@^4.2.0, domhandler@^4.3.1: dependencies: domelementtype "^2.2.0" +domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -2191,6 +3176,23 @@ domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^3.0.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78" + integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dotenv@^16.4.5: version "16.6.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" @@ -2263,6 +3265,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^4.2.0, entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -3685,7 +4692,7 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jsesc@^3.0.2: +jsesc@^3.0.2, jsesc@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== @@ -3739,7 +4746,7 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.1.2, json5@^2.2.1: +json5@^2.1.2, json5@^2.2.1, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -4053,6 +5060,13 @@ loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4142,6 +5156,16 @@ mdast-util-to-string@^3.1.0: dependencies: "@types/mdast" "^3.0.0" +mdn-data@2.0.28: + version "2.0.28" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.28.tgz#5ec48e7bef120654539069e1ae4ddc81ca490eba" + integrity sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g== + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -4482,6 +5506,14 @@ next@15.0.5: "@next/swc-win32-x64-msvc" "15.0.5" sharp "^0.33.5" +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + node-exports-info@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/node-exports-info/-/node-exports-info-1.6.0.tgz#1aedafb01a966059c9a5e791a94a94d93f5c2a13" @@ -4792,6 +5824,11 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pause-stream@0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" @@ -5169,6 +6206,18 @@ reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: get-proto "^1.0.1" which-builtin-type "^1.2.1" +regenerate-unicode-properties@^10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz#aa113812ba899b630658c7623466be71e1f86f66" + integrity sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" @@ -5181,6 +6230,30 @@ regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: gopd "^1.2.0" set-function-name "^2.0.2" +regexpu-core@^6.3.1: + version "6.4.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.4.0.tgz#3580ce0c4faedef599eccb146612436b62a176e5" + integrity sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.2" + regjsgen "^0.8.0" + regjsparser "^0.13.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.2.1" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.13.0.tgz#01f8351335cf7898d43686bc74d2dd71c847ecc0" + integrity sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q== + dependencies: + jsesc "~3.1.0" + rehype-raw@6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-6.1.1.tgz#81bbef3793bd7abacc6bf8335879d1b6c868c9d4" @@ -5245,7 +6318,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@^1.22.4: +resolve@^1.22.11, resolve@^1.22.4: version "1.22.11" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== @@ -5365,6 +6438,11 @@ sass@1.32.8: dependencies: chokidar ">=2.0.0 <4.0.0" +sax@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.0.tgz#da59637629307b97e7c4cb28e080a7bc38560d5b" + integrity sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA== + scheduler@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015" @@ -5546,6 +6624,14 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + socks-proxy-agent@^8.0.5: version "8.0.5" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" @@ -5563,7 +6649,7 @@ socks@^2.8.3: ip-address "^10.0.1" smart-buffer "^4.2.0" -source-map-js@^1.0.2, source-map-js@^1.2.1: +source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -5790,6 +6876,24 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +svg-parser@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^3.0.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-3.3.3.tgz#8246aee0b08791fde3b0ed22b5661b471fadf58e" + integrity sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng== + dependencies: + commander "^7.2.0" + css-select "^5.1.0" + css-tree "^2.3.1" + css-what "^6.1.0" + csso "^5.0.5" + picocolors "^1.0.0" + sax "^1.5.0" + swiper@*: version "12.1.2" resolved "https://registry.yarnpkg.com/swiper/-/swiper-12.1.2.tgz#39eaad0c088def66a7eb8f6bae1439384586ab90" @@ -5964,7 +7068,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0: +tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -6081,6 +7185,29 @@ undici-types@~7.18.0: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz#65a7adfad8574c219890e219285ce4c64ed67eaa" + integrity sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz#301d4f8a43d2b75c97adfad87c9dd5350c9475d1" + integrity sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ== + unified@^10.0.0: version "10.1.2" resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df"