diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 948f84f..7a66ed0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,36 +47,27 @@ google-protobuf: specifier: ^3.21.2 version: 3.21.2 - i18next: - specifier: ^23.10.1 - version: 23.10.1 mobx: specifier: ^6.12.0 version: 6.12.0 mobx-react-lite: specifier: ^4.0.6 version: 4.0.6(mobx@6.12.0)(react-dom@18.2.0)(react@18.2.0) + next: + specifier: ^14.1.3 + version: 14.1.3(react-dom@18.2.0)(react@18.2.0)(sass@1.72.0) + next-intl: + specifier: ^3.9.5 + version: 3.9.5(next@14.1.3)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 react-contexify: specifier: ^6.0.0 version: 6.0.0(react-dom@18.2.0)(react@18.2.0) - react-device-detect: - specifier: ^2.2.3 - version: 2.2.3(react-dom@18.2.0)(react@18.2.0) react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) - react-i18next: - specifier: ^14.1.0 - version: 14.1.0(i18next@23.10.1)(react-dom@18.2.0)(react@18.2.0) - react-router-dom: - specifier: ^6.22.3 - version: 6.22.3(react-dom@18.2.0)(react@18.2.0) - react-scripts: - specifier: ^5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(react@18.2.0)(sass@1.72.0)(typescript@5.4.2) react-spinners: specifier: ^0.13.8 version: 0.13.8(react-dom@18.2.0)(react@18.2.0) @@ -120,6 +111,9 @@ '@types/sprintf-js': specifier: ^1.1.4 version: 1.1.4 + eslint-config-next: + specifier: ^14.1.3 + version: 14.1.3(eslint@8.57.0)(typescript@5.4.2) typescript: specifier: ^5.4.2 version: 5.4.2 @@ -238,21 +232,30 @@ dayjs: specifier: ^1.11.10 version: 1.11.10 + eslint-config-next: + specifier: ^14.1.3 + version: 14.1.3(eslint@8.57.0)(typescript@5.4.2) + next: + specifier: ^14.1.3 + version: 14.1.3(react-dom@18.2.0)(react@18.2.0)(sass@1.72.0) + next-intl: + specifier: ^3.9.5 + version: 3.9.5(next@14.1.3)(react@18.2.0) qs: specifier: ^6.12.0 version: 6.12.0 react: specifier: ^18.2.0 version: 18.2.0 - react-router-dom: - specifier: ^6.22.3 - version: 6.22.3(react-dom@18.2.0)(react@18.2.0) rollup: specifier: ^4.13.0 version: 4.13.0 tslib: specifier: ^2.6.2 version: 2.6.2 + urlcat: + specifier: ^3.1.0 + version: 3.1.0 taehui-www: dependencies: @@ -2269,6 +2272,51 @@ resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@formatjs/ecma402-abstract@1.11.4: + resolution: {integrity: sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==} + dependencies: + '@formatjs/intl-localematcher': 0.2.25 + tslib: 2.6.2 + + /@formatjs/ecma402-abstract@1.18.2: + resolution: {integrity: sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==} + dependencies: + '@formatjs/intl-localematcher': 0.5.4 + tslib: 2.6.2 + + /@formatjs/fast-memoize@1.2.1: + resolution: {integrity: sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==} + dependencies: + tslib: 2.6.2 + + /@formatjs/icu-messageformat-parser@2.1.0: + resolution: {integrity: sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + '@formatjs/icu-skeleton-parser': 1.3.6 + tslib: 2.6.2 + + /@formatjs/icu-skeleton-parser@1.3.6: + resolution: {integrity: sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + tslib: 2.6.2 + + /@formatjs/intl-localematcher@0.2.25: + resolution: {integrity: sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==} + dependencies: + tslib: 2.6.2 + + /@formatjs/intl-localematcher@0.2.32: + resolution: {integrity: sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==} + dependencies: + tslib: 2.6.2 + + /@formatjs/intl-localematcher@0.5.4: + resolution: {integrity: sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==} + dependencies: + tslib: 2.6.2 + /@humanwhocodes/config-array@0.11.14: resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -2286,6 +2334,18 @@ /@humanwhocodes/object-schema@2.0.2: resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -2609,6 +2669,87 @@ resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} dev: false + /@next/env@14.1.3: + resolution: {integrity: sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ==} + + /@next/eslint-plugin-next@14.1.3: + resolution: {integrity: sha512-VCnZI2cy77Yaj3L7Uhs3+44ikMM1VD/fBMwvTBb3hIaTIuqa+DmG4dhUDq+MASu3yx97KhgsVJbsas0XuiKyww==} + dependencies: + glob: 10.3.10 + dev: true + + /@next/swc-darwin-arm64@14.1.3: + resolution: {integrity: sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@next/swc-darwin-x64@14.1.3: + resolution: {integrity: sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@next/swc-linux-arm64-gnu@14.1.3: + resolution: {integrity: sha512-USArX9B+3rZSXYLFvgy0NVWQgqh6LHWDmMt38O4lmiJNQcwazeI6xRvSsliDLKt+78KChVacNiwvOMbl6g6BBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@next/swc-linux-arm64-musl@14.1.3: + resolution: {integrity: sha512-esk1RkRBLSIEp1qaQXv1+s6ZdYzuVCnDAZySpa62iFTMGTisCyNQmqyCTL9P+cLJ4N9FKCI3ojtSfsyPHJDQNw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@next/swc-linux-x64-gnu@14.1.3: + resolution: {integrity: sha512-8uOgRlYEYiKo0L8YGeS+3TudHVDWDjPVDUcST+z+dUzgBbTEwSSIaSgF/vkcC1T/iwl4QX9iuUyUdQEl0Kxalg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@next/swc-linux-x64-musl@14.1.3: + resolution: {integrity: sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@next/swc-win32-arm64-msvc@14.1.3: + resolution: {integrity: sha512-HjssFsCdsD4GHstXSQxsi2l70F/5FsRTRQp8xNgmQs15SxUfUJRvSI9qKny/jLkY3gLgiCR3+6A7wzzK0DBlfA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@next/swc-win32-ia32-msvc@14.1.3: + resolution: {integrity: sha512-DRuxD5axfDM1/Ue4VahwSxl1O5rn61hX8/sF0HY8y0iCbpqdxw3rB3QasdHn/LJ6Wb2y5DoWzXcz3L1Cr+Thrw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@next/swc-win32-x64-msvc@14.1.3: + resolution: {integrity: sha512-uC2DaDoWH7h1P/aJ4Fok3Xiw6P0Lo4ez7NbowW2VGNXw/Xv6tOuLUcxhBYZxsSUJtpeknCi8/fvnSpyCFp4Rcg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + /@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1: resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} dependencies: @@ -2638,6 +2779,13 @@ '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + /@pmmmwh/react-refresh-webpack-plugin@0.5.10(react-refresh@0.11.0)(webpack-dev-server@4.15.1)(webpack@5.88.1): resolution: {integrity: sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==} engines: {node: '>= 10.13'} @@ -2685,6 +2833,7 @@ /@remix-run/router@1.15.3: resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} engines: {node: '>=14.0.0'} + dev: false /@rollup/plugin-babel@5.3.1(@babel/core@7.22.9)(rollup@2.79.1): resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} @@ -2883,6 +3032,10 @@ resolution: {integrity: sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==} dev: false + /@rushstack/eslint-patch@1.7.2: + resolution: {integrity: sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==} + dev: true + /@sinclair/typebox@0.24.51: resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: false @@ -3021,6 +3174,11 @@ - supports-color dev: false + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} + dependencies: + tslib: 2.6.2 + /@tanstack/query-core@5.28.0: resolution: {integrity: sha512-BfltXqnoIAXTCFrQCu40M3Ch7odQ6IJraTy0t8n12jAwXMYKIgDwOBWTqkSUYD+vxMi8Ag0+9F8lw9wZKhi2Yg==} dev: false @@ -3232,7 +3390,6 @@ /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: false /@types/keygrip@1.0.2: resolution: {integrity: sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==} @@ -3467,7 +3624,6 @@ typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: false /@typescript-eslint/scope-manager@5.62.0: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} @@ -3475,7 +3631,6 @@ dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - dev: false /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} @@ -3500,7 +3655,6 @@ /@typescript-eslint/types@5.62.0: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: false /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.2): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} @@ -3521,7 +3675,6 @@ typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: false /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} @@ -3549,7 +3702,6 @@ dependencies: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - dev: false /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -3809,7 +3961,6 @@ /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -3827,6 +3978,11 @@ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: false @@ -3855,14 +4011,19 @@ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: dequal: 2.0.3 - dev: false /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: call-bind: 1.0.2 is-array-buffer: 3.0.2 - dev: false + + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} @@ -3881,12 +4042,51 @@ es-abstract: 1.22.1 get-intrinsic: 1.2.1 is-string: 1.0.7 - dev: false + + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.4 + is-string: 1.0.7 /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} - dev: false + + /array.prototype.filter@1.0.3: + resolution: {integrity: sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-array-method-boxes-properly: 1.0.0 + is-string: 1.0.7 + + /array.prototype.findlast@1.2.4: + resolution: {integrity: sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.findlastindex@1.2.4: + resolution: {integrity: sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 /array.prototype.flat@1.3.1: resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} @@ -3896,7 +4096,15 @@ define-properties: 1.2.0 es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 - dev: false + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 /array.prototype.flatmap@1.3.1: resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} @@ -3906,7 +4114,15 @@ define-properties: 1.2.0 es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 - dev: false + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 /array.prototype.reduce@1.0.5: resolution: {integrity: sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==} @@ -3919,6 +4135,15 @@ is-string: 1.0.7 dev: false + /array.prototype.toreversed@1.1.2: + resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + dev: true + /array.prototype.tosorted@1.1.1: resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} dependencies: @@ -3929,6 +4154,16 @@ get-intrinsic: 1.2.1 dev: false + /array.prototype.tosorted@1.1.3: + resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + dev: true + /arraybuffer.prototype.slice@1.0.1: resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} engines: {node: '>= 0.4'} @@ -3939,7 +4174,19 @@ get-intrinsic: 1.2.1 is-array-buffer: 3.0.2 is-shared-array-buffer: 1.0.2 - dev: false + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 /asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -3947,12 +4194,17 @@ /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} - dev: false /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: false + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: false @@ -3981,12 +4233,16 @@ /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - dev: false + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 /axe-core@4.7.2: resolution: {integrity: sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==} engines: {node: '>=4'} - dev: false /axios@1.6.7: resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} @@ -4002,7 +4258,6 @@ resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: dequal: 2.0.3 - dev: false /babel-jest@27.5.1(@babel/core@7.22.9): resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} @@ -4253,7 +4508,6 @@ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: false /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -4291,6 +4545,12 @@ engines: {node: '>=6'} dev: false + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + /bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -4314,7 +4574,6 @@ dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.1 - dev: false /call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} @@ -4356,7 +4615,7 @@ resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: browserslist: 4.21.9 - caniuse-lite: 1.0.30001516 + caniuse-lite: 1.0.30001597 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 dev: false @@ -4365,6 +4624,9 @@ resolution: {integrity: sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==} dev: false + /caniuse-lite@1.0.30001597: + resolution: {integrity: sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==} + /case-sensitive-paths-webpack-plugin@2.4.0: resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} engines: {node: '>=4'} @@ -4444,6 +4706,9 @@ source-map: 0.6.1 dev: false + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + /cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -4956,7 +5221,6 @@ /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dev: false /data-urls@2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} @@ -4997,7 +5261,6 @@ optional: true dependencies: ms: 2.1.3 - dev: false /debug@4.3.4(supports-color@5.5.0): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -5057,7 +5320,14 @@ dependencies: has-property-descriptors: 1.0.0 object-keys: 1.1.1 - dev: false + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -5086,7 +5356,6 @@ /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: false /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} @@ -5139,7 +5408,6 @@ engines: {node: '>=8'} dependencies: path-type: 4.0.0 - dev: false /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -5161,7 +5429,6 @@ engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 - dev: false /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} @@ -5281,6 +5548,10 @@ resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: false + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false @@ -5312,7 +5583,6 @@ /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: false /emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} @@ -5334,7 +5604,6 @@ dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: false /entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} @@ -5400,11 +5669,55 @@ typed-array-length: 1.0.4 unbox-primitive: 1.0.2 which-typed-array: 1.1.10 - dev: false + + /es-abstract@1.22.5: + resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.1 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.5 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 /es-array-method-boxes-properly@1.0.0: resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} - dev: false /es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} @@ -5416,6 +5729,27 @@ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + /es-iterator-helpers@1.0.17: + resolution: {integrity: sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==} + engines: {node: '>= 0.4'} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + globalthis: 1.0.3 + has-property-descriptors: 1.0.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + iterator.prototype: 1.1.2 + safe-array-concat: 1.1.2 + dev: true + /es-module-lexer@1.3.0: resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==} dev: false @@ -5427,13 +5761,24 @@ get-intrinsic: 1.2.1 has: 1.0.3 has-tostringtag: 1.0.0 - dev: false + + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.1 /es-shim-unscopables@1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: has: 1.0.3 - dev: false + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.1 /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -5442,7 +5787,6 @@ is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - dev: false /esbuild@0.20.1: resolution: {integrity: sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==} @@ -5507,6 +5851,31 @@ source-map: 0.6.1 dev: false + /eslint-config-next@14.1.3(eslint@8.57.0)(typescript@5.4.2): + resolution: {integrity: sha512-sUCpWlGuHpEhI0pIT0UtdSLJk5Z8E2DYinPTwsBiWaSYQomchdl0i60pjynY48+oXvtyWMQ7oE+G3m49yrfacg==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@next/eslint-plugin-next': 14.1.3 + '@rushstack/eslint-patch': 1.7.2 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2) + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.7 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.7.1(eslint@8.57.0) + eslint-plugin-react: 7.34.0(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) + typescript: 5.4.2 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - supports-color + dev: true + /eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(jest@27.5.1)(typescript@5.4.2): resolution: {integrity: sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==} engines: {node: '>=14.0.0'} @@ -5550,9 +5919,39 @@ resolve: 1.22.2 transitivePeerDependencies: - supports-color - dev: false - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.57.0): + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.13.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: 4.3.4(supports-color@5.5.0) + enhanced-resolve: 5.15.0 + eslint: 8.57.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + fast-glob: 3.3.2 + get-tsconfig: 4.7.3 + is-core-module: 2.12.1 + is-glob: 4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -5577,9 +5976,38 @@ debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - dev: false + + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + transitivePeerDependencies: + - supports-color /eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0): resolution: {integrity: sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==} @@ -5614,7 +6042,7 @@ doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) has: 1.0.3 is-core-module: 2.12.1 is-glob: 4.0.3 @@ -5629,6 +6057,40 @@ - supports-color dev: false + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2) + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.4 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + hasown: 2.0.1 + is-core-module: 2.13.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.7 + object.groupby: 1.0.2 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + /eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0)(eslint@8.57.0)(jest@27.5.1)(typescript@5.4.2): resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -5674,7 +6136,6 @@ object.entries: 1.1.6 object.fromentries: 2.0.6 semver: 6.3.1 - dev: false /eslint-plugin-react-hooks@4.6.0(eslint@8.57.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} @@ -5683,7 +6144,6 @@ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: eslint: 8.57.0 - dev: false /eslint-plugin-react@7.32.2(eslint@8.57.0): resolution: {integrity: sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==} @@ -5709,6 +6169,33 @@ string.prototype.matchall: 4.0.8 dev: false + /eslint-plugin-react@7.34.0(eslint@8.57.0): + resolution: {integrity: sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.7 + array.prototype.findlast: 1.2.4 + array.prototype.flatmap: 1.3.2 + array.prototype.toreversed: 1.1.2 + array.prototype.tosorted: 1.1.3 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.17 + eslint: 8.57.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.4 + minimatch: 3.1.2 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 + dev: true + /eslint-plugin-testing-library@5.11.0(eslint@8.57.0)(typescript@5.4.2): resolution: {integrity: sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} @@ -5961,7 +6448,16 @@ glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: false + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -6104,7 +6600,14 @@ resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 - dev: false + + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true /fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.0)(typescript@5.4.2)(webpack@5.88.1): resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} @@ -6225,11 +6728,18 @@ define-properties: 1.2.0 es-abstract: 1.22.1 functions-have-names: 1.2.3 - dev: false + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + functions-have-names: 1.2.3 /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: false /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -6247,7 +6757,6 @@ has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 - dev: false /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} @@ -6279,7 +6788,19 @@ dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.1 - dev: false + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + /get-tsconfig@4.7.3: + resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==} + dependencies: + resolve-pkg-maps: 1.0.0 /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -6297,6 +6818,18 @@ resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: false + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 + dev: true + /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} dependencies: @@ -6350,7 +6883,6 @@ engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.0 - dev: false /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -6362,7 +6894,6 @@ ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 - dev: false /google-protobuf@3.21.2: resolution: {integrity: sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==} @@ -6396,7 +6927,6 @@ /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: false /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} @@ -6410,7 +6940,6 @@ resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.1 - dev: false /has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -6421,6 +6950,10 @@ resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} @@ -6430,7 +6963,12 @@ engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 - dev: false + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} @@ -6746,7 +7284,22 @@ get-intrinsic: 1.2.1 has: 1.0.3 side-channel: 1.0.4 - dev: false + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.1 + side-channel: 1.0.6 + + /intl-messageformat@9.13.0: + resolution: {integrity: sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + '@formatjs/fast-memoize': 1.2.1 + '@formatjs/icu-messageformat-parser': 2.1.0 + tslib: 2.6.2 /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} @@ -6764,7 +7317,13 @@ call-bind: 1.0.2 get-intrinsic: 1.2.1 is-typed-array: 1.1.10 - dev: false + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -6774,11 +7333,17 @@ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} dev: false + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 - dev: false /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} @@ -6792,24 +7357,26 @@ dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: false /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - dev: false /is-core-module@2.12.1: resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} dependencies: has: 1.0.3 + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.1 + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: false /is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} @@ -6821,6 +7388,12 @@ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.7 + dev: true + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6835,7 +7408,6 @@ engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: false /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -6843,6 +7415,11 @@ dependencies: is-extglob: 2.1.1 + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: true + /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: false @@ -6850,14 +7427,16 @@ /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} - dev: false + + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: false /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} @@ -6886,7 +7465,6 @@ dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: false /is-regexp@1.0.0: resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} @@ -6898,11 +7476,21 @@ engines: {node: '>=6'} dev: false + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + dev: true + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.2 - dev: false + + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} @@ -6914,14 +7502,12 @@ engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: false /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 - dev: false /is-typed-array@1.1.10: resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} @@ -6932,17 +7518,34 @@ for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: false + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: false + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: true + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 - dev: false + + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: true /is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} @@ -6957,7 +7560,6 @@ /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: false /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -7008,6 +7610,25 @@ istanbul-lib-report: 3.0.0 dev: false + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.5 + set-function-name: 2.0.2 + dev: true + + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /jake@10.8.7: resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==} engines: {node: '>=10'} @@ -7715,7 +8336,6 @@ hasBin: true dependencies: minimist: 1.2.8 - dev: false /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} @@ -7744,7 +8364,6 @@ array.prototype.flat: 1.3.1 object.assign: 4.1.4 object.values: 1.1.6 - dev: false /keygrip@1.1.0: resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} @@ -7848,13 +8467,11 @@ /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} - dev: false /language-tags@1.0.5: resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} dependencies: language-subtag-registry: 0.3.22 - dev: false /launch-editor@2.6.0: resolution: {integrity: sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==} @@ -7972,7 +8589,6 @@ /lru-cache@10.0.1: resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==} engines: {node: 14 || >=16.14} - dev: false /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -8047,7 +8663,6 @@ /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: false /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} @@ -8110,9 +8725,20 @@ brace-expansion: 2.0.1 dev: false + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: false + + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} @@ -8157,7 +8783,6 @@ /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: false /multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} @@ -8179,7 +8804,6 @@ resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -8191,12 +8815,62 @@ /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - dev: false /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: false + /next-intl@3.9.5(next@14.1.3)(react@18.2.0): + resolution: {integrity: sha512-tsp4N433WgTAbbyZdMlcsLGHFM88wv2a7ZpF/od8X9+qAlO1TrajZrNrGBpIg6nA9EGZyMbQPzZD7XZrqYIv7g==} + peerDependencies: + next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@formatjs/intl-localematcher': 0.2.32 + negotiator: 0.6.3 + next: 14.1.3(react-dom@18.2.0)(react@18.2.0)(sass@1.72.0) + react: 18.2.0 + use-intl: 3.9.5(react@18.2.0) + + /next@14.1.3(react-dom@18.2.0)(react@18.2.0)(sass@1.72.0): + resolution: {integrity: sha512-oexgMV2MapI0UIWiXKkixF8J8ORxpy64OuJ/J9oVUmIthXOUCcuVEZX+dtpgq7wIfIqtBwQsKEDXejcjTsan9g==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.1.3 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 + caniuse-lite: 1.0.30001597 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + sass: 1.72.0 + styled-jsx: 5.1.1(react@18.2.0) + optionalDependencies: + '@next/swc-darwin-arm64': 14.1.3 + '@next/swc-darwin-x64': 14.1.3 + '@next/swc-linux-arm64-gnu': 14.1.3 + '@next/swc-linux-arm64-musl': 14.1.3 + '@next/swc-linux-x64-gnu': 14.1.3 + '@next/swc-linux-x64-musl': 14.1.3 + '@next/swc-win32-arm64-msvc': 14.1.3 + '@next/swc-win32-ia32-msvc': 14.1.3 + '@next/swc-win32-x64-msvc': 14.1.3 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: @@ -8281,7 +8955,6 @@ /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - dev: false /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} @@ -8290,7 +8963,6 @@ /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - dev: false /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -8298,7 +8970,6 @@ /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - dev: false /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -8308,7 +8979,15 @@ define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: false + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 /object.entries@1.1.6: resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} @@ -8317,7 +8996,15 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true /object.fromentries@2.0.6: resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} @@ -8326,7 +9013,14 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 /object.getownpropertydescriptors@2.1.6: resolution: {integrity: sha512-lq+61g26E/BgHv0ZTFgRvi7NMEPuAxLkFU7rukXjc/AlwH4Am5xXVnIXy3un1bg/JPbXHrixRkK1itUzzPiIjQ==} @@ -8339,6 +9033,15 @@ safe-array-concat: 1.0.0 dev: false + /object.groupby@1.0.2: + resolution: {integrity: sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==} + dependencies: + array.prototype.filter: 1.0.3 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + /object.hasown@1.1.2: resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: @@ -8346,6 +9049,13 @@ es-abstract: 1.22.1 dev: false + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + /object.values@1.1.6: resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} engines: {node: '>= 0.4'} @@ -8353,7 +9063,14 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 /obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} @@ -8518,6 +9235,14 @@ /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.0.1 + minipass: 7.0.4 + dev: true + /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} dev: false @@ -8529,7 +9254,6 @@ /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - dev: false /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -8541,7 +9265,6 @@ /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: false /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -8571,6 +9294,10 @@ find-up: 3.0.0 dev: false + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + /postcss-attribute-case-insensitive@5.0.2(postcss@8.4.26): resolution: {integrity: sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==} engines: {node: ^12 || ^14 || >=16} @@ -9348,6 +10075,14 @@ source-map-js: 1.0.2 dev: false + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -9422,7 +10157,6 @@ loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: false /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} @@ -9584,17 +10318,6 @@ - vue-template-compiler dev: false - /react-device-detect@2.2.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==} - peerDependencies: - react: '>= 0.14.0' - react-dom: '>= 0.14.0' - dependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - ua-parser-js: 1.0.35 - dev: false - /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -9643,7 +10366,6 @@ /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: false /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -9682,6 +10404,7 @@ react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-router: 6.22.3(react@18.2.0) + dev: false /react-router@6.22.3(react@18.2.0): resolution: {integrity: sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==} @@ -9691,6 +10414,7 @@ dependencies: '@remix-run/router': 1.15.3 react: 18.2.0 + dev: false /react-scripts@5.0.1(@babel/plugin-syntax-flow@7.23.3)(@babel/plugin-transform-react-jsx@7.23.4)(eslint@8.57.0)(react@18.2.0)(sass@1.72.0)(typescript@5.4.2): resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==} @@ -9900,6 +10624,19 @@ minimatch: 3.1.2 dev: false + /reflect.getprototypeof@1.0.5: + resolution: {integrity: sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -9935,7 +10672,15 @@ call-bind: 1.0.2 define-properties: 1.2.0 functions-have-names: 1.2.3 - dev: false + + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 /regexpu-core@5.3.2: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} @@ -9999,6 +10744,9 @@ engines: {node: '>=8'} dev: false + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + /resolve-url-loader@4.0.0: resolution: {integrity: sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==} engines: {node: '>=8.9'} @@ -10031,6 +10779,14 @@ path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + /resolve@2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true @@ -10040,6 +10796,15 @@ supports-preserve-symlinks-flag: 1.0.0 dev: false + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -10118,7 +10883,15 @@ get-intrinsic: 1.2.1 has-symbols: 1.0.3 isarray: 2.0.5 - dev: false + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -10134,7 +10907,14 @@ call-bind: 1.0.2 get-intrinsic: 1.2.1 is-regex: 1.1.4 - dev: false + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 /safe-stable-stringify@2.4.3: resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} @@ -10250,7 +11030,6 @@ /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - dev: false /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -10330,6 +11109,15 @@ gopd: 1.0.1 has-property-descriptors: 1.0.2 + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + /setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} dev: false @@ -10357,7 +11145,6 @@ call-bind: 1.0.2 get-intrinsic: 1.2.1 object-inspect: 1.12.3 - dev: false /side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} @@ -10372,6 +11159,11 @@ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: false + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} dependencies: @@ -10522,6 +11314,10 @@ engines: {node: '>= 0.8'} dev: false + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -10550,6 +11346,29 @@ is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + regexp.prototype.flags: 1.5.0 + set-function-name: 2.0.2 + side-channel: 1.0.6 + dev: true + /string.prototype.matchall@4.0.8: resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: @@ -10570,7 +11389,14 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} @@ -10578,7 +11404,13 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 /string.prototype.trimstart@1.0.6: resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} @@ -10586,7 +11418,13 @@ call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.22.1 - dev: false + + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.22.5 /string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -10620,12 +11458,10 @@ engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: false /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: false /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} @@ -10655,6 +11491,22 @@ webpack: 5.88.1 dev: false + /styled-jsx@5.1.1(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + client-only: 0.0.1 + react: 18.2.0 + /stylehacks@5.1.1(postcss@8.4.26): resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} engines: {node: ^10 || ^12 || >=14.0} @@ -10796,7 +11648,6 @@ /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - dev: false /temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} @@ -10975,9 +11826,16 @@ strip-bom: 3.0.0 dev: false + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: false /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -10995,7 +11853,6 @@ dependencies: tslib: 1.14.1 typescript: 5.4.2 - dev: false /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -11037,7 +11894,14 @@ call-bind: 1.0.2 get-intrinsic: 1.2.1 is-typed-array: 1.1.10 - dev: false + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 /typed-array-byte-length@1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} @@ -11047,7 +11911,16 @@ for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.10 - dev: false + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 /typed-array-byte-offset@1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} @@ -11058,7 +11931,17 @@ for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.10 - dev: false + + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} @@ -11066,7 +11949,17 @@ call-bind: 1.0.2 for-each: 0.3.3 is-typed-array: 1.1.10 - dev: false + + /typed-array-length@1.0.5: + resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 /typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} @@ -11079,10 +11972,6 @@ engines: {node: '>=14.17'} hasBin: true - /ua-parser-js@1.0.35: - resolution: {integrity: sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==} - dev: false - /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -11090,7 +11979,6 @@ has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: false /undefsafe@2.0.5: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} @@ -11176,6 +12064,12 @@ requires-port: 1.0.0 dev: false + /urlcat@3.1.0: + resolution: {integrity: sha512-qY6b94/aGMIHh70EEQ/4hfR2LUGZ+fPQNp64cf7yRX9kAp4XG2tx7LgYUU1Qkh17bFylME0u4n3lOezonougPw==} + dependencies: + qs: 6.12.0 + dev: true + /use-composed-ref@1.3.0(react@18.2.0): resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} peerDependencies: @@ -11184,6 +12078,15 @@ react: 18.2.0 dev: false + /use-intl@3.9.5(react@18.2.0): + resolution: {integrity: sha512-1g+f/pKEeXqOXrd+QBvwnIN5kzM56PHsorbVWzNvlnGk2fo/eRwuuT/S0jTuzKLRW4uNybpHvRs6U06rP31iKw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@formatjs/ecma402-abstract': 1.18.2 + intl-messageformat: 9.13.0 + react: 18.2.0 + /use-isomorphic-layout-effect@1.1.2(@types/react@18.2.65)(react@18.2.0): resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==} peerDependencies: @@ -11513,7 +12416,34 @@ is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: false + + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.5 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.10 + dev: true + + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + dev: true /which-typed-array@1.1.10: resolution: {integrity: sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==} @@ -11525,7 +12455,16 @@ gopd: 1.0.1 has-tostringtag: 1.0.0 is-typed-array: 1.1.10 - dev: false + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} @@ -11752,6 +12691,15 @@ string-width: 4.2.3 strip-ansi: 6.0.1 + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} diff --git a/qwilight-fe/.eslintrc.json b/qwilight-fe/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/qwilight-fe/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/qwilight-fe/.gitignore b/qwilight-fe/.gitignore index 201c98c..741a54f 100644 --- a/qwilight-fe/.gitignore +++ b/qwilight-fe/.gitignore @@ -4,23 +4,36 @@ /node_modules /.pnp .pnp.js +.yarn/install-state.gz # testing /coverage +# next.js +/.next/ +/out/ + # production /build # misc .DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local +*.pem +# debug npm-debug.log* yarn-debug.log* yarn-error.log* -/.env -/.turbo +# local env files +.env*.local +.env.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +.turbo diff --git a/qwilight-fe/next-env.d.ts b/qwilight-fe/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/qwilight-fe/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/qwilight-fe/next.config.mjs b/qwilight-fe/next.config.mjs new file mode 100644 index 0000000..19c53ea --- /dev/null +++ b/qwilight-fe/next.config.mjs @@ -0,0 +1,22 @@ +import createNextIntlPlugin from 'next-intl/plugin'; + +export default createNextIntlPlugin()({ + async rewrites() { + return [ + { + source: "/www/:path", + destination: `${process.env.API ?? "https://taehui.ddns.net"}/qwilight/www/:path` + }, + ] + }, + async redirects() { + return [ + { + source: "/", + destination: "/note", + permanent: true + }, + ] + }, + basePath: "/qwilight" +}); diff --git a/qwilight-fe/package.json b/qwilight-fe/package.json index 6735483..b09a091 100644 --- a/qwilight-fe/package.json +++ b/qwilight-fe/package.json @@ -10,16 +10,13 @@ "crypto-js": "^4.2.0", "dompurify": "^3.0.9", "google-protobuf": "^3.21.2", - "i18next": "^23.10.1", "mobx": "^6.12.0", "mobx-react-lite": "^4.0.6", + "next": "^14.1.3", + "next-intl": "^3.9.5", "react": "^18.2.0", "react-contexify": "^6.0.0", - "react-device-detect": "^2.2.3", "react-dom": "^18.2.0", - "react-i18next": "^14.1.0", - "react-router-dom": "^6.22.3", - "react-scripts": "^5.0.1", "react-spinners": "^0.13.8", "react-toastify": "^10.0.4", "reactstrap": "^9.2.2", @@ -36,12 +33,14 @@ "@types/react-dom": "^18.2.22", "@types/react-router-dom": "^5.3.3", "@types/sprintf-js": "^1.1.4", + "eslint-config-next": "^14.1.3", "typescript": "^5.4.2" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "eject": "react-scripts eject", + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", "deploy": "qwilight-fe.cmd" }, "eslintConfig": { @@ -61,6 +60,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "homepage": "qwilight" + } } diff --git a/qwilight-fe/src/AvatarDrawing.tsx b/qwilight-fe/src/AvatarDrawing.tsx index b331976..e4e39cd 100644 --- a/qwilight-fe/src/AvatarDrawing.tsx +++ b/qwilight-fe/src/AvatarDrawing.tsx @@ -1,7 +1,8 @@ -import { wwwAPI } from "src/Www"; -import { getDefaultAvatarID } from "src/Utility"; +import { wwwAPI } from "@/Www"; +import { getDefaultAvatarID } from "@/Utility"; -import scss from "src/AvatarDrawing.module.scss"; +import scss from "@/AvatarDrawing.module.scss"; +import Image from "next/image"; const EDGE_MARGIN = 1.25; const EDGE_XY = (EDGE_MARGIN - 1.0) / 2; @@ -23,7 +24,7 @@ height: drawingHeight * EDGE_MARGIN, }} > - - 만약 불법 BMS/BMSON 노트 파일을 발견하시면 %s로 알려주시면 삭제합니다.", - "commentSiteName": "성과 알림방", - "defaultSiteName": "일반 대화방", - "enterSite": "입장하기", - "etcAutoMode": "턴 테이블", - "etcAvatar": "활동 사용자 추세", - "etcFaintNoteMode": "노트 시각", - "etcFavorites": "선호곡 TOP 10", - "etcFavoritesAt": "이번 달 선호곡 TOP 10", - "etcHitPointsMode": "라이프 게이지", - "etcInputFavorMode": "라인 개수 수정", - "etcInputMode": "노트 라인", - "etcJudgmentMode": "판정 난이도", - "etcLongNoteMode": "롱 노트 떼는 판정", - "etcLowestJudgmentConditionMode": "간접 미스", - "etcNoteMobilityMode": "노트 무질서도", - "etcNoteModifyMode": "노트 수정", - "etcNoteSaltMode": "노트 배치", - "etcSignUp": "신규 가입 추세", - "etcTotal": "플레이 추세", - "etcTotalEdges": "프레임 TOP 10", - "etcTotalNoteFiles": "이번 달 인기곡 TOP 10", - "etcTotalTitles": "호칭 TOP 10", - "exileAvatar": "추방", - "highestCountText": "기록 개수: %s 개", - "hofAbilityText": "레이팅", - "hofAtText": "이번 달", - "hofBand": "콤보", - "hofHighest": "기록", - "hofLevelText": "레벨", - "hofStand": "점수", - "hofTotal": "플레이", - "hofTotalText": "전체", - "inputNewSite": "대화방 만들기", - "notAvatarViewFault": "비회원의 프로필은 제공되지 않습니다.", - "notSignedInText": "%s님 감사합니다.", - "notSignIn": "로그아웃", - "onAvatars": "사용자 목록", - "onClose": "지우기", - "onConfigure": "환경 설정", - "onSiteWindow": "대화방 목록", - "onWant": "검색", - "onWantMe": "내 프로필 보기", - "platformSiteName": "디스코드 대화방", - "point": "정확도", - "postFile": "파일 업로드", - "quitSite": "방 나가기", - "save": "저장하기", - "setSiteHand": "방장 위임", - "setSiteName": "방 이름 수정", - "setSiteNameText": "수정할 이름을 입력하세요", - "signedInText": "%s님 환영합니다.", - "signIn": "로그인", - "signInCipher": "비밀번호", - "signInID": "아이디", - "silentSiteNew": "1대1 대화", - "siteAudio": "알림 사운드", - "siteAutoEnterDefault": "일반 대화방 자동 입장", - "siteAutoEnterNotify": "알림방 자동 입장", - "siteAutoEnterPlatform": "디스코드 대화방 자동 입장", - "siteCipher": "대화방 비밀번호", - "siteName": "대화방 이름", - "siteSaveTraffic": "데이터 절약 모드", - "siteWindowNew": "대화방 만들기", - "siteYellEnter": "입장함", - "siteYellInvite": "저랑 같이 %s 에서 멀티 플레이 하려면 클릭하세요", - "siteYellNewNetSite": "새 게임방을 만듦", - "siteYellNewSite": "새 대화방을 만듦", - "siteYellQuit": "퇴장함", - "siteYellTaehui": "개발자", - "siteYellTV": "Qwilight 방송 %s을 보려면 클릭하세요", - "stand": "점수", - "textBand": "%s 콤보", - "textCount": "%s 개", - "textHandled": "%s 회", - "textStand": "%s 점", - "toAvatar": "온라인 프로필", - "toEtc": "통계", - "toFit0": "기록 개수순", - "toFit1": "플레이 횟수순", - "toFit2": "업데이트순", - "toFit3": "제목순", - "toFit4": "아티스트순", - "toFit5": "장르순", - "toFit6": "난이도순", - "toHOF": "명예의 전당", - "toilNoteFile": "불법 BMS, BMSON 노트 파일로 신고", - "toilNoteFileText": "신고 사유를 적어주세요", - "toNote": "온라인 랭킹", - "toNotifySiteName": "알림방", - "toSite": "온라인 대화", - "toSrc0": "제목으로", - "toSrc1": "닉네임으로", - "toSrc2": "아티스트로", - "toSrc3": "장르로", - "totalCountText": "플레이 횟수: %s 회", - "totalLengthText": "플레이 시간: %d 시간 %d 분 %d 초", - "viewAvatarView": "프로필 보기", - "wantAvatarAssist": "검색할 닉네임을 입력하세요", - "wipedSiteYell": "삭제된 메시지입니다.", - "wwwLevel": "도전 과제", - "wwwLevelClearText": "도전 과제 %s 클리어! 축하합니다." - } - }, - "en-US": { - "translation": { - "abilityFittedText": "%s Points (+ %s Points)", - "audioMultiplier": "Music speed", - "autoSignIn": "Automatic login", - "avatarAbilitiesText": "Rating TOP 50", - "avatarCountText": "%d people", - "avatarDate": "Last Connection Date: %s", - "avatarDateText": "Activity Trends", - "avatarFavoritesText": "Most plays TOP 50", - "avatarIntroText": "Introduce yourself", - "avatarLastsText": "Last plays TOP 50", - "avatarQuitStatusText": "Rank", - "bannedNoteFile": "Illegal BMS and BMSON note files are filtered by themselves by checking the number of key notes.
If you find illegal BMS/BMSON note file, please let us know via %s and delete it.", - "commentSiteName": "Performance notification room", - "defaultSiteName": "General chat room", - "enterSite": "Enter", - "etcAutoMode": "Turntable", - "etcAvatar": "Activity User Trends", - "etcFaintNoteMode": "Note time", - "etcFavorites": "Favorite songs TOP 10", - "etcFavoritesAt": "Favorite songs TOP 10 for this month", - "etcHitPointsMode": "Life Gauge", - "etcInputFavorMode": "Modifying the number of lines", - "etcInputMode": "Note line", - "etcJudgmentMode": "Difficulty level of judgment", - "etcLongNoteMode": "Judgment of taking long notes", - "etcLowestJudgmentConditionMode": "Indirect miss", - "etcNoteMobilityMode": "Even the disorder of notes", - "etcNoteModifyMode": "Modifying Notes", - "etcNoteSaltMode": "Place notes", - "etcSignUp": "New Subscription Trends", - "etcTotal": "Play trend", - "etcTotalEdges": "Frames TOP 10", - "etcTotalNoteFiles": "Popular Songs TOP 10 for this month", - "etcTotalTitles": "Titles TOP 10", - "exileAvatar": "Kick", - "highestCountText": "Record count: %s", - "hofAbilityText": "Rating", - "hofAtText": "Month", - "hofBand": "Combo", - "hofHighest": "Record", - "hofLevelText": "Level", - "hofStand": "Score", - "hofTotal": "Play", - "hofTotalText": "All", - "inputNewSite": "Create Chat Room", - "notAvatarViewFault": "Non-member profiles are not available.", - "notSignedInText": "Thank you, %s.", - "notSignIn": "Sign out", - "onAvatars": "User list.", - "onClose": "Clear", - "onConfigure": "Preferences", - "onSiteWindow": "Chat Room List", - "onWant": "Search", - "onWantMe": "View My Profile", - "platformSiteName": "Discord Chat Room", - "point": "Accuracy", - "postFile": "Upload File", - "quitSite": "Leaving the room", - "save": "Save", - "setSiteHand": "Delegation of the Director", - "setSiteName": "Modify Room Name", - "setSiteNameText": "Please enter a name to modify", - "signedInText": "Welcome, %s.", - "signIn": "Login", - "signInCipher": "Password", - "signInID": "ID", - "silentSiteNew": "One-on-one conversation", - "siteAudio": "Alarm sound.", - "siteAutoEnterDefault": "Automatically enter the regular chat room.", - "siteAutoEnterNotify": "Automatically enter the notification room.", - "siteAutoEnterPlatform": "Automatic entry to discode chat room", - "siteCipher": "Chat Room Password", - "siteName": "Chat Room Name", - "siteSaveTraffic": "Data saving mode.", - "siteWindowNew": "Create Chat Room", - "siteYellEnter": "Entered", - "siteYellInvite": "Click to play multiple games with me on %s.", - "siteYellNewNetSite": "Create a new game room", - "siteYellNewSite": "Create a new chat room", - "siteYellQuit": "Exited", - "siteYellTaehui": "Developer", - "siteYellTV": "Click to watch Qwilight broadcast %s", - "stand": "Score", - "textBand": "%s combo", - "textCount": "%s", - "textHandled": "%s times", - "textStand": "%s point", - "toAvatar": "Online Profile", - "toEtc": "Statistics", - "toFit0": "Sequence of records", - "toFit1": "Number of plays", - "toFit2": "Update order", - "toFit3": "Subject order", - "toFit4": "Artist order", - "toFit5": "Genre order", - "toFit6": "Difficulty order", - "toHOF": "Hall of Fame", - "toilNoteFile": "Illegal BMS, reported as BMSON note file", - "toilNoteFileText": "Please write down the reason for the report", - "toNote": "Online Ranking", - "toNotifySiteName": "Notification room", - "toSite": "Online Chat", - "toSrc0": "As a title", - "toSrc1": "As a nickname", - "toSrc2": "As an artist", - "toSrc3": "As a genre", - "totalCountText": "Number of plays: %s.", - "totalLengthText": "Playtime: %d hours %d minutes %d seconds", - "viewAvatarView": "View Profiles", - "wantAvatarAssist": "Enter nickname to search", - "wipedSiteYell": "Deleted message.", - "wwwLevel": "Challenges", - "wwwLevelClearText": "Challenge %s cleared! Congratulations." - } - } -} diff --git a/qwilight-fe/src/Loading.tsx b/qwilight-fe/src/Loading.tsx index 057da13..03b970b 100644 --- a/qwilight-fe/src/Loading.tsx +++ b/qwilight-fe/src/Loading.tsx @@ -1,54 +1,6 @@ -import BarLoader from "react-spinners/BarLoader"; -import { useTranslation } from "react-i18next"; -import { Badge, Col, ListGroup, ListGroupItem, Row } from "reactstrap"; -import NoteItem from "src/note/NoteItem"; -import AvatarItem from "src/hof/AvatarItem"; -import WwwLevelItem from "src/avatar/WwwLevelItem"; - -const LoadingLayer = ({ text }: { text: string }) => { - return ( - - - - {text} - - - - - - - ); -}; - -export const NoteViewLoading = () => { - const { t } = useTranslation(); - - return ; -}; - -export const SiteViewLoading = () => { - const { t } = useTranslation(); - - return ; -}; - -export const AvatarViewLoading = () => { - const { t } = useTranslation(); - - return ; -}; - -export const HOFViewLoading = () => { - const { t } = useTranslation(); - - return ; -}; - -export const EtcViewLoading = () => { - const { t } = useTranslation(); - - return ; -}; +import NoteItem from "@/note/NoteItem"; +import AvatarItem from "@/hof/AvatarItem"; +import WwwLevelItem from "@/avatar/WwwLevelItem"; export const NoteLoading = ({ loadingCount }: { loadingCount: number }) => { return [...Array(loadingCount).keys()].map((i) => ( @@ -64,11 +16,7 @@ )); }; -export const AvatarWwwLevelLoading = ({ - loadingCount, -}: { - loadingCount: number; -}) => { +export const WwwLevelLoading = ({ loadingCount }: { loadingCount: number }) => { return [...Array(loadingCount).keys()].map((i) => ( { +export const AvatarLoading = ({ loadingCount }: { loadingCount: number }) => { return [...Array(loadingCount).keys()].map((i) => ( )); diff --git a/qwilight-fe/src/LoadingLayer.tsx b/qwilight-fe/src/LoadingLayer.tsx new file mode 100644 index 0000000..634fa36 --- /dev/null +++ b/qwilight-fe/src/LoadingLayer.tsx @@ -0,0 +1,17 @@ +import { Badge, Col, ListGroup, ListGroupItem, Row } from "reactstrap"; +import BarLoader from "react-spinners/BarLoader"; + +export default function LoadingLayer({ text }: { text: string }) { + return ( + + + + {text} + + + + + + + ); +} diff --git a/qwilight-fe/src/QwilightView.tsx b/qwilight-fe/src/QwilightView.tsx new file mode 100644 index 0000000..9dbda1c --- /dev/null +++ b/qwilight-fe/src/QwilightView.tsx @@ -0,0 +1,87 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { ReactNode, useEffect, useRef } from "react"; +import { Button, Col, Container, Navbar, NavbarBrand, Row } from "reactstrap"; +import { ToastContainer } from "react-toastify"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +import SignInWindow from "@/site/SignInWindow"; +import useSiteComponent from "@/site/useSiteComponent"; + +import platform from "@/assets/discord-logo-white.png"; +import { useTranslations } from "next-intl"; +import { useIsPath } from "taehui-ts/fe-utility"; +import { useSiteStore } from "@/Stores"; + +const queryClient = new QueryClient(); + +export default function QwilightView({ children }: { children: ReactNode }) { + const t = useTranslations(); + const titleComponent = useRef(null); + const siteYellsView = useRef(null); + const { setComponents } = useSiteStore(); + + useSiteComponent(); + + const isPath = useIsPath(); + + const getColor = (route: string) => (isPath(route) ? "primary" : "secondary"); + + const onPlatform = () => { + window.open("https://taehui.ddns.net/qwilight/platform"); + }; + + useEffect(() => { + setComponents(titleComponent, siteYellsView); + }, [setComponents]); + + return ( + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {children} + + + +
+ ); +} diff --git a/qwilight-fe/src/Stores.tsx b/qwilight-fe/src/Stores.tsx index cac87d1..7833401 100644 --- a/qwilight-fe/src/Stores.tsx +++ b/qwilight-fe/src/Stores.tsx @@ -1,17 +1,20 @@ +"use client"; + import { createContext, FC, PropsWithChildren, useContext } from "react"; import { useLocalObservable } from "mobx-react-lite"; -import setSiteStore from "src/site/setSiteStore"; -import setNoteStore from "src/note/setNoteStore"; -import setAvatarStore from "src/avatar/setAvatarStore"; -import setEtcStore from "src/etc/setEtcStore"; -import setHOFStore from "src/hof/setHOFStore"; + +import setSiteStore from "@/site/setSiteStore"; +import setNoteStore from "@/note/setNoteStore"; +import setAvatarStore from "@/avatar/setAvatarStore"; +import setHOFStore from "@/hof/setHOFStore"; +import setEtcStore from "@/etc/setEtcStore"; type QwilightStore = { noteStore: ReturnType; siteStore: ReturnType; avatarStore: ReturnType; - etcStore: ReturnType; hofStore: ReturnType; + etcStore: ReturnType; }; const qwilightStore = createContext({} as QwilightStore); @@ -23,8 +26,8 @@ noteStore: useLocalObservable(setNoteStore), siteStore: useLocalObservable(setSiteStore), avatarStore: useLocalObservable(setAvatarStore), - etcStore: useLocalObservable(setEtcStore), hofStore: useLocalObservable(setHOFStore), + etcStore: useLocalObservable(setEtcStore), }} > {children} @@ -37,6 +40,6 @@ export const useAvatarStore = () => useContext(qwilightStore).avatarStore; -export const useEtcStore = () => useContext(qwilightStore).etcStore; - export const useHOFStore = () => useContext(qwilightStore).hofStore; + +export const useEtcStore = () => useContext(qwilightStore).etcStore; diff --git a/qwilight-fe/src/Utility.ts b/qwilight-fe/src/Utility.ts index 0900d86..1da1911 100644 --- a/qwilight-fe/src/Utility.ts +++ b/qwilight-fe/src/Utility.ts @@ -1,68 +1,67 @@ -import { TFunction } from "i18next"; - -import i4 from "src/assets/i4.png"; -import i5 from "src/assets/i5.png"; -import i6 from "src/assets/i6.png"; -import i7 from "src/assets/i7.png"; -import i8 from "src/assets/i8.png"; -import i9 from "src/assets/i9.png"; -import i10 from "src/assets/i10.png"; -import i11 from "src/assets/i11.png"; -import i12 from "src/assets/i12.png"; -import i13 from "src/assets/i13.png"; -import i14 from "src/assets/i14.png"; -import i15 from "src/assets/i15.png"; -import i16 from "src/assets/i16.png"; -import m00 from "src/assets/m00.png"; -import m01 from "src/assets/m01.png"; -import m10 from "src/assets/m10.png"; -import m11 from "src/assets/m11.png"; -import m12 from "src/assets/m12.png"; -import m14 from "src/assets/m14.png"; -import m111 from "src/assets/m111.png"; -import m113 from "src/assets/m113.png"; -import m20 from "src/assets/m20.png"; -import m21 from "src/assets/m21.png"; -import m22 from "src/assets/m22.png"; -import m23 from "src/assets/m23.png"; -import m30 from "src/assets/m30.png"; -import m31 from "src/assets/m31.png"; -import m32 from "src/assets/m32.png"; -import m33 from "src/assets/m33.png"; -import m34 from "src/assets/m34.png"; -import m40 from "src/assets/m40.png"; -import m41 from "src/assets/m41.png"; -import m42 from "src/assets/m42.png"; -import m43 from "src/assets/m43.png"; -import m44 from "src/assets/m44.png"; -import m45 from "src/assets/m45.png"; -import m47 from "src/assets/m47.png"; -import m50 from "src/assets/m50.png"; -import m51 from "src/assets/m51.png"; -import m53 from "src/assets/m53.png"; -import m54 from "src/assets/m54.png"; -import m55 from "src/assets/m55.png"; -import m60 from "src/assets/m60.png"; -import m61 from "src/assets/m61.png"; -import m70 from "src/assets/m70.png"; -import m74 from "src/assets/m74.png"; -import m75 from "src/assets/m75.png"; -import m76 from "src/assets/m76.png"; -import m77 from "src/assets/m77.png"; -import m78 from "src/assets/m78.png"; -import m79 from "src/assets/m79.png"; -import m710 from "src/assets/m710.png"; -import m711 from "src/assets/m711.png"; -import m712 from "src/assets/m712.png"; -import m713 from "src/assets/m713.png"; -import m714 from "src/assets/m714.png"; -import m715 from "src/assets/m715.png"; -import m716 from "src/assets/m716.png"; -import m80 from "src/assets/m80.png"; -import m81 from "src/assets/m81.png"; -import m120 from "src/assets/m120.png"; -import m121 from "src/assets/m121.png"; -import { AbilitySiteYell } from "src/site/Site"; +import i4 from "@/assets/i4.png"; +import i5 from "@/assets/i5.png"; +import i6 from "@/assets/i6.png"; +import i7 from "@/assets/i7.png"; +import i8 from "@/assets/i8.png"; +import i9 from "@/assets/i9.png"; +import i10 from "@/assets/i10.png"; +import i11 from "@/assets/i11.png"; +import i12 from "@/assets/i12.png"; +import i13 from "@/assets/i13.png"; +import i14 from "@/assets/i14.png"; +import i15 from "@/assets/i15.png"; +import i16 from "@/assets/i16.png"; +import m00 from "@/assets/m00.png"; +import m01 from "@/assets/m01.png"; +import m10 from "@/assets/m10.png"; +import m11 from "@/assets/m11.png"; +import m12 from "@/assets/m12.png"; +import m14 from "@/assets/m14.png"; +import m111 from "@/assets/m111.png"; +import m113 from "@/assets/m113.png"; +import m20 from "@/assets/m20.png"; +import m21 from "@/assets/m21.png"; +import m22 from "@/assets/m22.png"; +import m23 from "@/assets/m23.png"; +import m30 from "@/assets/m30.png"; +import m31 from "@/assets/m31.png"; +import m32 from "@/assets/m32.png"; +import m33 from "@/assets/m33.png"; +import m34 from "@/assets/m34.png"; +import m40 from "@/assets/m40.png"; +import m41 from "@/assets/m41.png"; +import m42 from "@/assets/m42.png"; +import m43 from "@/assets/m43.png"; +import m44 from "@/assets/m44.png"; +import m45 from "@/assets/m45.png"; +import m47 from "@/assets/m47.png"; +import m50 from "@/assets/m50.png"; +import m51 from "@/assets/m51.png"; +import m53 from "@/assets/m53.png"; +import m54 from "@/assets/m54.png"; +import m55 from "@/assets/m55.png"; +import m60 from "@/assets/m60.png"; +import m61 from "@/assets/m61.png"; +import m70 from "@/assets/m70.png"; +import m74 from "@/assets/m74.png"; +import m75 from "@/assets/m75.png"; +import m76 from "@/assets/m76.png"; +import m77 from "@/assets/m77.png"; +import m78 from "@/assets/m78.png"; +import m79 from "@/assets/m79.png"; +import m710 from "@/assets/m710.png"; +import m711 from "@/assets/m711.png"; +import m712 from "@/assets/m712.png"; +import m713 from "@/assets/m713.png"; +import m714 from "@/assets/m714.png"; +import m715 from "@/assets/m715.png"; +import m716 from "@/assets/m716.png"; +import m80 from "@/assets/m80.png"; +import m81 from "@/assets/m81.png"; +import m120 from "@/assets/m120.png"; +import m121 from "@/assets/m121.png"; +import { AbilitySiteYell } from "@/site/Site"; +import { useTranslations } from "next-intl"; export const is = [ "", @@ -138,7 +137,7 @@ genre.length === 0 || genre.startsWith("#") ? genre : `#${genre}`; export const getAbilityUpText = ( - t: TFunction, + t: ReturnType, { inputMode, ability }: AbilitySiteYell, ) => { let inputModeText = ""; @@ -163,7 +162,10 @@ return `${dateText.toLocaleDateString()} ${dateText.toLocaleTimeString()}`; }; -export const getSiteName = (siteName: string, t: TFunction) => { +export const getSiteName = ( + siteName: string, + t: ReturnType>, +) => { switch (siteName) { case "@Comment": return t("commentSiteName"); diff --git "a/qwilight-fe/src/app/\133language\135/avatar/loading.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/loading.tsx" new file mode 100644 index 0000000..93f1fc8 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/avatar/loading.tsx" @@ -0,0 +1,9 @@ +import { useTranslations } from "next-intl"; + +import LoadingLayer from "@/LoadingLayer"; + +export default function Loading() { + const t = useTranslations(); + + return ; +} diff --git "a/qwilight-fe/src/app/\133language\135/avatar/page.module.scss" "b/qwilight-fe/src/app/\133language\135/avatar/page.module.scss" new file mode 100644 index 0000000..1073444 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/avatar/page.module.scss" @@ -0,0 +1,5 @@ +img { + &.abilityClass { + height: 6rem; + } +} diff --git "a/qwilight-fe/src/app/\133language\135/avatar/page.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/page.tsx" new file mode 100644 index 0000000..cbab831 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/avatar/page.tsx" @@ -0,0 +1,295 @@ +"use client"; + +import Image from "next/image"; +import { useEffect } from "react"; +import { observer } from "mobx-react-lite"; +import { sprintf } from "sprintf-js"; +import { + Button, + Col, + Input, + ListGroup, + ListGroupItem, + Nav, + NavItem, + NavLink, + Progress, + Row, + TabContent, + TabPane, +} from "reactstrap"; +import { useWant } from "taehui-ts/fe-utility"; + +import { useAvatarStore, useSiteStore } from "@/Stores"; +import IntroView from "@/avatar/IntroView"; +import DateView from "@/avatar/DateView"; +import FavoritesView from "@/avatar/FavoritesView"; +import WwwLevelsView from "@/avatar/WwwLevelsView"; +import LastsView from "@/avatar/LastsView"; +import AbilitiesView from "@/avatar/AbilitiesView"; +import { getDefaultAvatarID } from "@/Utility"; +import { wwwAPI } from "@/Www"; +import AvatarDrawing from "@/AvatarDrawing"; +import QuitStatusValues from "@/avatar/QuitStatusValues"; +import AvatarTitle from "@/AvatarTitle"; +import useGetAvatar from "@/avatar/useGetAvatar"; + +import scss from "@/app/[language]/avatar/page.module.scss"; +import { useTranslations } from "next-intl"; +import Loading from "@/app/[language]/avatar/loading"; + +export default observer(() => { + const { input, setInput, tabPosition, setTabPosition } = useAvatarStore(); + const { siteAvatarID, isSignedIn, setSignInOpened } = useSiteStore(); + + const { want, setWant } = useWant("/avatar"); + + const t = useTranslations(); + + useEffect(() => { + setInput(want); + }, [want, setInput]); + + const { isFetched: isAvatarLoaded, data: avatar } = useGetAvatar(); + + const onWant = () => { + setWant(input); + }; + + const getProperties = (i: number) => ({ + className: tabPosition === i ? "active route" : "route", + onClick: () => { + setTabPosition(i); + }, + }); + + return ( + <> + + + + + + { + setInput(value); + }} + onKeyDown={({ key }) => { + if (key === "Enter") { + onWant(); + } + }} + placeholder={t("wantAvatarAssist")} + /> + + + + + + + + + {want && !isAvatarLoaded && } + {isAvatarLoaded && + (Array.isArray(avatar) ? ( + + {avatar.map(({ avatarID, avatarName, avatarIntro }) => { + return ( + + { + setWant(`${encodeURIComponent("#")}${avatarID}`); + }} + > + + + + + + + {avatarName} ({avatarID}) + +
+ {avatarIntro} + +
+
+ ); + })} +
+ ) : ( + <> + + + + + + + + {avatar.avatarName} ({avatar.avatarID}) + +
+ {sprintf(t("totalCountText"), avatar.totalCount)} +
+ {avatar.totalLength} +
+ + {sprintf(t("highestCountText"), avatar.highestCount)} + +
+ {sprintf(t("avatarDate"), avatar.date)} +
+ LV. {avatar.avatarLevels[0]} + +
+ + + + {avatar.avatarAbility5KPlace > 0 && ( + <> +
+ + #{avatar.avatarAbility5KPlaceText} + + /{avatar.avatarAbility5KCountText} +
+ {avatar.avatarAbility5KText} Point + + )} + + + + {avatar.avatarAbility7KPlace > 0 && ( + <> +
+ + #{avatar.avatarAbility7KPlace} + + /{avatar.avatarAbility7KCountText} +
+ {avatar.avatarAbility7KText} Point + + )} + + + + {avatar.avatarAbility9KPlace > 0 && ( + <> +
+ + #{avatar.avatarAbility9KPlace} + + /{avatar.avatarAbility9KCountText} +
+ {avatar.avatarAbility9KText} Point + + )} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + ))} + + ); +}); diff --git "a/qwilight-fe/src/app/\133language\135/etc/loading.tsx" "b/qwilight-fe/src/app/\133language\135/etc/loading.tsx" new file mode 100644 index 0000000..276bf6d --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/etc/loading.tsx" @@ -0,0 +1,9 @@ +import { useTranslations } from "next-intl"; + +import LoadingLayer from "@/LoadingLayer"; + +export default function Loading() { + const t = useTranslations(); + + return ; +} diff --git "a/qwilight-fe/src/app/\133language\135/etc/page.tsx" "b/qwilight-fe/src/app/\133language\135/etc/page.tsx" new file mode 100644 index 0000000..61841ba --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/etc/page.tsx" @@ -0,0 +1,179 @@ +"use client"; + +import { Col, Row } from "reactstrap"; + +import DateView from "@/etc/DateView"; +import ModeItem from "@/etc/ModeItem"; +import { + is, + m0s, + m12s, + m1s, + m2s, + m3s, + m4s, + m5s, + m6s, + m7s, + m8s, +} from "@/Utility"; +import TotalNoteFilesView from "@/etc/TotalNoteFilesView"; +import TotalTitlesView from "@/etc/TotalTitlesView"; +import TotalEdgesView from "@/etc/TotalEdgesView"; +import FavoritesView from "@/etc/FavoritesView"; +import useGetEtc from "@/etc/useGetEtc"; +import { useTranslations } from "next-intl"; + +export default function Page() { + const t = useTranslations(); + + const { + data: { + totalDateSet, + totalDateValues, + signUpDateSet, + signUpDateValues, + avatarDateSet, + avatarDateValues, + totalNoteFiles, + totalTitles, + totalEdges, + favorites, + favoritesAt, + inputModes, + autoModes, + noteSaltModes, + faintNoteModes, + judgmentModes, + hitPointsModes, + noteMobilityModes, + longNoteModes, + inputFavorModes, + noteModifyModes, + lowestJudgmentConditionModes, + }, + isFetched: isEtcLoaded, + } = useGetEtc(); + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git "a/qwilight-fe/src/app/\133language\135/hof/loading.tsx" "b/qwilight-fe/src/app/\133language\135/hof/loading.tsx" new file mode 100644 index 0000000..3146325 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/hof/loading.tsx" @@ -0,0 +1,9 @@ +import { useTranslations } from "next-intl"; + +import LoadingLayer from "@/LoadingLayer"; + +export default function Loading() { + const t = useTranslations(); + + return ; +} diff --git "a/qwilight-fe/src/app/\133language\135/hof/page.tsx" "b/qwilight-fe/src/app/\133language\135/hof/page.tsx" new file mode 100644 index 0000000..a93ab32 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/hof/page.tsx" @@ -0,0 +1,285 @@ +"use client"; + +import { + ListGroup, + Nav, + NavItem, + NavLink, + TabContent, + TabPane, +} from "reactstrap"; +import { observer } from "mobx-react-lite"; + +import { useHOFStore } from "@/Stores"; +import { HOF } from "@/hof/HOF"; +import AvatarItem from "@/hof/AvatarItem"; +import { AvatarLoading } from "@/Loading"; +import useGetTotalTotalHOF from "@/hof/useGetTotalTotalHOF"; +import useGetTotalHighestHOF from "@/hof/useGetTotalHighestHOF"; +import useGetTotalStandHOF from "@/hof/useGetTotalStandHOF"; +import useGetTotalBandHOF from "@/hof/useGetTotalBandHOF"; +import useGetAtTotalHOF from "@/hof/useGetAtTotalHOF"; +import useGetAtHighestHOF from "@/hof/useGetAtHighestHOF"; +import useGetAtStandHOF from "@/hof/useGetAtStandHOF"; +import useGetAtBandHOF from "@/hof/useGetAtBandHOF"; +import useGetAbility5KHOF from "@/hof/useGetAbility5KHOF"; +import useGetAbility7KHOF from "@/hof/useGetAbility7KHOF"; +import useGetAbility9KHOF from "@/hof/useGetAbility9KHOF"; +import useGetLevelHOF from "@/hof/useGetLevelHOF"; +import { useTranslations } from "next-intl"; + +const getAvatarItems = (hofs: HOF[]) => { + return hofs.map(({ avatarID, avatarName, text }) => ( + + )); +}; + +export default observer(() => { + const { + tabPosition, + totalTabPosition, + atTabPosition, + abilityTabPosition, + setTabPosition, + setTotalTabPosition, + setAtTabPosition, + setAbilityTabPosition, + } = useHOFStore(); + const t = useTranslations(); + + const { data: totalTotalHOF, isFetched: isTotalTotalHOFLoaded } = + useGetTotalTotalHOF(); + const { data: totalHighestHOF, isFetched: isTotalHighestHOFLoaded } = + useGetTotalHighestHOF(); + const { data: totalStandHOF, isFetched: isTotalStandHOFLoaded } = + useGetTotalStandHOF(); + const { data: totalBandHOF, isFetched: isTotalBandHOFLoaded } = + useGetTotalBandHOF(); + const { data: atTotalHOF, isFetched: isAtTotalHOFLoaded } = + useGetAtTotalHOF(); + const { data: atHighestHOF, isFetched: isAtHighestHOFLoaded } = + useGetAtHighestHOF(); + const { data: atStandHOF, isFetched: isAtStandHOFLoaded } = + useGetAtStandHOF(); + const { data: atBandHOF, isFetched: isAtBandHOFLoaded } = useGetAtBandHOF(); + const { data: ability5KHOF, isFetched: isAbility5KHOFLoaded } = + useGetAbility5KHOF(); + const { data: ability7KHOF, isFetched: isAbility7KHOFLoaded } = + useGetAbility7KHOF(); + const { data: ability9KHOF, isFetched: isAbility9KHOFLoaded } = + useGetAbility9KHOF(); + const { data: levelHOF, isFetched: isLevelHOFLoaded } = useGetLevelHOF(); + + const getProperties = (i: number) => ({ + className: tabPosition === i ? "active route" : "route", + onClick: () => { + setTabPosition(i); + }, + }); + + const getTotalProperties = (i: number) => ({ + className: totalTabPosition === i ? "active route" : "route", + onClick: () => { + setTotalTabPosition(i); + }, + }); + + const getAtProperties = (i: number) => ({ + className: atTabPosition === i ? "active route" : "route", + onClick: () => { + setAtTabPosition(i); + }, + }); + + const getAbilityProperties = (i: number) => ({ + className: abilityTabPosition === i ? "active route" : "route", + onClick: () => { + setAbilityTabPosition(i); + }, + }); + + return ( + <> + + + + + + + + {isTotalTotalHOFLoaded ? ( + getAvatarItems(totalTotalHOF) + ) : ( + + )} + + + + + {isTotalHighestHOFLoaded ? ( + getAvatarItems(totalHighestHOF) + ) : ( + + )} + + + + + {isTotalStandHOFLoaded ? ( + getAvatarItems(totalStandHOF) + ) : ( + + )} + + + + + {isTotalBandHOFLoaded ? ( + getAvatarItems(totalBandHOF) + ) : ( + + )} + + + + + + + + + + {isAtTotalHOFLoaded ? ( + getAvatarItems(atTotalHOF) + ) : ( + + )} + + + + + {isAtHighestHOFLoaded ? ( + getAvatarItems(atHighestHOF) + ) : ( + + )} + + + + + {isAtStandHOFLoaded ? ( + getAvatarItems(atStandHOF) + ) : ( + + )} + + + + + {isAtBandHOFLoaded ? ( + getAvatarItems(atBandHOF) + ) : ( + + )} + + + + + + + + + + {isAbility5KHOFLoaded ? ( + getAvatarItems(ability5KHOF) + ) : ( + + )} + + + + + {isAbility7KHOFLoaded ? ( + getAvatarItems(ability7KHOF) + ) : ( + + )} + + + + + {isAbility9KHOFLoaded ? ( + getAvatarItems(ability9KHOF) + ) : ( + + )} + + + + + + + {isLevelHOFLoaded ? ( + getAvatarItems(levelHOF) + ) : ( + + )} + + + + + ); +}); diff --git "a/qwilight-fe/src/app/\133language\135/layout.tsx" "b/qwilight-fe/src/app/\133language\135/layout.tsx" new file mode 100644 index 0000000..5768952 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/layout.tsx" @@ -0,0 +1,34 @@ +import { ReactNode } from "react"; + +import "bootstrap/dist/css/bootstrap.min.css"; +import "react-contexify/dist/ReactContexify.css"; +import "react-toastify/dist/ReactToastify.css"; + +import "@/app/globals.scss"; +import { Stores } from "@/Stores"; +import QwilightView from "@/QwilightView"; +import { NextIntlClientProvider } from "next-intl"; +import { getMessages } from "next-intl/server"; + +export default async function RootLayout({ + children, + params: { language }, +}: { + children: ReactNode; + params: { language: string }; +}) { + return ( + + + + + {children} + + + + + ); +} diff --git "a/qwilight-fe/src/app/\133language\135/note/\133\133...want\135\135/page.tsx" "b/qwilight-fe/src/app/\133language\135/note/\133\133...want\135\135/page.tsx" new file mode 100644 index 0000000..62a5f6e --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/note/\133\133...want\135\135/page.tsx" @@ -0,0 +1,129 @@ +"use client"; + +import { observer } from "mobx-react-lite"; +import { Button, Col, Row } from "reactstrap"; +import { sprintf } from "sprintf-js"; + +import { useNoteStore } from "@/Stores"; +import NoteItems from "@/note/NoteItems"; +import FitInput from "@/note/FitInput"; +import SrcInput from "@/note/SrcInput"; +import PositionInput from "@/note/PositionInput"; +import { formatText } from "@/Utility"; +import useGetNote from "@/note/useGetNote"; +import WantInput from "@/note/WantInput"; +import { useWant } from "taehui-ts/fe-utility"; +import { useEffect } from "react"; +import { useIntParam } from "taehui-ts/fe-utility"; +import { useTranslations } from "next-intl"; + +export default observer(() => { + const { + setWantAvatar, + wantInput, + lastPage, + setLastPage, + viewUnit, + lastWant, + lastSrc, + } = useNoteStore(); + const t = useTranslations(); + + const { want, setWant } = useWant("/note"); + const { param: src } = useIntParam("src", 0); + const { param: page, setParam: setPage } = useIntParam("page", 1); + + const { + data: { highestCount, totalCount, noteCount }, + isFetched: isNoteLoaded, + } = useGetNote(); + + useEffect(() => { + if ((want !== lastWant || src !== lastSrc) && page > 1) { + setPage(1); + } + }, [lastSrc, lastWant, page, setPage, src, want]); + + useEffect(() => { + if (isNoteLoaded) { + setLastPage(Math.max(1, Math.ceil(noteCount / viewUnit))); + } + }, [isNoteLoaded, noteCount, setLastPage, viewUnit]); + + useEffect(() => { + setWantAvatar(src === 1 ? want : ""); + }, [setWantAvatar, src, want]); + + const onWant = () => { + setWant(wantInput); + }; + + const onClose = () => { + setWant(""); + }; + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + {lastPage >= 0 && ( + + + + + + )} + + {isNoteLoaded && ( + + + + {sprintf(t("highestCountText"), formatText(highestCount))} + +
+ {sprintf(t("totalCountText"), formatText(totalCount))} + +
+ )} + + + + taehui@taehui.ddns.net', + ), + }} + /> + + + + ); +}); diff --git "a/qwilight-fe/src/app/\133language\135/note/loading.tsx" "b/qwilight-fe/src/app/\133language\135/note/loading.tsx" new file mode 100644 index 0000000..393915f --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/note/loading.tsx" @@ -0,0 +1,9 @@ +import { useTranslations } from "next-intl"; + +import LoadingLayer from "@/LoadingLayer"; + +export default function Loading() { + const t = useTranslations(); + + return ; +} diff --git "a/qwilight-fe/src/app/\133language\135/site/loading.tsx" "b/qwilight-fe/src/app/\133language\135/site/loading.tsx" new file mode 100644 index 0000000..2016b3d --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/site/loading.tsx" @@ -0,0 +1,9 @@ +import { useTranslations } from "next-intl"; + +import LoadingLayer from "@/LoadingLayer"; + +export default function Loading() { + const t = useTranslations(); + + return ; +} diff --git "a/qwilight-fe/src/app/\133language\135/site/page.module.scss" "b/qwilight-fe/src/app/\133language\135/site/page.module.scss" new file mode 100644 index 0000000..5bbb208 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/site/page.module.scss" @@ -0,0 +1,5 @@ +div { + &.siteView { + overflow: auto; + } +} diff --git "a/qwilight-fe/src/app/\133language\135/site/page.tsx" "b/qwilight-fe/src/app/\133language\135/site/page.tsx" new file mode 100644 index 0000000..f4bdbc3 --- /dev/null +++ "b/qwilight-fe/src/app/\133language\135/site/page.tsx" @@ -0,0 +1,373 @@ +"use client"; + +import { + MutableRefObject, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; +import { observer } from "mobx-react-lite"; +import { Item, ItemParams, Menu, useContextMenu } from "react-contexify"; +import { + Alert, + Button, + Col, + Offcanvas, + OffcanvasBody, + OffcanvasHeader, + Row, +} from "reactstrap"; +import Swal from "sweetalert2"; +import { toast } from "react-toastify"; +import { sprintf } from "sprintf-js"; +import { useTo } from "taehui-ts/fe-utility"; +import { useQueryClient } from "@tanstack/react-query"; + +import { useSiteStore } from "@/Stores"; +import SiteComponent from "@/site/SiteComponent"; +import ConfigureWindow from "@/site/ConfigureWindow"; +import SiteWindow from "@/site/SiteWindow"; +import SiteYellItems from "@/site/SiteYellItems"; +import AvatarItems from "@/site/AvatarItems"; +import SiteInput from "@/site/SiteInput"; +import SiteYellItem from "@/site/SiteYellItem"; +import { getDefaultAvatarID } from "@/Utility"; +import { OnSiteYellInput } from "@/site/Site"; + +import scss from "@/app/[language]/site/page.module.scss"; +import { useTranslations } from "next-intl"; +import { usePathname } from "next/navigation"; + +const EventPB = require("@/Event_pb"); + +export default observer(() => { + const { + avatars, + siteNotify, + isAvatarsOpened, + isPendingSiteYellOpened, + lastPendingSiteYell, + targetSiteID, + siteViews, + siteAvatarID, + siteYells, + setSiteYellsViewLowest, + getSiteView, + onSiteIDModified, + siteYellsViewMove, + setPendingSiteYellOpened, + setAvatarsOpened, + isLoading, + setSiteWindowOpened, + siteYellsView, + titleComponent, + } = useSiteStore(); + const t = useTranslations(); + const to = useTo(); + const { show: viewSiteNameInput } = useContextMenu({ + id: "siteName", + }); + const { show: viewAvatarInput } = useContextMenu({ + id: "avatar", + }); + const { show: viewSiteYellInput } = useContextMenu({ + id: "siteYell", + }); + + const pathname = usePathname(); + + useEffect(() => { + if (pathname === "/site") { + siteYellsViewMove(); + } + }, [pathname, siteYellsViewMove]); + + const [siteYellsViewHeight, setSiteYellsViewHeight] = useState(""); + const siteViewsView = useRef(null); + const inputComponent = useRef(null); + + const onViewAvatar = ({ props: { avatarID } }: ItemParams) => { + if (avatarID.startsWith("*")) { + toast.warning(t("notAvatarViewFault")); + } else { + to(`/avatar/${encodeURIComponent("#")}${getDefaultAvatarID(avatarID)}`); + } + }; + + useEffect(() => { + window.Notification?.requestPermission(); + }, []); + + const onViewsModified = useCallback(() => { + setSiteYellsViewHeight( + `${ + document.documentElement.clientHeight - + (titleComponent?.current?.clientHeight ?? 0) - + (siteViewsView.current?.clientHeight ?? 0) - + (inputComponent.current?.clientHeight ?? 0) + }px`, + ); + }, [titleComponent]); + + useEffect(() => { + onViewsModified(); + }, [onViewsModified, isLoading, avatars, lastPendingSiteYell]); + + useEffect(() => { + const onModified = () => { + onViewsModified(); + siteYellsViewMove(); + }; + + window.addEventListener("resize", onModified); + + return () => { + window.removeEventListener("resize", onModified); + }; + }, [onViewsModified, siteYellsViewMove]); + + const onSiteYellsViewMove = useCallback(() => { + if (siteYellsView) { + const { current } = siteYellsView; + if (current) { + const siteYellID = siteYells[0]?.siteYellID; + if (siteYellID && siteYellID > 0 && !current.scrollTop) { + SiteComponent.send({ + eventID: EventPB.Event.EventID.GET_SITE_YELLS, + text: JSON.stringify({ + siteID: targetSiteID, + siteYellID: siteYellID, + }), + }); + } + + const isSiteYellsViewLowest = + current.scrollTop + current.clientHeight >= current.scrollHeight; + setSiteYellsViewLowest(isSiteYellsViewLowest); + if (isSiteYellsViewLowest) { + setPendingSiteYellOpened(false); + } + } + } + }, [ + setPendingSiteYellOpened, + setSiteYellsViewLowest, + siteYells, + siteYellsView, + targetSiteID, + ]); + + useEffect(() => { + if (siteYellsView) { + const { current } = siteYellsView; + + if (current) { + current.addEventListener("scroll", onSiteYellsViewMove); + + return () => { + current.removeEventListener("scroll", onSiteYellsViewMove); + }; + } + } + }, [onSiteYellsViewMove, isLoading, siteYellsView]); + + const isSiteHand = useMemo( + () => getSiteView(targetSiteID)?.siteHand === siteAvatarID, + [getSiteView, siteAvatarID, targetSiteID], + ); + + const queryClient = useQueryClient(); + + const onSiteYellInput: OnSiteYellInput = (event, avatarID) => { + viewSiteYellInput({ event, props: { avatarID } }); + }; + + return ( + <> +
+ + {siteViews.map(({ siteID, siteName, isNew }) => { + return ( + + + + ); + })} + + + + {targetSiteID && ( + + + + )} + +
+ + + + + {siteNotify} + + + + + + + + {lastPendingSiteYell && ( + + )} + + + + +
+ +
+ + setAvatarsOpened(false)} + > + setAvatarsOpened(false)}> + {sprintf(t("avatarCountText"), avatars.length)} + + + { + viewAvatarInput({ event, props: { avatarID } }); + }} + /> + + + + { + SiteComponent.send({ + eventID: EventPB.Event("EventID.SET_SITE_OWNER"), + text: JSON.stringify({ + siteID: targetSiteID, + avatarID, + }), + }); + }} + > + {t("setSiteHand")} + + + {t("viewAvatarView")} + + { + SiteComponent.send({ + eventID: EventPB.Event("EventID.NEW_SILENT_SITE"), + text: avatarID, + }); + }} + > + {t("silentSiteNew")} + + { + SiteComponent.send({ + eventID: EventPB.Event("EventID.EXILE_AVATAR"), + text: JSON.stringify({ + siteID: targetSiteID, + avatarID, + }), + }); + }} + > + {t("exileAvatar")} + + + + + + + {t("viewAvatarView")} + + + + + { + const { isConfirmed, value } = await Swal.fire({ + title: t("setSiteNameText"), + input: "text", + }); + if (isConfirmed) { + SiteComponent.send({ + eventID: EventPB.Event("EventID.SET_SITE_NAME"), + text: JSON.stringify({ + siteID: targetSiteID, + siteName: value, + }), + }); + } + }} + > + {t("setSiteName")} + + + +
+ +
+ + + + + ); +}); diff --git a/qwilight-fe/src/app/globals.scss b/qwilight-fe/src/app/globals.scss new file mode 100644 index 0000000..2c03ca1 --- /dev/null +++ b/qwilight-fe/src/app/globals.scss @@ -0,0 +1,240 @@ +* { + margin: 0; + font-family: "Century Gothic", + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + "Roboto", + "Oxygen", + "Ubuntu", + "Cantarell", + "Fira Sans", + "Droid Sans", + "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +@mixin default() { + font-size: 0.75rem; +} + +a { + &.nav-link { + @include default(); + color: white; + + &:hover { + @include default(); + color: white; + } + } +} + +body { + background: url("../assets/dark-honeycomb.png"); +} + +button { + &.btn { + @include default(); + } + + &.page-link { + @include default(); + } + + &.dropdown-item { + @include default(); + } +} + +input[type="button"], +input[type="submit"], +input[type="search"], +input[type="text"], +input[type="password"] { + @include default(); +} + +li { + &.page-item { + @include default(); + } + + &.list-group-item { + background-color: rgba(0, 0, 0, 0.125); + border: none; + } +} + +.target { + border: thin solid; + border-image: linear-gradient(43deg, #4158d0 0%, #c850c0 46%, #ffcc70 100%); + border-image-slice: 1; +} + +div { + &.offcanvas-body { + background-color: black; + } +} + +span { + & { + @include default(); + } + + :not(.page-link, .contexify_itemContent, .alert) > & { + color: white; + } + + ul.list-group > &.badge { + font-weight: normal; + border-radius: 0; + } + + div.modal-content & { + color: black; + } + + &.date { + color: darkgray; + } + + &.stand { + color: white; + } + + &.point { + color: white; + } + + &.band { + color: white; + } + + &.title { + color: white; + } + + &.genre { + color: darkgray; + } + + &.fittedText { + color: dodgerblue; + } + + &.artist { + color: lightgray; + } + + &.level0 { + color: darkgray; + } + + &.level1 { + color: mediumspringgreen; + } + + &.level2 { + color: mediumturquoise; + } + + &.level3 { + color: yellow; + } + + &.level4 { + color: mediumvioletred; + } + + &.level5 { + color: mediumpurple; + } + + &.titleLV2000 { + background: linear-gradient( + to right, + red, + orange, + yellow, + green, + blue, + indigo, + purple + ); + background-clip: text; + -webkit-text-fill-color: transparent; + } + + &.highestJudgment { + color: cyan; + } + + &.higherJudgment { + color: deepskyblue; + } + + &.highJudgment { + color: lightgreen; + } + + &.lowJudgment { + color: yellow; + } + + &.lowerJudgment { + color: mediumpurple; + } + + &.lowestJudgment { + color: red; + } + + &.S\+ { + color: gold; + } + + &.S { + color: gold; + } + + &.A\+ { + color: green; + } + + &.A { + color: green; + } + + &.B { + color: blue; + } + + &.C { + color: magenta; + } + + &.D { + color: red; + } + + &.audioMultiplier { + color: white; + } + + &.avatarPlace { + font-size: 1.5rem; + } + + &.avatarIntro { + white-space: pre-line; + } +} + +.route { + cursor: pointer; +} diff --git a/qwilight-fe/src/assets/language/en.json b/qwilight-fe/src/assets/language/en.json new file mode 100644 index 0000000..2423fc5 --- /dev/null +++ b/qwilight-fe/src/assets/language/en.json @@ -0,0 +1,115 @@ +{ + "abilityFittedText": "%s Points (+ %s Points)", + "audioMultiplier": "Music speed", + "autoSignIn": "Automatic login", + "avatarAbilitiesText": "Rating TOP 50", + "avatarCountText": "%d people", + "avatarDate": "Last Connection Date: %s", + "avatarDateText": "Activity Trends", + "avatarFavoritesText": "Most plays TOP 50", + "avatarIntroText": "Introduce yourself", + "avatarLastsText": "Last plays TOP 50", + "avatarQuitStatusText": "Rank", + "bannedNoteFile": "Illegal BMS and BMSON note files are filtered by themselves by checking the number of key notes.
If you find illegal BMS/BMSON note file, please let us know via %s and delete it.", + "commentSiteName": "Performance notification room", + "defaultSiteName": "General chat room", + "enterSite": "Enter", + "etcAutoMode": "Turntable", + "etcAvatar": "Activity User Trends", + "etcFaintNoteMode": "Note time", + "etcFavorites": "Favorite songs TOP 10", + "etcFavoritesAt": "Favorite songs TOP 10 for this month", + "etcHitPointsMode": "Life Gauge", + "etcInputFavorMode": "Modifying the number of lines", + "etcInputMode": "Note line", + "etcJudgmentMode": "Difficulty level of judgment", + "etcLongNoteMode": "Judgment of taking long notes", + "etcLowestJudgmentConditionMode": "Indirect miss", + "etcNoteMobilityMode": "Even the disorder of notes", + "etcNoteModifyMode": "Modifying Notes", + "etcNoteSaltMode": "Place notes", + "etcSignUp": "New Subscription Trends", + "etcTotal": "Play trend", + "etcTotalEdges": "Frames TOP 10", + "etcTotalNoteFiles": "Popular Songs TOP 10 for this month", + "etcTotalTitles": "Titles TOP 10", + "exileAvatar": "Kick", + "highestCountText": "Record count: %s", + "hofAbilityText": "Rating", + "hofAtText": "Month", + "hofBand": "Combo", + "hofHighest": "Record", + "hofLevelText": "Level", + "hofStand": "Score", + "hofTotal": "Play", + "hofTotalText": "All", + "inputNewSite": "Create Chat Room", + "notAvatarViewFault": "Non-member profiles are not available.", + "notSignedInText": "Thank you, %s.", + "notSignIn": "Sign out", + "onAvatars": "User list.", + "onClose": "Clear", + "onConfigure": "Preferences", + "onSiteWindow": "Chat Room List", + "onWant": "Search", + "onWantMe": "View My Profile", + "platformSiteName": "Discord Chat Room", + "point": "Accuracy", + "postFile": "Upload File", + "quitSite": "Leaving the room", + "save": "Save", + "setSiteHand": "Delegation of the Director", + "setSiteName": "Modify Room Name", + "setSiteNameText": "Please enter a name to modify", + "signedInText": "Welcome, %s.", + "signIn": "Login", + "signInCipher": "Password", + "signInID": "ID", + "silentSiteNew": "One-on-one conversation", + "siteAudio": "Alarm sound.", + "siteAutoEnterDefault": "Automatically enter the regular chat room.", + "siteAutoEnterNotify": "Automatically enter the notification room.", + "siteAutoEnterPlatform": "Automatic entry to discode chat room", + "siteCipher": "Chat Room Password", + "siteName": "Chat Room Name", + "siteSaveTraffic": "Data saving mode.", + "siteWindowNew": "Create Chat Room", + "siteYellEnter": "Entered", + "siteYellInvite": "Click to play multiple games with me on %s.", + "siteYellNewNetSite": "Create a new game room", + "siteYellNewSite": "Create a new chat room", + "siteYellQuit": "Exited", + "siteYellTaehui": "Developer", + "siteYellTV": "Click to watch Qwilight broadcast %s", + "stand": "Score", + "textBand": "%s combo", + "textCount": "%s", + "textHandled": "%s times", + "textStand": "%s point", + "toAvatar": "Online Profile", + "toEtc": "Statistics", + "toFit0": "Sequence of records", + "toFit1": "Number of plays", + "toFit2": "Update order", + "toFit3": "Subject order", + "toFit4": "Artist order", + "toFit5": "Genre order", + "toFit6": "Difficulty order", + "toHOF": "Hall of Fame", + "toilNoteFile": "Illegal BMS, reported as BMSON note file", + "toilNoteFileText": "Please write down the reason for the report", + "toNote": "Online Ranking", + "toNotifySiteName": "Notification room", + "toSite": "Online Chat", + "toSrc0": "As a title", + "toSrc1": "As a nickname", + "toSrc2": "As an artist", + "toSrc3": "As a genre", + "totalCountText": "Number of plays: %s.", + "totalLengthText": "Playtime: %d hours %d minutes %d seconds", + "viewAvatarView": "View Profiles", + "wantAvatarAssist": "Enter nickname to search", + "wipedSiteYell": "Deleted message.", + "wwwLevel": "Challenges", + "wwwLevelClearText": "Challenge %s cleared! Congratulations." +} diff --git a/qwilight-fe/src/assets/language/ko.json b/qwilight-fe/src/assets/language/ko.json new file mode 100644 index 0000000..c375615 --- /dev/null +++ b/qwilight-fe/src/assets/language/ko.json @@ -0,0 +1,115 @@ +{ + "abilityFittedText": "%s 점 (+ %s Point)", + "audioMultiplier": "음악 속도", + "autoSignIn": "자동 로그인", + "avatarAbilitiesText": "성과 TOP 50", + "avatarCountText": "%d 명", + "avatarDate": "마지막 접속일: %s", + "avatarDateText": "활동 추세", + "avatarFavoritesText": "가장 많이 플레이 TOP 50", + "avatarIntroText": "자기소개", + "avatarLastsText": "마지막 플레이 TOP 50", + "avatarQuitStatusText": "랭크", + "bannedNoteFile": "불법 BMS, BMSON 노트 파일은 키음 개수를 확인하여 자체적으로 걸러집니다.
만약 불법 BMS/BMSON 노트 파일을 발견하시면 %s로 알려주시면 삭제합니다.", + "commentSiteName": "성과 알림방", + "defaultSiteName": "일반 대화방", + "enterSite": "입장하기", + "etcAutoMode": "턴 테이블", + "etcAvatar": "활동 사용자 추세", + "etcFaintNoteMode": "노트 시각", + "etcFavorites": "선호곡 TOP 10", + "etcFavoritesAt": "이번 달 선호곡 TOP 10", + "etcHitPointsMode": "라이프 게이지", + "etcInputFavorMode": "라인 개수 수정", + "etcInputMode": "노트 라인", + "etcJudgmentMode": "판정 난이도", + "etcLongNoteMode": "롱 노트 떼는 판정", + "etcLowestJudgmentConditionMode": "간접 미스", + "etcNoteMobilityMode": "노트 무질서도", + "etcNoteModifyMode": "노트 수정", + "etcNoteSaltMode": "노트 배치", + "etcSignUp": "신규 가입 추세", + "etcTotal": "플레이 추세", + "etcTotalEdges": "프레임 TOP 10", + "etcTotalNoteFiles": "이번 달 인기곡 TOP 10", + "etcTotalTitles": "호칭 TOP 10", + "exileAvatar": "추방", + "highestCountText": "기록 개수: %s 개", + "hofAbilityText": "레이팅", + "hofAtText": "이번 달", + "hofBand": "콤보", + "hofHighest": "기록", + "hofLevelText": "레벨", + "hofStand": "점수", + "hofTotal": "플레이", + "hofTotalText": "전체", + "inputNewSite": "대화방 만들기", + "notAvatarViewFault": "비회원의 프로필은 제공되지 않습니다.", + "notSignedInText": "%s님 감사합니다.", + "notSignIn": "로그아웃", + "onAvatars": "사용자 목록", + "onClose": "지우기", + "onConfigure": "환경 설정", + "onSiteWindow": "대화방 목록", + "onWant": "검색", + "onWantMe": "내 프로필 보기", + "platformSiteName": "디스코드 대화방", + "point": "정확도", + "postFile": "파일 업로드", + "quitSite": "방 나가기", + "save": "저장하기", + "setSiteHand": "방장 위임", + "setSiteName": "방 이름 수정", + "setSiteNameText": "수정할 이름을 입력하세요", + "signedInText": "%s님 환영합니다.", + "signIn": "로그인", + "signInCipher": "비밀번호", + "signInID": "아이디", + "silentSiteNew": "1대1 대화", + "siteAudio": "알림 사운드", + "siteAutoEnterDefault": "일반 대화방 자동 입장", + "siteAutoEnterNotify": "알림방 자동 입장", + "siteAutoEnterPlatform": "디스코드 대화방 자동 입장", + "siteCipher": "대화방 비밀번호", + "siteName": "대화방 이름", + "siteSaveTraffic": "데이터 절약 모드", + "siteWindowNew": "대화방 만들기", + "siteYellEnter": "입장함", + "siteYellInvite": "저랑 같이 %s 에서 멀티 플레이 하려면 클릭하세요", + "siteYellNewNetSite": "새 게임방을 만듦", + "siteYellNewSite": "새 대화방을 만듦", + "siteYellQuit": "퇴장함", + "siteYellTaehui": "개발자", + "siteYellTV": "Qwilight 방송 %s을 보려면 클릭하세요", + "stand": "점수", + "textBand": "%s 콤보", + "textCount": "%s 개", + "textHandled": "%s 회", + "textStand": "%s 점", + "toAvatar": "온라인 프로필", + "toEtc": "통계", + "toFit0": "기록 개수순", + "toFit1": "플레이 횟수순", + "toFit2": "업데이트순", + "toFit3": "제목순", + "toFit4": "아티스트순", + "toFit5": "장르순", + "toFit6": "난이도순", + "toHOF": "명예의 전당", + "toilNoteFile": "불법 BMS, BMSON 노트 파일로 신고", + "toilNoteFileText": "신고 사유를 적어주세요", + "toNote": "온라인 랭킹", + "toNotifySiteName": "알림방", + "toSite": "온라인 대화", + "toSrc0": "제목으로", + "toSrc1": "닉네임으로", + "toSrc2": "아티스트로", + "toSrc3": "장르로", + "totalCountText": "플레이 횟수: %s 회", + "totalLengthText": "플레이 시간: %d 시간 %d 분 %d 초", + "viewAvatarView": "프로필 보기", + "wantAvatarAssist": "검색할 닉네임을 입력하세요", + "wipedSiteYell": "삭제된 메시지입니다.", + "wwwLevel": "도전 과제", + "wwwLevelClearText": "도전 과제 %s 클리어! 축하합니다." +} diff --git a/qwilight-fe/src/avatar/AbilitiesView.tsx b/qwilight-fe/src/avatar/AbilitiesView.tsx index 441498f..10b2c48 100644 --- a/qwilight-fe/src/avatar/AbilitiesView.tsx +++ b/qwilight-fe/src/avatar/AbilitiesView.tsx @@ -9,12 +9,12 @@ TabPane, } from "reactstrap"; -import { useAvatarStore } from "src/Stores"; -import NoteItem from "src/note/NoteItem"; -import { NoteLoading } from "src/Loading"; -import { GetAvatar } from "src/avatar/useGetAvatar"; -import useGetAvatarAbility from "src/avatar/useGetAvatarAbility"; -import { getAbilityInputMode } from "src/Utility"; +import { useAvatarStore } from "@/Stores"; +import NoteItem from "@/note/NoteItem"; +import { NoteLoading } from "@/Loading"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import useGetAvatarAbility from "@/avatar/useGetAvatarAbility"; +import { getAbilityInputMode } from "@/Utility"; export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => { const { abilitiesTabPosition, tabPosition, setAbilitiesTabPosition } = diff --git a/qwilight-fe/src/avatar/AvatarView.module.scss b/qwilight-fe/src/avatar/AvatarView.module.scss deleted file mode 100644 index 1073444..0000000 --- a/qwilight-fe/src/avatar/AvatarView.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -img { - &.abilityClass { - height: 6rem; - } -} diff --git a/qwilight-fe/src/avatar/AvatarView.tsx b/qwilight-fe/src/avatar/AvatarView.tsx deleted file mode 100644 index c8ec23b..0000000 --- a/qwilight-fe/src/avatar/AvatarView.tsx +++ /dev/null @@ -1,292 +0,0 @@ -import { useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { observer } from "mobx-react-lite"; -import { sprintf } from "sprintf-js"; -import { - Button, - Col, - Input, - ListGroup, - ListGroupItem, - Nav, - NavItem, - NavLink, - Progress, - Row, - TabContent, - TabPane, -} from "reactstrap"; -import { useWant } from "taehui-ts/fe-utility"; - -import { useAvatarStore, useSiteStore } from "src/Stores"; -import IntroView from "src/avatar/IntroView"; -import DateView from "src/avatar/DateView"; -import FavoritesView from "src/avatar/FavoritesView"; -import WwwLevelsView from "src/avatar/WwwLevelsView"; -import LastsView from "src/avatar/LastsView"; -import AbilitiesView from "src/avatar/AbilitiesView"; -import { getDefaultAvatarID } from "src/Utility"; -import { wwwAPI } from "src/Www"; -import AvatarDrawing from "src/AvatarDrawing"; -import QuitStatusValues from "src/avatar/QuitStatusValues"; -import AvatarTitle from "src/AvatarTitle"; -import { AvatarViewLoading } from "src/Loading"; -import useGetAvatar from "src/avatar/useGetAvatar"; - -import scss from "src/avatar/AvatarView.module.scss"; - -export default observer(() => { - const { input, setInput, tabPosition, setTabPosition } = useAvatarStore(); - const { siteAvatarID, isSignedIn, setSignInOpened } = useSiteStore(); - - const { want, setWant } = useWant("/qwilight/avatar"); - - const { t } = useTranslation(); - - useEffect(() => { - setInput(want); - }, [want, setInput]); - - const { isFetched: isAvatarLoaded, data: avatar } = useGetAvatar(); - - const onWant = () => { - setWant(input); - }; - - const getProperties = (i: number) => ({ - className: tabPosition === i ? "active route" : "route", - onClick: () => { - setTabPosition(i); - }, - }); - - return ( - <> - - - - - - { - setInput(value); - }} - onKeyDown={({ key }) => { - if (key === "Enter") { - onWant(); - } - }} - placeholder={t("wantAvatarAssist")} - /> - - - - - - - - - {want && !isAvatarLoaded && } - {isAvatarLoaded && - (Array.isArray(avatar) ? ( - - {avatar.map(({ avatarID, avatarName, avatarIntro }) => { - return ( - - { - setWant(`${encodeURIComponent("#")}${avatarID}`); - }} - > - - - - - - - {avatarName} ({avatarID}) - -
- {avatarIntro} - -
-
- ); - })} -
- ) : ( - <> - - - - - - - - {avatar.avatarName} ({avatar.avatarID}) - -
- {sprintf(t("totalCountText"), avatar.totalCount)} -
- {avatar.totalLength} -
- - {sprintf(t("highestCountText"), avatar.highestCount)} - -
- {sprintf(t("avatarDate"), avatar.date)} -
- LV. {avatar.avatarLevels[0]} - -
- - - - {avatar.avatarAbility5KPlace > 0 && ( - <> -
- - #{avatar.avatarAbility5KPlaceText} - - /{avatar.avatarAbility5KCountText} -
- {avatar.avatarAbility5KText} Point - - )} - - - - {avatar.avatarAbility7KPlace > 0 && ( - <> -
- - #{avatar.avatarAbility7KPlace} - - /{avatar.avatarAbility7KCountText} -
- {avatar.avatarAbility7KText} Point - - )} - - - - {avatar.avatarAbility9KPlace > 0 && ( - <> -
- - #{avatar.avatarAbility9KPlace} - - /{avatar.avatarAbility9KCountText} -
- {avatar.avatarAbility9KText} Point - - )} - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - ))} - - ); -}); diff --git a/qwilight-fe/src/avatar/DateView.tsx b/qwilight-fe/src/avatar/DateView.tsx index cb7d86a..15a873c 100644 --- a/qwilight-fe/src/avatar/DateView.tsx +++ b/qwilight-fe/src/avatar/DateView.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useEffect, useRef } from "react"; import { BarController, @@ -7,9 +9,9 @@ LinearScale, } from "chart.js"; import { Badge, ListGroup, ListGroupItem } from "reactstrap"; -import { useTranslation } from "react-i18next"; -import { GetAvatar } from "src/avatar/useGetAvatar"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import { useTranslations } from "next-intl"; export default function DateView({ avatar: { dateSet, dateValues }, @@ -18,7 +20,7 @@ }) { const dateView = useRef(null); - const { t } = useTranslation(); + const t = useTranslations(); useEffect(() => { const dateView2D = dateView.current?.getContext("2d"); diff --git a/qwilight-fe/src/avatar/FavoritesView.tsx b/qwilight-fe/src/avatar/FavoritesView.tsx index ca7a1e2..aa795de 100644 --- a/qwilight-fe/src/avatar/FavoritesView.tsx +++ b/qwilight-fe/src/avatar/FavoritesView.tsx @@ -9,12 +9,12 @@ TabPane, } from "reactstrap"; -import { useAvatarStore } from "src/Stores"; -import NoteItem from "src/note/NoteItem"; -import { NoteLoading } from "src/Loading"; -import { GetAvatar } from "src/avatar/useGetAvatar"; -import useGetAvatarFavorites from "src/avatar/useGetAvatarFavorites"; -import { getInputMode } from "src/Utility"; +import { useAvatarStore } from "@/Stores"; +import NoteItem from "@/note/NoteItem"; +import { NoteLoading } from "@/Loading"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import useGetAvatarFavorites from "@/avatar/useGetAvatarFavorites"; +import { getInputMode } from "@/Utility"; export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => { const { tabPosition, favoritesTabPosition, setFavoritesTabPosition } = diff --git a/qwilight-fe/src/avatar/IntroView.tsx b/qwilight-fe/src/avatar/IntroView.tsx index 01f83ff..ea6da23 100644 --- a/qwilight-fe/src/avatar/IntroView.tsx +++ b/qwilight-fe/src/avatar/IntroView.tsx @@ -1,14 +1,14 @@ -import { useTranslation } from "react-i18next"; import { Badge, ListGroup, ListGroupItem } from "reactstrap"; -import { GetAvatar } from "src/avatar/useGetAvatar"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import { useTranslations } from "next-intl"; export default function IntroView({ avatar: { avatarIntro }, }: { avatar: GetAvatar; }) { - const { t } = useTranslation(); + const t = useTranslations(); if (!avatarIntro) { return null; diff --git a/qwilight-fe/src/avatar/LastsView.tsx b/qwilight-fe/src/avatar/LastsView.tsx index 32d998d..5a2d018 100644 --- a/qwilight-fe/src/avatar/LastsView.tsx +++ b/qwilight-fe/src/avatar/LastsView.tsx @@ -9,12 +9,12 @@ TabPane, } from "reactstrap"; -import { useAvatarStore } from "src/Stores"; -import NoteItem from "src/note/NoteItem"; -import { NoteLoading } from "src/Loading"; -import useGetAvatarLasts from "src/avatar/useGetAvatarLasts"; -import { GetAvatar } from "src/avatar/useGetAvatar"; -import { getInputMode } from "src/Utility"; +import { useAvatarStore } from "@/Stores"; +import NoteItem from "@/note/NoteItem"; +import { NoteLoading } from "@/Loading"; +import useGetAvatarLasts from "@/avatar/useGetAvatarLasts"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import { getInputMode } from "@/Utility"; export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => { const { tabPosition, lastsTabPosition, setLastsTabPosition } = diff --git a/qwilight-fe/src/avatar/QuitStatusValues.tsx b/qwilight-fe/src/avatar/QuitStatusValues.tsx index 5abc343..015bcdf 100644 --- a/qwilight-fe/src/avatar/QuitStatusValues.tsx +++ b/qwilight-fe/src/avatar/QuitStatusValues.tsx @@ -1,7 +1,7 @@ -import { useTranslation } from "react-i18next"; import { Badge, ListGroup, ListGroupItem } from "reactstrap"; -import { GetAvatar } from "src/avatar/useGetAvatar"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import { useTranslations } from "next-intl"; const quitItems = ["S+", "S", "A+", "A", "B", "C", "D"] as const; @@ -10,7 +10,7 @@ }: { avatar: GetAvatar; }) { - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/qwilight-fe/src/avatar/WwwLevelItem.tsx b/qwilight-fe/src/avatar/WwwLevelItem.tsx index 46bd0d8..7ee2cab 100644 --- a/qwilight-fe/src/avatar/WwwLevelItem.tsx +++ b/qwilight-fe/src/avatar/WwwLevelItem.tsx @@ -1,7 +1,7 @@ import { Col, ListGroupItem, Row } from "reactstrap"; -import { toDate } from "src/Utility"; -import { GetAvatarWwwLevelsAPI } from "src/wwwAPI"; +import { toDate } from "@/Utility"; +import { GetAvatarWwwLevelsAPI } from "@/wwwAPI"; export default function WwwLevelItem({ title, diff --git a/qwilight-fe/src/avatar/WwwLevelsView.tsx b/qwilight-fe/src/avatar/WwwLevelsView.tsx index bfc1d64..03b09f9 100644 --- a/qwilight-fe/src/avatar/WwwLevelsView.tsx +++ b/qwilight-fe/src/avatar/WwwLevelsView.tsx @@ -1,11 +1,11 @@ import { observer } from "mobx-react-lite"; import { ListGroup } from "reactstrap"; -import WwwLevelItem from "src/avatar/WwwLevelItem"; -import { AvatarWwwLevelLoading } from "src/Loading"; -import { GetAvatar } from "src/avatar/useGetAvatar"; -import useGetAvatarWwwLevels from "src/avatar/useGetAvatarWwwLevels"; -import { useAvatarStore } from "src/Stores"; +import WwwLevelItem from "@/avatar/WwwLevelItem"; +import { WwwLevelLoading } from "@/Loading"; +import { GetAvatar } from "@/avatar/useGetAvatar"; +import useGetAvatarWwwLevels from "@/avatar/useGetAvatarWwwLevels"; +import { useAvatarStore } from "@/Stores"; export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => { const { tabPosition } = useAvatarStore(); @@ -27,7 +27,7 @@ /> )) ) : ( - + )} ); diff --git a/qwilight-fe/src/avatar/useGetAvatar.ts b/qwilight-fe/src/avatar/useGetAvatar.ts index 5ef3b69..20b05c7 100644 --- a/qwilight-fe/src/avatar/useGetAvatar.ts +++ b/qwilight-fe/src/avatar/useGetAvatar.ts @@ -1,12 +1,12 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; import { useWant } from "taehui-ts/fe-utility"; -import { wwwAXIOS } from "src/Www"; -import { AvatarAPIAvatar, AvatarAPIWantAvatar } from "src/wwwAPI"; -import { formatText, toDate } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { AvatarAPIAvatar, AvatarAPIWantAvatar } from "@/wwwAPI"; +import { formatText, toDate } from "@/Utility"; +import { useTranslations } from "next-intl"; export type GetAvatar = { avatarID: string; @@ -38,14 +38,14 @@ }; export default function useGetAvatar() { - const { want } = useWant("/qwilight/avatar"); + const { want } = useWant("/avatar"); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); return useQuery({ - enabled: !!want && pathname.startsWith("/qwilight/avatar"), + enabled: !!want && pathname.startsWith("/avatar"), queryKey: ["avatar", want], queryFn: async () => { const { data } = await wwwAXIOS.get< diff --git a/qwilight-fe/src/avatar/useGetAvatarAbility.ts b/qwilight-fe/src/avatar/useGetAvatarAbility.ts index e8434b6..4c70fd7 100644 --- a/qwilight-fe/src/avatar/useGetAvatarAbility.ts +++ b/qwilight-fe/src/avatar/useGetAvatarAbility.ts @@ -1,22 +1,22 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; import { sprintf } from "sprintf-js"; -import { wwwAXIOS } from "src/Www"; -import { GetAvatarAbilitiesAPI } from "src/wwwAPI"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetAvatarAbilitiesAPI } from "@/wwwAPI"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAvatarAbility( inputMode: "5K" | "7K" | "9K", avatarID?: string, ) { - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); return useQuery({ - enabled: !!avatarID && pathname.startsWith("/qwilight/avatar"), + enabled: !!avatarID && pathname.startsWith("/avatar"), queryKey: ["avatarAbility", inputMode, avatarID], queryFn: async () => { const { data } = await wwwAXIOS.get( diff --git a/qwilight-fe/src/avatar/useGetAvatarFavorites.ts b/qwilight-fe/src/avatar/useGetAvatarFavorites.ts index 039a0fe..daa2f2f 100644 --- a/qwilight-fe/src/avatar/useGetAvatarFavorites.ts +++ b/qwilight-fe/src/avatar/useGetAvatarFavorites.ts @@ -1,11 +1,11 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetAvatarFavoritesAPI } from "src/wwwAPI"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetAvatarFavoritesAPI } from "@/wwwAPI"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAvatarFavorites( inputMode: "6K" | "5K" | "7K" | "9K" | "10K" | "14K" | "24K" | "48K", @@ -13,10 +13,10 @@ ) { const { pathname } = useLocation(); - const { t } = useTranslation(); + const t = useTranslations(); return useQuery({ - enabled: !!avatarID && pathname.startsWith("/qwilight/avatar"), + enabled: !!avatarID && pathname.startsWith("/avatar"), queryKey: ["avatarFavorites", inputMode, avatarID], queryFn: async () => { const { data } = await wwwAXIOS.get( diff --git a/qwilight-fe/src/avatar/useGetAvatarLasts.ts b/qwilight-fe/src/avatar/useGetAvatarLasts.ts index 3b35693..6561407 100644 --- a/qwilight-fe/src/avatar/useGetAvatarLasts.ts +++ b/qwilight-fe/src/avatar/useGetAvatarLasts.ts @@ -1,9 +1,9 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; -import { wwwAXIOS } from "src/Www"; -import { GetAvatarLastsAPI } from "src/wwwAPI"; -import { toDate } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetAvatarLastsAPI } from "@/wwwAPI"; +import { toDate } from "@/Utility"; export default function useGetAvatarLasts( inputMode: "6K" | "5K" | "7K" | "9K" | "10K" | "14K" | "24K" | "48K", @@ -12,7 +12,7 @@ const { pathname } = useLocation(); return useQuery({ - enabled: !!avatarID && pathname.startsWith("/qwilight/avatar"), + enabled: !!avatarID && pathname.startsWith("/avatar"), queryKey: ["avatarLasts", inputMode, avatarID], queryFn: async () => { const { data } = await wwwAXIOS.get( diff --git a/qwilight-fe/src/avatar/useGetAvatarWwwLevels.ts b/qwilight-fe/src/avatar/useGetAvatarWwwLevels.ts index c7132cd..66a5a45 100644 --- a/qwilight-fe/src/avatar/useGetAvatarWwwLevels.ts +++ b/qwilight-fe/src/avatar/useGetAvatarWwwLevels.ts @@ -1,14 +1,14 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; -import { wwwAXIOS } from "src/Www"; -import { GetAvatarWwwLevelsAPI } from "src/wwwAPI"; +import { wwwAXIOS } from "@/Www"; +import { GetAvatarWwwLevelsAPI } from "@/wwwAPI"; export default function useGetAvatarWwwLevels(avatarID?: string) { const { pathname } = useLocation(); return useQuery({ - enabled: !!avatarID && pathname.startsWith("/qwilight/avatar"), + enabled: !!avatarID && pathname.startsWith("/avatar"), queryKey: ["avatarWwwLevels", avatarID], queryFn: async () => { const { data } = await wwwAXIOS.get( diff --git a/qwilight-fe/src/etc/EdgeItem.tsx b/qwilight-fe/src/etc/EdgeItem.tsx index 8378b13..3c4d303 100644 --- a/qwilight-fe/src/etc/EdgeItem.tsx +++ b/qwilight-fe/src/etc/EdgeItem.tsx @@ -1,6 +1,7 @@ import { Col, ListGroupItem, Row } from "reactstrap"; -import scss from "src/etc/EdgeItem.module.scss"; +import scss from "@/etc/EdgeItem.module.scss"; +import Image from "next/image"; export default function EdgeItem({ edge, @@ -13,7 +14,7 @@ - ; - } - - return ( - <> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/qwilight-fe/src/etc/FavoritesView.tsx b/qwilight-fe/src/etc/FavoritesView.tsx index 576059f..f4f6adf 100644 --- a/qwilight-fe/src/etc/FavoritesView.tsx +++ b/qwilight-fe/src/etc/FavoritesView.tsx @@ -1,7 +1,7 @@ import { Badge, ListGroup } from "reactstrap"; -import NoteItem from "src/note/NoteItem"; -import { EtcAPINoteFile } from "src/wwwAPI"; +import NoteItem from "@/note/NoteItem"; +import { EtcAPINoteFile } from "@/wwwAPI"; export default function FavoritesView({ title, diff --git a/qwilight-fe/src/etc/ModeItem.tsx b/qwilight-fe/src/etc/ModeItem.tsx index 5765d16..8590bf5 100644 --- a/qwilight-fe/src/etc/ModeItem.tsx +++ b/qwilight-fe/src/etc/ModeItem.tsx @@ -1,11 +1,12 @@ +import Image, { StaticImageData } from "next/image"; import { Badge, Col, ListGroup, ListGroupItem, Row } from "reactstrap"; -import { useTranslation } from "react-i18next"; import { sprintf } from "sprintf-js"; -import { formatText } from "src/Utility"; -import { EtcAPIMode } from "src/wwwAPI"; +import { formatText } from "@/Utility"; +import { EtcAPIMode } from "@/wwwAPI"; -import scss from "src/etc/ModeItem.module.scss"; +import scss from "@/etc/ModeItem.module.scss"; +import { useTranslations } from "next-intl"; export default function ModeItem({ title, @@ -14,9 +15,9 @@ }: { title: string; modes: EtcAPIMode[]; - drawings: string[]; + drawings: (string | StaticImageData)[]; }) { - const { t } = useTranslation(); + const t = useTranslations(); return ( @@ -27,7 +28,7 @@ - + {sprintf(t("textHandled"), formatText(value))} diff --git a/qwilight-fe/src/etc/TitleItem.tsx b/qwilight-fe/src/etc/TitleItem.tsx index 2d80071..0f329c8 100644 --- a/qwilight-fe/src/etc/TitleItem.tsx +++ b/qwilight-fe/src/etc/TitleItem.tsx @@ -1,6 +1,6 @@ import { Col, ListGroupItem, Row } from "reactstrap"; -import Title from "src/Title"; +import Title from "@/Title"; export default function TitleItem({ title, diff --git a/qwilight-fe/src/etc/TotalEdgesView.tsx b/qwilight-fe/src/etc/TotalEdgesView.tsx index d64a3f6..f880e52 100644 --- a/qwilight-fe/src/etc/TotalEdgesView.tsx +++ b/qwilight-fe/src/etc/TotalEdgesView.tsx @@ -1,16 +1,16 @@ -import { useTranslation } from "react-i18next"; import { Badge, ListGroup } from "reactstrap"; import { sprintf } from "sprintf-js"; -import EdgeItem from "src/etc/EdgeItem"; -import { EtcAPIEdge } from "src/wwwAPI"; +import EdgeItem from "@/etc/EdgeItem"; +import { EtcAPIEdge } from "@/wwwAPI"; +import { useTranslations } from "next-intl"; export default function TotalEdgesView({ totalEdges, }: { totalEdges: EtcAPIEdge[]; }) { - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/qwilight-fe/src/etc/TotalNoteFilesView.tsx b/qwilight-fe/src/etc/TotalNoteFilesView.tsx index 3ff016d..4e2a355 100644 --- a/qwilight-fe/src/etc/TotalNoteFilesView.tsx +++ b/qwilight-fe/src/etc/TotalNoteFilesView.tsx @@ -1,16 +1,16 @@ -import { useTranslation } from "react-i18next"; import { Badge, ListGroup } from "reactstrap"; import { sprintf } from "sprintf-js"; -import NoteItem from "src/note/NoteItem"; -import { EtcAPINoteFile } from "src/wwwAPI"; +import NoteItem from "@/note/NoteItem"; +import { EtcAPINoteFile } from "@/wwwAPI"; +import { useTranslations } from "next-intl"; export default function TotalNoteFilesView({ totalNoteFiles, }: { totalNoteFiles: EtcAPINoteFile[]; }) { - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/qwilight-fe/src/etc/TotalTitlesView.tsx b/qwilight-fe/src/etc/TotalTitlesView.tsx index db45d86..d7f8ba1 100644 --- a/qwilight-fe/src/etc/TotalTitlesView.tsx +++ b/qwilight-fe/src/etc/TotalTitlesView.tsx @@ -1,16 +1,16 @@ -import { useTranslation } from "react-i18next"; import { Badge, ListGroup } from "reactstrap"; import { sprintf } from "sprintf-js"; -import TitleItem from "src/etc/TitleItem"; -import { EtcAPITitle } from "src/wwwAPI"; +import TitleItem from "@/etc/TitleItem"; +import { EtcAPITitle } from "@/wwwAPI"; +import { useTranslations } from "next-intl"; export default function TotalTitlesView({ totalTitles, }: { totalTitles: EtcAPITitle[]; }) { - const { t } = useTranslation(); + const t = useTranslations(); return ( diff --git a/qwilight-fe/src/etc/useGetEtc.ts b/qwilight-fe/src/etc/useGetEtc.ts index ce5138b..1dfe672 100644 --- a/qwilight-fe/src/etc/useGetEtc.ts +++ b/qwilight-fe/src/etc/useGetEtc.ts @@ -2,15 +2,15 @@ import { useLocation } from "react-router-dom"; import { getLanguage } from "taehui-ts/language"; -import { wwwAXIOS } from "src/Www"; -import { GetEtcAPI } from "src/wwwAPI"; +import { wwwAXIOS } from "@/Www"; +import { GetEtcAPI } from "@/wwwAPI"; export default function useGetEtc() { const { pathname } = useLocation(); const language = getLanguage(); return useQuery({ - enabled: pathname.startsWith("/qwilight/etc"), + enabled: pathname.startsWith("/etc"), queryKey: ["etc"], queryFn: async () => { const { data } = await wwwAXIOS.get("/etc", { diff --git a/qwilight-fe/src/hof/AvatarItem.tsx b/qwilight-fe/src/hof/AvatarItem.tsx index d1b948d..e8fccba 100644 --- a/qwilight-fe/src/hof/AvatarItem.tsx +++ b/qwilight-fe/src/hof/AvatarItem.tsx @@ -1,9 +1,9 @@ import { Col, ListGroupItem, Row } from "reactstrap"; import { useTo } from "taehui-ts/fe-utility"; -import { HOF } from "src/hof/HOF"; -import AvatarDrawing from "src/AvatarDrawing"; -import AvatarTitle from "src/AvatarTitle"; +import { HOF } from "@/hof/HOF"; +import AvatarDrawing from "@/AvatarDrawing"; +import AvatarTitle from "@/AvatarTitle"; export default function AvatarItem({ avatarID, avatarName, text }: HOF) { const to = useTo(); @@ -13,7 +13,7 @@ { - to(`/qwilight/avatar/${encodeURIComponent("#")}${avatarID}`); + to(`/avatar/${encodeURIComponent("#")}${avatarID}`); }} > diff --git a/qwilight-fe/src/hof/HOFView.tsx b/qwilight-fe/src/hof/HOFView.tsx deleted file mode 100644 index 6144c3a..0000000 --- a/qwilight-fe/src/hof/HOFView.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import { useTranslation } from "react-i18next"; -import { - ListGroup, - Nav, - NavItem, - NavLink, - TabContent, - TabPane, -} from "reactstrap"; -import { observer } from "mobx-react-lite"; - -import { useHOFStore } from "src/Stores"; -import { HOF } from "src/hof/HOF"; -import AvatarItem from "src/hof/AvatarItem"; -import { HOFAvatarLoading } from "src/Loading"; -import useGetTotalTotalHOF from "src/hof/useGetTotalTotalHOF"; -import useGetTotalHighestHOF from "src/hof/useGetTotalHighestHOF"; -import useGetTotalStandHOF from "src/hof/useGetTotalStandHOF"; -import useGetTotalBandHOF from "src/hof/useGetTotalBandHOF"; -import useGetAtTotalHOF from "src/hof/useGetAtTotalHOF"; -import useGetAtHighestHOF from "src/hof/useGetAtHighestHOF"; -import useGetAtStandHOF from "src/hof/useGetAtStandHOF"; -import useGetAtBandHOF from "src/hof/useGetAtBandHOF"; -import useGetAbility5KHOF from "src/hof/useGetAbility5KHOF"; -import useGetAbility7KHOF from "src/hof/useGetAbility7KHOF"; -import useGetAbility9KHOF from "src/hof/useGetAbility9KHOF"; -import useGetLevelHOF from "src/hof/useGetLevelHOF"; - -const getAvatarItems = (hofs: HOF[]) => { - return hofs.map(({ avatarID, avatarName, text }) => ( - - )); -}; - -export default observer(() => { - const { - tabPosition, - totalTabPosition, - atTabPosition, - abilityTabPosition, - setTabPosition, - setTotalTabPosition, - setAtTabPosition, - setAbilityTabPosition, - } = useHOFStore(); - const { t } = useTranslation(); - - const { data: totalTotalHOF, isFetched: isTotalTotalHOFLoaded } = - useGetTotalTotalHOF(); - const { data: totalHighestHOF, isFetched: isTotalHighestHOFLoaded } = - useGetTotalHighestHOF(); - const { data: totalStandHOF, isFetched: isTotalStandHOFLoaded } = - useGetTotalStandHOF(); - const { data: totalBandHOF, isFetched: isTotalBandHOFLoaded } = - useGetTotalBandHOF(); - const { data: atTotalHOF, isFetched: isAtTotalHOFLoaded } = - useGetAtTotalHOF(); - const { data: atHighestHOF, isFetched: isAtHighestHOFLoaded } = - useGetAtHighestHOF(); - const { data: atStandHOF, isFetched: isAtStandHOFLoaded } = - useGetAtStandHOF(); - const { data: atBandHOF, isFetched: isAtBandHOFLoaded } = useGetAtBandHOF(); - const { data: ability5KHOF, isFetched: isAbility5KHOFLoaded } = - useGetAbility5KHOF(); - const { data: ability7KHOF, isFetched: isAbility7KHOFLoaded } = - useGetAbility7KHOF(); - const { data: ability9KHOF, isFetched: isAbility9KHOFLoaded } = - useGetAbility9KHOF(); - const { data: levelHOF, isFetched: isLevelHOFLoaded } = useGetLevelHOF(); - - const getProperties = (i: number) => ({ - className: tabPosition === i ? "active route" : "route", - onClick: () => { - setTabPosition(i); - }, - }); - - const getTotalProperties = (i: number) => ({ - className: totalTabPosition === i ? "active route" : "route", - onClick: () => { - setTotalTabPosition(i); - }, - }); - - const getAtProperties = (i: number) => ({ - className: atTabPosition === i ? "active route" : "route", - onClick: () => { - setAtTabPosition(i); - }, - }); - - const getAbilityProperties = (i: number) => ({ - className: abilityTabPosition === i ? "active route" : "route", - onClick: () => { - setAbilityTabPosition(i); - }, - }); - - return ( - <> - - - - - - - - {isTotalTotalHOFLoaded ? ( - getAvatarItems(totalTotalHOF) - ) : ( - - )} - - - - - {isTotalHighestHOFLoaded ? ( - getAvatarItems(totalHighestHOF) - ) : ( - - )} - - - - - {isTotalStandHOFLoaded ? ( - getAvatarItems(totalStandHOF) - ) : ( - - )} - - - - - {isTotalBandHOFLoaded ? ( - getAvatarItems(totalBandHOF) - ) : ( - - )} - - - - - - - - - - {isAtTotalHOFLoaded ? ( - getAvatarItems(atTotalHOF) - ) : ( - - )} - - - - - {isAtHighestHOFLoaded ? ( - getAvatarItems(atHighestHOF) - ) : ( - - )} - - - - - {isAtStandHOFLoaded ? ( - getAvatarItems(atStandHOF) - ) : ( - - )} - - - - - {isAtBandHOFLoaded ? ( - getAvatarItems(atBandHOF) - ) : ( - - )} - - - - - - - - - - {isAbility5KHOFLoaded ? ( - getAvatarItems(ability5KHOF) - ) : ( - - )} - - - - - {isAbility7KHOFLoaded ? ( - getAvatarItems(ability7KHOF) - ) : ( - - )} - - - - - {isAbility9KHOFLoaded ? ( - getAvatarItems(ability9KHOF) - ) : ( - - )} - - - - - - - {isLevelHOFLoaded ? ( - getAvatarItems(levelHOF) - ) : ( - - )} - - - - - ); -}); diff --git a/qwilight-fe/src/hof/useGetAbility5KHOF.ts b/qwilight-fe/src/hof/useGetAbility5KHOF.ts index 0603512..f1eb956 100644 --- a/qwilight-fe/src/hof/useGetAbility5KHOF.ts +++ b/qwilight-fe/src/hof/useGetAbility5KHOF.ts @@ -2,10 +2,10 @@ import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; export default function useGetAbility5KHOF() { const { tabPosition, abilityTabPosition } = useHOFStore(); @@ -22,7 +22,7 @@ enabled: tabPosition === 2 && abilityTabPosition === 0 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["ability5KHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/ability/5K"); diff --git a/qwilight-fe/src/hof/useGetAbility7KHOF.ts b/qwilight-fe/src/hof/useGetAbility7KHOF.ts index d77f389..5607fca 100644 --- a/qwilight-fe/src/hof/useGetAbility7KHOF.ts +++ b/qwilight-fe/src/hof/useGetAbility7KHOF.ts @@ -2,10 +2,10 @@ import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; export default function useGetAbility7KHOF() { const { tabPosition, abilityTabPosition } = useHOFStore(); @@ -22,7 +22,7 @@ enabled: tabPosition === 2 && abilityTabPosition === 1 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["ability7KHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/ability/7K"); diff --git a/qwilight-fe/src/hof/useGetAbility9KHOF.ts b/qwilight-fe/src/hof/useGetAbility9KHOF.ts index 3817b9a..12f1439 100644 --- a/qwilight-fe/src/hof/useGetAbility9KHOF.ts +++ b/qwilight-fe/src/hof/useGetAbility9KHOF.ts @@ -2,10 +2,10 @@ import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; export default function useGetAbility9KHOF() { const { tabPosition, abilityTabPosition } = useHOFStore(); @@ -22,7 +22,7 @@ enabled: tabPosition === 2 && abilityTabPosition === 2 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["ability9KHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/ability/9K"); diff --git a/qwilight-fe/src/hof/useGetAtBandHOF.ts b/qwilight-fe/src/hof/useGetAtBandHOF.ts index ffff445..15cee6f 100644 --- a/qwilight-fe/src/hof/useGetAtBandHOF.ts +++ b/qwilight-fe/src/hof/useGetAtBandHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAtBandHOF() { const { tabPosition, atTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -23,9 +23,7 @@ }[] >({ enabled: - tabPosition === 1 && - atTabPosition === 3 && - pathname.startsWith("/qwilight/hof"), + tabPosition === 1 && atTabPosition === 3 && pathname.startsWith("/hof"), queryKey: ["atBandHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/atBand"); diff --git a/qwilight-fe/src/hof/useGetAtHighestHOF.ts b/qwilight-fe/src/hof/useGetAtHighestHOF.ts index eef5c3e..069af69 100644 --- a/qwilight-fe/src/hof/useGetAtHighestHOF.ts +++ b/qwilight-fe/src/hof/useGetAtHighestHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAtHighestHOF() { const { tabPosition, atTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -23,9 +23,7 @@ }[] >({ enabled: - tabPosition === 1 && - atTabPosition === 1 && - pathname.startsWith("/qwilight/hof"), + tabPosition === 1 && atTabPosition === 1 && pathname.startsWith("/hof"), queryKey: ["atHighestHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/atHighest"); diff --git a/qwilight-fe/src/hof/useGetAtStandHOF.ts b/qwilight-fe/src/hof/useGetAtStandHOF.ts index 0cf663a..86948a3 100644 --- a/qwilight-fe/src/hof/useGetAtStandHOF.ts +++ b/qwilight-fe/src/hof/useGetAtStandHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAtStandHOF() { const { tabPosition, atTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -23,9 +23,7 @@ }[] >({ enabled: - tabPosition === 1 && - atTabPosition === 2 && - pathname.startsWith("/qwilight/hof"), + tabPosition === 1 && atTabPosition === 2 && pathname.startsWith("/hof"), queryKey: ["atStandHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/atStand"); diff --git a/qwilight-fe/src/hof/useGetAtTotalHOF.ts b/qwilight-fe/src/hof/useGetAtTotalHOF.ts index d82a0dc..dbe928a 100644 --- a/qwilight-fe/src/hof/useGetAtTotalHOF.ts +++ b/qwilight-fe/src/hof/useGetAtTotalHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetAtTotalHOF() { const { tabPosition, atTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -23,9 +23,7 @@ }[] >({ enabled: - tabPosition === 1 && - atTabPosition === 0 && - pathname.startsWith("/qwilight/hof"), + tabPosition === 1 && atTabPosition === 0 && pathname.startsWith("/hof"), queryKey: ["atTotalHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/atTotal"); diff --git a/qwilight-fe/src/hof/useGetLevelHOF.ts b/qwilight-fe/src/hof/useGetLevelHOF.ts index 3156e14..c361ac1 100644 --- a/qwilight-fe/src/hof/useGetLevelHOF.ts +++ b/qwilight-fe/src/hof/useGetLevelHOF.ts @@ -2,10 +2,10 @@ import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; export default function useGetLevelHOF() { const { tabPosition } = useHOFStore(); @@ -19,7 +19,7 @@ text: string; }[] >({ - enabled: tabPosition === 3 && pathname.startsWith("/qwilight/hof"), + enabled: tabPosition === 3 && pathname.startsWith("/hof"), queryKey: ["levelHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/level"); diff --git a/qwilight-fe/src/hof/useGetTotalBandHOF.ts b/qwilight-fe/src/hof/useGetTotalBandHOF.ts index 5d7973e..cf36b3c 100644 --- a/qwilight-fe/src/hof/useGetTotalBandHOF.ts +++ b/qwilight-fe/src/hof/useGetTotalBandHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetTotalBandHOF() { const { tabPosition, totalTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -25,7 +25,7 @@ enabled: tabPosition === 0 && totalTabPosition === 3 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["totalBandHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/totalBand"); diff --git a/qwilight-fe/src/hof/useGetTotalHighestHOF.ts b/qwilight-fe/src/hof/useGetTotalHighestHOF.ts index a3fe4ed..c233646 100644 --- a/qwilight-fe/src/hof/useGetTotalHighestHOF.ts +++ b/qwilight-fe/src/hof/useGetTotalHighestHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetTotalHighestHOF() { const { tabPosition, totalTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -25,7 +25,7 @@ enabled: tabPosition === 0 && totalTabPosition === 1 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["totalHighestHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/totalHighest"); diff --git a/qwilight-fe/src/hof/useGetTotalStandHOF.ts b/qwilight-fe/src/hof/useGetTotalStandHOF.ts index 964d79a..c13c338 100644 --- a/qwilight-fe/src/hof/useGetTotalStandHOF.ts +++ b/qwilight-fe/src/hof/useGetTotalStandHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetTotalStandHOF() { const { tabPosition, totalTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -25,7 +25,7 @@ enabled: tabPosition === 0 && totalTabPosition === 2 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["totalStandHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/totalStand"); diff --git a/qwilight-fe/src/hof/useGetTotalTotalHOF.ts b/qwilight-fe/src/hof/useGetTotalTotalHOF.ts index 7a0cca9..3a34d8a 100644 --- a/qwilight-fe/src/hof/useGetTotalTotalHOF.ts +++ b/qwilight-fe/src/hof/useGetTotalTotalHOF.ts @@ -1,17 +1,17 @@ import { useQuery } from "@tanstack/react-query"; import { useLocation } from "react-router-dom"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetHOFAPI } from "src/wwwAPI"; -import { useHOFStore } from "src/Stores"; -import { formatText } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetHOFAPI } from "@/wwwAPI"; +import { useHOFStore } from "@/Stores"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function useGetTotalTotalHOF() { const { tabPosition, totalTabPosition } = useHOFStore(); - const { t } = useTranslation(); + const t = useTranslations(); const { pathname } = useLocation(); @@ -25,7 +25,7 @@ enabled: tabPosition === 0 && totalTabPosition === 0 && - pathname.startsWith("/qwilight/hof"), + pathname.startsWith("/hof"), queryKey: ["totalTotalHOF"], queryFn: async () => { const { data } = await wwwAXIOS.get("/hof/totalTotal"); diff --git a/qwilight-fe/src/i18n.ts b/qwilight-fe/src/i18n.ts new file mode 100644 index 0000000..ac20b23 --- /dev/null +++ b/qwilight-fe/src/i18n.ts @@ -0,0 +1,14 @@ +import { notFound } from "next/navigation"; +import { getRequestConfig } from "next-intl/server"; + +const locales = ["en", "ko"]; + +export default getRequestConfig(async ({ locale }) => { + if (!locales.includes(locale)) { + notFound(); + } + + return { + messages: (await import(`@/assets/language/${locale}.json`)).default, + }; +}); diff --git a/qwilight-fe/src/index.scss b/qwilight-fe/src/index.scss deleted file mode 100644 index e49dd08..0000000 --- a/qwilight-fe/src/index.scss +++ /dev/null @@ -1,240 +0,0 @@ -* { - margin: 0; - font-family: "Century Gothic", - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - "Roboto", - "Oxygen", - "Ubuntu", - "Cantarell", - "Fira Sans", - "Droid Sans", - "Helvetica Neue", - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -@mixin default() { - font-size: 0.75rem; -} - -a { - &.nav-link { - @include default(); - color: white; - - &:hover { - @include default(); - color: white; - } - } -} - -body { - background: url("assets/dark-honeycomb.png"); -} - -button { - &.btn { - @include default(); - } - - &.page-link { - @include default(); - } - - &.dropdown-item { - @include default(); - } -} - -input[type="button"], -input[type="submit"], -input[type="search"], -input[type="text"], -input[type="password"] { - @include default(); -} - -li { - &.page-item { - @include default(); - } - - &.list-group-item { - background-color: rgba(0, 0, 0, 0.125); - border: none; - } -} - -.target { - border: thin solid; - border-image: linear-gradient(43deg, #4158d0 0%, #c850c0 46%, #ffcc70 100%); - border-image-slice: 1; -} - -div { - &.offcanvas-body { - background-color: black; - } -} - -span { - & { - @include default(); - } - - :not(.page-link, .contexify_itemContent, .alert) > & { - color: white; - } - - ul.list-group > &.badge { - font-weight: normal; - border-radius: 0; - } - - div.modal-content & { - color: black; - } - - &.date { - color: darkgray; - } - - &.stand { - color: white; - } - - &.point { - color: white; - } - - &.band { - color: white; - } - - &.title { - color: white; - } - - &.genre { - color: darkgray; - } - - &.fittedText { - color: dodgerblue; - } - - &.artist { - color: lightgray; - } - - &.level0 { - color: darkgray; - } - - &.level1 { - color: mediumspringgreen; - } - - &.level2 { - color: mediumturquoise; - } - - &.level3 { - color: yellow; - } - - &.level4 { - color: mediumvioletred; - } - - &.level5 { - color: mediumpurple; - } - - &.titleLV2000 { - background: linear-gradient( - to right, - red, - orange, - yellow, - green, - blue, - indigo, - purple - ); - background-clip: text; - -webkit-text-fill-color: transparent; - } - - &.highestJudgment { - color: cyan; - } - - &.higherJudgment { - color: deepskyblue; - } - - &.highJudgment { - color: lightgreen; - } - - &.lowJudgment { - color: yellow; - } - - &.lowerJudgment { - color: mediumpurple; - } - - &.lowestJudgment { - color: red; - } - - &.S\+ { - color: gold; - } - - &.S { - color: gold; - } - - &.A\+ { - color: green; - } - - &.A { - color: green; - } - - &.B { - color: blue; - } - - &.C { - color: magenta; - } - - &.D { - color: red; - } - - &.audioMultiplier { - color: white; - } - - &.avatarPlace { - font-size: 1.5rem; - } - - &.avatarIntro { - white-space: pre-line; - } -} - -.route { - cursor: pointer; -} diff --git a/qwilight-fe/src/index.tsx b/qwilight-fe/src/index.tsx deleted file mode 100644 index a091cf8..0000000 --- a/qwilight-fe/src/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { createRoot } from "react-dom/client"; -import { BrowserRouter } from "react-router-dom"; -import { initReactI18next } from "react-i18next"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import i18n from "i18next"; -import { getLanguage } from "taehui-ts/language"; - -import Language from "src/Language.json"; -import { Stores } from "src/Stores"; -import QwilightView from "src/qwilight/QwilightView"; - -import "bootstrap/dist/css/bootstrap.min.css"; -import "react-contexify/dist/ReactContexify.css"; -import "react-toastify/dist/ReactToastify.css"; -import "src/index.scss"; - -const root = document.getElementById("root"); -if (root) { - (async () => { - await i18n.use(initReactI18next).init({ - resources: Language, - }); - - const language = getLanguage(); - await i18n.changeLanguage(language); - - const queryClient = new QueryClient(); - createRoot(root).render( - - - - - - - , - ); - })(); -} diff --git a/qwilight-fe/src/middleware.ts b/qwilight-fe/src/middleware.ts new file mode 100644 index 0000000..69dc475 --- /dev/null +++ b/qwilight-fe/src/middleware.ts @@ -0,0 +1,12 @@ +import createMiddleware from "next-intl/middleware"; + +const locales = ["en", "ko"]; + +export default createMiddleware({ + locales, + defaultLocale: locales[0], +}); + +export const config = { + matcher: ["/((?!www|api|_next|.*\\..*).*)"], +}; diff --git a/qwilight-fe/src/note/CommentItem.tsx b/qwilight-fe/src/note/CommentItem.tsx index 461d9e7..9987755 100644 --- a/qwilight-fe/src/note/CommentItem.tsx +++ b/qwilight-fe/src/note/CommentItem.tsx @@ -1,26 +1,29 @@ +"use client"; + +import Image from "next/image"; import { useMemo } from "react"; import { Col, Row } from "reactstrap"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; import { useTo } from "taehui-ts/fe-utility"; -import { GetCommentAPI } from "src/wwwAPI"; +import { GetCommentAPI } from "@/wwwAPI"; import { formatText, getHitPointsClass, getQuitStatusValue, toDate, -} from "src/Utility"; -import AvatarDrawing from "src/AvatarDrawing"; -import AvatarTitle from "src/AvatarTitle"; +} from "@/Utility"; +import AvatarDrawing from "@/AvatarDrawing"; +import AvatarTitle from "@/AvatarTitle"; -import w0 from "src/assets/w0.png"; -import w1 from "src/assets/w1.png"; -import w2 from "src/assets/w2.png"; -import w4 from "src/assets/w4.png"; -import w5 from "src/assets/w5.png"; -import w6 from "src/assets/w6.png"; -import w7 from "src/assets/w7.png"; +import w0 from "@/assets/w0.png"; +import w1 from "@/assets/w1.png"; +import w2 from "@/assets/w2.png"; +import w4 from "@/assets/w4.png"; +import w5 from "@/assets/w5.png"; +import w6 from "@/assets/w6.png"; +import w7 from "@/assets/w7.png"; +import { useTranslations } from "next-intl"; const ws = [w0, w1, w2, "", w4, w5, w6, w7]; @@ -43,13 +46,13 @@ () => getQuitStatusValue(point, stand), [point, stand], ); - const { t } = useTranslation(); const to = useTo(); + const t = useTranslations(); return ( { - to(`/qwilight/avatar/${encodeURIComponent("#")}${avatarID}`); + to(`/avatar/${encodeURIComponent("#")}${avatarID}`); }} className={`g-0 route ${isTargetAvatar ? "target" : ""}`} > @@ -57,7 +60,7 @@ - + {quit} diff --git a/qwilight-fe/src/note/CommentItems.tsx b/qwilight-fe/src/note/CommentItems.tsx index 2bcc4db..b0ffc28 100644 --- a/qwilight-fe/src/note/CommentItems.tsx +++ b/qwilight-fe/src/note/CommentItems.tsx @@ -1,6 +1,9 @@ -import { GetCommentAPI } from "src/wwwAPI"; -import CommentItem from "src/note/CommentItem"; -import { formatText } from "src/Utility"; +"use client"; + +import { GetCommentAPI } from "@/wwwAPI"; +import CommentItem from "@/note/CommentItem"; +import { formatText } from "@/Utility"; +import { useTranslations } from "next-intl"; export default function CommentItems({ comments, diff --git a/qwilight-fe/src/note/FitInput.tsx b/qwilight-fe/src/note/FitInput.tsx index d07074e..b9fd963 100644 --- a/qwilight-fe/src/note/FitInput.tsx +++ b/qwilight-fe/src/note/FitInput.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useState } from "react"; import { Dropdown, @@ -5,14 +7,15 @@ DropdownMenu, DropdownToggle, } from "reactstrap"; -import { useTranslation } from "react-i18next"; import { useIntParam } from "taehui-ts/fe-utility"; +import { useTranslations } from "next-intl"; export default function FitInput() { const [isFitOpened, setFitOpened] = useState(false); - const { t } = useTranslation(); const { param: fit, setParam: setFit } = useIntParam("fit", 0); + const t = useTranslations(); + const onInput = (fit: number) => () => { setFit(fit); }; diff --git a/qwilight-fe/src/note/NoteItem.tsx b/qwilight-fe/src/note/NoteItem.tsx index a8403f9..5cdcbfa 100644 --- a/qwilight-fe/src/note/NoteItem.tsx +++ b/qwilight-fe/src/note/NoteItem.tsx @@ -1,23 +1,26 @@ +"use client"; + +import Image from "next/image"; import { useState } from "react"; import { Col, Collapse, ListGroupItem, Row, Spinner } from "reactstrap"; import { sprintf } from "sprintf-js"; -import { useTranslation } from "react-i18next"; import { Item, Menu, useContextMenu } from "react-contexify"; import Swal from "sweetalert2"; -import CommentItems from "src/note/CommentItems"; -import { GetNoteAPI } from "src/wwwAPI"; -import { formatText, getGenreText } from "src/Utility"; -import useGetComment from "src/note/useGetComment"; -import usePostToil from "src/note/usePostToil"; +import CommentItems from "@/note/CommentItems"; +import { GetNoteAPI } from "@/wwwAPI"; +import { formatText, getGenreText } from "@/Utility"; +import useGetComment from "@/note/useGetComment"; +import usePostToil from "@/note/usePostToil"; -import w0 from "src/assets/w0.png"; -import w1 from "src/assets/w1.png"; -import w2 from "src/assets/w2.png"; -import w4 from "src/assets/w4.png"; -import w5 from "src/assets/w5.png"; -import w6 from "src/assets/w6.png"; -import w7 from "src/assets/w7.png"; +import w0 from "@/assets/w0.png"; +import w1 from "@/assets/w1.png"; +import w2 from "@/assets/w2.png"; +import w4 from "@/assets/w4.png"; +import w5 from "@/assets/w5.png"; +import w6 from "@/assets/w6.png"; +import w7 from "@/assets/w7.png"; +import { useTranslations } from "next-intl"; const ws = [w0, w1, w2, "", w4, w5, w6, w7]; @@ -35,8 +38,9 @@ wantAvatarName, handled, }: GetNoteAPI["notes"][number] & { handled?: number }) { + const t = useTranslations(); + const [isCommentOpened, setCommentOpened] = useState(false); - const { t } = useTranslation(); const { show: viewToilInput } = useContextMenu({ id: `toil-${noteID}`, @@ -63,7 +67,7 @@ > {typeof handled === "number" && ( - + )} diff --git a/qwilight-fe/src/note/NoteItems.tsx b/qwilight-fe/src/note/NoteItems.tsx index 96a3724..aa0142c 100644 --- a/qwilight-fe/src/note/NoteItems.tsx +++ b/qwilight-fe/src/note/NoteItems.tsx @@ -1,11 +1,14 @@ +"use client"; + import { observer } from "mobx-react-lite"; import { Col, ListGroup, Row } from "reactstrap"; import { useWindowArea } from "taehui-ts/fe-utility"; -import { useNoteStore } from "src/Stores"; -import NoteItem from "src/note/NoteItem"; -import { NoteLoading } from "src/Loading"; -import useGetNote from "src/note/useGetNote"; +import { useNoteStore } from "@/Stores"; +import NoteItem from "@/note/NoteItem"; +import { NoteLoading } from "@/Loading"; +import useGetNote from "@/note/useGetNote"; +import { useEffect, useLayoutEffect, useState } from "react"; export default observer(() => { const { wantAvatar, viewUnit } = useNoteStore(); @@ -15,17 +18,22 @@ isFetched: isNoteLoaded, } = useGetNote(); - const line = useWindowArea().windowLength < 992 ? 1 : 2; + const { windowLength } = useWindowArea(); + const [table, setTable] = useState(1); + + useLayoutEffect(() => { + setTable(windowLength < 992 ? 1 : 2); + }, [windowLength]); return ( - {[...Array(line).keys()].map((i) => { + {[...Array(table).keys()].map((i) => { if (isNoteLoaded) { return ( {notes - .slice((viewUnit / line) * i, (viewUnit / line) * (i + 1)) + .slice((viewUnit / table) * i, (viewUnit / table) * (i + 1)) .map( ({ noteID, @@ -59,7 +67,7 @@ return ( - + ); diff --git a/qwilight-fe/src/note/NoteView.tsx b/qwilight-fe/src/note/NoteView.tsx deleted file mode 100644 index a938230..0000000 --- a/qwilight-fe/src/note/NoteView.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { useEffect } from "react"; -import { observer } from "mobx-react-lite"; -import { useTranslation } from "react-i18next"; -import { Button, Col, Input, Row } from "reactstrap"; -import { sprintf } from "sprintf-js"; -import { useIntParam, useWant } from "taehui-ts/fe-utility"; - -import { useNoteStore } from "src/Stores"; -import NoteItems from "src/note/NoteItems"; -import FitInput from "src/note/FitInput"; -import SrcInput from "src/note/SrcInput"; -import PositionInput from "src/note/PositionInput"; -import { formatText } from "src/Utility"; -import useGetNote from "src/note/useGetNote"; - -export default observer(() => { - const { - lastWant, - setLastWant, - lastSrc, - setLastSrc, - input, - setInput, - lastPage, - setLastPage, - viewUnit, - setWantAvatar, - } = useNoteStore(); - - const { want, setWant } = useWant("/qwilight/note"); - - const { param: page, setParam: setPage } = useIntParam("page", 1); - const { param: src } = useIntParam("src", 0); - - const { t } = useTranslation(); - - useEffect(() => { - if ((want !== lastWant || src !== lastSrc) && page > 1) { - setPage(1); - } - }, [lastSrc, lastWant, page, setPage, src, want]); - - useEffect(() => { - setLastWant(want); - }, [setLastWant, want]); - - useEffect(() => { - setLastSrc(src); - }, [setLastSrc, src]); - - useEffect(() => { - setWantAvatar(src === 1 ? want : ""); - }, [setWantAvatar, src, want]); - - const { - data: { highestCount, totalCount, noteCount }, - isFetched: isNoteLoaded, - } = useGetNote(); - - useEffect(() => { - if (isNoteLoaded) { - setLastPage(Math.max(1, Math.ceil(noteCount / viewUnit))); - } - }, [isNoteLoaded, noteCount, setLastPage, viewUnit]); - - useEffect(() => { - setInput(want); - }, [setInput, want]); - - const onWant = () => { - setWant(input); - }; - - const onClose = () => { - setWant(""); - }; - - return ( - <> - - - - - - - - - { - setInput(value); - }} - onKeyDown={({ key }) => { - if (key === "Enter") { - onWant(); - } - }} - /> - - - - - - - - - - - - - - - - {lastPage >= 0 && ( - - - - - - )} - - {isNoteLoaded && ( - - - - {sprintf(t("highestCountText"), formatText(highestCount))} - -
- {sprintf(t("totalCountText"), formatText(totalCount))} - -
- )} - - - - taehui@taehui.ddns.net', - ), - }} - /> - - - - ); -}); diff --git a/qwilight-fe/src/note/PositionInput.tsx b/qwilight-fe/src/note/PositionInput.tsx index 3f1aabb..9c6ea12 100644 --- a/qwilight-fe/src/note/PositionInput.tsx +++ b/qwilight-fe/src/note/PositionInput.tsx @@ -1,12 +1,14 @@ +"use client"; + import { useMemo } from "react"; import { observer } from "mobx-react-lite"; import { Pagination, PaginationItem, PaginationLink } from "reactstrap"; import { useIntParam } from "taehui-ts/fe-utility"; -import { useNoteStore } from "src/Stores"; +import { useNoteStore } from "@/Stores"; export default observer(() => { - const { pageUnit, lastPage } = useNoteStore(); + const { pageUnit, lastPage, lastWant, lastSrc } = useNoteStore(); const { param: page, setParam: setPage } = useIntParam("page", 1); diff --git a/qwilight-fe/src/note/SrcInput.tsx b/qwilight-fe/src/note/SrcInput.tsx index 86a9086..8cd46c7 100644 --- a/qwilight-fe/src/note/SrcInput.tsx +++ b/qwilight-fe/src/note/SrcInput.tsx @@ -1,5 +1,6 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; +"use client"; + +import { useEffect, useState } from "react"; import { Dropdown, DropdownItem, @@ -7,16 +8,24 @@ DropdownToggle, } from "reactstrap"; import { useIntParam } from "taehui-ts/fe-utility"; +import { useNoteStore } from "@/Stores"; +import { useTranslations } from "next-intl"; export default function SrcInput() { + const { setLastSrc, setWantAvatar } = useNoteStore(); const [isSrcOpened, setSrcOpened] = useState(false); - const { t } = useTranslation(); const { param: src, setParam: setSrc } = useIntParam("src", 0); + const t = useTranslations(); + const onInput = (src: number) => () => { setSrc(src); }; + useEffect(() => { + setLastSrc(src); + }, [setLastSrc, src]); + return ( { + setWant(wantInput); + }; + + useEffect(() => { + setWantInput(want); + }, [setWantInput, want]); + + useEffect(() => { + setLastWant(want); + }, [setLastWant, want]); + + return ( + { + setWantInput(value); + }} + onKeyDown={({ key }) => { + if (key === "Enter") { + onWant(); + } + }} + /> + ); +} diff --git a/qwilight-fe/src/note/setNoteStore.ts b/qwilight-fe/src/note/setNoteStore.ts index daa1398..1526734 100644 --- a/qwilight-fe/src/note/setNoteStore.ts +++ b/qwilight-fe/src/note/setNoteStore.ts @@ -3,7 +3,7 @@ lastWant: "", lastSrc: 0, wantAvatar: "", - input: "", + wantInput: "", lastPage: 1, pageUnit: 10, viewUnit: 20, @@ -16,8 +16,8 @@ this.lastSrc = lastSrc; }, - setInput(input: string) { - this.input = input; + setWantInput(wantInput: string) { + this.wantInput = wantInput; }, setWantAvatar(wantAvatar: string) { diff --git a/qwilight-fe/src/note/useGetComment.ts b/qwilight-fe/src/note/useGetComment.ts index d0e82ae..ac9c36e 100644 --- a/qwilight-fe/src/note/useGetComment.ts +++ b/qwilight-fe/src/note/useGetComment.ts @@ -1,9 +1,9 @@ import { useQuery } from "@tanstack/react-query"; import { getLanguage } from "taehui-ts/language"; -import { useSiteStore } from "src/Stores"; -import { wwwAXIOS } from "src/Www"; -import { GetCommentAPI } from "src/wwwAPI"; +import { useSiteStore } from "@/Stores"; +import { wwwAXIOS } from "@/Www"; +import { GetCommentAPI } from "@/wwwAPI"; export default function useGetComment( noteID: string, diff --git a/qwilight-fe/src/note/useGetNote.ts b/qwilight-fe/src/note/useGetNote.ts index a08c96d..3b80327 100644 --- a/qwilight-fe/src/note/useGetNote.ts +++ b/qwilight-fe/src/note/useGetNote.ts @@ -2,9 +2,10 @@ import { useQuery } from "@tanstack/react-query"; import { useIntParam, useWant } from "taehui-ts/fe-utility"; -import { wwwAXIOS } from "src/Www"; -import { GetNoteAPI } from "src/wwwAPI"; -import { useNoteStore } from "src/Stores"; +import { wwwAXIOS } from "@/Www"; +import { GetNoteAPI } from "@/wwwAPI"; +import { useNoteStore } from "@/Stores"; +import { useIsPath } from "taehui-ts/fe-utility"; export default function useGetNote() { const { viewUnit } = useNoteStore(); @@ -13,12 +14,12 @@ const { param: fit } = useIntParam("fit", 0); const { param: src } = useIntParam("src", 0); - const { want } = useWant("/qwilight/note"); + const { want } = useWant("/note"); - const { pathname } = useLocation(); + const isPath = useIsPath(); return useQuery({ - enabled: pathname.startsWith("/qwilight/note"), + enabled: isPath("/note"), queryKey: ["note", fit, src, want, page, viewUnit], queryFn: async () => { const { data } = await wwwAXIOS.get("/note", { diff --git a/qwilight-fe/src/note/usePostToil.ts b/qwilight-fe/src/note/usePostToil.ts index a8135ab..ff6c31b 100644 --- a/qwilight-fe/src/note/usePostToil.ts +++ b/qwilight-fe/src/note/usePostToil.ts @@ -1,6 +1,6 @@ import { useMutation } from "@tanstack/react-query"; -import { wwwAXIOS } from "src/Www"; +import { wwwAXIOS } from "@/Www"; export default function usePostToil() { return useMutation({ diff --git a/qwilight-fe/src/qwilight/QwilightView.module.scss b/qwilight-fe/src/qwilight/QwilightView.module.scss deleted file mode 100644 index a6dad95..0000000 --- a/qwilight-fe/src/qwilight/QwilightView.module.scss +++ /dev/null @@ -1,9 +0,0 @@ -img { - &.platform { - height: 0.75rem; - } - - &.qwilight { - height: 3rem; - } -} diff --git a/qwilight-fe/src/qwilight/QwilightView.tsx b/qwilight-fe/src/qwilight/QwilightView.tsx deleted file mode 100644 index 4ffcf10..0000000 --- a/qwilight-fe/src/qwilight/QwilightView.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { lazy, Suspense, useRef } from "react"; -import { Link, Navigate, Route, Routes, useLocation } from "react-router-dom"; -import { Button, Col, Container, Navbar, NavbarBrand, Row } from "reactstrap"; -import { useTranslation } from "react-i18next"; -import { ToastContainer } from "react-toastify"; - -import SignInWindow from "src/site/SignInWindow"; -import useSiteComponent from "src/site/useSiteComponent"; -import { - AvatarViewLoading, - EtcViewLoading, - HOFViewLoading, - NoteViewLoading, - SiteViewLoading, -} from "src/Loading"; - -import platform from "src/assets/discord-logo-white.png"; - -import scss from "src/qwilight/QwilightView.module.scss"; - -const NoteView = lazy(() => import("src/note/NoteView")); -const SiteView = lazy(() => import("src/site/SiteView")); -const AvatarView = lazy(() => import("src/avatar/AvatarView")); -const HOFView = lazy(() => import("src/hof/HOFView")); -const EtcView = lazy(() => import("src/etc/EtcView")); - -export default function QwilightView() { - const { t } = useTranslation(); - const titleComponent = useRef(null); - const siteYellsView = useRef(null); - - useSiteComponent(siteYellsView); - - const { pathname } = useLocation(); - - const getColor = (route: string) => - pathname.startsWith(route) ? "primary" : "secondary"; - - const onPlatform = () => { - window.open("https://taehui.ddns.net/qwilight/platform"); - }; - - const getTo = (pathname: string) => ({ - ...window.location, - pathname, - search: "", - }); - - return ( - <> -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - }> - - - } - /> - } - /> - - - - - - - ); -} diff --git a/qwilight-fe/src/react-app-env.d.ts b/qwilight-fe/src/react-app-env.d.ts deleted file mode 100644 index 6431bc5..0000000 --- a/qwilight-fe/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/qwilight-fe/src/setupProxy.js b/qwilight-fe/src/setupProxy.js deleted file mode 100644 index 7b45e08..0000000 --- a/qwilight-fe/src/setupProxy.js +++ /dev/null @@ -1,18 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); - -module.exports = function (app) { - app - .use( - createProxyMiddleware("/qwilight/www", { - target: process.env.API ?? "https://taehui.ddns.net", - changeOrigin: true, - }), - ) - .use( - createProxyMiddleware("/qwilight/ws", { - target: process.env.WS_API ?? "wss://taehui.ddns.net", - changeOrigin: true, - ws: true, - }), - ); -}; diff --git a/qwilight-fe/src/site/AvatarItem.module.scss b/qwilight-fe/src/site/AvatarItem.module.scss index 1d51adf..3a2522b 100644 --- a/qwilight-fe/src/site/AvatarItem.module.scss +++ b/qwilight-fe/src/site/AvatarItem.module.scss @@ -1,9 +1,3 @@ -img { - &.avatarConfigure { - height: 1.5rem; - } -} - span { &.audioInput { color: green; diff --git a/qwilight-fe/src/site/AvatarItem.tsx b/qwilight-fe/src/site/AvatarItem.tsx index 91d4bf7..e4362d2 100644 --- a/qwilight-fe/src/site/AvatarItem.tsx +++ b/qwilight-fe/src/site/AvatarItem.tsx @@ -1,14 +1,15 @@ -import ac1 from "src/assets/ac1.png"; -import ac2 from "src/assets/ac2.png"; -import ac3 from "src/assets/ac3.png"; -import ac4 from "src/assets/ac4.png"; -import valve from "src/assets/valve.png"; -import { OnAvatarInput } from "src/site/Site"; -import AvatarDrawing from "src/AvatarDrawing"; +import ac1 from "@/assets/ac1.png"; +import ac2 from "@/assets/ac2.png"; +import ac3 from "@/assets/ac3.png"; +import ac4 from "@/assets/ac4.png"; +import valve from "@/assets/valve.png"; +import { OnAvatarInput } from "@/site/Site"; +import AvatarDrawing from "@/AvatarDrawing"; import { Col, Row } from "reactstrap"; -import AvatarTitle from "src/AvatarTitle"; +import AvatarTitle from "@/AvatarTitle"; -import scss from "src/site/AvatarItem.module.scss"; +import scss from "@/site/AvatarItem.module.scss"; +import Image from "next/image"; const acs = ["", ac1, ac2, ac3, ac4]; @@ -51,13 +52,13 @@ {isValve && ( <> {" "} - + )} {acs[avatarConfigure] && ( <> {" "} - {" "} - + )} diff --git a/qwilight-fe/src/site/AvatarItems.tsx b/qwilight-fe/src/site/AvatarItems.tsx index c4f9d50..3b68e7d 100644 --- a/qwilight-fe/src/site/AvatarItems.tsx +++ b/qwilight-fe/src/site/AvatarItems.tsx @@ -1,8 +1,8 @@ import { observer } from "mobx-react-lite"; -import { useSiteStore } from "src/Stores"; -import AvatarItem from "src/site/AvatarItem"; -import { OnAvatarInput } from "src/site/Site"; +import { useSiteStore } from "@/Stores"; +import AvatarItem from "@/site/AvatarItem"; +import { OnAvatarInput } from "@/site/Site"; export default observer( ({ onAvatarInput }: { onAvatarInput: OnAvatarInput }) => { diff --git a/qwilight-fe/src/site/ConfigureWindow.tsx b/qwilight-fe/src/site/ConfigureWindow.tsx index b9ca46c..0daf918 100644 --- a/qwilight-fe/src/site/ConfigureWindow.tsx +++ b/qwilight-fe/src/site/ConfigureWindow.tsx @@ -1,8 +1,8 @@ import { Button, Col, Modal, Row } from "reactstrap"; import { observer } from "mobx-react-lite"; -import { useTranslation } from "react-i18next"; -import { useSiteStore } from "src/Stores"; +import { useSiteStore } from "@/Stores"; +import { useTranslations } from "next-intl"; export default observer(() => { const { @@ -17,7 +17,7 @@ autoEnterPlatform, setAutoEnterPlatform, } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); return ( { const { isNewSiteWindowOpened, setSiteWindowOpened, setNewSiteWindowOpened } = useSiteStore(); const [siteName, setSiteName] = useState(""); const [siteCipher, setSiteCipher] = useState(""); - const { t } = useTranslation(); + const t = useTranslations(); const onNewSite = () => { SiteComponent.send({ diff --git a/qwilight-fe/src/site/SignInWindow.tsx b/qwilight-fe/src/site/SignInWindow.tsx index 7ccdc2e..c679eb5 100644 --- a/qwilight-fe/src/site/SignInWindow.tsx +++ b/qwilight-fe/src/site/SignInWindow.tsx @@ -2,15 +2,15 @@ import { Button, Col, Input, Modal, Row } from "reactstrap"; import CryptoJS from "crypto-js"; import { observer } from "mobx-react-lite"; -import { useTranslation } from "react-i18next"; -import { useSiteStore } from "src/Stores"; -import SiteComponent from "src/site/SiteComponent"; +import { useSiteStore } from "@/Stores"; +import SiteComponent from "@/site/SiteComponent"; +import { useTranslations } from "next-intl"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); export default observer(() => { const { isSignInOpened, setSignInOpened } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); const [avatarID, setAvatarID] = useState(""); const [avatarCipher, setAvatarCipher] = useState(""); diff --git a/qwilight-fe/src/site/SiteCipherWindow.tsx b/qwilight-fe/src/site/SiteCipherWindow.tsx index 664bc8f..12cf611 100644 --- a/qwilight-fe/src/site/SiteCipherWindow.tsx +++ b/qwilight-fe/src/site/SiteCipherWindow.tsx @@ -1,12 +1,12 @@ import { useState } from "react"; import { observer } from "mobx-react-lite"; import { Button, Col, Input, Modal, Row } from "reactstrap"; -import { useTranslation } from "react-i18next"; -import { useSiteStore } from "src/Stores"; -import SiteComponent from "src/site/SiteComponent"; +import { useSiteStore } from "@/Stores"; +import SiteComponent from "@/site/SiteComponent"; +import { useTranslations } from "next-intl"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); export default observer( ({ siteID, siteName }: { siteID: string; siteName: string }) => { @@ -16,7 +16,7 @@ setSiteCipherWindowOpened, } = useSiteStore(); const [siteCipher, setSiteCipher] = useState(""); - const { t } = useTranslation(); + const t = useTranslations(); const onEnterSite = () => { SiteComponent.send({ diff --git a/qwilight-fe/src/site/SiteComponent.ts b/qwilight-fe/src/site/SiteComponent.ts index af400e6..e76729f 100644 --- a/qwilight-fe/src/site/SiteComponent.ts +++ b/qwilight-fe/src/site/SiteComponent.ts @@ -1,9 +1,9 @@ import { getLanguage } from "taehui-ts/language"; import { getMillis } from "taehui-ts/date"; -import { CloseEventHandler, Event, EventHandler } from "src/site/Site"; +import { CloseEventHandler, Event, EventHandler } from "@/site/Site"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); const siteComponent = new (class { ws?: WebSocket; @@ -48,9 +48,7 @@ connect() { this.ws = new WebSocket( - `${window.location.protocol.replace("http", "ws")}//${ - window.location.host - }/qwilight/ws`, + `${process.env.WS_API ?? "wss://taehui.ddns.net"}/qwilight/ws`, ); this.ws.binaryType = "arraybuffer"; this.ws.addEventListener("open", this.onLoaded); diff --git a/qwilight-fe/src/site/SiteInput.tsx b/qwilight-fe/src/site/SiteInput.tsx index ab2108f..a55bcfa 100644 --- a/qwilight-fe/src/site/SiteInput.tsx +++ b/qwilight-fe/src/site/SiteInput.tsx @@ -1,11 +1,11 @@ import { observer } from "mobx-react-lite"; -import { useTranslation } from "react-i18next"; import { Button, Col, Input, Row } from "reactstrap"; -import { useSiteStore } from "src/Stores"; -import SiteComponent from "src/site/SiteComponent"; +import { useSiteStore } from "@/Stores"; +import SiteComponent from "@/site/SiteComponent"; +import { useTranslations } from "next-intl"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); export default observer(() => { const { @@ -18,7 +18,7 @@ setConfigureOpened, setSignInOpened, } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); const postFile = (file: File) => { const fr = new FileReader(); diff --git a/qwilight-fe/src/site/SiteView.module.scss b/qwilight-fe/src/site/SiteView.module.scss deleted file mode 100644 index 5bbb208..0000000 --- a/qwilight-fe/src/site/SiteView.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -div { - &.siteView { - overflow: auto; - } -} diff --git a/qwilight-fe/src/site/SiteView.tsx b/qwilight-fe/src/site/SiteView.tsx deleted file mode 100644 index 498948b..0000000 --- a/qwilight-fe/src/site/SiteView.tsx +++ /dev/null @@ -1,381 +0,0 @@ -import { - MutableRefObject, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { observer } from "mobx-react-lite"; -import { Item, ItemParams, Menu, useContextMenu } from "react-contexify"; -import { useTranslation } from "react-i18next"; -import { - Alert, - Button, - Col, - Offcanvas, - OffcanvasBody, - OffcanvasHeader, - Row, -} from "reactstrap"; -import { isFirefox } from "react-device-detect"; -import Swal from "sweetalert2"; -import { toast } from "react-toastify"; -import { sprintf } from "sprintf-js"; -import { useTo } from "taehui-ts/fe-utility"; -import { useQueryClient } from "@tanstack/react-query"; - -import { useSiteStore } from "src/Stores"; -import SiteComponent from "src/site/SiteComponent"; -import ConfigureWindow from "src/site/ConfigureWindow"; -import SiteWindow from "src/site/SiteWindow"; -import SiteYellItems from "src/site/SiteYellItems"; -import AvatarItems from "src/site/AvatarItems"; -import SiteInput from "src/site/SiteInput"; -import SiteYellItem from "src/site/SiteYellItem"; -import { getDefaultAvatarID } from "src/Utility"; -import { SiteViewLoading } from "src/Loading"; -import { OnSiteYellInput } from "src/site/Site"; - -import scss from "src/site/SiteView.module.scss"; - -const EventPB = require("src/Event_pb"); - -export default observer<{ - titleComponent: MutableRefObject; - siteYellsView: MutableRefObject; -}>(({ titleComponent, siteYellsView }) => { - const { - avatars, - siteNotify, - isAvatarsOpened, - isPendingSiteYellOpened, - lastPendingSiteYell, - targetSiteID, - siteViews, - siteAvatarID, - siteYells, - setSiteYellsViewLowest, - getSiteView, - onSiteIDModified, - siteYellsViewMove, - setPendingSiteYellOpened, - setAvatarsOpened, - isLoading, - setSiteWindowOpened, - } = useSiteStore(); - const { t } = useTranslation(); - const to = useTo(); - const { show: viewSiteNameInput } = useContextMenu({ - id: "siteName", - }); - const { show: viewAvatarInput } = useContextMenu({ - id: "avatar", - }); - const { show: viewSiteYellInput } = useContextMenu({ - id: "siteYell", - }); - - useEffect(() => { - if (window.location.pathname === "/qwilight/site") { - siteYellsViewMove(siteYellsView); - } - }, [siteYellsView, siteYellsViewMove]); - - const [siteYellsViewHeight, setSiteYellsViewHeight] = useState(""); - const siteViewsView = useRef(null); - const inputComponent = useRef(null); - - const onViewAvatar = ({ props: { avatarID } }: ItemParams) => { - if (avatarID.startsWith("*")) { - toast.warning(t("notAvatarViewFault")); - } else { - to( - `/qwilight/avatar/${encodeURIComponent("#")}${getDefaultAvatarID( - avatarID, - )}`, - ); - } - }; - - useEffect(() => { - window.Notification?.requestPermission(); - }, []); - - const onViewsModified = useCallback(() => { - setSiteYellsViewHeight( - `${ - document.documentElement.clientHeight - - (titleComponent.current?.clientHeight ?? 0) - - (siteViewsView.current?.clientHeight ?? 0) - - (inputComponent.current?.clientHeight ?? 0) - - (isFirefox ? 1 : 0) - }px`, - ); - }, [titleComponent]); - - useEffect(() => { - onViewsModified(); - }, [onViewsModified, isLoading, avatars, lastPendingSiteYell]); - - useEffect(() => { - const onModified = () => { - onViewsModified(); - siteYellsViewMove(siteYellsView); - }; - - window.addEventListener("resize", onModified); - - return () => { - window.removeEventListener("resize", onModified); - }; - }, [onViewsModified, siteYellsView, siteYellsViewMove]); - - const onSiteYellsViewMove = useCallback(() => { - const { current } = siteYellsView; - if (current) { - const siteYellID = siteYells[0]?.siteYellID; - if (siteYellID && siteYellID > 0 && !current.scrollTop) { - SiteComponent.send({ - eventID: EventPB.Event.EventID.GET_SITE_YELLS, - text: JSON.stringify({ - siteID: targetSiteID, - siteYellID: siteYellID, - }), - }); - } - - const isSiteYellsViewLowest = - current.scrollTop + current.clientHeight >= current.scrollHeight; - setSiteYellsViewLowest(isSiteYellsViewLowest); - if (isSiteYellsViewLowest) { - setPendingSiteYellOpened(false); - } - } - }, [ - setPendingSiteYellOpened, - setSiteYellsViewLowest, - siteYells, - siteYellsView, - targetSiteID, - ]); - - useEffect(() => { - const { current } = siteYellsView; - - if (current) { - current.addEventListener("scroll", onSiteYellsViewMove); - - return () => { - current.removeEventListener("scroll", onSiteYellsViewMove); - }; - } - }, [onSiteYellsViewMove, isLoading, siteYellsView]); - - const isSiteHand = useMemo( - () => getSiteView(targetSiteID)?.siteHand === siteAvatarID, - [getSiteView, siteAvatarID, targetSiteID], - ); - - const queryClient = useQueryClient(); - - if (isLoading) { - return ; - } - - const onSiteYellInput: OnSiteYellInput = (event, avatarID) => { - viewSiteYellInput({ event, props: { avatarID } }); - }; - - return ( - <> -
- - {siteViews.map(({ siteID, siteName, isNew }) => { - return ( - - - - ); - })} - - - - {targetSiteID && ( - - - - )} - -
- - - - - {siteNotify} - - - - - - - { - siteYellsViewMove(siteYellsView); - }} - > - {lastPendingSiteYell && ( - - )} - - - - -
- -
- - setAvatarsOpened(false)} - > - setAvatarsOpened(false)}> - {sprintf(t("avatarCountText"), avatars.length)} - - - { - viewAvatarInput({ event, props: { avatarID } }); - }} - /> - - - - { - SiteComponent.send({ - eventID: EventPB.Event.EventID.SET_SITE_OWNER, - text: JSON.stringify({ - siteID: targetSiteID, - avatarID, - }), - }); - }} - > - {t("setSiteHand")} - - - {t("viewAvatarView")} - - { - SiteComponent.send({ - eventID: EventPB.Event.EventID.NEW_SILENT_SITE, - text: avatarID, - }); - }} - > - {t("silentSiteNew")} - - { - SiteComponent.send({ - eventID: EventPB.Event.EventID.EXILE_AVATAR, - text: JSON.stringify({ - siteID: targetSiteID, - avatarID, - }), - }); - }} - > - {t("exileAvatar")} - - - - - - - {t("viewAvatarView")} - - - - - { - const { isConfirmed, value } = await Swal.fire({ - title: t("setSiteNameText"), - input: "text", - }); - if (isConfirmed) { - SiteComponent.send({ - eventID: EventPB.Event.EventID.SET_SITE_NAME, - text: JSON.stringify({ - siteID: targetSiteID, - siteName: value, - }), - }); - } - }} - > - {t("setSiteName")} - - - -
- -
- - - - - ); -}); diff --git a/qwilight-fe/src/site/SiteWindow.module.scss b/qwilight-fe/src/site/SiteWindow.module.scss deleted file mode 100644 index 5aad382..0000000 --- a/qwilight-fe/src/site/SiteWindow.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -img { - &.sc { - height: 1.5rem; - } -} diff --git a/qwilight-fe/src/site/SiteWindow.tsx b/qwilight-fe/src/site/SiteWindow.tsx index 4179e80..22b184c 100644 --- a/qwilight-fe/src/site/SiteWindow.tsx +++ b/qwilight-fe/src/site/SiteWindow.tsx @@ -1,22 +1,22 @@ import { useState } from "react"; import { observer } from "mobx-react-lite"; -import { useTranslation } from "react-i18next"; import { Button, Col, Modal, Row } from "reactstrap"; import { sprintf } from "sprintf-js"; -import { useSiteStore } from "src/Stores"; -import NewSiteWindow from "src/site/NewSiteWindow"; -import SiteComponent from "src/site/SiteComponent"; -import SiteCipherWindow from "src/site/SiteCipherWindow"; +import { useSiteStore } from "@/Stores"; +import NewSiteWindow from "@/site/NewSiteWindow"; +import SiteComponent from "@/site/SiteComponent"; +import SiteCipherWindow from "@/site/SiteCipherWindow"; -import sc0 from "src/assets/sc0.png"; -import sc2 from "src/assets/sc2.png"; -import sc from "src/assets/sc.png"; +import sc0 from "@/assets/sc0.png"; +import sc2 from "@/assets/sc2.png"; +import sc from "@/assets/sc.png"; -import scss from "src/site/SiteWindow.module.scss"; -import useGetSites from "src/site/useGetSites"; +import useGetSites from "@/site/useGetSites"; +import { useTranslations } from "next-intl"; +import Image from "next/image"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); const scs = [sc0, "", sc2]; @@ -29,7 +29,7 @@ targetSiteID, setNewSiteWindowOpened, } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); const [siteID, setSiteID] = useState(""); const [siteName, setSiteName] = useState(""); @@ -52,7 +52,7 @@ > {scs[siteConfigure] && ( - + )}{" "} {" "} - + )} diff --git a/qwilight-fe/src/site/SiteYellItem.tsx b/qwilight-fe/src/site/SiteYellItem.tsx index 0694dc3..ff7b980 100644 --- a/qwilight-fe/src/site/SiteYellItem.tsx +++ b/qwilight-fe/src/site/SiteYellItem.tsx @@ -1,10 +1,9 @@ import { observer } from "mobx-react-lite"; import { Col, Row } from "reactstrap"; -import { useTranslation } from "react-i18next"; import { sprintf } from "sprintf-js"; import { sanitize } from "dompurify"; -import { useSiteStore } from "src/Stores"; +import { useSiteStore } from "@/Stores"; import { AbilitySiteYell, CommentSiteYell, @@ -13,22 +12,24 @@ OnSiteYellInput, SiteYell, TVSiteYell, -} from "src/site/Site"; +} from "@/site/Site"; import { formatText, getAbilityUpText, getGenreText, getHitPointsClass, -} from "src/Utility"; -import AvatarDrawing from "src/AvatarDrawing"; -import AvatarTitle from "src/AvatarTitle"; +} from "@/Utility"; +import AvatarDrawing from "@/AvatarDrawing"; +import AvatarTitle from "@/AvatarTitle"; -import { ReactComponent } from "src/assets/tv0.svg"; -import tv1 from "src/assets/tv1.png"; -import scss from "src/site/SiteYellItem.module.scss"; -import SiteComponent from "src/site/SiteComponent"; +import TV0 from "@/assets/tv0.svg"; +import tv1 from "@/assets/tv1.png"; +import scss from "@/site/SiteYellItem.module.scss"; +import SiteComponent from "@/site/SiteComponent"; +import { useTranslations } from "next-intl"; +import Image from "next/image"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); export default observer( ({ @@ -40,7 +41,7 @@ }) => { const { siteYellVariety, date, avatarID, avatarName, siteYell } = data; const { saveTraffic } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); const doSiteYell = (siteYell: string) => { siteYell = siteYell.replace(" ", " "); @@ -183,7 +184,7 @@ return ( - {t("siteYellTaehui")}{" "} + {t("siteYellTaehu")}{" "} {date}
{href.startsWith("https://www.twitch.tv") && ( - + )} {href.startsWith("https://chzzk.naver.com") && ( - + )} diff --git a/qwilight-fe/src/site/SiteYellItems.tsx b/qwilight-fe/src/site/SiteYellItems.tsx index 00e5404..5ac7470 100644 --- a/qwilight-fe/src/site/SiteYellItems.tsx +++ b/qwilight-fe/src/site/SiteYellItems.tsx @@ -1,8 +1,8 @@ import { observer } from "mobx-react-lite"; -import SiteYellItem from "src/site/SiteYellItem"; -import { useSiteStore } from "src/Stores"; -import { OnSiteYellInput } from "src/site/Site"; +import SiteYellItem from "@/site/SiteYellItem"; +import { useSiteStore } from "@/Stores"; +import { OnSiteYellInput } from "@/site/Site"; export default observer( ({ onSiteYellInput }: { onSiteYellInput: OnSiteYellInput }) => { diff --git a/qwilight-fe/src/site/setSiteStore.ts b/qwilight-fe/src/site/setSiteStore.ts index 0af1d5e..979c611 100644 --- a/qwilight-fe/src/site/setSiteStore.ts +++ b/qwilight-fe/src/site/setSiteStore.ts @@ -1,22 +1,22 @@ -import { MutableRefObject } from "react"; +import { RefObject } from "react"; import { toast } from "react-toastify"; import { runInAction } from "mobx"; import { sprintf } from "sprintf-js"; import CryptoJS from "crypto-js"; -import { TFunction } from "i18next"; -import SiteComponent from "src/site/SiteComponent"; -import { AbilitySiteYell, Avatar, SiteView, SiteYell } from "src/site/Site"; +import SiteComponent from "@/site/SiteComponent"; +import { AbilitySiteYell, Avatar, SiteView, SiteYell } from "@/site/Site"; import { formatText, getAbilityUpText, getDefaultAvatarID, getGenreText, getSiteName, -} from "src/Utility"; -import { wwwAPI } from "src/Www"; +} from "@/Utility"; +import { wwwAPI } from "@/Www"; +import { useTranslations } from "next-intl"; -const EventPB = require("src/Event_pb"); +const EventPB = require("@/Event_pb"); const getSiteYellItem = ({ avatarID, @@ -113,6 +113,8 @@ export default function setSiteStore() { return { + titleComponent: undefined as RefObject | undefined, + siteYellsView: undefined as RefObject | undefined, avatars: [] as Avatar[], siteYells: [] as SiteYell[], isSignInOpened: false, @@ -122,11 +124,17 @@ isConfigureOpened: false, targetSiteID: "", siteNotify: "", - saveTraffic: window.localStorage.getItem("saveTraffic") === "true", - autoEnterNotify: window.localStorage.getItem("autoEnterNotify") !== "false", + saveTraffic: + typeof window === "object" && + window.localStorage.getItem("saveTraffic") === "true", + autoEnterNotify: + typeof window === "object" && + window.localStorage.getItem("autoEnterNotify") !== "false", autoEnterDefault: + typeof window === "object" && window.localStorage.getItem("autoEnterDefault") !== "false", autoEnterPlatform: + typeof window === "object" && window.localStorage.getItem("autoEnterPlatform") !== "false", isEditable: true, input: "", @@ -141,10 +149,15 @@ isPendingSiteYellOpened: false, isAvatarsOpened: false, - setEventHandler( - siteYellsView: MutableRefObject, - t: TFunction, + setComponents( + titleComponent: RefObject, + siteYellsView: RefObject, ) { + this.titleComponent = titleComponent; + this.siteYellsView = siteYellsView; + }, + + setEventHandler(t: ReturnType>) { const autoEnter = () => { SiteComponent.send({ eventID: EventPB.Event.EventID.ENTER_SITE, @@ -286,7 +299,7 @@ avatarID === this.siteAvatarID || this.isSiteYellsViewLowest ) { - this.siteYellsViewMove(siteYellsView); + this.siteYellsViewMove(); } else { runInAction(() => { this.lastPendingSiteYell = siteYellItem; @@ -392,28 +405,30 @@ break; case EventPB.Event.EventID.GET_SITE_YELLS: if (text) { - const { current } = siteYellsView; - if (current) { - const lastPosition1BeforeCalled = - current.scrollHeight - current.clientHeight; - const { siteID, data } = JSON.parse(text); + if (this.siteYellsView) { + const { current } = this.siteYellsView; + if (current) { + const lastPosition1BeforeCalled = + current.scrollHeight - current.clientHeight; + const { siteID, data } = JSON.parse(text); - data - .reverse() - .map(getSiteYellItem) - .forEach((siteYellItem: SiteYell) => { - this.putSiteYell(siteID, siteYellItem, true); - if (this.targetSiteID === siteID) { - this.putTargetSiteYell(siteYellItem, true); - } - }); + data + .reverse() + .map(getSiteYellItem) + .forEach((siteYellItem: SiteYell) => { + this.putSiteYell(siteID, siteYellItem, true); + if (this.targetSiteID === siteID) { + this.putTargetSiteYell(siteYellItem, true); + } + }); - setTimeout(() => { - current.scrollTop = - current.scrollHeight - - current.clientHeight - - lastPosition1BeforeCalled; - }, 0); + setTimeout(() => { + current.scrollTop = + current.scrollHeight - + current.clientHeight - + lastPosition1BeforeCalled; + }, 0); + } } } break; @@ -474,7 +489,7 @@ avatars: [], siteYells: data.map(getSiteYellItem), }); - this.onSiteIDModified(siteID, siteYellsView); + this.onSiteIDModified(siteID); } break; case EventPB.Event.EventID.QUIT_SITE: @@ -482,7 +497,6 @@ this.quitSiteView(text); this.onSiteIDModified( this.siteViews[this.siteViews.length - 1]?.siteID, - siteYellsView, ); } break; @@ -504,13 +518,11 @@ }); }, - setEventCloseHandler( - siteYellsView: MutableRefObject, - ) { + setEventCloseHandler() { SiteComponent.setEventCloseHandler(() => { this.setSiteAvatar("", ""); this.setSignedIn(false); - this.onSiteIDModified("", siteYellsView); + this.onSiteIDModified(""); this.wipeSiteViews(); this.setLoading(true); }); @@ -656,10 +668,7 @@ return this.siteViews.find(({ siteID }) => siteID === targetSiteID); }, - onSiteIDModified( - siteID: string, - siteYellsView: MutableRefObject, - ) { + onSiteIDModified(siteID: string) { this.targetSiteID = siteID; const siteView = this.getSiteView(siteID); if (siteView) { @@ -673,7 +682,7 @@ this.siteNotify = siteView.siteNotify; this.avatars = [...siteView.avatars]; this.siteYells = [...siteView.siteYells]; - this.siteYellsViewMove(siteYellsView); + this.siteYellsViewMove(); } else { this.isEditable = false; this.siteNotify = ""; @@ -686,11 +695,13 @@ return (this.isVisible = document.visibilityState === "visible"); }, - siteYellsViewMove(siteYellsView: MutableRefObject) { + siteYellsViewMove() { setTimeout(() => { - const { current } = siteYellsView; - if (current) { - current.scrollTop = current.scrollHeight; + if (this.siteYellsView) { + const { current } = this.siteYellsView; + if (current) { + current.scrollTop = current.scrollHeight; + } } }, 0); }, diff --git a/qwilight-fe/src/site/useGetSites.ts b/qwilight-fe/src/site/useGetSites.ts index cc280bc..ca504c1 100644 --- a/qwilight-fe/src/site/useGetSites.ts +++ b/qwilight-fe/src/site/useGetSites.ts @@ -1,21 +1,21 @@ import { useQuery } from "@tanstack/react-query"; -import { useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { wwwAXIOS } from "src/Www"; -import { GetSitesAPI } from "src/wwwAPI"; -import { useSiteStore } from "src/Stores"; -import { getSiteName } from "src/Utility"; +import { wwwAXIOS } from "@/Www"; +import { GetSitesAPI } from "@/wwwAPI"; +import { useSiteStore } from "@/Stores"; +import { getSiteName } from "@/Utility"; +import { useTranslations } from "next-intl"; +import { useIsPath } from "taehui-ts/fe-utility"; export default function useGetSites() { const { isSiteWindowOpened } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); - const { pathname } = useLocation(); + const isPath = useIsPath(); return useQuery({ - enabled: isSiteWindowOpened && pathname.startsWith("/qwilight/site"), + enabled: isSiteWindowOpened && isPath("/site"), queryKey: ["sites"], queryFn: async () => { const { data } = await wwwAXIOS.get("/sites"); diff --git a/qwilight-fe/src/site/useSiteComponent.tsx b/qwilight-fe/src/site/useSiteComponent.tsx index 8c42f89..5c46f34 100644 --- a/qwilight-fe/src/site/useSiteComponent.tsx +++ b/qwilight-fe/src/site/useSiteComponent.tsx @@ -1,11 +1,9 @@ import { MutableRefObject, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { useSiteStore } from "src/Stores"; -import SiteComponent from "src/site/SiteComponent"; +import { useSiteStore } from "@/Stores"; +import SiteComponent from "@/site/SiteComponent"; +import { useTranslations } from "next-intl"; -export default function useSiteComponent( - siteYellsView: MutableRefObject, -) { +export default function useSiteComponent() { const { targetSiteID, getSiteView, @@ -13,7 +11,7 @@ setEventHandler, setEventCloseHandler, } = useSiteStore(); - const { t } = useTranslation(); + const t = useTranslations(); useEffect(() => { const onVisibilityModified = () => { @@ -34,9 +32,9 @@ useEffect(() => { setVisible(); - setEventHandler(siteYellsView, t); - setEventCloseHandler(siteYellsView); - }, [setEventCloseHandler, setEventHandler, setVisible, siteYellsView, t]); + setEventHandler(t); + setEventCloseHandler(); + }, [setEventCloseHandler, setEventHandler, setVisible, t]); useEffect(() => { SiteComponent.connect(); diff --git a/qwilight-fe/src/useGetTitle.ts b/qwilight-fe/src/useGetTitle.ts index dab4891..905bd35 100644 --- a/qwilight-fe/src/useGetTitle.ts +++ b/qwilight-fe/src/useGetTitle.ts @@ -1,8 +1,8 @@ import { useQuery } from "@tanstack/react-query"; import { getLanguage } from "taehui-ts/language"; -import { wwwAXIOS } from "src/Www"; -import { GetTitleAPI } from "src/wwwAPI"; +import { wwwAXIOS } from "@/Www"; +import { GetTitleAPI } from "@/wwwAPI"; export default function useGetTitle(avatarID: string) { const language = getLanguage(); diff --git a/qwilight-fe/tsconfig.json b/qwilight-fe/tsconfig.json index a2fa134..002d44f 100644 --- a/qwilight-fe/tsconfig.json +++ b/qwilight-fe/tsconfig.json @@ -4,17 +4,24 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, + "noEmit": true, + "esModuleInterop": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "baseUrl": "." - } + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"], } diff --git a/taehui-ts/.eslintrc.json b/taehui-ts/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/taehui-ts/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/taehui-ts/package.json b/taehui-ts/package.json index 4392a7a..f69e86e 100644 --- a/taehui-ts/package.json +++ b/taehui-ts/package.json @@ -25,30 +25,37 @@ "@types/qs": "^6.9.12", "@types/react": "^18.2.65", "dayjs": "^1.11.10", + "eslint-config-next": "^14.1.3", + "next": "^14.1.3", + "next-intl": "^3.9.5", "qs": "^6.12.0", "react": "^18.2.0", - "react-router-dom": "^6.22.3", "rollup": "^4.13.0", - "tslib": "^2.6.2" + "tslib": "^2.6.2", + "urlcat": "^3.1.0" }, "peerDependencies": { "dayjs": "^1.11.10", + "next": "^14.1.3", + "next-intl": "^3.9.5", "qs": "^6.11.2", - "react": "^18.2.0", - "react-router-dom": "^6.18.0" + "react": "^18.2.0" }, "peerDependenciesMeta": { "dayjs": { "optional": true }, + "next": { + "optional": true + }, + "next-intl": { + "optional": true + }, "qs": { "optional": true }, "react": { "optional": true - }, - "react-router-dom": { - "optional": true } }, "scripts": { diff --git a/taehui-ts/rollup.config.mjs b/taehui-ts/rollup.config.mjs index 5407976..f4756f2 100644 --- a/taehui-ts/rollup.config.mjs +++ b/taehui-ts/rollup.config.mjs @@ -2,7 +2,7 @@ import typescript from "@rollup/plugin-typescript"; export default defineConfig({ - external: ["dayjs", "qs", "react", "react-router-dom"], + external: ["dayjs", "next", "next-intl", "qs", "react"], input: ["src/date.ts", "src/language.ts", "src/fe-utility.ts"], plugins: [ typescript({ diff --git a/taehui-ts/src/fe-utility.ts b/taehui-ts/src/fe-utility.ts index f32d2e9..0bcf9cd 100644 --- a/taehui-ts/src/fe-utility.ts +++ b/taehui-ts/src/fe-utility.ts @@ -1,9 +1,21 @@ +import { + useParams, + usePathname, + useRouter, + useSearchParams, +} from "next/navigation"; import { useCallback, useEffect, useState } from "react"; -import { useNavigate, useParams, useSearchParams } from "react-router-dom"; +import { parse, stringify } from "qs"; +import urlcat from "urlcat"; +import { useLocale } from "next-intl"; export function useWindowArea() { - const [windowLength, setWindowLength] = useState(window.innerWidth); - const [windowHeight, setWindowHeight] = useState(window.innerHeight); + const [windowLength, setWindowLength] = useState( + typeof window === "object" ? window.innerWidth : 0, + ); + const [windowHeight, setWindowHeight] = useState( + typeof window === "object" ? window.innerHeight : 0, + ); useEffect(() => { const onModified = () => { @@ -22,24 +34,28 @@ } export function useTo() { - const navigate = useNavigate(); + const { push } = useRouter(); - return (pathname: string, search: string = window.location.search) => - navigate({ ...window.location, pathname, search }); + return useCallback( + (pathname: string, search = "") => push(urlcat(pathname, parse(search))), + [push], + ); } export function useParam(text: string, defaultValue: string) { - const [searchParams, setSearchParams] = useSearchParams(); + const to = useTo(); + const searchParams = useSearchParams(); const param = searchParams.get(text) ?? defaultValue; + const pathname = usePathname(); + return { param, setParam: useCallback( (param: string) => { - searchParams.set(text, param.toString()); - setSearchParams(searchParams); + to(pathname, stringify({ ...searchParams.entries(), [text]: param })); }, - [searchParams, setSearchParams], + [pathname, searchParams, text, to], ), }; } @@ -60,10 +76,10 @@ export function useWant(route: string) { const to = useTo(); - const { want = "" } = useParams<{ want: string }>(); + const { want = [] } = useParams(); return { - want, + want: Array.isArray(want) ? want[0] : want, setWant: useCallback( (want: string) => { to(route + "/" + want); @@ -72,3 +88,13 @@ ), }; } + +export function useIsPath() { + const pathname = usePathname(); + const locale = useLocale(); + + return useCallback( + (route: string) => pathname.startsWith(`/${locale}${route}`), + [locale, pathname], + ); +} diff --git a/taehui-ts/src/language.ts b/taehui-ts/src/language.ts index d1381b3..2bc117b 100644 --- a/taehui-ts/src/language.ts +++ b/taehui-ts/src/language.ts @@ -1,14 +1,17 @@ import { parse } from "qs"; export const getLanguage = () => { - let { language } = parse(window.location.search, { - ignoreQueryPrefix: true, - }); - language = (language && String(language)) ?? window.navigator.language; - if (language.startsWith("ko")) { - return "ko-KR"; + if (typeof window === "object") { + let { language } = parse(window.location.search, { + ignoreQueryPrefix: true, + }); + language = (language && String(language)) ?? window.navigator.language; + if (language.startsWith("ko")) { + return "ko-KR"; + } else { + return "en-US"; + } } else { return "en-US"; } }; -