diff --git a/eslint.config.mjs b/eslint.config.mjs index c053932..fa40a7c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -16,7 +16,6 @@ const compat = new FlatCompat({ const eslintConfig = [ ...compat.extends("next/core-web-vitals", "next/typescript"), - { plugins: { import: eslintPluginImport, @@ -27,84 +26,105 @@ const eslintConfig = [ }, rules: { - /* неиспользуемые переменные и импорты */ - "@typescript-eslint/no-unused-vars": [ - "warn", - { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, - ], - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ - "warn", - { - vars: "all", - varsIgnorePattern: "^_", - args: "after-used", - argsIgnorePattern: "^_", - }, - ], + /* неиспользуемые переменные и импорты */ + "@typescript-eslint/no-unused-vars": [ + "warn", + { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }, + ], + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { + vars: "all", + varsIgnorePattern: "^_", + args: "after-used", + argsIgnorePattern: "^_", + }, + ], - /* порядок импортов: стили .module.(s)css внизу */ - "simple-import-sort/imports": [ - "error", - { - groups: [ - ["^\\u0000"], // side-effects - ["^react", "^next", "^@?\\w"], // пакеты - ["^@/"], // алиасы проекта - ["^\\.\\.?(?:/|$)"], // относительные импорты (включая "..") - ["^.+\\.module\\.(css|scss)$"], // модули стилей - ], - }, - ], - "simple-import-sort/exports": "error", + /* порядок импортов: стили .module.(s)css внизу */ + "simple-import-sort/imports": [ + "error", + { + groups: [ + ["^\\u0000"], // side-effects + ["^react", "^next", "^@?\\w"], // пакеты + ["^@/"], // алиасы проекта + ["^\\.\\.?(?:/|$)"], // относительные импорты (включая "..") + ["^.+\\.module\\.(css|scss)$"], // модули стилей + ], + }, + ], + "simple-import-sort/exports": "error", - /* React правила */ - "react/jsx-uses-react": "off", // не нужно в React 17+ - "react/react-in-jsx-scope": "off", // не нужно в React 17+ - "react/prop-types": "off", // используем TypeScript - "react/display-name": "warn", - "react/jsx-key": "error", - "react/jsx-no-duplicate-props": "error", - "react/jsx-no-undef": "error", - // "react/no-array-index-key": "warn", - "react/no-danger": "warn", - "react/no-deprecated": "error", - "react/no-direct-mutation-state": "error", - "react/no-find-dom-node": "error", - "react/no-is-mounted": "error", - "react/no-render-return-value": "error", - "react/no-string-refs": "error", - "react/no-unescaped-entities": "warn", - "react/no-unknown-property": "error", - "react/no-unsafe": "warn", - "react/self-closing-comp": "error", + /* React правила */ + "react/jsx-uses-react": "off", // не нужно в React 17+ + "react/react-in-jsx-scope": "off", // не нужно в React 17+ + "react/prop-types": "off", // используем TypeScript + "react/display-name": "warn", + "react/jsx-key": "error", + "react/jsx-no-duplicate-props": "error", + "react/jsx-no-undef": "error", + // "react/no-array-index-key": "warn", + "react/no-danger": "warn", + "react/no-deprecated": "error", + "react/no-direct-mutation-state": "error", + "react/no-find-dom-node": "error", + "react/no-is-mounted": "error", + "react/no-render-return-value": "error", + "react/no-string-refs": "error", + "react/no-unescaped-entities": "warn", + "react/no-unknown-property": "error", + "react/no-unsafe": "warn", + "react/self-closing-comp": "error", - /* React Hooks правила */ - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", + /* React Hooks правила */ + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", - /* TypeScript правила */ - "@typescript-eslint/no-explicit-any": "warn", - "@typescript-eslint/no-non-null-assertion": "warn", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-empty-function": "warn", - "@typescript-eslint/no-inferrable-types": "error", + /* TypeScript правила */ + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-empty-function": "warn", + "@typescript-eslint/no-inferrable-types": "error", - /* Общие правила */ - "no-console": "warn", - "no-debugger": "error", - "no-alert": "warn", - "no-var": "error", - "prefer-const": "error", - "no-unused-expressions": "error", - "no-duplicate-imports": "error", - "no-multiple-empty-lines": ["error", { max: 2 }], - "eol-last": "error", - "no-trailing-spaces": "error", - }, + /* Общие правила */ + "no-console": "warn", + "no-debugger": "error", + "no-alert": "warn", + "no-var": "error", + "prefer-const": "error", + "no-unused-expressions": "error", + "no-duplicate-imports": "error", + "no-multiple-empty-lines": ["error", { max: 2 }], + "eol-last": "error", + "no-trailing-spaces": "error", + + /* Запрет SVG импортов как компонентов */ + "no-restricted-imports": [ + "error", + { + patterns: [ + { + group: ["*.svg"], + message: "❌ SVG imports as components break in production. Use inline SVG or next/image.", + }, + ], + }, + ], }, -]; +}, { + ignores: [ + "node_modules/**", + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + "public/metrics-scripts/**" + ] +}]; export default eslintConfig; diff --git a/messages/de.json b/messages/de.json index b55f3f2..755bf5d 100644 --- a/messages/de.json +++ b/messages/de.json @@ -222,6 +222,13 @@ "required_field": "This field is required" }, "AdditionalPurchases": { + "banner": { + "title": "Amazing!", + "description": "Your journey begins now" + }, + "Progress": { + "final_step": "Access Your Results" + }, "caution": { "title": "Caution!", "description": "To prevent double charges please don`t close the page and don`t go back." @@ -238,7 +245,8 @@ "save": "Save {discount}%", "get_my_consultation": "Get my consultation", "skip_this_offer": "Skip this offer", - "payment_error": "Something went wrong. Please try again later." + "payment_error": "Something went wrong. Please try again later.", + "copyright": "© 2025, Wit Lab LLC, California, US" }, "add-guides": { "title": "Choose your sign-up offer 🔥", @@ -248,6 +256,7 @@ "payment_error": "Something went wrong. Please try again later.", "select_product_error": "Please select a product", "skip_offer": "Skip offer", + "copyright": "© 2025, Wit Lab LLC, California, US", "products": { "main_ultra_pack": { "title": "ULTRA PACK", @@ -288,6 +297,17 @@ "emoji": "rised_hand.webp" } } + }, + "video-guides": { + "title": "Choose your sign-up offer 🔥", + "subtitle": "Available only now", + "description": "* You will be charged for the add-on services or offers selected at the time of purchase. This is a non-recuring payment.", + "button": "Continue", + "skip_button": "Skip this offer and proceed further", + "copyright": "© 2025, Wit Lab LLC, California, US", + "now": "Now", + "payment_error": "Something went wrong. Please try again later.", + "select_product_error": "Please select a product" } }, "Chat": { @@ -398,4 +418,4 @@ }, "Soulmate": {} } -} \ No newline at end of file +} diff --git a/messages/en.json b/messages/en.json index d9f7ffb..4ad28d3 100644 --- a/messages/en.json +++ b/messages/en.json @@ -229,6 +229,13 @@ "required_field": "This field is required" }, "AdditionalPurchases": { + "banner": { + "title": "Amazing!", + "description": "Your journey begins now" + }, + "Progress": { + "final_step": "Access Your Results" + }, "caution": { "title": "Caution!", "description": "To prevent double charges please don`t close the page and don`t go back." @@ -245,7 +252,8 @@ "save": "Save {discount}%", "get_my_consultation": "Get my consultation", "skip_this_offer": "Skip this offer", - "payment_error": "Something went wrong. Please try again later." + "payment_error": "Something went wrong. Please try again later.", + "copyright": "© 2025, Wit Lab LLC, California, US" }, "add-guides": { "title": "Choose your sign-up offer 🔥", @@ -255,6 +263,7 @@ "payment_error": "Something went wrong. Please try again later.", "select_product_error": "Please select a product", "skip_offer": "Skip offer", + "copyright": "© 2025, Wit Lab LLC, California, US", "products": { "main_ultra_pack": { "title": "ULTRA PACK", @@ -295,6 +304,24 @@ "emoji": "rised_hand.webp" } } + }, + "video-guides": { + "title": "Choose your sign-up offer 🔥", + "subtitle": "Available only now", + "description": "* You will be charged for the add-on services or offers selected at the time of purchase. This is a non-recuring payment.", + "button": "Continue", + "skip_button": "Skip this offer and proceed further", + "copyright": "© 2025, Wit Lab LLC, California, US", + "now": "Now" + } + }, + "Dashboard": { + "adviser": { + "title": "Talk to an Astrologer" + }, + "videoGuides": { + "now": "Now", + "purchaseFor": "Buy for {price}" } }, "Chat": { @@ -641,4 +668,4 @@ "month": "{count, plural, zero {#-months} one {#-month} two {#-months} few {#-months} many {#-months} other {#-months}}", "year": "{count, plural, zero {#-years} one {#-year} two {#-years} few {#-years} many {#-years} other {#-years}}" } -} \ No newline at end of file +} diff --git a/messages/es.json b/messages/es.json index 4dccde1..f57b0cc 100644 --- a/messages/es.json +++ b/messages/es.json @@ -222,6 +222,13 @@ "required_field": "This field is required" }, "AdditionalPurchases": { + "banner": { + "title": "Amazing!", + "description": "Your journey begins now" + }, + "Progress": { + "final_step": "Access Your Results" + }, "caution": { "title": "Caution!", "description": "To prevent double charges please don`t close the page and don`t go back." @@ -238,7 +245,8 @@ "save": "Save {discount}%", "get_my_consultation": "Get my consultation", "skip_this_offer": "Skip this offer", - "payment_error": "Something went wrong. Please try again later." + "payment_error": "Something went wrong. Please try again later.", + "copyright": "© 2025, Wit Lab LLC, California, US" }, "add-guides": { "title": "Choose your sign-up offer 🔥", @@ -248,6 +256,7 @@ "payment_error": "Something went wrong. Please try again later.", "select_product_error": "Please select a product", "skip_offer": "Skip offer", + "copyright": "© 2025, Wit Lab LLC, California, US", "products": { "main_ultra_pack": { "title": "ULTRA PACK", @@ -288,6 +297,17 @@ "emoji": "rised_hand.webp" } } + }, + "video-guides": { + "title": "Choose your sign-up offer 🔥", + "subtitle": "Available only now", + "description": "* You will be charged for the add-on services or offers selected at the time of purchase. This is a non-recuring payment.", + "button": "Continue", + "skip_button": "Skip this offer and proceed further", + "copyright": "© 2025, Wit Lab LLC, California, US", + "now": "Now", + "payment_error": "Something went wrong. Please try again later.", + "select_product_error": "Please select a product" } }, "Chat": { @@ -398,4 +418,4 @@ }, "Soulmate": {} } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index ed08e02..217be75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,20 +12,24 @@ "@tanstack/react-virtual": "^3.13.12", "client-only": "^0.0.1", "clsx": "^2.1.1", + "hls.js": "^1.6.13", "idb": "^8.0.3", - "next": "15.3.3", + "media-chrome": "^4.15.0", + "next": "^15.5.6", "next-intl": "^4.1.0", "react": "^19.0.0", "react-circular-progressbar": "^2.2.0", "react-dom": "^19.0.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", "sass": "^1.89.2", "server-only": "^0.0.1", + "shaka-player": "^4.16.7", "socket.io-client": "^4.8.1", "zod": "^3.25.64", "zustand": "^5.0.5" }, "devDependencies": { - "@eslint/eslintrc": "^3", "@svgr/webpack": "^8.1.0", "@types/node": "^20", "@types/react": "^19", @@ -1796,33 +1800,10 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.0.2", - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", - "dev": true, + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", + "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", "license": "MIT", "optional": true, "dependencies": { @@ -2109,10 +2090,20 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz", - "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.4.tgz", + "integrity": "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==", "cpu": [ "arm64" ], @@ -2128,13 +2119,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" + "@img/sharp-libvips-darwin-arm64": "1.2.3" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz", - "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.4.tgz", + "integrity": "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==", "cpu": [ "x64" ], @@ -2150,13 +2141,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.1.0" + "@img/sharp-libvips-darwin-x64": "1.2.3" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", - "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==", "cpu": [ "arm64" ], @@ -2170,9 +2161,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", - "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==", "cpu": [ "x64" ], @@ -2186,9 +2177,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", - "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.3.tgz", + "integrity": "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==", "cpu": [ "arm" ], @@ -2202,9 +2193,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", - "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.3.tgz", + "integrity": "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==", "cpu": [ "arm64" ], @@ -2218,9 +2209,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", - "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.3.tgz", + "integrity": "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==", "cpu": [ "ppc64" ], @@ -2234,9 +2225,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", - "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.3.tgz", + "integrity": "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==", "cpu": [ "s390x" ], @@ -2250,9 +2241,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", - "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.3.tgz", + "integrity": "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==", "cpu": [ "x64" ], @@ -2266,9 +2257,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", - "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.3.tgz", + "integrity": "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==", "cpu": [ "arm64" ], @@ -2282,9 +2273,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", - "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", + "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", "cpu": [ "x64" ], @@ -2298,9 +2289,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz", - "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.4.tgz", + "integrity": "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==", "cpu": [ "arm" ], @@ -2316,13 +2307,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.1.0" + "@img/sharp-libvips-linux-arm": "1.2.3" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz", - "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.4.tgz", + "integrity": "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==", "cpu": [ "arm64" ], @@ -2338,13 +2329,35 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.1.0" + "@img/sharp-libvips-linux-arm64": "1.2.3" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.4.tgz", + "integrity": "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.3" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz", - "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.4.tgz", + "integrity": "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==", "cpu": [ "s390x" ], @@ -2360,13 +2373,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.1.0" + "@img/sharp-libvips-linux-s390x": "1.2.3" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz", - "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", + "integrity": "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==", "cpu": [ "x64" ], @@ -2382,13 +2395,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.1.0" + "@img/sharp-libvips-linux-x64": "1.2.3" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz", - "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.4.tgz", + "integrity": "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==", "cpu": [ "arm64" ], @@ -2404,13 +2417,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz", - "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", + "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", "cpu": [ "x64" ], @@ -2426,20 +2439,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz", - "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.4.tgz", + "integrity": "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==", "cpu": [ "wasm32" ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.4.3" + "@emnapi/runtime": "^1.5.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -2449,9 +2462,9 @@ } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz", - "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.4.tgz", + "integrity": "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==", "cpu": [ "arm64" ], @@ -2468,9 +2481,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz", - "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.4.tgz", + "integrity": "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==", "cpu": [ "ia32" ], @@ -2487,9 +2500,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz", - "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.4.tgz", + "integrity": "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==", "cpu": [ "x64" ], @@ -2573,23 +2586,10 @@ "integrity": "sha512-wirTuVcR/cu9HTckgrXjQggeO4sap4QPBLWDUyBDEQJugY3CLHm4lECrDtLBtIzUJZXTeyidvTOY9lZIQ5qdTw==", "license": "MIT" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" - } - }, "node_modules/@next/env": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz", - "integrity": "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.6.tgz", + "integrity": "sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -2603,9 +2603,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz", - "integrity": "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.6.tgz", + "integrity": "sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==", "cpu": [ "arm64" ], @@ -2619,9 +2619,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz", - "integrity": "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.6.tgz", + "integrity": "sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==", "cpu": [ "x64" ], @@ -2635,9 +2635,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz", - "integrity": "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.6.tgz", + "integrity": "sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==", "cpu": [ "arm64" ], @@ -2651,9 +2651,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz", - "integrity": "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.6.tgz", + "integrity": "sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==", "cpu": [ "arm64" ], @@ -2667,9 +2667,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", - "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.6.tgz", + "integrity": "sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==", "cpu": [ "x64" ], @@ -2683,9 +2683,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", - "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.6.tgz", + "integrity": "sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==", "cpu": [ "x64" ], @@ -2699,9 +2699,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz", - "integrity": "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.6.tgz", + "integrity": "sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==", "cpu": [ "arm64" ], @@ -2715,9 +2715,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz", - "integrity": "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.6.tgz", + "integrity": "sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==", "cpu": [ "x64" ], @@ -2814,26 +2814,6 @@ "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", - "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@parcel/watcher-darwin-arm64": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", @@ -2854,226 +2834,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", - "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", - "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", - "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", - "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", - "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", - "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", - "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", - "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", - "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", - "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", - "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -3371,12 +3131,6 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "license": "Apache-2.0" - }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -3423,24 +3177,39 @@ "node": ">=10.13.0" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", - "dev": true, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@types/ms": "*" } }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3455,6 +3224,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz", @@ -3469,7 +3253,6 @@ "version": "19.1.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", - "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -3485,6 +3268,12 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.34.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz", @@ -3772,33 +3561,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.0.tgz", - "integrity": "sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.0.tgz", - "integrity": "sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.9.0", @@ -3814,233 +3581,6 @@ "darwin" ] }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.0.tgz", - "integrity": "sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.0.tgz", - "integrity": "sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.0.tgz", - "integrity": "sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.0.tgz", - "integrity": "sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.0.tgz", - "integrity": "sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.0.tgz", - "integrity": "sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.0.tgz", - "integrity": "sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.0.tgz", - "integrity": "sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.0.tgz", - "integrity": "sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.0.tgz", - "integrity": "sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.0.tgz", - "integrity": "sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.0.tgz", - "integrity": "sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.0.tgz", - "integrity": "sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.0.tgz", - "integrity": "sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.0.tgz", - "integrity": "sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.0.tgz", - "integrity": "sha512-k59o9ZyeyS0hAlcaKFezYSH2agQeRFEB7KoQLXl3Nb3rgkqT1NY9Vwy+SqODiLmYnEjxWJVRE/yq2jFVqdIxZw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -4379,6 +3919,16 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4461,17 +4011,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -4565,6 +4104,25 @@ ], "license": "CC-BY-4.0" }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ce-la-react": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ce-la-react/-/ce-la-react-0.3.1.tgz", + "integrity": "sha512-g0YwpZDPIwTwFumGTzNHcgJA6VhFfFCJkSNdUdC04br2UfU+56JDrJrJva3FZ7MToB4NDHAFBiPE/PZdNl1mQA==", + "license": "BSD-3-Clause", + "peerDependencies": { + "react": ">=17.0.0" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4582,6 +4140,46 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -4612,25 +4210,11 @@ "node": ">=6" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4643,18 +4227,17 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "devOptional": true, + "dev": true, "license": "MIT" }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/commander": { @@ -4821,7 +4404,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -4889,7 +4471,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4909,6 +4490,19 @@ "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "license": "MIT" }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4962,6 +4556,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -4975,6 +4578,19 @@ "node": ">=0.10" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -5798,6 +5414,16 @@ "node": ">=4.0" } }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -5808,6 +5434,12 @@ "node": ">=0.10.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6227,6 +5859,62 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hls.js": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.6.13.tgz", + "integrity": "sha512-hNEzjZNHf5bFrUNvdS4/1RjIanuJ6szpWNfTaX5I6WfGynWXGT7K/YQLYtemSvFExzeMdgdE4SsyVLJbd5PcZA==", + "license": "Apache-2.0" + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/idb": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.3.tgz", @@ -6276,6 +5964,12 @@ "node": ">=0.8.19" } }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -6303,6 +5997,30 @@ "tslib": "^2.8.0" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -6321,13 +6039,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT", - "optional": true - }, "node_modules/is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", @@ -6455,6 +6166,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -6513,6 +6234,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -6566,6 +6297,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -6914,6 +6657,16 @@ "dev": true, "license": "MIT" }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6947,6 +6700,16 @@ "yallist": "^3.0.2" } }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6957,6 +6720,288 @@ "node": ">= 0.4" } }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", @@ -6964,6 +7009,15 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/media-chrome": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/media-chrome/-/media-chrome-4.15.0.tgz", + "integrity": "sha512-OgC6m3Ss4cCUEVhvmRdUbnExqVKf8CDRDmbVTjIuRGAXdmz/vc34fL3onSsOm2uDZbhDB4Lb4KArGA48wG8Puw==", + "license": "MIT", + "dependencies": { + "ce-la-react": "^0.3.0" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -6974,6 +7028,569 @@ "node": ">= 8" } }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -7068,15 +7685,13 @@ } }, "node_modules/next": { - "version": "15.3.3", - "resolved": "https://registry.npmjs.org/next/-/next-15.3.3.tgz", - "integrity": "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==", + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.6.tgz", + "integrity": "sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==", "license": "MIT", "dependencies": { - "@next/env": "15.3.3", - "@swc/counter": "0.1.3", + "@next/env": "15.5.6", "@swc/helpers": "0.5.15", - "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" @@ -7088,19 +7703,19 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.3.3", - "@next/swc-darwin-x64": "15.3.3", - "@next/swc-linux-arm64-gnu": "15.3.3", - "@next/swc-linux-arm64-musl": "15.3.3", - "@next/swc-linux-x64-gnu": "15.3.3", - "@next/swc-linux-x64-musl": "15.3.3", - "@next/swc-win32-arm64-msvc": "15.3.3", - "@next/swc-win32-x64-msvc": "15.3.3", - "sharp": "^0.34.1" + "@next/swc-darwin-arm64": "15.5.6", + "@next/swc-darwin-x64": "15.5.6", + "@next/swc-linux-arm64-gnu": "15.5.6", + "@next/swc-linux-arm64-musl": "15.5.6", + "@next/swc-linux-x64-gnu": "15.5.6", + "@next/swc-linux-x64-musl": "15.5.6", + "@next/swc-win32-arm64-msvc": "15.5.6", + "@next/swc-win32-x64-msvc": "15.5.6", + "sharp": "^0.34.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", @@ -7390,6 +8005,31 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -7541,6 +8181,16 @@ "react-is": "^16.13.1" } }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7609,6 +8259,33 @@ "dev": true, "license": "MIT" }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -7724,6 +8401,72 @@ "regjsparser": "bin/parser" } }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -7949,16 +8692,25 @@ "node": ">= 0.4" } }, + "node_modules/shaka-player": { + "version": "4.16.7", + "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-4.16.7.tgz", + "integrity": "sha512-JWIVIxXRDkmogT+3t7UtYDbqY0dHyrfpqYPkKsyTXqBimwEgKFJIayhxwYF7Cn/qTkhp2nocHIdzaVZkaZLK4A==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, "node_modules/sharp": { - "version": "0.34.2", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz", - "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.4.tgz", + "integrity": "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==", "hasInstallScript": true, "license": "Apache-2.0", "optional": true, "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.4", + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.0", "semver": "^7.7.2" }, "engines": { @@ -7968,33 +8720,34 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.2", - "@img/sharp-darwin-x64": "0.34.2", - "@img/sharp-libvips-darwin-arm64": "1.1.0", - "@img/sharp-libvips-darwin-x64": "1.1.0", - "@img/sharp-libvips-linux-arm": "1.1.0", - "@img/sharp-libvips-linux-arm64": "1.1.0", - "@img/sharp-libvips-linux-ppc64": "1.1.0", - "@img/sharp-libvips-linux-s390x": "1.1.0", - "@img/sharp-libvips-linux-x64": "1.1.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", - "@img/sharp-libvips-linuxmusl-x64": "1.1.0", - "@img/sharp-linux-arm": "0.34.2", - "@img/sharp-linux-arm64": "0.34.2", - "@img/sharp-linux-s390x": "0.34.2", - "@img/sharp-linux-x64": "0.34.2", - "@img/sharp-linuxmusl-arm64": "0.34.2", - "@img/sharp-linuxmusl-x64": "0.34.2", - "@img/sharp-wasm32": "0.34.2", - "@img/sharp-win32-arm64": "0.34.2", - "@img/sharp-win32-ia32": "0.34.2", - "@img/sharp-win32-x64": "0.34.2" + "@img/sharp-darwin-arm64": "0.34.4", + "@img/sharp-darwin-x64": "0.34.4", + "@img/sharp-libvips-darwin-arm64": "1.2.3", + "@img/sharp-libvips-darwin-x64": "1.2.3", + "@img/sharp-libvips-linux-arm": "1.2.3", + "@img/sharp-libvips-linux-arm64": "1.2.3", + "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-s390x": "1.2.3", + "@img/sharp-libvips-linux-x64": "1.2.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.3", + "@img/sharp-linux-arm": "0.34.4", + "@img/sharp-linux-arm64": "0.34.4", + "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-s390x": "0.34.4", + "@img/sharp-linux-x64": "0.34.4", + "@img/sharp-linuxmusl-arm64": "0.34.4", + "@img/sharp-linuxmusl-x64": "0.34.4", + "@img/sharp-wasm32": "0.34.4", + "@img/sharp-win32-arm64": "0.34.4", + "@img/sharp-win32-ia32": "0.34.4", + "@img/sharp-win32-x64": "0.34.4" } }, "node_modules/sharp/node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "optional": true, "engines": { @@ -8100,16 +8853,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, "node_modules/snake-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", @@ -8192,6 +8935,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -8213,14 +8966,6 @@ "node": ">= 0.4" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -8334,6 +9079,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -8357,6 +9116,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.18.tgz", + "integrity": "sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.11" + } + }, + "node_modules/style-to-object": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.11.tgz", + "integrity": "sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -8497,6 +9274,26 @@ "node": ">=8.0" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -8704,6 +9501,93 @@ "node": ">=4" } }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unrs-resolver": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.0.tgz", @@ -8794,6 +9678,34 @@ "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8995,6 +9907,16 @@ "optional": true } } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index 9e94def..428cdf2 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "dev": "next dev --turbopack", "build": "next build", "start": "next start -p 3001", - "lint": "next lint", - "lint:fix": "next lint --fix", + "lint": "eslint .", + "lint:fix": "eslint --fix .", "format": "prettier --write .", "format:check": "prettier --check .", "type-check": "tsc --noEmit" @@ -17,20 +17,24 @@ "@tanstack/react-virtual": "^3.13.12", "client-only": "^0.0.1", "clsx": "^2.1.1", + "hls.js": "^1.6.13", "idb": "^8.0.3", - "next": "15.3.3", + "media-chrome": "^4.15.0", + "next": "^15.5.6", "next-intl": "^4.1.0", "react": "^19.0.0", "react-circular-progressbar": "^2.2.0", "react-dom": "^19.0.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1", "sass": "^1.89.2", "server-only": "^0.0.1", + "shaka-player": "^4.16.7", "socket.io-client": "^4.8.1", "zod": "^3.25.64", "zustand": "^5.0.5" }, "devDependencies": { - "@eslint/eslintrc": "^3", "@svgr/webpack": "^8.1.0", "@types/node": "^20", "@types/react": "^19", diff --git a/public/emoji/heart_from_hands.webp b/public/emoji/heart_from_hands.webp new file mode 100644 index 0000000..be923a0 Binary files /dev/null and b/public/emoji/heart_from_hands.webp differ diff --git a/public/emoji/ring.webp b/public/emoji/ring.webp new file mode 100644 index 0000000..98f9fb8 Binary files /dev/null and b/public/emoji/ring.webp differ diff --git a/public/emoji/rose.webp b/public/emoji/rose.webp new file mode 100644 index 0000000..01d5b96 Binary files /dev/null and b/public/emoji/rose.webp differ diff --git a/src/app/[locale]/(additional-purchases)/ap/[pageType]/layout.tsx b/src/app/[locale]/(additional-purchases)/ap/[pageType]/layout.tsx index 8a311ed..04d878c 100644 --- a/src/app/[locale]/(additional-purchases)/ap/[pageType]/layout.tsx +++ b/src/app/[locale]/(additional-purchases)/ap/[pageType]/layout.tsx @@ -1,6 +1,9 @@ import { redirect } from "next/navigation"; -import { MultiPageNavigationProvider } from "@/components/domains/additional-purchases"; +import { + MultiPageNavigationProvider, + ProgressLayout, +} from "@/components/domains/additional-purchases"; import { loadFunnelPaymentById } from "@/entities/session/funnel/loaders"; import { ROUTES } from "@/shared/constants/client-routes"; import { ELocalesPlacement } from "@/types"; @@ -30,7 +33,7 @@ export default async function MultiPageLayout({ return ( - {children} + {children} ); } diff --git a/src/app/[locale]/(additional-purchases)/ap/[pageType]/page.tsx b/src/app/[locale]/(additional-purchases)/ap/[pageType]/page.tsx index 9e7d979..a74b02a 100644 --- a/src/app/[locale]/(additional-purchases)/ap/[pageType]/page.tsx +++ b/src/app/[locale]/(additional-purchases)/ap/[pageType]/page.tsx @@ -3,6 +3,7 @@ import { redirect } from "next/navigation"; import { AddConsultantPage, AddGuidesPage, + VideoGuidesPage, } from "@/components/domains/additional-purchases"; import { ROUTES } from "@/shared/constants/client-routes"; @@ -20,6 +21,8 @@ export default async function AdditionalProductPage({ return ; case "add_guides": return ; + case "video_guides": + return ; default: return redirect(ROUTES.home()); } diff --git a/src/app/[locale]/(core)/page.module.scss b/src/app/[locale]/(core)/page.module.scss index 7f581db..70eb179 100644 --- a/src/app/[locale]/(core)/page.module.scss +++ b/src/app/[locale]/(core)/page.module.scss @@ -1,6 +1,6 @@ .page { display: flex; flex-direction: column; - gap: 24px; + gap: 37px; position: relative; } diff --git a/src/app/[locale]/(core)/page.tsx b/src/app/[locale]/(core)/page.tsx index 4f4e81f..b701641 100644 --- a/src/app/[locale]/(core)/page.tsx +++ b/src/app/[locale]/(core)/page.tsx @@ -11,6 +11,7 @@ import { PalmSection, PalmSectionSkeleton, PortraitsSection, + VideoGuidesSection, } from "@/components/domains/dashboard"; import { loadChatsList } from "@/entities/chats/loaders"; import { @@ -19,18 +20,25 @@ import { loadMeditations, loadPalms, loadPortraits, + loadVideoGuides, } from "@/entities/dashboard/loaders"; import styles from "./page.module.scss"; +// Force dynamic to always get fresh data +export const dynamic = "force-dynamic"; + export default async function Home() { const chatsPromise = loadChatsList(); const portraits = await loadPortraits(); + const videoGuides = await loadVideoGuides(); return (
+ + }> diff --git a/src/app/[locale]/(core)/video-guides/[id]/layout.tsx b/src/app/[locale]/(core)/video-guides/[id]/layout.tsx new file mode 100644 index 0000000..ef8c04f --- /dev/null +++ b/src/app/[locale]/(core)/video-guides/[id]/layout.tsx @@ -0,0 +1,7 @@ +export default function VideoGuideLayout({ + children, +}: { + children: React.ReactNode; +}) { + return <>{children}; +} diff --git a/src/app/[locale]/(core)/video-guides/[id]/loading.tsx b/src/app/[locale]/(core)/video-guides/[id]/loading.tsx new file mode 100644 index 0000000..ef6ee0e --- /dev/null +++ b/src/app/[locale]/(core)/video-guides/[id]/loading.tsx @@ -0,0 +1,22 @@ +import { Spinner } from "@/components/ui"; + +export default function Loading() { + return ( +
+ +
+ ); +} diff --git a/src/app/[locale]/(core)/video-guides/[id]/page.tsx b/src/app/[locale]/(core)/video-guides/[id]/page.tsx new file mode 100644 index 0000000..3900914 --- /dev/null +++ b/src/app/[locale]/(core)/video-guides/[id]/page.tsx @@ -0,0 +1,42 @@ +import { notFound } from "next/navigation"; + +import { VideoGuideView } from "@/components/domains/video-guides"; +import { VideoGuideSchema } from "@/entities/dashboard/types"; +import { http } from "@/shared/api/httpClient"; +import { API_ROUTES } from "@/shared/constants/api-routes"; + +// Force dynamic to always get fresh data +export const dynamic = "force-dynamic"; + +export default async function VideoGuidePage({ + params, +}: { + params: Promise<{ id: string }>; +}) { + const { id } = await params; + + // Get specific video guide data from new API + const response = await http.get<{ status: string; data: typeof VideoGuideSchema._type }>( + API_ROUTES.videoGuide(id), + { + cache: "no-store", + } + ); + + const videoGuide = response.data; + + if (!videoGuide || !videoGuide.isPurchased) { + notFound(); + } + + return ( + + ); +} diff --git a/src/app/[locale]/(email-marketing)/em/(soulmate)/s/v1/landing/page.tsx b/src/app/[locale]/(email-marketing)/em/(soulmate)/s/v1/landing/page.tsx index 09385af..83efe4c 100644 --- a/src/app/[locale]/(email-marketing)/em/(soulmate)/s/v1/landing/page.tsx +++ b/src/app/[locale]/(email-marketing)/em/(soulmate)/s/v1/landing/page.tsx @@ -34,7 +34,10 @@ function getUsernameFromEmail(email: string): string { export default async function EmailMarketingSoulmateV1Landing() { const [payment, user] = await Promise.all([ - loadFunnelPaymentById(payload, "main") as Promise, + loadFunnelPaymentById( + payload, + "main" + ) as Promise, loadUser(), ]); diff --git a/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.module.scss b/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.module.scss index cf8be48..e2127ad 100644 --- a/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.module.scss +++ b/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.module.scss @@ -1,26 +1,45 @@ -.container.container { - display: flex; - flex-direction: column; - -webkit-box-align: center; - align-items: center; - width: 100%; - height: fit-content; - max-width: 560px; +.container { position: fixed; - bottom: 0dvh; + bottom: calc(0dvh + 16px); left: 50%; transform: translateX(-50%); - margin-top: 0px; - padding-bottom: 20px; - padding-inline: 15px; - z-index: 5; -} + width: 100%; + padding-inline: 24px; + max-width: 560px; + height: fit-content; -.button.button { - padding-block: 16px; -} + & > .button { + padding-block: 20px; + background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%); + border-radius: 16px; + box-shadow: + 0px 5px 14px 0px #3b82f666, + 0px 4px 6px 0px #3b82f61a; -.skipButton.skipButton { - background-color: transparent; - text-decoration: underline; + & > .text { + font-size: 19px; + font-weight: 500; + line-height: 125%; + } + } + + & > .skipButton { + padding: 0; + min-height: none; + margin-top: 13px; + + & > .text { + font-size: 16px; + line-height: 24px; + color: #1f2937; + text-decoration: underline; + } + } + + & > .copyright { + font-size: 12px; + line-height: 16px; + color: #9ca3af; + margin-top: 20px; + } } diff --git a/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.tsx b/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.tsx index 94d3f24..be206bd 100644 --- a/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.tsx +++ b/src/components/domains/additional-purchases/AddConsultantButton/AddConsultantButton.tsx @@ -1,5 +1,6 @@ "use client"; +import { useState } from "react"; import { useTranslations } from "next-intl"; import { Button, Spinner, Typography } from "@/components/ui"; @@ -17,12 +18,14 @@ export default function AddConsultantButton() { const { addToast } = useToast(); const { navigation } = useMultiPageNavigationContext(); const data = navigation.currentItem; + const [isNavigating, setIsNavigating] = useState(false); const product = data?.variants?.[0]; const { handleSingleCheckout, isLoading } = useSingleCheckout({ - onSuccess: () => { - navigation.goToNext(); + onSuccess: async () => { + setIsNavigating(true); + await navigation.goToNext(); }, onError: _error => { addToast({ @@ -57,30 +60,36 @@ export default function AddConsultantButton() { navigation.goToNext(); }; + const isButtonDisabled = isLoading || isNavigating || !product; + return ( + + {t("copyright")} + ); } diff --git a/src/components/domains/additional-purchases/AddConsultantPage/AddConsultantPage.tsx b/src/components/domains/additional-purchases/AddConsultantPage/AddConsultantPage.tsx index 1b7eeb8..aa259d0 100644 --- a/src/components/domains/additional-purchases/AddConsultantPage/AddConsultantPage.tsx +++ b/src/components/domains/additional-purchases/AddConsultantPage/AddConsultantPage.tsx @@ -1,20 +1,18 @@ -import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; import { AddConsultantButton, - Caution, ConsultationTable, } from "@/components/domains/additional-purchases"; import { Card, Typography } from "@/components/ui"; import styles from "./AddConsultantPage.module.scss"; -export default function AddConsultantPage() { - const t = useTranslations("AdditionalPurchases.add-consultant"); +export default async function AddConsultantPage() { + const t = await getTranslations("AdditionalPurchases.add-consultant"); return ( <> - {t("title")} diff --git a/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.module.scss b/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.module.scss index 28a4f02..465d567 100644 --- a/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.module.scss +++ b/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.module.scss @@ -7,8 +7,26 @@ padding-inline: 24px; max-width: 560px; height: fit-content; -} -.button { - padding-block: 16px; + & > .button { + padding-block: 20px; + background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%); + border-radius: 16px; + box-shadow: + 0px 5px 14px 0px #3b82f666, + 0px 4px 6px 0px #3b82f61a; + + & > .text { + font-size: 19px; + font-weight: 500; + line-height: 125%; + } + } + + & > .copyright { + font-size: 12px; + line-height: 16px; + color: #9ca3af; + margin-top: 20px; + } } diff --git a/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.tsx b/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.tsx index 3e0a305..2213171 100644 --- a/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.tsx +++ b/src/components/domains/additional-purchases/AddGuidesButton/AddGuidesButton.tsx @@ -1,5 +1,6 @@ "use client"; +import { useState } from "react"; import { useTranslations } from "next-intl"; import { Button, Spinner, Typography } from "@/components/ui"; @@ -18,10 +19,12 @@ export default function AddGuidesButton() { const { addToast } = useToast(); const { selectedProduct } = useProductSelection(); const { navigation } = useMultiPageNavigationContext(); + const [isNavigating, setIsNavigating] = useState(false); const { handleSingleCheckout, isLoading } = useSingleCheckout({ - onSuccess: () => { - navigation.goToNext(); + onSuccess: async () => { + setIsNavigating(true); + await navigation.goToNext(); }, onError: _error => { addToast({ @@ -58,21 +61,26 @@ export default function AddGuidesButton() { const isSkipOffer = selectedProduct?.id === "main_skip_offer"; + const isButtonDisabled = isLoading || isNavigating; + return ( + + {t("copyright")} + ); } diff --git a/src/components/domains/additional-purchases/AddGuidesPage/AddGuidesPage.tsx b/src/components/domains/additional-purchases/AddGuidesPage/AddGuidesPage.tsx index c44f400..1e8e90a 100644 --- a/src/components/domains/additional-purchases/AddGuidesPage/AddGuidesPage.tsx +++ b/src/components/domains/additional-purchases/AddGuidesPage/AddGuidesPage.tsx @@ -1,9 +1,8 @@ import { Suspense } from "react"; -import { useTranslations } from "next-intl"; +import { getTranslations } from "next-intl/server"; import { AddGuidesButton, - Caution, Offers, OffersSkeleton, ProductSelectionProvider, @@ -12,12 +11,11 @@ import { Typography } from "@/components/ui"; import styles from "./AddGuidesPage.module.scss"; -export default function AddGuidesPage() { - const t = useTranslations("AdditionalPurchases.add-guides"); +export default async function AddGuidesPage() { + const t = await getTranslations("AdditionalPurchases.add-guides"); return ( - {t("title")} diff --git a/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.module.scss b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.module.scss new file mode 100644 index 0000000..5ecfd76 --- /dev/null +++ b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.module.scss @@ -0,0 +1,45 @@ +.container { + width: 100%; + padding: 18px 20px 25px 25px; + background: linear-gradient( + 90deg, + rgba(78, 205, 196, 0.1) 0%, + rgba(102, 126, 234, 0.1) 100% + ); + border: 1px solid #4ecdc433; + border-radius: 32px; + margin-top: 34px; + display: grid; + grid-template-columns: 48px 1fr; + gap: 16px; + + & > .iconContainer { + width: 48px; + height: 48px; + border-radius: 50%; + background-color: #4ecdc433; + display: flex; + align-items: center; + justify-content: center; + } + + & > .textContainer { + display: flex; + flex-direction: column; + align-items: flex-start; + + & > .title { + font-size: 18px; + font-weight: 700; + line-height: 28px; + color: #262626; + } + + & > .description { + font-size: 16px; + font-weight: 500; + line-height: 24px; + color: #525252; + } + } +} diff --git a/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.tsx b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.tsx new file mode 100644 index 0000000..4700c2e --- /dev/null +++ b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/AdditionalPurchaseBanner.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useTranslations } from "next-intl"; + +import { Typography } from "@/components/ui"; + +import styles from "./AdditionalPurchaseBanner.module.scss"; + +export default function AdditionalPurchaseBanner() { + const t = useTranslations("AdditionalPurchases.banner"); + + return ( +
+
+ + + +
+
+ + {t("title")} + + + {t("description")} + +
+
+ ); +} diff --git a/src/components/domains/additional-purchases/AdditionalPurchaseBanner/HeartIcon.svg b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/HeartIcon.svg new file mode 100644 index 0000000..78e1716 --- /dev/null +++ b/src/components/domains/additional-purchases/AdditionalPurchaseBanner/HeartIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/domains/additional-purchases/Progress/Progress.module.scss b/src/components/domains/additional-purchases/Progress/Progress.module.scss new file mode 100644 index 0000000..b2ee372 --- /dev/null +++ b/src/components/domains/additional-purchases/Progress/Progress.module.scss @@ -0,0 +1,108 @@ +.container { + width: 100%; + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: space-between; + position: sticky; + top: 24px; + z-index: 7777; + + & > .blurGradient { + background: rgb(247 247 247 / 42%); + rotate: 180deg; + left: -24px; + right: -24px; + } + + & > * { + z-index: 8888; + } + + & > .item { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; + max-width: 80px; + + & > .marker { + width: 32px; + height: 32px; + border: 1px solid #e2e8f0; + border-radius: 50%; + background: f8fafc; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + background-color: #f8fafc; + + & > .number { + font-size: 12px; + font-weight: 500; + color: #9ca3af; + } + } + + & > .text { + font-size: 12px; + font-weight: 500; + line-height: 16px; + color: #9ca3af; + } + + &.active { + & > .marker { + position: relative; + box-shadow: 0px 2px 15px 0px #3b82f6f7; + background-color: #3b82f6; + border: 2px solid #ffffff; + + &::before { + content: ""; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #fff; + } + + & > .number { + display: none; + } + } + + & > .text { + color: #2866ed; + font-weight: 600; + } + } + + &.done { + & > .marker { + box-shadow: 0px 0px 0px 0px #3b82f626; + background-color: #2866ed; + border: none; + + & > .number { + display: none; + } + } + + & > .text { + color: #282828; + } + } + } + + .connector { + position: absolute; + top: 15px; + height: 2px; + z-index: 7777; + } +} diff --git a/src/components/domains/additional-purchases/Progress/Progress.tsx b/src/components/domains/additional-purchases/Progress/Progress.tsx new file mode 100644 index 0000000..eecb8d1 --- /dev/null +++ b/src/components/domains/additional-purchases/Progress/Progress.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { useTranslations } from "next-intl"; +import clsx from "clsx"; + +import { Icon, IconName, Typography } from "@/components/ui"; +import { BlurComponent } from "@/components/widgets"; +import { useDynamicSize } from "@/hooks/DOM/useDynamicSize"; + +import styles from "./Progress.module.scss"; + +interface IProgressProps { + items: string[]; + activeItemIndex: number; +} + +export default function Progress({ items, activeItemIndex }: IProgressProps) { + const t = useTranslations("AdditionalPurchases.Progress"); + + const finalStep = t("final_step"); + const allItems = [...items, finalStep]; + + const { width: containerWidth, elementRef } = useDynamicSize({ + defaultWidth: 327, + }); + + const firstChild = elementRef.current?.childNodes[0] as HTMLElement; + + const lastChild = elementRef.current?.childNodes[ + allItems.length - 1 + ] as HTMLElement; + + const leftIndent = + ((firstChild?.getBoundingClientRect().width || 100) - 32) / 2; + + const rightIndent = + ((lastChild?.getBoundingClientRect().width || 76) - 32) / 2; + + return ( + + {allItems.map((item, index) => ( +
index && styles.done + )} + > +
+ {activeItemIndex > index && styles.done && ( + + )} + + {index + 1} + +
+ + {item} + +
+ ))} +
+ + ); +} diff --git a/src/components/domains/additional-purchases/ProgressLayout/ProgressLayout.tsx b/src/components/domains/additional-purchases/ProgressLayout/ProgressLayout.tsx new file mode 100644 index 0000000..70021e8 --- /dev/null +++ b/src/components/domains/additional-purchases/ProgressLayout/ProgressLayout.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { IFunnelPaymentPlacement } from "@/entities/session/funnel/types"; + +import { Progress, useMultiPageNavigationContext } from ".."; + +interface IProgressLayoutProps { + children: React.ReactNode; +} + +export default function ProgressLayout({ children }: IProgressLayoutProps) { + const { navigation } = useMultiPageNavigationContext(); + + const progressItems = navigation.data.map((item: IFunnelPaymentPlacement) => { + return item.title || item.type || ""; + }); + + return ( + <> + + {children} + + ); +} diff --git a/src/components/domains/additional-purchases/VideoGuidesBanner/HeartIcon.svg b/src/components/domains/additional-purchases/VideoGuidesBanner/HeartIcon.svg new file mode 100644 index 0000000..78e1716 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesBanner/HeartIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.module.scss b/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.module.scss new file mode 100644 index 0000000..5ecfd76 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.module.scss @@ -0,0 +1,45 @@ +.container { + width: 100%; + padding: 18px 20px 25px 25px; + background: linear-gradient( + 90deg, + rgba(78, 205, 196, 0.1) 0%, + rgba(102, 126, 234, 0.1) 100% + ); + border: 1px solid #4ecdc433; + border-radius: 32px; + margin-top: 34px; + display: grid; + grid-template-columns: 48px 1fr; + gap: 16px; + + & > .iconContainer { + width: 48px; + height: 48px; + border-radius: 50%; + background-color: #4ecdc433; + display: flex; + align-items: center; + justify-content: center; + } + + & > .textContainer { + display: flex; + flex-direction: column; + align-items: flex-start; + + & > .title { + font-size: 18px; + font-weight: 700; + line-height: 28px; + color: #262626; + } + + & > .description { + font-size: 16px; + font-weight: 500; + line-height: 24px; + color: #525252; + } + } +} diff --git a/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.tsx b/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.tsx new file mode 100644 index 0000000..4db3bac --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesBanner/VideoGuidesBanner.tsx @@ -0,0 +1,27 @@ +import { getTranslations } from "next-intl/server"; + +import { Typography } from "@/components/ui"; + +import styles from "./VideoGuidesBanner.module.scss"; + +export default async function VideoGuidesBanner() { + const t = await getTranslations("AdditionalPurchases.video-guides.banner"); + + return ( +
+
+ + + +
+
+ + {t("title")} + + + {t("description")} + +
+
+ ); +} diff --git a/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.module.scss b/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.module.scss new file mode 100644 index 0000000..e2127ad --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.module.scss @@ -0,0 +1,45 @@ +.container { + position: fixed; + bottom: calc(0dvh + 16px); + left: 50%; + transform: translateX(-50%); + width: 100%; + padding-inline: 24px; + max-width: 560px; + height: fit-content; + + & > .button { + padding-block: 20px; + background: linear-gradient(90deg, #3b82f6 0%, #2563eb 100%); + border-radius: 16px; + box-shadow: + 0px 5px 14px 0px #3b82f666, + 0px 4px 6px 0px #3b82f61a; + + & > .text { + font-size: 19px; + font-weight: 500; + line-height: 125%; + } + } + + & > .skipButton { + padding: 0; + min-height: none; + margin-top: 13px; + + & > .text { + font-size: 16px; + line-height: 24px; + color: #1f2937; + text-decoration: underline; + } + } + + & > .copyright { + font-size: 12px; + line-height: 16px; + color: #9ca3af; + margin-top: 20px; + } +} diff --git a/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.tsx b/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.tsx new file mode 100644 index 0000000..febc548 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesButton/VideoGuidesButton.tsx @@ -0,0 +1,93 @@ +"use client"; + +import { useState } from "react"; +import { useTranslations } from "next-intl"; + +import { Button, Spinner, Typography } from "@/components/ui"; +import { BlurComponent } from "@/components/widgets"; +import { useSingleCheckout } from "@/hooks/payment/useSingleCheckout"; +import { useToast } from "@/providers/toast-provider"; +import { ROUTES } from "@/shared/constants/client-routes"; + +import { useMultiPageNavigationContext } from ".."; +import { useProductSelection } from "../ProductSelectionProvider"; + +import styles from "./VideoGuidesButton.module.scss"; + +export default function VideoGuidesButton() { + const t = useTranslations("AdditionalPurchases.video-guides"); + const { addToast } = useToast(); + const { selectedProduct } = useProductSelection(); + const { navigation } = useMultiPageNavigationContext(); + const [isNavigating, setIsNavigating] = useState(false); + + const { handleSingleCheckout, isLoading } = useSingleCheckout({ + onSuccess: async () => { + setIsNavigating(true); + await navigation.goToNext(); + }, + onError: _error => { + addToast({ + variant: "error", + message: t("payment_error"), + duration: 5000, + }); + }, + returnUrl: new URL( + navigation.getNextPageUrl() || ROUTES.home(), + process.env.NEXT_PUBLIC_APP_URL || "" + ).toString(), + }); + + const handlePurchase = () => { + if (!selectedProduct) { + addToast({ + variant: "error", + message: t("select_product_error"), + duration: 5000, + }); + return; + } + + handleSingleCheckout({ + productId: selectedProduct.id, + key: selectedProduct.key, + }); + }; + + const handleSkipOffer = () => { + navigation.goToNext(); + }; + + const isButtonDisabled = isLoading || isNavigating; + + return ( + + + + + {t("copyright")} + + + ); +} diff --git a/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.module.scss b/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.module.scss new file mode 100644 index 0000000..aa1012a --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.module.scss @@ -0,0 +1,131 @@ +.container.container { + position: relative; + width: 100%; + padding: 11px 18px 12px; + display: flex; + flex-direction: column; + box-shadow: 0px 0px 30px 0px #0000001f; + gap: 4px; + + & > .topBadge { + position: absolute; + top: -15px; + right: 49px; + background: #ff3737; + box-shadow: 0px 1px 11.98px 0px #ff44448c; + border: 2px solid #ffffff4d; + padding: 8px 12px; + border-radius: 9999px; + z-index: 10; + + & > .topBadgeText { + color: #fff; + font-size: 14px; + font-weight: 800; + letter-spacing: 0.5px; + } + } + + & > .content { + display: grid; + grid-template-columns: 40px 1fr 20px; + gap: 12px; + + & > .emojiContainer { + width: 40px; + height: 40px; + border: 1px solid #cedfff; + background: linear-gradient(0deg, #e2ebff, #e2ebff); + border-radius: 16px; + display: flex; + align-items: center; + justify-content: center; + + & > .emoji { + width: 30px; + height: 30px; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + } + } + + & > .textContainer { + display: flex; + flex-direction: column; + align-items: flex-start; + + & > .title { + font-size: 16px; + font-weight: 700; + line-height: 24px; + color: #262626; + } + + & > .subtitle { + font-size: 14px; + font-weight: 500; + line-height: 16px; + color: #737373; + } + } + + & > .checmarkContainer { + width: 20px; + height: 20px; + border: 2px solid #d4d4d4; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-top: auto; + } + } + + & > .footer { + display: flex; + align-items: flex-start; + justify-content: space-between; + + & > .price { + font-size: 14px; + line-height: 20px; + color: #737373; + + & > .currentPrice { + font-size: 14px; + line-height: 20px; + color: #737373; + } + + & > .oldPrice { + font-size: 14px; + line-height: 20px; + color: #9ca3af; + text-decoration: line-through; + } + } + + & > .discount { + display: block; + padding: 6px 8px; + background: #ff6b6b1a; + border-radius: 9999; + font-size: 12px; + font-weight: 700; + color: #ff6b6b; + margin-right: 19px; + } + } + + &.active { + outline: 2px solid #9fbdff; + + & > .content { + & > .checmarkContainer { + background-color: #2866ed; + border: none; + } + } + } +} diff --git a/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.tsx b/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.tsx new file mode 100644 index 0000000..57481c7 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesOffer/VideoGuidesOffer.tsx @@ -0,0 +1,94 @@ +import { useTranslations } from "next-intl"; +import clsx from "clsx"; + +import { Card, Icon, IconName, Typography } from "@/components/ui"; +import { IFunnelPaymentVariant } from "@/entities/session/funnel/types"; +import { getFormattedPrice } from "@/shared/utils/price"; +import { Currency } from "@/types"; + +import styles from "./VideoGuidesOffer.module.scss"; + +interface VideoGuidesOfferProps { + offer: IFunnelPaymentVariant; + isActive: boolean; + isFirstOffer?: boolean; + className?: string; + onClick: () => void; +} + +export default function VideoGuidesOffer(props: VideoGuidesOfferProps) { + const { offer, isActive, isFirstOffer, className, onClick } = props; + + const { key, name, description, emoji, price, oldPrice } = offer; + + const productKey = key.replaceAll(".", "_"); + + const currency = Currency.USD; + + const discount = Math.round( + (((oldPrice || 0) - price) / (oldPrice || 0)) * 100 + ); + + const t = useTranslations("AdditionalPurchases.video-guides"); + + return ( + + {isFirstOffer && ( +
+ {discount}% OFF +
+ )} +
+
+ +
+
+ + {name} + + {description && ( + + {description} + + )} +
+
+ +
+
+
+ + {t("now")}{" "} + + {getFormattedPrice(price, currency)} + + {" "} + + {getFormattedPrice(oldPrice || 0, currency)} + + + {!isFirstOffer && ( + {discount}% OFF + )} +
+
+ ); +} diff --git a/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.module.scss b/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.module.scss new file mode 100644 index 0000000..f1812c0 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.module.scss @@ -0,0 +1,7 @@ +.container { + width: 100%; + display: flex; + flex-direction: column; + gap: 12px; + margin-top: 37px; +} diff --git a/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.tsx b/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.tsx new file mode 100644 index 0000000..8a25b33 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesOffers/VideoGuidesOffers.tsx @@ -0,0 +1,68 @@ +"use client"; + +import { useEffect, useMemo, useState } from "react"; + +import { Skeleton } from "@/components/ui"; +import { IFunnelPaymentVariant } from "@/entities/session/funnel/types"; + +import { useMultiPageNavigationContext, VideoGuidesOffer } from ".."; +import { useProductSelection } from "../ProductSelectionProvider"; + +import styles from "./VideoGuidesOffers.module.scss"; + +// Зашитые проценты скидки: первый товар - 50%, остальные - 45% +const FIRST_PRODUCT_DISCOUNT = 50; +const OTHER_PRODUCTS_DISCOUNT = 45; + +export default function VideoGuidesOffers() { + const { navigation } = useMultiPageNavigationContext(); + const data = navigation.currentItem; + + const offers = useMemo(() => { + // Используем данные с сервера и добавляем oldPrice на основе зашитого процента скидки + const serverOffers = data?.variants ?? []; + return serverOffers.map((offer: IFunnelPaymentVariant, index: number) => { + // Первый товар имеет скидку 50%, остальные - 45% + const discountPercent = + index === 0 ? FIRST_PRODUCT_DISCOUNT : OTHER_PRODUCTS_DISCOUNT; + // Рассчитываем oldPrice: если price это цена со скидкой X%, то oldPrice = price / (1 - X/100) + const oldPrice = Math.round(offer.price / (1 - discountPercent / 100)); + return { + ...offer, + oldPrice, + }; + }); + }, [data]); + const [activeOffer, setActiveOffer] = useState(""); + const { setSelectedProduct } = useProductSelection(); + + useEffect(() => { + if (offers[0]) { + setActiveOffer(offers[0]?.id); + setSelectedProduct(offers[0]); + } + }, [offers, setSelectedProduct]); + + const handleOfferClick = (offer: IFunnelPaymentVariant) => { + setActiveOffer(offer.id); + setSelectedProduct(offer); + }; + + return ( +
+ {offers.map((offer, index) => ( + handleOfferClick(offer)} + /> + ))} +
+ ); +} + +export function VideoGuidesOffersSkeleton() { + return ; +} diff --git a/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.module.scss b/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.module.scss new file mode 100644 index 0000000..e8a36d9 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.module.scss @@ -0,0 +1,23 @@ +.title { + font-size: 25px; + font-weight: 600; + line-height: 28px; + margin-top: 32px; + color: #000000; + max-width: 281px; + margin-inline: auto; +} + +.subtitle { + font-size: 16px; + font-weight: 500; + line-height: 24px; + color: #737373; +} + +.description { + font-size: 12px; + line-height: 16px; + color: #6b7280; + margin-top: 12px; +} diff --git a/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.tsx b/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.tsx new file mode 100644 index 0000000..b3b9046 --- /dev/null +++ b/src/components/domains/additional-purchases/VideoGuidesPage/VideoGuidesPage.tsx @@ -0,0 +1,36 @@ +import { Suspense } from "react"; +import { getTranslations } from "next-intl/server"; + +import { + AdditionalPurchaseBanner, + ProductSelectionProvider, + VideoGuidesButton, + VideoGuidesOffers, + VideoGuidesOffersSkeleton, +} from "@/components/domains/additional-purchases"; +import { Typography } from "@/components/ui"; + +import styles from "./VideoGuidesPage.module.scss"; + +export default async function VideoGuidesPage() { + const t = await getTranslations("AdditionalPurchases.video-guides"); + + return ( + + + + {t("title")} + + + {t("subtitle")} + + }> + + + + {t("description")} + + + + ); +} diff --git a/src/components/domains/additional-purchases/index.ts b/src/components/domains/additional-purchases/index.ts index 360f109..5b0b597 100644 --- a/src/components/domains/additional-purchases/index.ts +++ b/src/components/domains/additional-purchases/index.ts @@ -2,6 +2,7 @@ export { default as AddConsultantButton } from "./AddConsultantButton/AddConsult export { default as AddConsultantPage } from "./AddConsultantPage/AddConsultantPage"; export { default as AddGuidesButton } from "./AddGuidesButton/AddGuidesButton"; export { default as AddGuidesPage } from "./AddGuidesPage/AddGuidesPage"; +export { default as AdditionalPurchaseBanner } from "./AdditionalPurchaseBanner/AdditionalPurchaseBanner"; export { default as Caution } from "./Caution/Caution"; export { default as ConsultationTable } from "./ConsultationTable/ConsultationTable"; export { @@ -14,3 +15,13 @@ export { ProductSelectionProvider, useProductSelection, } from "./ProductSelectionProvider"; +export { default as Progress } from "./Progress/Progress"; +export { default as ProgressLayout } from "./ProgressLayout/ProgressLayout"; +export { default as VideoGuidesBanner } from "./VideoGuidesBanner/VideoGuidesBanner"; +export { default as VideoGuidesButton } from "./VideoGuidesButton/VideoGuidesButton"; +export { default as VideoGuidesOffer } from "./VideoGuidesOffer/VideoGuidesOffer"; +export { + default as VideoGuidesOffers, + VideoGuidesOffersSkeleton, +} from "./VideoGuidesOffers/VideoGuidesOffers"; +export { default as VideoGuidesPage } from "./VideoGuidesPage/VideoGuidesPage"; diff --git a/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.module.scss b/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.module.scss index a57a294..96eb748 100644 --- a/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.module.scss +++ b/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.module.scss @@ -1,12 +1,14 @@ .container { width: 100%; - padding: 0 16px; + padding: 16px; display: flex; flex-direction: column; align-items: flex-end; gap: 16px; position: sticky; - top: 76px; + top: 60px; z-index: 100; - margin-bottom: clamp(16px, 2.5vw, 32px); + padding-bottom: clamp(16px, 2.5vw, 32px); + backdrop-filter: blur(12px); + background: #f8fafc8f; } diff --git a/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.tsx b/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.tsx index 6d99bf9..c27063d 100644 --- a/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.tsx +++ b/src/components/domains/chat/GlobalNewMessagesBanner/GlobalNewMessagesBanner.tsx @@ -17,7 +17,7 @@ export default function GlobalNewMessagesBanner() { const { unreadChats } = useChats(); const { balance } = useBalance(); - // Exclude banner on chat-related, settings (profile), retention funnel, and portraits pages + // Exclude banner on chat-related, settings (profile), retention funnel, portraits, and video guides pages const pathname = usePathname(); const locale = useLocale(); const pathnameWithoutLocale = stripLocale(pathname, locale); @@ -25,7 +25,8 @@ export default function GlobalNewMessagesBanner() { pathnameWithoutLocale.startsWith(ROUTES.chat()) || pathnameWithoutLocale.startsWith(ROUTES.profile()) || pathnameWithoutLocale.startsWith("/retaining") || - pathnameWithoutLocale.startsWith("/portraits"); + pathnameWithoutLocale.startsWith("/portraits") || + pathnameWithoutLocale.startsWith("/video-guides"); const hasHydrated = useAppUiStore(state => state._hasHydrated); const { isVisibleAll } = useAppUiStore(state => state.home.newMessages); @@ -35,6 +36,11 @@ export default function GlobalNewMessagesBanner() { return (
+ {unreadChats.length > 1 && ( setHomeNewMessages({ isVisibleAll: !isVisibleAll })} /> )} -
); } diff --git a/src/components/domains/chat/MessageInput/MessageInput.tsx b/src/components/domains/chat/MessageInput/MessageInput.tsx index 621742f..435e101 100644 --- a/src/components/domains/chat/MessageInput/MessageInput.tsx +++ b/src/components/domains/chat/MessageInput/MessageInput.tsx @@ -82,7 +82,10 @@ export default function MessageInput({ aria-label="Send" className={styles.sendButton} > - +
diff --git a/src/components/domains/chat/ViewAll/ViewAll.module.scss b/src/components/domains/chat/ViewAll/ViewAll.module.scss index 50e2561..456f391 100644 --- a/src/components/domains/chat/ViewAll/ViewAll.module.scss +++ b/src/components/domains/chat/ViewAll/ViewAll.module.scss @@ -5,4 +5,8 @@ width: fit-content; height: fit-content; background-color: transparent; + + & > .text { + color: #6b7280; + } } diff --git a/src/components/domains/chat/ViewAll/ViewAll.tsx b/src/components/domains/chat/ViewAll/ViewAll.tsx index e844bbc..5b890e7 100644 --- a/src/components/domains/chat/ViewAll/ViewAll.tsx +++ b/src/components/domains/chat/ViewAll/ViewAll.tsx @@ -17,7 +17,7 @@ export default function ViewAll({ count, isAll, onClick }: ViewAllProps) { return ( diff --git a/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.module.scss b/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.module.scss index 79be070..9b37602 100644 --- a/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.module.scss +++ b/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.module.scss @@ -8,7 +8,9 @@ display: flex; flex-direction: column; cursor: pointer; - transition: transform 0.2s ease, box-shadow 0.2s ease; + transition: + transform 0.2s ease, + box-shadow 0.2s ease; &:hover { transform: translateY(-4px); @@ -102,14 +104,14 @@ } .statusDone { - color: #16A34A; + color: #16a34a; .statusText { - color: #16A34A; + color: #16a34a; } .checkmark { - color: #16A34A; + color: #16a34a; } } @@ -158,7 +160,9 @@ align-items: center; justify-content: center; cursor: pointer; - transition: background 0.2s ease, transform 0.1s ease; + transition: + background 0.2s ease, + transform 0.1s ease; flex-shrink: 0; svg { diff --git a/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.tsx b/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.tsx index cd7c3cc..ef6a83d 100644 --- a/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.tsx +++ b/src/components/domains/dashboard/cards/PortraitCard/PortraitCard.tsx @@ -12,13 +12,22 @@ import styles from "./PortraitCard.module.scss"; type PortraitCardProps = PartnerPortrait; const HeartCheckIcon = () => ( - + - + - + @@ -35,21 +44,39 @@ const getStatusConfig = (status: PartnerPortrait["status"]) => { }; case "processing": return { - icon: , + icon: ( + + ), text: "Processing...", showCheckmark: false, className: styles.statusProcessing, }; case "queued": return { - icon: , + icon: ( + + ), text: "In Queue", showCheckmark: false, className: styles.statusQueued, }; case "error": return { - icon: , + icon: ( + + ), text: "Error", showCheckmark: false, className: styles.statusError, @@ -66,7 +93,10 @@ export default function PortraitCard({ const router = useRouter(); // Use polling hook to update status in real-time - const { status, imageUrl: polledImageUrl } = useGenerationStatus(_id, initialStatus); + const { status, imageUrl: polledImageUrl } = useGenerationStatus( + _id, + initialStatus + ); // Use polled imageUrl if available, otherwise use initial const imageUrl = polledImageUrl || initialImageUrl; @@ -84,7 +114,7 @@ export default function PortraitCard({
{imageUrl ? ( @@ -98,17 +128,32 @@ export default function PortraitCard({ /> ) : (
- +
)}
- + {title} - + Finding the One Guide
@@ -120,13 +165,21 @@ export default function PortraitCard({ {statusConfig.text} {statusConfig.showCheckmark && ( - + )}
{status === "done" && ( )} diff --git a/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.module.scss b/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.module.scss new file mode 100644 index 0000000..e5ee6e0 --- /dev/null +++ b/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.module.scss @@ -0,0 +1,273 @@ +.container.container { + display: flex; + min-width: 260px; + min-height: 280px; + height: 100%; + flex-direction: column; + align-items: flex-start; + border-radius: 24px; + border: 0 solid #e5e7eb; + background: rgba(0, 0, 0, 0); + box-shadow: + 0 4px 6px 0 rgba(0, 0, 0, 0.1), + 0 10px 15px 0 rgba(0, 0, 0, 0.1); + overflow: hidden; + padding: 0; + transition: + transform 0.2s ease, + box-shadow 0.2s ease; + position: relative; + + // Hover effect only for purchased cards (wrapped in Link) + :global(a):hover & { + transform: translateY(-4px); + box-shadow: + 0 6px 10px 0 rgba(0, 0, 0, 0.12), + 0 12px 18px 0 rgba(0, 0, 0, 0.12); + } + + &.processing { + pointer-events: none; + } +} + +.processingOverlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 255, 0.95); + z-index: 10; +} + +// Image section +.image { + display: flex; + min-height: 160px; + padding: 16px; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; + align-self: stretch; + border: 0 solid #e5e7eb; + position: relative; + overflow: hidden; + + &::before { + content: ""; + position: absolute; + inset: 0; + background: lightgray 50% / cover no-repeat; + z-index: 0; + } + + .imageContent { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; + pointer-events: none; + z-index: 0; + } + + .playIcon { + position: relative; + z-index: 1; + width: 64px; + height: 65px; + + svg { + width: 64px; + height: 65px; + filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.25)); + } + } +} + +// Content section +.content { + display: flex; + padding: 16px; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + gap: 24px; + align-self: stretch; + background: #fff; + flex: 1; + + .purchased & { + gap: 6px; + } +} + +// Top section +.top { + display: flex; + align-items: flex-start; + gap: 14px; + align-self: stretch; + + .text { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 3px; + flex: 1 0 0; + } + + .arrowButton { + display: flex; + width: 40px; + height: 40px; + padding: 12px 0; + justify-content: center; + align-items: center; + border-radius: 9999px; + border: 0 solid #e5e7eb; + background: #f5f5f7; + cursor: pointer; + transition: opacity 0.2s ease; + + svg { + width: 8px; + height: 14px; + flex-shrink: 0; + } + + &:hover { + opacity: 0.8; + } + } +} + +.title { + align-self: stretch; + color: #1d1d1f; + font-family: Inter, sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 500; + line-height: 28px; + text-align: left; +} + +.subtitle { + align-self: stretch; + color: #6b7280; + font-family: Inter, sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 20px; + text-align: left; +} + +// Bottom section +.bottom { + display: flex; + flex-direction: column; + justify-content: flex-end; + align-items: flex-end; + gap: 8px; + align-self: stretch; +} + +.bottomText { + display: flex; + height: 24px; + justify-content: space-between; + align-items: center; + align-self: stretch; +} + +.duration { + display: flex; + width: 49px; + flex-direction: column; + justify-content: center; + align-self: stretch; + color: #6b7280; + font-family: Inter, sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 20px; +} + +.durationPurchased { + display: flex; + justify-content: flex-end; + align-self: stretch; + color: #6b7280; + font-family: Inter, sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 20px; +} + +.discountBadge { + display: flex; + padding: 6px 10px; + justify-content: center; + align-items: center; + gap: 10px; + align-self: stretch; + border-radius: 9999px; + border: 0 solid #e5e7eb; + background: rgba(255, 107, 107, 0.1); +} + +.discountText { + color: #ff6b6b; + text-align: center; + font-family: Inter, sans-serif; + font-size: 12px; + font-style: normal; + font-weight: 700; + line-height: normal; + + .oldPrice { + color: #8b8b8b; + font-family: Inter, sans-serif; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: normal; + text-decoration-line: line-through; + } +} + +.buyButton.buyButton { + display: flex; + padding: 8px 10px; + justify-content: center; + align-items: center; + gap: 10px; + border-radius: 12px; + border: 0 solid #e5e7eb; + background: #2563eb; + cursor: pointer; + transition: opacity 0.2s ease; + width: auto; + + color: #fff; + text-align: center; + font-family: Inter, sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: normal; + + &:hover { + opacity: 0.9; + } +} diff --git a/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.tsx b/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.tsx new file mode 100644 index 0000000..8ca3bd9 --- /dev/null +++ b/src/components/domains/dashboard/cards/VideoGuideCard/VideoGuideCard.tsx @@ -0,0 +1,207 @@ +"use client"; + +import Image from "next/image"; +import { useTranslations } from "next-intl"; +import clsx from "clsx"; + +import { Button, Card, Spinner, Typography } from "@/components/ui"; +import { getFormattedPrice } from "@/shared/utils/price"; +import { Currency } from "@/types"; + +import styles from "./VideoGuideCard.module.scss"; + +interface VideoGuideCardProps { + name: string; + description: string; + imageUrl: string; + duration: string; + price: number; + oldPrice: number; + discount: number; + isPurchased: boolean; + isCheckoutLoading?: boolean; + isProcessingPurchase?: boolean; + onPurchaseClick?: () => void; + className?: string; +} + +export default function VideoGuideCard(props: VideoGuideCardProps) { + const { + name, + description, + imageUrl, + duration, + price, + oldPrice, + discount, + isPurchased, + isCheckoutLoading, + isProcessingPurchase, + onPurchaseClick, + className, + } = props; + + const tCommon = useTranslations("Dashboard.videoGuides"); + + const currency = Currency.USD; + + // Если идет обработка покупки - показываем только лоадер на всей карточке + if (isProcessingPurchase) { + return ( + +
+ +
+
+ ); + } + + return ( + + {/* Image with Play Icon */} +
+ {name} +
+ + + + + + + + + + + + + + + + + +
+
+ + {/* Content */} +
+ {/* Top Section */} +
+
+ + {name} + + + {description} + +
+ {isPurchased && ( + + )} +
+ + {/* Bottom Section */} +
+ {!isPurchased ? ( + <> +
+ + {duration} + +
+ + {discount}% OFF{" "} + + {getFormattedPrice(oldPrice, currency)} + + +
+
+ + + ) : ( + + {duration} + + )} +
+
+
+ ); +} diff --git a/src/components/domains/dashboard/cards/VideoGuideCard/index.ts b/src/components/domains/dashboard/cards/VideoGuideCard/index.ts new file mode 100644 index 0000000..e1d5d96 --- /dev/null +++ b/src/components/domains/dashboard/cards/VideoGuideCard/index.ts @@ -0,0 +1 @@ +export { default as VideoGuideCard } from "./VideoGuideCard"; diff --git a/src/components/domains/dashboard/cards/index.ts b/src/components/domains/dashboard/cards/index.ts index 65540f0..1a27805 100644 --- a/src/components/domains/dashboard/cards/index.ts +++ b/src/components/domains/dashboard/cards/index.ts @@ -3,3 +3,4 @@ export { default as CompatibilityCard } from "./CompatibilityCard/CompatibilityC export { default as MeditationCard } from "./MeditationCard/MeditationCard"; export { default as PalmCard } from "./PalmCard/PalmCard"; export { default as PortraitCard } from "./PortraitCard/PortraitCard"; +export { default as VideoGuideCard } from "./VideoGuideCard/VideoGuideCard"; diff --git a/src/components/domains/dashboard/sections/AdvisersSection/AdvisersSection.tsx b/src/components/domains/dashboard/sections/AdvisersSection/AdvisersSection.tsx index addacd3..b083fa3 100644 --- a/src/components/domains/dashboard/sections/AdvisersSection/AdvisersSection.tsx +++ b/src/components/domains/dashboard/sections/AdvisersSection/AdvisersSection.tsx @@ -31,7 +31,12 @@ export default function AdvisersSection({ }: AdvisersSectionProps) { const assistants = use(promiseAssistants); const chats = use(promiseChats); - const columns = getOptimalColumns(assistants?.length || 0); + + if (!assistants || assistants.length === 0) { + return null; + } + + const columns = getOptimalColumns(assistants.length); return (
diff --git a/src/components/domains/dashboard/sections/CompatibilitySection/CompatibilitySection.tsx b/src/components/domains/dashboard/sections/CompatibilitySection/CompatibilitySection.tsx index b0455c8..5289ff1 100644 --- a/src/components/domains/dashboard/sections/CompatibilitySection/CompatibilitySection.tsx +++ b/src/components/domains/dashboard/sections/CompatibilitySection/CompatibilitySection.tsx @@ -22,7 +22,12 @@ export default function CompatibilitySection({ gridDisplayMode = "horizontal", }: CompatibilitySectionProps) { const compatibilities = use(promise); - const columns = Math.ceil(compatibilities?.length / 2); + + if (!compatibilities || compatibilities.length === 0) { + return null; + } + + const columns = Math.ceil(compatibilities.length / 2); return (
diff --git a/src/components/domains/dashboard/sections/MeditationSection/MeditationSection.tsx b/src/components/domains/dashboard/sections/MeditationSection/MeditationSection.tsx index 45d9638..8e3de49 100644 --- a/src/components/domains/dashboard/sections/MeditationSection/MeditationSection.tsx +++ b/src/components/domains/dashboard/sections/MeditationSection/MeditationSection.tsx @@ -20,7 +20,12 @@ export default function MeditationSection({ gridDisplayMode = "horizontal", }: MeditationSectionProps) { const meditations = use(promise); - const columns = meditations?.length; + + if (!meditations || meditations.length === 0) { + return null; + } + + const columns = meditations.length; return (
diff --git a/src/components/domains/dashboard/sections/PalmSection/PalmSection.tsx b/src/components/domains/dashboard/sections/PalmSection/PalmSection.tsx index bffcc40..d6fa71a 100644 --- a/src/components/domains/dashboard/sections/PalmSection/PalmSection.tsx +++ b/src/components/domains/dashboard/sections/PalmSection/PalmSection.tsx @@ -15,7 +15,12 @@ export default function PalmSection({ promise: Promise; }) { const palms = use(promise); - const columns = palms?.length; + + if (!palms || palms.length === 0) { + return null; + } + + const columns = palms.length; return (
diff --git a/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.module.scss b/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.module.scss new file mode 100644 index 0000000..4bcbd0d --- /dev/null +++ b/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.module.scss @@ -0,0 +1,21 @@ +.sectionContent.sectionContent { + overflow-x: scroll; + -webkit-overflow-scrolling: touch; + width: calc(100% + 32px); + padding: 20px 16px 24px 16px; + padding-right: 0; + margin: -20px -16px -24px -16px; +} + +.grid { + padding-right: 16px; + grid-auto-rows: 1fr; + + a, + > div { + text-decoration: none; + color: inherit; + display: block; + height: 100%; + } +} diff --git a/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.tsx b/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.tsx new file mode 100644 index 0000000..adab144 --- /dev/null +++ b/src/components/domains/dashboard/sections/VideoGuidesSection/VideoGuidesSection.tsx @@ -0,0 +1,97 @@ +"use client"; + +import { useMemo } from "react"; +import Link from "next/link"; + +import { Grid, Section } from "@/components/ui"; +import { VideoGuide } from "@/entities/dashboard/types"; +import { useVideoGuidePurchase } from "@/hooks/video-guides/useVideoGuidePurchase"; + +import { VideoGuideCard } from "../../cards"; + +import styles from "./VideoGuidesSection.module.scss"; + +interface VideoGuidesSectionProps { + videoGuides: VideoGuide[]; +} + +function VideoGuideCardWrapper({ videoGuide }: { videoGuide: VideoGuide }) { + const { handlePurchase, isCheckoutLoading, isProcessingPurchase } = + useVideoGuidePurchase({ + videoGuideId: videoGuide.id, + productId: videoGuide.productId, // Используем productId из payment-service + productKey: videoGuide.key, + }); + + // Для купленных видео - ссылка на страницу просмотра + const href = videoGuide.isPurchased + ? `/video-guides/${videoGuide.id}` + : "#"; + + const isClickable = videoGuide.isPurchased; + + const cardElement = ( + + ); + + if (isClickable) { + return ( + + {cardElement} + + ); + } + + return
{cardElement}
; +} + +export default function VideoGuidesSection({ + videoGuides, +}: VideoGuidesSectionProps) { + // Сортируем видео: купленные в начало + const sortedVideoGuides = useMemo(() => { + if (!videoGuides || videoGuides.length === 0) { + return []; + } + + return [...videoGuides].sort((a, b) => { + // Купленные видео идут первыми + if (a.isPurchased && !b.isPurchased) return -1; + if (!a.isPurchased && b.isPurchased) return 1; + + // Сохраняем исходный порядок для видео с одинаковым статусом покупки + return 0; + }); + }, [videoGuides]); + + if (sortedVideoGuides.length === 0) { + return null; + } + + const columns = sortedVideoGuides.length; + + return ( +
+ + {sortedVideoGuides.map(videoGuide => ( + + ))} + +
+ ); +} diff --git a/src/components/domains/dashboard/sections/VideoGuidesSection/index.ts b/src/components/domains/dashboard/sections/VideoGuidesSection/index.ts new file mode 100644 index 0000000..444247a --- /dev/null +++ b/src/components/domains/dashboard/sections/VideoGuidesSection/index.ts @@ -0,0 +1 @@ +export { default as VideoGuidesSection } from "./VideoGuidesSection"; diff --git a/src/components/domains/dashboard/sections/index.ts b/src/components/domains/dashboard/sections/index.ts index 989e957..bc600d1 100644 --- a/src/components/domains/dashboard/sections/index.ts +++ b/src/components/domains/dashboard/sections/index.ts @@ -20,3 +20,4 @@ export { PalmSectionSkeleton, } from "./PalmSection/PalmSection"; export { default as PortraitsSection } from "./PortraitsSection/PortraitsSection"; +export { default as VideoGuidesSection } from "./VideoGuidesSection/VideoGuidesSection"; diff --git a/src/components/domains/email-marketing/soulmate/v1/DetailedPortraitCard/DetailedPortraitCard.tsx b/src/components/domains/email-marketing/soulmate/v1/DetailedPortraitCard/DetailedPortraitCard.tsx index 1fc6854..325ff38 100644 --- a/src/components/domains/email-marketing/soulmate/v1/DetailedPortraitCard/DetailedPortraitCard.tsx +++ b/src/components/domains/email-marketing/soulmate/v1/DetailedPortraitCard/DetailedPortraitCard.tsx @@ -12,9 +12,7 @@ import styles from "./DetailedPortraitCard.module.scss"; export default function DetailedPortraitCard() { const t = useTranslations( - translatePathEmailMarketingSoulmateV1( - "Landing.what-get.detailed-portrait" - ) + translatePathEmailMarketingSoulmateV1("Landing.what-get.detailed-portrait") ); const { user } = useUser(); const gender = user?.profile?.gender; diff --git a/src/components/domains/email-marketing/soulmate/v1/GuaranteedSecurityPayments/GuaranteedSecurityPayments.tsx b/src/components/domains/email-marketing/soulmate/v1/GuaranteedSecurityPayments/GuaranteedSecurityPayments.tsx index 5c084e2..d1c117b 100644 --- a/src/components/domains/email-marketing/soulmate/v1/GuaranteedSecurityPayments/GuaranteedSecurityPayments.tsx +++ b/src/components/domains/email-marketing/soulmate/v1/GuaranteedSecurityPayments/GuaranteedSecurityPayments.tsx @@ -8,9 +8,7 @@ import { translatePathEmailMarketingSoulmateV1 } from "@/shared/constants/transl import styles from "./GuaranteedSecurityPayments.module.scss"; export default function GuaranteedSecurityPayments() { - const t = useTranslations( - translatePathEmailMarketingSoulmateV1("Landing") - ); + const t = useTranslations(translatePathEmailMarketingSoulmateV1("Landing")); return (
; diff --git a/src/components/domains/email-marketing/soulmate/v1/LandingButtonWrapper/LandingButtonWrapper.tsx b/src/components/domains/email-marketing/soulmate/v1/LandingButtonWrapper/LandingButtonWrapper.tsx index 33ef6ef..d9353a2 100644 --- a/src/components/domains/email-marketing/soulmate/v1/LandingButtonWrapper/LandingButtonWrapper.tsx +++ b/src/components/domains/email-marketing/soulmate/v1/LandingButtonWrapper/LandingButtonWrapper.tsx @@ -12,9 +12,7 @@ import styles from "./LandingButtonWrapper.module.scss"; export default function LandingButtonWrapper() { const router = useRouter(); - const t = useTranslations( - translatePathEmailMarketingSoulmateV1("Landing") - ); + const t = useTranslations(translatePathEmailMarketingSoulmateV1("Landing")); const handleContinue = () => { router.push(ROUTES.emailMarketingSoulmateV1SpecialOffer()); diff --git a/src/components/domains/email-marketing/soulmate/v1/Payments/Payments.tsx b/src/components/domains/email-marketing/soulmate/v1/Payments/Payments.tsx index 1737f94..8b7384a 100644 --- a/src/components/domains/email-marketing/soulmate/v1/Payments/Payments.tsx +++ b/src/components/domains/email-marketing/soulmate/v1/Payments/Payments.tsx @@ -1,8 +1,6 @@ import Image from "next/image"; -import { - emailMarketingCompV2Images, -} from "@/shared/constants/images"; +import { emailMarketingCompV2Images } from "@/shared/constants/images"; import styles from "./Payments.module.scss"; diff --git a/src/components/domains/email-marketing/soulmate/v1/TrialIntervalOffer/TrialIntervalOffer.tsx b/src/components/domains/email-marketing/soulmate/v1/TrialIntervalOffer/TrialIntervalOffer.tsx index f07aa6f..f533e28 100644 --- a/src/components/domains/email-marketing/soulmate/v1/TrialIntervalOffer/TrialIntervalOffer.tsx +++ b/src/components/domains/email-marketing/soulmate/v1/TrialIntervalOffer/TrialIntervalOffer.tsx @@ -19,9 +19,7 @@ export default async function TrialIntervalOffer({ newTrialInterval, }: ITrialIntervalOfferProps) { const t = await getTranslations( - translatePathEmailMarketingSoulmateV1( - "Landing.special-offer.trial-offer" - ) + translatePathEmailMarketingSoulmateV1("Landing.special-offer.trial-offer") ); return ( diff --git a/src/components/domains/portraits/PortraitView/PortraitView.module.scss b/src/components/domains/portraits/PortraitView/PortraitView.module.scss index 677f344..e36f756 100644 --- a/src/components/domains/portraits/PortraitView/PortraitView.module.scss +++ b/src/components/domains/portraits/PortraitView/PortraitView.module.scss @@ -7,6 +7,8 @@ display: flex; flex-direction: column; overflow: hidden; + z-index: 1000; + background: var(--background); } .header { diff --git a/src/components/domains/portraits/PortraitView/PortraitView.tsx b/src/components/domains/portraits/PortraitView/PortraitView.tsx index 0d1e671..c69d401 100644 --- a/src/components/domains/portraits/PortraitView/PortraitView.tsx +++ b/src/components/domains/portraits/PortraitView/PortraitView.tsx @@ -14,7 +14,11 @@ interface PortraitViewProps { result?: string | null; } -export default function PortraitView({ title, imageUrl, result }: PortraitViewProps) { +export default function PortraitView({ + title, + imageUrl, + result, +}: PortraitViewProps) { const router = useRouter(); const handleDownload = async () => { @@ -42,7 +46,12 @@ export default function PortraitView({ title, imageUrl, result }: PortraitViewPr - + {title}
@@ -67,28 +76,87 @@ export default function PortraitView({ title, imageUrl, result }: PortraitViewPr onClick={handleDownload} aria-label="Download portrait" > - + - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/components/domains/video-guides/VideoGuideView/VideoGuideView.module.scss b/src/components/domains/video-guides/VideoGuideView/VideoGuideView.module.scss new file mode 100644 index 0000000..0fac90e --- /dev/null +++ b/src/components/domains/video-guides/VideoGuideView/VideoGuideView.module.scss @@ -0,0 +1,99 @@ +.container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: column; + overflow: hidden; + z-index: 1000; + background: var(--background); +} + +.header { + display: flex; + align-items: center; + gap: 12px; + padding: 16px; + background: var(--background); + position: relative; + flex-shrink: 0; +} + +.backButton { + width: 40px; + height: 40px; + border-radius: 50%; + background: #f5f5f5; + display: flex; + align-items: center; + justify-content: center; + border: none; + cursor: pointer; + flex-shrink: 0; + transition: background 0.2s ease; + + &:hover { + background: #e0e0e0; + } + + &:active { + background: #d0d0d0; + } +} + +.title { + flex: 1; + text-align: center; + padding-right: 40px; // Compensate for back button width +} + +.contentWrapper { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 24px; + overflow-y: auto; + gap: 32px; +} + +.videoContainer { + position: relative; + width: 100%; + max-width: 800px; + aspect-ratio: 16 / 9; + border-radius: 24px; + overflow: hidden; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + flex-shrink: 0; /* Prevent video from shrinking */ +} + +.videoInner { + position: relative; + width: 100%; + height: 100%; +} + +.video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: none; +} + +.descriptionWrapper { + width: 100%; + max-width: 800px; + padding: 0; + position: relative; /* Ensure proper positioning context */ + flex-shrink: 0; /* Prevent shrinking */ +} + +.description { + color: #646464; + line-height: 1.6; +} diff --git a/src/components/domains/video-guides/VideoGuideView/VideoGuideView.tsx b/src/components/domains/video-guides/VideoGuideView/VideoGuideView.tsx new file mode 100644 index 0000000..a4d436a --- /dev/null +++ b/src/components/domains/video-guides/VideoGuideView/VideoGuideView.tsx @@ -0,0 +1,99 @@ +"use client"; + +import { useEffect, useState } from "react"; +import dynamic from "next/dynamic"; +import { useRouter } from "next/navigation"; + +import { Icon, IconName, MarkdownText, Typography } from "@/components/ui"; + +import styles from "./VideoGuideView.module.scss"; + +const VideoPlayer = dynamic(() => import("../VideoPlayer"), { ssr: false }); + +interface VideoGuideViewProps { + id: string; + name: string; + description: string; + videoLinkHLS: string; + videoLinkDASH: string; + contentUrl?: string; +} + +export default function VideoGuideView({ + name, + description, + videoLinkHLS, + videoLinkDASH, + contentUrl, +}: VideoGuideViewProps) { + const router = useRouter(); + const [markdownContent, setMarkdownContent] = useState(null); + const [isLoadingMarkdown, setIsLoadingMarkdown] = useState(false); + + // Load markdown content if contentUrl is provided + useEffect(() => { + if (!contentUrl) return; + + const loadMarkdown = async () => { + setIsLoadingMarkdown(true); + try { + const response = await fetch(contentUrl); + if (response.ok) { + const text = await response.text(); + setMarkdownContent(text); + } + // Silently fail and show description as fallback + } catch { + // Silently fail and show description as fallback + } finally { + setIsLoadingMarkdown(false); + } + }; + + loadMarkdown(); + }, [contentUrl]); + + return ( +
+ {/* Header with back button and title */} +
+ + + {name} + +
+ + {/* Video and Description */} +
+ {/* Video Player */} +
+ +
+ + {/* Description or Markdown Content */} + {(isLoadingMarkdown || markdownContent || description) && ( +
+ {isLoadingMarkdown ? ( + + Loading content... + + ) : markdownContent ? ( + + ) : description ? ( + + {description} + + ) : null} +
+ )} +
+
+ ); +} diff --git a/src/components/domains/video-guides/VideoPlayer/VideoPlayer.module.scss b/src/components/domains/video-guides/VideoPlayer/VideoPlayer.module.scss new file mode 100644 index 0000000..8e63dc3 --- /dev/null +++ b/src/components/domains/video-guides/VideoPlayer/VideoPlayer.module.scss @@ -0,0 +1,98 @@ +.playerWrapper { + position: relative; + width: 100%; + height: 100%; + background: #000; + border-radius: 24px; + overflow: hidden; +} + +.video { + width: 100%; + height: auto; + display: block; + background: #000; +} + +.loading { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #000; + z-index: 1; +} + +.spinner { + width: 48px; + height: 48px; + border: 4px solid rgba(255, 255, 255, 0.1); + border-top-color: #fff; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.error { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: #000; + color: #fff; + padding: 24px; + text-align: center; + z-index: 1; + + p { + margin: 0 0 8px; + font-size: 16px; + font-weight: 600; + } +} + +.errorSubtext { + font-size: 14px !important; + font-weight: 400 !important; + color: rgba(255, 255, 255, 0.6) !important; +} + +.playButton { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 2; + background: none; + border: none; + cursor: pointer; + padding: 0; + transition: all 0.3s ease; + + &:hover { + transform: translate(-50%, -50%) scale(1.1); + opacity: 0.9; + } + + &:active { + transform: translate(-50%, -50%) scale(0.95); + } + + svg { + filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3)); + } +} diff --git a/src/components/domains/video-guides/VideoPlayer/VideoPlayer.tsx b/src/components/domains/video-guides/VideoPlayer/VideoPlayer.tsx new file mode 100644 index 0000000..aef10c1 --- /dev/null +++ b/src/components/domains/video-guides/VideoPlayer/VideoPlayer.tsx @@ -0,0 +1,253 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; + +import styles from "./VideoPlayer.module.scss"; + +interface VideoPlayerProps { + mpd: string; + m3u8: string; + poster?: string; + autoPlay?: boolean; +} + +export default function VideoPlayer({ + mpd, + m3u8, + poster, + autoPlay = false, +}: VideoPlayerProps) { + const videoRef = useRef(null); + const [isLoading, setIsLoading] = useState(true); + const [hasError, setHasError] = useState(false); + const [showPlayButton, setShowPlayButton] = useState(true); + + useEffect(() => { + const video = videoRef.current; + if (!video) return; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let shakaPlayer: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let hls: any; + let cleanup = false; + + const initPlayer = async () => { + try { + setIsLoading(true); + setHasError(false); + + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Initializing player..."); + // eslint-disable-next-line no-console + console.log("[VideoPlayer] DASH URL:", mpd); + // eslint-disable-next-line no-console + console.log("[VideoPlayer] HLS URL:", m3u8); + + // iOS/Safari - нативный HLS + if (video.canPlayType("application/vnd.apple.mpegurl")) { + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Using native HLS support"); + video.src = m3u8; + setIsLoading(false); + return; + } + + // DASH через Shaka (предпочтительно для Android/Desktop) + try { + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Trying Shaka Player for DASH..."); + const shaka = await import("shaka-player/dist/shaka-player.compiled.js"); + + if (cleanup) return; + + shakaPlayer = new shaka.default.Player(video); + shakaPlayer.configure({ + streaming: { + bufferingGoal: 20, + rebufferingGoal: 2, + lowLatencyMode: false, + }, + manifest: { + dash: { + ignoreMinBufferTime: true, + }, + }, + }); + + await shakaPlayer.load(mpd); + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Shaka Player loaded successfully"); + setIsLoading(false); + return; + } catch (e) { + // eslint-disable-next-line no-console + console.warn("[VideoPlayer] Shaka failed, fallback to HLS.js", e); + } + + // Запасной вариант - HLS.js + try { + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Trying HLS.js..."); + const Hls = (await import("hls.js")).default; + + if (cleanup) return; + + if (Hls.isSupported()) { + hls = new Hls({ + maxBufferLength: 30, + debug: false, + }); + + hls.loadSource(m3u8); + hls.attachMedia(video); + + hls.on(Hls.Events.MANIFEST_PARSED, () => { + // eslint-disable-next-line no-console + console.log("[VideoPlayer] HLS.js manifest parsed"); + setIsLoading(false); + }); + + hls.on( + Hls.Events.ERROR, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (_event: any, data: any) => { + // eslint-disable-next-line no-console + console.error("[VideoPlayer] HLS.js error:", data); + if (data.fatal) { + setHasError(true); + setIsLoading(false); + } + }, + ); + + return; + } + } catch (e) { + // eslint-disable-next-line no-console + console.warn("[VideoPlayer] HLS.js failed", e); + } + + // Совсем запасной - прямой src + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Using direct video src"); + video.src = m3u8; + setIsLoading(false); + } catch (error) { + // eslint-disable-next-line no-console + console.error("[VideoPlayer] Fatal error:", error); + setHasError(true); + setIsLoading(false); + } + }; + + initPlayer(); + + return () => { + cleanup = true; + try { + shakaPlayer?.destroy(); + } catch { + // Ignore cleanup errors + } + try { + hls?.destroy(); + } catch { + // Ignore cleanup errors + } + }; + }, [mpd, m3u8, autoPlay]); + + const handlePlay = async () => { + const video = videoRef.current; + if (!video) return; + + try { + // Убеждаемся что звук включен + video.muted = false; + await video.play(); + setShowPlayButton(false); + // eslint-disable-next-line no-console + console.log("[VideoPlayer] Started playing with sound"); + } catch (error) { + // eslint-disable-next-line no-console + console.error("[VideoPlayer] Play failed:", error); + } + }; + + const handleVideoPlay = () => { + setShowPlayButton(false); + }; + + const handleVideoPause = () => { + // Пауза через нативные контролы + }; + + return ( +
+ {isLoading && !hasError && ( +
+
+
+ )} + + {hasError && ( +
+

Unable to load video

+

+ Please check your connection and try again +

+
+ )} + + {!isLoading && !hasError && showPlayButton && ( + + )} + +
+ ); +} diff --git a/src/components/domains/video-guides/VideoPlayer/index.ts b/src/components/domains/video-guides/VideoPlayer/index.ts new file mode 100644 index 0000000..c269b57 --- /dev/null +++ b/src/components/domains/video-guides/VideoPlayer/index.ts @@ -0,0 +1 @@ +export { default } from "./VideoPlayer"; diff --git a/src/components/domains/video-guides/index.ts b/src/components/domains/video-guides/index.ts new file mode 100644 index 0000000..b5887f5 --- /dev/null +++ b/src/components/domains/video-guides/index.ts @@ -0,0 +1 @@ +export { default as VideoGuideView } from "./VideoGuideView/VideoGuideView"; diff --git a/src/components/layout/Header/Header.tsx b/src/components/layout/Header/Header.tsx index 4cf60a2..4931637 100644 --- a/src/components/layout/Header/Header.tsx +++ b/src/components/layout/Header/Header.tsx @@ -35,10 +35,11 @@ export default function Header({ const locale = useLocale(); const pathnameWithoutLocale = stripLocale(pathname, locale); - // Hide header on portraits page + // Hide header on portraits and video-guides pages const isPortraitsPage = pathnameWithoutLocale.startsWith("/portraits"); + const isVideoGuidesPage = pathnameWithoutLocale.startsWith("/video-guides"); - if (isPortraitsPage) return null; + if (isPortraitsPage || isVideoGuidesPage) return null; const handleBack = () => { router.back(); diff --git a/src/components/layout/NavigationBar/NavigationBar.module.scss b/src/components/layout/NavigationBar/NavigationBar.module.scss index 2ac3fc2..6841564 100644 --- a/src/components/layout/NavigationBar/NavigationBar.module.scss +++ b/src/components/layout/NavigationBar/NavigationBar.module.scss @@ -6,13 +6,15 @@ right: 0; width: 100vw; // Height: tab bar height + moderate overlap above tab bar - height: calc(14px + 60px + 20px); // bottom offset + tab bar height + overlap above + height: calc( + 14px + 60px + 20px + ); // bottom offset + tab bar height + overlap above z-index: 9994; // Just below the tab bar backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); background: rgba(255, 255, 255, 0.7); pointer-events: none; // Don't block interactions - + // Fallback for browsers that don't support backdrop-filter @supports not (backdrop-filter: blur(1px)) { background: rgba(255, 255, 255, 0.85); diff --git a/src/components/layout/NavigationBar/NavigationBar.tsx b/src/components/layout/NavigationBar/NavigationBar.tsx index 77711bf..ae1cdf9 100644 --- a/src/components/layout/NavigationBar/NavigationBar.tsx +++ b/src/components/layout/NavigationBar/NavigationBar.tsx @@ -24,11 +24,12 @@ export default function NavigationBar() { const pathnameWithoutLocale = stripLocale(pathname, locale); const { totalUnreadCount } = useChats(); - // Hide navigation bar on retaining funnel and portraits pages + // Hide navigation bar on retaining funnel, portraits pages, and video guides pages const isRetainingFunnel = pathnameWithoutLocale.startsWith("/retaining"); const isPortraitsPage = pathnameWithoutLocale.startsWith("/portraits"); + const isVideoGuidesPage = pathnameWithoutLocale.startsWith("/video-guides"); - if (isRetainingFunnel || isPortraitsPage) return null; + if (isRetainingFunnel || isPortraitsPage || isVideoGuidesPage) return null; return ( <> diff --git a/src/components/ui/Icon/icons/AlertCircle.tsx b/src/components/ui/Icon/icons/AlertCircle.tsx index e96fa1b..eccda6b 100644 --- a/src/components/ui/Icon/icons/AlertCircle.tsx +++ b/src/components/ui/Icon/icons/AlertCircle.tsx @@ -11,25 +11,9 @@ export default function AlertCircleIcon(props: SVGProps) { xmlns="http://www.w3.org/2000/svg" {...props} > - - - + + + ); } diff --git a/src/components/ui/MarkdownText/MarkdownText.module.scss b/src/components/ui/MarkdownText/MarkdownText.module.scss index 277c033..e43199e 100644 --- a/src/components/ui/MarkdownText/MarkdownText.module.scss +++ b/src/components/ui/MarkdownText/MarkdownText.module.scss @@ -79,6 +79,60 @@ font-style: italic; } + // Code + .codeBlock { + background-color: #f5f5f5; + border-radius: 6px; + padding: 12px 16px; + margin: 8px 0; + overflow-x: auto; + border: 1px solid #e0e0e0; + } + + .code { + font-family: 'Courier New', Courier, monospace; + font-size: 14px; + line-height: 1.5; + color: #333; + } + + .inlineCode { + background-color: #f5f5f5; + padding: 2px 6px; + border-radius: 3px; + font-family: 'Courier New', Courier, monospace; + font-size: 14px; + color: #d63384; + border: 1px solid #e0e0e0; + } + + // Blockquote + .blockquote { + border-left: 4px solid #646464; + padding-left: 16px; + margin: 8px 0; + color: #646464; + font-style: italic; + } + + // Horizontal rule + .hr { + border: none; + border-top: 1px solid #e0e0e0; + margin: 16px 0; + } + + // Links + .link { + color: #0066cc; + text-decoration: underline; + transition: color 0.2s; + + &:hover { + color: #0052a3; + } + } + // Line breaks br { display: block; diff --git a/src/components/ui/MarkdownText/MarkdownText.tsx b/src/components/ui/MarkdownText/MarkdownText.tsx index c893a2e..882f40c 100644 --- a/src/components/ui/MarkdownText/MarkdownText.tsx +++ b/src/components/ui/MarkdownText/MarkdownText.tsx @@ -1,6 +1,7 @@ "use client"; -import React from "react"; +import ReactMarkdown, { type Components } from "react-markdown"; +import remarkGfm from "remark-gfm"; import styles from "./MarkdownText.module.scss"; @@ -13,114 +14,37 @@ export default function MarkdownText({ content, className, }: MarkdownTextProps) { - // Simple markdown parser for basic formatting - const parseMarkdown = (text: string): React.ReactNode[] => { - const lines = text.split("\n"); - const elements: React.ReactNode[] = []; - let key = 0; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - - // Skip empty lines - if (line.trim() === "") { - elements.push(
); - continue; - } - - // Headers (# ## ###) - const headerMatch = line.match(/^(#{1,6})\s+(.+)$/); - if (headerMatch) { - const level = headerMatch[1].length; - const text = headerMatch[2]; - const HeaderTag = `h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; - elements.push( - React.createElement( - HeaderTag, - { key: `h${level}-${key++}`, className: styles[`h${level}`] }, - parseInlineMarkdown(text) - ) - ); - continue; - } - - // Unordered lists (- or *) - const listMatch = line.match(/^[\*\-]\s+(.+)$/); - if (listMatch) { - elements.push( -
  • - {parseInlineMarkdown(listMatch[1])} -
  • - ); - continue; - } - - // Ordered lists (1. 2. etc) - const orderedListMatch = line.match(/^\d+\.\s+(.+)$/); - if (orderedListMatch) { - elements.push( -
  • - {parseInlineMarkdown(orderedListMatch[1])} -
  • - ); - continue; - } - - // Regular paragraph - elements.push( -

    - {parseInlineMarkdown(line)} -

    - ); - } - - return elements; - }; - - // Parse inline markdown (bold, italic, links) - const parseInlineMarkdown = (text: string): React.ReactNode[] => { - const parts: React.ReactNode[] = []; - let remaining = text; - let key = 0; - - while (remaining.length > 0) { - // Bold (**text** or __text__) - const boldMatch = remaining.match(/^(.*?)(\*\*|__)(.*?)\2/); - if (boldMatch) { - if (boldMatch[1]) parts.push(boldMatch[1]); - parts.push( - - {boldMatch[3]} - - ); - remaining = remaining.substring(boldMatch[0].length); - continue; - } - - // Italic (*text* or _text_) - const italicMatch = remaining.match(/^(.*?)(\*|_)(.*?)\2/); - if (italicMatch) { - if (italicMatch[1]) parts.push(italicMatch[1]); - parts.push( - - {italicMatch[3]} - - ); - remaining = remaining.substring(italicMatch[0].length); - continue; - } - - // No more markdown, add remaining text - parts.push(remaining); - break; - } - - return parts; + const components: Components = { + h1: ({ ...props }) =>

    , + h2: ({ ...props }) =>

    , + h3: ({ ...props }) =>

    , + h4: ({ ...props }) =>

    , + h5: ({ ...props }) =>

    , + h6: ({ ...props }) =>
    , + p: ({ ...props }) =>

    , + li: ({ ...props }) =>

  • , + strong: ({ ...props }) => , + em: ({ ...props }) => , + pre: ({ ...props }) =>
    ,
    +    // @ts-expect-error - inline prop is provided by react-markdown
    +    code: ({ inline, ...props }) =>
    +      inline ? (
    +        
    +      ) : (
    +        
    +      ),
    +    blockquote: ({ ...props }) => 
    , + hr: ({ ...props }) =>
    , + a: ({ ...props }) => ( + + ), }; return (
    - {parseMarkdown(content)} + + {content} +
    ); } diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 498ac49..b5a0ff1 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -8,7 +8,10 @@ export { default as FullScreenBlurModal } from "./FullScreenBlurModal/FullScreen export { default as GPTAnimationText } from "./GPTAnimationText/GPTAnimationText"; export { default as Grid } from "./Grid/Grid"; export { default as Icon, IconName, type IconProps } from "./Icon/Icon"; -export { default as IconLabel, type IconLabelProps } from "./IconLabel/IconLabel"; +export { + default as IconLabel, + type IconLabelProps, +} from "./IconLabel/IconLabel"; export { default as MarkdownText } from "./MarkdownText/MarkdownText"; export { default as MetaLabel } from "./MetaLabel/MetaLabel"; export { default as Modal, type ModalProps } from "./Modal/Modal"; diff --git a/src/entities/dashboard/actions.ts b/src/entities/dashboard/actions.ts new file mode 100644 index 0000000..88a6c60 --- /dev/null +++ b/src/entities/dashboard/actions.ts @@ -0,0 +1,38 @@ +"use server"; + +import { z } from "zod"; + +import { http } from "@/shared/api/httpClient"; +import { API_ROUTES } from "@/shared/constants/api-routes"; +import { ActionResponse } from "@/types"; + +const CheckVideoGuidePurchaseResponseSchema = z.object({ + isPurchased: z.boolean(), + videoLink: z.string().nullable(), +}); + +export type CheckVideoGuidePurchaseResponse = z.infer< + typeof CheckVideoGuidePurchaseResponseSchema +>; + +export async function checkVideoGuidePurchase( + productKey: string +): Promise> { + try { + const response = await http.get( + API_ROUTES.checkVideoGuidePurchase(productKey), + { + cache: "no-store", + schema: CheckVideoGuidePurchaseResponseSchema, + } + ); + + return { data: response, error: null }; + } catch (error) { + // eslint-disable-next-line no-console + console.error("Failed to check video guide purchase:", error); + const errorMessage = + error instanceof Error ? error.message : "Something went wrong."; + return { data: null, error: errorMessage }; + } +} diff --git a/src/entities/dashboard/api.ts b/src/entities/dashboard/api.ts index 57643d1..6dee16e 100644 --- a/src/entities/dashboard/api.ts +++ b/src/entities/dashboard/api.ts @@ -5,7 +5,7 @@ import { DashboardData, DashboardSchema } from "./types"; export const getDashboard = async () => { return http.get(API_ROUTES.dashboard(), { - tags: ["dashboard"], + cache: "no-store", // Всегда свежие данные schema: DashboardSchema, }); }; diff --git a/src/entities/dashboard/loaders.ts b/src/entities/dashboard/loaders.ts index c1d5fa0..1533d2b 100644 --- a/src/entities/dashboard/loaders.ts +++ b/src/entities/dashboard/loaders.ts @@ -1,19 +1,21 @@ -import { cache } from "react"; - import { getDashboard } from "./api"; -export const loadDashboard = cache(getDashboard); +// Убран cache() для всегда свежих данных +export const loadDashboard = getDashboard; -export const loadAssistants = cache(() => - loadDashboard().then(d => d.assistants) -); -export const loadCompatibility = cache(() => - loadDashboard().then(d => d.compatibilityActions) -); -export const loadMeditations = cache(() => - loadDashboard().then(d => d.meditations) -); -export const loadPalms = cache(() => loadDashboard().then(d => d.palmActions)); -export const loadPortraits = cache(() => - loadDashboard().then(d => d.partnerPortraits || []) -); +export const loadAssistants = () => + loadDashboard().then(d => d.assistants || []); + +export const loadCompatibility = () => + loadDashboard().then(d => d.compatibilityActions || []); + +export const loadMeditations = () => + loadDashboard().then(d => d.meditations || []); + +export const loadPalms = () => loadDashboard().then(d => d.palmActions || []); + +export const loadPortraits = () => + loadDashboard().then(d => d.partnerPortraits || []); + +export const loadVideoGuides = () => + loadDashboard().then(d => d.videoGuides || []); diff --git a/src/entities/dashboard/types.ts b/src/entities/dashboard/types.ts index 29a784e..c32695e 100644 --- a/src/entities/dashboard/types.ts +++ b/src/entities/dashboard/types.ts @@ -61,12 +61,33 @@ export const PartnerPortraitSchema = z.object({ }); export type PartnerPortrait = z.infer; +/* ---------- Video Guide ---------- */ +export const VideoGuideSchema = z.object({ + id: z.string(), + productId: z.string(), // ID продукта для покупки + key: z.string(), + type: z.string(), + name: z.string(), + description: z.string(), + imageUrl: z.string(), + duration: z.string(), + price: z.number(), + oldPrice: z.number(), + discount: z.number(), + isPurchased: z.boolean(), + videoLinkHLS: z.string(), // HLS format (.m3u8) + videoLinkDASH: z.string(), // DASH format (.mpd) + contentUrl: z.string().optional(), // URL to markdown content file +}); +export type VideoGuide = z.infer; + /* ---------- Итоговый ответ /dashboard ---------- */ export const DashboardSchema = z.object({ - assistants: z.array(AssistantSchema), - compatibilityActions: z.array(ActionSchema), - palmActions: z.array(ActionSchema), - meditations: z.array(ActionSchema), + assistants: z.array(AssistantSchema).optional(), + compatibilityActions: z.array(ActionSchema).optional(), + palmActions: z.array(ActionSchema).optional(), + meditations: z.array(ActionSchema).optional(), partnerPortraits: z.array(PartnerPortraitSchema).optional(), + videoGuides: z.array(VideoGuideSchema).optional(), }); export type DashboardData = z.infer; diff --git a/src/entities/session/funnel/types.ts b/src/entities/session/funnel/types.ts index 9231dcd..8bc3cf6 100644 --- a/src/entities/session/funnel/types.ts +++ b/src/entities/session/funnel/types.ts @@ -17,6 +17,9 @@ export const FunnelPaymentVariantSchema = z.object({ id: z.string(), key: z.string(), type: z.string(), + name: z.string().optional(), + description: z.string().optional(), + emoji: z.string().optional(), price: z.number(), oldPrice: z.number().optional(), trialPrice: z.number().optional(), @@ -35,6 +38,7 @@ export const FunnelPaymentPlacementSchema = z.object({ variants: z.array(FunnelPaymentVariantSchema).optional(), paymentUrl: z.string().optional(), type: z.string().optional(), + title: z.string().optional(), }); export const FunnelSchema = z.object({ diff --git a/src/hooks/chats/useChatSocket.ts b/src/hooks/chats/useChatSocket.ts index 47b85c4..db23e8b 100644 --- a/src/hooks/chats/useChatSocket.ts +++ b/src/hooks/chats/useChatSocket.ts @@ -144,7 +144,9 @@ export const useChatSocket = ( autoTopUp: false, }); // eslint-disable-next-line no-console - console.info("Auto top-up disabled successfully after payment failure"); + console.info( + "Auto top-up disabled successfully after payment failure" + ); } } catch (error) { // eslint-disable-next-line no-console diff --git a/src/hooks/multiPages/useMultiPageNavigation.ts b/src/hooks/multiPages/useMultiPageNavigation.ts index c1680b8..fcb5919 100644 --- a/src/hooks/multiPages/useMultiPageNavigation.ts +++ b/src/hooks/multiPages/useMultiPageNavigation.ts @@ -16,6 +16,7 @@ interface PageNavigationOptions { } interface PageNavigationReturn { + data: T[]; currentItem: T | undefined; currentIndex: number; isFirst: boolean; @@ -124,6 +125,7 @@ export function useMultiPageNavigation({ return useMemo( () => ({ + data, currentItem, nextItem, currentIndex, @@ -141,6 +143,7 @@ export function useMultiPageNavigation({ totalPages, }), [ + data, currentItem, nextItem, currentIndex, diff --git a/src/hooks/payment/useSingleCheckout.ts b/src/hooks/payment/useSingleCheckout.ts index 21b89a5..363c2bb 100644 --- a/src/hooks/payment/useSingleCheckout.ts +++ b/src/hooks/payment/useSingleCheckout.ts @@ -21,6 +21,7 @@ export function useSingleCheckout(options: UseSingleCheckoutOptions = {}) { if (isLoading) return; setIsLoading(true); + let shouldResetLoading = true; try { const payload: SingleCheckoutRequest = { @@ -45,11 +46,18 @@ export function useSingleCheckout(options: UseSingleCheckoutOptions = {}) { const { status, paymentUrl } = response.data.payment; if (paymentUrl) { - return window.location.replace(paymentUrl); + // При редиректе на внешний платеж не сбрасываем isLoading + shouldResetLoading = false; + window.location.replace(paymentUrl); + return; } if (status === "paid") { - onSuccess?.(); + // При успешной покупке НЕ сбрасываем isLoading + // onSuccess callback сам будет управлять состоянием через isNavigating + shouldResetLoading = false; + await onSuccess?.(); + return; } else { onError?.("Payment status is not paid"); } @@ -62,7 +70,10 @@ export function useSingleCheckout(options: UseSingleCheckoutOptions = {}) { error instanceof Error ? error.message : "Payment failed"; onError?.(errorMessage); } finally { - setIsLoading(false); + // Сбрасываем isLoading только если не было успешного платежа или редиректа + if (shouldResetLoading) { + setIsLoading(false); + } } }, [isLoading, returnUrl, onError, onSuccess] diff --git a/src/hooks/timer/useTimer.ts b/src/hooks/timer/useTimer.ts index 644e613..aa50582 100644 --- a/src/hooks/timer/useTimer.ts +++ b/src/hooks/timer/useTimer.ts @@ -22,7 +22,7 @@ export function useTimer({ // Load from localStorage after mount (client-only) useEffect(() => { - if (persist && storageKey && typeof window !== 'undefined') { + if (persist && storageKey && typeof window !== "undefined") { const saved = localStorage.getItem(storageKey); if (saved !== null) { const parsed = parseInt(saved, 10); @@ -36,7 +36,7 @@ export function useTimer({ // Save to localStorage when seconds change useEffect(() => { - if (persist && storageKey && typeof window !== 'undefined') { + if (persist && storageKey && typeof window !== "undefined") { localStorage.setItem(storageKey, seconds.toString()); } }, [seconds, persist, storageKey]); @@ -61,7 +61,7 @@ export function useTimer({ const reset = useCallback(() => { setSeconds(initialSeconds); - if (persist && storageKey && typeof window !== 'undefined') { + if (persist && storageKey && typeof window !== "undefined") { localStorage.setItem(storageKey, initialSeconds.toString()); } }, [initialSeconds, persist, storageKey]); diff --git a/src/hooks/video-guides/index.ts b/src/hooks/video-guides/index.ts new file mode 100644 index 0000000..5560f7e --- /dev/null +++ b/src/hooks/video-guides/index.ts @@ -0,0 +1 @@ +export { useVideoGuidePurchase } from "./useVideoGuidePurchase"; diff --git a/src/hooks/video-guides/useVideoGuidePurchase.ts b/src/hooks/video-guides/useVideoGuidePurchase.ts new file mode 100644 index 0000000..45a176a --- /dev/null +++ b/src/hooks/video-guides/useVideoGuidePurchase.ts @@ -0,0 +1,122 @@ +"use client"; + +import { useCallback, useState, useTransition } from "react"; +import { useRouter } from "next/navigation"; + +import { checkVideoGuidePurchase } from "@/entities/dashboard/actions"; +import { useSingleCheckout } from "@/hooks/payment/useSingleCheckout"; +import { useToast } from "@/providers/toast-provider"; +import { ROUTES } from "@/shared/constants/client-routes"; + +interface UseVideoGuidePurchaseOptions { + videoGuideId: string; + productId: string; + productKey: string; +} + +export function useVideoGuidePurchase(options: UseVideoGuidePurchaseOptions) { + const { productId, productKey } = options; + const { addToast } = useToast(); + const router = useRouter(); + const [isProcessingPurchase, setIsProcessingPurchase] = useState(false); + const [isCheckingPurchase, setIsCheckingPurchase] = useState(false); + const [isPending, startTransition] = useTransition(); + + const { handleSingleCheckout, isLoading: isCheckoutLoading } = + useSingleCheckout({ + onSuccess: async () => { + // Показываем toast о успешной покупке + addToast({ + variant: "success", + message: "Video guide purchased successfully!", + duration: 3000, + }); + + // Включаем лоадер на всей карточке + setIsProcessingPurchase(true); + + // Ждем 3 секунды перед обновлением + await new Promise(resolve => setTimeout(resolve, 3000)); + + // Обновляем данные dashboard в transition + // isPending будет true пока данные загружаются + startTransition(() => { + router.refresh(); + }); + + // Убираем наш флаг, но isPending продолжит показывать loader + setIsProcessingPurchase(false); + }, + onError: error => { + addToast({ + variant: "error", + message: error || "Purchase failed. Please try again.", + duration: 5000, + }); + }, + returnUrl: new URL( + ROUTES.home(), + process.env.NEXT_PUBLIC_APP_URL || "" + ).toString(), + }); + + const handlePurchase = useCallback(async () => { + // Сначала проверяем, не куплен ли уже продукт + setIsCheckingPurchase(true); + + try { + const result = await checkVideoGuidePurchase(productKey); + + if (result.data && result.data.isPurchased) { + // Продукт уже куплен! Показываем сообщение и обновляем страницу + addToast({ + variant: "success", + message: "You already own this video guide!", + duration: 3000, + }); + + setIsCheckingPurchase(false); + + // Включаем лоадер на всей карточке + setIsProcessingPurchase(true); + + // Даем небольшую задержку для плавного UX + await new Promise(resolve => setTimeout(resolve, 1000)); + + // Обновляем данные dashboard в transition + // isPending будет true пока данные загружаются + startTransition(() => { + router.refresh(); + }); + + // Убираем наш флаг, но isPending продолжит показывать loader + setIsProcessingPurchase(false); + return; + } + + // Продукт не куплен, продолжаем с checkout + setIsCheckingPurchase(false); + handleSingleCheckout({ + productId, + key: productKey, + }); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Error checking purchase status:", error); + setIsCheckingPurchase(false); + + // Даже если проверка не удалась, продолжаем с checkout + // чтобы не блокировать покупку + handleSingleCheckout({ + productId, + key: productKey, + }); + } + }, [handleSingleCheckout, productId, productKey, addToast, router]); + + return { + handlePurchase, + isCheckoutLoading: isCheckoutLoading || isCheckingPurchase, // Загрузка на кнопке (во время checkout или проверки) + isProcessingPurchase: isProcessingPurchase || isPending, // Загрузка на всей карточке (включая transition) + }; +} diff --git a/src/shared/constants/api-routes.ts b/src/shared/constants/api-routes.ts index 406ffa9..6a4e86c 100644 --- a/src/shared/constants/api-routes.ts +++ b/src/shared/constants/api-routes.ts @@ -13,6 +13,10 @@ const createRoute = ( export const API_ROUTES = { dashboard: () => createRoute(["dashboard"]), + videoGuides: () => createRoute(["video-guides"], ROOT_ROUTE_V2), + videoGuide: (id: string) => createRoute(["video-guides", id], ROOT_ROUTE_V2), + checkVideoGuidePurchase: (productKey: string) => + createRoute(["products", "video-guides", productKey, "check-purchase"]), subscriptions: () => createRoute(["payment", "subscriptions"], ROOT_ROUTE_V3), paymentCheckout: () => createRoute(["payment", "checkout"], ROOT_ROUTE_V2), paymentSingleCheckout: () => createRoute(["payment", "checkout"]),