feat: new data
Gitea Auto Deploy / Deploy-Container (push) Failing after 53s

This commit is contained in:
2026-06-02 18:24:12 +07:00
parent ee101f3851
commit 796969a174
60 changed files with 1126 additions and 984 deletions
+119 -81
View File
@@ -6,37 +6,37 @@
"name": "firefly-tools", "name": "firefly-tools",
"dependencies": { "dependencies": {
"@next/bundle-analyzer": "16.1.6", "@next/bundle-analyzer": "16.1.6",
"@tanstack/react-query": "^5.90.20", "@tanstack/react-query": "^5.100.10",
"axios": "^1.13.4", "axios": "^1.16.1",
"fast-average-color": "^9.5.0", "fast-average-color": "^9.5.2",
"framer-motion": "^12.29.2", "framer-motion": "^12.38.0",
"html2canvas-pro": "^1.6.6", "html2canvas-pro": "^1.6.7",
"lru-cache": "^11.2.5", "lru-cache": "^11.3.6",
"lucide-react": "^0.563.0", "lucide-react": "^0.563.0",
"next": "16.1.6", "next": "16.1.6",
"next-intl": "^4.8.2", "next-intl": "^4.12.0",
"prismjs": "^1.30.0", "prismjs": "^1.30.0",
"react": "19.2.4", "react": "19.2.4",
"react-dom": "19.2.4", "react-dom": "19.2.4",
"react-select": "^5.10.2", "react-select": "^5.10.2",
"react-simple-code-editor": "^0.14.1", "react-simple-code-editor": "^0.14.1",
"react-toastify": "^11.0.5", "react-toastify": "^11.1.0",
"sharp": "^0.34.5", "sharp": "^0.34.5",
"zod": "^4.3.6", "zod": "^4.4.3",
"zustand": "^5.0.11", "zustand": "^5.0.13",
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.18", "@tailwindcss/postcss": "^4.3.0",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^25.1.0", "@types/node": "^25.8.0",
"@types/react": "19.2.6", "@types/react": "19.2.6",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"baseline-browser-mapping": "^2.9.19", "baseline-browser-mapping": "^2.10.29",
"daisyui": "^5.5.14", "daisyui": "^5.5.19",
"eslint": "^9.39.2", "eslint": "^9.39.4",
"eslint-config-next": "16.1.6", "eslint-config-next": "16.1.6",
"tailwind-scrollbar": "^4.0.2", "tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.3.0",
"ts-to-zod": "^5.1.0", "ts-to-zod": "^5.1.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
}, },
@@ -121,15 +121,15 @@
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="],
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
@@ -143,13 +143,13 @@
"@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@3.1.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "@formatjs/intl-localematcher": "0.8.0", "decimal.js": "^10.6.0", "tslib": "^2.8.1" } }, "sha512-CjP1sUzM7XiQW6YluDreN+dMvcKZysO/J4ikvuDjDyd6nSOoSqAK9gvD1s75ZFaJVXtYOsz+y3CUXPZ1sKxcxw=="], "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@3.1.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "@formatjs/intl-localematcher": "0.8.0", "decimal.js": "^10.6.0", "tslib": "^2.8.1" } }, "sha512-CjP1sUzM7XiQW6YluDreN+dMvcKZysO/J4ikvuDjDyd6nSOoSqAK9gvD1s75ZFaJVXtYOsz+y3CUXPZ1sKxcxw=="],
"@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="], "@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.5", "", {}, "sha512-KLi3fan6WnCHmigd9pmEEN8Hid0v4wiFBW576M/d07KMWYecf1CvyMI3n34vCmHT4AoVqG2n702kiHbXjzZX2A=="],
"@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@3.5.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "@formatjs/icu-skeleton-parser": "2.1.0", "tslib": "^2.8.1" } }, "sha512-Q01XuvtbDVCJQsG/E2MSfMZ+UdUoZV8v4Aex8tTH44SqKJZCeu5LjuclaKFUS0o1YoXndfEinJen5k1T1GR1vg=="], "@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@3.5.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "@formatjs/icu-skeleton-parser": "2.1.0", "tslib": "^2.8.1" } }, "sha512-Q01XuvtbDVCJQsG/E2MSfMZ+UdUoZV8v4Aex8tTH44SqKJZCeu5LjuclaKFUS0o1YoXndfEinJen5k1T1GR1vg=="],
"@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@2.1.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "tslib": "^2.8.1" } }, "sha512-wNer4imHDFBVAJnMb2OGoSyM4wL/uuLnuo5mrenliqkDaNjRbG4jzlJcwTTDEBhai8iCjnzUsE7xwNJC29SfWw=="], "@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@2.1.0", "", { "dependencies": { "@formatjs/ecma402-abstract": "3.1.0", "tslib": "^2.8.1" } }, "sha512-wNer4imHDFBVAJnMb2OGoSyM4wL/uuLnuo5mrenliqkDaNjRbG4jzlJcwTTDEBhai8iCjnzUsE7xwNJC29SfWw=="],
"@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.5.10", "", { "dependencies": { "tslib": "2" } }, "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q=="], "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.8", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.5" } }, "sha512-pBr2hVKWvkHVnfXegW+53NT9U2uaVQCc+EgzLPCCwXqBA3nvM5fPbK9IcJlNjV+NMKGyZ2F3ZSG78iGdxAAqbA=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -329,39 +329,39 @@
"@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="], "@swc/types": ["@swc/types@0.1.25", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g=="],
"@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="], "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="],
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="], "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="],
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="], "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="],
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="], "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="],
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="], "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="],
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="], "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="],
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="], "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="],
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="], "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="],
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="], "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="],
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="], "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="],
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="], "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="],
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="], "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="],
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="], "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="],
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="], "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.0", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "postcss": "^8.5.10", "tailwindcss": "4.3.0" } }, "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w=="],
"@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], "@tanstack/query-core": ["@tanstack/query-core@5.100.10", "", {}, "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w=="],
"@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="], "@tanstack/react-query": ["@tanstack/react-query@5.100.10", "", { "dependencies": { "@tanstack/query-core": "5.100.10" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
@@ -379,7 +379,7 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], "@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="],
"@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="],
@@ -463,7 +463,9 @@
"acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
"ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
"ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
@@ -505,7 +507,7 @@
"axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="],
"axios": ["axios@1.13.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg=="], "axios": ["axios@1.16.1", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -515,7 +517,7 @@
"base64-arraybuffer": ["base64-arraybuffer@1.0.2", "", {}, "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="], "base64-arraybuffer": ["base64-arraybuffer@1.0.2", "", {}, "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.10.29", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
@@ -573,7 +575,7 @@
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"daisyui": ["daisyui@5.5.14", "", {}, "sha512-L47rvw7I7hK68TA97VB8Ee0woHew+/ohR6Lx6Ah/krfISOqcG4My7poNpX5Mo5/ytMxiR40fEaz6njzDi7cuSg=="], "daisyui": ["daisyui@5.5.19", "", {}, "sha512-pbFAkl1VCEh/MPCeclKL61I/MqRIFFhNU7yiXoDDRapXN4/qNCoMxeCCswyxEEhqL5eiTTfwHvucFtOE71C9sA=="],
"damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="],
@@ -613,7 +615,7 @@
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
"enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], "enhanced-resolve": ["enhanced-resolve@5.21.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q=="],
"environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="],
@@ -639,7 +641,7 @@
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="],
"eslint-config-next": ["eslint-config-next@16.1.6", "", { "dependencies": { "@next/eslint-plugin-next": "16.1.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA=="], "eslint-config-next": ["eslint-config-next@16.1.6", "", { "dependencies": { "@next/eslint-plugin-next": "16.1.6", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA=="],
@@ -675,7 +677,7 @@
"expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], "expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="],
"fast-average-color": ["fast-average-color@9.5.0", "", {}, "sha512-nC6x2YIlJ9xxgkMFMd1BNoM1ctMjNoRKfRliPmiEWW3S6rLTHiQcy9g3pt/xiKv/D0NAAkhb9VyV+WJFvTqMGg=="], "fast-average-color": ["fast-average-color@9.5.2", "", {}, "sha512-FbaU8iPTPljP7tmnVhXbCyASNw/zxnmaNDf88gn5pTXlNvejl9w4FapeWMh6UNDwIjhJJU28EPfQWwW032YgPA=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
@@ -703,13 +705,13 @@
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], "follow-redirects": ["follow-redirects@1.16.0", "", { "peerDependencies": { "debug": "*" }, "optionalPeers": ["debug"] }, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="],
"for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
"form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
"framer-motion": ["framer-motion@12.29.2", "", { "dependencies": { "motion-dom": "^12.29.2", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-lSNRzBJk4wuIy0emYQ/nfZ7eWhqud2umPKw2QAQki6uKhZPKm2hRQHeQoHTG9MIvfobb+A/LbEWPJU794ZUKrg=="], "framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@@ -767,9 +769,11 @@
"html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
"html2canvas-pro": ["html2canvas-pro@1.6.6", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-5mRhTXZhv4B0kIcsn3bFBjol2o8vzP35mhtxdXBGPA3V3gZd6Sa2PIIFbT//DiqAX8UuywlcJit5jRKej4nV4Q=="], "html2canvas-pro": ["html2canvas-pro@1.6.7", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-BzuCTXx0jf2TfnrJrtjMCY1FR9rxlPdy7yLWt9ZMhZm7Ylaw9MLb7agSheqv2mT/ARduBHDAqvJIFlbxrZfyOA=="],
"icu-minify": ["icu-minify@4.8.2", "", { "dependencies": { "@formatjs/icu-messageformat-parser": "^3.4.0" } }, "sha512-LHBQV+skKkjZSPd590pZ7ZAHftUgda3eFjeuNwA8/15L8T8loCNBktKQyTlkodAU86KovFXeg/9WntlAo5wA5A=="], "https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
"icu-minify": ["icu-minify@4.12.0", "", { "dependencies": { "@formatjs/icu-messageformat-parser": "^3.4.0" } }, "sha512-zDmM05uav3t3+kxSfRrNlmyXOdj2b+uHA+p04CG32eJabtaHbugXujuL+YfRkwP9joAnf0Uh+RMGCKD5NLa5rQ=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
@@ -893,29 +897,29 @@
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
@@ -931,7 +935,7 @@
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], "lru-cache": ["lru-cache@11.3.6", "", {}, "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A=="],
"lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="],
@@ -951,13 +955,13 @@
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
"motion-dom": ["motion-dom@12.29.2", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-/k+NuycVV8pykxyiTCoFzIVLA95Nb1BFIVvfSu9L50/6K6qNeAYtkxXILy/LRutt7AzaYDc2myj0wkCVVYAPPA=="], "motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="],
"motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="], "motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
@@ -973,9 +977,9 @@
"next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@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", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="], "next": ["next@16.1.6", "", { "dependencies": { "@next/env": "16.1.6", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.1.6", "@next/swc-darwin-x64": "16.1.6", "@next/swc-linux-arm64-gnu": "16.1.6", "@next/swc-linux-arm64-musl": "16.1.6", "@next/swc-linux-x64-gnu": "16.1.6", "@next/swc-linux-x64-musl": "16.1.6", "@next/swc-win32-arm64-msvc": "16.1.6", "@next/swc-win32-x64-msvc": "16.1.6", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@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", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw=="],
"next-intl": ["next-intl@4.8.2", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.5.4", "@parcel/watcher": "^2.4.1", "@swc/core": "^1.15.2", "icu-minify": "^4.8.2", "negotiator": "^1.0.0", "next-intl-swc-plugin-extractor": "^4.8.2", "po-parser": "^2.1.1", "use-intl": "^4.8.2" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-GuuwyvyEI49/oehQbBXEoY8KSIYCzmfMLhmIwhMXTb+yeBmly1PnJcpgph3KczQ+HTJMXwXCmkizgtT8jBMf3A=="], "next-intl": ["next-intl@4.12.0", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.8.1", "@parcel/watcher": "^2.4.1", "@swc/core": "^1.15.2", "icu-minify": "^4.12.0", "negotiator": "^1.0.0", "next-intl-swc-plugin-extractor": "^4.12.0", "po-parser": "^2.1.1", "use-intl": "^4.12.0" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-v8KpppWG0yLLlChJ3Of6uoPew9LeRDBAtY6vpJmF7YJmBZlHEzzoEL4w1g1dAU+VleEPNoXNm9hg1eEsKWV5hw=="],
"next-intl-swc-plugin-extractor": ["next-intl-swc-plugin-extractor@4.8.2", "", {}, "sha512-sHDs36L1VZmFHj3tPHsD+KZJtnsRudHlNvT0ieIe3iFVn5OpGLTxW3d/Zc/2LXSj5GpGuR6wQeikbhFjU9tMQQ=="], "next-intl-swc-plugin-extractor": ["next-intl-swc-plugin-extractor@4.12.0", "", {}, "sha512-jUxVEu1Nryjt4YgaDktSys7ioOgQfcNPF/SF2dbPNxbVb6U+P1INRgHeCVN+EC59H2rnTFIQwbddmOCrUWFr3g=="],
"node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="],
@@ -1029,7 +1033,7 @@
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
@@ -1041,7 +1045,7 @@
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], "proxy-from-env": ["proxy-from-env@2.1.0", "", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
@@ -1057,7 +1061,7 @@
"react-simple-code-editor": ["react-simple-code-editor@0.14.1", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow=="], "react-simple-code-editor": ["react-simple-code-editor@0.14.1", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow=="],
"react-toastify": ["react-toastify@11.0.5", "", { "dependencies": { "clsx": "^2.1.1" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA=="], "react-toastify": ["react-toastify@11.1.0", "", { "dependencies": { "clsx": "^2.1.1" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-e9h23x3phN0wbFeB6yovmWp7lobzV4CaCH0LO8nVP6H7Y+3GbcLpIzMm9dJhcp1RXbpyfvjgpfXqO80QAmn7sg=="],
"react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="],
@@ -1161,9 +1165,9 @@
"tailwind-scrollbar": ["tailwind-scrollbar@4.0.2", "", { "dependencies": { "prism-react-renderer": "^2.4.1" }, "peerDependencies": { "tailwindcss": "4.x" } }, "sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA=="], "tailwind-scrollbar": ["tailwind-scrollbar@4.0.2", "", { "dependencies": { "prism-react-renderer": "^2.4.1" }, "peerDependencies": { "tailwindcss": "4.x" } }, "sha512-wAQiIxAPqk0MNTPptVe/xoyWi27y+NRGnTwvn4PQnbvB9kp8QUBiGl/wsfoVBHnQxTmhXJSNt9NHTmcz9EivFA=="],
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="], "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="],
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"text-camel-case": ["text-camel-case@1.2.10", "", { "dependencies": { "text-pascal-case": "1.2.10" } }, "sha512-KNrWeZzQT+gh73V1LnmgTkjK7V+tMRjLCc6VrGwkqbiRdnGVIWBUgIvVnvnaVCxIvZ/2Ke8DCmgPirlQcCqD3Q=="], "text-camel-case": ["text-camel-case@1.2.10", "", { "dependencies": { "text-pascal-case": "1.2.10" } }, "sha512-KNrWeZzQT+gh73V1LnmgTkjK7V+tMRjLCc6VrGwkqbiRdnGVIWBUgIvVnvnaVCxIvZ/2Ke8DCmgPirlQcCqD3Q=="],
@@ -1243,7 +1247,7 @@
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
"unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="],
@@ -1251,7 +1255,7 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-intl": ["use-intl@4.8.2", "", { "dependencies": { "@formatjs/fast-memoize": "^3.1.0", "@schummar/icu-type-parser": "1.21.5", "icu-minify": "^4.8.2", "intl-messageformat": "^11.1.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-3VNXZgDnPFqhIYosQ9W1Hc6K5q+ZelMfawNbexdwL/dY7BTHbceLUBX5Eeex9lgogxTp0pf1SjHuhYNAjr9H3g=="], "use-intl": ["use-intl@4.12.0", "", { "dependencies": { "@formatjs/fast-memoize": "^3.1.0", "@schummar/icu-type-parser": "1.21.5", "icu-minify": "^4.12.0", "intl-messageformat": "^11.1.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-r+qVb7UI1+kiOhjYsmsNUCY+jrnjVopwGeFlmMyQj4YInlwZzgMeMSv9n8MqnWWy77HL5BVM8K2WgX50SbtcpA=="],
"use-isomorphic-layout-effect": ["use-isomorphic-layout-effect@1.2.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA=="], "use-isomorphic-layout-effect": ["use-isomorphic-layout-effect@1.2.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA=="],
@@ -1285,11 +1289,11 @@
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
"zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="],
"zustand": ["zustand@5.0.11", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="], "zustand": ["zustand@5.0.13", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ=="],
"@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
@@ -1305,19 +1309,25 @@
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@formatjs/ecma402-abstract/@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="],
"@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "tslib": "^2.8.1" } }, "sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ=="], "@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.8.0", "", { "dependencies": { "@formatjs/fast-memoize": "3.1.0", "tslib": "^2.8.1" } }, "sha512-zgMYWdUlmEZpX2Io+v3LHrfq9xZ6khpQVf9UAw2xYWhGerGgI9XgH1HvL/A34jWiruUJpYlP5pk4g8nIcaDrXQ=="],
"@jest/pattern/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"@jest/types/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"@oclif/core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@oclif/core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "@oclif/core/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="],
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
@@ -1327,6 +1337,8 @@
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"browserslist/baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
"chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"cli-truncate/string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="], "cli-truncate/string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="],
@@ -1337,20 +1349,34 @@
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-import/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-jsx-a11y/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-react/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
"eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-react-hooks/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], "filelist/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
"hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"intl-messageformat/@formatjs/fast-memoize": ["@formatjs/fast-memoize@3.1.0", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg=="],
"jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"jest-mock/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"jest-util/@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"listr2/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], "listr2/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
"log-update/ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], "log-update/ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="],
@@ -1361,6 +1387,8 @@
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"next/baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
@@ -1373,10 +1401,16 @@
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"ts-to-zod/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"tsutils/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], "tsutils/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
"wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"@jest/pattern/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@jest/types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"@oclif/core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@oclif/core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
@@ -1385,6 +1419,10 @@
"filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"jest-mock/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"jest-util/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"listr2/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "listr2/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"listr2/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "listr2/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
BIN
View File
Binary file not shown.
Binary file not shown.
+8
View File
@@ -1,4 +1,12 @@
[ [
{
"version": "4.2.5",
"date": "01/05/2026",
"type": "update",
"items": [
"New data for 4.2.5"
]
},
{ {
"version": "4.1.6", "version": "4.1.6",
"date": "12/04/2026", "date": "12/04/2026",
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+5 -5
View File
@@ -1,15 +1,15 @@
services: services:
srtools-live: srtools:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: srtools-live container_name: srtools
restart: unless-stopped restart: unless-stopped
ports: ports:
- "3009:3000" - "3006:3000"
networks: networks:
- srtools-live-network - srtools-network
networks: networks:
srtools-live-network: srtools-network:
driver: bridge driver: bridge
+8 -6
View File
@@ -1,13 +1,15 @@
import nextCoreWebVitals from "eslint-config-next/core-web-vitals"; import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
import nextTypescript from "eslint-config-next/typescript"; import nextTypescript from "eslint-config-next/typescript";
import { dirname } from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const eslintConfig = [...nextCoreWebVitals, ...nextTypescript, { const eslintConfig = [...nextCoreWebVitals, ...nextTypescript, {
ignores: ["node_modules/**", ".next/**", "out/**", "build/**", "next-env.d.ts"] ignores: [
"node_modules/**",
".next/**",
".history/**",
"out/**",
"build/**",
"next-env.d.ts",
]
}]; }];
export default eslintConfig; export default eslintConfig;
+18 -2
View File
@@ -1,11 +1,27 @@
import { getRequestConfig } from "next-intl/server"; import { getRequestConfig } from "next-intl/server";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
const supportedLocales = new Set([
"en",
"vi",
"ja",
"ko",
"zh",
"de",
"es",
"fr",
"id",
"pt",
"ru",
"th",
]);
export default getRequestConfig( async () => { export default getRequestConfig( async () => {
const locale = (await cookies()).get("MYNEXTAPP_LOCALE")?.value || "en"; const cookieLocale = (await cookies()).get("MYNEXTAPP_LOCALE")?.value;
const locale = cookieLocale && supportedLocales.has(cookieLocale) ? cookieLocale : "en";
return { return {
locale, locale,
messages: (await import(`../messages/${locale}.json`)).default messages: (await import(`../messages/${locale}.json`)).default
} }
}) })
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Turbulenz-Buff verwenden?", "useTurbulenceBuff": "Turbulenz-Buff verwenden?",
"firstHalfEnemies": "Gegner erste Hälfte", "firstHalfEnemies": "Gegner erste Hälfte",
"secondHalfEnemies": "Gegner zweite Hälfte", "secondHalfEnemies": "Gegner zweite Hälfte",
"firstNodeEnemies": "Gegner Knoten 1",
"secondNodeEnemies": "Gegner Knoten 2",
"thirdNodeEnemies": "Gegner Knoten 3",
"firstNode": "Knoten 1",
"secondNode": "Knoten 2",
"thirdNode": "Knoten 3",
"listEnemies": "Gegnerliste", "listEnemies": "Gegnerliste",
"turbulenceBuff": "Turbulenz-Buff", "turbulenceBuff": "Turbulenz-Buff",
"noEventSelected": "Kein Ereignis ausgewählt", "noEventSelected": "Kein Ereignis ausgewählt",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Use turbulence buff?", "useTurbulenceBuff": "Use turbulence buff?",
"firstHalfEnemies": "First half enemies", "firstHalfEnemies": "First half enemies",
"secondHalfEnemies": "Second half enemies", "secondHalfEnemies": "Second half enemies",
"firstNodeEnemies": "First node enemies",
"secondNodeEnemies": "Second node enemies",
"thirdNodeEnemies": "Third node enemies",
"firstNode": "First Node",
"secondNode": "Second Node",
"thirdNode": "Third Node",
"listEnemies": "List enemies", "listEnemies": "List enemies",
"turbulenceBuff": "Turbulence Buff", "turbulenceBuff": "Turbulence Buff",
"noEventSelected": "No event selected", "noEventSelected": "No event selected",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "¿Usar buff de turbulencia?", "useTurbulenceBuff": "¿Usar buff de turbulencia?",
"firstHalfEnemies": "Enemigos primera mitad", "firstHalfEnemies": "Enemigos primera mitad",
"secondHalfEnemies": "Enemigos segunda mitad", "secondHalfEnemies": "Enemigos segunda mitad",
"firstNodeEnemies": "Enemigos del nodo 1",
"secondNodeEnemies": "Enemigos del nodo 2",
"thirdNodeEnemies": "Enemigos del nodo 3",
"firstNode": "Nodo 1",
"secondNode": "Nodo 2",
"thirdNode": "Nodo 3",
"listEnemies": "Lista de enemigos", "listEnemies": "Lista de enemigos",
"turbulenceBuff": "Buff de Turbulencia", "turbulenceBuff": "Buff de Turbulencia",
"noEventSelected": "Ningún evento seleccionado", "noEventSelected": "Ningún evento seleccionado",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Utiliser le buff de turbulence ?", "useTurbulenceBuff": "Utiliser le buff de turbulence ?",
"firstHalfEnemies": "Ennemis première moitié", "firstHalfEnemies": "Ennemis première moitié",
"secondHalfEnemies": "Ennemis deuxième moitié", "secondHalfEnemies": "Ennemis deuxième moitié",
"firstNodeEnemies": "Ennemis du nœud 1",
"secondNodeEnemies": "Ennemis du nœud 2",
"thirdNodeEnemies": "Ennemis du nœud 3",
"firstNode": "Nœud 1",
"secondNode": "Nœud 2",
"thirdNode": "Nœud 3",
"listEnemies": "Liste des ennemis", "listEnemies": "Liste des ennemis",
"turbulenceBuff": "Buff de Turbulence", "turbulenceBuff": "Buff de Turbulence",
"noEventSelected": "Aucun événement sélectionné", "noEventSelected": "Aucun événement sélectionné",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Gunakan buff turbulence?", "useTurbulenceBuff": "Gunakan buff turbulence?",
"firstHalfEnemies": "Musuh paruh pertama", "firstHalfEnemies": "Musuh paruh pertama",
"secondHalfEnemies": "Musuh paruh kedua", "secondHalfEnemies": "Musuh paruh kedua",
"firstNodeEnemies": "Musuh Node 1",
"secondNodeEnemies": "Musuh Node 2",
"thirdNodeEnemies": "Musuh Node 3",
"firstNode": "Node 1",
"secondNode": "Node 2",
"thirdNode": "Node 3",
"listEnemies": "Daftar musuh", "listEnemies": "Daftar musuh",
"turbulenceBuff": "Turbulence Buff", "turbulenceBuff": "Turbulence Buff",
"noEventSelected": "Tidak ada event dipilih", "noEventSelected": "Tidak ada event dipilih",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "乱気流バフを使用しますか?", "useTurbulenceBuff": "乱気流バフを使用しますか?",
"firstHalfEnemies": "前半の敵", "firstHalfEnemies": "前半の敵",
"secondHalfEnemies": "後半の敵", "secondHalfEnemies": "後半の敵",
"firstNodeEnemies": "ノード 1 の敵",
"secondNodeEnemies": "ノード 2 の敵",
"thirdNodeEnemies": "ノード 3 の敵",
"firstNode": "ノード 1",
"secondNode": "ノード 2",
"thirdNode": "ノード 3",
"turbulenceBuff": "乱気流バフ", "turbulenceBuff": "乱気流バフ",
"noEventSelected": "イベントが選択されていません", "noEventSelected": "イベントが選択されていません",
"noTurbulenceBuff": "乱気流バフがありません", "noTurbulenceBuff": "乱気流バフがありません",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "난류 버프 사용?", "useTurbulenceBuff": "난류 버프 사용?",
"firstHalfEnemies": "전반 적", "firstHalfEnemies": "전반 적",
"secondHalfEnemies": "후반 적", "secondHalfEnemies": "후반 적",
"firstNodeEnemies": "노드 1 적",
"secondNodeEnemies": "노드 2 적",
"thirdNodeEnemies": "노드 3 적",
"firstNode": "노드 1",
"secondNode": "노드 2",
"thirdNode": "노드 3",
"turbulenceBuff": "난류 버프", "turbulenceBuff": "난류 버프",
"noEventSelected": "이벤트가 선택되지 않음", "noEventSelected": "이벤트가 선택되지 않음",
"noTurbulenceBuff": "난류 버프가 없음", "noTurbulenceBuff": "난류 버프가 없음",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Usar buff de turbulência?", "useTurbulenceBuff": "Usar buff de turbulência?",
"firstHalfEnemies": "Inimigos da primeira metade", "firstHalfEnemies": "Inimigos da primeira metade",
"secondHalfEnemies": "Inimigos da segunda metade", "secondHalfEnemies": "Inimigos da segunda metade",
"firstNodeEnemies": "Inimigos do nodo 1",
"secondNodeEnemies": "Inimigos do nodo 2",
"thirdNodeEnemies": "Inimigos do nodo 3",
"firstNode": "Nodo 1",
"secondNode": "Nodo 2",
"thirdNode": "Nodo 3",
"listEnemies": "Lista de inimigos", "listEnemies": "Lista de inimigos",
"turbulenceBuff": "Buff de Turbulência", "turbulenceBuff": "Buff de Turbulência",
"noEventSelected": "Nenhum evento selecionado", "noEventSelected": "Nenhum evento selecionado",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Использовать бафф турбулентности?", "useTurbulenceBuff": "Использовать бафф турбулентности?",
"firstHalfEnemies": "Враги первой половины", "firstHalfEnemies": "Враги первой половины",
"secondHalfEnemies": "Враги второй половины", "secondHalfEnemies": "Враги второй половины",
"firstNodeEnemies": "Враги узла 1",
"secondNodeEnemies": "Враги узла 2",
"thirdNodeEnemies": "Враги узла 3",
"firstNode": "Узел 1",
"secondNode": "Узел 2",
"thirdNode": "Узел 3",
"listEnemies": "Список врагов", "listEnemies": "Список врагов",
"turbulenceBuff": "Бафф турбулентности", "turbulenceBuff": "Бафф турбулентности",
"noEventSelected": "Событие не выбрано", "noEventSelected": "Событие не выбрано",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "ใช้บัฟบรรยากาศหรือไม่?", "useTurbulenceBuff": "ใช้บัฟบรรยากาศหรือไม่?",
"firstHalfEnemies": "ศัตรูครึ่งแรก", "firstHalfEnemies": "ศัตรูครึ่งแรก",
"secondHalfEnemies": "ศัตรูครึ่งหลัง", "secondHalfEnemies": "ศัตรูครึ่งหลัง",
"firstNodeEnemies": "ศัตรูโหนด 1",
"secondNodeEnemies": "ศัตรูโหนด 2",
"thirdNodeEnemies": "ศัตรูโหนด 3",
"firstNode": "โหนด 1",
"secondNode": "โหนด 2",
"thirdNode": "โหนด 3",
"listEnemies": "รายการศัตรู", "listEnemies": "รายการศัตรู",
"turbulenceBuff": "บัฟบรรยากาศ", "turbulenceBuff": "บัฟบรรยากาศ",
"noEventSelected": "ไม่ได้เลือกอีเวนต์", "noEventSelected": "ไม่ได้เลือกอีเวนต์",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "Dùng buff hỗn loạn?", "useTurbulenceBuff": "Dùng buff hỗn loạn?",
"firstHalfEnemies": "Địch nửa đầu", "firstHalfEnemies": "Địch nửa đầu",
"secondHalfEnemies": "Địch nửa sau", "secondHalfEnemies": "Địch nửa sau",
"firstNodeEnemies": "Địch Node 1",
"secondNodeEnemies": "Địch Node 2",
"thirdNodeEnemies": "Địch Node 3",
"firstNode": "Node 1",
"secondNode": "Node 2",
"thirdNode": "Node 3",
"turbulenceBuff": "Buff hỗn loạn", "turbulenceBuff": "Buff hỗn loạn",
"noEventSelected": "Không có sự kiện", "noEventSelected": "Không có sự kiện",
"noTurbulenceBuff": "Không có buff hỗn loạn", "noTurbulenceBuff": "Không có buff hỗn loạn",
+6
View File
@@ -189,6 +189,12 @@
"useTurbulenceBuff": "使用记忆紊流?", "useTurbulenceBuff": "使用记忆紊流?",
"firstHalfEnemies": "上半场敌人", "firstHalfEnemies": "上半场敌人",
"secondHalfEnemies": "下半场敌人", "secondHalfEnemies": "下半场敌人",
"firstNodeEnemies": "节点 1 敌人",
"secondNodeEnemies": "节点 2 敌人",
"thirdNodeEnemies": "节点 3 敌人",
"firstNode": "节点 1",
"secondNode": "节点 2",
"thirdNode": "节点 3",
"turbulenceBuff": "增益效果", "turbulenceBuff": "增益效果",
"noEventSelected": "未选择事件", "noEventSelected": "未选择事件",
"noTurbulenceBuff": "未选择增益效果", "noTurbulenceBuff": "未选择增益效果",
+16 -16
View File
@@ -10,37 +10,37 @@
}, },
"dependencies": { "dependencies": {
"@next/bundle-analyzer": "16.1.6", "@next/bundle-analyzer": "16.1.6",
"@tanstack/react-query": "^5.90.20", "@tanstack/react-query": "^5.100.10",
"axios": "^1.13.4", "axios": "^1.16.1",
"fast-average-color": "^9.5.0", "fast-average-color": "^9.5.2",
"framer-motion": "^12.29.2", "framer-motion": "^12.38.0",
"html2canvas-pro": "^1.6.6", "html2canvas-pro": "^1.6.7",
"lru-cache": "^11.2.5", "lru-cache": "^11.3.6",
"lucide-react": "^0.563.0", "lucide-react": "^0.563.0",
"next": "16.1.6", "next": "16.1.6",
"next-intl": "^4.8.2", "next-intl": "^4.12.0",
"prismjs": "^1.30.0", "prismjs": "^1.30.0",
"react": "19.2.4", "react": "19.2.4",
"react-dom": "19.2.4", "react-dom": "19.2.4",
"react-select": "^5.10.2", "react-select": "^5.10.2",
"react-simple-code-editor": "^0.14.1", "react-simple-code-editor": "^0.14.1",
"react-toastify": "^11.0.5", "react-toastify": "^11.1.0",
"sharp": "^0.34.5", "sharp": "^0.34.5",
"zod": "^4.3.6", "zod": "^4.4.3",
"zustand": "^5.0.11" "zustand": "^5.0.13"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.18", "@tailwindcss/postcss": "^4.3.0",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^25.1.0", "@types/node": "^25.8.0",
"@types/react": "19.2.6", "@types/react": "19.2.6",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"baseline-browser-mapping": "^2.9.19", "baseline-browser-mapping": "^2.10.29",
"daisyui": "^5.5.14", "daisyui": "^5.5.19",
"eslint": "^9.39.2", "eslint": "^9.39.4",
"eslint-config-next": "16.1.6", "eslint-config-next": "16.1.6",
"tailwind-scrollbar": "^4.0.2", "tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.3.0",
"ts-to-zod": "^5.1.0", "ts-to-zod": "^5.1.0",
"typescript": "^5.9.3" "typescript": "^5.9.3"
}, },
+3 -1
View File
@@ -79,6 +79,8 @@ export default function Header() {
if (cookieLocale) { if (cookieLocale) {
if (!listCurrentLanguageApi.hasOwnProperty(cookieLocale)) { if (!listCurrentLanguageApi.hasOwnProperty(cookieLocale)) {
setLocale("en") setLocale("en")
document.cookie = "MYNEXTAPP_LOCALE=en;"
router.refresh()
} else { } else {
setLocale(cookieLocale) setLocale(cookieLocale)
} }
@@ -614,4 +616,4 @@ export default function Header() {
))} ))}
</div> </div>
) )
} }
+24 -9
View File
@@ -71,8 +71,11 @@ export default function CopyImport() {
const selectAll = () => { const selectAll = () => {
if (avatarCopySelected) { if (avatarCopySelected) {
setSelectedProfiles(avatars[avatarCopySelected?.ID.toString()].profileList.map((profile, index) => { const sourceAvatar = avatars[avatarCopySelected.ID.toString()]
if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { const sourceProfiles = sourceAvatar?.profileList ?? []
setSelectedProfiles(sourceProfiles.map((profile, index) => {
if (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0) {
return null; return null;
} }
return { return {
@@ -110,8 +113,20 @@ export default function CopyImport() {
return; return;
} }
const newListProfile = avatars[avatarCopySelected.ID.toString()].profileList.map((profile) => { const sourceAvatar = avatars[avatarCopySelected.ID.toString()]
if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { const targetAvatar = avatars[avatarSelected.ID.toString()]
if (!sourceAvatar || !targetAvatar) {
setMessage({
type: "error",
text: transI18n("noDataToImport")
});
return;
}
const selectedKeys = new Set(selectedProfiles.map((profile) => profile.key))
const newListProfile = sourceAvatar.profileList.map((profile, index) => {
if (!selectedKeys.has(index) || (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0)) {
return null; return null;
} }
return { return {
@@ -121,9 +136,9 @@ export default function CopyImport() {
}).filter((profile) => profile !== null); }).filter((profile) => profile !== null);
const newAvatar = { const newAvatar = {
...avatars[avatarSelected?.ID?.toString()], ...targetAvatar,
profileList: avatars[avatarSelected?.ID?.toString()].profileList.concat(newListProfile), profileList: targetAvatar.profileList.concat(newListProfile),
profileSelect: avatars[avatarSelected?.ID?.toString()].profileList.length - 1, profileSelect: targetAvatar.profileList.length + newListProfile.length - 1,
} }
setAvatar(newAvatar); setAvatar(newAvatar);
setSelectedProfiles([]); setSelectedProfiles([]);
@@ -275,7 +290,7 @@ export default function CopyImport() {
{/* Character Grid */} {/* Character Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{avatarCopySelected && avatars[avatarCopySelected?.ID.toString()]?.profileList.map((profile, index) => { {avatarCopySelected && avatars[avatarCopySelected?.ID.toString()]?.profileList.map((profile, index) => {
if (!profile.lightcone?.item_id && Object.keys(profile.relics).length == 0) { if (!profile.lightcone?.item_id && Object.keys(profile.relics ?? {}).length == 0) {
return null; return null;
} }
return ( return (
@@ -291,4 +306,4 @@ export default function CopyImport() {
</div> </div>
</div> </div>
) )
} }
+53 -63
View File
@@ -9,6 +9,28 @@ import { converterOneEnkaDataToAvatarStore } from "@/helper";
import useModelStore from "@/stores/modelStore"; import useModelStore from "@/stores/modelStore";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { avatarEnkaDetailSchema, enkaResponseSchema } from "@/zod";
import { z } from "zod";
import useDetailDataStore from "@/stores/detailDataStore";
type AvatarEnkaDetailInput = z.infer<typeof avatarEnkaDetailSchema>;
const toCharacterInfoCard = (character: AvatarEnkaDetailInput): CharacterInfoCardType => ({
key: character.avatarId,
avatar_id: character.avatarId,
rank: character.rank ?? 0,
level: character.level,
lightcone: {
level: character.equipment?.level ?? 0,
rank: character.equipment?.rank ?? 0,
item_id: character.equipment?.tid ?? 0,
},
relics: character.relicList.map((relic) => ({
level: relic.level,
relic_id: relic.tid,
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
})),
});
export default function EnkaImport() { export default function EnkaImport() {
const { const {
@@ -22,8 +44,10 @@ export default function EnkaImport() {
const transI18n = useTranslations("DataPage") const transI18n = useTranslations("DataPage")
const { avatars, setAvatar } = useUserDataStore(); const { avatars, setAvatar } = useUserDataStore();
const { setIsOpenImport } = useModelStore() const { setIsOpenImport } = useModelStore()
const { mapAvatar } = useDetailDataStore()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [Error, setError] = useState("") const [Error, setError] = useState("")
const validCharacters = enkaData?.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId]) ?? []
const handlerFetchData = async () => { const handlerFetchData = async () => {
if (!uidInput) { if (!uidInput) {
@@ -31,32 +55,27 @@ export default function EnkaImport() {
return; return;
} }
setIsLoading(true) setIsLoading(true)
const data : EnkaResponse = await SendDataThroughProxy({data: {serverUrl: "https://enka.network/api/hsr/uid/" + uidInput, method: "GET"}}) try {
if (data) { const data: unknown = await SendDataThroughProxy({data: {serverUrl: "https://enka.network/api/hsr/uid/" + uidInput, method: "GET"}})
setEnkaData(data) const parsed = enkaResponseSchema.safeParse(data)
setSelectedCharacters(data.detailInfo.avatarDetailList.map((character) => {
return { if (!parsed.success) {
key: character.avatarId, setEnkaData(null)
avatar_id: character.avatarId, setSelectedCharacters([])
rank: character.rank ?? 0, setError(transI18n("failedToFetchEnkaData"))
level: character.level, return
lightcone: { }
level: character.equipment?.level ?? 0,
rank: character.equipment?.rank ?? 0, setEnkaData(parsed.data as EnkaResponse)
item_id: character.equipment?.tid ?? 0, setSelectedCharacters(parsed.data.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId]).map(toCharacterInfoCard))
},
relics: character.relicList.map((relic) => ({
level: relic.level,
relic_id: relic.tid,
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
})),
} as CharacterInfoCardType
}))
setError("") setError("")
} else { } catch {
setEnkaData(null)
setSelectedCharacters([])
setError(transI18n("failedToFetchEnkaData")) setError(transI18n("failedToFetchEnkaData"))
} finally {
setIsLoading(false)
} }
setIsLoading(false)
} }
const handleCharacterToggle = (character: CharacterInfoCardType) => { const handleCharacterToggle = (character: CharacterInfoCardType) => {
@@ -73,26 +92,7 @@ export default function EnkaImport() {
const selectAll = () => { const selectAll = () => {
if (enkaData) { if (enkaData) {
setSelectedCharacters(enkaData?.detailInfo.avatarDetailList.map((character) => { setSelectedCharacters(validCharacters.map(toCharacterInfoCard));
return {
key: character.avatarId,
avatar_id: character.avatarId,
rank: character.rank ?? 0,
level: character.level,
lightcone: (character.equipment && character.equipment.tid) ? {
level: character.equipment?.level ?? 0,
rank: character.equipment?.rank ?? 0,
item_id: character.equipment?.tid ?? 0,
} : null,
relics: character.relicList.map((relic) => {
return {
level: relic.level,
relic_id: relic.tid,
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
}
}),
} as CharacterInfoCardType
}));
} }
}; };
@@ -107,7 +107,13 @@ export default function EnkaImport() {
} }
setError(""); setError("");
const listAvatars = { ...avatars } const listAvatars = { ...avatars }
const filterData = enkaData.detailInfo.avatarDetailList.filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatarId)) const parsed = enkaResponseSchema.safeParse(enkaData)
if (!parsed.success) {
setError(transI18n("failedToFetchEnkaData"));
return;
}
const filterData = parsed.data.detailInfo.avatarDetailList.filter((character) => mapAvatar?.[character.avatarId] && selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatarId))
filterData.forEach((character) => { filterData.forEach((character) => {
const newAvatar = { ...listAvatars[character.avatarId.toString()] } const newAvatar = { ...listAvatars[character.avatarId.toString()] }
if (Object.keys(newAvatar).length !== 0) { if (Object.keys(newAvatar).length !== 0) {
@@ -193,26 +199,10 @@ export default function EnkaImport() {
)} )}
{/* Character Grid */} {/* Character Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{enkaData?.detailInfo.avatarDetailList.map((character) => ( {validCharacters.map((character) => (
<CharacterInfoCard <CharacterInfoCard
key={character.avatarId} key={character.avatarId}
character={{ character={toCharacterInfoCard(character)}
key: character.avatarId,
avatar_id: character.avatarId,
rank: character.rank ?? 0,
level: character.level ?? 0,
lightcone: {
level: character.equipment?.level ?? 0,
rank: character.equipment?.rank ?? 0,
item_id: character.equipment?.tid ?? 0,
},
relics: character.relicList.map((relic) => ({
level: relic.level ?? 0,
relic_id: relic.tid,
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
})),
} as CharacterInfoCardType
}
selectedCharacters={selectedCharacters} selectedCharacters={selectedCharacters}
onCharacterToggle={handleCharacterToggle} onCharacterToggle={handleCharacterToggle}
/> />
@@ -221,4 +211,4 @@ export default function EnkaImport() {
</div> </div>
</div> </div>
); );
} }
+59 -68
View File
@@ -11,6 +11,31 @@ import { toast } from "react-toastify";
import { converterOneFreeSRDataToAvatarStore } from "@/helper"; import { converterOneFreeSRDataToAvatarStore } from "@/helper";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import useDetailDataStore from "@/stores/detailDataStore"; import useDetailDataStore from "@/stores/detailDataStore";
import { z } from "zod";
type FreeSRJsonInput = z.infer<typeof freeSrJsonSchema>;
const toCharacterInfoCard = (data: FreeSRJsonInput, character: FreeSRJsonInput["avatars"][string]): CharacterInfoCardType => {
const lightcone = data.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id)
const relics = data.relics.filter((relic) => relic.equip_avatar === character.avatar_id)
return {
key: character.avatar_id,
avatar_id: character.avatar_id,
rank: character.data.rank ?? 0,
level: character.level,
lightcone: {
level: lightcone?.level ?? 0,
rank: lightcone?.rank ?? 0,
item_id: lightcone?.item_id ?? 0,
},
relics: relics.map((relic) => ({
level: relic.level,
relic_id: relic.relic_id,
relic_set_id: relic.relic_set_id,
})),
}
}
export default function FreeSRImport() { export default function FreeSRImport() {
const { avatars, setAvatar } = useUserDataStore(); const { avatars, setAvatar } = useUserDataStore();
@@ -20,6 +45,8 @@ export default function FreeSRImport() {
const [Error, setError] = useState("") const [Error, setError] = useState("")
const { freeSRData, setFreeSRData, selectedCharacters, setSelectedCharacters } = useFreeSRStore() const { freeSRData, setFreeSRData, selectedCharacters, setSelectedCharacters } = useFreeSRStore()
const transI18n = useTranslations("DataPage") const transI18n = useTranslations("DataPage")
const parsedFreeSRData = freeSrJsonSchema.safeParse(freeSRData)
const validFreeSRData = parsedFreeSRData.success ? parsedFreeSRData.data : null
const handleCharacterToggle = (character: CharacterInfoCardType) => { const handleCharacterToggle = (character: CharacterInfoCardType) => {
if (selectedCharacters.some((selectedCharacter) => selectedCharacter.key === character.key)) { if (selectedCharacters.some((selectedCharacter) => selectedCharacter.key === character.key)) {
@@ -34,27 +61,9 @@ export default function FreeSRImport() {
}; };
const selectAll = () => { const selectAll = () => {
if (freeSRData) { const parsed = freeSrJsonSchema.safeParse(freeSRData)
setSelectedCharacters(Object.values(freeSRData?.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { if (parsed.success) {
const lightcone = freeSRData.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id) setSelectedCharacters(Object.values(parsed.data.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => toCharacterInfoCard(parsed.data, character)));
const relics = freeSRData.relics.filter((relic) => relic.equip_avatar === character.avatar_id)
return {
key: character.avatar_id,
avatar_id: character.avatar_id,
rank: character.data.rank ?? 0,
level: character.level,
lightcone: {
level: lightcone?.level ?? 0,
rank: lightcone?.rank ?? 0,
item_id: lightcone?.item_id ?? "",
},
relics: relics.map((relic) => ({
level: relic.level,
relic_id: relic.relic_id,
relic_set_id: relic.relic_set_id,
})),
} as CharacterInfoCardType
}));
} }
}; };
@@ -82,41 +91,35 @@ export default function FreeSRImport() {
reader.onload = (e) => { reader.onload = (e) => {
try { try {
const data = JSON.parse(e.target?.result as string); const data = JSON.parse(e.target?.result as string);
const parsed = freeSrJsonSchema.parse(data) const parsed = freeSrJsonSchema.safeParse(data)
setFreeSRData(parsed) if (!parsed.success) {
setSelectedCharacters([])
setFreeSRData(null)
setError(transI18n("fileMustBeAValidJsonFile"))
return
}
setFreeSRData(parsed.data)
setError("") setError("")
setSelectedCharacters(Object.values(parsed?.avatars || {}).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { setSelectedCharacters(Object.values(parsed.data.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => toCharacterInfoCard(parsed.data, character)));
const lightcone = parsed?.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id)
const relics = parsed?.relics.filter((relic) => relic.equip_avatar === character.avatar_id)
return {
key: character.avatar_id,
avatar_id: character.avatar_id,
rank: character.data.rank ?? 0,
level: character.level,
lightcone: {
level: lightcone?.level ?? 0,
rank: lightcone?.rank ?? 0,
item_id: lightcone?.item_id ?? "",
},
relics: relics?.map((relic) => ({
level: relic.level,
relic_id: relic.relic_id,
relic_set_id: relic.relic_set_id,
})) ?? [],
} as CharacterInfoCardType
}));
} catch { } catch {
setSelectedCharacters([]) setSelectedCharacters([])
setFreeSRData(null) setFreeSRData(null)
setError(transI18n("fileMustBeAValidJsonFile")) setError(transI18n("fileMustBeAValidJsonFile"))
} finally {
setIsLoading(false)
} }
}; };
reader.onerror = () => {
setSelectedCharacters([])
setFreeSRData(null)
setError(transI18n("fileMustBeAValidJsonFile"))
setIsLoading(false)
}
reader.readAsText(file); reader.readAsText(file);
setIsLoading(false)
} }
setIsLoading(false)
}; };
const handleImport = () => { const handleImport = () => {
@@ -130,8 +133,14 @@ export default function FreeSRImport() {
} }
setError(""); setError("");
const parsed = freeSrJsonSchema.safeParse(freeSRData)
if (!parsed.success) {
setError(transI18n("fileMustBeAValidJsonFile"));
return;
}
const listAvatars = { ...avatars } const listAvatars = { ...avatars }
const filterData = Object.values(freeSRData?.avatars || {}).filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatar_id)) const filterData = Object.values(parsed.data.avatars).filter((character) => selectedCharacters.some((selectedCharacter) => selectedCharacter.avatar_id === character.avatar_id))
filterData.forEach((character) => { filterData.forEach((character) => {
const newAvatar = { ...listAvatars[character.avatar_id] } const newAvatar = { ...listAvatars[character.avatar_id] }
if (Object.keys(newAvatar).length !== 0) { if (Object.keys(newAvatar).length !== 0) {
@@ -141,7 +150,7 @@ export default function FreeSRImport() {
rank: character.data.rank ?? 0, rank: character.data.rank ?? 0,
skills: character.data.skills skills: character.data.skills
} }
const newProfile = converterOneFreeSRDataToAvatarStore(freeSRData, newAvatar.profileList.length, character.avatar_id) const newProfile = converterOneFreeSRDataToAvatarStore(parsed.data, newAvatar.profileList.length, character.avatar_id)
if (newProfile) { if (newProfile) {
newAvatar.profileList.push(newProfile) newAvatar.profileList.push(newProfile)
newAvatar.profileSelect = newAvatar.profileList.length - 1 newAvatar.profileSelect = newAvatar.profileList.length - 1
@@ -202,29 +211,11 @@ export default function FreeSRImport() {
)} )}
{/* Character Grid */} {/* Character Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{Object.values(freeSRData?.avatars || {}).filter(it => mapAvatar?.[it.avatar_id]).map((character) => { {validFreeSRData && Object.values(validFreeSRData.avatars).filter(it => mapAvatar?.[it.avatar_id]).map((character) => {
const lightcone = freeSRData?.lightcones.find((lightcone) => lightcone.equip_avatar === character.avatar_id)
const relics = freeSRData?.relics.filter((relic) => relic.equip_avatar === character.avatar_id)
return ( return (
<CharacterInfoCard <CharacterInfoCard
key={character.avatar_id} key={character.avatar_id}
character={{ character={toCharacterInfoCard(validFreeSRData, character)}
key: character.avatar_id,
avatar_id: character.avatar_id,
rank: character.data.rank ?? 0,
level: character.level,
lightcone: {
level: lightcone?.level ?? 0,
rank: lightcone?.rank ?? 0,
item_id: lightcone?.item_id ?? "",
},
relics: relics?.map((relic) => ({
level: relic.level,
relic_id: relic.relic_id,
relic_set_id: relic.relic_set_id,
})) ?? [],
} as CharacterInfoCardType
}
selectedCharacters={selectedCharacters} selectedCharacters={selectedCharacters}
onCharacterToggle={handleCharacterToggle} onCharacterToggle={handleCharacterToggle}
/> />
@@ -234,4 +225,4 @@ export default function FreeSRImport() {
</div> </div>
</div> </div>
) )
} }
+143 -219
View File
@@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper";
import useLocaleStore from "@/stores/localeStore"; import useLocaleStore from "@/stores/localeStore";
import useUserDataStore from "@/stores/userDataStore"; import useUserDataStore from "@/stores/userDataStore";
import Image from "next/image"; import Image from "next/image";
import { MonsterStore } from "@/types"; import { ASEvent, MonsterStore } from "@/types";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import useDetailDataStore from "@/stores/detailDataStore"; import useDetailDataStore from "@/stores/detailDataStore";
@@ -16,7 +16,6 @@ export default function AsBar() {
setAsConfig setAsConfig
} = useUserDataStore() } = useUserDataStore()
const { mapMonster, mapAS, damageType, hardLevelConfig, eliteConfig } = useDetailDataStore() const { mapMonster, mapAS, damageType, hardLevelConfig, eliteConfig } = useDetailDataStore()
const transI18n = useTranslations("DataPage") const transI18n = useTranslations("DataPage")
const challengeSelected = useMemo(() => { const challengeSelected = useMemo(() => {
@@ -27,20 +26,52 @@ export default function AsBar() {
return mapAS[as_config.event_id.toString()] return mapAS[as_config.event_id.toString()]
}, [as_config, mapAS]) }, [as_config, mapAS])
const floorSideList = useMemo(() => {
if (!eventSelected) return [];
const floorList = [
{
id: "firstNode",
name: transI18n("firstNode"),
wave: transI18n("firstNodeEnemies")
},
{
id: "secondNode",
name: transI18n("secondNode"),
wave: transI18n("secondNodeEnemies")
},
]
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === as_config.challenge_id) {
floorList.push({
id: "thirdNode",
name: transI18n("thirdNode"),
wave: transI18n("thirdNodeEnemies")
})
}
return floorList
}, [as_config.challenge_id, eventSelected, transI18n])
const buffList = useMemo(() => { const buffList = useMemo(() => {
if (!eventSelected) return []; if (!eventSelected) return [];
if (as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower") { if (as_config.floor_side === "firstNode") {
return eventSelected?.BuffList1 ?? []; return eventSelected?.BuffList1 ?? [];
} }
if (as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper") { if (as_config.floor_side === "secondNode") {
return eventSelected?.BuffList2 ?? []; return eventSelected?.BuffList2 ?? [];
} }
if (as_config.floor_side === "thirdNode" && eventSelected?.BuffList3) {
return eventSelected?.BuffList3 ?? [];
}
return []; return [];
}, [as_config.floor_side, eventSelected]); }, [as_config.floor_side, eventSelected]);
useEffect(() => { useEffect(() => {
if (!challengeSelected || as_config.event_id === 0 || as_config.challenge_id === 0) return if (!challengeSelected || as_config.event_id === 0 || as_config.challenge_id === 0) return
const newBattleConfig = structuredClone(as_config) const newBattleConfig = structuredClone(as_config)
@@ -65,67 +96,36 @@ export default function AsBar() {
newBattleConfig.monsters = [] newBattleConfig.monsters = []
newBattleConfig.stage_id = 0 newBattleConfig.stage_id = 0
if ((as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower")
&& challengeSelected.EventList1.length > 0) { let targetEventList: ASEvent[] = []
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID if (as_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
for (const wave of challengeSelected.EventList1[0].MonsterList) { targetEventList = challengeSelected.EventList1
} else if (as_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
targetEventList = challengeSelected.EventList2
} else if (as_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
targetEventList = eventSelected.Tierce.EventList
}
if (targetEventList.length > 0) {
newBattleConfig.stage_id = targetEventList[0].ID
for (const wave of targetEventList[0].MonsterList) {
const newWave: MonsterStore[] = [] const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) { for (const value of Object.values(wave)) {
newWave.push({ newWave.push({
monster_id: value, monster_id: value,
level: challengeSelected.EventList1[0].Level, level: targetEventList[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if ((as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper")
&& challengeSelected.EventList2.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if (as_config.floor_side === "Lower -> Upper"
&& challengeSelected.EventList1.length > 0) {
for (const wave of challengeSelected.EventList1[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList1[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
} else if (as_config.floor_side === "Upper -> Lower"
&& challengeSelected.EventList2.length > 0) {
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1, amount: 1,
}) })
} }
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} }
setAsConfig(newBattleConfig) setAsConfig(newBattleConfig)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
challengeSelected, challengeSelected,
eventSelected,
mapAS, mapAS,
as_config.event_id, as_config.event_id,
as_config.challenge_id, as_config.challenge_id,
@@ -186,10 +186,9 @@ export default function AsBar() {
onChange={(e) => setAsConfig({ ...as_config, floor_side: e.target.value })} onChange={(e) => setAsConfig({ ...as_config, floor_side: e.target.value })}
> >
<option value={0} disabled={true}>{transI18n("selectSide")}</option> <option value={0} disabled={true}>{transI18n("selectSide")}</option>
<option value="Upper">{transI18n("upper")}</option> {floorSideList.map((side) => {
<option value="Lower">{transI18n("lower")}</option> return <option key={side.id} value={side.id}>{side.name}</option>
<option value="Upper -> Lower">{transI18n("upperToLower")}</option> })}
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
</select> </select>
</div> </div>
</div> </div>
@@ -233,182 +232,107 @@ export default function AsBar() {
{/* Enemy Waves */} {/* Enemy Waves */}
{(as_config?.challenge_id ?? 0) !== 0 && ( {(as_config?.challenge_id ?? 0) !== 0 && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* First Half */} {floorSideList.map((side, i) => {
<div className="rounded-xl p-4 mt-2 border border-warning"> const eventList = side.id === "firstNode"
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2> ? challengeSelected?.EventList1
: side.id === "secondNode"
? challengeSelected?.EventList2
: side.id === "thirdNode"
? eventSelected?.Tierce?.EventList
: [];
{challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => ( if (!eventList || eventList.length === 0) return null;
<div key={waveIndex} className="mb-6"> const targetEvent = eventList[0];
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Object.values(wave).map((waveValue, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
challengeSelected?.EventList1?.[0]?.EliteGroup,
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
challengeSelected?.EventList1?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList1[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl"> return (
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( <div key={i} className="rounded-xl p-4 mt-2 border border-warning">
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100"> <h2 className="text-2xl font-bold mb-6 text-info">{side.wave}</h2>
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2"> {targetEvent?.MonsterList?.map((wave, waveIndex) => (
<div className="flex flex-col space-y-1.5"> <div key={waveIndex} className="mb-6">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<span className="text-xs font-semibold text-error">HP</span> <div className="flex flex-wrap gap-2 mt-2">
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> {Object.values(wave).map((waveValue, enemyIndex) => {
</div> const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> targetEvent?.EliteGroup,
<span className="text-xs font-semibold text-info">Speed</span> targetEvent?.HardLevelGroup,
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> targetEvent?.Level,
</div> hardLevelConfig,
eliteConfig
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> );
<span className="text-xs font-semibold text-base-content/70">Toughness</span> return (
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> <div
</div> key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {targetEvent.Level}
</div> </div>
<div className="mt-3 pt-2 border-t border-base-300 flex flex-col items-center"> <div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5"> {mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
Weakness <div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image <Image
key={iconIndex}
unoptimized unoptimized
crossOrigin="anonymous" crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`} src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt={icon} alt="Enemy Icon"
width={40} width={150}
height={40} height={150}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform" className="w-full h-full object-cover"
/> />
))} </div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2">
<div className="flex flex-col space-y-1.5">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-3 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> )
) })}
})} </div>
</div> </div>
</div> ))}
))} </div>
</div> )})}
{/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Object.values(wave).map((waveValue, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
challengeSelected?.EventList2?.[0]?.EliteGroup,
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
challengeSelected?.EventList2?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList2[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2">
<div className="flex flex-col space-y-1.5">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
))}
</div>
</div> </div>
)} )}
+140 -214
View File
@@ -7,7 +7,7 @@ import useLocaleStore from "@/stores/localeStore";
import useUserDataStore from "@/stores/userDataStore"; import useUserDataStore from "@/stores/userDataStore";
import Image from "next/image"; import Image from "next/image";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { MonsterStore } from "@/types"; import { MoCEvent, MonsterStore } from "@/types";
import useDetailDataStore from "@/stores/detailDataStore"; import useDetailDataStore from "@/stores/detailDataStore";
export default function MocBar() { export default function MocBar() {
@@ -28,6 +28,33 @@ export default function MocBar() {
return mapMoc[moc_config.event_id.toString()] return mapMoc[moc_config.event_id.toString()]
}, [moc_config, mapMoc]) }, [moc_config, mapMoc])
const floorSideList = useMemo(() => {
if (!eventSelected) return [];
const floorList = [
{
id: "firstNode",
name: transI18n("firstNode"),
wave: transI18n("firstNodeEnemies")
},
{
id: "secondNode",
name: transI18n("secondNode"),
wave: transI18n("secondNodeEnemies")
},
]
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === moc_config.challenge_id) {
floorList.push({
id: "thirdNode",
name: transI18n("thirdNode"),
wave: transI18n("thirdNodeEnemies")
})
}
return floorList
}, [moc_config.challenge_id, eventSelected, transI18n])
useEffect(() => { useEffect(() => {
if (!challengeSelected || moc_config.event_id === 0 || moc_config.challenge_id === 0) return if (!challengeSelected || moc_config.event_id === 0 || moc_config.challenge_id === 0) return
@@ -47,62 +74,36 @@ export default function MocBar() {
} }
newBattleConfig.monsters = [] newBattleConfig.monsters = []
newBattleConfig.stage_id = 0 newBattleConfig.stage_id = 0
if ((moc_config.floor_side === "Upper" || moc_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID let targetEventList: MoCEvent[] = []
for (const wave of challengeSelected.EventList1[0].MonsterList) { if (moc_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
targetEventList = challengeSelected.EventList1
} else if (moc_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
targetEventList = challengeSelected.EventList2
} else if (moc_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
targetEventList = eventSelected.Tierce.EventList
}
if (targetEventList.length > 0) {
newBattleConfig.stage_id = targetEventList[0].ID
for (const wave of targetEventList[0].MonsterList) {
const newWave: MonsterStore[] = [] const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) { for (const value of Object.values(wave)) {
newWave.push({ newWave.push({
monster_id: value, monster_id: value,
level: challengeSelected.EventList1[0].Level, level: targetEventList[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if ((moc_config.floor_side === "Lower" || moc_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if (moc_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) {
for (const wave of challengeSelected.EventList1[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList1[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
} else if (moc_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) {
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1, amount: 1,
}) })
} }
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} }
setMocConfig(newBattleConfig) setMocConfig(newBattleConfig)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
challengeSelected,
eventSelected,
moc_config.event_id, moc_config.event_id,
moc_config.challenge_id, moc_config.challenge_id,
moc_config.floor_side, moc_config.floor_side,
@@ -168,10 +169,9 @@ export default function MocBar() {
onChange={(e) => setMocConfig({ ...moc_config, floor_side: e.target.value })} onChange={(e) => setMocConfig({ ...moc_config, floor_side: e.target.value })}
> >
<option value={0} disabled={true}>{transI18n("selectSide")}</option> <option value={0} disabled={true}>{transI18n("selectSide")}</option>
<option value="Upper">{transI18n("upper")}</option> {floorSideList.map((side) => (
<option value="Lower">{transI18n("lower")}</option> <option key={side.id} value={side.id}>{side.name}</option>
<option value="Upper -> Lower">{transI18n("upperToLower")}</option> ))}
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
</select> </select>
</div> </div>
@@ -232,182 +232,108 @@ export default function MocBar() {
{/* Enemy Waves */} {/* Enemy Waves */}
{(moc_config?.challenge_id ?? 0) !== 0 && ( {(moc_config?.challenge_id ?? 0) !== 0 && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* First Half */} {floorSideList.map((side, i) => {
<div className="rounded-xl p-4 mt-2 border border-warning"> const eventList = side.id === "firstNode"
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2> ? challengeSelected?.EventList1
: side.id === "secondNode"
? challengeSelected?.EventList2
: side.id === "thirdNode"
? eventSelected?.Tierce?.EventList
: [];
{challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => ( if (!eventList || eventList.length === 0) return null;
<div key={waveIndex} className="mb-6"> const targetEvent = eventList[0];
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Object.values(wave).map((waveValue, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
challengeSelected?.EventList1?.[0]?.EliteGroup,
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
challengeSelected?.EventList1?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList1[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl"> return (
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && ( <div key={i} className="rounded-xl p-4 mt-2 border border-warning">
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100"> <h2 className="text-2xl font-bold mb-6 text-info">{side.wave}</h2>
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2"> {targetEvent?.MonsterList?.map((wave, waveIndex) => (
<div className="flex flex-col space-y-1.5"> <div key={waveIndex} className="mb-6">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<span className="text-xs font-semibold text-error">HP</span> <div className="flex flex-wrap gap-2 mt-2">
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> {Object.values(wave).map((waveValue, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
targetEvent?.EliteGroup,
targetEvent?.HardLevelGroup,
targetEvent?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {targetEvent.Level}
</div> </div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
<span className="text-xs font-semibold text-info">Speed</span> {mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> <div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div> </div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <div className="flex flex-col px-1 pb-2 pt-2">
<span className="text-xs font-semibold text-base-content/70">Toughness</span> <div className="flex flex-col space-y-1.5">
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> <div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div> </div>
</div> </div>
)
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center"> })}
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5"> </div>
Weakness </div>
</span> ))}
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div>
</div>
)
})}
</div>
</div> </div>
))} )
</div> })}
{/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => (
<div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Object.values(wave).map((waveValue, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[waveValue.toString()],
challengeSelected?.EventList2?.[0]?.EliteGroup,
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
challengeSelected?.EventList2?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList2[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2">
<div className="flex flex-col space-y-1.5">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
))}
</div>
</div> </div>
)} )}
+141 -216
View File
@@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper";
import useLocaleStore from "@/stores/localeStore"; import useLocaleStore from "@/stores/localeStore";
import useUserDataStore from "@/stores/userDataStore"; import useUserDataStore from "@/stores/userDataStore";
import Image from "next/image"; import Image from "next/image";
import { MonsterStore } from "@/types"; import { MonsterStore, PFEvent } from "@/types";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import useDetailDataStore from "@/stores/detailDataStore"; import useDetailDataStore from "@/stores/detailDataStore";
@@ -26,6 +26,33 @@ export default function PfBar() {
return mapPF[pf_config.event_id.toString()] return mapPF[pf_config.event_id.toString()]
}, [pf_config, mapPF]) }, [pf_config, mapPF])
const floorSideList = useMemo(() => {
if (!eventSelected) return [];
const floorList = [
{
id: "firstNode",
name: transI18n("firstNode"),
wave: transI18n("firstNodeEnemies")
},
{
id: "secondNode",
name: transI18n("secondNode"),
wave: transI18n("secondNodeEnemies")
},
]
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === pf_config.challenge_id) {
floorList.push({
id: "thirdNode",
name: transI18n("thirdNode"),
wave: transI18n("thirdNodeEnemies")
})
}
return floorList
}, [pf_config.challenge_id, eventSelected, transI18n])
useEffect(() => { useEffect(() => {
if (!challengeSelected || pf_config.event_id === 0 || pf_config.challenge_id === 0) { if (!challengeSelected || pf_config.event_id === 0 || pf_config.challenge_id === 0) {
@@ -50,63 +77,36 @@ export default function PfBar() {
} }
newBattleConfig.monsters = [] newBattleConfig.monsters = []
newBattleConfig.stage_id = 0 newBattleConfig.stage_id = 0
if ((pf_config.floor_side === "Upper" || pf_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID let targetEventList: PFEvent[] = []
for (const wave of challengeSelected.EventList1[0].MonsterList) { if (pf_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
targetEventList = challengeSelected.EventList1
} else if (pf_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
targetEventList = challengeSelected.EventList2
} else if (pf_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
targetEventList = eventSelected.Tierce.EventList
}
if (targetEventList.length > 0) {
newBattleConfig.stage_id = targetEventList[0].ID
for (const wave of targetEventList[0].MonsterList) {
const newWave: MonsterStore[] = [] const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) { for (const value of Object.values(wave)) {
newWave.push({ newWave.push({
monster_id: value, monster_id: value as number,
level: challengeSelected.EventList1[0].Level, level: targetEventList[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if ((pf_config.floor_side === "Lower" || pf_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) {
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
}
if (pf_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) {
for (const wave of challengeSelected.EventList1[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList1[0].Level,
amount: 1,
})
}
newBattleConfig.monsters.push(newWave)
}
} else if (pf_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) {
for (const wave of challengeSelected.EventList2[0].MonsterList) {
const newWave: MonsterStore[] = []
for (const value of Object.values(wave)) {
newWave.push({
monster_id: value,
level: challengeSelected.EventList2[0].Level,
amount: 1, amount: 1,
}) })
} }
newBattleConfig.monsters.push(newWave) newBattleConfig.monsters.push(newWave)
} }
} }
setPfConfig(newBattleConfig) setPfConfig(newBattleConfig)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
challengeSelected, challengeSelected,
eventSelected,
pf_config.event_id, pf_config.event_id,
pf_config.challenge_id, pf_config.challenge_id,
pf_config.floor_side, pf_config.floor_side,
@@ -167,10 +167,9 @@ export default function PfBar() {
onChange={(e) => setPfConfig({ ...pf_config, floor_side: e.target.value })} onChange={(e) => setPfConfig({ ...pf_config, floor_side: e.target.value })}
> >
<option value={0} disabled={true}>{transI18n("selectSide")}</option> <option value={0} disabled={true}>{transI18n("selectSide")}</option>
<option value="Upper">{transI18n("upper")}</option> {floorSideList.map((side) => (
<option value="Lower">{transI18n("lower")}</option> <option key={side.id} value={side.id}>{side.name}</option>
<option value="Upper -> Lower">{transI18n("upperToLower")}</option> ))}
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
</select> </select>
</div> </div>
</div> </div>
@@ -232,182 +231,108 @@ export default function PfBar() {
{/* Enemy Waves */} {/* Enemy Waves */}
{(pf_config?.challenge_id ?? 0) !== 0 && ( {(pf_config?.challenge_id ?? 0) !== 0 && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* First Half */} {floorSideList.map((side, i) => {
<div className="rounded-xl p-4 mt-2 border border-warning"> const eventList = side.id === "firstNode"
<h2 className="text-2xl font-bold mb-2 text-info">{transI18n("firstHalfEnemies")}</h2> ? challengeSelected?.EventList1
: side.id === "secondNode"
{challengeSelected && Object.values(challengeSelected.EventList1?.[0]?.Infinite || []).map((waveValue, waveIndex) => ( ? challengeSelected?.EventList2
<div key={waveIndex} className="mb-6"> : side.id === "thirdNode"
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3> ? eventSelected?.Tierce?.EventList
<div className="flex flex-wrap gap-2 mt-2"> : [];
{Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[monsterId.toString()],
waveValue.EliteGroup,
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
challengeSelected?.EventList1?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList1[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl"> if (!eventList || eventList.length === 0) return null;
{mapMonster?.[monsterId.toString()]?.Image?.IconPath && ( const targetEvent = eventList[0];
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[monsterId.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2"> return (
<div className="flex flex-col space-y-1.5"> <div key={i} className="rounded-xl p-4 mt-2 border border-warning">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <h2 className="text-2xl font-bold mb-2 text-info">{side.wave}</h2>
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> {targetEvent && Object.values(targetEvent.Infinite || []).map((waveValue, waveIndex) => (
<div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[monsterId.toString()],
waveValue.EliteGroup,
targetEvent?.HardLevelGroup,
targetEvent?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {targetEvent.Level}
</div> </div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
<span className="text-xs font-semibold text-info">Speed</span> {mapMonster?.[monsterId.toString()]?.Image?.IconPath && (
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> <div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[monsterId.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div> </div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg"> <div className="flex flex-col px-1 pb-2 pt-2">
<span className="text-xs font-semibold text-base-content/70">Toughness</span> <div className="flex flex-col space-y-1.5">
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span> <div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div> </div>
</div> </div>
)
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center"> })}
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5"> </div>
Weakness </div>
</span> ))}
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div>
</div>
)
})}
</div>
</div> </div>
))} )
</div> })}
{/* Second Half */}
<div className="rounded-xl p-4 mt-2 border border-warning">
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
{challengeSelected && Object.values(challengeSelected?.EventList2[0]?.Infinite || []).map((waveValue, waveIndex) => (
<div key={waveIndex} className="mb-6">
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
<div className="flex flex-wrap gap-2 mt-2">
{Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => {
const monsterStats = calcMonsterStats(
mapMonster?.[monsterId.toString()],
waveValue.EliteGroup,
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
challengeSelected?.EventList2?.[0]?.Level,
hardLevelConfig,
eliteConfig
);
return (
<div
key={enemyIndex}
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
>
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
Lv. {challengeSelected?.EventList2[0].Level}
</div>
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
{mapMonster?.[monsterId.toString()]?.Image?.IconPath && (
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
<Image
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${mapMonster?.[monsterId.toString()]?.Image?.IconPath}`}
alt="Enemy Icon"
width={150}
height={150}
className="w-full h-full object-cover"
/>
</div>
)}
</div>
<div className="flex flex-col px-1 pb-2 pt-2">
<div className="flex flex-col space-y-1.5">
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-error">HP</span>
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-info">Speed</span>
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
</div>
</div>
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
Weakness
</span>
<div className="flex items-center justify-center gap-1.5 flex-wrap">
{mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
<Image
key={iconIndex}
unoptimized
crossOrigin="anonymous"
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
alt={icon}
width={40}
height={40}
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
/>
))}
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
))}
</div>
</div> </div>
)} )}
+11 -11
View File
@@ -278,33 +278,33 @@ export default function QuickView() {
if (avatarProfile?.lightcone && mapLightCone[avatarProfile?.lightcone?.item_id]) { if (avatarProfile?.lightcone && mapLightCone[avatarProfile?.lightcone?.item_id]) {
const lightconePromotion = calcPromotion(avatarProfile?.lightcone?.level) const lightconePromotion = calcPromotion(avatarProfile?.lightcone?.level)
statsData.HP.value += calcBaseStatRaw( statsData.HP.value += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHP, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
statsData.HP.base += calcBaseStatRaw( statsData.HP.base += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHP, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHPAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
statsData.ATK.value += calcBaseStatRaw( statsData.ATK.value += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttack, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttackAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
statsData.ATK.base += calcBaseStatRaw( statsData.ATK.base += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttack, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseAttackAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
statsData.DEF.value += calcBaseStatRaw( statsData.DEF.value += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefence, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefenceAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
statsData.DEF.base += calcBaseStatRaw( statsData.DEF.base += calcBaseStatRaw(
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefence, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence,
mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseDefenceAdd, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
+6 -6
View File
@@ -95,20 +95,20 @@ export default function ShowCaseInfo() {
if (!avatarSelected || !avatarProfile?.lightcone || !mapLightCone[avatarProfile?.lightcone?.item_id]) return if (!avatarSelected || !avatarProfile?.lightcone || !mapLightCone[avatarProfile?.lightcone?.item_id]) return
const promotion = calcPromotion(avatarProfile?.lightcone?.level) const promotion = calcPromotion(avatarProfile?.lightcone?.level)
const atkStat = calcBaseStat( const atkStat = calcBaseStat(
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseAttack, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseAttack,
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseAttackAdd, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseAttackAdd,
0, 0,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
const hpStat = calcBaseStat( const hpStat = calcBaseStat(
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseHP, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseHP,
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseHPAdd, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseHPAdd,
0, 0,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
const defStat = calcBaseStat( const defStat = calcBaseStat(
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseDefence, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseDefence,
mapLightCone[avatarProfile?.lightcone?.item_id].Stats[promotion].BaseDefenceAdd, mapLightCone[avatarProfile?.lightcone?.item_id]?.Stats?.[promotion]?.BaseDefenceAdd,
0, 0,
avatarProfile?.lightcone?.level avatarProfile?.lightcone?.level
) )
+21 -6
View File
@@ -24,7 +24,10 @@ export function calcPromotion(level: number) {
} }
export function calcRarity(rarity: string) { export function calcRarity(rarity?: string) {
if (!rarity) {
return 1
}
if (rarity.includes("5")) { if (rarity.includes("5")) {
return 5 return 5
} }
@@ -40,11 +43,12 @@ export function calcRarity(rarity: string) {
export function calcMainAffixBonus(affix?: MainAffixData, level?: number) { export function calcMainAffixBonus(affix?: MainAffixData, level?: number) {
if (!affix || typeof level !== "number") return "0" if (!affix || typeof level !== "number") return "0"
const value = affix.BaseValue + affix.LevelAdd * level; const value = affix.BaseValue + affix.LevelAdd * level;
const statMeta = mappingStats[affix.Property]
if (mappingStats?.[affix.Property].unit === "%") { if (statMeta?.unit === "%") {
return (value * 100).toFixed(1); return (value * 100).toFixed(1);
} }
if (mappingStats?.[affix.Property].name === "SPD") { if (statMeta?.name === "SPD") {
return value.toFixed(1); return value.toFixed(1);
} }
@@ -53,10 +57,11 @@ export function calcMainAffixBonus(affix?: MainAffixData, level?: number) {
export const calcAffixBonus = (affix?: SubAffixData, stepCount?: number, rollCount?: number) => { export const calcAffixBonus = (affix?: SubAffixData, stepCount?: number, rollCount?: number) => {
if (!affix || typeof stepCount !== "number" || typeof rollCount !== "number") return "0" if (!affix || typeof stepCount !== "number" || typeof rollCount !== "number") return "0"
if (mappingStats?.[affix.Property].unit === "%") { const statMeta = mappingStats[affix.Property]
if (statMeta?.unit === "%") {
return ((affix.BaseValue * rollCount + affix.StepValue * stepCount) * 100).toFixed(1); return ((affix.BaseValue * rollCount + affix.StepValue * stepCount) * 100).toFixed(1);
} }
if (mappingStats?.[affix.Property].name === "SPD") { if (statMeta?.name === "SPD") {
return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(1); return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(1);
} }
return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(0); return (affix.BaseValue * rollCount + affix.StepValue * stepCount).toFixed(0);
@@ -107,6 +112,16 @@ export const calcMonsterStats = (
hardLevelConfig: Record<string, Record<string, HardLevelData>>, hardLevelConfig: Record<string, Record<string, HardLevelData>>,
eliteConfig: Record<string, EliteData> eliteConfig: Record<string, EliteData>
) => { ) => {
if (!monster?.Base || !monster?.Modify) {
return {
atk: 0,
def: 0,
hp: 0,
spd: 0,
stance: 0,
}
}
let hardLevelRatio = { let hardLevelRatio = {
AttackRatio: 1, AttackRatio: 1,
DefenceRatio:1, DefenceRatio:1,
@@ -135,4 +150,4 @@ export const calcMonsterStats = (
spd: monster.Base.SpeedBase * monster.Modify.SpeedModifyRatio * hardLevelRatio.SpeedRatio * eliteRatio.SpeedRatio, spd: monster.Base.SpeedBase * monster.Modify.SpeedModifyRatio * hardLevelRatio.SpeedRatio * eliteRatio.SpeedRatio,
stance: (monster.Base.StanceBase * monster.Modify.StanceModifyRatio * hardLevelRatio.StanceRatio * eliteRatio.StanceRatio) / 3, stance: (monster.Base.StanceBase * monster.Modify.StanceModifyRatio * hardLevelRatio.StanceRatio * eliteRatio.StanceRatio) / 3,
} }
} }
+8 -7
View File
@@ -15,7 +15,7 @@ export function converterToAvatarStore(data: Record<string, AvatarDetail>): { [k
avatar_id: Number(key), avatar_id: Number(key),
data: { data: {
rank: 0, rank: 0,
skills: Object.values(value.SkillTrees).reduce((acc, dataPointEntry) => { skills: Object.values(value.SkillTrees ?? {}).reduce((acc, dataPointEntry) => {
const firstEntry = Object.values(dataPointEntry)[0]; const firstEntry = Object.values(dataPointEntry)[0];
if (firstEntry) { if (firstEntry) {
acc[firstEntry.PointID] = firstEntry.MaxLevel; acc[firstEntry.PointID] = firstEntry.MaxLevel;
@@ -42,7 +42,8 @@ export function converterToAvatarStore(data: Record<string, AvatarDetail>): { [k
} }
export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count: number): AvatarProfileStore | null { export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count: number): AvatarProfileStore | null {
if (!data.equipment && (!data.relicList || data.relicList.length === 0)) return null const relicList = data.relicList ?? []
if (!data.equipment && relicList.length === 0) return null
const profile: AvatarProfileStore = { const profile: AvatarProfileStore = {
profile_name: `Enka Profile ${count}`, profile_name: `Enka Profile ${count}`,
lightcone: (data.equipment && data.equipment.tid) ? { lightcone: (data.equipment && data.equipment.tid) ? {
@@ -51,12 +52,12 @@ export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count:
rank: data.equipment?.rank ?? 0, rank: data.equipment?.rank ?? 0,
promotion: data.equipment?.promotion ?? 0, promotion: data.equipment?.promotion ?? 0,
} : null, } : null,
relics: Object.fromEntries(data.relicList.map((relic) => [relic.tid.toString()[relic.tid.toString().length - 1], { relics: Object.fromEntries(relicList.map((relic) => [relic.tid.toString()[relic.tid.toString().length - 1], {
level: relic.level ?? 0, level: relic.level ?? 0,
relic_id: relic.tid, relic_id: relic.tid,
relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10), relic_set_id: parseInt(relic.tid.toString().slice(1, -1), 10),
main_affix_id: relic.mainAffixId, main_affix_id: relic.mainAffixId,
sub_affixes: relic.subAffixList.map((subAffix) => ({ sub_affixes: (relic.subAffixList ?? []).map((subAffix) => ({
sub_affix_id: subAffix.affixId, sub_affix_id: subAffix.affixId,
count: subAffix.cnt, count: subAffix.cnt,
step: subAffix.step ?? 0 step: subAffix.step ?? 0
@@ -68,8 +69,8 @@ export function converterOneEnkaDataToAvatarStore(data: AvatarEnkaDetail, count:
export function converterOneFreeSRDataToAvatarStore(data: FreeSRJson, count: number , avatar_id: number): AvatarProfileStore | null { export function converterOneFreeSRDataToAvatarStore(data: FreeSRJson, count: number , avatar_id: number): AvatarProfileStore | null {
const lightcone = data.lightcones.find((lightcone) => lightcone.equip_avatar === avatar_id) const lightcone = (data.lightcones ?? []).find((lightcone) => lightcone.equip_avatar === avatar_id)
const relics = data.relics.filter((relic) => relic.equip_avatar === avatar_id) const relics = (data.relics ?? []).filter((relic) => relic.equip_avatar === avatar_id)
if (!lightcone && (!relics || relics.length === 0)) return null if (!lightcone && (!relics || relics.length === 0)) return null
const relicsMap = {} as Record<string, RelicStore> const relicsMap = {} as Record<string, RelicStore>
@@ -79,7 +80,7 @@ export function converterOneFreeSRDataToAvatarStore(data: FreeSRJson, count: num
relic_id: relic.relic_id, relic_id: relic.relic_id,
relic_set_id: relic.relic_set_id, relic_set_id: relic.relic_set_id,
main_affix_id: relic.main_affix_id, main_affix_id: relic.main_affix_id,
sub_affixes: relic.sub_affixes.map((subAffix) => ({ sub_affixes: (relic.sub_affixes ?? []).map((subAffix) => ({
sub_affix_id: subAffix.sub_affix_id, sub_affix_id: subAffix.sub_affix_id,
count: subAffix.count, count: subAffix.count,
step: subAffix.step ?? 0 step: subAffix.step ?? 0
+12 -7
View File
@@ -84,7 +84,9 @@ export function converterToFreeSRJson(
let internalUidLightcone = 0 let internalUidLightcone = 0
let internalUidRelic = 0 let internalUidRelic = 0
Object.entries(avatars).forEach(([avatarId, avatar]) => { Object.entries(avatars ?? {}).forEach(([avatarId, avatar]) => {
if (!avatar) return
const skillsByAnchorType: Record<string, number> = {} const skillsByAnchorType: Record<string, number> = {}
for (const [skillId, level] of Object.entries(avatar?.data?.skills || {})) { for (const [skillId, level] of Object.entries(avatar?.data?.skills || {})) {
if (skillConfig?.[skillId]) { if (skillConfig?.[skillId]) {
@@ -95,17 +97,20 @@ export function converterToFreeSRJson(
owner_uid: Number(avatar.owner_uid || 0), owner_uid: Number(avatar.owner_uid || 0),
avatar_id: Number(avatar.avatar_id || 0), avatar_id: Number(avatar.avatar_id || 0),
data: { data: {
rank: Number(avatar.data.rank || 0), rank: Number(avatar.data?.rank || 0),
skills: avatar.data.skills, skills: avatar.data?.skills ?? {},
skills_by_anchor_type: Object.keys(skillsByAnchorType).length > 0 ? skillsByAnchorType : undefined, skills_by_anchor_type: Object.keys(skillsByAnchorType).length > 0 ? skillsByAnchorType : undefined,
}, },
level: Number(avatar.level || 0), level: Number(avatar.level || 0),
promotion: Number(avatar.promotion || 0), promotion: Number(avatar.promotion || 0),
techniques: avatar.techniques, techniques: avatar.techniques ?? [],
sp_value: Number(avatar.sp_value || 0), sp_value: Number(avatar.sp_value || 0),
sp_max: Number(avatar.sp_max || 0), sp_max: Number(avatar.sp_max || 0),
enhanced_id: avatar.enhanced ? Number(avatar.enhanced || 0) : undefined,
} }
const currentProfile = avatar.profileList[avatar.profileSelect] const currentProfile = avatar.profileList?.[avatar.profileSelect] ?? avatar.profileList?.[0]
if (!currentProfile) return
if (currentProfile.lightcone && currentProfile.lightcone.item_id !== 0) { if (currentProfile.lightcone && currentProfile.lightcone.item_id !== 0) {
const newLightcone: LightconeJson = { const newLightcone: LightconeJson = {
level: Number(currentProfile.lightcone.level || 0), level: Number(currentProfile.lightcone.level || 0),
@@ -128,7 +133,7 @@ export function converterToFreeSRJson(
relic_id: Number(relic.relic_id || 0), relic_id: Number(relic.relic_id || 0),
relic_set_id: Number(relic.relic_set_id || 0), relic_set_id: Number(relic.relic_set_id || 0),
main_affix_id: Number(relic.main_affix_id || 0), main_affix_id: Number(relic.main_affix_id || 0),
sub_affixes: relic.sub_affixes, sub_affixes: relic.sub_affixes ?? [],
internal_uid: internalUidRelic, internal_uid: internalUidRelic,
equip_avatar: Number(avatar.avatar_id || 0), equip_avatar: Number(avatar.avatar_id || 0),
} }
@@ -146,4 +151,4 @@ export function converterToFreeSRJson(
avatars: avatarsJson, avatars: avatarsJson,
battle_config: battleJson, battle_config: battleJson,
} }
} }
-2
View File
@@ -43,8 +43,6 @@ export function getLocaleName(locale: string, data: Record<string, string> | und
return "" return ""
} }
const langKey = listCurrentLanguageApi[locale as keyof typeof listCurrentLanguageApi].toLowerCase(); const langKey = listCurrentLanguageApi[locale as keyof typeof listCurrentLanguageApi].toLowerCase();
let text = data[langKey] ?? ""; let text = data[langKey] ?? "";
+1 -1
View File
@@ -12,7 +12,7 @@ export function getSkillTree(avatarSelected: AvatarDetail | null, enhanced: stri
}, {} as Record<string, number>) }, {} as Record<string, number>)
} }
return Object.values(avatarSelected?.SkillTrees).reduce((acc, dataPointEntry) => { return Object.values(avatarSelected?.SkillTrees ?? {}).reduce((acc, dataPointEntry) => {
const firstEntry = Object.values(dataPointEntry)[0]; const firstEntry = Object.values(dataPointEntry)[0];
if (firstEntry) { if (firstEntry) {
acc[firstEntry.PointID] = firstEntry.MaxLevel; acc[firstEntry.PointID] = firstEntry.MaxLevel;
+19 -11
View File
@@ -1,15 +1,23 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function downloadJson(fileName: string, data: any) { export function downloadJson(fileName: string, data: any): boolean {
const json = JSON.stringify(data, null, 2) if (typeof document === "undefined") return false
const blob = new Blob([json], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const link = document.createElement('a') try {
link.href = url const json = JSON.stringify(data, null, 2)
link.download = `${fileName}.json` const blob = new Blob([json], { type: 'application/json' })
document.body.appendChild(link) const url = URL.createObjectURL(blob)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url) const link = document.createElement('a')
link.href = url
link.download = `${fileName}.json`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
return true
} catch (error) {
console.error("Failed to download JSON:", error)
return false
}
} }
+8 -1
View File
@@ -1,4 +1,11 @@
export function randomPartition(sum: number, parts: number): number[] { export function randomPartition(sum: number, parts: number): number[] {
if (!Number.isFinite(sum) || !Number.isInteger(parts) || parts <= 0) {
return [];
}
if (sum < parts) {
return Array.from({ length: parts }, () => 0);
}
const raw = Array.from({ length: parts }, () => Math.random()); const raw = Array.from({ length: parts }, () => Math.random());
const total = raw.reduce((a, b) => a + b, 0); const total = raw.reduce((a, b) => a + b, 0);
const result = raw.map(r => Math.floor((r / total) * (sum - parts)) + 1); const result = raw.map(r => Math.floor((r / total) * (sum - parts)) + 1);
@@ -24,4 +31,4 @@ export function randomStep(x: number): number {
total += Math.floor(Math.random() * 3); total += Math.floor(Math.random() * 3);
} }
return total; return total;
} }
+3 -2
View File
@@ -13,7 +13,8 @@ const formatValue = (value: number, format: string, floatDigits?: string, hasPer
return String(value); return String(value);
}; };
export function replaceByParam(desc: string, params: number[]): string { export function replaceByParam(desc?: string, params: number[] = []): string {
if (!desc) return "";
const PARAM_REGEX = /#(\d+)\[(f(\d+)|i)\](%)?/g; const PARAM_REGEX = /#(\d+)\[(f(\d+)|i)\](%)?/g;
@@ -35,4 +36,4 @@ export function replaceByParam(desc: string, params: number[]): string {
result = result.replace(PARAM_REGEX, processor); result = result.replace(PARAM_REGEX, processor);
return result.split("\\n").join("<br/>"); return result.split("\\n").join("<br/>");
} }
+15 -4
View File
@@ -1,5 +1,7 @@
import { create } from 'zustand' import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'; import { persist } from 'zustand/middleware';
import { connectPersistedSchema } from '@/zod';
import { createValidatedJSONStorage } from './persistStorage';
interface ConnectState { interface ConnectState {
@@ -15,8 +17,10 @@ interface ConnectState {
setPassword: (newPassword: string) => void; setPassword: (newPassword: string) => void;
} }
type ConnectPersistedState = Pick<ConnectState, "connectionType" | "privateType" | "serverUrl" | "username" | "password">;
const useConnectStore = create<ConnectState>()( const useConnectStore = create<ConnectState>()(
persist( persist<ConnectState, [], [], ConnectPersistedState>(
(set) => ({ (set) => ({
connectionType: "FireflyGo", connectionType: "FireflyGo",
privateType: "Local", privateType: "Local",
@@ -31,9 +35,16 @@ const useConnectStore = create<ConnectState>()(
}), }),
{ {
name: 'connect-storage', name: 'connect-storage',
storage: createJSONStorage(() => localStorage), storage: createValidatedJSONStorage(() => localStorage, connectPersistedSchema),
partialize: (state) => ({
connectionType: state.connectionType,
privateType: state.privateType,
serverUrl: state.serverUrl,
username: state.username,
password: state.password,
}),
} }
) )
); );
export default useConnectStore; export default useConnectStore;
+3 -3
View File
@@ -6,7 +6,7 @@ interface EnkaState {
enkaData: EnkaResponse | null; enkaData: EnkaResponse | null;
uidInput: string; uidInput: string;
setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => void; setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => void;
setEnkaData: (newEnkaData: EnkaResponse) => void; setEnkaData: (newEnkaData: EnkaResponse | null) => void;
setUidInput: (newUidInput: string) => void; setUidInput: (newUidInput: string) => void;
} }
@@ -16,7 +16,7 @@ const useEnkaStore = create<EnkaState>((set) => ({
uidInput: "", uidInput: "",
setUidInput: (newUidInput: string) => set({ uidInput: newUidInput }), setUidInput: (newUidInput: string) => set({ uidInput: newUidInput }),
setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => set({ selectedCharacters: newListAvatar }), setSelectedCharacters: (newListAvatar: CharacterInfoCardType[]) => set({ selectedCharacters: newListAvatar }),
setEnkaData: (newEnkaData: EnkaResponse) => set({ enkaData: newEnkaData }), setEnkaData: (newEnkaData: EnkaResponse | null) => set({ enkaData: newEnkaData }),
})); }));
export default useEnkaStore; export default useEnkaStore;
+14 -4
View File
@@ -1,6 +1,8 @@
import { ChangelogItemType } from '@/types'; import { ChangelogItemType } from '@/types';
import { create } from 'zustand' import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'; import { persist } from 'zustand/middleware';
import { localePersistedSchema } from '@/zod';
import { createValidatedJSONStorage } from './persistStorage';
interface LocaleState { interface LocaleState {
@@ -14,8 +16,10 @@ interface LocaleState {
setLocale: (newLocale: string) => void; setLocale: (newLocale: string) => void;
} }
type LocalePersistedState = Pick<LocaleState, "locale" | "theme" | "currentVersion" | "changelog">;
const useLocaleStore = create<LocaleState>()( const useLocaleStore = create<LocaleState>()(
persist( persist<LocaleState, [], [], LocalePersistedState>(
(set) => ({ (set) => ({
locale: "en", locale: "en",
theme: "night", theme: "night",
@@ -28,9 +32,15 @@ const useLocaleStore = create<LocaleState>()(
}), }),
{ {
name: 'locale-storage', name: 'locale-storage',
storage: createJSONStorage(() => localStorage), storage: createValidatedJSONStorage(() => localStorage, localePersistedSchema),
partialize: (state) => ({
locale: state.locale,
theme: state.theme,
currentVersion: state.currentVersion,
changelog: state.changelog,
}),
} }
) )
); );
export default useLocaleStore; export default useLocaleStore;
+79
View File
@@ -0,0 +1,79 @@
import type { PersistStorage, StateStorage, StorageValue } from "zustand/middleware";
import type { ZodType } from "zod";
export function createValidatedJSONStorage<S>(
getStorage: () => StateStorage,
stateSchema: ZodType<S>
): PersistStorage<S> | undefined {
let storage: StateStorage;
try {
storage = getStorage();
} catch {
return undefined;
}
const removeInvalidItem = (name: string, reason: string) => {
console.warn(`Invalid persisted store "${name}" was cleared: ${reason}`);
storage.removeItem(name);
};
return {
getItem: (name) => {
const raw = storage.getItem(name);
if (raw === null) {
return null;
}
if (raw instanceof Promise) {
return raw.then((value) => parseStorageValue(name, value, stateSchema, removeInvalidItem));
}
return parseStorageValue(name, raw, stateSchema, removeInvalidItem);
},
setItem: (name, value) => {
storage.setItem(name, JSON.stringify(value));
},
removeItem: (name) => {
storage.removeItem(name);
},
};
}
function parseStorageValue<S>(
name: string,
raw: string | null,
stateSchema: ZodType<S>,
removeInvalidItem: (name: string, reason: string) => void
): StorageValue<S> | null {
if (raw === null) {
return null;
}
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch {
removeInvalidItem(name, "malformed JSON");
return null;
}
if (!parsed || typeof parsed !== "object" || !("state" in parsed)) {
removeInvalidItem(name, "missing persisted state");
return null;
}
const storedValue = parsed as StorageValue<unknown>;
const state = stateSchema.safeParse(storedValue.state);
if (!state.success) {
removeInvalidItem(name, "state schema mismatch");
return null;
}
return {
state: state.data,
version: typeof storedValue.version === "number" ? storedValue.version : undefined,
};
}
+26 -4
View File
@@ -1,6 +1,8 @@
import { ASConfigStore, AvatarStore, CEConfigStore, MOCConfigStore, PEAKConfigStore, PFConfigStore } from '@/types'; import { ASConfigStore, AvatarStore, CEConfigStore, MOCConfigStore, PEAKConfigStore, PFConfigStore } from '@/types';
import { create } from 'zustand' import { create } from 'zustand'
import { createJSONStorage, persist } from 'zustand/middleware'; import { persist } from 'zustand/middleware';
import { micsSchema } from '@/zod';
import { createValidatedJSONStorage } from './persistStorage';
interface UserDataState { interface UserDataState {
@@ -21,8 +23,19 @@ interface UserDataState {
setCeConfig: (newCeConfig: CEConfigStore) => void; setCeConfig: (newCeConfig: CEConfigStore) => void;
} }
type UserDataPersistedState = Pick<
UserDataState,
| "avatars"
| "battle_type"
| "moc_config"
| "pf_config"
| "as_config"
| "peak_config"
| "ce_config"
>;
const useUserDataStore = create<UserDataState>()( const useUserDataStore = create<UserDataState>()(
persist( persist<UserDataState, [], [], UserDataPersistedState>(
(set) => ({ (set) => ({
avatars: {}, avatars: {},
battle_type: "", battle_type: "",
@@ -84,9 +97,18 @@ const useUserDataStore = create<UserDataState>()(
}), }),
{ {
name: 'user-data-storage', name: 'user-data-storage',
storage: createJSONStorage(() => localStorage), storage: createValidatedJSONStorage(() => localStorage, micsSchema),
partialize: (state) => ({
avatars: state.avatars,
battle_type: state.battle_type,
moc_config: state.moc_config,
pf_config: state.pf_config,
as_config: state.as_config,
peak_config: state.peak_config,
ce_config: state.ce_config,
}),
} }
) )
); );
export default useUserDataStore; export default useUserDataStore;
+13
View File
@@ -9,7 +9,9 @@ export interface ASGroupDetail {
EndTime: string; EndTime: string;
BuffList1: ASBuff[]; BuffList1: ASBuff[];
BuffList2: ASBuff[]; BuffList2: ASBuff[];
BuffList3: ASBuff[] | null;
Level: ASLevel[]; Level: ASLevel[];
Tierce: ASTierceLevel | null;
} }
export interface ASBuff { export interface ASBuff {
@@ -21,6 +23,16 @@ export interface ASBuff {
ExtraList?: ExtraEffect[]; ExtraList?: ExtraEffect[];
} }
export interface ASTierceLevel {
ID: number;
PreChallenge: number;
Name: Record<string, string>;
Target: ASTarget[];
DamageType: string[];
TurnLimit: number;
EventList: ASEvent[];
}
export interface ASLevel { export interface ASLevel {
Floor: number; Floor: number;
ID: number; ID: number;
@@ -35,6 +47,7 @@ export interface ASLevel {
EventList2: ASEvent[]; EventList2: ASEvent[];
Monster1: ASMonster; Monster1: ASMonster;
Monster2: ASMonster; Monster2: ASMonster;
Monster3: ASMonster | null;
} }
export interface ASTarget { export interface ASTarget {
+2 -2
View File
@@ -31,7 +31,7 @@ interface FlatProp {
interface RelicFlat { interface RelicFlat {
props: FlatProp[] props: FlatProp[]
setName: string setName: string | number
setID: number setID: number
} }
@@ -51,7 +51,7 @@ interface SkillTree {
interface EquipmentFlat { interface EquipmentFlat {
props: FlatProp[] props: FlatProp[]
name: string name: string | number
} }
interface Equipment { interface Equipment {
+11
View File
@@ -7,6 +7,17 @@ export interface MOCGroupDetail {
BeginTime: string; BeginTime: string;
EndTime: string; EndTime: string;
Level: MoCLevel[]; Level: MoCLevel[];
Tierce: MoCTierceLevel | null;
}
export interface MoCTierceLevel {
ID: number;
PreChallenge: number;
Name: Record<string, string>;
Target: MoCTarget[];
DamageType: string[];
TurnLimit: number;
EventList: MoCEvent[];
} }
export interface MoCLevel { export interface MoCLevel {
+16 -5
View File
@@ -6,7 +6,8 @@ export interface PFGroupDetail {
EndTime: string; EndTime: string;
SubOption: MazeBuff[]; SubOption: MazeBuff[];
Option: MazeBuff[]; Option: MazeBuff[];
Level: LevelData[]; Level: PFLevel[];
Tierce: PFTierceLevel | null;
} }
export interface MazeBuff { export interface MazeBuff {
@@ -17,7 +18,17 @@ export interface MazeBuff {
Desc: Record<string, string>; Desc: Record<string, string>;
} }
export interface LevelData { export interface PFTierceLevel {
ID: number;
PreChallenge: number;
Name: Record<string, string>;
Target: StoryTarget[];
DamageType: string[];
TurnLimit: number;
EventList: PFEvent[];
}
export interface PFLevel {
Floor: number; Floor: number;
ID: number; ID: number;
StageNum: number; StageNum: number;
@@ -26,8 +37,8 @@ export interface LevelData {
DamageType1: string[]; DamageType1: string[];
DamageType2: string[]; DamageType2: string[];
MazeBuff: MazeBuff[]; MazeBuff: MazeBuff[];
EventList1: StageConfig[]; EventList1: PFEvent[];
EventList2: StageConfig[]; EventList2: PFEvent[];
TurnLimit: number; TurnLimit: number;
BattleTarget: BattleTarget[]; BattleTarget: BattleTarget[];
ClearScore: number; ClearScore: number;
@@ -45,7 +56,7 @@ export interface BattleTarget {
Name: Record<string, string>; Name: Record<string, string>;
} }
export interface StageConfig { export interface PFEvent {
ID: number; ID: number;
Name: Record<string, string>; Name: Record<string, string>;
HardLevelGroup: number; HardLevelGroup: number;
+1 -1
View File
@@ -37,6 +37,7 @@ export interface AvatarJson {
techniques: number[]; techniques: number[];
sp_value: number; sp_value: number;
sp_max: number; sp_max: number;
enhanced_id?: number;
} }
export interface MonsterJson { export interface MonsterJson {
monster_id: number; monster_id: number;
@@ -49,7 +50,6 @@ export interface DynamicKeyJson {
value: number; value: number;
} }
//BattleBuff
export interface BattleBuffJson { export interface BattleBuffJson {
level: number; level: number;
id: number; id: number;
+1 -4
View File
@@ -1,5 +1,6 @@
// Generated by ts-to-zod // Generated by ts-to-zod
import { z } from "zod"; import { z } from "zod";
import { lightconeStoreSchema, relicStoreSchema } from "./mics.zod";
export const characterInfoCardTypeSchema = z.object({ export const characterInfoCardTypeSchema = z.object({
key: z.number(), key: z.number(),
@@ -18,10 +19,6 @@ export const characterInfoCardTypeSchema = z.object({
})) }))
}); });
const lightconeStoreSchema = z.any();
const relicStoreSchema = z.any();
export const avatarProfileCardTypeSchema = z.object({ export const avatarProfileCardTypeSchema = z.object({
key: z.number(), key: z.number(),
profile_name: z.string(), profile_name: z.string(),
+2 -2
View File
@@ -33,7 +33,7 @@ const flatPropSchema = z.object({
const relicFlatSchema = z.object({ const relicFlatSchema = z.object({
props: z.array(flatPropSchema), props: z.array(flatPropSchema),
setName: z.string(), setName: z.union([z.string(), z.number()]),
setID: z.number() setID: z.number()
}); });
@@ -53,7 +53,7 @@ const skillTreeSchema = z.object({
const equipmentFlatSchema = z.object({ const equipmentFlatSchema = z.object({
props: z.array(flatPropSchema), props: z.array(flatPropSchema),
name: z.string() name: z.union([z.string(), z.number()])
}); });
const equipmentSchema = z.object({ const equipmentSchema = z.object({
+1
View File
@@ -5,5 +5,6 @@ export * from "./enka.zod"
export * from "./card.zod" export * from "./card.zod"
export * from "./extraData.zod" export * from "./extraData.zod"
export * from "./showcase.zod" export * from "./showcase.zod"
export * from "./persistedStore.zod"
export * from "./srtools.zod" export * from "./srtools.zod"
+18
View File
@@ -125,4 +125,22 @@ export const micsSchema = z.object({
as_config: asConfigStoreSchema, as_config: asConfigStoreSchema,
ce_config: ceConfigStoreSchema, ce_config: ceConfigStoreSchema,
peak_config: peakConfigStoreSchema peak_config: peakConfigStoreSchema
}).superRefine((data, ctx) => {
for (const [avatarId, avatar] of Object.entries(data.avatars)) {
if (avatar.profileList.length === 0) {
ctx.addIssue({
code: "custom",
path: ["avatars", avatarId, "profileList"],
message: "profileList must contain at least one profile"
});
}
if (avatar.profileSelect < 0 || avatar.profileSelect >= avatar.profileList.length) {
ctx.addIssue({
code: "custom",
path: ["avatars", avatarId, "profileSelect"],
message: "profileSelect must point to an existing profile"
});
}
}
}); });
+24
View File
@@ -0,0 +1,24 @@
import { z } from "zod";
import type { ChangelogItemType } from "@/types";
export const changelogItemSchema: z.ZodType<ChangelogItemType> = z.object({
version: z.string(),
date: z.string(),
type: z.string(),
items: z.array(z.string()),
});
export const localePersistedSchema = z.object({
locale: z.string(),
theme: z.string(),
currentVersion: z.string(),
changelog: z.array(changelogItemSchema),
});
export const connectPersistedSchema = z.object({
connectionType: z.string(),
privateType: z.string(),
serverUrl: z.string(),
username: z.string(),
password: z.string(),
});
+2 -1
View File
@@ -40,7 +40,8 @@ export const avatarJsonSchema = z.object({
promotion: z.number(), promotion: z.number(),
techniques: z.array(z.number()), techniques: z.array(z.number()),
sp_value: z.number(), sp_value: z.number(),
sp_max: z.number() sp_max: z.number(),
enhanced_id: z.number().optional()
}); });
export const monsterJsonSchema = z.object({ export const monsterJsonSchema = z.object({