diff --git a/.github/workflows/generate-llms.yml b/.github/workflows/generate-llms.yml new file mode 100644 index 0000000..272ceba --- /dev/null +++ b/.github/workflows/generate-llms.yml @@ -0,0 +1,51 @@ +name: Generate LLMs files + +on: + push: + branches: + - dev + +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 staging env file + run: | + echo "${{ secrets.ENV_STAGING }}" | base64 -d > .env + rm -f .env.local + + - name: Generate llms.txt + run: node scripts/generate-llms.mjs + env: + LLMS_MODE: curated + + - name: Generate llms-full.txt + run: node scripts/generate-llms.mjs + env: + LLMS_MODE: full + + - 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 files" + git push + fi \ No newline at end of file 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..81f7cae 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "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 node scripts/generate-llms.mjs", + "generate:llms:full": "cross-env LLMS_MODE=full node scripts/generate-llms.mjs", "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 +20,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 +79,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..c006fe0 --- /dev/null +++ b/public/keepsimple_/assets/tools/container/dark-bg.svg @@ -0,0 +1,10 @@ + + + + + + + + + + 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/scripts/generate-llms.mjs b/scripts/generate-llms.mjs new file mode 100644 index 0000000..687e311 --- /dev/null +++ b/scripts/generate-llms.mjs @@ -0,0 +1,400 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import dotenv from 'dotenv'; + +dotenv.config({ path: '.env' }); +dotenv.config({ path: '.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 seoDescriptions = { + '/': '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 = { + curated: { + outputFile: path.join(PUBLIC_DIR, 'keepsimple_', 'llms.txt'), + slugLimit: 10, + writeMarkdown: false, + modeLabel: 'curated', + }, + full: { + outputFile: path.join(PUBLIC_DIR, 'keepsimple_', 'llms-full.txt'), + slugLimit: Infinity, + writeMarkdown: true, + markdownRoot: path.join( + PUBLIC_DIR, + 'keepsimple_', + 'llms-full-pages', + 'article', + ), + modeLabel: 'full', + }, +}; + +const appConfig = { + mode: process.env.LLMS_MODE === 'full' ? 'full' : 'curated', +}; + +const stripHtml = value => + String(value || '') + .replace(/<[^>]*>/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + +const formatPageName = route => { + 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, route) => { + const normalizedBase = String(baseUrl || 'https://keepsimple.io').replace( + /\/+$/, + '', + ); + const normalizedRoute = route.startsWith('/') ? route : `/${route}`; + return `${normalizedBase}${normalizedRoute}`; +}; + +const shouldSkipEntry = entryName => entryName.startsWith('_'); + +const isRouteFile = fileName => + /\.(tsx|ts|jsx|js)$/.test(fileName) && + !/^(404|500)\.(tsx|ts|jsx|js)$/.test(fileName); + +const routeFromFilePath = filePath => { + 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 => { + 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 [...routeSet].sort((a, b) => a.localeCompare(b)); +}; + +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); +}; + +const getArticleRecords = async () => { + const url = `${process.env.NEXT_PUBLIC_STRAPI}/api/articles?locale=en&pagination[pageSize]=1000&populate=*`; + + try { + return await fetch(url) + .then(resp => resp.json()) + .then(json => json?.data || []); + } catch (error) { + console.log( + `[strapi] failed to fetch articles: ${error?.message || error}`, + ); + return []; + } +}; + +const toArticleSlugRecord = record => { + const attributes = record?.attributes || {}; + const newUrl = String(attributes?.newUrl || '') + .replace(/^\/+/, '') + .replace(/\/+$/, ''); + const oldUrl = String(attributes?.url || '') + .replace(/^\/+/, '') + .replace(/\/+$/, '') + .toLowerCase(); + + if (!newUrl) return null; + + const type = String(attributes?.type || '').toLowerCase(); + const isUxCore = + oldUrl.startsWith('uxcore/') || + oldUrl.startsWith('uxcg/') || + type.includes('uxcore') || + type.includes('uxcg') || + type.includes('thoughts'); + + return { + slug: newUrl, + title: attributes?.title || newUrl, + seoDescription: stripHtml( + attributes?.seoDescription || attributes?.description, + ), + isUxCore, + }; +}; + +const applyDynamicExpansions = async ({ routes, modeConfig }) => { + const records = (await getArticleRecords()) + .map(toArticleSlugRecord) + .filter(Boolean); + + if (!records.length) { + console.log('[expand] skipped all dynamic expansions (no article records)'); + return { + routes, + expandedArticleEntries: [], + expandedUxCoreEntries: [], + }; + } + + const limit = modeConfig.slugLimit; + const articleEntries = records.slice(0, limit).map(record => ({ + route: `/articles/${record.slug}`, + title: record.title, + seoDescription: record.seoDescription, + slug: record.slug, + })); + + const uxCoreEntries = records + .filter(record => record.isUxCore) + .slice(0, limit) + .map(record => ({ + route: `/uxcore/${record.slug}`, + title: record.title, + seoDescription: record.seoDescription, + slug: record.slug, + })); + + const nextRoutes = routes.filter( + route => + route !== '/articles/[slug]' && + route !== '/articles/[page]' && + route !== '/uxcore/[slug]' && + route !== '/uxcore/[page]', + ); + + articleEntries.forEach(item => { + nextRoutes.push(item.route); + console.log(`[expand] found article slug ${item.route}`); + }); + + uxCoreEntries.forEach(item => { + nextRoutes.push(item.route); + console.log(`[expand] found uxcore slug ${item.route}`); + }); + + return { + routes: [...new Set(nextRoutes)].sort((a, b) => a.localeCompare(b)), + expandedArticleEntries: articleEntries, + expandedUxCoreEntries: uxCoreEntries, + }; +}; + +const routeToDescription = (route, dynamicLookup) => { + 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 = [], +}) => { + const lines = []; + lines.push(`# ${title}`); + lines.push(`> ${description}`); + lines.push('## Pages & Resources'); + + routes.forEach(route => { + const name = formatPageName(route); + const absoluteUrl = toAbsoluteUrl(baseUrl, route); + const seoDescription = routeToDescription(route, dynamicLookup); + lines.push(`- [${name}](${absoluteUrl}): ${seoDescription}`); + }); + + customEntries.forEach(entry => { + lines.push( + `- [${entry.name}](${toAbsoluteUrl(baseUrl, entry.route)}): ${entry.description}`, + ); + }); + + return `${lines.join('\n')}\n`; +}; + +const writeMarkdownPages = async ({ + entries, + baseUrl, + markdownRoot, + sectionName, +}) => { + if (!markdownRoot) return; + + await fs.mkdir(markdownRoot, { recursive: true }); + + for (const entry of entries) { + const filePath = path.join(markdownRoot, `${entry.slug}.md`); + const body = [ + `# ${entry.title}`, + `- URL: ${toAbsoluteUrl(baseUrl, entry.route)}`, + `- Description: ${entry.seoDescription || 'No description available.'}`, + '', + ].join('\n'); + + try { + await fs.writeFile(filePath, body, 'utf8'); + console.log(`[markdown] found ${sectionName} page ${filePath}`); + } catch (error) { + console.log( + `[markdown] skipped ${sectionName} ${entry.slug}: ${error?.message || error}`, + ); + } + } +}; + +const run = async () => { + const modeConfig = MODE_CONFIG[appConfig.mode]; + const baseUrl = process.env.NEXT_PUBLIC_DOMAIN || 'https://keepsimple.io'; + const strapiUrl = process.env.NEXT_PUBLIC_STRAPI; + + if (!strapiUrl) { + console.log( + '[config] NEXT_PUBLIC_STRAPI is missing, dynamic and meta fetches may be skipped.', + ); + } + + let title = DEFAULT_TITLE; + let description = DEFAULT_DESCRIPTION; + + try { + const meta = await getLlmsMeta(); + title = meta?.title || DEFAULT_TITLE; + description = stripHtml(meta?.description || DEFAULT_DESCRIPTION); + console.log('[meta] found llms-meta'); + } catch (error) { + console.log(`[meta] skipped llms-meta: ${error?.message || error}`); + } + + let 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]'); + } + if (!routes.includes('/uxcore/[slug]')) { + routes.push('/uxcore/[slug]'); + } + + const { + routes: expandedRoutes, + expandedArticleEntries, + expandedUxCoreEntries, + } = await applyDynamicExpansions({ routes, modeConfig }); + + const seeAllArticlesRoute = '/articles'; + if (!expandedRoutes.includes(seeAllArticlesRoute)) { + expandedRoutes.push(seeAllArticlesRoute); + } + console.log('[expand] found See All Articles -> /articles'); + + const dynamicLookup = {}; + [...expandedArticleEntries, ...expandedUxCoreEntries].forEach(entry => { + dynamicLookup[entry.route] = entry.seoDescription; + }); + + const content = buildContent({ + title, + description, + routes: expandedRoutes.sort((a, b) => 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) { + console.log(`[write] skipped llms output: ${error?.message || error}`); + } + + if (modeConfig.writeMarkdown) { + await writeMarkdownPages({ + entries: [...expandedArticleEntries, ...expandedUxCoreEntries], + baseUrl, + markdownRoot: modeConfig.markdownRoot, + sectionName: 'article', + }); + } + + console.log( + `Successfully mapped ${expandedRoutes.length} routes to ${modeConfig.outputFile}`, + ); +}; + +run().catch(error => { + console.log(`[fatal] generator failed: ${error?.message || error}`); +}); 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..e648583 --- /dev/null +++ b/src/assets/icons/tools/btn-vg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + 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..ae682c4 --- /dev/null +++ b/src/assets/icons/tools/company-management.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + 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..50c3beb --- /dev/null +++ b/src/assets/icons/tools/tool-icons/bob.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..a535d3d --- /dev/null +++ b/src/assets/icons/tools/tool-icons/claude-bob.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c974e08 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/ema.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0f2e9f8 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/github.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..7f3806d --- /dev/null +++ b/src/assets/icons/tools/tool-icons/mosaic.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + 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..e3a5ae1 --- /dev/null +++ b/src/assets/icons/tools/tool-icons/tom.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 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/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..3165ed1 100644 --- a/src/components/articles/ArticleTag/ArticleTag.module.scss +++ b/src/components/articles/ArticleTag/ArticleTag.module.scss @@ -14,11 +14,18 @@ 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; @@ -26,6 +33,24 @@ padding: 5px 0 27px 0; letter-spacing: -0.15em; } + + .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%; + } + } } .bgMobile { @@ -42,6 +67,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 +81,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..1bfc2a4 --- /dev/null +++ b/src/components/tools/BobAchievements/BobAchievements.tsx @@ -0,0 +1,44 @@ +import cn from 'classnames'; +import { FC } from 'react'; + +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, +}) => { + return ( +
+ + First Behavior + UX Agent on OpenAI + +
+
+ + {' '} + {darkTheme ? : } 4.7 + + Ratings (40+) +
+
+ Productivity + Category +
+
+ 3906 + 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..d4a10b4 --- /dev/null +++ b/src/components/tools/ToolContainer/ToolContainer.module.scss @@ -0,0 +1,272 @@ +@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; + min-height: 390px; + 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; + } + + .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; +} + +.backgroundSvg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: 8; + left: 48px; + top: 32px; +} + +.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, +.primaryButton.inDevelopment .buttonBg path { + opacity: 1; +} + +.primaryButton.inDevelopment .buttonBg path, +.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: 600; + 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; + } + + .content { + min-height: 360px; + padding: 24px 16px 28px; + } + + .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..b26f411 --- /dev/null +++ b/src/components/tools/ToolContainer/ToolContainer.tsx @@ -0,0 +1,128 @@ +import cn from 'classnames'; +import Link from 'next/link'; +import { FC } from 'react'; + +import { DEFAULT_CONFIG, TOOL_CONFIG } from '@constants/tools'; + +import { useEffectiveDarkTheme } from '@hooks/useEffectiveDarkTheme'; +import useGlobals from '@hooks/useGlobals'; + +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 { isDarkTheme: globalDarkTheme } = useGlobals()[1]; + const darkTheme = useEffectiveDarkTheme(isDarkTheme || globalDarkTheme); + + const config = (id != null && TOOL_CONFIG[id]) || DEFAULT_CONFIG; + 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 ( + <> +
+ +
+

{title}

+

{description}

+ + {isChatGPT && isBob && } + +
+ {isClaude ? ( + + + Download + + ) : ( + + + + {isBlank && } + {isInDevelopment ? 'In Development' : 'Open'} + + + )} + + {isClaude && ( + } + className={styles.secondaryButton} + contentClassName={styles.secondaryButtonContent} + /> + )} + + {(isClaude || isChatGPT) && ( + + {isClaude ? ( + <> + + Powered by Claude + + ) : ( + <> + + Powered by 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..dd8b736 --- /dev/null +++ b/src/constants/tools.ts @@ -0,0 +1,61 @@ +import { FC, SVGProps } from 'react'; + +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: MosaicIcon, + hoverColor: '#3F4A7A', + darkHoverColor: '#C1D6FF', + darkIconFill: '#E08080', + }, + 2: { + Icon: EmaIcon, + hoverColor: '#0A3D3D', + darkHoverColor: '#95CCCC', + darkIconFill: '#95CCCC', + }, + 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: MosaicIcon, + hoverColor: '#3F4A7A', + darkHoverColor: '#C1D6FF', + darkIconFill: '#E08080', +}; 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/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/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..a644141 --- /dev/null +++ b/src/layouts/ToolsLayout/ToolsLayout.module.scss @@ -0,0 +1,63 @@ +.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; +} 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/contributors.tsx b/src/pages/contributors.tsx index 994ea67..4222f1b 100644 --- a/src/pages/contributors.tsx +++ b/src/pages/contributors.tsx @@ -12,6 +12,8 @@ import SeoGenerator from '@components/SeoGenerator'; import ContributorsLayout from '@layouts/ContributorsLayout'; +import DownloadIcon from './../assets/icons/download.svg'; + const Contributors: FC = ({ contributors }) => { const router = useRouter(); const { locale } = router as TRouter; @@ -44,6 +46,7 @@ const Contributors: FC = ({ contributors }) => { createdDate={data.createdAt} modifiedDate={data.updatedAt} /> + = ({ tools }) => { + 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"