diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index b58b603..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a1..0000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/prettier.xml b/.idea/prettier.xml
index 0c83ac4..b0ab31a 100644
--- a/.idea/prettier.xml
+++ b/.idea/prettier.xml
@@ -1,7 +1,6 @@
-
\ No newline at end of file
diff --git a/.idea/taehui.iml b/.idea/taehui.iml
index 96fc861..24643cc 100644
--- a/.idea/taehui.iml
+++ b/.idea/taehui.iml
@@ -5,18 +5,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..f5fbff7
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,503 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "associatedIndex": 4
+}
+
+
+
+
+
+ {
+ "keyToString": {
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "git-widget-placeholder": "develop",
+ "ignore.virus.scanning.warn.message": "true",
+ "javascript.nodejs.core.library.configured.version": "20.12.0",
+ "javascript.nodejs.core.library.typings.version": "20.11.30",
+ "last_opened_file_path": "C:/Users/qpdgo/WebStormProjects/taehui/qwilight-fe/src/assets",
+ "list.type.of.created.stylesheet": "SCSS",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.standard": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.standard": "",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "pnpm",
+ "npm.taehui > dev.executor": "Run",
+ "npm.taehui > start.executor": "Run",
+ "npm.taehui > start:taehui-www.executor": "Run",
+ "prettierjs.PrettierConfiguration.Package": "C:\\Users\\qpdgo\\WebStormProjects\\taehui\\node_modules\\prettier",
+ "run.code.analysis.last.selected.profile": "pProject Default",
+ "settings.editor.selected.configurable": "preferences.keymap",
+ "ts.external.directory.path": "C:\\Users\\qpdgo\\WebStormProjects\\taehui\\node_modules\\typescript\\lib",
+ "vue.rearranger.settings.migration": "true"
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1706600973216
+
+
+ 1706600973216
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1706840402146
+
+
+
+ 1706840402146
+
+
+
+ 1710546694689
+
+
+
+ 1710546694689
+
+
+
+ 1710573385361
+
+
+
+ 1710573385361
+
+
+
+ 1710573970842
+
+
+
+ 1710573970842
+
+
+
+ 1710574375572
+
+
+
+ 1710574375572
+
+
+
+ 1710606496419
+
+
+
+ 1710606496419
+
+
+
+ 1710606501674
+
+
+
+ 1710606501674
+
+
+
+ 1710608850558
+
+
+
+ 1710608850558
+
+
+
+ 1710611609312
+
+
+
+ 1710611609312
+
+
+
+ 1710630550886
+
+
+
+ 1710630550886
+
+
+
+ 1710652355321
+
+
+
+ 1710652355321
+
+
+
+ 1710658261458
+
+
+
+ 1710658261458
+
+
+
+ 1710659860614
+
+
+
+ 1710659860614
+
+
+
+ 1710660494786
+
+
+
+ 1710660494786
+
+
+
+ 1710660808675
+
+
+
+ 1710660808675
+
+
+
+ 1710662734101
+
+
+
+ 1710662734102
+
+
+
+ 1710663225453
+
+
+
+ 1710663225453
+
+
+
+ 1710665113315
+
+
+
+ 1710665113315
+
+
+
+ 1710690712991
+
+
+
+ 1710690712991
+
+
+
+ 1710690719991
+
+
+
+ 1710690719991
+
+
+
+ 1710690736795
+
+
+
+ 1710690736795
+
+
+
+ 1710723249388
+
+
+
+ 1710723249388
+
+
+
+ 1710723268626
+
+
+
+ 1710723268626
+
+
+
+ 1710886988474
+
+
+
+ 1710886988474
+
+
+
+ 1710953171779
+
+
+
+ 1710953171779
+
+
+
+ 1710953909685
+
+
+
+ 1710953909685
+
+
+
+ 1711024900786
+
+
+
+ 1711024900786
+
+
+
+ 1711040624676
+
+
+
+ 1711040624676
+
+
+
+ 1711183081024
+
+
+
+ 1711183081024
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 9520656..0427cab 100644
--- a/package.json
+++ b/package.json
@@ -16,10 +16,10 @@
"deploy": "taehui.cmd"
},
"devDependencies": {
- "eslint": "^8.57.0",
+ "eslint": "^9.0.0",
"prettier": "^3.2.5",
- "sass": "^1.72.0",
- "typescript": "^5.4.2"
+ "sass": "^1.74.1",
+ "typescript": "^5.4.4"
},
"packageManager": "pnpm@8.15.4"
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a28f88a..3131196 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,23 +9,23 @@
.:
devDependencies:
eslint:
- specifier: ^8.57.0
- version: 8.57.0
+ specifier: ^9.0.0
+ version: 9.0.0
prettier:
specifier: ^3.2.5
version: 3.2.5
sass:
- specifier: ^1.72.0
- version: 1.72.0
+ specifier: ^1.74.1
+ version: 1.74.1
typescript:
- specifier: ^5.4.2
- version: 5.4.2
+ specifier: ^5.4.4
+ version: 5.4.4
qwilight-fe:
dependencies:
'@tanstack/react-query':
- specifier: ^5.28.4
- version: 5.28.4(react@18.2.0)
+ specifier: ^5.29.0
+ version: 5.29.0(react@18.2.0)
axios:
specifier: ^1.6.8
version: 1.6.8
@@ -39,29 +39,35 @@
specifier: ^4.2.0
version: 4.2.0
dompurify:
- specifier: ^3.0.9
- version: 3.0.9
+ specifier: ^3.0.11
+ version: 3.0.11
google-protobuf:
specifier: ^3.21.2
version: 3.21.2
isomorphic-dompurify:
- specifier: ^2.4.0
- version: 2.4.0
+ specifier: ^2.6.0
+ version: 2.6.0
mobx:
- specifier: ^6.12.0
- version: 6.12.0
+ specifier: ^6.12.3
+ version: 6.12.3
mobx-react-lite:
- specifier: ^4.0.6
- version: 4.0.6(mobx@6.12.0)(react-dom@18.2.0)(react@18.2.0)
+ specifier: ^4.0.7
+ version: 4.0.7(mobx@6.12.3)(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)
+ specifier: ^14.1.4
+ version: 14.1.4(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1)
next-intl:
- specifier: ^3.9.5
- version: 3.9.5(next@14.1.3)(react@18.2.0)
+ specifier: ^3.11.1
+ version: 3.11.1(next@14.1.4)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
+ react-bootstrap:
+ specifier: ^2.10.2
+ version: 2.10.2(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
+ react-bootstrap-icons:
+ specifier: ^1.11.3
+ version: 1.11.3(react@18.2.0)
react-contexify:
specifier: ^6.0.0
version: 6.0.0(react-dom@18.2.0)(react@18.2.0)
@@ -74,18 +80,18 @@
react-toastify:
specifier: ^10.0.5
version: 10.0.5(react-dom@18.2.0)(react@18.2.0)
- reactstrap:
- specifier: ^9.2.2
- version: 9.2.2(react-dom@18.2.0)(react@18.2.0)
sharp:
- specifier: ^0.33.2
- version: 0.33.2
+ specifier: ^0.33.3
+ version: 0.33.3
sweetalert2:
- specifier: ^11.10.6
- version: 11.10.6
+ specifier: ^11.10.7
+ version: 11.10.7
taehui-ts:
specifier: workspace:^
version: link:../taehui-ts
+ urlcat:
+ specifier: ^3.1.0
+ version: 3.1.0
devDependencies:
'@types/crypto-js':
specifier: ^4.2.2
@@ -97,26 +103,26 @@
specifier: ^29.5.12
version: 29.5.12
'@types/node':
- specifier: ^20.11.28
- version: 20.11.28
+ specifier: ^20.12.5
+ version: 20.12.5
'@types/react':
- specifier: ^18.2.66
- version: 18.2.66
+ specifier: ^18.2.74
+ version: 18.2.74
'@types/react-dom':
- specifier: ^18.2.22
- version: 18.2.22
+ specifier: ^18.2.24
+ version: 18.2.24
eslint-config-next:
- specifier: ^14.1.3
- version: 14.1.3(eslint@8.57.0)(typescript@5.4.2)
+ specifier: ^14.1.4
+ version: 14.1.4(eslint@8.57.0)(typescript@5.4.4)
typescript:
- specifier: ^5.4.2
- version: 5.4.2
+ specifier: ^5.4.4
+ version: 5.4.4
taehui-fe:
dependencies:
'@tanstack/react-query':
- specifier: ^5.28.4
- version: 5.28.4(react@18.2.0)
+ specifier: ^5.29.0
+ version: 5.29.0(react@18.2.0)
axios:
specifier: ^1.6.8
version: 1.6.8
@@ -130,32 +136,38 @@
specifier: ^1.11.10
version: 1.11.10
dompurify:
- specifier: ^3.0.9
- version: 3.0.9
+ specifier: ^3.0.11
+ version: 3.0.11
htmlparser2:
specifier: ^9.1.0
version: 9.1.0
isomorphic-dompurify:
- specifier: ^2.4.0
- version: 2.4.0
+ specifier: ^2.6.0
+ version: 2.6.0
mariadb:
- specifier: ^3.2.3
- version: 3.2.3
+ specifier: ^3.3.0
+ version: 3.3.0
mobx:
- specifier: ^6.12.0
- version: 6.12.0
+ specifier: ^6.12.3
+ version: 6.12.3
mobx-react-lite:
- specifier: ^4.0.6
- version: 4.0.6(mobx@6.12.0)(react-dom@18.2.0)(react@18.2.0)
+ specifier: ^4.0.7
+ version: 4.0.7(mobx@6.12.3)(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)
+ specifier: ^14.1.4
+ version: 14.1.4(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1)
next-intl:
- specifier: ^3.9.5
- version: 3.9.5(next@14.1.3)(react@18.2.0)
+ specifier: ^3.11.1
+ version: 3.11.1(next@14.1.4)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
+ react-bootstrap:
+ specifier: ^2.10.2
+ version: 2.10.2(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
+ react-bootstrap-icons:
+ specifier: ^1.11.3
+ version: 1.11.3(react@18.2.0)
react-contexify:
specifier: ^6.0.0
version: 6.0.0(react-dom@18.2.0)(react@18.2.0)
@@ -167,19 +179,16 @@
version: 6.1.0(react@18.2.0)
react-textarea-autosize:
specifier: ^8.5.3
- version: 8.5.3(@types/react@18.2.66)(react@18.2.0)
+ version: 8.5.3(@types/react@18.2.74)(react@18.2.0)
react-toastify:
specifier: ^10.0.5
version: 10.0.5(react-dom@18.2.0)(react@18.2.0)
- reactstrap:
- specifier: ^9.2.2
- version: 9.2.2(react-dom@18.2.0)(react@18.2.0)
redis:
specifier: ^4.6.13
version: 4.6.13
sweetalert2:
- specifier: ^11.10.6
- version: 11.10.6
+ specifier: ^11.10.7
+ version: 11.10.7
taehui-ts:
specifier: workspace:^
version: link:../taehui-ts
@@ -187,11 +196,11 @@
specifier: ^9.0.1
version: 9.0.1
winston:
- specifier: ^3.12.0
- version: 3.12.0
+ specifier: ^3.13.0
+ version: 3.13.0
winston-daily-rotate-file:
specifier: ^5.0.0
- version: 5.0.0(winston@3.12.0)
+ version: 5.0.0(winston@3.13.0)
devDependencies:
'@types/crypto-js':
specifier: ^4.2.2
@@ -203,14 +212,14 @@
specifier: ^29.5.12
version: 29.5.12
'@types/node':
- specifier: ^20.11.28
- version: 20.11.28
+ specifier: ^20.12.5
+ version: 20.12.5
'@types/react':
- specifier: ^18.2.66
- version: 18.2.66
+ specifier: ^18.2.74
+ version: 18.2.74
'@types/react-dom':
- specifier: ^18.2.22
- version: 18.2.22
+ specifier: ^18.2.24
+ version: 18.2.24
'@types/showdown':
specifier: ^2.0.6
version: 2.0.6
@@ -218,50 +227,44 @@
specifier: ^9.0.8
version: 9.0.8
eslint-config-next:
- specifier: ^14.1.3
- version: 14.1.3(eslint@8.57.0)(typescript@5.4.2)
+ specifier: ^14.1.4
+ version: 14.1.4(eslint@8.57.0)(typescript@5.4.4)
typescript:
- specifier: ^5.4.2
- version: 5.4.2
+ specifier: ^5.4.4
+ version: 5.4.4
taehui-ts:
devDependencies:
'@rollup/plugin-typescript':
specifier: ^11.1.6
- version: 11.1.6(rollup@4.13.0)(tslib@2.6.2)(typescript@5.4.2)
- '@types/qs':
- specifier: ^6.9.12
- version: 6.9.12
+ version: 11.1.6(rollup@4.14.0)(tslib@2.6.2)(typescript@5.4.4)
'@types/react':
- specifier: ^18.2.66
- version: 18.2.66
+ specifier: ^18.2.74
+ version: 18.2.74
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)
+ specifier: ^14.1.4
+ version: 14.1.4(eslint@8.57.0)(typescript@5.4.4)
next:
- specifier: ^14.1.3
- version: 14.1.3(react-dom@18.2.0)(react@18.2.0)(sass@1.72.0)
+ specifier: ^14.1.4
+ version: 14.1.4(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1)
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
+ specifier: ^3.11.1
+ version: 3.11.1(next@14.1.4)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
rollup:
- specifier: ^4.13.0
- version: 4.13.0
+ specifier: ^4.14.0
+ version: 4.14.0
+ rollup-plugin-scss:
+ specifier: ^4.0.0
+ version: 4.0.0
tslib:
specifier: ^2.6.2
version: 2.6.2
- urlcat:
- specifier: ^3.1.0
- version: 3.1.0
packages:
@@ -291,13 +294,6 @@
js-tokens: 4.0.0
dev: true
- /@babel/runtime@7.23.2:
- resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==}
- engines: {node: '>=6.9.0'}
- dependencies:
- regenerator-runtime: 0.14.0
- dev: false
-
/@babel/runtime@7.23.9:
resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==}
engines: {node: '>=6.9.0'}
@@ -322,8 +318,8 @@
kuler: 2.0.0
dev: false
- /@emnapi/runtime@0.45.0:
- resolution: {integrity: sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==}
+ /@emnapi/runtime@1.1.0:
+ resolution: {integrity: sha512-gCGlE0fJGWalfy+wbFApjhKn6uoSVvopru77IPyxNKkjkaiSx2HxDS7eOYSmo9dcMIhmmIvoxiC3N9TM1c3EaA==}
requiresBuild: true
dependencies:
tslib: 2.6.2
@@ -340,6 +336,16 @@
eslint-visitor-keys: 3.4.3
dev: true
+ /@eslint-community/eslint-utils@4.4.0(eslint@9.0.0):
+ resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ dependencies:
+ eslint: 9.0.0
+ eslint-visitor-keys: 3.4.3
+ dev: true
+
/@eslint-community/regexpp@4.6.2:
resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@@ -362,11 +368,33 @@
- supports-color
dev: true
+ /@eslint/eslintrc@3.0.2:
+ resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.4
+ espree: 10.0.1
+ globals: 14.0.0
+ ignore: 5.2.4
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@eslint/js@8.57.0:
resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
+ /@eslint/js@9.0.0:
+ resolution: {integrity: sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dev: true
+
/@formatjs/ecma402-abstract@1.11.4:
resolution: {integrity: sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==}
dependencies:
@@ -423,6 +451,17 @@
- supports-color
dev: true
+ /@humanwhocodes/config-array@0.12.3:
+ resolution: {integrity: sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.3
+ debug: 4.3.4
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
/@humanwhocodes/module-importer@1.0.1:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
@@ -432,30 +471,34 @@
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
dev: true
- /@img/sharp-darwin-arm64@0.33.2:
- resolution: {integrity: sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==}
+ /@humanwhocodes/object-schema@2.0.3:
+ resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+ dev: true
+
+ /@img/sharp-darwin-arm64@0.33.3:
+ resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-darwin-arm64': 1.0.1
+ '@img/sharp-libvips-darwin-arm64': 1.0.2
dev: false
optional: true
- /@img/sharp-darwin-x64@0.33.2:
- resolution: {integrity: sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==}
+ /@img/sharp-darwin-x64@0.33.3:
+ resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [darwin]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-darwin-x64': 1.0.1
+ '@img/sharp-libvips-darwin-x64': 1.0.2
dev: false
optional: true
- /@img/sharp-libvips-darwin-arm64@1.0.1:
- resolution: {integrity: sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==}
+ /@img/sharp-libvips-darwin-arm64@1.0.2:
+ resolution: {integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==}
engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [darwin]
@@ -463,8 +506,8 @@
dev: false
optional: true
- /@img/sharp-libvips-darwin-x64@1.0.1:
- resolution: {integrity: sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==}
+ /@img/sharp-libvips-darwin-x64@1.0.2:
+ resolution: {integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==}
engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [darwin]
@@ -472,8 +515,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linux-arm64@1.0.1:
- resolution: {integrity: sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==}
+ /@img/sharp-libvips-linux-arm64@1.0.2:
+ resolution: {integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==}
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
@@ -481,8 +524,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linux-arm@1.0.1:
- resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==}
+ /@img/sharp-libvips-linux-arm@1.0.2:
+ resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==}
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm]
os: [linux]
@@ -490,8 +533,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linux-s390x@1.0.1:
- resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==}
+ /@img/sharp-libvips-linux-s390x@1.0.2:
+ resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==}
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [s390x]
os: [linux]
@@ -499,8 +542,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linux-x64@1.0.1:
- resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==}
+ /@img/sharp-libvips-linux-x64@1.0.2:
+ resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==}
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
@@ -508,8 +551,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linuxmusl-arm64@1.0.1:
- resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==}
+ /@img/sharp-libvips-linuxmusl-arm64@1.0.2:
+ resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==}
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
@@ -517,8 +560,8 @@
dev: false
optional: true
- /@img/sharp-libvips-linuxmusl-x64@1.0.1:
- resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==}
+ /@img/sharp-libvips-linuxmusl-x64@1.0.2:
+ resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==}
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
@@ -526,84 +569,84 @@
dev: false
optional: true
- /@img/sharp-linux-arm64@0.33.2:
- resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==}
+ /@img/sharp-linux-arm64@0.33.3:
+ resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linux-arm64': 1.0.1
+ '@img/sharp-libvips-linux-arm64': 1.0.2
dev: false
optional: true
- /@img/sharp-linux-arm@0.33.2:
- resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==}
+ /@img/sharp-linux-arm@0.33.3:
+ resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==}
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linux-arm': 1.0.1
+ '@img/sharp-libvips-linux-arm': 1.0.2
dev: false
optional: true
- /@img/sharp-linux-s390x@0.33.2:
- resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==}
+ /@img/sharp-linux-s390x@0.33.3:
+ resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==}
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [s390x]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linux-s390x': 1.0.1
+ '@img/sharp-libvips-linux-s390x': 1.0.2
dev: false
optional: true
- /@img/sharp-linux-x64@0.33.2:
- resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==}
+ /@img/sharp-linux-x64@0.33.3:
+ resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==}
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linux-x64': 1.0.1
+ '@img/sharp-libvips-linux-x64': 1.0.2
dev: false
optional: true
- /@img/sharp-linuxmusl-arm64@0.33.2:
- resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==}
+ /@img/sharp-linuxmusl-arm64@0.33.3:
+ resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [arm64]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.2
dev: false
optional: true
- /@img/sharp-linuxmusl-x64@0.33.2:
- resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==}
+ /@img/sharp-linuxmusl-x64@0.33.3:
+ resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==}
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [linux]
requiresBuild: true
optionalDependencies:
- '@img/sharp-libvips-linuxmusl-x64': 1.0.1
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.2
dev: false
optional: true
- /@img/sharp-wasm32@0.33.2:
- resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==}
+ /@img/sharp-wasm32@0.33.3:
+ resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [wasm32]
requiresBuild: true
dependencies:
- '@emnapi/runtime': 0.45.0
+ '@emnapi/runtime': 1.1.0
dev: false
optional: true
- /@img/sharp-win32-ia32@0.33.2:
- resolution: {integrity: sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==}
+ /@img/sharp-win32-ia32@0.33.3:
+ resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [ia32]
os: [win32]
@@ -611,8 +654,8 @@
dev: false
optional: true
- /@img/sharp-win32-x64@0.33.2:
- resolution: {integrity: sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==}
+ /@img/sharp-win32-x64@0.33.3:
+ resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
cpu: [x64]
os: [win32]
@@ -653,7 +696,7 @@
'@jest/schemas': 29.6.0
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
- '@types/node': 20.11.28
+ '@types/node': 20.12.5
'@types/yargs': 17.0.24
chalk: 4.1.2
dev: true
@@ -662,81 +705,81 @@
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
dev: false
- /@next/env@14.1.3:
- resolution: {integrity: sha512-VhgXTvrgeBRxNPjyfBsDIMvgsKDxjlpw4IAUsHCX8Gjl1vtHUYRT3+xfQ/wwvLPDd/6kqfLqk9Pt4+7gysuCKQ==}
+ /@next/env@14.1.4:
+ resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==}
- /@next/eslint-plugin-next@14.1.3:
- resolution: {integrity: sha512-VCnZI2cy77Yaj3L7Uhs3+44ikMM1VD/fBMwvTBb3hIaTIuqa+DmG4dhUDq+MASu3yx97KhgsVJbsas0XuiKyww==}
+ /@next/eslint-plugin-next@14.1.4:
+ resolution: {integrity: sha512-n4zYNLSyCo0Ln5b7qxqQeQ34OZKXwgbdcx6kmkQbywr+0k6M3Vinft0T72R6CDAcDrne2IAgSud4uWCzFgc5HA==}
dependencies:
glob: 10.3.10
dev: true
- /@next/swc-darwin-arm64@14.1.3:
- resolution: {integrity: sha512-LALu0yIBPRiG9ANrD5ncB3pjpO0Gli9ZLhxdOu6ZUNf3x1r3ea1rd9Q+4xxUkGrUXLqKVK9/lDkpYIJaCJ6AHQ==}
+ /@next/swc-darwin-arm64@14.1.4:
+ resolution: {integrity: sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
optional: true
- /@next/swc-darwin-x64@14.1.3:
- resolution: {integrity: sha512-E/9WQeXxkqw2dfcn5UcjApFgUq73jqNKaE5bysDm58hEUdUGedVrnRhblhJM7HbCZNhtVl0j+6TXsK0PuzXTCg==}
+ /@next/swc-darwin-x64@14.1.4:
+ resolution: {integrity: sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==}
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==}
+ /@next/swc-linux-arm64-gnu@14.1.4:
+ resolution: {integrity: sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==}
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==}
+ /@next/swc-linux-arm64-musl@14.1.4:
+ resolution: {integrity: sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==}
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==}
+ /@next/swc-linux-x64-gnu@14.1.4:
+ resolution: {integrity: sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
optional: true
- /@next/swc-linux-x64-musl@14.1.3:
- resolution: {integrity: sha512-DX2zqz05ziElLoxskgHasaJBREC5Y9TJcbR2LYqu4r7naff25B4iXkfXWfcp69uD75/0URmmoSgT8JclJtrBoQ==}
+ /@next/swc-linux-x64-musl@14.1.4:
+ resolution: {integrity: sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==}
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==}
+ /@next/swc-win32-arm64-msvc@14.1.4:
+ resolution: {integrity: sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==}
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==}
+ /@next/swc-win32-ia32-msvc@14.1.4:
+ resolution: {integrity: sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==}
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==}
+ /@next/swc-win32-x64-msvc@14.1.4:
+ resolution: {integrity: sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -775,6 +818,16 @@
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
dev: false
+ /@react-aria/ssr@3.9.2(react@18.2.0):
+ resolution: {integrity: sha512-0gKkgDYdnq1w+ey8KzG9l+H5Z821qh9vVjztk55rUg71vTk/Eaebeir+WtzcLLwTjw3m/asIjx8Y59y1lJZhBw==}
+ engines: {node: '>= 12'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0
+ dependencies:
+ '@swc/helpers': 0.5.2
+ react: 18.2.0
+ dev: false
+
/@redis/bloom@1.2.0(@redis/client@1.5.14):
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
peerDependencies:
@@ -824,7 +877,35 @@
'@redis/client': 1.5.14
dev: false
- /@rollup/plugin-typescript@11.1.6(rollup@4.13.0)(tslib@2.6.2)(typescript@5.4.2):
+ /@restart/hooks@0.4.16(react@18.2.0):
+ resolution: {integrity: sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==}
+ peerDependencies:
+ react: '>=16.8.0'
+ dependencies:
+ dequal: 2.0.3
+ react: 18.2.0
+ dev: false
+
+ /@restart/ui@1.6.8(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-6ndCv3oZ7r9vuP1Ok9KH55TM1/UkdBnP/fSraW0DFDMbPMzWKhVKeFAIEUCRCSdzayjZDcFYK6xbMlipN9dmMA==}
+ peerDependencies:
+ react: '>=16.14.0'
+ react-dom: '>=16.14.0'
+ dependencies:
+ '@babel/runtime': 7.23.9
+ '@popperjs/core': 2.11.8
+ '@react-aria/ssr': 3.9.2(react@18.2.0)
+ '@restart/hooks': 0.4.16(react@18.2.0)
+ '@types/warning': 3.0.3
+ dequal: 2.0.3
+ dom-helpers: 5.2.1
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ uncontrollable: 8.0.4(react@18.2.0)
+ warning: 4.0.3
+ dev: false
+
+ /@rollup/plugin-typescript@11.1.6(rollup@4.14.0)(tslib@2.6.2)(typescript@5.4.4):
resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@@ -837,14 +918,14 @@
tslib:
optional: true
dependencies:
- '@rollup/pluginutils': 5.1.0(rollup@4.13.0)
+ '@rollup/pluginutils': 5.1.0(rollup@4.14.0)
resolve: 1.22.2
- rollup: 4.13.0
+ rollup: 4.14.0
tslib: 2.6.2
- typescript: 5.4.2
+ typescript: 5.4.4
dev: true
- /@rollup/pluginutils@5.1.0(rollup@4.13.0):
+ /@rollup/pluginutils@5.1.0(rollup@4.14.0):
resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==}
engines: {node: '>=14.0.0'}
peerDependencies:
@@ -856,107 +937,123 @@
'@types/estree': 1.0.1
estree-walker: 2.0.2
picomatch: 2.3.1
- rollup: 4.13.0
+ rollup: 4.14.0
dev: true
- /@rollup/rollup-android-arm-eabi@4.13.0:
- resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==}
+ /@rollup/rollup-android-arm-eabi@4.14.0:
+ resolution: {integrity: sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-android-arm64@4.13.0:
- resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==}
+ /@rollup/rollup-android-arm64@4.14.0:
+ resolution: {integrity: sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-darwin-arm64@4.13.0:
- resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==}
+ /@rollup/rollup-darwin-arm64@4.14.0:
+ resolution: {integrity: sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-darwin-x64@4.13.0:
- resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==}
+ /@rollup/rollup-darwin-x64@4.14.0:
+ resolution: {integrity: sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-arm-gnueabihf@4.13.0:
- resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==}
+ /@rollup/rollup-linux-arm-gnueabihf@4.14.0:
+ resolution: {integrity: sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-arm64-gnu@4.13.0:
- resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==}
+ /@rollup/rollup-linux-arm64-gnu@4.14.0:
+ resolution: {integrity: sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-arm64-musl@4.13.0:
- resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==}
+ /@rollup/rollup-linux-arm64-musl@4.14.0:
+ resolution: {integrity: sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-riscv64-gnu@4.13.0:
- resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==}
+ /@rollup/rollup-linux-powerpc64le-gnu@4.14.0:
+ resolution: {integrity: sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==}
+ cpu: [ppc64le]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-riscv64-gnu@4.14.0:
+ resolution: {integrity: sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-x64-gnu@4.13.0:
- resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==}
+ /@rollup/rollup-linux-s390x-gnu@4.14.0:
+ resolution: {integrity: sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==}
+ cpu: [s390x]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /@rollup/rollup-linux-x64-gnu@4.14.0:
+ resolution: {integrity: sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-linux-x64-musl@4.13.0:
- resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==}
+ /@rollup/rollup-linux-x64-musl@4.14.0:
+ resolution: {integrity: sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-win32-arm64-msvc@4.13.0:
- resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==}
+ /@rollup/rollup-win32-arm64-msvc@4.14.0:
+ resolution: {integrity: sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-win32-ia32-msvc@4.13.0:
- resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==}
+ /@rollup/rollup-win32-ia32-msvc@4.14.0:
+ resolution: {integrity: sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
- /@rollup/rollup-win32-x64-msvc@4.13.0:
- resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==}
+ /@rollup/rollup-win32-x64-msvc@4.14.0:
+ resolution: {integrity: sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==}
cpu: [x64]
os: [win32]
requiresBuild: true
@@ -976,16 +1073,16 @@
dependencies:
tslib: 2.6.2
- /@tanstack/query-core@5.28.4:
- resolution: {integrity: sha512-uQZqOFqLWUvXNIQZ63XdKzg22NtHzgCBUfDmjDHi3BoF+nUYeBNvMi/xFPtFrMhqRzG2Ir4mYaGsWZzmiEjXpA==}
+ /@tanstack/query-core@5.29.0:
+ resolution: {integrity: sha512-WgPTRs58hm9CMzEr5jpISe8HXa3qKQ8CxewdYZeVnA54JrPY9B1CZiwsCoLpLkf0dGRZq+LcX5OiJb0bEsOFww==}
dev: false
- /@tanstack/react-query@5.28.4(react@18.2.0):
- resolution: {integrity: sha512-BErcoB/QQG6YwLSUKnaGxF+lSc270RH2w3kMBpG0i4YzDCsFs2pdxPX1WVknQvFk9bNgukMb158hc2Zb4SdwSA==}
+ /@tanstack/react-query@5.29.0(react@18.2.0):
+ resolution: {integrity: sha512-yxlhHB73jaBla6h5B6zPaGmQjokkzAhMHN4veotkPNiQ3Ac/mCxgABRZPsJJrgCTvhpcncBZcDBFxaR2B37vug==}
peerDependencies:
react: ^18.0.0
dependencies:
- '@tanstack/query-core': 5.28.4
+ '@tanstack/query-core': 5.29.0
react: 18.2.0
dev: false
@@ -1006,8 +1103,8 @@
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
dev: true
- /@types/geojson@7946.0.10:
- resolution: {integrity: sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==}
+ /@types/geojson@7946.0.14:
+ resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==}
dev: false
/@types/istanbul-lib-coverage@2.0.4:
@@ -1037,39 +1134,32 @@
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
- /@types/node@17.0.45:
- resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
- dev: false
-
- /@types/node@20.11.28:
- resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==}
+ /@types/node@20.12.5:
+ resolution: {integrity: sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==}
dependencies:
undici-types: 5.26.5
- dev: true
/@types/prop-types@15.7.5:
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
- /@types/qs@6.9.12:
- resolution: {integrity: sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==}
- dev: true
-
- /@types/react-dom@18.2.22:
- resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==}
+ /@types/react-dom@18.2.24:
+ resolution: {integrity: sha512-cN6upcKd8zkGy4HU9F1+/s98Hrp6D4MOcippK4PoE8OZRngohHZpbJn1GsaDLz87MqvHNoT13nHvNqM9ocRHZg==}
dependencies:
- '@types/react': 18.2.66
+ '@types/react': 18.2.74
dev: true
- /@types/react@18.2.66:
- resolution: {integrity: sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==}
+ /@types/react-transition-group@4.4.10:
+ resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==}
+ dependencies:
+ '@types/react': 18.2.74
+ dev: false
+
+ /@types/react@18.2.74:
+ resolution: {integrity: sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==}
dependencies:
'@types/prop-types': 15.7.5
- '@types/scheduler': 0.16.3
csstype: 3.1.2
- /@types/scheduler@0.16.3:
- resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
-
/@types/showdown@2.0.6:
resolution: {integrity: sha512-pTvD/0CIeqe4x23+YJWlX2gArHa8G0J0Oh6GKaVXV7TAeickpkkZiNOgFcFcmLQ5lB/K0qBJL1FtRYltBfbGCQ==}
dev: true
@@ -1089,6 +1179,10 @@
resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
dev: true
+ /@types/warning@3.0.3:
+ resolution: {integrity: sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==}
+ dev: false
+
/@types/yargs-parser@21.0.0:
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
dev: true
@@ -1099,7 +1193,7 @@
'@types/yargs-parser': 21.0.0
dev: true
- /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2):
+ /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.4):
resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1111,10 +1205,10 @@
dependencies:
'@typescript-eslint/scope-manager': 5.62.0
'@typescript-eslint/types': 5.62.0
- '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2)
+ '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.4)
debug: 4.3.4
eslint: 8.57.0
- typescript: 5.4.2
+ typescript: 5.4.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -1132,7 +1226,7 @@
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
- /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.2):
+ /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.4):
resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1147,8 +1241,8 @@
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.4
- tsutils: 3.21.0(typescript@5.4.2)
- typescript: 5.4.2
+ tsutils: 3.21.0(typescript@5.4.4)
+ typescript: 5.4.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -1173,12 +1267,26 @@
acorn: 8.10.0
dev: true
+ /acorn-jsx@5.3.2(acorn@8.11.3):
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ dependencies:
+ acorn: 8.11.3
+ dev: true
+
/acorn@8.10.0:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
+ /acorn@8.11.3:
+ resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
/agent-base@7.1.0:
resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
engines: {node: '>= 14'}
@@ -1248,13 +1356,6 @@
dequal: 2.0.3
dev: true
- /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: true
-
/array-buffer-byte-length@1.0.1:
resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
engines: {node: '>= 0.4'}
@@ -1263,24 +1364,13 @@
is-array-buffer: 3.0.4
dev: true
- /array-includes@3.1.6:
- resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- get-intrinsic: 1.2.1
- is-string: 1.0.7
- dev: true
-
/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
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
get-intrinsic: 1.2.4
is-string: 1.0.7
dev: true
@@ -1323,34 +1413,14 @@
es-shim-unscopables: 1.0.2
dev: true
- /array.prototype.flat@1.3.1:
- resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- es-shim-unscopables: 1.0.0
- dev: true
-
/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
- dev: true
-
- /array.prototype.flatmap@1.3.1:
- resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- es-shim-unscopables: 1.0.0
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-shim-unscopables: 1.0.2
dev: true
/array.prototype.flatmap@1.3.2:
@@ -1358,18 +1428,18 @@
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
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-shim-unscopables: 1.0.2
dev: true
/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
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
+ es-shim-unscopables: 1.0.2
dev: true
/array.prototype.tosorted@1.1.3:
@@ -1382,18 +1452,6 @@
es-shim-unscopables: 1.0.2
dev: true
- /arraybuffer.prototype.slice@1.0.1:
- resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==}
- engines: {node: '>= 0.4'}
- dependencies:
- array-buffer-byte-length: 1.0.0
- call-bind: 1.0.2
- define-properties: 1.2.0
- get-intrinsic: 1.2.1
- is-array-buffer: 3.0.2
- is-shared-array-buffer: 1.0.2
- dev: true
-
/arraybuffer.prototype.slice@1.0.3:
resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
engines: {node: '>= 0.4'}
@@ -1426,11 +1484,6 @@
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
- /available-typed-arrays@1.0.5:
- resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
- engines: {node: '>= 0.4'}
- dev: true
-
/available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -1500,13 +1553,6 @@
dependencies:
streamsearch: 1.1.0
- /call-bind@1.0.2:
- resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
- dependencies:
- function-bind: 1.1.1
- get-intrinsic: 1.2.1
- dev: true
-
/call-bind@1.0.7:
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
engines: {node: '>= 0.4'}
@@ -1516,7 +1562,6 @@
function-bind: 1.1.2
get-intrinsic: 1.2.4
set-function-length: 1.2.1
- dev: true
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
@@ -1723,15 +1768,6 @@
es-define-property: 1.0.0
es-errors: 1.3.0
gopd: 1.0.1
- dev: true
-
- /define-properties@1.2.0:
- resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
- engines: {node: '>= 0.4'}
- dependencies:
- has-property-descriptors: 1.0.0
- object-keys: 1.1.1
- dev: true
/define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
@@ -1755,10 +1791,9 @@
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
- dev: true
- /detect-libc@2.0.2:
- resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
+ /detect-libc@2.0.3:
+ resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
engines: {node: '>=8'}
dev: false
@@ -1814,8 +1849,8 @@
domelementtype: 2.3.0
dev: false
- /dompurify@3.0.9:
- resolution: {integrity: sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ==}
+ /dompurify@3.0.11:
+ resolution: {integrity: sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg==}
dev: false
/domutils@3.1.0:
@@ -1855,51 +1890,6 @@
engines: {node: '>=0.12'}
dev: false
- /es-abstract@1.22.1:
- resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==}
- engines: {node: '>= 0.4'}
- dependencies:
- array-buffer-byte-length: 1.0.0
- arraybuffer.prototype.slice: 1.0.1
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- es-set-tostringtag: 2.0.1
- es-to-primitive: 1.2.1
- function.prototype.name: 1.1.5
- get-intrinsic: 1.2.1
- get-symbol-description: 1.0.0
- globalthis: 1.0.3
- gopd: 1.0.1
- has: 1.0.3
- has-property-descriptors: 1.0.0
- has-proto: 1.0.1
- has-symbols: 1.0.3
- internal-slot: 1.0.5
- is-array-buffer: 3.0.2
- is-callable: 1.2.7
- is-negative-zero: 2.0.2
- is-regex: 1.1.4
- is-shared-array-buffer: 1.0.2
- is-string: 1.0.7
- is-typed-array: 1.1.10
- is-weakref: 1.0.2
- object-inspect: 1.12.3
- object-keys: 1.1.1
- object.assign: 4.1.4
- regexp.prototype.flags: 1.5.0
- safe-array-concat: 1.0.0
- safe-regex-test: 1.0.0
- string.prototype.trim: 1.2.7
- string.prototype.trimend: 1.0.6
- string.prototype.trimstart: 1.0.6
- typed-array-buffer: 1.0.0
- typed-array-byte-length: 1.0.0
- typed-array-byte-offset: 1.0.0
- typed-array-length: 1.0.4
- unbox-primitive: 1.0.2
- which-typed-array: 1.1.10
- dev: true
-
/es-abstract@1.22.5:
resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==}
engines: {node: '>= 0.4'}
@@ -1956,12 +1946,10 @@
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.4
- dev: true
/es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
- dev: true
/es-iterator-helpers@1.0.17:
resolution: {integrity: sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==}
@@ -1977,22 +1965,13 @@
get-intrinsic: 1.2.4
globalthis: 1.0.3
has-property-descriptors: 1.0.2
- has-proto: 1.0.1
+ has-proto: 1.0.3
has-symbols: 1.0.3
internal-slot: 1.0.7
iterator.prototype: 1.1.2
safe-array-concat: 1.1.2
dev: true
- /es-set-tostringtag@2.0.1:
- resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
- engines: {node: '>= 0.4'}
- dependencies:
- get-intrinsic: 1.2.1
- has: 1.0.3
- has-tostringtag: 1.0.0
- dev: true
-
/es-set-tostringtag@2.0.3:
resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
engines: {node: '>= 0.4'}
@@ -2002,12 +1981,6 @@
hasown: 2.0.1
dev: true
- /es-shim-unscopables@1.0.0:
- resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==}
- dependencies:
- has: 1.0.3
- dev: true
-
/es-shim-unscopables@1.0.2:
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
dependencies:
@@ -2038,8 +2011,8 @@
engines: {node: '>=10'}
dev: true
- /eslint-config-next@14.1.3(eslint@8.57.0)(typescript@5.4.2):
- resolution: {integrity: sha512-sUCpWlGuHpEhI0pIT0UtdSLJk5Z8E2DYinPTwsBiWaSYQomchdl0i60pjynY48+oXvtyWMQ7oE+G3m49yrfacg==}
+ /eslint-config-next@14.1.4(eslint@8.57.0)(typescript@5.4.4):
+ resolution: {integrity: sha512-cihIahbhYAWwXJwZkAaRPpUi5t9aOi/HdfWXOjZeUOqNWXHD8X22kd1KG58Dc3MVaRx3HoR/oMGk2ltcrqDn8g==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0
typescript: '>=3.3.1'
@@ -2047,9 +2020,9 @@
typescript:
optional: true
dependencies:
- '@next/eslint-plugin-next': 14.1.3
+ '@next/eslint-plugin-next': 14.1.4
'@rushstack/eslint-patch': 1.7.2
- '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.4)
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.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
@@ -2057,7 +2030,7 @@
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
+ typescript: 5.4.4
transitivePeerDependencies:
- eslint-import-resolver-webpack
- supports-color
@@ -2087,7 +2060,7 @@
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-core-module: 2.13.1
is-glob: 4.0.3
transitivePeerDependencies:
- '@typescript-eslint/parser'
@@ -2117,7 +2090,7 @@
eslint-import-resolver-webpack:
optional: true
dependencies:
- '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.4)
debug: 3.2.7
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
@@ -2136,7 +2109,7 @@
'@typescript-eslint/parser':
optional: true
dependencies:
- '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2)
+ '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.4)
array-includes: 3.1.7
array.prototype.findlastindex: 1.2.4
array.prototype.flat: 1.3.2
@@ -2169,8 +2142,8 @@
dependencies:
'@babel/runtime': 7.23.9
aria-query: 5.3.0
- array-includes: 3.1.6
- array.prototype.flatmap: 1.3.1
+ array-includes: 3.1.7
+ array.prototype.flatmap: 1.3.2
ast-types-flow: 0.0.7
axe-core: 4.7.2
axobject-query: 3.2.1
@@ -2181,8 +2154,8 @@
jsx-ast-utils: 3.3.4
language-tags: 1.0.5
minimatch: 3.1.2
- object.entries: 1.1.6
- object.fromentries: 2.0.6
+ object.entries: 1.1.7
+ object.fromentries: 2.0.7
semver: 6.3.1
dev: true
@@ -2230,11 +2203,24 @@
estraverse: 5.3.0
dev: true
+ /eslint-scope@8.0.1:
+ resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
/eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
+ /eslint-visitor-keys@4.0.0:
+ resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dev: true
+
/eslint@8.57.0:
resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -2282,6 +2268,58 @@
- supports-color
dev: true
+ /eslint@9.0.0:
+ resolution: {integrity: sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0)
+ '@eslint-community/regexpp': 4.6.2
+ '@eslint/eslintrc': 3.0.2
+ '@eslint/js': 9.0.0
+ '@humanwhocodes/config-array': 0.12.3
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.4
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.0.1
+ eslint-visitor-keys: 4.0.0
+ espree: 10.0.1
+ esquery: 1.5.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ graphemer: 1.4.0
+ ignore: 5.2.4
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.3
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree@10.0.1:
+ resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ dependencies:
+ acorn: 8.11.3
+ acorn-jsx: 5.3.2(acorn@8.11.3)
+ eslint-visitor-keys: 4.0.0
+ dev: true
+
/espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -2310,6 +2348,10 @@
engines: {node: '>=4.0'}
dev: true
+ /estree-walker@0.6.1:
+ resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==}
+ dev: true
+
/estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
@@ -2324,7 +2366,7 @@
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/expect-utils': 29.6.1
- '@types/node': 20.11.28
+ '@types/node': 20.12.5
jest-get-type: 29.4.3
jest-matcher-utils: 29.6.1
jest-message-util: 29.6.1
@@ -2335,17 +2377,6 @@
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
- /fast-glob@3.3.0:
- resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==}
- 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
- dev: true
-
/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
@@ -2382,6 +2413,13 @@
flat-cache: 3.0.4
dev: true
+ /file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+ dependencies:
+ flat-cache: 4.0.1
+ dev: true
+
/file-stream-rotator@0.6.1:
resolution: {integrity: sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==}
dependencies:
@@ -2410,10 +2448,22 @@
rimraf: 3.0.2
dev: true
+ /flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+ dependencies:
+ flatted: 3.3.1
+ keyv: 4.5.4
+ dev: true
+
/flatted@3.2.7:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
dev: true
+ /flatted@3.3.1:
+ resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
+ dev: true
+
/fn.name@1.1.0:
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
dev: false
@@ -2468,17 +2518,6 @@
/function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
- dev: true
-
- /function.prototype.name@1.1.5:
- resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- functions-have-names: 1.2.3
- dev: true
/function.prototype.name@1.1.6:
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
@@ -2499,15 +2538,6 @@
engines: {node: '>= 4'}
dev: false
- /get-intrinsic@1.2.1:
- resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
- dependencies:
- function-bind: 1.1.1
- has: 1.0.3
- has-proto: 1.0.1
- has-symbols: 1.0.3
- dev: true
-
/get-intrinsic@1.2.4:
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
@@ -2517,15 +2547,6 @@
has-proto: 1.0.1
has-symbols: 1.0.3
hasown: 2.0.1
- dev: true
-
- /get-symbol-description@1.0.0:
- resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- dev: true
/get-symbol-description@1.0.2:
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
@@ -2585,11 +2606,16 @@
type-fest: 0.20.2
dev: true
+ /globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+ dev: true
+
/globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
dependencies:
- define-properties: 1.2.0
+ define-properties: 1.2.1
dev: true
/globby@11.1.0:
@@ -2598,7 +2624,7 @@
dependencies:
array-union: 2.1.0
dir-glob: 3.0.1
- fast-glob: 3.3.0
+ fast-glob: 3.3.2
ignore: 5.2.4
merge2: 1.4.1
slash: 3.0.0
@@ -2612,7 +2638,6 @@
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies:
get-intrinsic: 1.2.4
- dev: true
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@@ -2635,22 +2660,14 @@
engines: {node: '>=8'}
dev: true
- /has-property-descriptors@1.0.0:
- resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
- dependencies:
- get-intrinsic: 1.2.1
- dev: true
-
/has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
dependencies:
es-define-property: 1.0.0
- dev: true
/has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
- dev: true
/has-proto@1.0.3:
resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
@@ -2660,14 +2677,6 @@
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
- dev: true
-
- /has-tostringtag@1.0.0:
- resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
- engines: {node: '>= 0.4'}
- dependencies:
- has-symbols: 1.0.3
- dev: true
/has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
@@ -2688,7 +2697,6 @@
engines: {node: '>= 0.4'}
dependencies:
function-bind: 1.1.2
- dev: true
/html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
@@ -2764,15 +2772,6 @@
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- /internal-slot@1.0.5:
- resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
- engines: {node: '>= 0.4'}
- dependencies:
- get-intrinsic: 1.2.1
- has: 1.0.3
- side-channel: 1.0.4
- dev: true
-
/internal-slot@1.0.7:
resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
engines: {node: '>= 0.4'}
@@ -2790,13 +2789,11 @@
'@formatjs/icu-messageformat-parser': 2.1.0
tslib: 2.6.2
- /is-array-buffer@3.0.2:
- resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+ /invariant@2.2.4:
+ resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- is-typed-array: 1.1.10
- dev: true
+ loose-envify: 1.4.0
+ dev: false
/is-array-buffer@3.0.4:
resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
@@ -2814,7 +2811,7 @@
resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: true
/is-bigint@1.0.4:
@@ -2833,8 +2830,8 @@
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
engines: {node: '>= 0.4'}
dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
dev: true
/is-callable@1.2.7:
@@ -2858,7 +2855,7 @@
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: true
/is-extglob@2.1.1:
@@ -2880,7 +2877,7 @@
resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: true
/is-glob@4.0.3:
@@ -2894,11 +2891,6 @@
engines: {node: '>= 0.4'}
dev: true
- /is-negative-zero@2.0.2:
- resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
- engines: {node: '>= 0.4'}
- dev: true
-
/is-negative-zero@2.0.3:
resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
engines: {node: '>= 0.4'}
@@ -2908,7 +2900,7 @@
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: true
/is-number@7.0.0:
@@ -2928,8 +2920,8 @@
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
dependencies:
- call-bind: 1.0.2
- has-tostringtag: 1.0.0
+ call-bind: 1.0.7
+ has-tostringtag: 1.0.2
dev: true
/is-set@2.0.3:
@@ -2937,12 +2929,6 @@
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: true
-
/is-shared-array-buffer@1.0.3:
resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
engines: {node: '>= 0.4'}
@@ -2959,7 +2945,7 @@
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
dependencies:
- has-tostringtag: 1.0.0
+ has-tostringtag: 1.0.2
dev: true
/is-symbol@1.0.4:
@@ -2969,17 +2955,6 @@
has-symbols: 1.0.3
dev: true
- /is-typed-array@1.1.10:
- resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
- engines: {node: '>= 0.4'}
- dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- for-each: 0.3.3
- gopd: 1.0.1
- has-tostringtag: 1.0.0
- dev: true
-
/is-typed-array@1.1.13:
resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
engines: {node: '>= 0.4'}
@@ -2995,7 +2970,7 @@
/is-weakref@1.0.2:
resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
dependencies:
- call-bind: 1.0.2
+ call-bind: 1.0.7
dev: true
/is-weakset@2.0.3:
@@ -3014,12 +2989,12 @@
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
- /isomorphic-dompurify@2.4.0:
- resolution: {integrity: sha512-OW3VSGrjppnbshcHz7RNKnoYlCJkyBBJzEE5yxrTSA+kOl9JPTIrXsnIgOuH4wdLqqRujx22bz/IXebGWPLMAg==}
+ /isomorphic-dompurify@2.6.0:
+ resolution: {integrity: sha512-hTH3xazYEhs+cJu2uLaw/mPPvTefW6ljyRt2JiQ3OBoQ7+3YpgZOLmeBrDrGS/tnDQx1BuwwZcl6wEsYIVK4uQ==}
engines: {node: '>=18'}
dependencies:
'@types/dompurify': 3.0.5
- dompurify: 3.0.9
+ dompurify: 3.0.11
jsdom: 24.0.0
transitivePeerDependencies:
- bufferutil
@@ -3092,7 +3067,7 @@
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
dependencies:
'@jest/types': 29.6.1
- '@types/node': 20.11.28
+ '@types/node': 20.12.5
chalk: 4.1.2
ci-info: 3.8.0
graceful-fs: 4.2.11
@@ -3145,6 +3120,10 @@
- utf-8-validate
dev: false
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ dev: true
+
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true
@@ -3164,10 +3143,16 @@
resolution: {integrity: sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==}
engines: {node: '>=4.0'}
dependencies:
- array-includes: 3.1.6
- array.prototype.flat: 1.3.1
- object.assign: 4.1.4
- object.values: 1.1.6
+ array-includes: 3.1.7
+ array.prototype.flat: 1.3.2
+ object.assign: 4.1.5
+ object.values: 1.1.7
+ dev: true
+
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ dependencies:
+ json-buffer: 3.0.1
dev: true
/kuler@2.0.0:
@@ -3223,6 +3208,12 @@
/lru-cache@10.0.1:
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
engines: {node: 14 || >=16.14}
+ dev: true
+
+ /lru-cache@10.2.0:
+ resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
+ engines: {node: 14 || >=16.14}
+ dev: false
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
@@ -3230,15 +3221,15 @@
dependencies:
yallist: 4.0.0
- /mariadb@3.2.3:
- resolution: {integrity: sha512-Hyc1ehdUJwzvvzcLU2juZS528wJ6oE8pUlpgY0BAOdpKWcdN1motuugi5lC3jkpCkFpyNknHG7Yg66KASl3aPg==}
- engines: {node: '>= 12'}
+ /mariadb@3.3.0:
+ resolution: {integrity: sha512-sAL4bJgbfCAtXcE8bXI+NAMzVaPNkIU8hRZUXYfgNFoWB9U57G3XQiMeCx/A6IrS6y7kGwBLylrwgsZQ8kUYlw==}
+ engines: {node: '>= 14'}
dependencies:
- '@types/geojson': 7946.0.10
- '@types/node': 17.0.45
+ '@types/geojson': 7946.0.14
+ '@types/node': 20.12.5
denque: 2.1.0
iconv-lite: 0.6.3
- lru-cache: 10.0.1
+ lru-cache: 10.2.0
dev: false
/merge2@1.4.1:
@@ -3288,8 +3279,8 @@
engines: {node: '>=16 || 14 >=14.17'}
dev: true
- /mobx-react-lite@4.0.6(mobx@6.12.0)(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-0rOE0KDMwV9CzsstYC86ZxxrUpKLGBN0/T3WpKZibLnJcukdb9HVL8VKHoDxaBPbInLZ5azPKUod4mXTsi+u+A==}
+ /mobx-react-lite@4.0.7(mobx@6.12.3)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-RjwdseshK9Mg8On5tyJZHtGD+J78ZnCnRaxeQDSiciKVQDUbfZcXhmld0VMxAwvcTnPEHZySGGewm467Fcpreg==}
peerDependencies:
mobx: ^6.9.0
react: ^16.8.0 || ^17 || ^18
@@ -3301,14 +3292,14 @@
react-native:
optional: true
dependencies:
- mobx: 6.12.0
+ mobx: 6.12.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
- /mobx@6.12.0:
- resolution: {integrity: sha512-Mn6CN6meXEnMa0a5u6a5+RKrqRedHBhZGd15AWLk9O6uFY4KYHzImdt8JI8WODo1bjTSRnwXhJox+FCUZhCKCQ==}
+ /mobx@6.12.3:
+ resolution: {integrity: sha512-c8NKkO4R2lShkSXZ2Ongj1ycjugjzFFo/UswHBnS62y07DMcTc9Rvo03/3nRyszIvwPNljlkd4S828zIBv/piw==}
dev: false
/moment@2.29.4:
@@ -3334,20 +3325,20 @@
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
- /next-intl@3.9.5(next@14.1.3)(react@18.2.0):
- resolution: {integrity: sha512-tsp4N433WgTAbbyZdMlcsLGHFM88wv2a7ZpF/od8X9+qAlO1TrajZrNrGBpIg6nA9EGZyMbQPzZD7XZrqYIv7g==}
+ /next-intl@3.11.1(next@14.1.4)(react@18.2.0):
+ resolution: {integrity: sha512-KaMdMMTLJ8Qs15AfltKFTdzk3OjAEIKRGmRu6kpH5Mv3DPUoOX9sQ+fXvNlKmLzw+TeBt5yPCswzLZFmJMbsOA==}
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)
+ next: 14.1.4(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1)
react: 18.2.0
- use-intl: 3.9.5(react@18.2.0)
+ use-intl: 3.11.1(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==}
+ /next@14.1.4(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1):
+ resolution: {integrity: sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -3361,7 +3352,7 @@
sass:
optional: true
dependencies:
- '@next/env': 14.1.3
+ '@next/env': 14.1.4
'@swc/helpers': 0.5.2
busboy: 1.6.0
caniuse-lite: 1.0.30001597
@@ -3369,18 +3360,18 @@
postcss: 8.4.31
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- sass: 1.72.0
+ sass: 1.74.1
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
+ '@next/swc-darwin-arm64': 14.1.4
+ '@next/swc-darwin-x64': 14.1.4
+ '@next/swc-linux-arm64-gnu': 14.1.4
+ '@next/swc-linux-arm64-musl': 14.1.4
+ '@next/swc-linux-x64-gnu': 14.1.4
+ '@next/swc-linux-x64-musl': 14.1.4
+ '@next/swc-win32-arm64-msvc': 14.1.4
+ '@next/swc-win32-ia32-msvc': 14.1.4
+ '@next/swc-win32-x64-msvc': 14.1.4
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
@@ -3402,29 +3393,14 @@
engines: {node: '>= 6'}
dev: false
- /object-inspect@1.12.3:
- resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
- dev: true
-
/object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
- dev: true
/object-keys@1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
dev: true
- /object.assign@4.1.4:
- resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- has-symbols: 1.0.3
- object-keys: 1.1.1
- dev: true
-
/object.assign@4.1.5:
resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
engines: {node: '>= 0.4'}
@@ -3435,31 +3411,13 @@
object-keys: 1.1.1
dev: true
- /object.entries@1.1.6:
- resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- dev: true
-
/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==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
dev: true
/object.fromentries@2.0.7:
@@ -3467,8 +3425,8 @@
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.1
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
dev: true
/object.groupby@1.0.2:
@@ -3484,17 +3442,8 @@
/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'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
dev: true
/object.values@1.1.7:
@@ -3502,8 +3451,8 @@
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.1
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
dev: true
/once@1.4.0:
@@ -3629,6 +3578,16 @@
react-is: 18.2.0
dev: true
+ /prop-types-extra@1.1.1(react@18.2.0):
+ resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==}
+ peerDependencies:
+ react: '>=0.14.0'
+ dependencies:
+ react: 18.2.0
+ react-is: 16.13.1
+ warning: 4.0.3
+ dev: false
+
/prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies:
@@ -3644,11 +3603,6 @@
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
dev: false
- /punycode@2.3.0:
- resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
- engines: {node: '>=6'}
- dev: false
-
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -3658,7 +3612,7 @@
engines: {node: '>=0.6'}
dependencies:
side-channel: 1.0.6
- dev: true
+ dev: false
/querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
@@ -3668,6 +3622,42 @@
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
+ /react-bootstrap-icons@1.11.3(react@18.2.0):
+ resolution: {integrity: sha512-f/DAy4UXnjdbaZyUcZKR2I3xim56uCznb9t+u3ojwzDG1p2RUrua/d8R4xplAQ8Bj/LVZwHVSrvO+npvp3l3pw==}
+ peerDependencies:
+ react: '>=16.8.6'
+ dependencies:
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
+ /react-bootstrap@2.10.2(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-UvB7mRqQjivdZNxJNEA2yOQRB7L9N43nBnKc33K47+cH90/ujmnMwatTCwQLu83gLhrzAl8fsa6Lqig/KLghaA==}
+ peerDependencies:
+ '@types/react': '>=16.14.8'
+ react: '>=16.14.0'
+ react-dom: '>=16.14.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.23.9
+ '@restart/hooks': 0.4.16(react@18.2.0)
+ '@restart/ui': 1.6.8(react-dom@18.2.0)(react@18.2.0)
+ '@types/react': 18.2.74
+ '@types/react-transition-group': 4.4.10
+ classnames: 2.3.2
+ dom-helpers: 5.2.1
+ invariant: 2.2.4
+ prop-types: 15.8.1
+ prop-types-extra: 1.1.1(react@18.2.0)
+ react: 18.2.0
+ react-dom: 18.2.0(react@18.2.0)
+ react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0)
+ uncontrollable: 7.2.1(react@18.2.0)
+ warning: 4.0.3
+ dev: false
+
/react-contexify@6.0.0(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-jMhz6yZI81Jv3UDj7TXqCkhdkCFEEmvwGCPXsQuA2ZUC8EbCuVQ6Cy8FzKMXa0y454XTDClBN2YFvvmoFlrFkg==}
peerDependencies:
@@ -3688,10 +3678,6 @@
react: 18.2.0
scheduler: 0.23.0
- /react-fast-compare@3.2.2:
- resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
- dev: false
-
/react-infinite-scroll-component@6.1.0(react@18.2.0):
resolution: {integrity: sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==}
peerDependencies:
@@ -3708,18 +3694,8 @@
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
dev: true
- /react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==}
- peerDependencies:
- '@popperjs/core': ^2.0.0
- react: ^16.8.0 || ^17 || ^18
- react-dom: ^16.8.0 || ^17 || ^18
- dependencies:
- '@popperjs/core': 2.11.8
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
- react-fast-compare: 3.2.2
- warning: 4.0.3
+ /react-lifecycles-compat@3.0.4:
+ resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
dev: false
/react-spinners@0.13.8(react-dom@18.2.0)(react@18.2.0):
@@ -3732,7 +3708,7 @@
react-dom: 18.2.0(react@18.2.0)
dev: false
- /react-textarea-autosize@8.5.3(@types/react@18.2.66)(react@18.2.0):
+ /react-textarea-autosize@8.5.3(@types/react@18.2.74)(react@18.2.0):
resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==}
engines: {node: '>=10'}
peerDependencies:
@@ -3741,7 +3717,7 @@
'@babel/runtime': 7.23.9
react: 18.2.0
use-composed-ref: 1.3.0(react@18.2.0)
- use-latest: 1.2.1(@types/react@18.2.66)(react@18.2.0)
+ use-latest: 1.2.1(@types/react@18.2.74)(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
dev: false
@@ -3777,22 +3753,6 @@
dependencies:
loose-envify: 1.4.0
- /reactstrap@9.2.2(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-4KroiGOdqZLAnMGzHjpErW3G7bLB+QbKzzMLIDXydPIV0y74lpdL7WtXHkLWAGInd97WCPNx4+R0NQDPyzIfhw==}
- peerDependencies:
- react: '>=16.8.0'
- react-dom: '>=16.8.0'
- dependencies:
- '@babel/runtime': 7.23.2
- '@popperjs/core': 2.11.8
- classnames: 2.3.2
- prop-types: 15.8.1
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
- react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@18.2.0)(react@18.2.0)
- react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0)
- dev: false
-
/readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
@@ -3835,15 +3795,6 @@
/regenerator-runtime@0.14.0:
resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
- /regexp.prototype.flags@1.5.0:
- resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- functions-have-names: 1.2.3
- dev: true
-
/regexp.prototype.flags@1.5.2:
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
engines: {node: '>= 0.4'}
@@ -3906,26 +3857,40 @@
glob: 7.2.3
dev: true
- /rollup@4.13.0:
- resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==}
+ /rollup-plugin-scss@4.0.0:
+ resolution: {integrity: sha512-wxasNXDYC2m+fDxCMgK00WebVWYmeFvShyNABmjvSJZ6D1/SepwqFeaMFMQromveI79gfvb64yJjiZZxSZxEIA==}
+ dependencies:
+ rollup-pluginutils: 2.8.2
+ dev: true
+
+ /rollup-pluginutils@2.8.2:
+ resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==}
+ dependencies:
+ estree-walker: 0.6.1
+ dev: true
+
+ /rollup@4.14.0:
+ resolution: {integrity: sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.13.0
- '@rollup/rollup-android-arm64': 4.13.0
- '@rollup/rollup-darwin-arm64': 4.13.0
- '@rollup/rollup-darwin-x64': 4.13.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.13.0
- '@rollup/rollup-linux-arm64-gnu': 4.13.0
- '@rollup/rollup-linux-arm64-musl': 4.13.0
- '@rollup/rollup-linux-riscv64-gnu': 4.13.0
- '@rollup/rollup-linux-x64-gnu': 4.13.0
- '@rollup/rollup-linux-x64-musl': 4.13.0
- '@rollup/rollup-win32-arm64-msvc': 4.13.0
- '@rollup/rollup-win32-ia32-msvc': 4.13.0
- '@rollup/rollup-win32-x64-msvc': 4.13.0
+ '@rollup/rollup-android-arm-eabi': 4.14.0
+ '@rollup/rollup-android-arm64': 4.14.0
+ '@rollup/rollup-darwin-arm64': 4.14.0
+ '@rollup/rollup-darwin-x64': 4.14.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.14.0
+ '@rollup/rollup-linux-arm64-gnu': 4.14.0
+ '@rollup/rollup-linux-arm64-musl': 4.14.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.14.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.14.0
+ '@rollup/rollup-linux-s390x-gnu': 4.14.0
+ '@rollup/rollup-linux-x64-gnu': 4.14.0
+ '@rollup/rollup-linux-x64-musl': 4.14.0
+ '@rollup/rollup-win32-arm64-msvc': 4.14.0
+ '@rollup/rollup-win32-ia32-msvc': 4.14.0
+ '@rollup/rollup-win32-x64-msvc': 4.14.0
fsevents: 2.3.3
dev: true
@@ -3939,16 +3904,6 @@
queue-microtask: 1.2.3
dev: true
- /safe-array-concat@1.0.0:
- resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==}
- engines: {node: '>=0.4'}
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- has-symbols: 1.0.3
- isarray: 2.0.5
- dev: true
-
/safe-array-concat@1.1.2:
resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
engines: {node: '>=0.4'}
@@ -3963,14 +3918,6 @@
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
- /safe-regex-test@1.0.0:
- resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- is-regex: 1.1.4
- dev: true
-
/safe-regex-test@1.0.3:
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
engines: {node: '>= 0.4'}
@@ -3989,8 +3936,8 @@
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
- /sass@1.72.0:
- resolution: {integrity: sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==}
+ /sass@1.74.1:
+ resolution: {integrity: sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
@@ -4021,6 +3968,15 @@
hasBin: true
dependencies:
lru-cache: 6.0.0
+ dev: true
+
+ /semver@7.6.0:
+ resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: false
/set-function-length@1.2.1:
resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==}
@@ -4032,7 +3988,6 @@
get-intrinsic: 1.2.4
gopd: 1.0.1
has-property-descriptors: 1.0.2
- dev: true
/set-function-name@2.0.2:
resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
@@ -4044,34 +3999,34 @@
has-property-descriptors: 1.0.2
dev: true
- /sharp@0.33.2:
- resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==}
- engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ /sharp@0.33.3:
+ resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==}
+ engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
requiresBuild: true
dependencies:
color: 4.2.3
- detect-libc: 2.0.2
- semver: 7.5.4
+ detect-libc: 2.0.3
+ semver: 7.6.0
optionalDependencies:
- '@img/sharp-darwin-arm64': 0.33.2
- '@img/sharp-darwin-x64': 0.33.2
- '@img/sharp-libvips-darwin-arm64': 1.0.1
- '@img/sharp-libvips-darwin-x64': 1.0.1
- '@img/sharp-libvips-linux-arm': 1.0.1
- '@img/sharp-libvips-linux-arm64': 1.0.1
- '@img/sharp-libvips-linux-s390x': 1.0.1
- '@img/sharp-libvips-linux-x64': 1.0.1
- '@img/sharp-libvips-linuxmusl-arm64': 1.0.1
- '@img/sharp-libvips-linuxmusl-x64': 1.0.1
- '@img/sharp-linux-arm': 0.33.2
- '@img/sharp-linux-arm64': 0.33.2
- '@img/sharp-linux-s390x': 0.33.2
- '@img/sharp-linux-x64': 0.33.2
- '@img/sharp-linuxmusl-arm64': 0.33.2
- '@img/sharp-linuxmusl-x64': 0.33.2
- '@img/sharp-wasm32': 0.33.2
- '@img/sharp-win32-ia32': 0.33.2
- '@img/sharp-win32-x64': 0.33.2
+ '@img/sharp-darwin-arm64': 0.33.3
+ '@img/sharp-darwin-x64': 0.33.3
+ '@img/sharp-libvips-darwin-arm64': 1.0.2
+ '@img/sharp-libvips-darwin-x64': 1.0.2
+ '@img/sharp-libvips-linux-arm': 1.0.2
+ '@img/sharp-libvips-linux-arm64': 1.0.2
+ '@img/sharp-libvips-linux-s390x': 1.0.2
+ '@img/sharp-libvips-linux-x64': 1.0.2
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.2
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.2
+ '@img/sharp-linux-arm': 0.33.3
+ '@img/sharp-linux-arm64': 0.33.3
+ '@img/sharp-linux-s390x': 0.33.3
+ '@img/sharp-linux-x64': 0.33.3
+ '@img/sharp-linuxmusl-arm64': 0.33.3
+ '@img/sharp-linuxmusl-x64': 0.33.3
+ '@img/sharp-wasm32': 0.33.3
+ '@img/sharp-win32-ia32': 0.33.3
+ '@img/sharp-win32-x64': 0.33.3
dev: false
/shebang-command@2.0.0:
@@ -4086,14 +4041,6 @@
engines: {node: '>=8'}
dev: true
- /side-channel@1.0.4:
- resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- object-inspect: 1.12.3
- dev: true
-
/side-channel@1.0.6:
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
engines: {node: '>= 0.4'}
@@ -4102,7 +4049,6 @@
es-errors: 1.3.0
get-intrinsic: 1.2.4
object-inspect: 1.13.1
- dev: true
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
@@ -4161,25 +4107,16 @@
resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==}
dependencies:
call-bind: 1.0.7
- define-properties: 1.2.0
- es-abstract: 1.22.1
+ define-properties: 1.2.1
+ es-abstract: 1.22.5
get-intrinsic: 1.2.4
has-symbols: 1.0.3
- internal-slot: 1.0.5
- regexp.prototype.flags: 1.5.0
+ internal-slot: 1.0.7
+ regexp.prototype.flags: 1.5.2
set-function-name: 2.0.2
side-channel: 1.0.6
dev: true
- /string.prototype.trim@1.2.7:
- resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- dev: true
-
/string.prototype.trim@1.2.8:
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
engines: {node: '>= 0.4'}
@@ -4189,14 +4126,6 @@
es-abstract: 1.22.5
dev: true
- /string.prototype.trimend@1.0.6:
- resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- dev: true
-
/string.prototype.trimend@1.0.7:
resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
dependencies:
@@ -4205,14 +4134,6 @@
es-abstract: 1.22.5
dev: true
- /string.prototype.trimstart@1.0.6:
- resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==}
- dependencies:
- call-bind: 1.0.2
- define-properties: 1.2.0
- es-abstract: 1.22.1
- dev: true
-
/string.prototype.trimstart@1.0.7:
resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
dependencies:
@@ -4286,8 +4207,8 @@
engines: {node: '>= 0.4'}
dev: true
- /sweetalert2@11.10.6:
- resolution: {integrity: sha512-CINZPLZXZRSZqSOE7H7j1F7X8e8O1kLOiXPmtJn1DYxvXsKBr3d16d90+IcwTTs7dJww20h8r8QIxIwsLGX+6A==}
+ /sweetalert2@11.10.7:
+ resolution: {integrity: sha512-5Jlzrmaitay6KzU+2+LhYu9q+L4v/dZ8oZyEDH14ep0C/QilCnFLHmqAyD/Lhq/lm5DiwsOs6Tr58iv8k3wyGg==}
dev: false
/symbol-tree@3.2.4:
@@ -4323,7 +4244,7 @@
engines: {node: '>=6'}
dependencies:
psl: 1.9.0
- punycode: 2.3.0
+ punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
dev: false
@@ -4356,14 +4277,14 @@
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
- /tsutils@3.21.0(typescript@5.4.2):
+ /tsutils@3.21.0(typescript@5.4.4):
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
- typescript: 5.4.2
+ typescript: 5.4.4
dev: true
/type-check@0.4.0:
@@ -4378,15 +4299,6 @@
engines: {node: '>=10'}
dev: true
- /typed-array-buffer@1.0.0:
- resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- get-intrinsic: 1.2.1
- is-typed-array: 1.1.10
- dev: true
-
/typed-array-buffer@1.0.2:
resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
engines: {node: '>= 0.4'}
@@ -4396,16 +4308,6 @@
is-typed-array: 1.1.13
dev: true
- /typed-array-byte-length@1.0.0:
- resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
- engines: {node: '>= 0.4'}
- dependencies:
- call-bind: 1.0.2
- for-each: 0.3.3
- has-proto: 1.0.1
- is-typed-array: 1.1.10
- dev: true
-
/typed-array-byte-length@1.0.1:
resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
engines: {node: '>= 0.4'}
@@ -4417,17 +4319,6 @@
is-typed-array: 1.1.13
dev: true
- /typed-array-byte-offset@1.0.0:
- resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
- engines: {node: '>= 0.4'}
- dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- for-each: 0.3.3
- has-proto: 1.0.1
- is-typed-array: 1.1.10
- dev: true
-
/typed-array-byte-offset@1.0.2:
resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
engines: {node: '>= 0.4'}
@@ -4440,14 +4331,6 @@
is-typed-array: 1.1.13
dev: true
- /typed-array-length@1.0.4:
- resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
- dependencies:
- call-bind: 1.0.2
- for-each: 0.3.3
- is-typed-array: 1.1.10
- dev: true
-
/typed-array-length@1.0.5:
resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==}
engines: {node: '>= 0.4'}
@@ -4460,8 +4343,8 @@
possible-typed-array-names: 1.0.0
dev: true
- /typescript@5.4.2:
- resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
+ /typescript@5.4.4:
+ resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
@@ -4469,15 +4352,34 @@
/unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
dependencies:
- call-bind: 1.0.2
+ call-bind: 1.0.7
has-bigints: 1.0.2
has-symbols: 1.0.3
which-boxed-primitive: 1.0.2
dev: true
+ /uncontrollable@7.2.1(react@18.2.0):
+ resolution: {integrity: sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==}
+ peerDependencies:
+ react: '>=15.0.0'
+ dependencies:
+ '@babel/runtime': 7.23.9
+ '@types/react': 18.2.74
+ invariant: 2.2.4
+ react: 18.2.0
+ react-lifecycles-compat: 3.0.4
+ dev: false
+
+ /uncontrollable@8.0.4(react@18.2.0):
+ resolution: {integrity: sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==}
+ peerDependencies:
+ react: '>=16.14.0'
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
- dev: true
/universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
@@ -4501,7 +4403,7 @@
resolution: {integrity: sha512-qY6b94/aGMIHh70EEQ/4hfR2LUGZ+fPQNp64cf7yRX9kAp4XG2tx7LgYUU1Qkh17bFylME0u4n3lOezonougPw==}
dependencies:
qs: 6.12.0
- dev: true
+ dev: false
/use-composed-ref@1.3.0(react@18.2.0):
resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==}
@@ -4511,8 +4413,8 @@
react: 18.2.0
dev: false
- /use-intl@3.9.5(react@18.2.0):
- resolution: {integrity: sha512-1g+f/pKEeXqOXrd+QBvwnIN5kzM56PHsorbVWzNvlnGk2fo/eRwuuT/S0jTuzKLRW4uNybpHvRs6U06rP31iKw==}
+ /use-intl@3.11.1(react@18.2.0):
+ resolution: {integrity: sha512-pFfrQXa3LBHh2MairVFUEXp6BnVcqJno9wbHIEaH0n7ib2kNTMP8jjjuboLHEIphRHygEpbFAjKIr0glUHCytA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
@@ -4520,7 +4422,7 @@
intl-messageformat: 9.13.0
react: 18.2.0
- /use-isomorphic-layout-effect@1.1.2(@types/react@18.2.66)(react@18.2.0):
+ /use-isomorphic-layout-effect@1.1.2(@types/react@18.2.74)(react@18.2.0):
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
peerDependencies:
'@types/react': '*'
@@ -4529,11 +4431,11 @@
'@types/react':
optional: true
dependencies:
- '@types/react': 18.2.66
+ '@types/react': 18.2.74
react: 18.2.0
dev: false
- /use-latest@1.2.1(@types/react@18.2.66)(react@18.2.0):
+ /use-latest@1.2.1(@types/react@18.2.74)(react@18.2.0):
resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==}
peerDependencies:
'@types/react': '*'
@@ -4542,9 +4444,9 @@
'@types/react':
optional: true
dependencies:
- '@types/react': 18.2.66
+ '@types/react': 18.2.74
react: 18.2.0
- use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.66)(react@18.2.0)
+ use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.74)(react@18.2.0)
dev: false
/use-sync-external-store@1.2.0(react@18.2.0):
@@ -4616,8 +4518,8 @@
resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==}
engines: {node: '>= 0.4'}
dependencies:
- function.prototype.name: 1.1.5
- has-tostringtag: 1.0.0
+ function.prototype.name: 1.1.6
+ has-tostringtag: 1.0.2
is-async-function: 2.0.0
is-date-object: 1.0.5
is-finalizationregistry: 1.0.2
@@ -4627,7 +4529,7 @@
isarray: 2.0.5
which-boxed-primitive: 1.0.2
which-collection: 1.0.2
- which-typed-array: 1.1.10
+ which-typed-array: 1.1.15
dev: true
/which-collection@1.0.2:
@@ -4640,18 +4542,6 @@
is-weakset: 2.0.3
dev: true
- /which-typed-array@1.1.10:
- resolution: {integrity: sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==}
- engines: {node: '>= 0.4'}
- dependencies:
- available-typed-arrays: 1.0.5
- call-bind: 1.0.2
- for-each: 0.3.3
- gopd: 1.0.1
- has-tostringtag: 1.0.0
- is-typed-array: 1.1.10
- dev: true
-
/which-typed-array@1.1.15:
resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
engines: {node: '>= 0.4'}
@@ -4671,7 +4561,7 @@
isexe: 2.0.0
dev: true
- /winston-daily-rotate-file@5.0.0(winston@3.12.0):
+ /winston-daily-rotate-file@5.0.0(winston@3.13.0):
resolution: {integrity: sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==}
engines: {node: '>=8'}
peerDependencies:
@@ -4680,7 +4570,7 @@
file-stream-rotator: 0.6.1
object-hash: 3.0.0
triple-beam: 1.4.1
- winston: 3.12.0
+ winston: 3.13.0
winston-transport: 4.7.0
dev: false
@@ -4693,8 +4583,8 @@
triple-beam: 1.4.1
dev: false
- /winston@3.12.0:
- resolution: {integrity: sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==}
+ /winston@3.13.0:
+ resolution: {integrity: sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==}
engines: {node: '>= 12.0.0'}
dependencies:
'@colors/colors': 1.6.0
diff --git a/qwilight-fe/package.json b/qwilight-fe/package.json
index 5a47e64..8691a08 100644
--- a/qwilight-fe/package.json
+++ b/qwilight-fe/package.json
@@ -11,36 +11,38 @@
"stop": "pm2 stop qwilight-fe"
},
"dependencies": {
- "@tanstack/react-query": "^5.28.4",
+ "@tanstack/react-query": "^5.29.0",
"axios": "^1.6.8",
"bootstrap": "^5.3.3",
"chart.js": "^4.4.2",
"crypto-js": "^4.2.0",
- "dompurify": "^3.0.9",
+ "dompurify": "^3.0.11",
"google-protobuf": "^3.21.2",
- "isomorphic-dompurify": "^2.4.0",
- "mobx": "^6.12.0",
- "mobx-react-lite": "^4.0.6",
- "next": "^14.1.3",
- "next-intl": "^3.9.5",
+ "isomorphic-dompurify": "^2.6.0",
+ "mobx": "^6.12.3",
+ "mobx-react-lite": "^4.0.7",
+ "next": "^14.1.4",
+ "next-intl": "^3.11.1",
"react": "^18.2.0",
+ "react-bootstrap": "^2.10.2",
+ "react-bootstrap-icons": "^1.11.3",
"react-contexify": "^6.0.0",
"react-dom": "^18.2.0",
"react-spinners": "^0.13.8",
"react-toastify": "^10.0.5",
- "reactstrap": "^9.2.2",
- "sharp": "^0.33.2",
- "sweetalert2": "^11.10.6",
- "taehui-ts": "workspace:^"
+ "sharp": "^0.33.3",
+ "sweetalert2": "^11.10.7",
+ "taehui-ts": "workspace:^",
+ "urlcat": "^3.1.0"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
"@types/dompurify": "^3.0.5",
"@types/jest": "^29.5.12",
- "@types/node": "^20.11.28",
- "@types/react": "^18.2.66",
- "@types/react-dom": "^18.2.22",
- "eslint-config-next": "^14.1.3",
- "typescript": "^5.4.2"
+ "@types/node": "^20.12.5",
+ "@types/react": "^18.2.74",
+ "@types/react-dom": "^18.2.24",
+ "eslint-config-next": "^14.1.4",
+ "typescript": "^5.4.4"
}
}
diff --git a/qwilight-fe/src/Event_pb.js b/qwilight-fe/src/Event_pb.js
index 281e28b..b577c00 100644
--- a/qwilight-fe/src/Event_pb.js
+++ b/qwilight-fe/src/Event_pb.js
@@ -1034,7 +1034,8 @@
POST_ITEM: 87,
SET_VALID_NET_MODE: 88,
SET_ALLOWED_POSTABLE_ITEMS: 89,
- SET_POSTABLE_ITEM_BAND: 90
+ SET_POSTABLE_ITEM_BAND: 90,
+ ABILITY_CLASS_UP: 91
};
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/\133\133...want\135\135/page.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/\133\133...want\135\135/page.tsx"
index ddb55dc..a0ff728 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/\133\133...want\135\135/page.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/\133\133...want\135\135/page.tsx"
@@ -1,10 +1,12 @@
"use client";
-import AbilitiesView from "@/app/[language]/avatar/components/AbilitiesView";
+import AbilityClassesView from "@/app/[language]/avatar/components/AbilityClassesView";
+import AbilitiesView from "@/app/[language]/avatar/components/AbilityView";
import DateView from "@/app/[language]/avatar/components/DateView";
import FavoritesView from "@/app/[language]/avatar/components/FavoritesView";
import IntroView from "@/app/[language]/avatar/components/IntroView";
import LastsView from "@/app/[language]/avatar/components/LastsView";
+import MainView from "@/app/[language]/avatar/components/MainView";
import QuitStatusValues from "@/app/[language]/avatar/components/QuitStatusValues";
import WwwLevelsView from "@/app/[language]/avatar/components/WwwLevelsView";
import Loading from "@/app/[language]/avatar/loading";
@@ -13,33 +15,31 @@
import AvatarTitle from "@/components/AvatarTitle";
import { useAvatarStore, useSiteStore } from "@/state/Stores";
import { getDefaultAvatarID } from "@/utilities/Utility";
-import { wwwAPIPath } from "@/utilities/wwwAPI";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import Image from "next/image";
-import { useEffect } from "react";
-import {
- Button,
- Col,
- Input,
- ListGroup,
- ListGroupItem,
- Nav,
- NavItem,
- NavLink,
- Progress,
- Row,
- TabContent,
- TabPane,
-} from "reactstrap";
-import { useWant } from "taehui-ts/fe-utilities";
+import Link from "next/link";
+import { useParams, useRouter } from "next/navigation";
+import { useEffect, useMemo } from "react";
+import { EraserFill, Search } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Col from "react-bootstrap/Col";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
export default observer(() => {
- const { textInput, setTextInput, tabPosition, setTabPosition } =
- useAvatarStore();
- const { siteAvatarID, isLoggedIn, setLogInOpened } = useSiteStore();
+ const { textInput, setTextInput, tabItem, setTabItem } = useAvatarStore();
+ const { siteAvatarID, isLoggedIn } = useSiteStore();
- const { want, setWant } = useWant("/avatar");
+ let { want: [want] = [""] } = useParams<{ want: string[] }>();
+ want = useMemo(() => decodeURIComponent(want), [want]);
+
+ const { push } = useRouter();
const t = useTranslations();
@@ -50,35 +50,22 @@
const { isFetched: isAvatarLoaded, data: avatar } = useGetAvatar();
const onWant = () => {
- setWant(textInput);
+ push(`/avatar/${textInput}`);
};
- const getProperties = (i: number) => ({
- className: tabPosition === i ? "active route" : "route",
- onClick: () => {
- setTabPosition(i);
- },
- });
-
return (
<>
-
-
+
+
-
-
- {
@@ -91,202 +78,106 @@
}}
placeholder={t("wantAvatarAssist")}
/>
-
-
-
- {want && !isAvatarLoaded && }
- {isAvatarLoaded &&
- (Array.isArray(avatar) ? (
-
- {avatar.map(({ avatarID, avatarName, avatarIntro }) => {
- return (
- {
- setWant(`!${avatarID}`);
- }}
- >
-
-
-
-
-
-
-
- {avatarName} ({avatarID})
-
-
- {avatarIntro}
-
-
-
- );
- })}
-
- ) : (
- <>
-
-
-
-
-
-
-
- {avatar.avatarName} ({avatar.avatarID})
-
-
-
- {t("totalCountText", { totalCount: avatar.totalCount })}
-
-
- {avatar.totalLength}
-
- {t("topCountText", { topCount: avatar.topCount })}
-
- {t("avatarDate", { date: 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
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- ))}
+
+ {want && !isAvatarLoaded && }
+ {isAvatarLoaded &&
+ (Array.isArray(avatar) ? (
+ avatar.length > 0 && (
+ <>
+
+
+ {avatar.map(({ avatarID, avatarName, avatarIntro }) => (
+
+
+
+
+
+
+
+
+ {avatarIntro}
+
+
+
+
+ ))}
+
+ >
+ )
+ ) : (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ if (eventKey) {
+ setTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ ))}
+
>
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/AbilitiesView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/AbilitiesView.tsx"
deleted file mode 100644
index e2a96b7..0000000
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/AbilitiesView.tsx"
+++ /dev/null
@@ -1,86 +0,0 @@
-import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
-import useGetAvatarAbility from "@/app/[language]/avatar/query/useGetAvatarAbility";
-import NoteItem from "@/app/[language]/note/components/NoteItem";
-
-import { useAvatarStore } from "@/state/Stores";
-import { getAbilityInputMode } from "@/utilities/Utility";
-import { observer } from "mobx-react-lite";
-import { useCallback } from "react";
-import {
- ListGroup,
- Nav,
- NavItem,
- NavLink,
- TabContent,
- TabPane,
-} from "reactstrap";
-
-export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => {
- const { abilitiesTabPosition, tabPosition, setAbilitiesTabPosition } =
- useAvatarStore();
-
- const getProperties = (i: number) => ({
- className: abilitiesTabPosition === i ? "active route" : "route",
- onClick: () => {
- setAbilitiesTabPosition(i);
- },
- });
-
- const { isFetched: isAvatarAbilityLoaded, data: avatarAbility } =
- useGetAvatarAbility(
- getAbilityInputMode(abilitiesTabPosition),
- tabPosition === 2 ? avatarID : undefined,
- );
-
- const AbilityView = useCallback(
- ({ tabPosition }: { tabPosition: number }) => {
- return (
-
-
- {isAvatarAbilityLoaded
- ? avatarAbility.map((avatarAbility) => (
-
- ))
- : [...Array(50).keys()].map((i) => (
-
- ))}
-
-
- );
- },
- [avatarID, avatarAbility, isAvatarAbilityLoaded],
- );
-
- return (
- <>
-
-
-
-
-
-
- >
- );
-});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/AbilityClassesView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/AbilityClassesView.tsx"
new file mode 100644
index 0000000..ba5297d
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/AbilityClassesView.tsx"
@@ -0,0 +1,41 @@
+import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
+import AvatarPlaceText from "@/components/AvatarPlaceText";
+import { wwwAPIPath } from "@/utilities/wwwAPI";
+import Image from "next/image";
+import Card from "react-bootstrap/Card";
+import CardBody from "react-bootstrap/CardBody";
+import CardFooter from "react-bootstrap/CardFooter";
+import CardHeader from "react-bootstrap/CardHeader";
+
+export default function AbilityClassesView({
+ avatar,
+ inputMode,
+}: {
+ avatar: GetAvatar;
+ inputMode: "5K" | "7K" | "9K";
+}) {
+ const avatarAbility = avatar[`avatarAbility${inputMode}`];
+ const avatarAbilityPlace = avatar[`avatarAbility${inputMode}Place`];
+ const avatarAbilityCount = avatar[`avatarAbility${inputMode}Count`];
+ const avatarAbilityText = avatar[`avatarAbility${inputMode}Text`];
+
+ return (
+
+
+
+
+
+
+
+ {avatarAbilityText} Point
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/AbilityView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/AbilityView.tsx"
new file mode 100644
index 0000000..4c3b9f6
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/AbilityView.tsx"
@@ -0,0 +1,64 @@
+import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
+import useGetAvatarAbility from "@/app/[language]/avatar/query/useGetAvatarAbility";
+import NoteView, {
+ NoteViewLoading,
+} from "@/app/[language]/note/components/NoteView";
+
+import { useAvatarStore } from "@/state/Stores";
+import { observer } from "mobx-react-lite";
+import { useCallback } from "react";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
+
+export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => {
+ const { tabItem, abilityTabItem, setAbilitiesTabItem } = useAvatarStore();
+
+ const { isFetched: isAvatarAbilityLoaded, data: avatarAbility } =
+ useGetAvatarAbility(
+ abilityTabItem,
+ tabItem === "abilities" ? avatarID : undefined,
+ );
+
+ const NotesView = useCallback(() => {
+ return (
+
+ {isAvatarAbilityLoaded
+ ? avatarAbility.map((avatarAbility) => (
+
+
+
+ ))
+ : [...Array(50).keys()].map((i) => (
+
+
+
+ ))}
+
+ );
+ }, [avatarAbility, avatarID, isAvatarAbilityLoaded]);
+
+ return (
+ <>
+ {
+ if (eventKey) {
+ setAbilitiesTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/AvatarView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/AvatarView.tsx"
new file mode 100644
index 0000000..d884765
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/AvatarView.tsx"
@@ -0,0 +1,26 @@
+import AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarTitle from "@/components/AvatarTitle";
+import { AvatarAPIWantAvatar } from "@/type/wwwAPI";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+
+export default function AvatarView({
+ avatar: { avatarID, avatarName, avatarIntro },
+}: {
+ avatar: AvatarAPIWantAvatar;
+}) {
+ return (
+
+
+
+
+
+
+
+ {avatarIntro}
+
+
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/DateView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/DateView.tsx"
index 62741f2..907db9e 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/DateView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/DateView.tsx"
@@ -8,7 +8,9 @@
} from "chart.js";
import { useTranslations } from "next-intl";
import { useEffect, useRef } from "react";
-import { Badge, ListGroup, ListGroupItem } from "reactstrap";
+import Card from "react-bootstrap/Card";
+import CardBody from "react-bootstrap/CardBody";
+import CardHeader from "react-bootstrap/CardHeader";
export default function DateView({
avatar: { dateSet, dateValues },
@@ -55,11 +57,11 @@
}, [dateSet, dateValues]);
return (
-
- {t("avatarDateText")}
-
+
+ {t("avatarDateText")}
+
-
-
+
+
);
}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/FavoritesView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/FavoritesView.tsx"
index f224b4d..2be4648 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/FavoritesView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/FavoritesView.tsx"
@@ -1,106 +1,79 @@
import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
import useGetAvatarFavorites from "@/app/[language]/avatar/query/useGetAvatarFavorites";
-import NoteItem from "@/app/[language]/note/components/NoteItem";
+import NoteView, {
+ NoteViewLoading,
+} from "@/app/[language]/note/components/NoteView";
import { useAvatarStore } from "@/state/Stores";
-import { getInputMode } from "@/utilities/Utility";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
-import {
- ListGroup,
- Nav,
- NavItem,
- NavLink,
- TabContent,
- TabPane,
-} from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => {
- const { tabPosition, favoritesTabPosition, setFavoritesTabPosition } =
- useAvatarStore();
+ const { tabItem, favoritesTabItem, setFavoritesTabItem } = useAvatarStore();
const { isFetched: isAvatarFavoritesLoaded, data: avatarFavorites } =
useGetAvatarFavorites(
- getInputMode(favoritesTabPosition),
- tabPosition === 0 ? avatarID : undefined,
+ favoritesTabItem,
+ tabItem === "favorites" ? avatarID : undefined,
);
- const getProperties = (i: number) => ({
- className: favoritesTabPosition === i ? "active route" : "route",
- onClick: () => {
- setFavoritesTabPosition(i);
- },
- });
-
- const FavoriteView = useCallback(
- ({ tabPosition }: { tabPosition: number }) => {
- return (
-
-
- {isAvatarFavoritesLoaded
- ? avatarFavorites.map((avatarFavorite) => (
-
- ))
- : [...Array(50).keys()].map((i) => (
-
- ))}
-
-
- );
- },
- [avatarFavorites, avatarID, isAvatarFavoritesLoaded],
- );
+ const NotesView = useCallback(() => {
+ return (
+
+ {isAvatarFavoritesLoaded
+ ? avatarFavorites.map((avatarFavorite) => (
+
+
+
+ ))
+ : [...Array(50).keys()].map((i) => (
+
+
+
+ ))}
+
+ );
+ }, [avatarFavorites, avatarID, isAvatarFavoritesLoaded]);
return (
<>
-
-
-
-
-
-
-
-
-
-
-
+ {
+ if (eventKey) {
+ setFavoritesTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/IntroView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/IntroView.tsx"
index f31cca3..2b4a266 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/IntroView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/IntroView.tsx"
@@ -1,6 +1,8 @@
import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
import { useTranslations } from "next-intl";
-import { Badge, ListGroup, ListGroupItem } from "reactstrap";
+import Card from "react-bootstrap/Card";
+import CardBody from "react-bootstrap/CardBody";
+import CardHeader from "react-bootstrap/CardHeader";
export default function IntroView({
avatar: { avatarIntro },
@@ -14,11 +16,11 @@
}
return (
-
- {t("avatarIntroText")}
-
- {avatarIntro}
-
-
+
+ {t("avatarIntroText")}
+
+ {avatarIntro}
+
+
);
}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/LastsView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/LastsView.tsx"
index 87cd371..313445d 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/LastsView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/LastsView.tsx"
@@ -1,106 +1,76 @@
import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
import useGetAvatarLasts from "@/app/[language]/avatar/query/useGetAvatarLasts";
-import NoteItem from "@/app/[language]/note/components/NoteItem";
+import NoteView, {
+ NoteViewLoading,
+} from "@/app/[language]/note/components/NoteView";
import { useAvatarStore } from "@/state/Stores";
-import { getInputMode } from "@/utilities/Utility";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
-import {
- ListGroup,
- Nav,
- NavItem,
- NavLink,
- TabContent,
- TabPane,
-} from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => {
- const { tabPosition, lastsTabPosition, setLastsTabPosition } =
- useAvatarStore();
+ const { tabItem, lastsTabItem, setLastsTabItem } = useAvatarStore();
const { isFetched: isAvatarLastsLoaded, data: avatarLasts } =
- useGetAvatarLasts(
- getInputMode(lastsTabPosition),
- tabPosition === 1 ? avatarID : undefined,
+ useGetAvatarLasts(lastsTabItem, tabItem === "lasts" ? avatarID : undefined);
+
+ const NotesView = useCallback(() => {
+ return (
+
+ {isAvatarLastsLoaded
+ ? avatarLasts.map((avatarLast) => (
+
+
+
+ ))
+ : [...Array(50).keys()].map((i) => (
+
+
+
+ ))}
+
);
-
- const getProperties = (i: number) => ({
- className: lastsTabPosition === i ? "active route" : "route",
- onClick: () => {
- setLastsTabPosition(i);
- },
- });
-
- const LastView = useCallback(
- ({ tabPosition }: { tabPosition: number }) => {
- return (
-
-
- {isAvatarLastsLoaded
- ? avatarLasts.map((avatarLast) => (
-
- ))
- : [...Array(50).keys()].map((i) => (
-
- ))}
-
-
- );
- },
- [avatarID, avatarLasts, isAvatarLastsLoaded],
- );
+ }, [avatarID, avatarLasts, isAvatarLastsLoaded]);
return (
<>
-
-
-
-
-
-
-
-
-
-
-
+ {
+ if (eventKey) {
+ setLastsTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
>
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/MainView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/MainView.tsx"
new file mode 100644
index 0000000..e2603e3
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/MainView.tsx"
@@ -0,0 +1,46 @@
+import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
+import AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarTitle from "@/components/AvatarTitle";
+import { useTranslations } from "next-intl";
+import Card from "react-bootstrap/Card";
+import CardBody from "react-bootstrap/CardBody";
+import CardFooter from "react-bootstrap/CardFooter";
+import CardHeader from "react-bootstrap/CardHeader";
+import ProgressBar from "react-bootstrap/ProgressBar";
+import Stack from "react-bootstrap/Stack";
+
+export default function MainView({ avatar }: { avatar: GetAvatar }) {
+ const t = useTranslations();
+
+ return (
+
+
+
+
+
+
+
+ {avatar.avatarName} ({avatar.avatarID})
+
+ LV. {avatar.avatarLevels[0]}
+
+
+
+
+
+
+
+ {t("totalCountText", {
+ totalCount: avatar.totalCount,
+ })}
+
+ {t("topCountText", { topCount: avatar.topCount })}
+ {avatar.totalLength}
+
+
+ {t("avatarDate", { date: avatar.date })}
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/QuitStatusValues.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/QuitStatusValues.tsx"
index 38f663a..9cd5162 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/QuitStatusValues.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/QuitStatusValues.tsx"
@@ -1,8 +1,11 @@
import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
import { useTranslations } from "next-intl";
-import { Badge, ListGroup, ListGroupItem } from "reactstrap";
+import Card from "react-bootstrap/Card";
+import CardHeader from "react-bootstrap/CardHeader";
+import CardBody from "react-bootstrap/CardBody";
+import CardText from "react-bootstrap/CardText";
-const quitItems = ["S+", "S", "A+", "A", "B", "C", "D"] as const;
+const quitStatusItems = ["S+", "S", "A+", "A", "B", "C", "D"] as const;
export default function QuitStatusValues({
avatar: { quitStatusValues },
@@ -12,14 +15,16 @@
const t = useTranslations();
return (
-
- {t("avatarQuitStatusText")}
- {quitItems.map((quitItem) => (
-
- {quitItem}{" "}
- {quitStatusValues[quitItems.indexOf(quitItem)]}
-
- ))}
-
+
+ {t("avatarQuitStatusText")}
+
+ {quitStatusItems.map((quitItem) => (
+
+ {quitItem}
+ {quitStatusValues[quitStatusItems.indexOf(quitItem)]}
+
+ ))}
+
+
);
}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelItem.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelItem.tsx"
deleted file mode 100644
index 4dc58c3..0000000
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelItem.tsx"
+++ /dev/null
@@ -1,20 +0,0 @@
-import { GetAvatarWwwLevelsAPI } from "@/type/wwwAPI";
-import { toDate } from "@/utilities/Utility";
-import { Col, ListGroupItem, Row } from "reactstrap";
-
-export default function WwwLevelItem({
- title,
- date,
-}: GetAvatarWwwLevelsAPI[number]) {
- return (
-
-
-
- {title}
-
- {date && {toDate(date)}}
-
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelView.tsx"
new file mode 100644
index 0000000..c9c3c0b
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelView.tsx"
@@ -0,0 +1,37 @@
+import LevelText from "@/components/LevelText";
+import { GetAvatarWwwLevelsAPI } from "@/type/wwwAPI";
+import { Placeholder } from "react-bootstrap";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import { getDatetime } from "taehui-ts/date";
+
+export default function WwwLevelView({
+ title,
+ levelText,
+ level,
+ date,
+}: GetAvatarWwwLevelsAPI[number]) {
+ return (
+
+
+
+
+ {title}
+
+
+
+ {getDatetime(date)}
+
+
+ );
+}
+
+export const WwwLevelViewLoading = () => {
+ return (
+
+
+
+
+ );
+};
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelsView.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelsView.tsx"
index 8e5f42e..0be7f0b 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelsView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/components/WwwLevelsView.tsx"
@@ -1,37 +1,31 @@
-import WwwLevelItem from "@/app/[language]/avatar/components/WwwLevelItem";
+import WwwLevelView, {
+ WwwLevelViewLoading,
+} from "@/app/[language]/avatar/components/WwwLevelView";
import { GetAvatar } from "@/app/[language]/avatar/query/useGetAvatar";
import useGetAvatarWwwLevels from "@/app/[language]/avatar/query/useGetAvatarWwwLevels";
import { useAvatarStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
-import { ListGroup } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
export default observer(({ avatar: { avatarID } }: { avatar: GetAvatar }) => {
- const { tabPosition } = useAvatarStore();
+ const { tabItem } = useAvatarStore();
- const { isFetched: isAvatarWwwLevelsLoaded, data: avatarWwwLevels } =
- useGetAvatarWwwLevels(tabPosition === 3 ? avatarID : undefined);
+ const { isFetched: isWwwLevelsLoaded, data: wwwLevels } =
+ useGetAvatarWwwLevels(tabItem === "wwwLevels" ? avatarID : undefined);
return (
- {isAvatarWwwLevelsLoaded ? (
- avatarWwwLevels.map(({ levelID, title, levelText, level, date }) => (
-
+ {isWwwLevelsLoaded ? (
+ wwwLevels.map((wwwLevel) => (
+
+
+
))
) : (
-
+
+
+
)}
);
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/loading.tsx" "b/qwilight-fe/src/app/\133language\135/avatar/loading.tsx"
index 8889c7a..10e0631 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/loading.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/loading.tsx"
@@ -1,8 +1,5 @@
-import LoadingLayer from "@/components/LoadingLayer";
-import { useTranslations } from "next-intl";
+import DefaultLoading from "@/components/DefaultLoading";
export default function Loading() {
- const t = useTranslations();
-
- return ;
+ return ;
}
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatar.ts" "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatar.ts"
index 761933d..3014eba 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatar.ts"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatar.ts"
@@ -1,10 +1,12 @@
import { AvatarAPIAvatar, AvatarAPIWantAvatar } from "@/type/wwwAPI";
-import { formatText, toDate } from "@/utilities/Utility";
-
+import { formatText } from "@/utilities/Utility";
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
-import { useIsPath, useWant } from "taehui-ts/fe-utilities";
+import { useParams } from "next/navigation";
+import { useMemo } from "react";
+import { getDatetime } from "taehui-ts/date";
+import { useIsPath } from "taehui-ts/fe-utilities";
export type GetAvatar = {
avatarID: string;
@@ -15,28 +17,26 @@
topCount: string;
date: string;
avatarLevels: number[];
+ avatarAbility5K: number;
avatarAbility5KText: string;
- avatarAbility5KClass: number;
avatarAbility5KPlace: number;
- avatarAbility5KPlaceText: string;
- avatarAbility5KCountText: string;
+ avatarAbility5KCount: number;
+ avatarAbility7K: number;
avatarAbility7KText: string;
- avatarAbility7KClass: number;
avatarAbility7KPlace: number;
- avatarAbility7KPlaceText: string;
- avatarAbility7KCountText: string;
+ avatarAbility7KCount: number;
+ avatarAbility9K: number;
avatarAbility9KText: string;
- avatarAbility9KClass: number;
avatarAbility9KPlace: number;
- avatarAbility9KPlaceText: string;
- avatarAbility9KCountText: string;
+ avatarAbility9KCount: number;
dateSet: number[];
dateValues: number[];
quitStatusValues: number[];
};
export default function useGetAvatar() {
- const { want } = useWant("/avatar");
+ let { want: [want] = [""] } = useParams<{ want: string[] }>();
+ want = useMemo(() => decodeURIComponent(want), [want]);
const t = useTranslations();
@@ -49,15 +49,13 @@
const { data } = await wwwAPI.get<
AvatarAPIWantAvatar[] | AvatarAPIAvatar
>("/avatar", {
- params: want.startsWith("!")
- ? {
- avatarID: want.substring(want.indexOf("!") + 1),
- }
- : {
- avatarName: want,
- },
+ params: { want },
});
+ if (!data) {
+ return [];
+ }
+
if (Array.isArray(data)) {
return data;
} else {
@@ -70,16 +68,16 @@
s: Math.floor((data.totalLength / 1000) % 60),
}),
topCount: formatText(data.topCount),
- date: toDate(data.date),
+ date: getDatetime(data.date),
+ avatarAbility5K: data.avatarAbility5K,
avatarAbility5KText: formatText(data.avatarAbility5K),
- avatarAbility5KPlaceText: formatText(data.avatarAbility5KPlace),
- avatarAbility5KCountText: formatText(data.avatarAbility5KCount),
+ avatarAbility5KCount: data.avatarAbility5KCount,
+ avatarAbility7K: data.avatarAbility7K,
avatarAbility7KText: formatText(data.avatarAbility7K),
- avatarAbility7KPlaceText: formatText(data.avatarAbility7KPlace),
- avatarAbility7KCountText: formatText(data.avatarAbility7KCount),
+ avatarAbility7KCount: data.avatarAbility7KCount,
+ avatarAbility9K: data.avatarAbility9K,
avatarAbility9KText: formatText(data.avatarAbility9K),
- avatarAbility9KPlaceText: formatText(data.avatarAbility9KPlace),
- avatarAbility9KCountText: formatText(data.avatarAbility9KCount),
+ avatarAbility9KCount: data.avatarAbility9KCount,
};
}
},
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarAbility.ts" "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarAbility.ts"
index e18e6ab..e9e043f 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarAbility.ts"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarAbility.ts"
@@ -7,7 +7,7 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAvatarAbility(
- inputMode: "5K" | "7K" | "9K",
+ abilitiesTabItem: string,
avatarID?: string,
) {
const t = useTranslations();
@@ -16,10 +16,10 @@
return useQuery({
enabled: !!avatarID && isPath("/avatar"),
- queryKey: ["avatarAbility", inputMode, avatarID],
+ queryKey: ["avatarAbility", abilitiesTabItem, avatarID],
queryFn: async () => {
const { data } = await wwwAPI.get(
- `/avatar/ability/${inputMode}`,
+ `/avatar/ability/${abilitiesTabItem}`,
{
params: { avatarID },
},
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarFavorites.ts" "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarFavorites.ts"
index 04ed68c..a5f09c4 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarFavorites.ts"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarFavorites.ts"
@@ -1,5 +1,4 @@
import { GetAvatarFavoritesAPI } from "@/type/wwwAPI";
-import { formatText } from "@/utilities/Utility";
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
@@ -7,7 +6,7 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAvatarFavorites(
- inputMode: "6K" | "5K" | "7K" | "9K" | "10K" | "14K" | "24K" | "48K",
+ favoritesTabItem: string,
avatarID?: string,
) {
const isPath = useIsPath();
@@ -16,18 +15,15 @@
return useQuery({
enabled: !!avatarID && isPath("/avatar"),
- queryKey: ["avatarFavorites", inputMode, avatarID],
+ queryKey: ["avatarFavorites", favoritesTabItem, avatarID],
queryFn: async () => {
const { data } = await wwwAPI.get(
- `/avatar/favorites/${inputMode}`,
+ `/avatar/favorites/${favoritesTabItem}`,
{
params: { avatarID },
},
);
- return data.map((data) => ({
- ...data,
- fittedText: t("textHandled", { value: formatText(data.totalCount) }),
- }));
+ return data;
},
initialData: [],
});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarLasts.ts" "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarLasts.ts"
index 73f118c..dfb0ccc 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarLasts.ts"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/query/useGetAvatarLasts.ts"
@@ -1,27 +1,29 @@
import { GetAvatarLastsAPI } from "@/type/wwwAPI";
-import { toDate } from "@/utilities/Utility";
-
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
+import { getDatetime } from "taehui-ts/date";
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAvatarLasts(
- inputMode: "6K" | "5K" | "7K" | "9K" | "10K" | "14K" | "24K" | "48K",
+ lastsTabItem: string,
avatarID?: string,
) {
const isPath = useIsPath();
return useQuery({
enabled: !!avatarID && isPath("/avatar"),
- queryKey: ["avatarLasts", inputMode, avatarID],
+ queryKey: ["avatarLasts", lastsTabItem, avatarID],
queryFn: async () => {
const { data } = await wwwAPI.get(
- `/avatar/lasts/${inputMode}`,
+ `/avatar/lasts/${lastsTabItem}`,
{
params: { avatarID },
},
);
- return data.map((data) => ({ ...data, fittedText: toDate(data.date) }));
+ return data.map((data) => ({
+ ...data,
+ fittedText: getDatetime(data.date),
+ }));
},
initialData: [],
});
diff --git "a/qwilight-fe/src/app/\133language\135/avatar/state/setAvatarStore.ts" "b/qwilight-fe/src/app/\133language\135/avatar/state/setAvatarStore.ts"
index 4ec663c..e3cf94d 100644
--- "a/qwilight-fe/src/app/\133language\135/avatar/state/setAvatarStore.ts"
+++ "b/qwilight-fe/src/app/\133language\135/avatar/state/setAvatarStore.ts"
@@ -1,29 +1,29 @@
export default function setAvatarStore() {
return {
textInput: "",
- tabPosition: 0,
- favoritesTabPosition: 0,
- lastsTabPosition: 0,
- abilitiesTabPosition: 0,
+ tabItem: "favorites",
+ favoritesTabItem: "6K",
+ lastsTabItem: "6K",
+ abilityTabItem: "5K",
- setTextInput(input: string) {
- this.textInput = input;
+ setTextInput(textInput: string) {
+ this.textInput = textInput;
},
- setTabPosition(tabPosition: number) {
- this.tabPosition = tabPosition;
+ setTabItem(tabItem: string) {
+ this.tabItem = tabItem;
},
- setFavoritesTabPosition(favoritesTabPosition: number) {
- this.favoritesTabPosition = favoritesTabPosition;
+ setFavoritesTabItem(favoritesTabItem: string) {
+ this.favoritesTabItem = favoritesTabItem;
},
- setLastsTabPosition(lastsTabPosition: number) {
- this.lastsTabPosition = lastsTabPosition;
+ setLastsTabItem(lastsTabItem: string) {
+ this.lastsTabItem = lastsTabItem;
},
- setAbilitiesTabPosition(abilitiesTabPosition: number) {
- this.abilitiesTabPosition = abilitiesTabPosition;
+ setAbilitiesTabItem(abilitiesTabItem: string) {
+ this.abilityTabItem = abilitiesTabItem;
},
};
}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/DateView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/DateView.tsx"
index e5fd885..20204b0 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/DateView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/DateView.tsx"
@@ -8,7 +8,9 @@
} from "chart.js";
import { observer } from "mobx-react-lite";
import { useEffect, useRef } from "react";
-import { Badge, ListGroup, ListGroupItem } from "reactstrap";
+import Card from "react-bootstrap/Card";
+import CardBody from "react-bootstrap/CardBody";
+import CardHeader from "react-bootstrap/CardHeader";
export default observer<{
title: string;
@@ -59,11 +61,11 @@
}, [dateSet, dateValues]);
return (
-
- {title}
-
+
+ {title}
+
-
-
+
+
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/EdgeItem.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/EdgeItem.tsx"
index b73b0ca..802ad55 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/EdgeItem.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/EdgeItem.tsx"
@@ -1,5 +1,6 @@
import Image from "next/image";
-import { Col, ListGroupItem, Row } from "reactstrap";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
export default function EdgeItem({
edge,
@@ -9,20 +10,16 @@
text: string;
}) {
return (
-
-
-
-
-
-
- {text}
-
-
-
+
+
+
+
+ {text}
+
);
}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/FavoritesView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/FavoritesView.tsx"
index 231c221..46983bd 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/FavoritesView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/FavoritesView.tsx"
@@ -1,31 +1,35 @@
-import NoteItem from "@/app/[language]/note/components/NoteItem";
+import NoteView from "@/app/[language]/note/components/NoteView";
+import { useSiteStore } from "@/state/Stores";
import { EtcAPINoteFile } from "@/type/wwwAPI";
-import { Badge, ListGroup } from "reactstrap";
+import { observer } from "mobx-react-lite";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
-export default function FavoritesView({
- title,
- favorites,
-}: {
+export default observer<{
title: string;
favorites: EtcAPINoteFile[];
-}) {
+}>(({ title, favorites }) => {
+ const { siteAvatarID } = useSiteStore();
+
return (
- {title}
+ {title}
{favorites.map(
({ noteID, artist, title, genre, levelText, level, value }) => (
-
+
+
+
),
)}
);
-}
+});
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/ModeItem.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/ModeItem.tsx"
deleted file mode 100644
index 8bc77d3..0000000
--- "a/qwilight-fe/src/app/\133language\135/etc/components/ModeItem.tsx"
+++ /dev/null
@@ -1,39 +0,0 @@
-import { EtcAPIMode } from "@/type/wwwAPI";
-import { formatText } from "@/utilities/Utility";
-import { useTranslations } from "next-intl";
-import Image, { StaticImageData } from "next/image";
-import { Badge, Col, ListGroup, ListGroupItem, Row } from "reactstrap";
-
-export default function ModeItem({
- title,
- modes,
- drawings,
-}: {
- title: string;
- modes: EtcAPIMode[];
- drawings: (string | StaticImageData)[];
-}) {
- const t = useTranslations();
-
- return (
-
- {title}
- {modes.map(({ mode, value }) => {
- return (
- value > 0 && (
-
-
-
-
-
-
- {t("textHandled", { value: formatText(value) })}
-
-
-
- )
- );
- })}
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/ModesView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/ModesView.tsx"
new file mode 100644
index 0000000..54a28c1
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/ModesView.tsx"
@@ -0,0 +1,42 @@
+import { EtcAPIMode } from "@/type/wwwAPI";
+import { formatText } from "@/utilities/Utility";
+import { useTranslations } from "next-intl";
+import Image, { StaticImageData } from "next/image";
+import Col from "react-bootstrap/Col";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Row from "react-bootstrap/Row";
+
+export default function ModesView({
+ title,
+ modes,
+ drawings,
+}: {
+ title: string;
+ modes: EtcAPIMode[];
+ drawings: (string | StaticImageData)[];
+}) {
+ const t = useTranslations();
+
+ return (
+
+ {title}
+ {modes.map(({ mode, value }) => {
+ return (
+ value > 0 && (
+
+
+
+
+
+
+ {t("textHandled", { value: formatText(value) })}
+
+
+
+ )
+ );
+ })}
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/TitleItem.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/TitleItem.tsx"
index db5d68f..01a2172 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/TitleItem.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/TitleItem.tsx"
@@ -1,5 +1,5 @@
import Title from "@/components/Title";
-import { Col, ListGroupItem, Row } from "reactstrap";
+import Stack from "react-bootstrap/Stack";
export default function TitleItem({
title,
@@ -11,14 +11,9 @@
text: string;
}) {
return (
-
-
-
-
-
- {text}
-
-
-
+
+
+ {text}
+
);
}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/TotalEdgesView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/TotalEdgesView.tsx"
index 738aecd..98d5ca9 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/TotalEdgesView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/TotalEdgesView.tsx"
@@ -1,7 +1,8 @@
import EdgeItem from "@/app/[language]/etc/components/EdgeItem";
import { EtcAPIEdge } from "@/type/wwwAPI";
import { useTranslations } from "next-intl";
-import { Badge, ListGroup } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
export default function TotalEdgesView({
totalEdges,
@@ -12,13 +13,14 @@
return (
- {t("etcTotalEdges")}
+ {t("etcTotalEdges")}
{totalEdges.map(({ edge, value }) => (
-
+
+
+
))}
);
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/TotalNoteFilesView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/TotalNoteFilesView.tsx"
index 96f3e96..5725641 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/TotalNoteFilesView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/TotalNoteFilesView.tsx"
@@ -1,32 +1,37 @@
-import NoteItem from "@/app/[language]/note/components/NoteItem";
+import NoteView from "@/app/[language]/note/components/NoteView";
+import { useSiteStore } from "@/state/Stores";
import { EtcAPINoteFile } from "@/type/wwwAPI";
+import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { Badge, ListGroup } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
-export default function TotalNoteFilesView({
- totalNoteFiles,
-}: {
+export default observer<{
totalNoteFiles: EtcAPINoteFile[];
-}) {
+}>(({ totalNoteFiles }) => {
+ const { siteAvatarID } = useSiteStore();
+
const t = useTranslations();
return (
- {t("etcTotalNoteFiles")}
+ {t("etcTotalNoteFiles")}
{totalNoteFiles.map(
({ noteID, artist, title, genre, levelText, level, value }) => (
-
+
+
+
),
)}
);
-}
+});
diff --git "a/qwilight-fe/src/app/\133language\135/etc/components/TotalTitlesView.tsx" "b/qwilight-fe/src/app/\133language\135/etc/components/TotalTitlesView.tsx"
index cfe541a..2ed6a2a 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/components/TotalTitlesView.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/components/TotalTitlesView.tsx"
@@ -1,7 +1,8 @@
import TitleItem from "@/app/[language]/etc/components/TitleItem";
import { EtcAPITitle } from "@/type/wwwAPI";
import { useTranslations } from "next-intl";
-import { Badge, ListGroup } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
export default function TotalTitlesView({
totalTitles,
@@ -12,14 +13,15 @@
return (
- {t("etcTotalTitles")}
+ {t("etcTotalTitles")}
{totalTitles.map(({ title, titleColor, value }) => (
-
+
+
+
))}
);
diff --git "a/qwilight-fe/src/app/\133language\135/etc/loading.tsx" "b/qwilight-fe/src/app/\133language\135/etc/loading.tsx"
index d6f4948..10e0631 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/loading.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/loading.tsx"
@@ -1,8 +1,5 @@
-import LoadingLayer from "@/components/LoadingLayer";
-import { useTranslations } from "next-intl";
+import DefaultLoading from "@/components/DefaultLoading";
export default function Loading() {
- const t = useTranslations();
-
- return ;
+ return ;
}
diff --git "a/qwilight-fe/src/app/\133language\135/etc/page.tsx" "b/qwilight-fe/src/app/\133language\135/etc/page.tsx"
index 9ce5769..2797c19 100644
--- "a/qwilight-fe/src/app/\133language\135/etc/page.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/etc/page.tsx"
@@ -2,7 +2,7 @@
import DateView from "@/app/[language]/etc/components/DateView";
import FavoritesView from "@/app/[language]/etc/components/FavoritesView";
-import ModeItem from "@/app/[language]/etc/components/ModeItem";
+import ModesView from "@/app/[language]/etc/components/ModesView";
import TotalEdgesView from "@/app/[language]/etc/components/TotalEdgesView";
import TotalNoteFilesView from "@/app/[language]/etc/components/TotalNoteFilesView";
import TotalTitlesView from "@/app/[language]/etc/components/TotalTitlesView";
@@ -22,7 +22,8 @@
m8s,
} from "@/utilities/Utility";
import { useTranslations } from "next-intl";
-import { Col, Row } from "reactstrap";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
export default function Page() {
const t = useTranslations();
@@ -31,8 +32,8 @@
data: {
totalDateSet,
totalDateValues,
- signUpDateSet,
- signUpDateValues,
+ enrollDateSet,
+ enrollDateValues,
avatarDateSet,
avatarDateValues,
totalNoteFiles,
@@ -61,117 +62,115 @@
return (
<>
-
-
+
+
-
+
-
+
-
-
-
+
-
+
-
+
-
-
-
+
-
+
-
-
-
-
+
-
-
+
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+
-
-
+ {
- to(`/avatar/!${avatarID}`);
- }
- }
- >
-
-
-
-
-
- {avatarID && }
- {avatarName}
-
- {text}
-
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/components/AvatarView.tsx" "b/qwilight-fe/src/app/\133language\135/hall/components/AvatarView.tsx"
new file mode 100644
index 0000000..c35deb7
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/hall/components/AvatarView.tsx"
@@ -0,0 +1,55 @@
+import { Hall } from "@/app/[language]/hall/type";
+import AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarPlaceText from "@/components/AvatarPlaceText";
+import AvatarTitle from "@/components/AvatarTitle";
+import Link from "next/link";
+import { ReactNode } from "react";
+import { Placeholder, PlaceholderButton } from "react-bootstrap";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+
+export default function AvatarView({
+ avatarID,
+ avatarName,
+ text,
+ avatarPlace,
+ children,
+}: Hall & { avatarPlace: number; children?: ReactNode }) {
+ return (
+
+
+
+
+ {children && {children}}
+
+
+
+
+
+
+ {text}
+
+
+
+ );
+}
+
+export function AvatarViewLoading() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/components/AvatarsView.tsx" "b/qwilight-fe/src/app/\133language\135/hall/components/AvatarsView.tsx"
new file mode 100644
index 0000000..3d1f07f
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/hall/components/AvatarsView.tsx"
@@ -0,0 +1,41 @@
+import AvatarView, {
+ AvatarViewLoading,
+} from "@/app/[language]/hall/components/AvatarView";
+import { Hall } from "@/app/[language]/hall/type";
+import { FC } from "react";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+
+export default function AvatarsView({
+ isLoaded,
+ halls,
+ Component,
+}: {
+ isLoaded: boolean;
+ halls: Hall[];
+ Component?: FC<{ value: number }>;
+}) {
+ return (
+
+ {isLoaded
+ ? halls.map(({ avatarID, avatarName, text, value }, i) => (
+
+
+ {Component && }
+
+
+ ))
+ : [...Array(50).keys()].map((i) => (
+
+
+
+ ))}
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/loading.tsx" "b/qwilight-fe/src/app/\133language\135/hall/loading.tsx"
index 8c40023..10e0631 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/loading.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/hall/loading.tsx"
@@ -1,8 +1,5 @@
-import LoadingLayer from "@/components/LoadingLayer";
-import { useTranslations } from "next-intl";
+import DefaultLoading from "@/components/DefaultLoading";
export default function Loading() {
- const t = useTranslations();
-
- return ;
+ return ;
}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/page.tsx" "b/qwilight-fe/src/app/\133language\135/hall/page.tsx"
index ea0881b..3b8c134 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/page.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/hall/page.tsx"
@@ -1,71 +1,50 @@
"use client";
-import AvatarItem from "@/app/[language]/hall/components/AvatarItem";
+import AvatarsView from "@/app/[language]/hall/components/AvatarsView";
import useGetAbility5KHall from "@/app/[language]/hall/query/useGetAbility5KHall";
import useGetAbility7KHall from "@/app/[language]/hall/query/useGetAbility7KHall";
import useGetAbility9KHall from "@/app/[language]/hall/query/useGetAbility9KHall";
import useGetAtBandHall from "@/app/[language]/hall/query/useGetAtBandHall";
-import useGetAtHighestHall from "@/app/[language]/hall/query/useGetAtHighestHall";
import useGetAtStandHall from "@/app/[language]/hall/query/useGetAtStandHall";
+import useGetAtTopHall from "@/app/[language]/hall/query/useGetAtTopHall";
import useGetAtTotalHall from "@/app/[language]/hall/query/useGetAtTotalHall";
import useGetLevelHall from "@/app/[language]/hall/query/useGetLevelHall";
import useGetTotalBandHall from "@/app/[language]/hall/query/useGetTotalBandHall";
-import useGetTotalHighestHall from "@/app/[language]/hall/query/useGetTotalHighestHall";
import useGetTotalStandHall from "@/app/[language]/hall/query/useGetTotalStandHall";
+import useGetTotalTopHall from "@/app/[language]/hall/query/useGetTotalTopHall";
import useGetTotalTotalHall from "@/app/[language]/hall/query/useGetTotalTotalHall";
-import { Hall } from "@/app/[language]/hall/type";
import { useHallStore } from "@/state/Stores";
+import { wwwAPIPath } from "@/utilities/wwwAPI";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import {
- ListGroup,
- Nav,
- NavItem,
- NavLink,
- TabContent,
- TabPane,
-} from "reactstrap";
-
-const getAvatarItems = (isLoaded: boolean, halls: Hall[]) => {
- return isLoaded
- ? halls.map(({ avatarID, avatarName, text }) => (
-
- ))
- : [...Array(50).keys()].map((i) => (
-
- ));
-};
+import Image from "next/image";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
export default observer(() => {
const {
- tabPosition,
- totalTabPosition,
- atTabPosition,
- abilityTabPosition,
- setTabPosition,
- setTotalTabPosition,
- setAtTabPosition,
- setAbilityTabPosition,
+ tabItem,
+ totalTabItem,
+ atTabItem,
+ abilityTabItem,
+ setTabItem,
+ setTotalTabItem,
+ setAtTabItem,
+ setAbilityTabItem,
} = useHallStore();
const t = useTranslations();
const { data: totalTotalHall, isFetched: isTotalTotalHallLoaded } =
useGetTotalTotalHall();
- const { data: totalHighestHall, isFetched: isTotalHighestHallLoaded } =
- useGetTotalHighestHall();
+ const { data: totalTopHall, isFetched: isTotalTopHallLoaded } =
+ useGetTotalTopHall();
const { data: totalStandHall, isFetched: isTotalStandHallLoaded } =
useGetTotalStandHall();
const { data: totalBandHall, isFetched: isTotalBandHallLoaded } =
useGetTotalBandHall();
const { data: atTotalHall, isFetched: isAtTotalHallLoaded } =
useGetAtTotalHall();
- const { data: atHighestHall, isFetched: isAtHighestHallLoaded } =
- useGetAtHighestHall();
+ const { data: atTopHall, isFetched: isAtTopHallLoaded } = useGetAtTopHall();
const { data: atStandHall, isFetched: isAtStandHallLoaded } =
useGetAtStandHall();
const { data: atBandHall, isFetched: isAtBandHallLoaded } =
@@ -78,161 +57,131 @@
useGetAbility9KHall();
const { data: levelHall, isFetched: isLevelHallLoaded } = useGetLevelHall();
- 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 (
<>
-
-
-
-
-
-
-
- {getAvatarItems(isTotalTotalHallLoaded, totalTotalHall)}
-
-
-
-
- {getAvatarItems(isTotalHighestHallLoaded, totalHighestHall)}
-
-
-
-
- {getAvatarItems(isTotalStandHallLoaded, totalStandHall)}
-
-
-
-
- {getAvatarItems(isTotalBandHallLoaded, totalBandHall)}
-
-
-
-
-
-
-
-
-
- {getAvatarItems(isAtTotalHallLoaded, atTotalHall)}
-
-
-
-
- {getAvatarItems(isAtHighestHallLoaded, atHighestHall)}
-
-
-
-
- {getAvatarItems(isAtStandHallLoaded, atStandHall)}
-
-
-
-
- {getAvatarItems(isAtBandHallLoaded, atBandHall)}
-
-
-
-
-
-
-
-
-
- {getAvatarItems(isAbility5KHallLoaded, ability5KHall)}
-
-
-
-
- {getAvatarItems(isAbility7KHallLoaded, ability7KHall)}
-
-
-
-
- {getAvatarItems(isAbility9KHallLoaded, ability9KHall)}
-
-
-
-
-
- {getAvatarItems(isLevelHallLoaded, levelHall)}
-
-
+ {
+ if (eventKey) {
+ setTabItem(eventKey);
+ }
+ }}
+ >
+
+ {
+ if (eventKey) {
+ setTotalTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ if (eventKey) {
+ setAtTabItem(eventKey);
+ }
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ if (eventKey) {
+ setAbilityTabItem(eventKey);
+ }
+ }}
+ >
+
+ (
+
+ )}
+ />
+
+
+ (
+
+ )}
+ />
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+
>
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility5KHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility5KHall.ts"
index 3fff1d6..ff0631b 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility5KHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility5KHall.ts"
@@ -7,17 +7,19 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAbility5KHall() {
- const { tabPosition, abilityTabPosition } = useHallStore();
+ const { tabItem, abilityTabItem } = useHallStore();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 2 && abilityTabPosition === 0 && isPath("/hall"),
+ enabled:
+ tabItem === "ability" && abilityTabItem === "5K" && isPath("/hall"),
queryKey: ["ability5KHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/ability/5K");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: `${formatText(hall.value)} Point`,
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility7KHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility7KHall.ts"
index 0651dd1..4f62df6 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility7KHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility7KHall.ts"
@@ -7,17 +7,19 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAbility7KHall() {
- const { tabPosition, abilityTabPosition } = useHallStore();
+ const { tabItem, abilityTabItem } = useHallStore();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 2 && abilityTabPosition === 1 && isPath("/hall"),
+ enabled:
+ tabItem === "ability" && abilityTabItem === "7K" && isPath("/hall"),
queryKey: ["ability7KHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/ability/7K");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: `${formatText(hall.value)} Point`,
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility9KHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility9KHall.ts"
index bff7c73..c7c20c3 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility9KHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAbility9KHall.ts"
@@ -7,17 +7,19 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAbility9KHall() {
- const { tabPosition, abilityTabPosition } = useHallStore();
+ const { tabItem, abilityTabItem } = useHallStore();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 2 && abilityTabPosition === 2 && isPath("/hall"),
+ enabled:
+ tabItem === "ability" && abilityTabItem === "9K" && isPath("/hall"),
queryKey: ["ability9KHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/ability/9K");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: `${formatText(hall.value)} Point`,
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtBandHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtBandHall.ts"
index 48e2bd4..fff1012 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtBandHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtBandHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAtBandHall() {
- const { tabPosition, atTabPosition } = useHallStore();
+ const { tabItem, atTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 1 && atTabPosition === 3 && isPath("/hall"),
+ enabled: tabItem === "at" && atTabItem === "band" && isPath("/hall"),
queryKey: ["atBandHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/atBand");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textBand", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtHighestHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtHighestHall.ts"
deleted file mode 100644
index edd1e47..0000000
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtHighestHall.ts"
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Hall } from "@/app/[language]/hall/type";
-import { useHallStore } from "@/state/Stores";
-import { GetHallAPI } from "@/type/wwwAPI";
-import { formatText } from "@/utilities/Utility";
-import { wwwAPI } from "@/utilities/wwwAPI";
-import { useQuery } from "@tanstack/react-query";
-import { useTranslations } from "next-intl";
-import { useIsPath } from "taehui-ts/fe-utilities";
-
-export default function useGetAtHighestHall() {
- const { tabPosition, atTabPosition } = useHallStore();
-
- const t = useTranslations();
-
- const isPath = useIsPath();
-
- return useQuery({
- enabled: tabPosition === 1 && atTabPosition === 1 && isPath("/hall"),
- queryKey: ["atHighestHall"],
- queryFn: async () => {
- const { data } = await wwwAPI.get("/hall/atHighest");
- return data.map((hall) => ({
- ...hall,
- text: t("textCount", { value: formatText(hall.value) }),
- }));
- },
- initialData: [],
- });
-}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtStandHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtStandHall.ts"
index 33a3af4..221e681 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtStandHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtStandHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAtStandHall() {
- const { tabPosition, atTabPosition } = useHallStore();
+ const { tabItem, atTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 1 && atTabPosition === 2 && isPath("/hall"),
+ enabled: tabItem === "at" && atTabItem === "stand" && isPath("/hall"),
queryKey: ["atStandHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/atStand");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textStand", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTopHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTopHall.ts"
new file mode 100644
index 0000000..bd35f39
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTopHall.ts"
@@ -0,0 +1,30 @@
+import { Hall } from "@/app/[language]/hall/type";
+import { useHallStore } from "@/state/Stores";
+import { GetHallAPI } from "@/type/wwwAPI";
+import { formatText } from "@/utilities/Utility";
+import { wwwAPI } from "@/utilities/wwwAPI";
+import { useQuery } from "@tanstack/react-query";
+import { useTranslations } from "next-intl";
+import { useIsPath } from "taehui-ts/fe-utilities";
+
+export default function useGetAtTopHall() {
+ const { tabItem, atTabItem } = useHallStore();
+
+ const t = useTranslations();
+
+ const isPath = useIsPath();
+
+ return useQuery({
+ enabled: tabItem === "at" && atTabItem === "top" && isPath("/hall"),
+ queryKey: ["atTopHall"],
+ queryFn: async () => {
+ const { data } = await wwwAPI.get("/hall/atTop");
+ return data.map((hall) => ({
+ ...hall,
+ value: hall.value,
+ text: t("textCount", { value: formatText(hall.value) }),
+ }));
+ },
+ initialData: [],
+ });
+}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTotalHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTotalHall.ts"
index ccd6472..95ee40c 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTotalHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetAtTotalHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetAtTotalHall() {
- const { tabPosition, atTabPosition } = useHallStore();
+ const { tabItem, atTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 1 && atTabPosition === 0 && isPath("/hall"),
+ enabled: tabItem === "at" && atTabItem === "total" && isPath("/hall"),
queryKey: ["atTotalHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/atTotal");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textHandled", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetLevelHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetLevelHall.ts"
index ac9a366..c328d65 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetLevelHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetLevelHall.ts"
@@ -6,17 +6,18 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetLevelHall() {
- const { tabPosition } = useHallStore();
+ const { tabItem } = useHallStore();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 3 && isPath("/hall"),
+ enabled: tabItem === "level" && isPath("/hall"),
queryKey: ["levelHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/level");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: `LV. ${hall.value}`,
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalBandHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalBandHall.ts"
index df4dd60..56058e3 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalBandHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalBandHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetTotalBandHall() {
- const { tabPosition, totalTabPosition } = useHallStore();
+ const { tabItem, totalTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 0 && totalTabPosition === 3 && isPath("/hall"),
+ enabled: tabItem === "total" && totalTabItem === "band" && isPath("/hall"),
queryKey: ["totalBandHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/totalBand");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textBand", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalHighestHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalHighestHall.ts"
deleted file mode 100644
index 14bf68e..0000000
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalHighestHall.ts"
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Hall } from "@/app/[language]/hall/type";
-import { useHallStore } from "@/state/Stores";
-import { GetHallAPI } from "@/type/wwwAPI";
-import { formatText } from "@/utilities/Utility";
-import { wwwAPI } from "@/utilities/wwwAPI";
-import { useQuery } from "@tanstack/react-query";
-import { useTranslations } from "next-intl";
-import { useIsPath } from "taehui-ts/fe-utilities";
-
-export default function useGetTotalHighestHall() {
- const { tabPosition, totalTabPosition } = useHallStore();
-
- const t = useTranslations();
-
- const isPath = useIsPath();
-
- return useQuery({
- enabled: tabPosition === 0 && totalTabPosition === 1 && isPath("/hall"),
- queryKey: ["totalHighestHall"],
- queryFn: async () => {
- const { data } = await wwwAPI.get("/hall/totalHighest");
- return data.map((hall) => ({
- ...hall,
- text: t("textCount", { value: formatText(hall.value) }),
- }));
- },
- initialData: [],
- });
-}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalStandHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalStandHall.ts"
index 3194e71..6c6be67 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalStandHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalStandHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetTotalStandHall() {
- const { tabPosition, totalTabPosition } = useHallStore();
+ const { tabItem, totalTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 0 && totalTabPosition === 2 && isPath("/hall"),
+ enabled: tabItem === "total" && totalTabItem === "stand" && isPath("/hall"),
queryKey: ["totalStandHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/totalStand");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textStand", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTopHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTopHall.ts"
new file mode 100644
index 0000000..41321c3
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTopHall.ts"
@@ -0,0 +1,30 @@
+import { Hall } from "@/app/[language]/hall/type";
+import { useHallStore } from "@/state/Stores";
+import { GetHallAPI } from "@/type/wwwAPI";
+import { formatText } from "@/utilities/Utility";
+import { wwwAPI } from "@/utilities/wwwAPI";
+import { useQuery } from "@tanstack/react-query";
+import { useTranslations } from "next-intl";
+import { useIsPath } from "taehui-ts/fe-utilities";
+
+export default function useGetTotalTopHall() {
+ const { tabItem, totalTabItem } = useHallStore();
+
+ const t = useTranslations();
+
+ const isPath = useIsPath();
+
+ return useQuery({
+ enabled: tabItem === "total" && totalTabItem === "top" && isPath("/hall"),
+ queryKey: ["totalTopHall"],
+ queryFn: async () => {
+ const { data } = await wwwAPI.get("/hall/totalTop");
+ return data.map((hall) => ({
+ ...hall,
+ value: hall.value,
+ text: t("textCount", { value: formatText(hall.value) }),
+ }));
+ },
+ initialData: [],
+ });
+}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTotalHall.ts" "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTotalHall.ts"
index 0740247..7d07fd1 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTotalHall.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/query/useGetTotalTotalHall.ts"
@@ -8,19 +8,20 @@
import { useIsPath } from "taehui-ts/fe-utilities";
export default function useGetTotalTotalHall() {
- const { tabPosition, totalTabPosition } = useHallStore();
+ const { tabItem, totalTabItem } = useHallStore();
const t = useTranslations();
const isPath = useIsPath();
return useQuery({
- enabled: tabPosition === 0 && totalTabPosition === 0 && isPath("/hall"),
+ enabled: tabItem === "total" && totalTabItem === "total" && isPath("/hall"),
queryKey: ["totalTotalHall"],
queryFn: async () => {
const { data } = await wwwAPI.get("/hall/totalTotal");
return data.map((hall) => ({
...hall,
+ value: hall.value,
text: t("textHandled", { value: formatText(hall.value) }),
}));
},
diff --git "a/qwilight-fe/src/app/\133language\135/hall/state/setHallStore.ts" "b/qwilight-fe/src/app/\133language\135/hall/state/setHallStore.ts"
index 22d76c6..8a1358c 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/state/setHallStore.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/state/setHallStore.ts"
@@ -1,24 +1,24 @@
export default function setHallStore() {
return {
- tabPosition: 0,
- totalTabPosition: 0,
- atTabPosition: 0,
- abilityTabPosition: 0,
+ tabItem: "total",
+ totalTabItem: "total",
+ atTabItem: "total",
+ abilityTabItem: "5K",
- setTabPosition(tabPosition: number) {
- this.tabPosition = tabPosition;
+ setTabItem(tabItem: string) {
+ this.tabItem = tabItem;
},
- setTotalTabPosition(totalTabPosition: number) {
- this.totalTabPosition = totalTabPosition;
+ setTotalTabItem(totalTabItem: string) {
+ this.totalTabItem = totalTabItem;
},
- setAtTabPosition(atTabPosition: number) {
- this.atTabPosition = atTabPosition;
+ setAtTabItem(atTabItem: string) {
+ this.atTabItem = atTabItem;
},
- setAbilityTabPosition(abilityTabPosition: number) {
- this.abilityTabPosition = abilityTabPosition;
+ setAbilityTabItem(abilityTabItem: string) {
+ this.abilityTabItem = abilityTabItem;
},
};
}
diff --git "a/qwilight-fe/src/app/\133language\135/hall/type/index.d.ts" "b/qwilight-fe/src/app/\133language\135/hall/type/index.d.ts"
index e4c8b20..64c3683 100644
--- "a/qwilight-fe/src/app/\133language\135/hall/type/index.d.ts"
+++ "b/qwilight-fe/src/app/\133language\135/hall/type/index.d.ts"
@@ -1,5 +1,6 @@
export type Hall = {
avatarID: string;
avatarName: string;
+ value: number;
text: string;
};
diff --git "a/qwilight-fe/src/app/\133language\135/layout.tsx" "b/qwilight-fe/src/app/\133language\135/layout.tsx"
index 3c513d4..6423d29 100644
--- "a/qwilight-fe/src/app/\133language\135/layout.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/layout.tsx"
@@ -4,10 +4,8 @@
import { getMessages } from "next-intl/server";
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";
export default async function Layout({
@@ -18,7 +16,7 @@
params: { language: string };
}) {
return (
-
+
Qwilight
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"
index 24bac82..4f2b1c2 100644
--- "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"
@@ -1,9 +1,7 @@
"use client";
-import FitInput from "@/app/[language]/note/components/FitInput";
-import NoteItems from "@/app/[language]/note/components/NoteItems";
+import NotesView from "@/app/[language]/note/components/NotesView";
import PositionInput from "@/app/[language]/note/components/PositionInput";
-import SrcInput from "@/app/[language]/note/components/SrcInput";
import WantInput from "@/app/[language]/note/components/WantInput";
import useGetNote from "@/app/[language]/note/query/useGetNote";
@@ -11,28 +9,30 @@
import { formatText } from "@/utilities/Utility";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { useEffect } from "react";
-import { Button, Col, Row } from "reactstrap";
-import { useIntParam, useWant } from "taehui-ts/fe-utilities";
+import { useParams } from "next/navigation";
+import { useEffect, useMemo } from "react";
+import Stack from "react-bootstrap/Stack";
+import { useIntParam } from "taehui-ts/fe-utilities";
export default observer(() => {
const {
+ setLastSrc,
setWantAvatar,
- wantInput,
- lastPage,
setLastPage,
- viewUnit,
lastWant,
lastSrc,
+ setWantInput,
+ setLastWant,
} = useNoteStore();
const t = useTranslations();
- const { want, setWant } = useWant("/note");
+ let { want: [want] = [""] } = useParams<{ want: string[] }>();
+ want = useMemo(() => decodeURIComponent(want), [want]);
const { param: src } = useIntParam("src", 0);
const { param: page, setParam: setPage } = useIntParam("page", 1);
const {
- data: { topCount, totalCount, noteCount },
+ data: { topCount, totalCount, lastPage },
isFetched: isNoteLoaded,
} = useGetNote();
@@ -44,85 +44,47 @@
useEffect(() => {
if (isNoteLoaded) {
- setLastPage(Math.max(1, Math.ceil(noteCount / viewUnit)));
+ setLastPage(lastPage);
}
- }, [isNoteLoaded, noteCount, setLastPage, viewUnit]);
+ }, [isNoteLoaded, lastPage, setLastPage]);
+
+ useEffect(() => {
+ setWantInput(want);
+ }, [setWantInput, want]);
+
+ useEffect(() => {
+ setLastWant(want);
+ }, [setLastWant, want]);
+
+ useEffect(() => {
+ setLastSrc(src);
+ }, [setLastSrc, src]);
useEffect(() => {
setWantAvatar(src === 1 ? want : "");
}, [setWantAvatar, src, want]);
- const onWant = () => {
- setWant(wantInput);
- };
-
- const onClose = () => {
- setWant("");
- };
-
return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- {t("onWant")}
-
-
-
-
- {t("onClose")}
-
-
-
-
-
-
-
-
-
-
- {lastPage >= 0 && (
-
-
-
-
-
- )}
-
+
+
+
+
+
+
{isNoteLoaded && (
-
-
-
- {t("topCountText", {
- topCount: formatText(topCount),
- })}
-
-
-
- {t("totalCountText", { totalCount: formatText(totalCount) })}
-
-
-
+ <>
+ {t("topCountText", {
+ topCount: formatText(topCount),
+ })}
+
+ {t("totalCountText", { totalCount: formatText(totalCount) })}
+ >
)}
-
-
-
-
-
-
- >
+
+
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/CommentItem.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/CommentItem.tsx"
deleted file mode 100644
index 07b4f46..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/CommentItem.tsx"
+++ /dev/null
@@ -1,103 +0,0 @@
-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 AvatarDrawing from "@/components/AvatarDrawing";
-import AvatarTitle from "@/components/AvatarTitle";
-
-import { GetCommentAPI } from "@/type/wwwAPI";
-import {
- formatText,
- getHitPointsClass,
- getQuitStatusValue,
- toDate,
-} from "@/utilities/Utility";
-import { useTranslations } from "next-intl";
-import Image from "next/image";
-import { useMemo } from "react";
-import { Col, Row } from "reactstrap";
-import { useTo } from "taehui-ts/fe-utilities";
-
-const ws = [w0, w1, w2, "", w4, w5, w6, w7];
-
-export default function CommentItem({
- date,
- avatarID,
- avatarName,
- stand,
- band,
- point,
- isP,
- commentary,
- isTargetAvatar,
- judgmentMode,
- hitPointsMode,
- isPaused,
- handled,
-}: GetCommentAPI["comments"][number]) {
- const { quit, quitCss } = useMemo(
- () => getQuitStatusValue(point, stand),
- [point, stand],
- );
- const to = useTo();
- const t = useTranslations();
-
- return (
- {
- to(`/avatar/!${avatarID}`);
- }}
- className={`g-0 route ${isTargetAvatar ? "target" : ""}`}
- >
-
-
-
-
-
-
-
- {quit}
- {isP && (
- <>
-
- FULL
- >
- )}
-
-
-
- {avatarName}{" "}
- {toDate(date)}
-
-
- {t("textStand", { value: formatText(stand) })}
- {" "}
- {
- switch (judgmentMode) {
- case 0:
- return "level2";
- case 2:
- return "level4";
- case 3:
- return "level1";
- case 5:
- return "level5";
- default:
- return "point";
- }
- })()}
- >
- {(100 * point).toFixed(2)}%
- {" "}
- {t("textBand", { value: band })}
- {isPaused && " ⏸️"}
-
- {commentary && 💬 {commentary}}
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/CommentItems.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/CommentItems.tsx"
deleted file mode 100644
index b1b99f0..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/CommentItems.tsx"
+++ /dev/null
@@ -1,64 +0,0 @@
-import CommentItem from "@/app/[language]/note/components/CommentItem";
-import { GetCommentAPI } from "@/type/wwwAPI";
-import { formatText } from "@/utilities/Utility";
-
-export default function CommentItems({
- comments,
- commentPlace,
- totalCount,
- wantAvatarID,
- wantAvatarName,
-}: {
- comments: GetCommentAPI["comments"];
- commentPlace: number;
- totalCount: number;
- wantAvatarID?: string;
- wantAvatarName?: string;
-}) {
- return (
- <>
- {commentPlace !== -1 && (
- <>
- #{formatText(commentPlace + 1)}
- /{formatText(totalCount)}
- >
- )}
- {comments.map(
- ({
- date,
- avatarID,
- avatarName,
- stand,
- band,
- point,
- commentary,
- isP,
- judgmentMode,
- hitPointsMode,
- isPaused,
- handled,
- }) => (
-
- ),
- )}
- >
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/CommentView.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/CommentView.tsx"
new file mode 100644
index 0000000..9f6db3a
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/note/components/CommentView.tsx"
@@ -0,0 +1,89 @@
+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 w8 from "@/assets/w8.png";
+import AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarTitle from "@/components/AvatarTitle";
+import HitPointsModeText from "@/components/HitPointsModeText";
+import JudgmentModeText from "@/components/JudgmentModeText";
+
+import { GetCommentAPI } from "@/type/wwwAPI";
+import { formatText, getQuitStatusValue } from "@/utilities/Utility";
+import { useTranslations } from "next-intl";
+import Image from "next/image";
+import Link from "next/link";
+import { useMemo } from "react";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import { getDatetime } from "taehui-ts/date";
+
+const ws = [w0, w1, w2, "", w4, w5, w6, w7, w8];
+
+export default function CommentView({
+ date,
+ avatarID,
+ avatarName,
+ stand,
+ band,
+ point,
+ isBand1,
+ commentary,
+ isTargetAvatar,
+ judgmentMode,
+ hitPointsMode,
+ isPaused,
+ handled,
+}: GetCommentAPI["comments"][number]) {
+ const { quit, quitCss } = useMemo(
+ () => getQuitStatusValue(point, stand),
+ [point, stand],
+ );
+ const t = useTranslations();
+
+ return (
+
+
+
+
+
+
+
+
+ {commentary && 💬 {commentary}}
+
+
+
+
+ {getDatetime(date)}
+
+
+ {t("textBand", { value: band })}
+ {isPaused && "⏸️"}
+
+
+
+
+ {quit}
+ {isBand1 && "FULL"}
+
+
+
+
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/FitInput.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/FitInput.tsx"
deleted file mode 100644
index 2192f2c..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/FitInput.tsx"
+++ /dev/null
@@ -1,40 +0,0 @@
-import { useTranslations } from "next-intl";
-import { useState } from "react";
-import {
- Dropdown,
- DropdownItem,
- DropdownMenu,
- DropdownToggle,
-} from "reactstrap";
-import { useIntParam } from "taehui-ts/fe-utilities";
-
-export default function FitInput() {
- const [isFitOpened, setFitOpened] = useState(false);
- const { param: fit, setParam: setFit } = useIntParam("fit", 0);
-
- const t = useTranslations();
-
- const onInput = (fit: number) => () => {
- setFit(fit);
- };
-
- return (
- {
- setFitOpened((prevState) => !prevState);
- }}
- >
- {t(`toFit${fit}`)}
-
- {t("toFit0")}
- {t("toFit1")}
- {t("toFit2")}
- {t("toFit3")}
- {t("toFit4")}
- {t("toFit5")}
- {t("toFit6")}
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/NoteItem.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/NoteItem.tsx"
deleted file mode 100644
index fd87953..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/NoteItem.tsx"
+++ /dev/null
@@ -1,132 +0,0 @@
-import CommentItems from "@/app/[language]/note/components/CommentItems";
-import useGetComment from "@/app/[language]/note/query/useGetComment";
-import usePostToil from "@/app/[language]/note/query/usePostToil";
-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 { GetNoteAPI } from "@/type/wwwAPI";
-import { formatText, getGenreText } from "@/utilities/Utility";
-import { useTranslations } from "next-intl";
-import Image from "next/image";
-import { useState } from "react";
-import { Item, Menu, useContextMenu } from "react-contexify";
-import { Col, Collapse, ListGroupItem, Row, Spinner } from "reactstrap";
-import Swal from "sweetalert2";
-
-const ws = [w0, w1, w2, "", w4, w5, w6, w7];
-
-export default function NoteItem({
- noteID,
- artist,
- title,
- genre,
- levelText,
- level,
- topCount,
- totalCount,
- fittedText,
- wantAvatarID,
- wantAvatarName,
- handled,
-}: GetNoteAPI["notes"][number] & { handled?: number }) {
- const t = useTranslations();
-
- const [isCommentOpened, setCommentOpened] = useState(false);
-
- const { show: viewToilInput } = useContextMenu({
- id: `toil-${noteID}`,
- });
-
- const {
- data: { comments, commentPlace, totalComments },
- isFetched: isCommentLoaded,
- } = useGetComment(noteID, isCommentOpened);
-
- const { mutateAsync: postToil } = usePostToil();
-
- const isLoading = !noteID;
-
- return (
-
- {
- setCommentOpened((prevState) => !prevState);
- }
- }
- onContextMenu={
- isLoading
- ? undefined
- : (event) => {
- event.preventDefault();
- viewToilInput({ event, props: { noteID } });
- }
- }
- >
- {typeof handled === "number" && (
-
-
-
- )}
-
- {levelText}{" "}
- {title}{" "}
- {isCommentOpened && !isCommentLoaded && (
-
- )}
-
- {fittedText && {fittedText}}{" "}
- {artist}{" "}
- {getGenreText(genre)}
-
- {typeof topCount === "number" && typeof totalCount === "number" && (
- <>
-
- {t("topCountText", {
- topCount: formatText(topCount),
- })}
-
-
-
- {t("totalCountText", { totalCount: formatText(totalCount) })}
-
- >
- )}
-
-
- {noteID && (
-
- )}
-
-
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/NoteItems.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/NoteItems.tsx"
deleted file mode 100644
index 7d29f65..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/NoteItems.tsx"
+++ /dev/null
@@ -1,84 +0,0 @@
-import NoteItem from "@/app/[language]/note/components/NoteItem";
-import useGetNote from "@/app/[language]/note/query/useGetNote";
-
-import { useNoteStore } from "@/state/Stores";
-import { observer } from "mobx-react-lite";
-import { useLayoutEffect, useState } from "react";
-import { Col, ListGroup, Row } from "reactstrap";
-import { useWindowArea } from "taehui-ts/fe-utilities";
-
-export default observer(() => {
- const { wantAvatar, viewUnit } = useNoteStore();
-
- const {
- data: { notes },
- isFetched: isNoteLoaded,
- } = useGetNote();
-
- const { windowLength } = useWindowArea();
- const [table, setTable] = useState(1);
-
- useLayoutEffect(() => {
- setTable(windowLength < 992 ? 1 : 2);
- }, [windowLength]);
-
- return (
-
- {[...Array(table).keys()].map((i) => {
- if (isNoteLoaded) {
- return (
-
-
- {notes
- .slice((viewUnit / table) * i, (viewUnit / table) * (i + 1))
- .map(
- ({
- noteID,
- artist,
- title,
- genre,
- levelText,
- level,
- topCount,
- totalCount,
- }) => (
-
- ),
- )}
-
-
- );
- }
-
- return (
-
-
- {[...Array(viewUnit / table).keys()].map((i) => (
-
- ))}
-
-
- );
- })}
-
- );
-});
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/NoteView.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/NoteView.tsx"
new file mode 100644
index 0000000..44fb587
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/note/components/NoteView.tsx"
@@ -0,0 +1,193 @@
+import CommentView from "@/app/[language]/note/components/CommentView";
+import useGetComment from "@/app/[language]/note/query/useGetComment";
+import usePostToil from "@/app/[language]/note/query/usePostToil";
+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 w8 from "@/assets/w8.png";
+import AvatarPlaceText from "@/components/AvatarPlaceText";
+import LevelText from "@/components/LevelText";
+import { GetNoteAPI } from "@/type/wwwAPI";
+import { formatText, getGenreText } from "@/utilities/Utility";
+import { useTranslations } from "next-intl";
+import Image from "next/image";
+import { useState } from "react";
+import { Placeholder } from "react-bootstrap";
+import Collapse from "react-bootstrap/Collapse";
+import Col from "react-bootstrap/esm/Col";
+import Row from "react-bootstrap/Row";
+import Spinner from "react-bootstrap/Spinner";
+import Stack from "react-bootstrap/Stack";
+import { Item, Menu, useContextMenu } from "react-contexify";
+import Swal from "sweetalert2";
+
+const ws = [w0, w1, w2, "", w4, w5, w6, w7, w8];
+
+export default function NoteView({
+ noteID,
+ artist,
+ title,
+ genre,
+ levelText,
+ level,
+ topCount,
+ totalCount,
+ fittedText,
+ wantAvatarID,
+ wantAvatarName,
+ handled,
+}: GetNoteAPI["notes"][number] & {
+ fittedText?: string;
+ wantAvatarID?: string;
+ wantAvatarName?: string;
+ handled?: number;
+}) {
+ const t = useTranslations();
+
+ const [isCommentOpened, setCommentOpened] = useState(false);
+
+ const { show: viewToilInput } = useContextMenu({
+ id: `toil-${noteID}`,
+ });
+
+ const { mutateAsync: postToil } = usePostToil();
+
+ const {
+ data: { comments, commentPlace, totalComments },
+ isFetched: isCommentLoaded,
+ } = useGetComment(noteID, isCommentOpened, wantAvatarID);
+
+ return (
+ <>
+
+ {
+ setCommentOpened((prevState) => !prevState);
+ }}
+ onContextMenu={(event) => {
+ event.preventDefault();
+ viewToilInput({ event, props: { noteID } });
+ }}
+ >
+
+
+
+
+ {title}
+ {isCommentOpened && !isCommentLoaded && }
+
+
+ {artist}
+ {getGenreText(genre)}
+
+ {typeof topCount === "number" && (
+
+ {t("topCountText", {
+ topCount: formatText(topCount),
+ })}
+
+ )}
+ {typeof totalCount === "number" && (
+
+ {t("totalCountText", {
+ totalCount: formatText(totalCount),
+ })}
+
+ )}
+ {fittedText && (
+ {fittedText}
+ )}
+
+
+ {typeof handled === "number" && (
+
+
+
+ )}
+
+
+
+
+ {commentPlace !== -1 && (
+
+ )}
+ {comments.map(
+ ({
+ date,
+ avatarID,
+ avatarName,
+ stand,
+ band,
+ point,
+ commentary,
+ isBand1,
+ judgmentMode,
+ hitPointsMode,
+ isPaused,
+ handled,
+ }) => (
+
+ ),
+ )}
+
+
+
+
+
+
+ >
+ );
+}
+
+export const NoteViewLoading = () => {
+ return (
+
+
+
+
+ );
+};
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/NotesView.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/NotesView.tsx"
new file mode 100644
index 0000000..f68355f
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/note/components/NotesView.tsx"
@@ -0,0 +1,85 @@
+import NoteView, {
+ NoteViewLoading,
+} from "@/app/[language]/note/components/NoteView";
+import useGetNote from "@/app/[language]/note/query/useGetNote";
+import { useNoteStore, useSiteStore } from "@/state/Stores";
+import { observer } from "mobx-react-lite";
+import { useLayoutEffect, useState } from "react";
+import Col from "react-bootstrap/Col";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Row from "react-bootstrap/Row";
+import { useWindowArea } from "taehui-ts/fe-utilities";
+
+export default observer(() => {
+ const { wantAvatar, viewUnit } = useNoteStore();
+ const { siteAvatarID } = useSiteStore();
+
+ const {
+ data: { notes },
+ isFetched: isNoteLoaded,
+ } = useGetNote();
+
+ const { windowLength } = useWindowArea();
+ const [table, setTable] = useState(1);
+
+ useLayoutEffect(() => {
+ setTable(windowLength < 992 ? 1 : 2);
+ }, [windowLength]);
+
+ return (
+
+ {[...Array(table).keys()].map((i) => {
+ if (isNoteLoaded) {
+ return (
+
+
+ {notes
+ .slice((viewUnit / table) * i, (viewUnit / table) * (i + 1))
+ .map(
+ ({
+ noteID,
+ artist,
+ title,
+ genre,
+ levelText,
+ level,
+ topCount,
+ totalCount,
+ }) => (
+
+
+
+ ),
+ )}
+
+
+ );
+ }
+
+ return (
+
+
+ {[...Array(viewUnit).keys()].map((i) => (
+
+
+
+ ))}
+
+
+ );
+ })}
+
+ );
+});
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/PositionInput.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/PositionInput.tsx"
index c66bc20..3b50dbb 100644
--- "a/qwilight-fe/src/app/\133language\135/note/components/PositionInput.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/note/components/PositionInput.tsx"
@@ -1,16 +1,16 @@
import { useNoteStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useMemo } from "react";
-import { Pagination, PaginationItem, PaginationLink } from "reactstrap";
+import Pagination from "react-bootstrap/Pagination";
import { useIntParam } from "taehui-ts/fe-utilities";
export default observer(() => {
- const { pageUnit, lastPage, lastWant, lastSrc } = useNoteStore();
+ const { pageUnit, lastPage } = useNoteStore();
const { param: page, setParam: setPage } = useIntParam("page", 1);
- const targetPages = useMemo(() => {
- const targetPages = [];
+ const pages = useMemo(() => {
+ const pages = [];
for (
let i = 1 + Math.floor((page - 1) / pageUnit) * pageUnit;
i <=
@@ -20,59 +20,55 @@
);
++i
) {
- targetPages.push(i);
+ pages.push(i);
}
- return targetPages;
+ return pages;
}, [lastPage, page, pageUnit]);
const isLowestPage = useMemo(() => page === 1, [page]);
const isHighestPage = useMemo(() => page === lastPage, [lastPage, page]);
+ if (lastPage === 0) {
+ return null;
+ }
+
return (
-
- {
+ setPage(1);
+ }}
+ />
+ {
+ setPage(page - 1);
+ }}
+ />
+ {pages.map((targetPage) => (
+ {
- setPage(1);
+ setPage(targetPage);
}}
- />
-
-
- {
- setPage(page - 1);
- }}
- />
-
- {targetPages.map((targetPage) => (
-
- {
- setPage(targetPage);
- }}
- >
- {targetPage}
-
-
+ >
+ {targetPage}
+
))}
-
- {
- setPage(page + 1);
- }}
- />
-
-
- {
- setPage(lastPage);
- }}
- />
-
+ {
+ setPage(page + 1);
+ }}
+ />
+ {
+ setPage(lastPage);
+ }}
+ />
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/SrcInput.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/SrcInput.tsx"
deleted file mode 100644
index 97d1040..0000000
--- "a/qwilight-fe/src/app/\133language\135/note/components/SrcInput.tsx"
+++ /dev/null
@@ -1,43 +0,0 @@
-import { useNoteStore } from "@/state/Stores";
-import { useTranslations } from "next-intl";
-import { useEffect, useState } from "react";
-import {
- Dropdown,
- DropdownItem,
- DropdownMenu,
- DropdownToggle,
-} from "reactstrap";
-import { useIntParam } from "taehui-ts/fe-utilities";
-
-export default function SrcInput() {
- const { setLastSrc, setWantAvatar } = useNoteStore();
- const [isSrcOpened, setSrcOpened] = useState(false);
- const { param: src, setParam: setSrc } = useIntParam("src", 0);
-
- const t = useTranslations();
-
- const onInput = (src: number) => () => {
- setSrc(src);
- };
-
- useEffect(() => {
- setLastSrc(src);
- }, [setLastSrc, src]);
-
- return (
- {
- setSrcOpened((prevState) => !prevState);
- }}
- >
- {t(`toSrc${src}`)}
-
- {t("toSrc0")}
- {t("toSrc1")}
- {t("toSrc2")}
- {t("toSrc3")}
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/note/components/WantInput.tsx" "b/qwilight-fe/src/app/\133language\135/note/components/WantInput.tsx"
index 1e095bc..1982874 100644
--- "a/qwilight-fe/src/app/\133language\135/note/components/WantInput.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/note/components/WantInput.tsx"
@@ -1,37 +1,90 @@
import { useNoteStore } from "@/state/Stores";
-import { useEffect } from "react";
-import { Input } from "reactstrap";
-import { useWant } from "taehui-ts/fe-utilities";
+import { observer } from "mobx-react-lite";
+import { useTranslations } from "next-intl";
+import { useRouter, useSearchParams } from "next/navigation";
+import { EraserFill, Search } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Dropdown from "react-bootstrap/Dropdown";
+import DropdownItem from "react-bootstrap/DropdownItem";
+import DropdownMenu from "react-bootstrap/DropdownMenu";
+import DropdownToggle from "react-bootstrap/DropdownToggle";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import { useIntParam } from "taehui-ts/fe-utilities";
-export default function SrcInput() {
- const { wantInput, setWantInput, setLastWant } = useNoteStore();
+export default observer(() => {
+ const { wantInput, setWantInput } = useNoteStore();
- const { want, setWant } = useWant("/note");
+ const { push } = useRouter();
+ const searchParams = useSearchParams();
const onWant = () => {
- setWant(wantInput);
+ push(`/note/${wantInput}?${new URLSearchParams(searchParams)}`);
};
- useEffect(() => {
- setWantInput(want);
- }, [setWantInput, want]);
+ const { param: fit, setParam: setFit } = useIntParam("fit", 0);
+ const { param: src, setParam: setSrc } = useIntParam("src", 0);
- useEffect(() => {
- setLastWant(want);
- }, [setLastWant, want]);
+ const t = useTranslations();
return (
- {
- setWantInput(value);
- }}
- onKeyDown={({ key }) => {
- if (key === "Enter") {
- onWant();
- }
- }}
- />
+
+ {
+ if (eventKey) {
+ setFit(Number.parseInt(eventKey));
+ }
+ }}
+ >
+ {t(`fit${fit}`)}
+
+ {t("fit0")}
+ {t("fit1")}
+ {t("fit2")}
+ {t("fit3")}
+ {t("fit4")}
+ {t("fit5")}
+ {t("fit6")}
+
+
+ {
+ if (eventKey) {
+ setSrc(Number.parseInt(eventKey));
+ }
+ }}
+ >
+ {t(`src${src}`)}
+
+ {t("src0")}
+ {t("src1")}
+ {t("src2")}
+ {t("src3")}
+
+
+ {
+ setWantInput(value);
+ }}
+ onKeyDown={({ key }) => {
+ if (key === "Enter") {
+ onWant();
+ }
+ }}
+ />
+
+
+
+ {
+ push("/note");
+ }}
+ >
+
+
+
);
-}
+});
diff --git "a/qwilight-fe/src/app/\133language\135/note/loading.tsx" "b/qwilight-fe/src/app/\133language\135/note/loading.tsx"
index 0743e4d..10e0631 100644
--- "a/qwilight-fe/src/app/\133language\135/note/loading.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/note/loading.tsx"
@@ -1,8 +1,5 @@
-import LoadingLayer from "@/components/LoadingLayer";
-import { useTranslations } from "next-intl";
+import DefaultLoading from "@/components/DefaultLoading";
export default function Loading() {
- const t = useTranslations();
-
- return ;
+ return ;
}
diff --git "a/qwilight-fe/src/app/\133language\135/note/query/useGetComment.ts" "b/qwilight-fe/src/app/\133language\135/note/query/useGetComment.ts"
index f7a86b2..32e3404 100644
--- "a/qwilight-fe/src/app/\133language\135/note/query/useGetComment.ts"
+++ "b/qwilight-fe/src/app/\133language\135/note/query/useGetComment.ts"
@@ -1,4 +1,3 @@
-import { useSiteStore } from "@/state/Stores";
import { GetCommentAPI } from "@/type/wwwAPI";
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
@@ -7,18 +6,18 @@
export default function useGetComment(
noteID: string,
isCommentOpened: boolean,
+ avatarID?: string,
) {
- const { siteAvatarID } = useSiteStore();
const language = useLanguage();
return useQuery({
enabled: isCommentOpened,
- queryKey: ["comment", noteID, siteAvatarID, language],
+ queryKey: ["comment", noteID, avatarID, language],
queryFn: async () => {
const { data } = await wwwAPI.get("/comment", {
params: {
noteID,
- avatarID: siteAvatarID,
+ avatarID,
language,
},
});
diff --git "a/qwilight-fe/src/app/\133language\135/note/query/useGetNote.ts" "b/qwilight-fe/src/app/\133language\135/note/query/useGetNote.ts"
index 036fd2a..5bc552d 100644
--- "a/qwilight-fe/src/app/\133language\135/note/query/useGetNote.ts"
+++ "b/qwilight-fe/src/app/\133language\135/note/query/useGetNote.ts"
@@ -3,7 +3,9 @@
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
-import { useIntParam, useIsPath, useWant } from "taehui-ts/fe-utilities";
+import { useParams } from "next/navigation";
+import { useMemo } from "react";
+import { useIntParam, useIsPath } from "taehui-ts/fe-utilities";
export default function useGetNote() {
const { viewUnit } = useNoteStore();
@@ -12,7 +14,8 @@
const { param: fit } = useIntParam("fit", 0);
const { param: src } = useIntParam("src", 0);
- const { want } = useWant("/note");
+ let { want: [want] = [""] } = useParams<{ want: string[] }>();
+ want = useMemo(() => decodeURIComponent(want), [want]);
const isPath = useIsPath();
@@ -35,7 +38,7 @@
initialData: {
totalCount: 0,
topCount: 0,
- noteCount: 0,
+ lastPage: 0,
notes: [],
},
});
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.module.scss" "b/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.module.scss"
deleted file mode 100644
index 3a2522b..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.module.scss"
+++ /dev/null
@@ -1,5 +0,0 @@
-span {
- &.audioInput {
- color: green;
- }
-}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.tsx"
deleted file mode 100644
index 2b8e289..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItem.tsx"
+++ /dev/null
@@ -1,76 +0,0 @@
-import scss from "@/app/[language]/site/components/AvatarItem.module.scss";
-import { OnAvatarInput } from "@/app/[language]/site/type";
-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 AvatarDrawing from "@/components/AvatarDrawing";
-import AvatarTitle from "@/components/AvatarTitle";
-import Image from "next/image";
-import { Col, Row } from "reactstrap";
-
-const acs = ["", ac1, ac2, ac3, ac4];
-
-export default function AvatarItem({
- avatarID,
- avatarName,
- avatarConfigure,
- isSiteHand,
- isMe,
- isValve,
- isAudioInput,
- onAvatarInput,
-}: {
- avatarID: string;
- avatarName: string;
- avatarConfigure: number;
- isSiteHand: boolean;
- isMe: boolean;
- isValve: boolean;
- isAudioInput: boolean;
- onAvatarInput: OnAvatarInput;
-}) {
- return (
- {
- e.preventDefault();
- onAvatarInput(e, avatarID);
- }}
- >
-
-
-
-
- {avatarID && }
-
- {avatarName}
-
-
- {isValve && (
- <>
- {" "}
-
- >
- )}
- {acs[avatarConfigure] && (
- <>
- {" "}
-
- >
- )}
- {isSiteHand && (
- <>
- {" "}
-
- >
- )}
-
-
- );
-}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItems.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/AvatarItems.tsx"
deleted file mode 100644
index 6d538da..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/AvatarItems.tsx"
+++ /dev/null
@@ -1,39 +0,0 @@
-import AvatarItem from "@/app/[language]/site/components/AvatarItem";
-import { OnAvatarInput } from "@/app/[language]/site/type";
-
-import { useSiteStore } from "@/state/Stores";
-import { observer } from "mobx-react-lite";
-
-export default observer(
- ({ onAvatarInput }: { onAvatarInput: OnAvatarInput }) => {
- const { avatars } = useSiteStore();
-
- return (
- <>
- {avatars.map(
- ({
- avatarID,
- avatarName,
- avatarConfigure,
- isSiteHand,
- isMe,
- isValve,
- isAudioInput,
- }) => (
-
- ),
- )}
- >
- );
- },
-);
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/AvatarView.module.scss" "b/qwilight-fe/src/app/\133language\135/site/components/AvatarView.module.scss"
new file mode 100644
index 0000000..3a2522b
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/AvatarView.module.scss"
@@ -0,0 +1,5 @@
+span {
+ &.audioInput {
+ color: green;
+ }
+}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/AvatarView.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/AvatarView.tsx"
new file mode 100644
index 0000000..ff238fe
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/AvatarView.tsx"
@@ -0,0 +1,68 @@
+import scss from "@/app/[language]/site/components/AvatarView.module.scss";
+import { OnAvatarInput } from "@/app/[language]/site/type";
+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 AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarTitle from "@/components/AvatarTitle";
+import Image from "next/image";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+
+const acs = ["", ac1, ac2, ac3, ac4];
+
+export default function AvatarItem({
+ avatarID,
+ avatarName,
+ avatarConfigure,
+ isSiteHand,
+ isValve,
+ isAudioInput,
+ onAvatarInput,
+}: {
+ avatarID: string;
+ avatarName: string;
+ avatarConfigure: number;
+ isSiteHand: boolean;
+ isValve: boolean;
+ isAudioInput: boolean;
+ onAvatarInput: OnAvatarInput;
+}) {
+ return (
+ {
+ e.preventDefault();
+ onAvatarInput(e, avatarID);
+ }}
+ >
+
+
+
+
+
+
+
+ {isValve && }
+
+ {isSiteHand && (
+
+ )}
+
+
+
+
+ );
+}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/ConfigureWindow.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/ConfigureWindow.tsx"
index 260de4b..8701a0a 100644
--- "a/qwilight-fe/src/app/\133language\135/site/components/ConfigureWindow.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/components/ConfigureWindow.tsx"
@@ -1,7 +1,10 @@
import { useSiteStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { Button, Col, Modal, Row } from "reactstrap";
+import FormCheck from "react-bootstrap/FormCheck";
+import Modal from "react-bootstrap/Modal";
+import ModalBody from "react-bootstrap/ModalBody";
+import Stack from "react-bootstrap/Stack";
export default observer(() => {
const {
@@ -20,8 +23,8 @@
return (
{
+ show={isConfigureOpened}
+ onHide={() => {
window.localStorage.setItem("saveTraffic", saveTraffic.toString());
window.localStorage.setItem(
"autoEnterNotify",
@@ -37,52 +40,43 @@
);
setConfigureOpened(false);
}}
- centered
>
-
-
- {
+
+
+ {
setSaveTraffic(!saveTraffic);
}}
- >
- {t("siteSaveTraffic")}
-
-
-
-
-
- {
+ />
+ {
setAutoEnterNotify(!autoEnterNotify);
}}
- >
- {t("siteAutoEnterNotify")}
-
-
-
- {
+ />
+ {
setAutoEnterDefault(!autoEnterDefault);
}}
- >
- {t("siteAutoEnterDefault")}
-
-
-
- {
+ />
+ {
setAutoEnterPlatform(!autoEnterPlatform);
}}
- >
- {t("siteAutoEnterPlatform")}
-
-
-
+ />
+
+
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/LogInWindow.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/LogInWindow.tsx"
deleted file mode 100644
index 7bc1654..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/LogInWindow.tsx"
+++ /dev/null
@@ -1,89 +0,0 @@
-import wsAPI from "@/app/[language]/site/lib/wsAPI";
-import { useSiteStore } from "@/state/Stores";
-import CryptoJS from "crypto-js";
-import { observer } from "mobx-react-lite";
-import { useTranslations } from "next-intl";
-import { useState } from "react";
-import { Button, Col, Form, Input, Modal, Row } from "reactstrap";
-
-const EventPB = require("@/Event_pb");
-
-export default observer(() => {
- const { isLogInOpened, setLogInOpened } = useSiteStore();
- const t = useTranslations();
-
- const [avatarID, setAvatarID] = useState("");
- const [avatarCipher, setAvatarCipher] = useState("");
- const [autoLogIn, setAutoLogIn] = useState(false);
-
- const onLogIn = () => {
- if (autoLogIn) {
- window.localStorage.setItem("avatarID", avatarID);
- window.localStorage.setItem(
- "avatarCipher",
- CryptoJS.AES.encrypt(
- avatarCipher,
- "591A6F91-2A27-4A88-88FA-0FEB7CB5FD94",
- ).toString(),
- );
- }
- window.localStorage.setItem("autoLogIn", autoLogIn.toString());
- wsAPI.send({
- eventID: EventPB.Event.EventID.LOG_IN,
- text: JSON.stringify({ avatarID, avatarCipher }),
- });
- };
-
- return (
- setLogInOpened(false)} centered>
-
-
- );
-});
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/NewSiteWindow.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/NewSiteWindow.tsx"
index 6bbafb9..a058b58 100644
--- "a/qwilight-fe/src/app/\133language\135/site/components/NewSiteWindow.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/components/NewSiteWindow.tsx"
@@ -4,7 +4,15 @@
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import { useState } from "react";
-import { Button, Col, Form, Input, Modal, Row } from "reactstrap";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Modal from "react-bootstrap/Modal";
+import ModalBody from "react-bootstrap/ModalBody";
+import ModalFooter from "react-bootstrap/ModalFooter";
+import Stack from "react-bootstrap/Stack";
const EventPB = require("@/Event_pb");
@@ -30,48 +38,47 @@
return (
{
+ show={isNewSiteWindowOpened}
+ onHide={() => {
setNewSiteWindowOpened(false);
}}
- centered
>
-
+
+
+
+
+
+
+
+
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteCipherWindow.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteCipherWindow.tsx"
index e626c60..4a14037 100644
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteCipherWindow.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteCipherWindow.tsx"
@@ -1,10 +1,17 @@
import wsAPI from "@/app/[language]/site/lib/wsAPI";
-
import { useSiteStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import { useState } from "react";
-import { Button, Col, Form, Input, Modal, Row } from "reactstrap";
+import { UnlockFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Modal from "react-bootstrap/Modal";
+import ModalBody from "react-bootstrap/ModalBody";
+import ModalFooter from "react-bootstrap/ModalFooter";
+import Stack from "react-bootstrap/Stack";
const EventPB = require("@/Event_pb");
@@ -29,42 +36,40 @@
return (
{
+ show={isSiteCipherWindowOpened}
+ onHide={() => {
setSiteCipherWindowOpened(false);
}}
- centered
>
-
+
+
+
+
+
+
+
+
);
},
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteInput.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteInput.tsx"
index 3e5da5f..2e62cf1 100644
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteInput.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteInput.tsx"
@@ -1,41 +1,58 @@
import wsAPI from "@/app/[language]/site/lib/wsAPI";
+import { SiteView } from "@/app/[language]/site/state/setSiteStore";
import { useSiteStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { Button, Col, Input, Row } from "reactstrap";
+import InputGroup from "react-bootstrap/InputGroup";
+import Button from "react-bootstrap/Button";
+import { useQueryClient } from "@tanstack/react-query";
+import FormControl from "react-bootstrap/FormControl";
+import {
+ ChatFill,
+ Back,
+ GearFill,
+ PeopleFill,
+ CloudUploadFill,
+} from "react-bootstrap-icons";
+import { forwardRef } from "react";
const EventPB = require("@/Event_pb");
-export default observer(() => {
- const {
- targetSiteID,
- isEditable,
- input,
- setInput,
- isLoggedIn,
- setAvatarsOpened,
- setConfigureOpened,
- setLogInOpened,
- } = useSiteStore();
- const t = useTranslations();
+export default observer(
+ forwardRef(function SiteInput(
+ { siteView: { isEditable, textInput, setTextInput, setAvatarsViewOpened } },
+ ref,
+ ) {
+ const { targetSiteID, setConfigureOpened, setSiteWindowOpened } =
+ useSiteStore();
+ const t = useTranslations();
- const postFile = (file: File) => {
- const fr = new FileReader();
- fr.readAsArrayBuffer(file);
- fr.addEventListener("loadend", () => {
- const { result } = fr;
- wsAPI.send({
- eventID: EventPB.Event.EventID.POST_FILE,
- text: file.name,
- data: [new Uint8Array(result as ArrayBufferLike)],
+ const postFile = (file: File) => {
+ const fr = new FileReader();
+ fr.readAsArrayBuffer(file);
+ fr.addEventListener("loadend", () => {
+ const { result } = fr;
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.POST_FILE,
+ text: file.name,
+ data: [new Uint8Array(result as ArrayBufferLike)],
+ });
});
- });
- };
+ };
- return (
-
-
+ const queryClient = useQueryClient();
+
+ return (
+
+ {
+ setConfigureOpened(true);
+ }}
+ >
+
+
{
const inputElement = document.createElement("input");
@@ -50,27 +67,26 @@
inputElement.click();
}}
>
- {t("postFile")}
+
-
-
- {
- setInput(value);
+ setTextInput(value);
}}
onKeyDown={({ key }) => {
if (key === "Enter") {
- if (input.length > 0) {
+ if (textInput.length > 0) {
wsAPI.send({
eventID: EventPB.Event.EventID.SITE_YELL,
text: JSON.stringify({
siteID: targetSiteID,
- siteYell: input,
+ siteYell: textInput,
}),
});
- setInput("");
+ setTextInput("");
}
}
}}
@@ -84,51 +100,35 @@
}
}}
/>
-
-
- {isLoggedIn ? (
+ {
+ setAvatarsViewOpened(true);
+ }}
+ >
+
+
+ {
+ await queryClient.invalidateQueries({ queryKey: ["sites"] });
+ setSiteWindowOpened(true);
+ }}
+ >
+
+
+ {targetSiteID && (
{
- window.localStorage.removeItem("avatarCipher");
- window.localStorage.removeItem("autoLogIn");
wsAPI.send({
- eventID: EventPB.Event.EventID.NOT_LOG_IN,
+ eventID: EventPB.Event.EventID.QUIT_SITE,
+ text: targetSiteID,
});
}}
>
- {t("notLogIn")}
-
- ) : (
- {
- setLogInOpened(true);
- }}
- >
- {t("logIn")}
+
)}
-
-
- {
- setAvatarsOpened(true);
- }}
- >
- {t("onAvatars")}
-
-
-
- {
- setConfigureOpened(true);
- }}
- >
- {t("onConfigure")}
-
-
-
- );
-});
+
+ );
+ }),
+);
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteWindow.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteWindow.tsx"
index db48514..e8b6c7d 100644
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteWindow.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteWindow.tsx"
@@ -1,19 +1,24 @@
import NewSiteWindow from "@/app/[language]/site/components/NewSiteWindow";
import SiteCipherWindow from "@/app/[language]/site/components/SiteCipherWindow";
import wsAPI from "@/app/[language]/site/lib/wsAPI";
-
import useGetSites from "@/app/[language]/site/query/useGetSites";
import sc from "@/assets/sc.png";
-
import sc0 from "@/assets/sc0.png";
import sc2 from "@/assets/sc2.png";
-
import { useSiteStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import Image from "next/image";
import { useState } from "react";
-import { Button, Col, Modal, Row } from "reactstrap";
+import Modal from "react-bootstrap/Modal";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Row from "react-bootstrap/Row";
+import Col from "react-bootstrap/Col";
+import Button from "react-bootstrap/Button";
+import ModalBody from "react-bootstrap/ModalBody";
+import ModalFooter from "react-bootstrap/ModalFooter";
+import { PencilFill, Plus } from "react-bootstrap-icons";
const EventPB = require("@/Event_pb");
@@ -40,62 +45,60 @@
};
return (
-
-
-
- {sites.map(
- ({ siteID, hasCipher, siteConfigure, siteName, avatarCount }) => (
- {
- if (hasCipher) {
- setSiteID(siteID);
- setSiteName(siteName);
- setSiteCipherWindowOpened(true);
- } else {
- wsAPI.send({
- eventID: EventPB.Event.EventID.ENTER_SITE,
- text: JSON.stringify({ siteID, siteCipher: "" }),
- });
- onClose();
- }
- }}
- >
-
- {scs[siteConfigure] && (
-
- )}{" "}
-
- {siteName} ({t("avatarCountText", { avatarCount })})
+ <>
+
+
+
+ {sites.map(
+ ({ siteID, hasCipher, siteConfigure, siteName, avatarCount }) => (
+
+ {
+ if (hasCipher) {
+ setSiteID(siteID);
+ setSiteName(siteName);
+ setSiteCipherWindowOpened(true);
+ } else {
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.ENTER_SITE,
+ text: JSON.stringify({ siteID, siteCipher: "" }),
+ });
+ onClose();
+ }
+ }}
+ >
+
+
+
+ {siteName}
{hasCipher && (
- <>
- {" "}
+
- >
+
)}
-
-
-
- ),
- )}
-
-
-
-
+ {t("avatarCountText", { avatarCount })}
+
+
+ ),
+ )}
+
+
+
{
setNewSiteWindowOpened(true);
}}
disabled={!siteAvatarID}
>
- {t("siteWindowNew")}
+
-
-
+
+
-
+ >
);
});
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.module.scss" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.module.scss"
deleted file mode 100644
index 7c1bd2b..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.module.scss"
+++ /dev/null
@@ -1,32 +0,0 @@
-@mixin file() {
- border: thin white solid;
- max-height: 9rem;
-}
-
-img {
- &.file {
- @include file();
- }
-}
-
-video {
- &.file {
- @include file();
- }
-}
-
-audio {
- &.file {
- @include file();
- }
-}
-
-span {
- &.enter {
- color: deepskyblue;
- }
-
- &.quit {
- color: deeppink;
- }
-}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.tsx"
deleted file mode 100644
index 2739bed..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItem.tsx"
+++ /dev/null
@@ -1,397 +0,0 @@
-import scss from "@/app/[language]/site/components/SiteYellItem.module.scss";
-import wsAPI from "@/app/[language]/site/lib/wsAPI";
-import {
- AbilitySiteYell,
- CommentSiteYell,
- InviteSiteYell,
- LevelSiteYell,
- OnSiteYellInput,
- SiteYell,
- TVSiteYell,
-} from "@/app/[language]/site/type";
-import TV0 from "@/assets/tv0.svg";
-import tv1 from "@/assets/tv1.png";
-import AvatarDrawing from "@/components/AvatarDrawing";
-import AvatarTitle from "@/components/AvatarTitle";
-
-import { useSiteStore } from "@/state/Stores";
-import {
- formatText,
- getAbilityUpText,
- getGenreText,
- getHitPointsClass,
-} from "@/utilities/Utility";
-import { sanitize } from "isomorphic-dompurify";
-import { observer } from "mobx-react-lite";
-import { useTranslations } from "next-intl";
-import Image from "next/image";
-import { Col, Row } from "reactstrap";
-
-const EventPB = require("@/Event_pb");
-
-export default observer(
- ({
- data,
- onSiteYellInput,
- }: {
- data: SiteYell;
- onSiteYellInput: OnSiteYellInput;
- }) => {
- const { siteYellVariety, date, avatarID, avatarName, siteYell } = data;
- const { saveTraffic } = useSiteStore();
- const t = useTranslations();
-
- const doSiteYell = (siteYell: string) => {
- siteYell = siteYell.replace(" ", " ");
- const m = siteYell.match(/(http|https|mailto|rtmp):\/\/[^ ]+/i);
- if (m != null) {
- const t = m[0];
-
- if (
- !saveTraffic &&
- t.match(/(\.aac|\.flac|\.mid|\.midi|\.mp3|\.ogg|\.wav|\.wma)($|\?)/i)
- ) {
- return siteYell.replace(
- t,
- ``,
- );
- }
-
- if (
- !saveTraffic &&
- t.match(/(\.bmp|\.gif|\.heic|\.jpeg|\.jpg|\.png|\.webp)($|\?)/i)
- ) {
- return siteYell.replace(
- t,
- `
-
- `,
- );
- }
-
- if (
- !saveTraffic &&
- t.match(/(\.avi|\.mkv|\.mp4|\.mpeg|\.mpg|\.wmv)($|\?)/i)
- ) {
- return siteYell.replace(
- t,
- ``,
- );
- }
-
- return siteYell.replace(t, `${t}`);
- }
-
- return siteYell;
- };
-
- switch (siteYellVariety) {
- case "@Enter":
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("siteYellEnter")}
-
-
- );
- case "@Quit":
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("siteYellQuit")}
-
-
- );
- case "@Site":
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("siteYellNewSite")}
-
-
- );
- case "@Net":
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("siteYellNewNetSite")}
-
-
- );
- case "@Notify":
- return (
-
-
- {t("siteYellTaehui")}{" "}
- {date}
-
-
-
-
- );
- case "@Invite": {
- const { siteID, siteName, avatarName } = siteYell as InviteSiteYell;
- return (
- {
- wsAPI.send({
- eventID: EventPB.Event.EventID.ENTER_SITE,
- text: JSON.stringify({
- siteID,
- siteCipher: "",
- }),
- });
- }}
- onContextMenu={(e) => {
- e.preventDefault();
- avatarID && onSiteYellInput && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("siteYellInvite", { siteName })}
-
-
- );
- }
- case "@TV":
- const { href, title, text } = siteYell as TVSiteYell;
- return (
- {
- window.open(href);
- }}
- >
-
- {href.startsWith("https://www.twitch.tv") && (
-
- )}
- {href.startsWith("https://chzzk.naver.com") && (
-
- )}
-
-
- {text} {date}
-
- {t("siteYellTV", { title })}
-
-
- );
- case "@Wiped":
- return (
-
- {
- e.preventDefault();
- avatarID && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && }
-
-
- {avatarID && }
- {avatarName} {date}
-
- {t("wipedSiteYell")}
-
-
- );
- case "@Comment": {
- const {
- avatarID,
- avatarName,
- title,
- artist,
- genre,
- level,
- levelText,
- stand,
- hitPointsMode,
- } = siteYell as CommentSiteYell;
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {levelText}{" "}
- {artist}{" "}
- {title}{" "}
- {getGenreText(genre)}
-
-
- {t("textStand", { value: formatText(stand) })}
-
-
-
- );
- }
- case "@Ability": {
- const { avatarID, avatarName } = siteYell as AbilitySiteYell;
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {getAbilityUpText(t, siteYell as AbilitySiteYell)}
-
-
-
- );
- }
- case "@Level": {
- const { avatarID, avatarName, title } = siteYell as LevelSiteYell;
- return (
- {
- e.preventDefault();
- avatarID && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && (
-
-
-
- )}
-
- {avatarID && }
- {avatarName} {date}
-
- {t("wwwLevelClearText", { title })}
-
-
-
- );
- }
- case "":
- return (
- <>
- {siteYell as string}
-
- >
- );
- case null:
- return (
-
- {
- e.preventDefault();
- avatarID && onSiteYellInput(e, avatarID);
- }}
- >
- {avatarID && }
-
-
- {avatarID && }
- {avatarName} {date}
-
-
-
-
- );
- default:
- return null;
- }
- },
-);
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItems.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellItems.tsx"
deleted file mode 100644
index 161e0d4..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellItems.tsx"
+++ /dev/null
@@ -1,24 +0,0 @@
-import SiteYellItem from "@/app/[language]/site/components/SiteYellItem";
-import { OnSiteYellInput } from "@/app/[language]/site/type";
-import { useSiteStore } from "@/state/Stores";
-import { observer } from "mobx-react-lite";
-
-export default observer(
- ({ onSiteYellInput }: { onSiteYellInput: OnSiteYellInput }) => {
- const { siteYells } = useSiteStore();
-
- return (
- <>
- {siteYells.map((siteYell) =>
- siteYell ? (
-
- ) : null,
- )}
- >
- );
- },
-);
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.module.scss" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.module.scss"
new file mode 100644
index 0000000..fefbd8e
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.module.scss"
@@ -0,0 +1,31 @@
+@mixin siteYell() {
+ max-width: 100%;
+}
+
+img {
+ &.siteYell {
+ @include siteYell();
+ }
+}
+
+video {
+ &.siteYell {
+ @include siteYell();
+ }
+}
+
+audio {
+ &.siteYell {
+ @include siteYell();
+ }
+}
+
+span {
+ &.enter {
+ color: deepskyblue;
+ }
+
+ &.quit {
+ color: deeppink;
+ }
+}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.tsx"
new file mode 100644
index 0000000..aa7bb6b
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellView.tsx"
@@ -0,0 +1,530 @@
+import scss from "@/app/[language]/site/components/SiteYellView.module.scss";
+import wsAPI from "@/app/[language]/site/lib/wsAPI";
+import {
+ AbilitySiteYell,
+ CommentSiteYell,
+ InviteSiteYell,
+ LevelSiteYell,
+ OnSiteYellInput,
+ SiteYellItem,
+ TVSiteYell,
+} from "@/app/[language]/site/type";
+import tv0 from "@/assets/tv0.svg";
+import tv1 from "@/assets/tv1.png";
+import AvatarDrawing from "@/components/AvatarDrawing";
+import AvatarTitle from "@/components/AvatarTitle";
+import HitPointsModeText from "@/components/HitPointsModeText";
+import LevelText from "@/components/LevelText";
+
+import { useSiteStore } from "@/state/Stores";
+import {
+ formatText,
+ getAbilityUpText,
+ getGenreText,
+} from "@/utilities/Utility";
+import { sanitize } from "isomorphic-dompurify";
+import { observer } from "mobx-react-lite";
+import { useTranslations } from "next-intl";
+import Image from "next/image";
+import Link from "next/link";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+
+const EventPB = require("@/Event_pb");
+
+export default observer(
+ ({
+ siteYellItem,
+ onSiteYellInput,
+ }: {
+ siteYellItem: SiteYellItem;
+ onSiteYellInput: OnSiteYellInput;
+ }) => {
+ const { siteYellVariety, date, avatarID, avatarName, siteYell } =
+ siteYellItem;
+ const { saveTraffic } = useSiteStore();
+ const t = useTranslations();
+
+ const doSiteYell = (siteYell: string) => {
+ siteYell = siteYell.replace(" ", " ");
+ const m = siteYell.match(/(http|https|mailto|rtmp):\/\/[^ ]+/i);
+ if (m != null) {
+ const t = m[0];
+
+ if (
+ !saveTraffic &&
+ t.match(/(\.aac|\.flac|\.mid|\.midi|\.mp3|\.ogg|\.wav|\.wma)($|\?)/i)
+ ) {
+ return siteYell.replace(
+ t,
+ ``,
+ );
+ }
+
+ if (
+ !saveTraffic &&
+ t.match(/(\.bmp|\.gif|\.heic|\.jpeg|\.jpg|\.png|\.webp)($|\?)/i)
+ ) {
+ return siteYell.replace(
+ t,
+ `
+
+ `,
+ );
+ }
+
+ if (
+ !saveTraffic &&
+ t.match(/(\.avi|\.mkv|\.mp4|\.mpeg|\.mpg|\.wmv)($|\?)/i)
+ ) {
+ return siteYell.replace(
+ t,
+ ``,
+ );
+ }
+
+ return siteYell.replace(t, `${t}`);
+ }
+
+ return siteYell;
+ };
+
+ switch (siteYellVariety) {
+ case "@Enter":
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("siteYellEnter")}
+
+
+
+
+ {date}
+
+
+ );
+ case "@Quit":
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("siteYellQuit")}
+
+
+
+
+ {date}
+
+
+ );
+ case "@Site":
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("siteYellNewSite")}
+
+
+
+
+ {date}
+
+
+ );
+ case "@Net":
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("siteYellNewNetSite")}
+
+
+
+
+ {date}
+
+
+ );
+ case "@Notify":
+ return (
+
+
+
+ {t("siteYellTaehui")}
+
+
+
+
+ {date}
+
+
+ );
+ case "@Invite": {
+ const { siteID, siteName, avatarName } = siteYell as InviteSiteYell;
+ return (
+ {
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.ENTER_SITE,
+ text: JSON.stringify({
+ siteID,
+ siteCipher: "",
+ }),
+ });
+ }}
+ onContextMenu={(e) => {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("siteYellInvite", { siteName })}
+
+
+
+
+ {date}
+
+
+ );
+ }
+ case "@TV":
+ const { href, title, text } = siteYell as TVSiteYell;
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+
+ {href.startsWith("https://www.twitch.tv") && (
+
+ )}
+ {href.startsWith("https://chzzk.naver.com") && (
+
+ )}
+
+
+
+
+ {t("siteYellTV", { title })}
+
+
+
+ {date}
+
+
+ );
+ case "@Wiped":
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+ {t("wipedSiteYell")}
+
+
+
+ {date}
+
+
+ );
+ case "@Comment": {
+ const {
+ avatarID,
+ avatarName,
+ title,
+ artist,
+ genre,
+ level,
+ levelText,
+ stand,
+ hitPointsMode,
+ } = siteYell as CommentSiteYell;
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+
+ {title}
+
+
+ {artist}
+ {getGenreText(genre)}
+
+
+
+
+
+ {date}
+
+
+
+
+ );
+ }
+ case "@Ability": {
+ const { avatarID, avatarName } = siteYell as AbilitySiteYell;
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {getAbilityUpText(t, siteYell as AbilitySiteYell)}
+
+
+
+
+ {date}
+
+
+ );
+ }
+ case "@Level": {
+ const { avatarID, avatarName, title } = siteYell as LevelSiteYell;
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+ {t("wwwLevelClearText", { title })}
+
+
+
+
+ {date}
+
+
+ );
+ }
+ case "":
+ return <>{siteYell}>;
+ case null:
+ return (
+ {
+ e.preventDefault();
+ if (avatarID) {
+ onSiteYellInput(e, avatarID);
+ }
+ }}
+ >
+ {avatarID && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ {date}
+
+
+ );
+ default:
+ return null;
+ }
+ },
+);
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.module.scss" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.module.scss"
new file mode 100644
index 0000000..73f307f
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.module.scss"
@@ -0,0 +1,14 @@
+@use "sass:math";
+
+div {
+ &.siteView {
+ overflow: auto;
+ }
+
+ &.alarm {
+ position: absolute;
+ left: 50%;
+ transform: translate(-50%);
+ z-index: math.$max-number;
+ }
+}
diff --git "a/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.tsx" "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.tsx"
new file mode 100644
index 0000000..c67fde6
--- /dev/null
+++ "b/qwilight-fe/src/app/\133language\135/site/components/SiteYellsView.tsx"
@@ -0,0 +1,256 @@
+import AvatarView from "@/app/[language]/site/components/AvatarView";
+import SiteInput from "@/app/[language]/site/components/SiteInput";
+import scss from "@/app/[language]/site/components/SiteYellsView.module.scss";
+import SiteYellView from "@/app/[language]/site/components/SiteYellView";
+import wsAPI from "@/app/[language]/site/lib/wsAPI";
+import { SiteView } from "@/app/[language]/site/state/setSiteStore";
+import { OnSiteYellInput } from "@/app/[language]/site/type";
+import { useSiteStore } from "@/state/Stores";
+import { getDefaultAvatarID } from "@/utilities/Utility";
+import { observer } from "mobx-react-lite";
+import { useTranslations } from "next-intl";
+import { useRouter } from "next/navigation";
+import { useEffect, useLayoutEffect, useRef, useState } from "react";
+import Alert from "react-bootstrap/Alert";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Offcanvas from "react-bootstrap/Offcanvas";
+import OffcanvasBody from "react-bootstrap/OffcanvasBody";
+import OffcanvasHeader from "react-bootstrap/OffcanvasHeader";
+import Stack from "react-bootstrap/Stack";
+import { Item, ItemParams, Menu, useContextMenu } from "react-contexify";
+import { toast } from "react-toastify";
+import { useWindowArea } from "taehui-ts/fe-utilities";
+
+const EventPB = require("@/Event_pb");
+
+export default observer(({ siteView }: { siteView: SiteView }) => {
+ const {
+ siteID,
+ siteName,
+ siteYellItems,
+ siteNotify,
+ isPendingSiteYellOpened,
+ lastPendingSiteYell,
+ isAvatarsViewOpened,
+ avatars,
+ isSiteHand,
+ setSiteYellsViewLowest,
+ setPendingSiteYellOpened,
+ setAvatarsViewOpened,
+ setSiteYellsView,
+ } = siteView;
+
+ const { titleView, targetSiteID } = useSiteStore();
+
+ const { push } = useRouter();
+
+ const t = useTranslations();
+
+ const siteYellsView = useRef(null);
+ const siteInputView = useRef(null);
+
+ const [siteYellsViewHeight, setSiteYellsViewHeight] = useState("");
+
+ const { windowLength, windowHeight } = useWindowArea();
+
+ useLayoutEffect(() => {
+ const tabs = document.getElementById("tabsView");
+ const title = titleView?.current;
+ const siteInput = siteInputView.current;
+ if (title && tabs && siteInput) {
+ const { height: titleHeight } = title.getBoundingClientRect();
+ const { height: tabsHeight } = tabs.getBoundingClientRect();
+ const { height: siteInputHeight } = siteInput.getBoundingClientRect();
+ setSiteYellsViewHeight(
+ `${windowHeight - 19.5 * 2 - titleHeight - tabsHeight - 2 * 2 - siteInputHeight}px`,
+ );
+ }
+ }, [titleView, windowLength, windowHeight, targetSiteID]);
+
+ const { show: viewSiteYellInput } = useContextMenu({
+ id: "siteYell",
+ });
+ const { show: viewAvatarInput } = useContextMenu({
+ id: "avatar",
+ });
+
+ const onViewAvatar = ({ props: { avatarID } }: ItemParams) => {
+ if (avatarID.startsWith("*")) {
+ toast.warning(t("notAvatarViewFault"));
+ } else {
+ push(`/avatar/!${getDefaultAvatarID(avatarID)}`);
+ }
+ };
+
+ const onSiteYellInput: OnSiteYellInput = (event, avatarID) => {
+ viewSiteYellInput({ event, props: { avatarID } });
+ };
+
+ useEffect(() => {
+ setSiteYellsView(siteYellsView);
+ }, [setSiteYellsView]);
+
+ useEffect(() => {
+ const { current } = siteYellsView;
+
+ if (current) {
+ const onSiteYellsViewMove = () => {
+ const { current } = siteYellsView;
+ if (current) {
+ const siteYellID = siteYellItems[0]?.siteYellID;
+ if (siteYellID && siteYellID > 0 && current.scrollTop === 0) {
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.GET_SITE_YELLS,
+ text: JSON.stringify({
+ siteID,
+ siteYellID: siteYellID,
+ }),
+ });
+ }
+
+ const { height } = current.getBoundingClientRect();
+
+ const isSiteYellsViewLowest =
+ Math.ceil(current.scrollTop + height) >= current.scrollHeight;
+ setSiteYellsViewLowest(isSiteYellsViewLowest);
+ if (isSiteYellsViewLowest) {
+ setPendingSiteYellOpened(false);
+ }
+ }
+ };
+
+ current.addEventListener("scroll", onSiteYellsViewMove);
+
+ return () => {
+ current.removeEventListener("scroll", onSiteYellsViewMove);
+ };
+ }
+ }, [setPendingSiteYellOpened, setSiteYellsViewLowest, siteID, siteYellItems]);
+
+ return (
+ <>
+
+ {lastPendingSiteYell && (
+
+ )}
+
+
+
+ {siteNotify}
+
+
+
+
+
+ {siteYellItems.map((siteYellItem) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ {
+ setAvatarsViewOpened(false);
+ }}
+ >
+
+
+ {siteName} ({t("avatarCountText", { avatarCount: avatars.length })})
+
+
+
+
+ {avatars.map(
+ ({
+ avatarID,
+ avatarName,
+ avatarConfigure,
+ isSiteHand,
+ isMe,
+ isValve,
+ isAudioInput,
+ }) => (
+
+ {
+ viewAvatarInput({ event, props: { avatarID } });
+ }}
+ />
+
+ ),
+ )}
+
+
+
+
+
+ >
+ );
+});
diff --git "a/qwilight-fe/src/app/\133language\135/site/lib/useWSAPI.tsx" "b/qwilight-fe/src/app/\133language\135/site/lib/useWSAPI.tsx"
index d0381b0..585cda4 100644
--- "a/qwilight-fe/src/app/\133language\135/site/lib/useWSAPI.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/lib/useWSAPI.tsx"
@@ -33,9 +33,9 @@
useEffect(() => {
setVisible();
- setEventHandler(t);
+ setEventHandler();
setEventCloseHandler();
- }, [setEventCloseHandler, setEventHandler, setVisible, t]);
+ }, [setEventCloseHandler, setEventHandler, setVisible]);
const language = useLanguage();
diff --git "a/qwilight-fe/src/app/\133language\135/site/lib/wsAPI.ts" "b/qwilight-fe/src/app/\133language\135/site/lib/wsAPI.ts"
index ea41a25..d563e60 100644
--- "a/qwilight-fe/src/app/\133language\135/site/lib/wsAPI.ts"
+++ "b/qwilight-fe/src/app/\133language\135/site/lib/wsAPI.ts"
@@ -15,7 +15,7 @@
eventCloseHandler: CloseEventHandler;
onLoaded: () => void;
onData: ({ data }: { data: MessageEvent }) => void;
- onClosed: () => void;
+ onClosed: (e: CloseEvent) => void;
language?: ReturnType;
constructor() {
@@ -44,7 +44,7 @@
} catch (e) {}
};
- this.onClosed = () => {
+ this.onClosed = (e) => {
this.eventCloseHandler();
this.connect();
};
diff --git "a/qwilight-fe/src/app/\133language\135/site/loading.tsx" "b/qwilight-fe/src/app/\133language\135/site/loading.tsx"
index 3f6c8ce..10e0631 100644
--- "a/qwilight-fe/src/app/\133language\135/site/loading.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/loading.tsx"
@@ -1,8 +1,5 @@
-import LoadingLayer from "@/components/LoadingLayer";
-import { useTranslations } from "next-intl";
+import DefaultLoading from "@/components/DefaultLoading";
export default function Loading() {
- const t = useTranslations();
-
- return ;
+ 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"
deleted file mode 100644
index 5bbb208..0000000
--- "a/qwilight-fe/src/app/\133language\135/site/page.module.scss"
+++ /dev/null
@@ -1,5 +0,0 @@
-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"
index d5c3751..891b7e3 100644
--- "a/qwilight-fe/src/app/\133language\135/site/page.tsx"
+++ "b/qwilight-fe/src/app/\133language\135/site/page.tsx"
@@ -1,342 +1,85 @@
"use client";
-import AvatarItems from "@/app/[language]/site/components/AvatarItems";
import ConfigureWindow from "@/app/[language]/site/components/ConfigureWindow";
-import SiteInput from "@/app/[language]/site/components/SiteInput";
import SiteWindow from "@/app/[language]/site/components/SiteWindow";
-import SiteYellItem from "@/app/[language]/site/components/SiteYellItem";
-import SiteYellItems from "@/app/[language]/site/components/SiteYellItems";
import wsAPI from "@/app/[language]/site/lib/wsAPI";
import Loading from "@/app/[language]/site/loading";
-import scss from "@/app/[language]/site/page.module.scss";
-import { OnSiteYellInput } from "@/app/[language]/site/type";
import { useSiteStore } from "@/state/Stores";
-import { getDefaultAvatarID } from "@/utilities/Utility";
-import { useQueryClient } from "@tanstack/react-query";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { usePathname } from "next/navigation";
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
-import { Item, ItemParams, Menu, useContextMenu } from "react-contexify";
-import { toast } from "react-toastify";
-import {
- Alert,
- Button,
- Col,
- Offcanvas,
- OffcanvasBody,
- OffcanvasHeader,
- Row,
-} from "reactstrap";
+import { useEffect, useMemo } from "react";
+import Tab from "react-bootstrap/Tab";
+import Tabs from "react-bootstrap/Tabs";
+import { Item, Menu, useContextMenu } from "react-contexify";
import Swal from "sweetalert2";
-import { useTo } from "taehui-ts/fe-utilities";
+import { useIsPath } from "taehui-ts/fe-utilities";
+import SiteYellsView from "./components/SiteYellsView";
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,
+ setTargetSiteID,
} = 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();
+ const isPath = useIsPath();
useEffect(() => {
- if (pathname === "/site") {
- siteYellsViewMove();
+ if (isPath("/site")) {
+ getSiteView(targetSiteID)?.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/!${getDefaultAvatarID(avatarID)}`);
- }
- };
+ }, [getSiteView, isPath, targetSiteID]);
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]);
-
- 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) {
- wsAPI.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, 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 (
-
- {
- onSiteIDModified(siteID);
- }}
- onContextMenu={(event) => {
- event.preventDefault();
- viewSiteNameInput({ event });
- }}
- >
- {siteName}
-
-
- );
- })}
-
- {
- await queryClient.invalidateQueries({ queryKey: ["sites"] });
- setSiteWindowOpened(true);
- }}
- >
- {t("onSiteWindow")}
-
-
- {targetSiteID && (
-
- {
- wsAPI.send({
- eventID: EventPB.Event("EventID.QUIT_SITE"),
- text: targetSiteID,
- });
- }}
- color="danger"
- >
- {t("quitSite")}
-
-
- )}
-
-
-
-
-
-
- {siteNotify}
-
-
-
-
-
-
-
- {lastPendingSiteYell && (
-
- )}
-
-
-
-
- {
+ setTargetSiteID(eventKey ?? "");
+ }}
+ onContextMenu={(event) => {
+ event.preventDefault();
+ viewSiteNameInput({ event });
}}
>
-
-
-
- setAvatarsOpened(false)}
- >
- setAvatarsOpened(false)}>
- {t("avatarCountText", { avatarCount: avatars.length })}
-
-
- {
- viewAvatarInput({ event, props: { avatarID } });
- }}
- />
-
-
-
-
-
-
+
+
+ ))}
+
-
-
-
-
>
diff --git "a/qwilight-fe/src/app/\133language\135/site/state/setSiteStore.ts" "b/qwilight-fe/src/app/\133language\135/site/state/setSiteStore.ts"
index 9d218bb..0ab2370 100644
--- "a/qwilight-fe/src/app/\133language\135/site/state/setSiteStore.ts"
+++ "b/qwilight-fe/src/app/\133language\135/site/state/setSiteStore.ts"
@@ -2,8 +2,7 @@
import {
AbilitySiteYell,
Avatar,
- SiteView,
- SiteYell,
+ SiteYellItem,
} from "@/app/[language]/site/type";
import {
formatText,
@@ -14,14 +13,138 @@
} from "@/utilities/Utility";
import { wwwAPIPath } from "@/utilities/wwwAPI";
import CryptoJS from "crypto-js";
-import { runInAction } from "mobx";
+import { makeAutoObservable } from "mobx";
import { useTranslations } from "next-intl";
import { RefObject } from "react";
import { toast } from "react-toastify";
const EventPB = require("@/Event_pb");
-const getSiteYellItem = ({
+export class SiteView {
+ siteID = "";
+ isEditable = false;
+ isNew = false;
+ wasNotify = false;
+ siteNotify = "";
+ siteName = "";
+ isNetMode = false;
+ avatars = [] as Avatar[];
+ siteHand = "";
+ situationValue = 0;
+ siteYellItems = [] as SiteYellItem[];
+ lastPendingSiteYell = undefined as SiteYellItem | undefined;
+ isPendingSiteYellOpened = false;
+ isSiteYellsViewLowest = false;
+ isAvatarsViewOpened = false;
+ isSiteHand = false;
+ textInput = "";
+ siteYellsView = undefined as RefObject | undefined;
+
+ constructor(
+ siteID: string,
+ siteNotify: string,
+ isEditable: boolean,
+ isNetMode: boolean,
+ siteYellItems: SiteYellItem[],
+ ) {
+ this.siteID = siteID;
+ this.siteNotify = siteNotify;
+ this.isEditable = isEditable;
+ this.isNetMode = isNetMode;
+ this.siteYellItems = siteYellItems;
+
+ makeAutoObservable(this);
+ }
+
+ setSiteYell(targetSiteYellID: number, siteYell: string) {
+ const targetSiteYell = this.siteYellItems.find(
+ ({ siteYellID }) => siteYellID === targetSiteYellID,
+ );
+ if (targetSiteYell) {
+ targetSiteYell.siteYell = siteYell;
+ }
+ }
+
+ setSiteYellsView = (siteYellsView: RefObject) => {
+ this.siteYellsView = siteYellsView;
+ };
+
+ putSiteYell(siteYellItem: SiteYellItem, isGetSiteYell: boolean) {
+ if (isGetSiteYell) {
+ this.siteYellItems.unshift(siteYellItem);
+ } else {
+ this.siteYellItems.push(siteYellItem);
+ }
+ }
+
+ siteYellsViewMove() {
+ setTimeout(() => {
+ if (this.siteYellsView) {
+ const { current } = this.siteYellsView;
+ if (current) {
+ current.scrollTop = current.scrollHeight;
+ }
+ }
+ }, 0);
+ }
+
+ setLastPendingSiteYell = (siteYellItem: SiteYellItem) => {
+ this.lastPendingSiteYell = siteYellItem;
+ this.isPendingSiteYellOpened = true;
+ };
+
+ setNew = (isNew: boolean) => {
+ this.isNew = isNew;
+ };
+
+ setSiteNotify = (siteNotify: string) => {
+ this.siteNotify = siteNotify;
+ };
+
+ setPendingSiteYellOpened = (isPendingSiteYellOpened: boolean) => {
+ this.isPendingSiteYellOpened = isPendingSiteYellOpened;
+ };
+
+ setAvatarsViewOpened = (isAvatarsViewOpened: boolean) => {
+ this.isAvatarsViewOpened = isAvatarsViewOpened;
+ };
+
+ doCallSiteAvatar = (
+ siteName: string,
+ siteHand: string,
+ situationValue: number,
+ avatars: Avatar[],
+ ) => {
+ this.siteName = siteName;
+ this.siteHand = siteHand;
+ this.situationValue = situationValue;
+ this.avatars = avatars;
+ };
+
+ setSiteYellsViewLowest = (isSiteYellsViewLowest: boolean) => {
+ this.isSiteYellsViewLowest = isSiteYellsViewLowest;
+ };
+
+ wipeSiteYell = (siteYellID: number) => {
+ const i = this.siteYellItems.findIndex(
+ (siteYellItem) => siteYellItem.siteYellID === siteYellID,
+ );
+ const siteYellItem = this.siteYellItems[i];
+ this.siteYellItems.splice(i, 1, {
+ siteYellID,
+ avatarID: siteYellItem.avatarID,
+ avatarName: siteYellItem.avatarName,
+ siteYellVariety: "@Wiped",
+ date: siteYellItem.date,
+ });
+ };
+
+ setTextInput = (textInput: string) => {
+ this.textInput = textInput;
+ };
+}
+
+const getSiteYell = ({
avatarID,
avatarName,
siteYell,
@@ -33,7 +156,7 @@
siteYell: string;
date: number;
siteYellID: number;
-}): SiteYell | null => {
+}): SiteYellItem => {
const dateText = new Date(date).toLocaleTimeString();
switch (avatarName) {
case "@Enter":
@@ -114,19 +237,16 @@
}
};
-export default function setSiteStore() {
+export default function setSiteStore(
+ t: ReturnType>,
+) {
return {
- titleComponent: undefined as RefObject | undefined,
- siteYellsView: undefined as RefObject | undefined,
- avatars: [] as Avatar[],
- siteYells: [] as SiteYell[],
- isLogInOpened: false,
+ titleView: undefined as RefObject | undefined,
isSiteWindowOpened: false,
isSiteCipherWindowOpened: false,
isNewSiteWindowOpened: false,
isConfigureOpened: false,
targetSiteID: "",
- siteNotify: "",
saveTraffic:
typeof window === "object" &&
window.localStorage.getItem("saveTraffic") === "true",
@@ -139,28 +259,18 @@
autoEnterPlatform:
typeof window === "object" &&
window.localStorage.getItem("autoEnterPlatform") !== "false",
- isEditable: true,
- input: "",
siteViews: [] as SiteView[],
siteAvatarID: "",
siteAvatarName: "",
isLoggedIn: false,
- isSiteYellsViewLowest: true,
isVisible: false,
isLoading: true,
- lastPendingSiteYell: undefined as SiteYell | undefined,
- isPendingSiteYellOpened: false,
- isAvatarsOpened: false,
- setComponents(
- titleComponent: RefObject,
- siteYellsView: RefObject,
- ) {
- this.titleComponent = titleComponent;
- this.siteYellsView = siteYellsView;
+ setTitleView(titleView: RefObject) {
+ this.titleView = titleView;
},
- setEventHandler(t: ReturnType>) {
+ setEventHandler() {
const autoEnter = () => {
wsAPI.send({
eventID: EventPB.Event.EventID.ENTER_SITE,
@@ -222,8 +332,8 @@
if (siteView?.wasNotify === false) {
new Notification("Qwilight", {
body: toNotify,
- icon: `${wwwAPIPath}/drawing?avatarID=${encodeURIComponent(
- getDefaultAvatarID(avatarID),
+ icon: `${wwwAPIPath}/drawing?avatarID=${getDefaultAvatarID(
+ avatarID,
)}&drawingVariety=0`,
});
siteView.wasNotify = true;
@@ -256,7 +366,6 @@
// EventPB.Event.EventID.LOG_IN
case undefined:
if (text) {
- this.setLogInOpened(false);
const { totem, avatarID, avatarName } = JSON.parse(text);
if (totem !== window.sessionStorage.getItem("totem")) {
toast.success(t("loggedInText", { avatarName }));
@@ -291,148 +400,139 @@
siteYellID,
date,
} = JSON.parse(text);
- const siteYellItem = getSiteYellItem({
+ const siteYellItem = getSiteYell({
avatarID,
avatarName,
siteYell,
date,
siteYellID,
});
- if (siteYellItem) {
- this.putSiteYell(siteID, siteYellItem, false);
+ const siteView = this.getSiteView(siteID);
+ if (siteView) {
+ siteView.putSiteYell(siteYellItem, false);
if (this.targetSiteID === siteID) {
- this.putTargetSiteYell(siteYellItem, false);
if (
avatarID === this.siteAvatarID ||
- this.isSiteYellsViewLowest
+ siteView.isSiteYellsViewLowest
) {
- this.siteYellsViewMove();
+ siteView.siteYellsViewMove();
} else {
- runInAction(() => {
- this.lastPendingSiteYell = siteYellItem;
- });
- this.setPendingSiteYellOpened(true);
+ siteView.setLastPendingSiteYell(siteYellItem);
}
} else {
- this.setModifiedSiteViews(siteID, (siteView) => {
- siteView.isNew = true;
- });
+ siteView.setNew(true);
}
- }
- const ltDate = new Date(Number(date)).toLocaleTimeString();
- let toNotify = "";
- switch (avatarName) {
- case "@Notify":
- if (this.targetSiteID === siteID) {
- this.siteNotify = siteYell;
- } else {
- const siteView = this.getSiteView(siteID);
- if (siteView) {
- siteView.siteNotify = siteYell;
- }
+ const ltDate = new Date(Number(date)).toLocaleTimeString();
+ let toNotify = "";
+ switch (avatarName) {
+ case "@Notify":
+ siteView.setSiteNotify(siteYell);
+ toNotify = `${t("siteYellTaehui")} (${ltDate}) ${siteYell}`;
+ break;
+ case "@Comment": {
+ const {
+ avatarName,
+ artist,
+ title,
+ genre,
+ levelText,
+ stand,
+ } = JSON.parse(siteYell);
+ toNotify = `${avatarName} (${ltDate}) ${levelText} ${artist} - ${title} ${getGenreText(
+ genre,
+ )} ${t("textStand", { value: formatText(stand) })}`;
+ break;
}
- toNotify = `${t("siteYellTaehui")} (${ltDate}) ${siteYell}`;
- break;
- case "@Comment": {
- const { avatarName, artist, title, genre, levelText, stand } =
- JSON.parse(siteYell);
- toNotify = `${avatarName} (${ltDate}) ${levelText} ${artist} - ${title} ${getGenreText(
- genre,
- )} ${t("textStand", { value: formatText(stand) })}`;
- break;
+ case "@Ability": {
+ toNotify = getAbilityUpText(
+ t,
+ JSON.parse(siteYell) as AbilitySiteYell,
+ );
+ break;
+ }
+ case "@Level": {
+ const { title } = JSON.parse(siteYell);
+ toNotify = t("wwwLevelClearText", { title });
+ break;
+ }
+ case "@Enter": {
+ toNotify = `${siteYell} ${ltDate} ${t("siteYellEnter")}`;
+ break;
+ }
+ case "@Quit": {
+ toNotify = `${siteYell} ${ltDate} ${t("siteYellQuit")}`;
+ break;
+ }
+ case "@Invite": {
+ const { avatarName, siteName } = JSON.parse(siteYell);
+ toNotify = `${avatarName} (${ltDate}) ${t(
+ "siteYellInvite",
+ {
+ siteName,
+ },
+ )}`;
+ break;
+ }
+ case "@TV": {
+ const { title, text } = JSON.parse(siteYell);
+ toNotify = `${text} (${ltDate}) ${t("siteYellTV", {
+ title,
+ })}`;
+ break;
+ }
+ case "@Wiped":
+ toNotify = `${avatarName} (${ltDate}) ${t("wipedSiteYell")}`;
+ break;
+ case "":
+ toNotify = siteYell;
+ break;
+ case null:
+ toNotify = `${avatarName} (${ltDate}) ${siteYell}`;
+ break;
}
- case "@Ability": {
- toNotify = getAbilityUpText(
- t,
- JSON.parse(siteYell) as AbilitySiteYell,
- );
- break;
+ if (toNotify) {
+ doNotify(avatarID, toNotify, siteID);
}
- case "@Level": {
- const { title } = JSON.parse(siteYell);
- toNotify = t("wwwLevelClearText", { title });
- break;
- }
- case "@Enter": {
- toNotify = `${siteYell} ${ltDate} ${t("siteYellEnter")}`;
- break;
- }
- case "@Quit": {
- toNotify = `${siteYell} ${ltDate} ${t("siteYellQuit")}`;
- break;
- }
- case "@Invite": {
- const { avatarName, siteName } = JSON.parse(siteYell);
- toNotify = `${avatarName} (${ltDate}) ${t("siteYellInvite", {
- siteName,
- })}`;
- break;
- }
- case "@TV": {
- const { title, text } = JSON.parse(siteYell);
- toNotify = `${text} (${ltDate}) ${t("siteYellTV", {
- title,
- })}`;
- break;
- }
- case "@Wiped":
- toNotify = `${avatarName} (${ltDate}) ${t("wipedSiteYell")}`;
- break;
- case "":
- toNotify = siteYell;
- break;
- case null:
- toNotify = `${avatarName} (${ltDate}) ${siteYell}`;
- break;
- }
- if (toNotify) {
- doNotify(avatarID, toNotify, siteID);
}
}
break;
case EventPB.Event.EventID.MODIFY_SITE_YELL:
if (text) {
const { siteID, siteYell, siteYellID } = JSON.parse(text);
- this.doModifySiteYell(siteID, siteYell, siteYellID);
- if (this.targetSiteID === siteID) {
- this.doModifyTargetSiteYell(siteYell, siteYellID);
- }
+ this.getSiteView(siteID)?.setSiteYell(siteYellID, siteYell);
}
break;
case EventPB.Event.EventID.WIPE_SITE_YELL:
if (text) {
const { siteID, siteYellID } = JSON.parse(text);
- this.wipeSiteYell(siteID, siteYellID);
- if (this.targetSiteID === siteID) {
- this.wipeTargetSiteYell(siteYellID);
- }
+ this.getSiteView(siteID)?.wipeSiteYell(siteYellID);
}
break;
case EventPB.Event.EventID.GET_SITE_YELLS:
if (text) {
- if (this.siteYellsView) {
- const { current } = this.siteYellsView;
- if (current) {
- const lastPosition1BeforeCalled =
- current.scrollHeight - current.clientHeight;
- const { siteID, data } = JSON.parse(text);
+ const { siteID, data } = JSON.parse(text);
+ const siteView = this.getSiteView(siteID);
+ if (siteView) {
+ if (siteView.siteYellsView) {
+ const { current } = siteView.siteYellsView;
+ if (current) {
+ const lastPosition1BeforeCalled =
+ current.scrollHeight - current.clientHeight;
- data
- .reverse()
- .map(getSiteYellItem)
- .forEach((siteYellItem: SiteYell) => {
- this.putSiteYell(siteID, siteYellItem, true);
- if (this.targetSiteID === siteID) {
- this.putTargetSiteYell(siteYellItem, true);
- }
- });
+ data
+ .reverse()
+ .map(getSiteYell)
+ .forEach((siteYellItem: SiteYellItem) => {
+ siteView.putSiteYell(siteYellItem, true);
+ });
- setTimeout(() => {
- current.scrollTop =
- current.scrollHeight -
- current.clientHeight -
- lastPosition1BeforeCalled;
- }, 0);
+ setTimeout(() => {
+ current.scrollTop =
+ current.scrollHeight -
+ current.clientHeight -
+ lastPosition1BeforeCalled;
+ }, 0);
+ }
}
}
}
@@ -441,21 +541,22 @@
if (text) {
const { siteID, siteName, situationValue, data, siteHand } =
JSON.parse(text);
- const avatars = data.map(
- ({
- avatarID,
- avatarName,
- avatarConfigure,
- isValve,
- isAudioInput,
- }: {
- avatarID: string;
- avatarName: string;
- avatarConfigure: number;
- isValve: boolean;
- isAudioInput: boolean;
- }) => {
- return {
+ const siteView = this.getSiteView(siteID);
+ if (siteView) {
+ const avatars = data.map(
+ ({
+ avatarID,
+ avatarName,
+ avatarConfigure,
+ isValve,
+ isAudioInput,
+ }: {
+ avatarID: string;
+ avatarName: string;
+ avatarConfigure: number;
+ isValve: boolean;
+ isAudioInput: boolean;
+ }) => ({
avatarID,
avatarName,
avatarConfigure,
@@ -463,17 +564,14 @@
isMe: this.siteAvatarID === avatarID,
isValve,
isAudioInput,
- };
- },
- );
- this.setModifiedSiteViews(siteID, (siteView) => {
- siteView.siteName = getSiteName(siteName, t);
- siteView.avatars = avatars;
- siteView.siteHand = siteHand;
- siteView.situationValue = situationValue;
- });
- if (siteID === this.targetSiteID) {
- this.setAvatars(avatars);
+ }),
+ );
+ siteView.doCallSiteAvatar(
+ getSiteName(siteName, t),
+ siteHand,
+ situationValue,
+ avatars,
+ );
}
}
break;
@@ -481,28 +579,20 @@
if (text) {
const { siteID, siteNotify, isEditable, isNetMode, data } =
JSON.parse(text);
- this.putSiteView({
+ const siteView = new SiteView(
siteID,
- isEditable,
- isNew: false,
- wasNotify: false,
siteNotify,
- siteName: "",
- siteHand: "",
- situationValue: 0,
+ isEditable,
isNetMode,
- avatars: [],
- siteYells: data.map(getSiteYellItem),
- });
- this.onSiteIDModified(siteID);
+ data.map(getSiteYell),
+ );
+ this.putSiteView(siteView);
+ this.setTargetSiteID(siteID);
}
break;
case EventPB.Event.EventID.QUIT_SITE:
if (text) {
- this.quitSiteView(text);
- this.onSiteIDModified(
- this.siteViews[this.siteViews.length - 1]?.siteID,
- );
+ this.wipeSiteView(text);
}
break;
case EventPB.Event.EventID.WARNING:
@@ -516,7 +606,7 @@
break;
case EventPB.Event.EventID.POST_FILE:
if (text) {
- this.setInput(text);
+ this.getSiteView(this.targetSiteID)?.setTextInput(text);
}
break;
}
@@ -527,16 +617,11 @@
wsAPI.setEventCloseHandler(() => {
this.setSiteAvatar("", "");
this.setLoggedIn(false);
- this.onSiteIDModified("");
this.wipeSiteViews();
this.setLoading(true);
});
},
- setPendingSiteYellOpened(isPendingSiteYellOpened: boolean) {
- this.isPendingSiteYellOpened = isPendingSiteYellOpened;
- },
-
setLoading(isLoading: boolean) {
this.isLoading = isLoading;
},
@@ -547,88 +632,6 @@
wsAPI.setAvatarID(this.siteAvatarID);
},
- putSiteYell(siteID: string, siteYell: SiteYell, isGetSiteYell: boolean) {
- const siteView = this.getSiteView(siteID);
- if (isGetSiteYell) {
- siteView?.siteYells?.unshift(siteYell);
- } else {
- siteView?.siteYells?.push(siteYell);
- }
- },
-
- putTargetSiteYell(siteYell: SiteYell, isGetSiteYell: boolean) {
- if (isGetSiteYell) {
- this.siteYells.unshift(siteYell);
- } else {
- this.siteYells.push(siteYell);
- }
- },
-
- doModifySiteYell(siteID: string, siteYell: string, siteYellID: number) {
- const targetSiteYell = this.getSiteView(siteID)?.siteYells?.find(
- (siteYell) => siteYell.siteYellID === siteYellID,
- );
- if (targetSiteYell) {
- targetSiteYell.siteYell = siteYell;
- }
- },
-
- doModifyTargetSiteYell(siteYell: string, siteYellID: number) {
- const targetSiteYell = this.siteYells?.find(
- (siteYell) => siteYell.siteYellID === siteYellID,
- );
- if (targetSiteYell) {
- targetSiteYell.siteYell = siteYell;
- }
- },
-
- wipeSiteYell(siteID: string, siteYellID: number) {
- const siteYells = this.getSiteView(siteID)?.siteYells;
- if (siteYells) {
- const i = siteYells.findIndex(
- (siteYell) => siteYell.siteYellID === siteYellID,
- );
- const siteYell = siteYells[i];
- siteYells.splice(i, 1, {
- siteYellID,
- avatarID: siteYell.avatarID,
- avatarName: siteYell.avatarName,
- siteYellVariety: "@Wiped",
- date: siteYell.date,
- });
- }
- },
-
- wipeTargetSiteYell(siteYellID: number) {
- const i = this.siteYells.findIndex(
- (siteYell) => siteYell.siteYellID === siteYellID,
- );
- const siteYell = this.siteYells[i];
- this.siteYells.splice(i, 1, {
- siteYellID,
- avatarID: siteYell.avatarID,
- avatarName: siteYell.avatarName,
- siteYellVariety: "@Wiped",
- date: siteYell.date,
- });
- },
-
- setModifiedSiteViews(
- targetSiteID: string,
- onModified: (siteView: SiteView) => void,
- ) {
- const tmpSiteView = this.siteViews.find(
- ({ siteID }) => targetSiteID === siteID,
- );
- if (tmpSiteView) {
- onModified(tmpSiteView);
- }
- },
-
- setInput(input: string) {
- this.input = input;
- },
-
setSaveTraffic(SaveTraffic: boolean) {
this.saveTraffic = SaveTraffic;
},
@@ -645,10 +648,6 @@
this.autoEnterPlatform = autoEnterPlatform;
},
- setLogInOpened(isLogInOpened: boolean) {
- this.isLogInOpened = isLogInOpened;
- },
-
setSiteWindowOpened(isSiteWindowOpened: boolean) {
this.isSiteWindowOpened = isSiteWindowOpened;
},
@@ -665,34 +664,15 @@
this.isConfigureOpened = isConfigureOpened;
},
- setSiteYellsViewLowest(isSiteYellsViewLowest: boolean) {
- this.isSiteYellsViewLowest = isSiteYellsViewLowest;
- },
-
getSiteView(targetSiteID: string) {
return this.siteViews.find(({ siteID }) => siteID === targetSiteID);
},
- onSiteIDModified(siteID: string) {
- this.targetSiteID = siteID;
- const siteView = this.getSiteView(siteID);
+ setTargetSiteID(targetSiteID: string) {
+ this.targetSiteID = targetSiteID;
+ const siteView = this.getSiteView(this.targetSiteID);
if (siteView) {
- if (this.isVisible) {
- siteView.wasNotify = false;
- }
- this.setModifiedSiteViews(siteID, (siteView) => {
- siteView.isNew = false;
- });
- this.isEditable = siteView.isEditable;
- this.siteNotify = siteView.siteNotify;
- this.avatars = [...siteView.avatars];
- this.siteYells = [...siteView.siteYells];
- this.siteYellsViewMove();
- } else {
- this.isEditable = false;
- this.siteNotify = "";
- this.avatars = [];
- this.siteYells = [];
+ siteView.setNew(false);
}
},
@@ -700,42 +680,25 @@
return (this.isVisible = document.visibilityState === "visible");
},
- siteYellsViewMove() {
- setTimeout(() => {
- if (this.siteYellsView) {
- const { current } = this.siteYellsView;
- if (current) {
- current.scrollTop = current.scrollHeight;
- }
- }
- }, 0);
- },
-
- setAvatarsOpened(isAvatarsOpened: boolean) {
- this.isAvatarsOpened = isAvatarsOpened;
- },
-
setLoggedIn(isLoggedIn: boolean) {
this.isLoggedIn = isLoggedIn;
},
- setAvatars(avatars: Avatar[]) {
- this.avatars = avatars;
- },
-
putSiteView(siteView: SiteView) {
this.siteViews.push(siteView);
},
- quitSiteView(siteID: string) {
+ wipeSiteView(targetSiteID: string) {
this.siteViews.splice(
- this.siteViews.findIndex((siteView) => siteView.siteID === siteID),
+ this.siteViews.findIndex(({ siteID }) => siteID === targetSiteID),
1,
);
+ this.targetSiteID = this.siteViews[this.siteViews.length - 1].siteID;
},
wipeSiteViews() {
this.siteViews = [];
+ this.targetSiteID = "";
},
};
}
diff --git "a/qwilight-fe/src/app/\133language\135/site/type/index.d.ts" "b/qwilight-fe/src/app/\133language\135/site/type/index.d.ts"
index ac2bda1..be9fb9f 100644
--- "a/qwilight-fe/src/app/\133language\135/site/type/index.d.ts"
+++ "b/qwilight-fe/src/app/\133language\135/site/type/index.d.ts"
@@ -10,7 +10,7 @@
isAudioInput: boolean;
};
-export type SiteYell = {
+export type SiteYellItem = {
avatarID?: string;
avatarName?: string;
siteYellVariety: ?string;
@@ -62,20 +62,6 @@
text: string;
};
-export type SiteView = {
- siteID: string;
- isEditable: boolean;
- isNew: boolean;
- wasNotify: boolean;
- siteNotify: string;
- siteName: string;
- isNetMode: boolean;
- avatars: Avatar[];
- siteHand: string;
- situationValue: number;
- siteYells: SiteYell[];
-};
-
export type Event = { eventID: number; text?: string; data?: ArrayBuffer[] };
export type EventHandler = (data: Event) => void;
diff --git a/qwilight-fe/src/app/globals.scss b/qwilight-fe/src/app/globals.scss
index f14bcd9..ec98da1 100644
--- a/qwilight-fe/src/app/globals.scss
+++ b/qwilight-fe/src/app/globals.scss
@@ -1,112 +1,19 @@
-@mixin default() {
- font-family: "Century Gothic", sans-serif;
- font-size: 0.75rem;
-}
-
-* {
- &.route {
- cursor: pointer;
- }
-}
-
-a {
- &.nav-link {
- @include default();
- color: white;
-
- &:hover {
- @include default();
- color: white;
- }
- }
-}
+@import "~bootstrap/scss/bootstrap";
+@import "~taehui-ts/globals";
body {
background: url("../assets/dark-honeycomb.png");
}
-button {
- &.btn {
- @include default();
- }
-
- &.page-link {
- @include default();
- }
-
- &.dropdown-item {
- @include default();
- }
-}
-
-input[type="button"],
-input[type="password"],
-input[type="submit"],
-input[type="search"],
-input[type="text"] {
- @include default();
-}
-
-li {
- &.page-item {
- @include default();
- }
-
- &.list-group-item {
- background-color: rgba(0, 0, 0, 0.125);
- border: none;
- }
-}
-
-div {
- &.offcanvas-body {
- background-color: black;
- }
-
- &.target {
- border: thin solid;
- border-image: linear-gradient(43deg, #4158d0 0%, #c850c0 46%, #ffcc70 100%);
- }
-}
-
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;
+ &.artist {
+ color: lightgray;
}
&.date {
color: darkgray;
}
- &.stand {
- color: white;
- }
-
- &.point {
- color: white;
- }
-
- &.band {
- color: white;
- }
-
- &.title {
- color: white;
- }
-
&.genre {
color: darkgray;
}
@@ -115,10 +22,6 @@
color: dodgerblue;
}
- &.artist {
- color: lightgray;
- }
-
&.level0 {
color: darkgray;
}
@@ -149,28 +52,8 @@
-webkit-text-fill-color: transparent;
}
- &.highestJudgment {
- color: cyan;
- }
-
- &.higherJudgment {
- color: deepskyblue;
- }
-
- &.highJudgment {
- color: lightgreen;
- }
-
- &.lowJudgment {
- color: yellow;
- }
-
- &.lowerJudgment {
- color: mediumpurple;
- }
-
- &.lowestJudgment {
- color: red;
+ &.quit {
+ font-size: xx-large;
}
&.S\+ {
@@ -200,16 +83,4 @@
&.D {
color: red;
}
-
- &.audioMultiplier {
- color: white;
- }
-
- &.avatarPlace {
- font-size: 1.5rem;
- }
-
- &.avatarIntro {
- white-space: pre-line;
- }
}
diff --git a/qwilight-fe/src/assets/language/en.json b/qwilight-fe/src/assets/language/en.json
index 46d305b..78d9219 100644
--- a/qwilight-fe/src/assets/language/en.json
+++ b/qwilight-fe/src/assets/language/en.json
@@ -1,21 +1,24 @@
{
"abilityFittedText": "{stand} Points (+ {ability} Points)",
- "audioMultiplier": "Music speed",
"autoLogIn": "Automatic login",
- "avatarAbilitiesText": "Rating TOP 50",
+ "avatar": "Online Profile",
+ "avatarAbilityTitle": "Rating TOP 50",
+ "avatarCipher": "Password",
"avatarCountText": "{avatarCount} people",
"avatarDate": "Last Connection Date: {date}",
"avatarDateText": "Activity Trends",
- "avatarFavoritesText": "Most plays TOP 50",
+ "avatarFavoritesTitle": "Most plays TOP 50",
+ "avatarID": "ID",
"avatarIntroText": "Introduce yourself",
- "avatarLastsText": "Last plays TOP 50",
+ "avatarLastsTitle": "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 taehui@taehui.ddns.net and delete it.",
"commentSiteName": "Performance notification room",
"defaultSiteName": "General chat room",
- "enterSite": "Enter",
+ "etc": "Statistics",
"etcAutoMode": "Turntable",
"etcAvatar": "Activity User Trends",
+ "etcEnroll": "New Subscription Trends",
"etcFaintNoteMode": "Note time",
"etcFavorites": "Favorite songs TOP 10",
"etcFavoritesAt": "Favorite songs TOP 10 for this month",
@@ -28,44 +31,41 @@
"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",
- "topCountText": "Record count: {topCount}",
- "hallAbilityText": "Rating",
- "hallAtText": "Month",
+ "fit0": "Sequence of records",
+ "fit1": "Number of plays",
+ "fit2": "Update order",
+ "fit3": "Subject order",
+ "fit4": "Artist order",
+ "fit5": "Genre order",
+ "fit6": "Difficulty order",
+ "hall": "Hall of Fame",
+ "hallAbilityTitle": "Rating",
+ "hallAtTitle": "Month",
"hallBand": "Combo",
- "hallHighest": "Record",
- "hallLevelText": "Level",
+ "hallLevelTitle": "Level",
"hallStand": "Score",
+ "hallTop": "Record",
"hallTotal": "Play",
- "hallTotalText": "All",
- "inputNewSite": "Create Chat Room",
+ "hallTotalTitle": "All",
+ "loggedInText": "Welcome, {avatarName}.",
+ "logIn": "Login",
"notAvatarViewFault": "Non-member profiles are not available.",
+ "note": "Online Ranking",
"notLoggedInText": "Thank you, {avatarName}.",
- "notLogIn": "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",
- "loggedInText": "Welcome, {avatarName}.",
- "logIn": "Login",
- "logInCipher": "Password",
- "logInID": "ID",
"silentSiteNew": "One-on-one conversation",
+ "site": "Online Chat",
"siteAudio": "Alarm sound.",
"siteAutoEnterDefault": "Automatically enter the regular chat room.",
"siteAutoEnterNotify": "Automatically enter the notification room.",
@@ -73,7 +73,6 @@
"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 {siteName}.",
"siteYellNewNetSite": "Create a new game room",
@@ -81,35 +80,24 @@
"siteYellQuit": "Exited",
"siteYellTaehui": "Developer",
"siteYellTV": "Click to watch Qwilight broadcast {title}",
+ "src0": "As a title",
+ "src1": "As a nickname",
+ "src2": "As an artist",
+ "src3": "As a genre",
"stand": "Score",
"textBand": "{value} combo",
"textCount": "{value}",
"textHandled": "{value} times",
"textStand": "{value} 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",
- "toHall": "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",
+ "topCountText": "Record count: {topCount}",
"totalCountText": "Number of plays: {totalCount}.",
"totalLengthText": "Playtime: {h} hours {m} minutes {s} seconds",
"viewAvatarView": "View Profiles",
"wantAvatarAssist": "Enter nickname to search",
"wipedSiteYell": "Deleted message.",
- "wwwLevel": "Challenges",
- "wwwLevelClearText": "Challenge {title} cleared! Congratulations."
+ "wwwLevelClearText": "Challenge {title} cleared! Congratulations.",
+ "wwwLevels": "Challenges"
}
diff --git a/qwilight-fe/src/assets/language/ko.json b/qwilight-fe/src/assets/language/ko.json
index eb3f838..c9551bd 100644
--- a/qwilight-fe/src/assets/language/ko.json
+++ b/qwilight-fe/src/assets/language/ko.json
@@ -1,21 +1,24 @@
{
"abilityFittedText": "{stand} 점 (+ {ability} Point)",
- "audioMultiplier": "음악 속도",
"autoLogIn": "자동 로그인",
- "avatarAbilitiesText": "성과 TOP 50",
+ "avatar": "온라인 프로필",
+ "avatarAbilityTitle": "성과 TOP 50",
+ "avatarCipher": "비밀번호",
"avatarCountText": "{avatarCount} 명",
"avatarDate": "마지막 접속일: {date}",
"avatarDateText": "활동 추세",
- "avatarFavoritesText": "가장 많이 플레이 TOP 50",
+ "avatarFavoritesTitle": "가장 많이 플레이 TOP 50",
+ "avatarID": "아이디",
"avatarIntroText": "자기소개",
- "avatarLastsText": "마지막 플레이 TOP 50",
+ "avatarLastsTitle": "마지막 플레이 TOP 50",
"avatarQuitStatusText": "랭크",
"bannedNoteFile": "불법 BMS, BMSON 노트 파일은 키음 개수를 확인하여 자체적으로 걸러집니다.
만약 불법 BMS/BMSON 노트 파일을 발견하시면 taehui@taehui.ddns.net로 알려주시면 삭제합니다.",
"commentSiteName": "성과 알림방",
"defaultSiteName": "일반 대화방",
- "enterSite": "입장하기",
+ "etc": "통계",
"etcAutoMode": "턴 테이블",
"etcAvatar": "활동 사용자 추세",
+ "etcEnroll": "신규 가입 추세",
"etcFaintNoteMode": "노트 시각",
"etcFavorites": "선호곡 TOP 10",
"etcFavoritesAt": "이번 달 선호곡 TOP 10",
@@ -28,44 +31,41 @@
"etcNoteMobilityMode": "노트 무질서도",
"etcNoteModifyMode": "노트 수정",
"etcNoteSaltMode": "노트 배치",
- "etcSignUp": "신규 가입 추세",
"etcTotal": "플레이 추세",
"etcTotalEdges": "프레임 TOP 10",
"etcTotalNoteFiles": "이번 달 인기곡 TOP 10",
"etcTotalTitles": "호칭 TOP 10",
"exileAvatar": "추방",
- "topCountText": "기록 개수: {topCount} 개",
- "hallAbilityText": "레이팅",
- "hallAtText": "이번 달",
+ "fit0": "기록 개수순",
+ "fit1": "플레이 횟수순",
+ "fit2": "업데이트순",
+ "fit3": "제목순",
+ "fit4": "아티스트순",
+ "fit5": "장르순",
+ "fit6": "난이도순",
+ "hall": "명예의 전당",
+ "hallAbilityTitle": "레이팅",
+ "hallAtTitle": "이번 달",
"hallBand": "콤보",
- "hallHighest": "기록",
- "hallLevelText": "레벨",
+ "hallLevelTitle": "레벨",
"hallStand": "점수",
+ "hallTop": "기록",
"hallTotal": "플레이",
- "hallTotalText": "전체",
- "inputNewSite": "대화방 만들기",
+ "hallTotalTitle": "전체",
+ "loggedInText": "{avatarName}님 환영합니다.",
+ "logIn": "로그인",
"notAvatarViewFault": "비회원의 프로필은 제공되지 않습니다.",
+ "note": "온라인 랭킹",
"notLoggedInText": "{avatarName}님 감사합니다.",
- "notLogIn": "로그아웃",
- "onAvatars": "사용자 목록",
- "onClose": "지우기",
- "onConfigure": "환경 설정",
- "onSiteWindow": "대화방 목록",
- "onWant": "검색",
"onWantMe": "내 프로필 보기",
"platformSiteName": "디스코드 대화방",
"point": "정확도",
- "postFile": "파일 업로드",
- "quitSite": "방 나가기",
"save": "저장하기",
"setSiteHand": "방장 위임",
"setSiteName": "방 이름 수정",
"setSiteNameText": "수정할 이름을 입력하세요",
- "loggedInText": "{avatarName}님 환영합니다.",
- "logIn": "로그인",
- "logInCipher": "비밀번호",
- "logInID": "아이디",
"silentSiteNew": "1대1 대화",
+ "site": "온라인 대화",
"siteAudio": "알림 사운드",
"siteAutoEnterDefault": "일반 대화방 자동 입장",
"siteAutoEnterNotify": "알림방 자동 입장",
@@ -73,7 +73,6 @@
"siteCipher": "대화방 비밀번호",
"siteName": "대화방 이름",
"siteSaveTraffic": "데이터 절약 모드",
- "siteWindowNew": "대화방 만들기",
"siteYellEnter": "입장함",
"siteYellInvite": "저랑 같이 {siteName} 에서 멀티 플레이 하려면 클릭하세요",
"siteYellNewNetSite": "새 게임방을 만듦",
@@ -81,35 +80,24 @@
"siteYellQuit": "퇴장함",
"siteYellTaehui": "개발자",
"siteYellTV": "Qwilight 방송 {title}을 보려면 클릭하세요",
+ "src0": "제목으로",
+ "src1": "닉네임으로",
+ "src2": "아티스트로",
+ "src3": "장르로",
"stand": "점수",
"textBand": "{value} 콤보",
"textCount": "{value} 개",
"textHandled": "{value} 회",
"textStand": "{value} 점",
- "toAvatar": "온라인 프로필",
- "toEtc": "통계",
- "toFit0": "기록 개수순",
- "toFit1": "플레이 횟수순",
- "toFit2": "업데이트순",
- "toFit3": "제목순",
- "toFit4": "아티스트순",
- "toFit5": "장르순",
- "toFit6": "난이도순",
- "toHall": "명예의 전당",
"toilNoteFile": "불법 BMS, BMSON 노트 파일로 신고",
"toilNoteFileText": "신고 사유를 적어주세요",
- "toNote": "온라인 랭킹",
"toNotifySiteName": "알림방",
- "toSite": "온라인 대화",
- "toSrc0": "제목으로",
- "toSrc1": "닉네임으로",
- "toSrc2": "아티스트로",
- "toSrc3": "장르로",
+ "topCountText": "기록 개수: {topCount} 개",
"totalCountText": "플레이 횟수: {totalCount} 회",
"totalLengthText": "플레이 시간: {h} 시간 {m} 분 {s} 초",
"viewAvatarView": "프로필 보기",
"wantAvatarAssist": "검색할 닉네임을 입력하세요",
"wipedSiteYell": "삭제된 메시지입니다.",
- "wwwLevel": "도전 과제",
- "wwwLevelClearText": "도전 과제 {title} 클리어! 축하합니다."
+ "wwwLevelClearText": "도전 과제 {title} 클리어! 축하합니다.",
+ "wwwLevels": "도전 과제"
}
diff --git a/qwilight-fe/src/assets/w8.png b/qwilight-fe/src/assets/w8.png
new file mode 100644
index 0000000..e0f4e44
--- /dev/null
+++ b/qwilight-fe/src/assets/w8.png
Binary files differ
diff --git a/qwilight-fe/src/components/AvatarDrawing.tsx b/qwilight-fe/src/components/AvatarDrawing.tsx
index 4dc007f..fe40813 100644
--- a/qwilight-fe/src/components/AvatarDrawing.tsx
+++ b/qwilight-fe/src/components/AvatarDrawing.tsx
@@ -25,8 +25,8 @@
>
+
+ #{avatarPlace > 0 ? avatarPlace : "?"}
+
+ {typeof avatarCount === "number" && <>/{avatarCount}>}
+
+ );
+}
diff --git a/qwilight-fe/src/components/AvatarTitle.tsx b/qwilight-fe/src/components/AvatarTitle.tsx
index 9d86510..fd8d57a 100644
--- a/qwilight-fe/src/components/AvatarTitle.tsx
+++ b/qwilight-fe/src/components/AvatarTitle.tsx
@@ -1,15 +1,35 @@
import Title from "@/components/Title";
import useGetTitle from "@/query/useGetTitle";
+import { DetailedHTMLProps, HTMLAttributes } from "react";
-export default function AvatarTitle({ avatarID }: { avatarID: string }) {
+export default function AvatarTitle({
+ avatarID,
+ avatarName,
+ textID = false,
+ ...props
+}: {
+ avatarID?: string;
+ avatarName?: string;
+ textID?: boolean;
+} & DetailedHTMLProps, HTMLSpanElement>) {
const {
data: { title, titleColor },
isFetched: isTitleLoaded,
} = useGetTitle(avatarID);
- if (!isTitleLoaded) {
+ if (!avatarName) {
return null;
}
- return ;
+ return (
+
+ {isTitleLoaded && (
+ <>
+ {" "}
+ >
+ )}
+ {avatarName}
+ {textID && avatarID && ` (${avatarID})`}
+
+ );
}
diff --git a/qwilight-fe/src/components/AvatarView.tsx b/qwilight-fe/src/components/AvatarView.tsx
new file mode 100644
index 0000000..236f38f
--- /dev/null
+++ b/qwilight-fe/src/components/AvatarView.tsx
@@ -0,0 +1,17 @@
+import LoggedInAvatarView from "@/components/LoggedInAvatarView";
+import NotLoggedInAvatarView from "@/components/NotLoggedInAvatarView";
+
+import { useSiteStore } from "@/state/Stores";
+import { observer } from "mobx-react-lite";
+
+export default observer(() => {
+ const { isLoggedIn, siteAvatarID, siteAvatarName } = useSiteStore();
+
+ if (isLoggedIn) {
+ return (
+
+ );
+ }
+
+ return ;
+});
diff --git a/qwilight-fe/src/components/DefaultLoading.tsx b/qwilight-fe/src/components/DefaultLoading.tsx
new file mode 100644
index 0000000..5dc95a9
--- /dev/null
+++ b/qwilight-fe/src/components/DefaultLoading.tsx
@@ -0,0 +1,15 @@
+import HashLoader from "react-spinners/HashLoader";
+
+export default function DefaultLoading() {
+ return (
+
+ );
+}
diff --git a/qwilight-fe/src/components/HitPointsModeText.tsx b/qwilight-fe/src/components/HitPointsModeText.tsx
new file mode 100644
index 0000000..9f6b3dd
--- /dev/null
+++ b/qwilight-fe/src/components/HitPointsModeText.tsx
@@ -0,0 +1,31 @@
+import { useMemo } from "react";
+
+export default function HitPointsModeText({
+ hitPointsMode,
+ text,
+}: {
+ hitPointsMode: number;
+ text: string;
+}) {
+ return (
+ {
+ switch (hitPointsMode) {
+ case 0:
+ return "level2";
+ case 2:
+ return "level4";
+ case 3:
+ case 5:
+ return "level5";
+ case 4:
+ return "level1";
+ default:
+ return "stand";
+ }
+ }, [hitPointsMode])}
+ >
+ {text}
+
+ );
+}
diff --git a/qwilight-fe/src/components/JudgmentModeText.tsx b/qwilight-fe/src/components/JudgmentModeText.tsx
new file mode 100644
index 0000000..4ea99b4
--- /dev/null
+++ b/qwilight-fe/src/components/JudgmentModeText.tsx
@@ -0,0 +1,30 @@
+import { useMemo } from "react";
+
+export default function JudgmentModeText({
+ judgmentMode,
+ text,
+}: {
+ judgmentMode: number;
+ text: string;
+}) {
+ return (
+ {
+ switch (judgmentMode) {
+ case 0:
+ return "level2";
+ case 2:
+ return "level4";
+ case 3:
+ return "level1";
+ case 5:
+ return "level5";
+ default:
+ return "point";
+ }
+ }, [])}
+ >
+ {text}
+
+ );
+}
diff --git a/qwilight-fe/src/components/LevelText.tsx b/qwilight-fe/src/components/LevelText.tsx
new file mode 100644
index 0000000..1ec0fb7
--- /dev/null
+++ b/qwilight-fe/src/components/LevelText.tsx
@@ -0,0 +1,14 @@
+import { DetailedHTMLProps, HTMLAttributes } from "react";
+
+export default function LevelText({
+ level,
+ levelText,
+ ...props
+}: {
+ level: number;
+ levelText: string;
+} & DetailedHTMLProps, HTMLSpanElement>) {
+ return (
+ {levelText}
+ );
+}
diff --git a/qwilight-fe/src/components/LoadingLayer.tsx b/qwilight-fe/src/components/LoadingLayer.tsx
deleted file mode 100644
index 7740746..0000000
--- a/qwilight-fe/src/components/LoadingLayer.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import BarLoader from "react-spinners/BarLoader";
-import { Badge, Col, ListGroup, ListGroupItem, Row } from "reactstrap";
-
-export default function LoadingLayer({ text }: { text: string }) {
- return (
-
-
-
- {text}
-
-
-
-
-
-
- );
-}
diff --git a/qwilight-fe/src/components/LoggedInAvatarView.tsx b/qwilight-fe/src/components/LoggedInAvatarView.tsx
new file mode 100644
index 0000000..d589d07
--- /dev/null
+++ b/qwilight-fe/src/components/LoggedInAvatarView.tsx
@@ -0,0 +1,48 @@
+import wsAPI from "@/app/[language]/site/lib/wsAPI";
+import AvatarDrawing from "@/components/AvatarDrawing";
+import { useTranslations } from "next-intl";
+import { Back } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+
+const EventPB = require("@/Event_pb");
+
+export default function LoggedInAvatarView({
+ avatarID,
+ avatarName,
+}: {
+ avatarID: string;
+ avatarName: string;
+}) {
+ const t = useTranslations();
+
+ return (
+
+
+
+
+
+
+
+ {avatarName} ({avatarID})
+
+ {
+ window.localStorage.removeItem("avatarCipher");
+ window.localStorage.removeItem("autoLogIn");
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.NOT_LOG_IN,
+ });
+ }}
+ >
+
+
+
+
+
+ );
+}
diff --git a/qwilight-fe/src/components/NotLoggedInAvatarView.tsx b/qwilight-fe/src/components/NotLoggedInAvatarView.tsx
new file mode 100644
index 0000000..42a0549
--- /dev/null
+++ b/qwilight-fe/src/components/NotLoggedInAvatarView.tsx
@@ -0,0 +1,69 @@
+import wsAPI from "@/app/[language]/site/lib/wsAPI";
+import CryptoJS from "crypto-js";
+import { useTranslations } from "next-intl";
+import { useState } from "react";
+import Button from "react-bootstrap/Button";
+import FormCheck from "react-bootstrap/FormCheck";
+import FormControl from "react-bootstrap/FormControl";
+import Stack from "react-bootstrap/Stack";
+
+const EventPB = require("@/Event_pb");
+
+export default function NotLoggedInAvatarView() {
+ const [avatarID, setAvatarID] = useState("");
+ const [avatarCipher, setAvatarCipher] = useState("");
+ const [autoLogIn, setAutoLogIn] = useState(false);
+
+ const t = useTranslations();
+
+ const onLogIn = async () => {
+ if (autoLogIn) {
+ window.localStorage.setItem("avatarID", avatarID);
+ window.localStorage.setItem(
+ "avatarCipher",
+ CryptoJS.AES.encrypt(
+ avatarCipher,
+ "591A6F91-2A27-4A88-88FA-0FEB7CB5FD94",
+ ).toString(),
+ );
+ }
+ window.localStorage.setItem("autoLogIn", autoLogIn.toString());
+ wsAPI.send({
+ eventID: EventPB.Event.EventID.LOG_IN,
+ text: JSON.stringify({ avatarID, avatarCipher }),
+ });
+ };
+
+ return (
+
+ {
+ setAvatarID(value);
+ }}
+ />
+ {
+ setAvatarCipher(value);
+ }}
+ />
+
+ {t("logIn")}
+
+ {
+ setAutoLogIn(!autoLogIn);
+ }}
+ />
+
+ );
+}
diff --git a/qwilight-fe/src/components/QwilightView.tsx b/qwilight-fe/src/components/QwilightView.tsx
index d6f601b..df91b38 100644
--- a/qwilight-fe/src/components/QwilightView.tsx
+++ b/qwilight-fe/src/components/QwilightView.tsx
@@ -1,91 +1,107 @@
"use client";
-import LogInWindow from "@/app/[language]/site/components/LogInWindow";
-import usewsAPI from "@/app/[language]/site/lib/useWSAPI";
+import useWSAPI from "@/app/[language]/site/lib/useWSAPI";
import platform from "@/assets/discord-logo-white.png";
+import AvatarView from "@/components/AvatarView";
import withQueryClient from "@/hoc/withQueryClient";
import { useSiteStore } from "@/state/Stores";
+import { getDefaultAvatarID } from "@/utilities/Utility";
+import { wwwAPIPath } from "@/utilities/wwwAPI";
+import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import Image from "next/image";
import Link from "next/link";
-import { ReactNode, useEffect, useRef } from "react";
+import { ReactNode, useLayoutEffect, useRef } from "react";
+import Container from "react-bootstrap/Container";
+import Nav from "react-bootstrap/Nav";
+import Navbar from "react-bootstrap/Navbar";
+import NavbarBrand from "react-bootstrap/NavbarBrand";
+import NavbarCollapse from "react-bootstrap/NavbarCollapse";
+import NavbarToggle from "react-bootstrap/NavbarToggle";
+import NavDropdown from "react-bootstrap/NavDropdown";
+import NavLink from "react-bootstrap/NavLink";
import { ToastContainer } from "react-toastify";
-import { Button, Col, Container, Navbar, NavbarBrand, Row } from "reactstrap";
import { useIsPath } from "taehui-ts/fe-utilities";
-export default withQueryClient(({ children }: { children: ReactNode }) => {
- const t = useTranslations();
- const titleComponent = useRef(null);
- const siteYellsView = useRef(null);
- const { setComponents } = useSiteStore();
+export default withQueryClient(
+ observer(({ children }: { children: ReactNode }) => {
+ const t = useTranslations();
+ const titleView = useRef(null);
+ const { setTitleView: setTitleView, siteAvatarID } = useSiteStore();
- usewsAPI();
+ useWSAPI();
- const isPath = useIsPath();
+ const isPath = useIsPath();
- const getColor = (route: string) => (isPath(route) ? "primary" : "secondary");
+ useLayoutEffect(() => {
+ setTitleView(titleView);
+ }, [setTitleView]);
- const onPlatform = () => {
- window.open("https://taehui.ddns.net/qwilight/platform");
- };
-
- useEffect(() => {
- setComponents(titleComponent, siteYellsView);
- }, [setComponents]);
-
- return (
- <>
-
-
-
+ return (
+ <>
+
+
-
-
-
- {t("toNote")}
-
-
-
-
- {t("toSite")}
-
-
-
-
- {t("toAvatar")}
-
-
-
-
- {t("toHall")}
-
-
-
-
- {t("toEtc")}
-
-
-
-
+
+
+
-
-
-
-
- {children}
-
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+ {children}
-
-
- >
- );
-});
+
+ >
+ );
+ }),
+);
diff --git a/qwilight-fe/src/query/useGetTitle.ts b/qwilight-fe/src/query/useGetTitle.ts
index 4b1df49..82cbd01 100644
--- a/qwilight-fe/src/query/useGetTitle.ts
+++ b/qwilight-fe/src/query/useGetTitle.ts
@@ -3,10 +3,11 @@
import { useQuery } from "@tanstack/react-query";
import { useLanguage } from "taehui-ts/language";
-export default function useGetTitle(avatarID: string) {
+export default function useGetTitle(avatarID?: string) {
const language = useLanguage();
return useQuery({
+ enabled: !!avatarID,
queryKey: ["title", avatarID, language],
queryFn: async () => {
const { data } = await wwwAPI.get("/title", {
diff --git a/qwilight-fe/src/state/Stores.tsx b/qwilight-fe/src/state/Stores.tsx
index 4837518..df2a0e8 100644
--- a/qwilight-fe/src/state/Stores.tsx
+++ b/qwilight-fe/src/state/Stores.tsx
@@ -5,6 +5,7 @@
import setNoteStore from "@/app/[language]/note/state/setNoteStore";
import setSiteStore from "@/app/[language]/site/state/setSiteStore";
import { useLocalObservable } from "mobx-react-lite";
+import { useTranslations } from "next-intl";
import { createContext, FC, PropsWithChildren, useContext } from "react";
type MainStore = {
@@ -17,18 +18,22 @@
const mainStore = createContext({} as MainStore);
const { Provider } = mainStore;
-export const Stores: FC = ({ children }) => (
-
- {children}
-
-);
+export const Stores: FC = ({ children }) => {
+ const t = useTranslations();
+
+ return (
+ setSiteStore(t)),
+ avatarStore: useLocalObservable(setAvatarStore),
+ hallStore: useLocalObservable(setHallStore),
+ }}
+ >
+ {children}
+
+ );
+};
export const useSiteStore = () => useContext(mainStore).siteStore;
diff --git a/qwilight-fe/src/type/wwwAPI.d.ts b/qwilight-fe/src/type/wwwAPI.d.ts
index d19825f..612561d 100644
--- a/qwilight-fe/src/type/wwwAPI.d.ts
+++ b/qwilight-fe/src/type/wwwAPI.d.ts
@@ -6,7 +6,7 @@
export type GetNoteAPI = {
totalCount: number;
topCount: number;
- noteCount: number;
+ lastPage: number;
notes: {
noteID: string;
artist: string;
@@ -16,9 +16,6 @@
level: number;
topCount?: number;
totalCount?: number;
- fittedText?: string;
- wantAvatarID?: string;
- wantAvatarName?: string;
}[];
};
@@ -30,7 +27,7 @@
stand: number;
band: number;
point: number;
- isP: boolean;
+ isBand1: boolean;
commentary: string;
isTargetAvatar: boolean;
judgmentMode: number;
@@ -66,15 +63,12 @@
date: number;
avatarLevels: number[];
avatarAbility5K: number;
- avatarAbility5KClass: number;
avatarAbility5KPlace: number;
avatarAbility5KCount: number;
avatarAbility7K: number;
- avatarAbility7KClass: number;
avatarAbility7KPlace: number;
avatarAbility7KCount: number;
avatarAbility9K: number;
- avatarAbility9KClass: number;
avatarAbility9KPlace: number;
avatarAbility9KCount: number;
dateSet: number[];
@@ -121,15 +115,15 @@
levelID: string;
title: string;
levelText: string;
- level: string;
+ level: number;
date: number;
}[];
export type GetEtcAPI = {
totalDateSet: string[];
totalDateValues: number[];
- signUpDateSet: string[];
- signUpDateValues: number[];
+ enrollDateSet: string[];
+ enrollDateValues: number[];
avatarDateSet: string[];
avatarDateValues: number[];
totalNoteFiles: EtcAPINoteFile[];
diff --git a/qwilight-fe/src/utilities/Utility.ts b/qwilight-fe/src/utilities/Utility.ts
index 146a89f..cbfef84 100644
--- a/qwilight-fe/src/utilities/Utility.ts
+++ b/qwilight-fe/src/utilities/Utility.ts
@@ -1,3 +1,4 @@
+import { AbilitySiteYell } from "@/app/[language]/site/type";
import i10 from "@/assets/i10.png";
import i11 from "@/assets/i11.png";
import i12 from "@/assets/i12.png";
@@ -60,7 +61,6 @@
import m79 from "@/assets/m79.png";
import m80 from "@/assets/m80.png";
import m81 from "@/assets/m81.png";
-import { AbilitySiteYell } from "@/app/[language]/site/type";
import { useTranslations } from "next-intl";
export const is = [
@@ -157,11 +157,6 @@
: `${inputModeText} ${ability.toFixed(2)} Point ↑`;
};
-export const toDate = (date: number) => {
- const dateText = new Date(date);
- return `${dateText.toLocaleDateString()} ${dateText.toLocaleTimeString()}`;
-};
-
export const getSiteName = (
siteName: string,
t: ReturnType>,
@@ -210,59 +205,3 @@
export const getDefaultAvatarID = (avatarID: string) =>
avatarID.substring(avatarID.indexOf("@") + 1);
-
-export const getHitPointsClass = (hitPointsMode: number) => {
- switch (hitPointsMode) {
- case 0:
- return "level2";
- case 2:
- return "level4";
- case 3:
- case 5:
- return "level5";
- case 4:
- return "level1";
- default:
- return "stand";
- }
-};
-
-export const getInputMode = (
- tabPosition: number,
-): "6K" | "5K" | "7K" | "9K" | "10K" | "14K" | "24K" | "48K" => {
- switch (tabPosition) {
- case 0:
- return "6K";
- case 1:
- return "5K";
- case 2:
- return "7K";
- case 3:
- return "9K";
- case 4:
- return "10K";
- case 5:
- return "14K";
- case 6:
- return "24K";
- case 7:
- return "48K";
- default:
- throw new Error(tabPosition.toString());
- }
-};
-
-export const getAbilityInputMode = (
- tabPosition: number,
-): "5K" | "7K" | "9K" => {
- switch (tabPosition) {
- case 0:
- return "5K";
- case 1:
- return "7K";
- case 2:
- return "9K";
- default:
- throw new Error(tabPosition.toString());
- }
-};
diff --git a/taehui-fe/package.json b/taehui-fe/package.json
index c6493ca..55cebc8 100644
--- a/taehui-fe/package.json
+++ b/taehui-fe/package.json
@@ -11,43 +11,44 @@
"stop": "pm2 stop taehui-fe"
},
"dependencies": {
- "@tanstack/react-query": "^5.28.4",
+ "@tanstack/react-query": "^5.29.0",
"axios": "^1.6.8",
"bootstrap": "^5.3.3",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
- "dompurify": "^3.0.9",
+ "dompurify": "^3.0.11",
"htmlparser2": "^9.1.0",
- "isomorphic-dompurify": "^2.4.0",
- "mariadb": "^3.2.3",
- "mobx": "^6.12.0",
- "mobx-react-lite": "^4.0.6",
- "next": "^14.1.3",
- "next-intl": "^3.9.5",
+ "isomorphic-dompurify": "^2.6.0",
+ "mariadb": "^3.3.0",
+ "mobx": "^6.12.3",
+ "mobx-react-lite": "^4.0.7",
+ "next": "^14.1.4",
+ "next-intl": "^3.11.1",
"react": "^18.2.0",
+ "react-bootstrap": "^2.10.2",
+ "react-bootstrap-icons": "^1.11.3",
"react-contexify": "^6.0.0",
"react-dom": "^18.2.0",
"react-infinite-scroll-component": "^6.1.0",
"react-textarea-autosize": "^8.5.3",
"react-toastify": "^10.0.5",
- "reactstrap": "^9.2.2",
"redis": "^4.6.13",
- "sweetalert2": "^11.10.6",
+ "sweetalert2": "^11.10.7",
"taehui-ts": "workspace:^",
"uuid": "^9.0.1",
- "winston": "^3.12.0",
+ "winston": "^3.13.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
"@types/dompurify": "^3.0.5",
"@types/jest": "^29.5.12",
- "@types/node": "^20.11.28",
- "@types/react": "^18.2.66",
- "@types/react-dom": "^18.2.22",
+ "@types/node": "^20.12.5",
+ "@types/react": "^18.2.74",
+ "@types/react-dom": "^18.2.24",
"@types/showdown": "^2.0.6",
"@types/uuid": "^9.0.8",
- "eslint-config-next": "^14.1.3",
- "typescript": "^5.4.2"
+ "eslint-config-next": "^14.1.4",
+ "typescript": "^5.4.4"
}
}
diff --git "a/taehui-fe/src/app/\133language\135/avatar/page.tsx" "b/taehui-fe/src/app/\133language\135/avatar/page.tsx"
index ca76448..aebbc6a 100644
--- "a/taehui-fe/src/app/\133language\135/avatar/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/avatar/page.tsx"
@@ -1,12 +1,12 @@
"use client";
+import EnrollView from "@/components/EnrollView";
import ModifyAvatarView from "@/components/ModifyAvatarView";
-import SignUpView from "@/components/SignUpView";
import { useTaehuiStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
export default observer(() => {
const { totem } = useTaehuiStore();
- return totem ? : ;
+ return totem ? : ;
});
diff --git "a/taehui-fe/src/app/\133language\135/commentary/components/CommentaryItem.tsx" "b/taehui-fe/src/app/\133language\135/commentary/components/CommentaryItem.tsx"
index 68310d3..b58acf6 100644
--- "a/taehui-fe/src/app/\133language\135/commentary/components/CommentaryItem.tsx"
+++ "b/taehui-fe/src/app/\133language\135/commentary/components/CommentaryItem.tsx"
@@ -3,17 +3,17 @@
import { GetCommentaryAPI } from "@/type/wwwAPI";
import { useTranslations } from "next-intl";
import { useState } from "react";
+import { PencilFill, TrashFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import ButtonGroup from "react-bootstrap/ButtonGroup";
+import Col from "react-bootstrap/Col";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import ReactTextareaAutosize from "react-textarea-autosize";
import { toast } from "react-toastify";
-import {
- Button,
- Col,
- Collapse,
- Form,
- Input,
- ListGroupItem,
- Row,
-} from "reactstrap";
import { getDatetime } from "taehui-ts/date";
export default function CommentaryItem({
@@ -30,86 +30,94 @@
const { mutateAsync: wipeCommentary } = useWipeCommentary();
const { mutateAsync: putCommentary } = usePutCommentary();
- return (
- {
- setModifyOpened(true);
- }}
- >
-
-
- {avatarName}
-
-
- {isModifyOpened ? (
-
+
+
+ {avatarName}
+ {
- setTextInput(value);
- }}
+ onChange={({ target: { value } }) => setTextInput(value)}
/>
- ) : (
- {text}
- )}
-
-
- {getDatetime(date)}
-
+
+ {getDatetime(date)}
+
+
+
+ {t("avatarCipher")}
+ setAvatarCipher(value)}
+ />
+ {
+ if (avatarCipher && textInput) {
+ await putCommentary({
+ commentaryID,
+ avatarCipher,
+ text: textInput,
+ });
+ setModifyOpened(false);
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+
+
-
-
-
-
+ );
+ }
+
+ const isLoading = !(commentaryID >= 0);
+
+ return (
+
+ {avatarName}
+
+ {text}
+
+
+
+ {getDatetime(date)}
+
+ {
+ setTextInput(text);
+ setModifyOpened(true);
+ }}
+ >
+
+
+ {
+ if (avatarCipher) {
+ await wipeCommentary({ commentaryID, avatarCipher });
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+
+
+
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/commentary/page.tsx" "b/taehui-fe/src/app/\133language\135/commentary/page.tsx"
index 071983b..e967be6 100644
--- "a/taehui-fe/src/app/\133language\135/commentary/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/commentary/page.tsx"
@@ -5,9 +5,17 @@
import usePostCommentary from "@/app/[language]/commentary/query/usePostCommentary";
import { useTranslations } from "next-intl";
import { useState } from "react";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Stack from "react-bootstrap/Stack";
import ReactTextareaAutosize from "react-textarea-autosize";
import { toast } from "react-toastify";
-import { Button, Col, Form, Input, ListGroup, Row } from "reactstrap";
+import { getDatetime } from "taehui-ts/date";
export default function Page() {
const t = useTranslations();
@@ -21,77 +29,79 @@
const { mutateAsync: postCommentary } = usePostCommentary();
return (
- <>
-
- {isCommentaryLoaded && (
-
-
-
- {commentary.map((commentary) => (
-
- ))}
-
-
-
- )}
- >
+
+ )}
+
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/commentary/query/usePostCommentary.ts" "b/taehui-fe/src/app/\133language\135/commentary/query/usePostCommentary.ts"
index 28fee98..075296f 100644
--- "a/taehui-fe/src/app/\133language\135/commentary/query/usePostCommentary.ts"
+++ "b/taehui-fe/src/app/\133language\135/commentary/query/usePostCommentary.ts"
@@ -1,6 +1,6 @@
-import { useMutation, useQueryClient } from "@tanstack/react-query";
-
import { wwwAPI } from "@/utilities/wwwAPI";
+import { useMutation, useQueryClient } from "@tanstack/react-query";
+import { getMillis } from "taehui-ts/date";
export default function usePostCommentary() {
const queryClient = useQueryClient();
@@ -15,11 +15,19 @@
avatarCipher: string;
text: string;
}) => {
- await wwwAPI.post("/commentary", {
- avatarName,
- avatarCipher,
- text,
- });
+ await wwwAPI.post(
+ "/commentary",
+ {
+ avatarName,
+ avatarCipher,
+ text,
+ },
+ {
+ headers: {
+ millis: getMillis(),
+ },
+ },
+ );
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["commentary"] });
diff --git "a/taehui-fe/src/app/\133language\135/commentary/query/usePutCommentary.ts" "b/taehui-fe/src/app/\133language\135/commentary/query/usePutCommentary.ts"
index cba778b..e8529cc 100644
--- "a/taehui-fe/src/app/\133language\135/commentary/query/usePutCommentary.ts"
+++ "b/taehui-fe/src/app/\133language\135/commentary/query/usePutCommentary.ts"
@@ -2,6 +2,7 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import { toast } from "react-toastify";
+import { getMillis } from "taehui-ts/date";
export default function usePutCommentary() {
const queryClient = useQueryClient();
@@ -18,11 +19,19 @@
avatarCipher: string;
text: string;
}) => {
- await wwwAPI.put("/commentary", {
- commentaryID,
- avatarCipher,
- text,
- });
+ await wwwAPI.put(
+ "/commentary",
+ {
+ commentaryID,
+ avatarCipher,
+ text,
+ },
+ {
+ headers: {
+ millis: getMillis(),
+ },
+ },
+ );
},
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: ["commentary"] });
diff --git "a/taehui-fe/src/app/\133language\135/components/HitText.tsx" "b/taehui-fe/src/app/\133language\135/components/HitText.tsx"
index 71ae543..d920ce9 100644
--- "a/taehui-fe/src/app/\133language\135/components/HitText.tsx"
+++ "b/taehui-fe/src/app/\133language\135/components/HitText.tsx"
@@ -1,4 +1,5 @@
import { useTranslations } from "next-intl";
+import Stack from "react-bootstrap/Stack";
export default function HitText({
hitBefore,
@@ -10,12 +11,10 @@
const t = useTranslations();
return (
-
- {t("hit01", { hitBefore })}
-
- {t("hit02", { hit })}
-
- {t("hit03")}
-
+
+ {t("hit01", { hitBefore })}
+ {t("hit02", { hit })}
+ {t("hit03")}
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/components/HitView.tsx" "b/taehui-fe/src/app/\133language\135/components/HitView.tsx"
index 0945bb3..2966102 100644
--- "a/taehui-fe/src/app/\133language\135/components/HitView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/components/HitView.tsx"
@@ -22,7 +22,7 @@
return (
<>
- {t("hit00")}
+ {t("hit00")}
{isHitLoaded ? (
) : (
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestAvatarView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestAvatarView.tsx"
new file mode 100644
index 0000000..4b4ae93
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/components/LatestAvatarView.tsx"
@@ -0,0 +1,29 @@
+import AvatarDrawing from "@/components/AvatarDrawing";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import { getDatetime } from "taehui-ts/date";
+
+export default function LatestAvatarView({
+ avatarID,
+ avatarName,
+ date,
+}: {
+ avatarID: string;
+ avatarName: string;
+ date: string;
+}) {
+ return (
+
+
+
+
+
+
+ {avatarName}
+ {getDatetime(date)}
+
+
+
+ );
+}
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestAvatarsView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestAvatarsView.tsx"
deleted file mode 100644
index 6e0bd17..0000000
--- "a/taehui-fe/src/app/\133language\135/components/LatestAvatarsView.tsx"
+++ /dev/null
@@ -1,37 +0,0 @@
-import useGetLatestAvatar from "@/app/[language]/query/useGetLatestAvatar";
-import AvatarTitle from "@/components/AvatarTitle";
-import { useTranslations } from "next-intl";
-import { Col, Row } from "reactstrap";
-import { getDatetime } from "taehui-ts/date";
-
-export default function LatestAvatarsView() {
- const t = useTranslations();
-
- const { data: latestAvatar, isFetched: isLatestAvatarLoaded } =
- useGetLatestAvatar();
-
- return (
-
- {[...Array(2).keys()].map((i) => (
-
- {t(`latestAvatarsView${i}`)}
- {isLatestAvatarLoaded
- ? latestAvatar[i].map(({ avatarID, avatarName, date }) => (
-
-
- {getDatetime(date)}
-
-
- ))
- : [...Array(5).keys()].map((i) => (
-
-
- {null}
-
-
- ))}
-
- ))}
-
- );
-}
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestCommentsView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestCommentsView.tsx"
index b628138..b4c65da 100644
--- "a/taehui-fe/src/app/\133language\135/components/LatestCommentsView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/components/LatestCommentsView.tsx"
@@ -1,7 +1,9 @@
-import CommentTitleView from "@/app/[language]/forum/components/CommentTitleView";
import useGetLatestComment from "@/app/[language]/query/useGetLatestComment";
+import CommentTitleView from "@/components/CommentTitleView";
import { useTranslations } from "next-intl";
-import { ListGroup, ListGroupItemHeading } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import { getDatetime } from "taehui-ts/date";
export default function LatestCommentsView() {
const t = useTranslations();
@@ -10,35 +12,33 @@
useGetLatestComment();
return (
- <>
- {t("latestCommentsView")}
-
- {isLatestCommentLoaded
- ? latestComment.map((latestComment) => {
- return (
-
- );
- })
- : [...Array(5).keys()].map((i) => (
+
+ {t("latestCommentsView")}
+ {isLatestCommentLoaded
+ ? latestComment.map((latestComment) => (
+
+
+ ))
+ : [...Array(5).keys()].map((i) => (
+
+
- ))}
-
- >
+
+ ))}
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestEnrolledAvatarsView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestEnrolledAvatarsView.tsx"
new file mode 100644
index 0000000..de9cbe1
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/components/LatestEnrolledAvatarsView.tsx"
@@ -0,0 +1,40 @@
+import LatestAvatarView from "@/app/[language]/components/LatestAvatarView";
+import useGetLatestEnrolledAvatar from "@/app/[language]/query/useGetLatestEnrolledAvatar";
+import { useTranslations } from "next-intl";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import { getDatetime } from "taehui-ts/date";
+
+export default function LatestEnrolledAvatarsView() {
+ const t = useTranslations();
+
+ const {
+ data: latestEnrolledAvatar,
+ isFetched: isLatestEnrolledAvatarLoaded,
+ } = useGetLatestEnrolledAvatar();
+
+ return (
+
+ {t("latestEnrolledAvatarsView")}
+ {isLatestEnrolledAvatarLoaded
+ ? latestEnrolledAvatar.map(({ avatarID, avatarName, date }) => (
+
+
+
+ ))
+ : [...Array(5).keys()].map((i) => (
+
+
+
+ ))}
+
+ );
+}
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestEssaysView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestEssaysView.tsx"
index e65bf3c..7d5bc07 100644
--- "a/taehui-fe/src/app/\133language\135/components/LatestEssaysView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/components/LatestEssaysView.tsx"
@@ -1,7 +1,9 @@
-import EssayTitleView from "@/app/[language]/forum/components/EssayTitleView";
import useGetLatestEssay from "@/app/[language]/query/useGetLatestEssay";
+import EssayTitleView from "@/components/EssayTitleView";
import { useTranslations } from "next-intl";
-import { ListGroup, ListGroupItemHeading } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import { getDatetime } from "taehui-ts/date";
export default function LatestEssaysView() {
const t = useTranslations();
@@ -10,33 +12,34 @@
useGetLatestEssay();
return (
- <>
- {t("latestEssaysView")}
-
- {isLatestEssayLoaded
- ? latestEssay.map((latestEssay) => (
+
+ {t("latestEssaysView")}
+ {isLatestEssayLoaded
+ ? latestEssay.map((latestEssay) => (
+
- ))
- : [...Array(5).keys()].map((i) => (
+
+ ))
+ : [...Array(5).keys()].map((i) => (
+
- ))}
-
- >
+
+ ))}
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/components/LatestLoggedInAvatarsView.tsx" "b/taehui-fe/src/app/\133language\135/components/LatestLoggedInAvatarsView.tsx"
new file mode 100644
index 0000000..65fafef
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/components/LatestLoggedInAvatarsView.tsx"
@@ -0,0 +1,40 @@
+import LatestAvatarView from "@/app/[language]/components/LatestAvatarView";
+import useGetLatestLoggedInAvatar from "@/app/[language]/query/useGetLatestLoggedInAvatar";
+import { useTranslations } from "next-intl";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import { getDatetime } from "taehui-ts/date";
+
+export default function LatestLoggedInAvatarsView() {
+ const t = useTranslations();
+
+ const {
+ data: latestLoggedInAvatar,
+ isFetched: isLatestLoggedInAvatarLoaded,
+ } = useGetLatestLoggedInAvatar();
+
+ return (
+
+ {t("latestLoggedInAvatarsView")}
+ {isLatestLoggedInAvatarLoaded
+ ? latestLoggedInAvatar.map(({ avatarID, avatarName, date }) => (
+
+
+
+ ))
+ : [...Array(5).keys()].map((i) => (
+
+
+
+ ))}
+
+ );
+}
diff --git "a/taehui-fe/src/app/\133language\135/components/MainView.tsx" "b/taehui-fe/src/app/\133language\135/components/MainView.tsx"
new file mode 100644
index 0000000..5826d4e
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/components/MainView.tsx"
@@ -0,0 +1,15 @@
+import { useTranslations } from "next-intl";
+import Stack from "react-bootstrap/Stack";
+
+export default function MainView() {
+ const t = useTranslations();
+
+ return (
+
+ {t("main00")}
+ {t("main01")}
+ {t("main02")}
+ {t("main03")}
+
+ );
+}
diff --git "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/\133essayID\135/page.tsx" "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/\133essayID\135/page.tsx"
index 376e4f1..cb81e3f 100644
--- "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/\133essayID\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/\133essayID\135/page.tsx"
@@ -1,18 +1,21 @@
"use client";
import CommentView from "@/app/[language]/forum/components/CommentView";
-import EssayTitleView from "@/app/[language]/forum/components/EssayTitleView";
import TextView from "@/app/[language]/forum/components/TextView";
import useGetEssay from "@/app/[language]/forum/query/useGetEssay";
import useWipeEssay from "@/app/[language]/forum/query/useWipeEssay";
-
+import EssayTitleView from "@/components/EssayTitleView";
import { useTaehuiStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { useParams } from "next/navigation";
-import { Button, Col, Row } from "reactstrap";
+import { useParams, useRouter } from "next/navigation";
+import { Back, EraserFill, PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import ButtonGroup from "react-bootstrap/ButtonGroup";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import Swal from "sweetalert2";
-import { useTo } from "taehui-ts/fe-utilities";
export default observer(() => {
const t = useTranslations();
@@ -24,7 +27,7 @@
essayID: string;
}>();
- const to = useTo();
+ const { push } = useRouter();
const { mutateAsync: wipeEssay } = useWipeEssay();
@@ -52,54 +55,53 @@
(
await Swal.fire({
title: "Taehui",
- text: t("wipeEssayQuestion"),
+ text: t("wipeEssayText"),
icon: "question",
showDenyButton: true,
})
).isConfirmed
) {
await wipeEssay({ essayID });
- to(`/forum/${forumID}`);
+ push(`/forum/${forumID}`);
}
};
- const onQuit = () => {
- to(`/forum/${forumID}`);
- };
-
const isAllowModify = isSU || taehuiAvatarID === avatarID;
return (
- <>
-
+
+
+
+ {forumTitle}
+
{isAllowModify && (
- <>
-
-
- {t("wipeEssay")}
+
+
+
+
-
-
{
- to(`/forum/${forumID}/edit/${essayID}`);
+ push(`/forum/${forumID}/edit/${essayID}`);
}}
>
- {t("doModifyEssay")}
+
-
- >
+ {
+ push(`/forum/${forumID}`);
+ }}
+ >
+
+
+
+
)}
-
-
- {t("quit")}
-
-
-
- {essayLater && (
-
- )}
- {essayBefore && (
-
+ {(essayLater || essayBefore) && (
+ <>
+
+ {essayLater && (
+
+ )}
+ {essayBefore && (
+
+ )}
+ >
)}
- >
+
);
});
diff --git "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx" "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx"
index 6b9dca7..9838160 100644
--- "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/edit/\133\133...essayID\135\135/page.tsx"
@@ -1,78 +1,83 @@
"use client";
-import AutoEssayTitleView from "@/app/[language]/forum/components/AutoEssayTitleView";
+import AutoEssayWindow from "@/app/[language]/forum/components/AutoEssayWindow";
+import FileUploading from "@/app/[language]/forum/components/FileUploadingWindow";
import TextView from "@/app/[language]/forum/components/TextView";
-import useGetAutoEssay from "@/app/[language]/forum/query/useGetAutoEssay";
import useGetEssay from "@/app/[language]/forum/query/useGetEssay";
+import useGetForum from "@/app/[language]/forum/query/useGetForum";
import usePostAutoEssay from "@/app/[language]/forum/query/usePostAutoEssay";
import usePostEssay from "@/app/[language]/forum/query/usePostEssay";
import usePostFile from "@/app/[language]/forum/query/usePostFile";
import usePutAutoEssay from "@/app/[language]/forum/query/usePutAutoEssay";
import usePutEssay from "@/app/[language]/forum/query/usePutEssay";
import { useForumStore, useTaehuiStore } from "@/state/Stores";
+import { useQueryClient } from "@tanstack/react-query";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { useParams } from "next/navigation";
+import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useLayoutEffect, useRef, useState } from "react";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import CloseButton from "react-bootstrap/CloseButton";
+import Col from "react-bootstrap/Col";
+import FormCheck from "react-bootstrap/FormCheck";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import { toast } from "react-toastify";
-import {
- Button,
- Col,
- Collapse,
- Input,
- ListGroup,
- Modal,
- ModalBody,
- Row,
- TabContent,
- TabPane,
-} from "reactstrap";
-import { useTo, useWindowArea } from "taehui-ts/fe-utilities";
+import { useWindowArea } from "taehui-ts/fe-utilities";
export default observer(() => {
const {
isTitleTextFilled,
title,
text,
+ viewUnit,
setTitle,
setText,
autoEssayID,
setAutoEssayID,
+ setAutoEssayOpened,
} = useForumStore();
- const { titleViewHeight, avatarViewHeight } = useTaehuiStore();
+
+ const inputView = useRef(null);
+
const { taehuiAvatarID, taehuiAvatarName } = useTaehuiStore();
const t = useTranslations();
const [isTestMode, setTestMode] = useState(false);
const [testText, setTestText] = useState("");
- const [textViewHeight, setTextViewHeight] = useState(100);
- const [isAutoEssayOpened, setAutoEssayOpened] = useState(false);
- const { forumID, essayID } = useParams<{
+ const { forumID, essayID: [essayID] = [""] } = useParams<{
forumID: string;
- essayID?: string;
+ essayID: string[];
}>();
- const { isFetched: isAutoEssayLoaded, data: autoEssay } = useGetAutoEssay(
- forumID,
- isAutoEssayOpened,
- );
-
- const editView = useRef(null);
const textView = useRef(null);
- const inputView = useRef(null);
+ const [textViewHeight, setTextViewHeight] = useState("");
+
+ const { windowLength, windowHeight } = useWindowArea();
+
+ useLayoutEffect(() => {
+ const textViewArea = textView.current?.getBoundingClientRect();
+ const inputViewArea = inputView.current?.getBoundingClientRect();
+ setTextViewHeight(
+ `${windowHeight - 8 * 4 - ((textViewArea?.top ?? 0) + (inputViewArea?.height ?? 0))}px`,
+ );
+ }, [windowLength, windowHeight]);
const { mutateAsync: postAutoEssay } = usePostAutoEssay();
const { mutateAsync: putAutoEssay } = usePutAutoEssay();
const { mutateAsync: putEssay } = usePutEssay();
- const { isPending, mutateAsync: postFile } = usePostFile();
+ const { mutateAsync: postFile, isPending: isPostFilePending } = usePostFile();
const { mutateAsync: postEssay } = usePostEssay();
- const {
- data: essay,
- data: { forumTitle },
- isFetched: isEssayLoaded,
- } = useGetEssay(essayID);
+ const { data: essay, isFetched: isEssayLoaded } = useGetEssay(essayID);
+ const searchParams = useSearchParams();
+
+ const { push } = useRouter();
useEffect(() => {
if (isEssayLoaded) {
@@ -81,10 +86,6 @@
}
}, [essay, isEssayLoaded, setText, setTitle]);
- const { windowHeight } = useWindowArea();
-
- const to = useTo();
-
const setTag = (tag: string) => {
const { current } = textView;
if (current) {
@@ -124,16 +125,6 @@
};
useEffect(() => {
- setTextViewHeight(
- windowHeight -
- titleViewHeight -
- avatarViewHeight -
- (editView.current?.clientHeight ?? 0) -
- (inputView.current?.clientHeight ?? 0),
- );
- }, [avatarViewHeight, titleViewHeight, windowHeight]);
-
- useEffect(() => {
if (!essayID) {
setTitle("");
setText("");
@@ -177,226 +168,184 @@
}
}, [isTestMode, text]);
+ const {
+ data: { title: forumTitle },
+ } = useGetForum(
+ forumID,
+ Number.parseInt(searchParams.get("page") ?? "1"),
+ viewUnit,
+ );
+
+ const onFileUpload = () => {
+ const inputElement = document.createElement("input");
+ inputElement.type = "file";
+ inputElement.accept = "audio/*,image/*,video/*";
+ inputElement.addEventListener("change", async ({ target }) => {
+ const file = (target as HTMLInputElement).files?.[0];
+ const { current } = textView;
+ if (file && current) {
+ const text = await postFile({
+ file,
+ textView: current,
+ });
+ if (text) {
+ setText(text);
+ }
+ }
+ });
+ inputElement.click();
+ };
+
+ const { back } = useRouter();
+
+ const queryClient = useQueryClient();
+
return (
<>
- {!isTestMode && (
-
-
-
-
+
+
+ {forumTitle}
+
+
+ {
+ setTestMode((prevState) => !prevState);
+ }}
+ />
+
+
+
+
+
+
+ {isTestMode ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+ {t("title")}
+ {
setTitle(value);
}}
/>
-
-
-
-
{
- const inputElement = document.createElement("input");
- inputElement.type = "file";
- inputElement.accept = "audio/*,image/*,video/*";
- inputElement.addEventListener(
- "change",
- async ({ target }) => {
- const file = (target as HTMLInputElement).files?.[0];
- const { current } = textView;
- if (file && current) {
- const text = await postFile({
- file,
- textView: current,
- });
- if (text) {
- setText(text);
- }
- }
- },
- );
- inputElement.click();
+ onClick={async () => {
+ await queryClient.invalidateQueries({
+ queryKey: ["autoEssay"],
+ });
+ setAutoEssayOpened(true);
}}
- color="info"
- >
- {t("fileUpload")}
-
-
-
- {
- setAutoEssayOpened((prevState) => !prevState);
- }}
- color={isAutoEssayOpened ? "secondary" : "primary"}
>
{t("autoEssays")}
-
-
-
-
-
-
- {isAutoEssayLoaded ? (
- autoEssay.map((autoEssay) => (
-
- ))
- ) : (
-
- )}
-
-
-
-
-
- )}
-
-
-
-
- {
- setText(value);
- }}
- innerRef={textView}
- style={{ height: textViewHeight }}
- />
-
-
-
-
-
-
-
-
-
-
- {
- setTag("strong");
- }}
- color="info"
- >
- {t("textTag")}
-
-
-
- {
- setTag("i");
- }}
- color="info"
- >
- {t("textTag")}
-
-
-
- {
- setTag("u");
- }}
- color="info"
- >
- {t("textTag")}
-
-
-
- {
- setTag("s");
- }}
- color="info"
- >
- {t("textTag")}
-
-
-
-
-
- {
- setTestMode((prevState) => !prevState);
- }}
- >
- {t("viewEditedEssay")}
-
-
- {essayID ? (
-
+
+
+
+ {t("fileUpload")}
+
{
- if (title && text) {
- await putEssay({ essayID, title, text });
- to(`/forum/${forumID}/${essayID}`);
- } else {
- toast.error(t("failedValidation"));
- }
+ variant="outline-primary"
+ onClick={() => {
+ setTag("strong");
}}
>
- {t("doModifyEssay")}
+ {t("textTag")}
-
- ) : (
-
{
- if (title && text) {
- const { essayID } = await postEssay({
- forumID,
- title,
- text,
- });
- to(`/forum/${forumID}/${essayID}`);
- } else {
- toast.error(t("failedValidation"));
- }
+ variant="outline-primary"
+ onClick={() => {
+ setTag("i");
}}
>
- {t("postEssay")}
+ {t("textTag")}
-
- )}
-
- {
- to(`/forum/${forumID}`);
+ {
+ setTag("u");
+ }}
+ >
+ {t("textTag")}
+
+ {
+ setTag("s");
+ }}
+ >
+ {t("textTag")}
+
+
+ {
+ setText(value);
}}
- >
- {t("quit")}
-
-
-
-
-
-
- {t("fileUploading")}
-
-
+ />
+ >
+ )}
+ {essayID ? (
+ {
+ if (title && text) {
+ await putEssay({ essayID, title, text });
+ push(`/forum/${forumID}/${essayID}`);
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+ ) : (
+ {
+ if (title && text) {
+ const { essayID } = await postEssay({
+ forumID,
+ title,
+ text,
+ });
+ push(`/forum/${forumID}/${essayID}`);
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+ )}
+
+
+
>
);
});
diff --git "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/page.tsx" "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/page.tsx"
index 7df4baa..076a122 100644
--- "a/taehui-fe/src/app/\133language\135/forum/\133forumID\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/\133forumID\135/page.tsx"
@@ -1,23 +1,20 @@
"use client";
-import EssayTitleView from "@/app/[language]/forum/components/EssayTitleView";
import PositionInput from "@/app/[language]/forum/components/PositionInput";
import useGetForum from "@/app/[language]/forum/query/useGetForum";
+import EssayTitleView from "@/components/EssayTitleView";
import { useForumStore, useTaehuiStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import Link from "next/link";
-import { useParams } from "next/navigation";
+import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
-import {
- Badge,
- Button,
- Col,
- ListGroup,
- ListGroupItemHeading,
- Row,
-} from "reactstrap";
-import { useIntParam, useTo } from "taehui-ts/fe-utilities";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Col from "react-bootstrap/Col";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
export default observer(() => {
const { taehuiLevel } = useTaehuiStore();
@@ -27,14 +24,18 @@
const { forumID } = useParams<{
forumID: string;
}>();
- const { param: page } = useIntParam("page", 1);
+ const searchParams = useSearchParams();
- const to = useTo();
+ const { push } = useRouter();
const {
data: { title, essays, essayCount, level },
isFetched: isForumLoaded,
- } = useGetForum(forumID, page, viewUnit);
+ } = useGetForum(
+ forumID,
+ Number.parseInt(searchParams.get("page") ?? "1"),
+ viewUnit,
+ );
useEffect(() => {
if (isForumLoaded) {
@@ -42,52 +43,37 @@
}
}, [essayCount, isForumLoaded, setLastPage, viewUnit]);
+ if (!isForumLoaded) {
+ return null;
+ }
+
return (
- <>
-
-
-
- {title}
-
-
- {isForumLoaded &&
- essays.map((essay) => (
-
- ))}
-
-
-
-
-
+
+
+ {title}
+ {essays.map((essay) => (
+
+
+
+ ))}
+
+
+
-
-
- {taehuiLevel >= level && (
-
-
- {t("postEssay")}
-
-
- )}
- = level ? "auto" : undefined}
- >
- {
- to("/forums");
- }}
- >
- {t("quit")}
-
+
+ {taehuiLevel >= level && (
+ {
+ push(`/forum/${forumID}/edit`);
+ }}
+ >
+
+
+ )}
- >
+
);
});
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/AutoEssayTitleView.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/AutoEssayTitleView.tsx"
index 4c32612..33afba4 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/AutoEssayTitleView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/AutoEssayTitleView.tsx"
@@ -1,52 +1,57 @@
import useWipeAutoEssay from "@/app/[language]/forum/query/useWipeAutoEssay";
-
import { useForumStore } from "@/state/Stores";
import { GetAutoEssayAPI } from "@/type/wwwAPI";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { Col, ListGroupItem, Row } from "reactstrap";
+import { useParams } from "next/navigation";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
import Swal from "sweetalert2";
import { getDatetime } from "taehui-ts/date";
-export default observer<{ autoEssay: GetAutoEssayAPI[0] }>(
+export default observer<{ autoEssay: GetAutoEssayAPI[number] }>(
({ autoEssay: { autoEssayID, title, text, date } }) => {
const { mutateAsync: wipeAutoEssay } = useWipeAutoEssay();
+ const { forumID } = useParams<{
+ forumID: string;
+ }>();
+
const { setTitle, setText, setAutoEssayID } = useForumStore();
const t = useTranslations();
+ const isLoading = !(autoEssayID >= 0);
+
return (
- {
- const { isConfirmed, isDenied } = await Swal.fire({
- title: t("autoEssay"),
- text: t("setAutoEssayQuestion"),
- icon: "question",
- showDenyButton: true,
- denyButtonText: t("wipeEssay"),
- });
+ {
+ const { isConfirmed, isDenied } = await Swal.fire({
+ title: "Taehui",
+ text: t("autoEssayText"),
+ icon: "question",
+ showDenyButton: true,
+ denyButtonText: t("wipeAutoEssay"),
+ });
- if (isConfirmed) {
- setTitle(title);
- setText(text);
- setAutoEssayID(autoEssayID);
- }
+ if (isConfirmed) {
+ setTitle(title);
+ setText(text);
+ setAutoEssayID(autoEssayID);
+ }
- if (isDenied) {
- await wipeAutoEssay({ autoEssayID });
- }
- }}
+ if (isDenied) {
+ await wipeAutoEssay({ forumID, autoEssayID });
+ }
+ },
+ })}
>
-
-
- {title}
-
-
- {getDatetime(date)}
-
-
-
+ {title}
+
+ {getDatetime(date)}
+
+
);
},
);
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/AutoEssayWindow.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/AutoEssayWindow.tsx"
new file mode 100644
index 0000000..cb5362f
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/forum/components/AutoEssayWindow.tsx"
@@ -0,0 +1,55 @@
+import AutoEssayTitleView from "@/app/[language]/forum/components/AutoEssayTitleView";
+import useGetAutoEssay from "@/app/[language]/forum/query/useGetAutoEssay";
+import { useForumStore } from "@/state/Stores";
+import { observer } from "mobx-react-lite";
+import { useParams } from "next/navigation";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Modal from "react-bootstrap/Modal";
+import ModalBody from "react-bootstrap/ModalBody";
+import { getDatetime } from "taehui-ts/date";
+
+export default observer(() => {
+ const { isAutoEssayOpened, setAutoEssayOpened } = useForumStore();
+
+ const { forumID } = useParams<{
+ forumID: string;
+ }>();
+
+ const { isFetched: isAutoEssayLoaded, data: autoEssay } = useGetAutoEssay(
+ forumID,
+ isAutoEssayOpened,
+ );
+
+ return (
+ {
+ setAutoEssayOpened(false);
+ }}
+ >
+
+
+ {isAutoEssayLoaded ? (
+ autoEssay.map((autoEssay) => (
+
+
+
+ ))
+ ) : (
+
+
+
+ )}
+
+
+
+ );
+});
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/CommentItem.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/CommentItem.tsx"
index 17fe846..5ebcca8 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/CommentItem.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/CommentItem.tsx"
@@ -1,15 +1,23 @@
import usePostComment from "@/app/[language]/forum/query/usePostComment";
import usePutComment from "@/app/[language]/forum/query/usePutComment";
import useWipeComment from "@/app/[language]/forum/query/useWipeComment";
-import AvatarTitle from "@/components/AvatarTitle";
+import AvatarDrawing from "@/components/AvatarDrawing";
import { useTaehuiStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import { useParams } from "next/navigation";
-import { useMemo, useState } from "react";
+import { useState } from "react";
+import { Back, EraserFill, PencilFill, ReplyFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import ButtonGroup from "react-bootstrap/ButtonGroup";
+import Col from "react-bootstrap/Col";
+import Collapse from "react-bootstrap/Collapse";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import ReactTextareaAutosize from "react-textarea-autosize";
import { toast } from "react-toastify";
-import { Button, Col, Collapse, Row } from "reactstrap";
import Swal from "sweetalert2";
import { getDatetime } from "taehui-ts/date";
@@ -34,129 +42,166 @@
const { essayID } = useParams<{ essayID: string }>();
- const [textInput, setTextInput] = useState("");
- const [targetTextInput, setTargetTextInput] = useState("");
- const [isTargetOpened, setTargetOpened] = useState(false);
-
- const isAllowModify = useMemo(
- () => isSU || taehuiAvatarID === avatarID,
- [isSU, avatarID, taehuiAvatarID],
- );
+ const [textInputModify, setTextInputModify] = useState("");
+ const [textInputPost, setTextInputPost] = useState("");
+ const [isPostOpened, setPostOpened] = useState(false);
+ const [isModifyOpened, setModifyOpened] = useState(false);
const { mutateAsync: wipeComment } = useWipeComment();
const { mutateAsync: putComment } = usePutComment();
const { mutateAsync: postComment } = usePostComment();
+ const isAllowModify = isSU || taehuiAvatarID === avatarID;
+
return (
-
-
{
- if (totem && !isTargetOpened) {
- setTargetOpened(true);
- }
- }}
- >
-
- {isTargetOpened && isAllowModify ? (
-
-
-
+
+ {isModifyOpened ? (
+ <>
+
+
+
+
+ {avatarName}
+
+ {
- setTextInput(value);
+ setTextInputModify(value);
}}
/>
-
-
{
- if (textInput) {
- await putComment({ commentID, text: textInput });
- setTargetOpened(false);
+ if (textInputModify) {
+ await putComment({ commentID, text: textInputModify });
+ setModifyOpened(false);
} else {
toast.error(t("failedValidation"));
}
}}
>
- {t("doModifyComment")}
+
-
-
{
- if (
- (
- await Swal.fire({
- title: "Taehui",
- text: t("wipeCommentQuestion"),
- icon: "question",
- showDenyButton: true,
- })
- ).isConfirmed
- ) {
- await wipeComment({ commentID, totem });
- }
+ variant="secondary"
+ onClick={() => {
+ setModifyOpened(false);
}}
>
- {t("wipeComment")}
+
-
-
- ) : (
- {text}
- )}
-
-
- {getDatetime(date)}
-
+
+
+ >
+ ) : (
+ <>
+
+
+
+
+
+ {avatarName}
+ {text}
+
+
+
+
+ {getDatetime(date)}
+ {(totem || isAllowModify) && (
+
+ {totem && (
+ {
+ if (totem) {
+ setPostOpened(!isPostOpened);
+ }
+ }}
+ >
+
+
+ )}
+ {isAllowModify && (
+ {
+ if (totem) {
+ setTextInputModify(text);
+ setModifyOpened(true);
+ }
+ }}
+ >
+
+
+ )}
+ {isAllowModify && (
+ {
+ if (
+ (
+ await Swal.fire({
+ title: "Taehui",
+ text: t("wipeCommentText"),
+ icon: "question",
+ showDenyButton: true,
+ })
+ ).isConfirmed
+ ) {
+ await wipeComment({ commentID, totem });
+ }
+ }}
+ >
+
+
+ )}
+
+ )}
+
+
+ >
+ )}
-
-
-
-
-
- {
- setTargetTextInput(value);
- }}
- />
-
-
- {
- if (targetTextInput) {
- await postComment({
- essayID,
- targetCommentID: commentID,
- text: targetTextInput,
- });
- setTargetOpened(false);
- } else {
- toast.error(t("failedValidation"));
- }
- }}
- >
- {t("postComment")}
-
-
-
-
+
+
+
+
+
+
+ {taehuiAvatarName}
+
+ {
+ setTextInputPost(value);
+ }}
+ />
+ {
+ if (textInputPost) {
+ await postComment({
+ essayID,
+ targetCommentID: commentID,
+ text: textInputPost,
+ });
+ setPostOpened(false);
+ setTextInputPost("");
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+
+
-
+ >
);
},
);
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/CommentTitleView.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/CommentTitleView.tsx"
deleted file mode 100644
index 76d781c..0000000
--- "a/taehui-fe/src/app/\133language\135/forum/components/CommentTitleView.tsx"
+++ /dev/null
@@ -1,42 +0,0 @@
-import AvatarTitle from "@/components/AvatarTitle";
-import { GetLatestCommentAPI } from "@/type/wwwAPI";
-import { Col, ListGroupItem, Row } from "reactstrap";
-import { getDatetime } from "taehui-ts/date";
-import { useTo } from "taehui-ts/fe-utilities";
-
-export default function CommentTitleView({
- forumID,
- essayID,
- comment: { avatarID, avatarName, date, text },
-}: {
- forumID?: string;
- essayID?: number;
- comment: GetLatestCommentAPI[number];
-}) {
- const to = useTo();
-
- const isLoading = !(forumID && essayID);
-
- return (
- {
- to(`/forum/${forumID}/${essayID}`);
- }
- }
- >
-
-
- {text}
-
-
- {getDatetime(date)}
-
-
-
- );
-}
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/CommentView.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/CommentView.tsx"
index afd8b21..7d99f3d 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/CommentView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/CommentView.tsx"
@@ -1,16 +1,22 @@
import CommentItem from "@/app/[language]/forum/components/CommentItem";
import useGetComment from "@/app/[language]/forum/query/useGetComment";
import usePostComment from "@/app/[language]/forum/query/usePostComment";
-import AvatarTitle from "@/components/AvatarTitle";
+import AvatarDrawing from "@/components/AvatarDrawing";
import { useTaehuiStore } from "@/state/Stores";
import { GetCommentAPI } from "@/type/wwwAPI";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import { useParams } from "next/navigation";
import { ReactNode, useMemo, useState } from "react";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Col from "react-bootstrap/Col";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import ReactTextareaAutosize from "react-textarea-autosize";
import { toast } from "react-toastify";
-import { Badge, Button, Col, Row } from "reactstrap";
export default observer(() => {
const t = useTranslations();
@@ -22,10 +28,10 @@
const { data: comment } = useGetComment(essayID);
const { mutateAsync: postComment } = usePostComment();
- const commentComponents = useMemo(() => {
- const commentComponents: ReactNode[] = [];
+ const commentItems = useMemo(() => {
+ const commentItems: ReactNode[] = [];
- const setCommentComponents =
+ const setCommentItems =
(level: number) =>
({
commentID,
@@ -35,7 +41,7 @@
text,
comments,
}: GetCommentAPI[number]) => {
- commentComponents.push(
+ commentItems.push(
,
);
- comments.forEach(setCommentComponents(level + 1));
+ comments.forEach(setCommentItems(level + 1));
};
comment.forEach((comment) => {
- setCommentComponents(0)(comment);
+ setCommentItems(0)(comment);
});
- return commentComponents;
+ return commentItems;
}, [comment]);
return (
- <>
-
-
-
- {t("commentCount", { commentCount: commentComponents.length })}
-
-
-
- {commentComponents}
+
+ {t("commentCount", { commentCount: commentItems.length })}
+
+ {commentItems}
{taehuiLevel >= 1 && (
-
-
-
-
- {
- setTextInput(value);
- }}
- />
-
-
- {
- if (textInput) {
- await postComment({
- essayID,
- targetCommentID: -1,
- text: textInput,
- });
- setTextInput("");
- } else {
- toast.error(t("failedValidation"));
- }
- }}
- >
- {t("postComment")}
-
-
-
-
+
+
+
+
+
+ {taehuiAvatarName}
+
+ {
+ setTextInput(value);
+ }}
+ />
+ {
+ if (textInput) {
+ await postComment({
+ essayID,
+ targetCommentID: -1,
+ text: textInput,
+ });
+ setTextInput("");
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+
+
)}
- >
+
);
});
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/EssayTitleView.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/EssayTitleView.tsx"
deleted file mode 100644
index 9d5d872..0000000
--- "a/taehui-fe/src/app/\133language\135/forum/components/EssayTitleView.tsx"
+++ /dev/null
@@ -1,47 +0,0 @@
-import AvatarTitle from "@/components/AvatarTitle";
-import { EssayAPIEssay } from "@/type/wwwAPI";
-import { useTranslations } from "next-intl";
-import { Col, ListGroupItem, Row } from "reactstrap";
-import { getDatetime } from "taehui-ts/date";
-import { useTo } from "taehui-ts/fe-utilities";
-
-export default function EssayTitleView({
- forumID,
- forumTitle,
- essay: { essayID, title, avatarID, avatarName, date, commentCount, hitCount },
-}: {
- forumID?: string;
- forumTitle?: string;
- essay: EssayAPIEssay;
-}) {
- const t = useTranslations();
- const to = useTo();
-
- const isLoading = !(forumID && essayID);
-
- return (
- {
- to(`/forum/${forumID}/${essayID}`);
- }
- }
- >
-
-
-
- {forumTitle && `[${forumTitle}]`} {title} [{commentCount}]
-
-
-
- {getDatetime(date)}
-
- {t("hitCount", { hitCount })}
-
-
-
- );
-}
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/FileUploadingWindow.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/FileUploadingWindow.tsx"
new file mode 100644
index 0000000..26d1b34
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/forum/components/FileUploadingWindow.tsx"
@@ -0,0 +1,17 @@
+import { useTranslations } from "next-intl";
+import Modal from "react-bootstrap/Modal";
+import ModalBody from "react-bootstrap/ModalBody";
+
+export default function FileUploadingWindow({
+ isOpened,
+}: {
+ isOpened: boolean;
+}) {
+ const t = useTranslations();
+
+ return (
+
+ {t("fileUploading")}
+
+ );
+}
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/ForumItem.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/ForumItem.tsx"
index cb9f0cf..9ca4e98 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/ForumItem.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/ForumItem.tsx"
@@ -1,7 +1,8 @@
-import EssayTitleView from "@/app/[language]/forum/components/EssayTitleView";
+import EssayTitleView from "@/components/EssayTitleView";
import { EssayAPIEssay } from "@/type/wwwAPI";
import Link from "next/link";
-import { Badge, ListGroup, ListGroupItemHeading } from "reactstrap";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
export default function ForumItem({
forum: { forumID, title, essays },
@@ -13,17 +14,15 @@
};
}) {
return (
- <>
-
-
- {title}
-
-
-
- {essays.map((essay) => (
-
- ))}
-
- >
+
+
+ {title}
+
+ {essays.map((essay) => (
+
+
+
+ ))}
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/PositionInput.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/PositionInput.tsx"
index d664c53..2bd3508 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/PositionInput.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/PositionInput.tsx"
@@ -1,7 +1,7 @@
import { useForumStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useMemo } from "react";
-import { Pagination, PaginationItem, PaginationLink } from "reactstrap";
+import Pagination from "react-bootstrap/Pagination";
import { useIntParam } from "taehui-ts/fe-utilities";
export default observer(() => {
@@ -9,8 +9,8 @@
const { param: page, setParam: setPage } = useIntParam("page", 1);
- const targetPages = useMemo(() => {
- const targetPages = [];
+ const pages = useMemo(() => {
+ const pages = [];
for (
let i = 1 + Math.floor((page - 1) / pageUnit) * pageUnit;
i <=
@@ -20,9 +20,9 @@
);
++i
) {
- targetPages.push(i);
+ pages.push(i);
}
- return targetPages;
+ return pages;
}, [lastPage, page, pageUnit]);
const isLowestPage = useMemo(() => page === 1, [page]);
@@ -30,49 +30,41 @@
return (
-
- {
+ setPage(1);
+ }}
+ />
+ {
+ setPage(page - 1);
+ }}
+ />
+ {pages.map((targetPage) => (
+ {
- setPage(1);
+ setPage(targetPage);
}}
- />
-
-
- {
- setPage(page - 1);
- }}
- />
-
- {targetPages.map((targetPage) => (
-
- {
- setPage(targetPage);
- }}
- >
- {targetPage}
-
-
+ >
+ {targetPage}
+
))}
-
- {
- setPage(page + 1);
- }}
- />
-
-
- {
- setPage(lastPage);
- }}
- />
-
+ {
+ setPage(page + 1);
+ }}
+ />
+ {
+ setPage(lastPage);
+ }}
+ />
);
});
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/TextView.module.scss" "b/taehui-fe/src/app/\133language\135/forum/components/TextView.module.scss"
index f097979..627ee3f 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/TextView.module.scss"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/TextView.module.scss"
@@ -1,5 +1,4 @@
@mixin essay() {
- border: thin black solid;
max-width: 100%;
}
diff --git "a/taehui-fe/src/app/\133language\135/forum/components/TextView.tsx" "b/taehui-fe/src/app/\133language\135/forum/components/TextView.tsx"
index 4297ad2..199a740 100644
--- "a/taehui-fe/src/app/\133language\135/forum/components/TextView.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forum/components/TextView.tsx"
@@ -1,15 +1,16 @@
import scss from "@/app/[language]/forum/components/TextView.module.scss";
import useGetHit from "@/app/[language]/forum/query/useGetHit";
-import AvatarTitle from "@/components/AvatarTitle";
+import AvatarDrawing from "@/components/AvatarDrawing";
import { getHitTexts, tag } from "@/utilities/Utility";
import { sanitize } from "isomorphic-dompurify";
import { useTranslations } from "next-intl";
import { useEffect, useMemo, useState } from "react";
-import { Badge, Col, Row } from "reactstrap";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
import { getDatetime } from "taehui-ts/date";
export default function TextView({
- forumTitle,
title,
text,
avatarID,
@@ -17,7 +18,6 @@
date,
hitCount,
}: {
- forumTitle: string;
title: string;
text: string;
avatarID: string;
@@ -60,35 +60,32 @@
return (
<>
-
-
- {forumTitle}
+
+
+
-
-
-
- {title}
-
-
- {typeof hitCount === "number" && (
- <>
- {getDatetime(date)}
-
+
+
+ {avatarName}
+ {title}
+
+
+
+
+ {getDatetime(date)}
+ {typeof hitCount === "number" && (
{t("hitCount", { hitCount })}
- >
- )}
+ )}
+
-
-
-
-
-
+
+
>
);
}
diff --git "a/taehui-fe/src/app/\133language\135/forum/query/useGetEssay.ts" "b/taehui-fe/src/app/\133language\135/forum/query/useGetEssay.ts"
index ec65822..bd39312 100644
--- "a/taehui-fe/src/app/\133language\135/forum/query/useGetEssay.ts"
+++ "b/taehui-fe/src/app/\133language\135/forum/query/useGetEssay.ts"
@@ -1,6 +1,7 @@
import { EssayAPIEssay, GetEssayAPI } from "@/type/wwwAPI";
import { wwwAPI } from "@/utilities/wwwAPI";
import { useQuery } from "@tanstack/react-query";
+import { getDatetime } from "taehui-ts/date";
import { useLanguage } from "taehui-ts/language";
export default function useGetEssay(essayID?: string) {
@@ -29,7 +30,7 @@
forumTitle: "",
title: "",
text: "",
- date: "",
+ date: getDatetime(),
avatarID: "",
avatarName: "",
hitCount: 0,
diff --git "a/taehui-fe/src/app/\133language\135/forum/query/useWipeAutoEssay.ts" "b/taehui-fe/src/app/\133language\135/forum/query/useWipeAutoEssay.ts"
index 3035212..7932d0a 100644
--- "a/taehui-fe/src/app/\133language\135/forum/query/useWipeAutoEssay.ts"
+++ "b/taehui-fe/src/app/\133language\135/forum/query/useWipeAutoEssay.ts"
@@ -10,8 +10,14 @@
const queryClient = useQueryClient();
return useMutation({
- mutationFn: async ({ autoEssayID }: { autoEssayID: number }) => {
- await wwwAPI.delete(`/autoEssay/${autoEssayID}`, {
+ mutationFn: async ({
+ forumID,
+ autoEssayID,
+ }: {
+ forumID: string;
+ autoEssayID: number;
+ }) => {
+ await wwwAPI.delete(`/autoEssay/${forumID}/${autoEssayID}`, {
headers: { millis: getMillis(), totem },
});
},
diff --git "a/taehui-fe/src/app/\133language\135/forum/state/setForumStore.ts" "b/taehui-fe/src/app/\133language\135/forum/state/setForumStore.ts"
index cefc759..ee04ce9 100644
--- "a/taehui-fe/src/app/\133language\135/forum/state/setForumStore.ts"
+++ "b/taehui-fe/src/app/\133language\135/forum/state/setForumStore.ts"
@@ -3,6 +3,7 @@
title: "",
text: "",
autoEssayID: undefined as number | undefined,
+ isAutoEssayOpened: false,
lastPage: 0,
pageUnit: 10,
@@ -21,6 +22,10 @@
this.autoEssayID = autoEssayID;
},
+ setAutoEssayOpened(isAutoEssayOpened: boolean) {
+ this.isAutoEssayOpened = isAutoEssayOpened;
+ },
+
setLastPage(lastPage: number) {
this.lastPage = lastPage;
},
diff --git "a/taehui-fe/src/app/\133language\135/forums/\133\133...forumGroup\135\135/page.tsx" "b/taehui-fe/src/app/\133language\135/forums/\133\133...forumGroup\135\135/page.tsx"
index a1c25bd..fff5a43 100644
--- "a/taehui-fe/src/app/\133language\135/forums/\133\133...forumGroup\135\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/forums/\133\133...forumGroup\135\135/page.tsx"
@@ -3,30 +3,21 @@
import ForumItem from "@/app/[language]/forum/components/ForumItem";
import useGetForums from "@/app/[language]/forums/query/useGetForums";
import { useParams } from "next/navigation";
-import { useEffect, useState } from "react";
-import { Col, Row } from "reactstrap";
-import { useWindowArea } from "taehui-ts/fe-utilities";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
export default function Page() {
- const [table, setTable] = useState(1);
-
- const { windowLength } = useWindowArea();
-
- useEffect(() => {
- setTable(windowLength < 992 ? 1 : 2);
- }, [windowLength]);
-
const { forumGroup } = useParams<{ forumGroup?: string }>();
const { data: forums, isFetched: isForumsLoaded } = useGetForums(forumGroup);
- return [...Array(Math.ceil(forums.length / table)).keys()].map((i) => (
-
- {forums.slice(table * i, table * i + table).map((forum) => (
-
+ return (
+
+ {forums.map((forum) => (
+
))}
- ));
+ );
}
diff --git "a/taehui-fe/src/app/\133language\135/layout.tsx" "b/taehui-fe/src/app/\133language\135/layout.tsx"
index 3ad3e2c..5189e04 100644
--- "a/taehui-fe/src/app/\133language\135/layout.tsx"
+++ "b/taehui-fe/src/app/\133language\135/layout.tsx"
@@ -4,13 +4,11 @@
import { getMessages } from "next-intl/server";
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";
-export default async function RootLayout({
+export default async function Layout({
children,
params: { language },
}: {
@@ -18,7 +16,7 @@
params: { language: string };
}) {
return (
-
+
Taehui
diff --git "a/taehui-fe/src/app/\133language\135/page.tsx" "b/taehui-fe/src/app/\133language\135/page.tsx"
index 1a00587..a4fa63c 100644
--- "a/taehui-fe/src/app/\133language\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/page.tsx"
@@ -1,35 +1,42 @@
"use client";
import HitView from "@/app/[language]/components/HitView";
-import LatestAvatarsView from "@/app/[language]/components/LatestAvatarsView";
import LatestCommentsView from "@/app/[language]/components/LatestCommentsView";
+import LatestEnrolledAvatarsView from "@/app/[language]/components/LatestEnrolledAvatarsView";
import LatestEssaysView from "@/app/[language]/components/LatestEssaysView";
+import LatestLoggedInAvatarsView from "@/app/[language]/components/LatestLoggedInAvatarsView";
+import MainView from "@/app/[language]/components/MainView";
import WantInput from "@/app/[language]/want/components/WantInput";
-import { useTranslations } from "next-intl";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
export default function Page() {
- const t = useTranslations();
-
return (
- <>
+
- {t("main00")}
-
- {t("main01")}
-
- {t("main02")}
-
- {t("main03")}
-
+
-
+
+
+
+
+
+
+
+
-
-
-
- >
+
+
+
+
+
+
+
+
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/ppt/page.tsx" "b/taehui-fe/src/app/\133language\135/ppt/page.tsx"
index d650e1b..b63761e 100644
--- "a/taehui-fe/src/app/\133language\135/ppt/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/ppt/page.tsx"
@@ -1,156 +1,154 @@
export default function Page() {
return (
<>
-
- 이름: 박태희
-
- 생년월일: 1994년 12월 21일
-
- 메일 주소:{" "}
- taehui@taehui.ddns.net
-
- 직장
-
- -
- (주) 네이버파이낸셜{" "}
- 프론트엔드 개발자 (2020년 3월 12일 ~)
-
- 경기도 성남시 분당구 정자일로 95 1784
-
- -
- (주) 네이버 2020 신입 프론트엔드
- 2020 신입 프론트엔드 개발자 (2020년 1월 2일 ~ 2020년 3월 11일)
-
- 경기도 성남시 분당구 불정로 6 NAVER
-
-
-
- 거주지
-
- - 경기도 성남시 분당구 (2020년)
- - 세종특별자치시 (2018년 ~ 2020년)
- - 대전광역시 유성구 (1994년 ~ 2018년)
-
-
- 경력
-
- -
-
- (주) 라인플러스 주 3일 인턴
- {" "}
- 안드로이드 앱 개발자 (2019년 4월 22일 ~ 2019년 6월 12일)
-
- 경기도 성남시 분당구 분당내곡로 117 크래프톤타워
-
-
-
- 학력
-
- -
- 금성초등학교 졸업 (2001년
- ~ 2007년)
-
- 대전광역시 유성구 신성로72번길 5
-
- -
- 성덕중학교 졸업 (2007년 ~
- 2010년)
-
- 대전광역시 유성구 신성로 19
-
- -
- 대덕고등학교 중퇴 후 고졸
- 검정고시 (2010년 ~ 2012년)
-
- 대전광역시 유성구 대덕대로556번길 15
-
- -
-
- 서울과학기술대학교 컴퓨터공학과
- {" "}
- 졸업 (평점 3.81 / 4.5) (2013년 3월 2일 ~ 2019년 2월 22일)
-
- 서울특별시 노원구 공릉로 232
-
-
-
- 군 복무
-
- -
- 대전시립박물관{" "}
- 사회복무요원 (2015년 3월 9일 ~ 2017년 3월 8일)
-
- 대전광역시 유성구 도안대로 398
-
- -
-
- {`"판, 세상을 담다"`}
- {" "}
- 골패점 개발자 (2015년 4월 30일 ~ 2015년 8월 30일)
-
- 대전광역시 유성구 도안대로 398
-
-
-
- 자격증
-
-
- 공모전
-
-
+ 이름: 박태희
+
+ 생년월일: 1994년 12월 21일
+
+ 메일 주소:{" "}
+ taehui@taehui.ddns.net
+
+ 직장
+
+ -
+ (주) 네이버파이낸셜{" "}
+ 프론트엔드 개발자 (2020년 3월 12일 ~)
+
+ 경기도 성남시 분당구 정자일로 95 1784
+
+ -
+ (주) 네이버 2020 신입 프론트엔드
+ 2020 신입 프론트엔드 개발자 (2020년 1월 2일 ~ 2020년 3월 11일)
+
+ 경기도 성남시 분당구 불정로 6 NAVER
+
+
+
+ 거주지
+
+ - 경기도 성남시 분당구 (2020년)
+ - 세종특별자치시 (2018년 ~ 2020년)
+ - 대전광역시 유성구 (1994년 ~ 2018년)
+
+
+ 경력
+
+ -
+
+ (주) 라인플러스 주 3일 인턴
+ {" "}
+ 안드로이드 앱 개발자 (2019년 4월 22일 ~ 2019년 6월 12일)
+
+ 경기도 성남시 분당구 분당내곡로 117 크래프톤타워
+
+
+
+ 학력
+
+ -
+ 금성초등학교 졸업 (2001년 ~
+ 2007년)
+
+ 대전광역시 유성구 신성로72번길 5
+
+ -
+ 성덕중학교 졸업 (2007년 ~
+ 2010년)
+
+ 대전광역시 유성구 신성로 19
+
+ -
+ 대덕고등학교 중퇴 후 고졸
+ 검정고시 (2010년 ~ 2012년)
+
+ 대전광역시 유성구 대덕대로556번길 15
+
+ -
+
+ 서울과학기술대학교 컴퓨터공학과
+ {" "}
+ 졸업 (평점 3.81 / 4.5) (2013년 3월 2일 ~ 2019년 2월 22일)
+
+ 서울특별시 노원구 공릉로 232
+
+
+
+ 군 복무
+
+ -
+ 대전시립박물관{" "}
+ 사회복무요원 (2015년 3월 9일 ~ 2017년 3월 8일)
+
+ 대전광역시 유성구 도안대로 398
+
+ -
+
+ {`"판, 세상을 담다"`}
+ {" "}
+ 골패점 개발자 (2015년 4월 30일 ~ 2015년 8월 30일)
+
+ 대전광역시 유성구 도안대로 398
+
+
+
+ 자격증
+
+
+ 공모전
+
>
);
}
diff --git "a/taehui-fe/src/app/\133language\135/query/useGetLatestAvatar.ts" "b/taehui-fe/src/app/\133language\135/query/useGetLatestAvatar.ts"
deleted file mode 100644
index 0acd626..0000000
--- "a/taehui-fe/src/app/\133language\135/query/useGetLatestAvatar.ts"
+++ /dev/null
@@ -1,15 +0,0 @@
-import { GetLatestAvatarAPI } from "@/type/wwwAPI";
-
-import { wwwAPI } from "@/utilities/wwwAPI";
-import { useQuery } from "@tanstack/react-query";
-
-export default function useGetLatestAvatar() {
- return useQuery({
- queryKey: ["latestAvatar"],
- queryFn: async () => {
- const { data } = await wwwAPI.get("/avatar/latest");
- return data;
- },
- initialData: [[], []],
- });
-}
diff --git "a/taehui-fe/src/app/\133language\135/query/useGetLatestEnrolledAvatar.ts" "b/taehui-fe/src/app/\133language\135/query/useGetLatestEnrolledAvatar.ts"
new file mode 100644
index 0000000..0558fd1
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/query/useGetLatestEnrolledAvatar.ts"
@@ -0,0 +1,15 @@
+import { GetLatestAPI } from "@/type/wwwAPI";
+
+import { wwwAPI } from "@/utilities/wwwAPI";
+import { useQuery } from "@tanstack/react-query";
+
+export default function useGetLatestEnrolledAvatar() {
+ return useQuery({
+ queryKey: ["latestEnrolledAvatar"],
+ queryFn: async () => {
+ const { data } = await wwwAPI.get("/avatar/latestEnrolled");
+ return data;
+ },
+ initialData: [],
+ });
+}
diff --git "a/taehui-fe/src/app/\133language\135/query/useGetLatestLoggedInAvatar.ts" "b/taehui-fe/src/app/\133language\135/query/useGetLatestLoggedInAvatar.ts"
new file mode 100644
index 0000000..688040e
--- /dev/null
+++ "b/taehui-fe/src/app/\133language\135/query/useGetLatestLoggedInAvatar.ts"
@@ -0,0 +1,15 @@
+import { GetLatestAPI } from "@/type/wwwAPI";
+
+import { wwwAPI } from "@/utilities/wwwAPI";
+import { useQuery } from "@tanstack/react-query";
+
+export default function useGetLatestLoggedInAvatar() {
+ return useQuery({
+ queryKey: ["latestLoggedInAvatar"],
+ queryFn: async () => {
+ const { data } = await wwwAPI.get("/avatar/latestLoggedIn");
+ return data;
+ },
+ initialData: [],
+ });
+}
diff --git "a/taehui-fe/src/app/\133language\135/want/\133wantVariety\135/\133\133...want\135\135/page.tsx" "b/taehui-fe/src/app/\133language\135/want/\133wantVariety\135/\133\133...want\135\135/page.tsx"
index fac28a7..b4d9b0b 100644
--- "a/taehui-fe/src/app/\133language\135/want/\133wantVariety\135/\133\133...want\135\135/page.tsx"
+++ "b/taehui-fe/src/app/\133language\135/want/\133wantVariety\135/\133\133...want\135\135/page.tsx"
@@ -1,27 +1,28 @@
"use client";
-import CommentTitleView from "@/app/[language]/forum/components/CommentTitleView";
-import EssayTitleView from "@/app/[language]/forum/components/EssayTitleView";
import WantInput from "@/app/[language]/want/components/WantInput";
import useGetWant from "@/app/[language]/want/query/useGetWant";
+import CommentTitleView from "@/components/CommentTitleView";
+import EssayTitleView from "@/components/EssayTitleView";
import { useWantStore } from "@/state/Stores";
import { GetWantAPIComment, GetWantAPIEssay } from "@/type/wwwAPI";
-import { useTranslations } from "next-intl";
import { useParams } from "next/navigation";
-import { useEffect } from "react";
+import { useEffect, useMemo } from "react";
+import ListGroup from "react-bootstrap/ListGroup";
+import ListGroupItem from "react-bootstrap/ListGroupItem";
+import Stack from "react-bootstrap/Stack";
import InfiniteScroll from "react-infinite-scroll-component";
-import { Col, ListGroup, ListGroupItemHeading, Row } from "reactstrap";
-import { useWant } from "taehui-ts/fe-utilities";
export default function Page() {
- const t = useTranslations();
-
const { setTextInput } = useWantStore();
const { wantVariety } = useParams<{
wantVariety: "essay" | "comment";
}>();
- const { want } = useWant("/want");
+ let { want: [want] = [""] } = useParams<{
+ want: string[];
+ }>();
+ want = useMemo(() => decodeURIComponent(want), [want]);
const {
fetchNextPage,
@@ -35,50 +36,42 @@
}, [setTextInput, want]);
return (
- <>
+
-
-
-
- {t("wantView")}
-
- {isWantLoaded && (
-
- fetchNextPage()}
- hasMore={hasNextPage}
- loader={null}
- >
- {wantVariety === "essay" &&
- (pages as GetWantAPIEssay[]).flatMap((wantedEssayTitle) => {
- return (
-
- );
- })}
- {wantVariety === "comment" &&
- (pages as GetWantAPIComment[]).flatMap(
- (wantedCommentTitle) => {
- return (
-
- );
- },
- )}
-
-
- )}
-
-
- >
+ {isWantLoaded && (pages as unknown[]).length > 0 && (
+ <>
+
+
+ fetchNextPage()}
+ hasMore={hasNextPage}
+ loader={null}
+ >
+ {wantVariety === "essay" &&
+ (pages as GetWantAPIEssay[]).flatMap((wantedEssayTitle) => (
+
+
+
+ ))}
+ {wantVariety === "comment" &&
+ (pages as GetWantAPIComment[]).flatMap((wantedCommentTitle) => (
+
+
+
+ ))}
+
+
+ >
+ )}
+
);
}
diff --git "a/taehui-fe/src/app/\133language\135/want/components/WantInput.tsx" "b/taehui-fe/src/app/\133language\135/want/components/WantInput.tsx"
index dd82816..b42e1f5 100644
--- "a/taehui-fe/src/app/\133language\135/want/components/WantInput.tsx"
+++ "b/taehui-fe/src/app/\133language\135/want/components/WantInput.tsx"
@@ -1,32 +1,28 @@
import { useWantStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import { ChangeEventHandler, KeyboardEventHandler, useState } from "react";
-import {
- Button,
- Col,
- Dropdown,
- DropdownItem,
- DropdownMenu,
- DropdownToggle,
- Input,
- Row,
-} from "reactstrap";
-import { useTo } from "taehui-ts/fe-utilities";
+import { useRouter } from "next/navigation";
+import { ChangeEventHandler, KeyboardEventHandler } from "react";
+import { Search } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import Dropdown from "react-bootstrap/Dropdown";
+import DropdownItem from "react-bootstrap/DropdownItem";
+import DropdownMenu from "react-bootstrap/DropdownMenu";
+import DropdownToggle from "react-bootstrap/DropdownToggle";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
export default observer(() => {
const { textInput, setTextInput, wantVariety, setWantVariety } =
useWantStore();
- const [isWantVarietyOpened, setWantVarietyOpened] = useState(false);
-
const t = useTranslations();
- const to = useTo();
+ const { push } = useRouter();
const onWant = () => {
if (textInput) {
- to(`/want/${wantVariety}/${encodeURIComponent(textInput)}`);
+ push(`/want/${wantVariety}/${textInput}`);
}
};
@@ -42,42 +38,30 @@
}
};
- const onCloseWantVariety = () => {
- setWantVarietyOpened(!isWantVarietyOpened);
- };
-
- const onInputWantVariety = (wantVariety: "essay" | "comment") => () => {
- setWantVariety(wantVariety);
- };
-
return (
-
-
-
- {t(wantVariety)}
-
-
- {t("essay")}
-
-
- {t("comment")}
-
-
-
-
-
-
-
-
-
- {t("onWant")}
-
-
-
+
+ {
+ if (eventKey) {
+ setWantVariety(eventKey);
+ }
+ }}
+ >
+ {t(wantVariety)}
+
+ {t("essay")}
+ {t("comment")}
+
+
+
+
+
+
+
);
});
diff --git a/taehui-fe/src/app/globals.scss b/taehui-fe/src/app/globals.scss
index 49a6948..052b097 100644
--- a/taehui-fe/src/app/globals.scss
+++ b/taehui-fe/src/app/globals.scss
@@ -1,62 +1,6 @@
-@mixin default() {
- font-family: "Century Gothic", sans-serif;
- font-size: 0.75rem;
-}
+@import "~bootstrap/scss/bootstrap";
+@import "taehui-ts/globals";
body {
- background: url("../assets/hexellence.png")
-}
-
-button {
- &.btn {
- @include default();
- }
-
- &.page-link {
- @include default();
- }
-
- &.dropdown-item {
- @include default();
- }
-}
-
-div, li, span {
- &.route {
- cursor: pointer;
- }
-}
-
-textarea {
- &.form-control {
- @include default();
- }
-}
-
-img {
- &.avatar {
- border: thin black solid;
- border-radius: 50%;
- }
-}
-
-input[type="search"],
-input[type="submit"],
-input[type="text"],
-input[type="email"],
-input[type="password"] {
- @include default();
-}
-
-span {
- @include default();
-
- &.badge {
- @include default();
- font-weight: normal;
- }
-
- &.ln {
- white-space: break-spaces;
- }
+ background: url("../assets/dark-honeycomb.png");
}
diff --git "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts" "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts"
index 5642836..71305f1 100644
--- "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts"
+++ "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/\133autoEssayID\135/route.ts"
@@ -1,18 +1,11 @@
-import logIP from "@/app/www/media/logIP";
-import validateMillis from "@/app/www/media/validateMillis";
-import validateTotem from "@/app/www/media/validateTotem";
import {
doModifyAutoEssay,
- getAutoEssays,
postAutoEssay,
wipeAutoEssay,
} from "@/app/www/logic/autoEssay";
-
-export const GET = validateMillis(async (req, { params: { forumID } }) => {
- const avatarID = req.headers.get("avatarID");
-
- return Response.json(await getAutoEssays(forumID, avatarID as string));
-});
+import logIP from "@/app/www/media/logIP";
+import validateMillis from "@/app/www/media/validateMillis";
+import validateTotem from "@/app/www/media/validateTotem";
export const POST = logIP(
validateMillis(
@@ -55,10 +48,10 @@
export const DELETE = logIP(
validateMillis(
validateTotem(async (req, { params: { autoEssayID } }) => {
- const avatarID = req.headers.get("avatarID");
+ const avatarID = req.headers.get("avatarID") as string;
return new Response(undefined, {
- status: (await wipeAutoEssay(Number(autoEssayID), avatarID as string))
+ status: (await wipeAutoEssay(Number(autoEssayID), avatarID))
? 204
: 403,
});
diff --git "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts" "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts"
index bc491be..ca72f1a 100644
--- "a/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts"
+++ "b/taehui-fe/src/app/www/autoEssay/\133forumID\135/route.ts"
@@ -1,12 +1,14 @@
+import { getAutoEssays, postAutoEssay } from "@/app/www/logic/autoEssay";
import validateMillis from "@/app/www/media/validateMillis";
import validateTotem from "@/app/www/media/validateTotem";
-import { getAutoEssays, postAutoEssay } from "@/app/www/logic/autoEssay";
-export const GET = validateMillis(async (req, { params: { forumID } }) => {
- const avatarID = req.headers.get("avatarID") as string;
+export const GET = validateMillis(
+ validateTotem(async (req, { params: { forumID } }) => {
+ const avatarID = req.headers.get("avatarID") as string;
- return Response.json(await getAutoEssays(forumID, avatarID));
-});
+ return Response.json(await getAutoEssays(forumID, avatarID));
+ }),
+);
export const POST = validateMillis(
validateTotem(async (req, { params: { forumID } }) => {
diff --git a/taehui-fe/src/app/www/avatar/latest/route.ts b/taehui-fe/src/app/www/avatar/latest/route.ts
deleted file mode 100644
index 3e8e607..0000000
--- a/taehui-fe/src/app/www/avatar/latest/route.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import logIP from "@/app/www/media/logIP";
-import { getLatestAvatars } from "@/app/www/logic/avatar";
-
-export const GET = logIP(async () => {
- return Response.json(await getLatestAvatars());
-});
diff --git a/taehui-fe/src/app/www/avatar/latestEnrolled/route.ts b/taehui-fe/src/app/www/avatar/latestEnrolled/route.ts
new file mode 100644
index 0000000..3c66f91
--- /dev/null
+++ b/taehui-fe/src/app/www/avatar/latestEnrolled/route.ts
@@ -0,0 +1,6 @@
+import { getLatestEnrolledAvatars } from "@/app/www/logic/avatar";
+import logIP from "@/app/www/media/logIP";
+
+export const GET = logIP(async () => {
+ return Response.json(await getLatestEnrolledAvatars());
+});
diff --git a/taehui-fe/src/app/www/avatar/latestLoggedIn/route.ts b/taehui-fe/src/app/www/avatar/latestLoggedIn/route.ts
new file mode 100644
index 0000000..c2233ab
--- /dev/null
+++ b/taehui-fe/src/app/www/avatar/latestLoggedIn/route.ts
@@ -0,0 +1,6 @@
+import { getLatestLoggedInAvatars } from "@/app/www/logic/avatar";
+import logIP from "@/app/www/media/logIP";
+
+export const GET = logIP(async () => {
+ return Response.json(await getLatestLoggedInAvatars());
+});
diff --git a/taehui-fe/src/app/www/avatar/totem/route.ts b/taehui-fe/src/app/www/avatar/totem/route.ts
index 0b9b1b8..96aa014 100644
--- a/taehui-fe/src/app/www/avatar/totem/route.ts
+++ b/taehui-fe/src/app/www/avatar/totem/route.ts
@@ -9,10 +9,10 @@
return Response.json(
{
avatarID: headers.get("avatarID"),
- avatarName: headers.get("avatarName"),
+ avatarName: decodeURIComponent(headers.get("avatarName") as string),
level: Number(headers.get("level")),
- fax: headers.get("fax"),
- avatarIntro: headers.get("avatarIntro"),
+ fax: decodeURIComponent(headers.get("fax") as string),
+ avatarIntro: decodeURIComponent(headers.get("avatarIntro") as string),
},
{ status: 201 },
);
diff --git a/taehui-fe/src/app/www/commentary/route.ts b/taehui-fe/src/app/www/commentary/route.ts
index de1d8c1..55b1e98 100644
--- a/taehui-fe/src/app/www/commentary/route.ts
+++ b/taehui-fe/src/app/www/commentary/route.ts
@@ -1,11 +1,11 @@
-import logIP from "@/app/www/media/logIP";
-import validateMillis from "@/app/www/media/validateMillis";
import {
doModifyCommentary,
getCommentary,
postCommentary,
wipeCommentary,
} from "@/app/www/logic/commentary";
+import logIP from "@/app/www/media/logIP";
+import validateMillis from "@/app/www/media/validateMillis";
export const GET = logIP(async () => {
return Response.json(await getCommentary());
diff --git a/taehui-fe/src/app/www/file/route.ts b/taehui-fe/src/app/www/file/route.ts
index 53ca5f2..07f8a15 100644
--- a/taehui-fe/src/app/www/file/route.ts
+++ b/taehui-fe/src/app/www/file/route.ts
@@ -22,7 +22,7 @@
await writeFile(
join(ESSAY_ENTRY_PATH, fileName),
Buffer.from(await file.arrayBuffer()),
- { flag: "wx" },
+ { flag: "w" },
);
return Response.json({ fileName }, { status: 201 });
}),
diff --git a/taehui-fe/src/app/www/logic/avatar.ts b/taehui-fe/src/app/www/logic/avatar.ts
index ce4d9f6..8b6ab38 100644
--- a/taehui-fe/src/app/www/logic/avatar.ts
+++ b/taehui-fe/src/app/www/logic/avatar.ts
@@ -2,7 +2,8 @@
doModifyAvatar as dbModifyAvatar,
doModifyAvatarIntro as dbModifyAvatarIntro,
getAvatar,
- getLatestAvatars as dbGetLatestAvatars,
+ getLatestEnrolledAvatars as dbGetLatestEnrolledAvatars,
+ getLatestLoggedInAvatars as dbGetLatestLoggedInAvatars,
postAvatar as dbPostAvatar,
setLastDate,
} from "@/app/www/system/DB";
@@ -133,8 +134,12 @@
}
};
-export const getLatestAvatars = async () => {
- return dbGetLatestAvatars();
+export const getLatestLoggedInAvatars = async () => {
+ return dbGetLatestLoggedInAvatars();
+};
+
+export const getLatestEnrolledAvatars = async () => {
+ return dbGetLatestEnrolledAvatars();
};
export const doInvalidateDrawing = async (avatarID: string) => {
diff --git a/taehui-fe/src/app/www/media/validateTotem.ts b/taehui-fe/src/app/www/media/validateTotem.ts
index c71d87b..6abf0d4 100644
--- a/taehui-fe/src/app/www/media/validateTotem.ts
+++ b/taehui-fe/src/app/www/media/validateTotem.ts
@@ -22,7 +22,7 @@
const avatar = await getAvatar(avatarID);
if (avatar) {
const { avatarID, avatarName, level, fax, avatarIntro } = avatar;
- req.headers.set("avatarID", encodeURIComponent(avatarID));
+ req.headers.set("avatarID", avatarID);
req.headers.set("avatarName", encodeURIComponent(avatarName));
req.headers.set("level", level.toString());
req.headers.set("fax", encodeURIComponent(fax));
diff --git a/taehui-fe/src/app/www/system/DB.ts b/taehui-fe/src/app/www/system/DB.ts
index a6cd2c8..3ef22a4 100644
--- a/taehui-fe/src/app/www/system/DB.ts
+++ b/taehui-fe/src/app/www/system/DB.ts
@@ -1,6 +1,6 @@
import Logger from "@/app/www/system/Logger";
import { ESSAY_ENTRY_PATH } from "@/app/www/utilities/Path";
-import { equalCipher, isTaehui } from "@/app/www/utilities/Utility";
+import { equalCipher, isSU } from "@/app/www/utilities/Utility";
import { readdir, unlink } from "fs/promises";
import {
Connection,
@@ -379,8 +379,9 @@
}[]
>(
`SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title
- FROM tn_essay, tn_avatar
- WHERE Forum_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID AND tn_essay.Date < ?
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE Forum_ID = ? AND tn_essay.Date < ?
ORDER BY tn_essay.Date DESC
LIMIT 1`,
[forumID, datetime],
@@ -414,8 +415,9 @@
}[]
>(
`SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title
- FROM tn_essay, tn_avatar
- WHERE Forum_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID AND tn_essay.Date > ?
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE Forum_ID = ? AND tn_essay.Date > ?
ORDER BY tn_essay.Date
LIMIT 1`,
[forumID, datetime],
@@ -450,8 +452,8 @@
}[]
>(
`SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title, tn_essay.Text
- FROM tn_essay, tn_avatar
- WHERE tn_avatar.Avatar_ID = tn_essay.Avatar_ID
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
ORDER BY tn_essay.Date DESC
LIMIT 5`,
);
@@ -578,7 +580,7 @@
text: string,
level: number,
) {
- const { affectedRows } = isTaehui(level)
+ const { affectedRows } = isSU(level)
? await db.query(
`UPDATE tn_essay
SET Title = ?, Text = ?
@@ -600,7 +602,7 @@
level: number,
) {
return getDB(async (db) => {
- const { affectedRows } = isTaehui(level)
+ const { affectedRows } = isSU(level)
? await db.query(
`DELETE
FROM tn_essay
@@ -652,8 +654,9 @@
}[]
>(
`SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title, Text
- FROM tn_essay, tn_avatar
- WHERE Essay_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID`,
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE Essay_ID = ?`,
[essayID],
)
)[0];
@@ -711,8 +714,9 @@
}[]
>(
`SELECT Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title
- FROM tn_essay, tn_avatar
- WHERE Forum_ID = ? AND tn_avatar.Avatar_ID = tn_essay.Avatar_ID
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE Forum_ID = ?
ORDER BY tn_essay.Date DESC
LIMIT ?, ?`,
[forumID, (page - 1) * viewUnit, viewUnit],
@@ -753,11 +757,12 @@
}[]
>(
`SELECT Forum_ID, Essay_ID, tn_essay.Avatar_ID, Avatar_Name, tn_essay.Date, Title
- FROM tn_essay, tn_avatar
- WHERE tn_avatar.Avatar_ID = tn_essay.Avatar_ID AND MATCH(Text) AGAINST(?)
+ FROM tn_essay
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE MATCH(Text) AGAINST(? IN BOOLEAN MODE)
ORDER BY tn_essay.Date DESC
LIMIT ?, ?`,
- [wantInput, (page - 1) * viewUnit, viewUnit],
+ [`${wantInput}*`, (page - 1) * viewUnit, viewUnit],
)
).map(async (data) => {
const essayID = Number(data["Essay_ID"]);
@@ -794,11 +799,13 @@
}[]
>(
`SELECT Forum_ID, tn_comment.Essay_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, tn_comment.Text
- FROM tn_essay, tn_comment, tn_avatar
- WHERE tn_essay.Essay_ID = tn_comment.Essay_ID AND tn_comment.Avatar_ID = tn_avatar.Avatar_ID AND MATCH(tn_comment.Text) AGAINST(?)
+ FROM tn_comment
+ INNER JOIN tn_essay USING(Essay_ID)
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE MATCH(tn_comment.Text) AGAINST(? IN BOOLEAN MODE)
ORDER BY tn_comment.Date DESC
LIMIT ?, ?`,
- [wantInput, (page - 1) * viewUnit, viewUnit],
+ [`${wantInput}*`, (page - 1) * viewUnit, viewUnit],
)
).map((data) => ({
forumID: data["Forum_ID"],
@@ -857,7 +864,7 @@
level: number,
) {
return getDB(async (db) => {
- const { affectedRows } = isTaehui(level)
+ const { affectedRows } = isSU(level)
? await db.query(
`UPDATE tn_comment
SET Text = ?
@@ -880,7 +887,7 @@
level: number,
) {
return getDB(async (db) => {
- const { affectedRows } = isTaehui(level)
+ const { affectedRows } = isSU(level)
? await db.query(
`DELETE
FROM tn_comment
@@ -910,8 +917,9 @@
}[]
>(
`SELECT Comment_ID, Target_Comment_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, Text
- FROM tn_comment, tn_avatar
- WHERE Essay_ID = ? AND tn_avatar.Avatar_ID = tn_comment.Avatar_ID
+ FROM tn_comment
+ INNER JOIN tn_avatar USING(Avatar_ID)
+ WHERE Essay_ID = ?
ORDER BY tn_comment.Date`,
[essayID],
);
@@ -940,8 +948,9 @@
}[]
>(
`SELECT Comment_ID, Forum_ID, tn_comment.Essay_ID AS Essay_ID, tn_comment.Avatar_ID, Avatar_Name, tn_comment.Date, tn_comment.Text
- FROM tn_comment, tn_essay, tn_avatar
- WHERE tn_comment.Essay_ID = tn_essay.Essay_ID AND tn_avatar.Avatar_ID = tn_comment.Avatar_ID
+ FROM tn_comment
+ INNER JOIN tn_essay USING(Essay_ID)
+ INNER JOIN tn_avatar ON tn_comment.Avatar_ID = tn_avatar.Avatar_ID
ORDER BY tn_comment.Date DESC
LIMIT 5`,
);
@@ -1118,36 +1127,41 @@
});
}
-export async function getLatestAvatars() {
+export async function getLatestLoggedInAvatars() {
return getDB(async (db) => {
- return Promise.all(
- ["Date", "Last_Date"].map(async (date) => {
- return (
- await db.query<
- { Avatar_ID: string; Avatar_Name: string; Date: string }[]
- >(
- `SELECT Avatar_ID, Avatar_Name, ${date} AS Date
+ return (
+ await db.query<
+ { Avatar_ID: string; Avatar_Name: string; Last_Date: string }[]
+ >(
+ `SELECT Avatar_ID, Avatar_Name, Last_Date
+ FROM tn_avatar
+ ORDER BY Last_Date DESC
+ LIMIT 5`,
+ )
+ ).map(({ Avatar_ID, Avatar_Name, Last_Date }) => ({
+ avatarID: Avatar_ID,
+ avatarName: Avatar_Name,
+ date: Last_Date,
+ }));
+ });
+}
+
+export async function getLatestEnrolledAvatars() {
+ return getDB(async (db) => {
+ return (
+ await db.query<
+ { Avatar_ID: string; Avatar_Name: string; Date: string }[]
+ >(
+ `SELECT Avatar_ID, Avatar_Name, Date
FROM tn_avatar
ORDER BY Date DESC
LIMIT 5`,
- )
- ).map(
- ({
- Avatar_ID,
- Avatar_Name,
- Date,
- }: {
- Avatar_ID: string;
- Avatar_Name: string;
- Date: string;
- }) => ({
- avatarID: Avatar_ID,
- avatarName: Avatar_Name,
- date: Date,
- }),
- );
- }),
- );
+ )
+ ).map(({ Avatar_ID, Avatar_Name, Date }) => ({
+ avatarID: Avatar_ID,
+ avatarName: Avatar_Name,
+ date: Date,
+ }));
});
}
@@ -1181,8 +1195,8 @@
>(
`SELECT Auto_Essay_ID, Title, Text, Date
FROM tn_auto_essay
- WHERE Forum_ID = ? AND Avatar_ID = ?`,
- [forumID, avatarID],
+ WHERE Avatar_ID = ? AND Forum_ID = ?`,
+ [avatarID, forumID],
)
).map(({ Auto_Essay_ID, Title, Text, Date }) => ({
autoEssayID: Auto_Essay_ID,
diff --git a/taehui-fe/src/app/www/utilities/Utility.ts b/taehui-fe/src/app/www/utilities/Utility.ts
index cb3c21d..563a2e2 100644
--- a/taehui-fe/src/app/www/utilities/Utility.ts
+++ b/taehui-fe/src/app/www/utilities/Utility.ts
@@ -109,4 +109,4 @@
}
};
-export const isTaehui = (level: number) => level === 2;
+export const isSU = (level: number) => level === 2;
diff --git a/taehui-fe/src/assets/dark-honeycomb.png b/taehui-fe/src/assets/dark-honeycomb.png
index 6ac0c5f..b6a0b0d 100644
--- a/taehui-fe/src/assets/dark-honeycomb.png
+++ b/taehui-fe/src/assets/dark-honeycomb.png
Binary files differ
diff --git a/taehui-fe/src/assets/language/en.json b/taehui-fe/src/assets/language/en.json
index e816da3..940b155 100644
--- a/taehui-fe/src/assets/language/en.json
+++ b/taehui-fe/src/assets/language/en.json
@@ -1,8 +1,8 @@
{
"alreadyAvatarID": "This ID is already registered.",
- "assistForum": "Manual",
- "autoEssay": "Auto Save",
+ "assist": "Manual",
"autoEssays": "Auto Save List",
+ "autoEssayText": "Do you want to load auto-saved posts? The text you are writing will disappear.",
"autoLogIn": "Automatic login",
"avatarCipher": "Password",
"avatarCipherModified": "Password to be modified",
@@ -13,12 +13,9 @@
"comment": "Comment",
"commentary": "Guestbook",
"commentCount": "{commentCount} comments",
- "dateForum": "Update History",
+ "date": "Update History",
"doModifiedAvatar": "Please log in again because your password has been modified",
- "doModifyAvatar": "Edit information",
- "doModifyComment": "Edit comment",
- "doModifyCommentary": "Edit guestbook",
- "doModifyEssay": "Edit post",
+ "enroll": "Join membership",
"essay": "Bulletin",
"essayBefore": "Previous post",
"essayLater": "Next post",
@@ -27,6 +24,7 @@
"fax": "E-mail",
"fileUpload": "Upload File",
"fileUploading": "Uploading.",
+ "forum": "Qwilight Bulletin",
"forums": "All Bulletins",
"hit00": "Visitor statistics",
"hit01": "{hitBefore} visitors yesterday",
@@ -34,39 +32,27 @@
"hit03": "Visits count from 2022-11-07.",
"hitCount": "{hitCount} views",
"hitFileCount": "Download {hit} times",
- "latestAvatarsView0": "Registered member",
- "latestAvatarsView1": "Member visited",
"latestCommentsView": "Comment written",
+ "latestEnrolledAvatarsView": "Registered member",
"latestEssaysView": "Posts Created",
- "notLoggedIn": "Sign out",
- "notLoggedInText": "Thank you, {avatarName}.",
- "onWant": "Search",
- "postComment": "Write comment",
- "postCommentary": "Write guestbook",
- "postedAutoEssay": "Your post will be saved automatically.",
- "postEssay": "Write post",
- "quit": "Exit",
- "qwilightForum": "Qwilight Bulletin",
- "setAutoEssayQuestion": "Do you want to load auto-saved posts? The text you are writing will disappear.",
+ "latestLoggedInAvatarsView": "Member visited",
"loggedInText": "Welcome, {avatarName}.",
"logIn": "Login",
- "signUp": "Join membership",
- "softwareForum": "Software",
- "ppt": "Developer Profile",
"main": "Home",
"main00": "Hello",
"main01": "This is 불로그 run by Taehui.",
"main02": "I am in charge of providing and operating the software I made.",
"main03": "This site is still under development.",
+ "notLoggedInText": "Thank you, {avatarName}.",
+ "postedAutoEssay": "Your post will be saved automatically.",
+ "ppt": "Developer Profile",
+ "setTestMode": "Preview",
+ "software": "Software",
"text": "Main text",
"textTag": "Letter",
"title": "Title",
- "viewEditedEssay": "Preview",
- "wantView": "Search Results",
- "wipeComment": "Delete Comment",
- "wipeCommentary": "Delete guestbook",
- "wipeCommentQuestion": "Are you sure you want to delete the comment?",
- "wipeEssay": "Delete post",
- "wipeEssayQuestion": "Are you sure you want to delete the post?",
+ "wipeAutoEssay": "Delete",
+ "wipeCommentText": "Are you sure you want to delete the comment?",
+ "wipeEssayText": "Are you sure you want to delete the post?",
"wrongAvatar": "This account is not valid."
}
diff --git a/taehui-fe/src/assets/language/ko.json b/taehui-fe/src/assets/language/ko.json
index 6fed780..3fbf176 100644
--- a/taehui-fe/src/assets/language/ko.json
+++ b/taehui-fe/src/assets/language/ko.json
@@ -1,8 +1,8 @@
{
"alreadyAvatarID": "이미 가입된 아이디입니다.",
- "assistForum": "매뉴얼",
- "autoEssay": "자동 저장",
+ "assist": "매뉴얼",
"autoEssays": "자동 저장 목록",
+ "autoEssayText": "자동 저장된 게시글을 불러올까요? 작성중인 글은 사라집니다.",
"autoLogIn": "자동 로그인",
"avatarCipher": "비밀번호",
"avatarCipherModified": "수정할 비밀번호",
@@ -13,12 +13,9 @@
"comment": "덧글",
"commentary": "방명록",
"commentCount": "덧글 {commentCount} 개",
- "dateForum": "업데이트 내역",
+ "date": "업데이트 내역",
"doModifiedAvatar": "비밀번호가 수정되어 다시 로그인하세요",
- "doModifyAvatar": "정보 수정",
- "doModifyComment": "덧글 수정",
- "doModifyCommentary": "방명록 수정",
- "doModifyEssay": "게시글 수정",
+ "enroll": "회원 가입",
"essay": "게시글",
"essayBefore": "이전 게시글",
"essayLater": "다음 게시글",
@@ -27,6 +24,7 @@
"fax": "이메일",
"fileUpload": "파일 업로드",
"fileUploading": "업로드하는 중입니다.",
+ "forum": "Qwilight 게시판",
"forums": "모든 게시판",
"hit00": "방문자 통계",
"hit01": "어제 방문자 {hitBefore} 명",
@@ -34,39 +32,27 @@
"hit03": "방문자 수는 2022-11-07 부터 집계됩니다.",
"hitCount": "조회수 {hitCount} 회",
"hitFileCount": "{hit} 회 다운로드",
- "latestAvatarsView0": "가입한 회원",
- "latestAvatarsView1": "방문한 회원",
"latestCommentsView": "작성된 덧글",
+ "latestEnrolledAvatarsView": "가입한 회원",
"latestEssaysView": "작성된 게시글",
- "notLoggedIn": "로그아웃",
- "notLoggedInText": "{avatarName}님 감사합니다.",
- "onWant": "검색",
- "postComment": "덧글 쓰기",
- "postCommentary": "방명록 쓰기",
- "postedAutoEssay": "게시글이 자동으로 저장됩니다.",
- "postEssay": "게시글 쓰기",
- "quit": "나가기",
- "qwilightForum": "Qwilight 게시판",
- "setAutoEssayQuestion": "자동 저장된 게시글을 불러올까요? 작성중인 글은 사라집니다.",
+ "latestLoggedInAvatarsView": "방문한 회원",
"loggedInText": "{avatarName}님 환영합니다.",
"logIn": "로그인",
- "signUp": "회원 가입",
- "softwareForum": "소프트웨어",
- "ppt": "개발자 프로필",
"main": "홈으로",
"main00": "안녕하세요",
"main01": "Taehui가 운영하는 불로그입니다.",
"main02": "제가 만든 소프트웨어의 제공과 운영을 담당합니다.",
"main03": "이 사이트는 아직 개발 중입니다.",
+ "notLoggedInText": "{avatarName}님 감사합니다.",
+ "postedAutoEssay": "게시글이 자동으로 저장됩니다.",
+ "ppt": "개발자 프로필",
+ "setTestMode": "미리 보기",
+ "software": "소프트웨어",
"text": "본문",
"textTag": "글자",
"title": "제목",
- "viewEditedEssay": "미리 보기",
- "wantView": "검색 결과",
- "wipeComment": "덧글 삭제",
- "wipeCommentary": "방명록 삭제",
- "wipeCommentQuestion": "덧글을 삭제할까요?",
- "wipeEssay": "게시글 삭제",
- "wipeEssayQuestion": "게시글을 삭제할까요?",
+ "wipeAutoEssay": "삭제",
+ "wipeCommentText": "덧글을 삭제할까요?",
+ "wipeEssayText": "게시글을 삭제할까요?",
"wrongAvatar": "올바르지 않은 계정입니다."
}
diff --git a/taehui-fe/src/assets/light_honeycomb.png b/taehui-fe/src/assets/light_honeycomb.png
new file mode 100644
index 0000000..b40112b
--- /dev/null
+++ b/taehui-fe/src/assets/light_honeycomb.png
Binary files differ
diff --git a/taehui-fe/src/assets/vcs.png b/taehui-fe/src/assets/vcs.png
index 007cc4c..910f993 100644
--- a/taehui-fe/src/assets/vcs.png
+++ b/taehui-fe/src/assets/vcs.png
Binary files differ
diff --git a/taehui-fe/src/components/AvatarDrawing.tsx b/taehui-fe/src/components/AvatarDrawing.tsx
new file mode 100644
index 0000000..909d5c1
--- /dev/null
+++ b/taehui-fe/src/components/AvatarDrawing.tsx
@@ -0,0 +1,23 @@
+import { wwwAPIPath } from "@/utilities/wwwAPI";
+import dayjs from "dayjs";
+import Image from "next/image";
+
+export default function AvatarDrawing({
+ avatarID,
+ drawingLength = 48,
+ drawingHeight = 48,
+}: {
+ avatarID: string;
+ drawingLength?: number;
+ drawingHeight?: number;
+}) {
+ return (
+
+ );
+}
diff --git a/taehui-fe/src/components/AvatarTitle.tsx b/taehui-fe/src/components/AvatarTitle.tsx
deleted file mode 100644
index 8b73349..0000000
--- a/taehui-fe/src/components/AvatarTitle.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { wwwAPIPath } from "@/utilities/wwwAPI";
-import dayjs from "dayjs";
-import Image from "next/image";
-import { ReactNode } from "react";
-import { Col } from "reactstrap";
-
-export default function AvatarTitle({
- avatarID,
- avatarName,
- children,
-}: {
- avatarID: string;
- avatarName: string;
- children: ReactNode;
-}) {
- return (
- <>
- {
- e.stopPropagation();
- }}
- >
-
-
-
- {avatarName}
-
- {children}
-
- >
- );
-}
diff --git a/taehui-fe/src/components/AvatarView.tsx b/taehui-fe/src/components/AvatarView.tsx
index 200168d..694ae66 100644
--- a/taehui-fe/src/components/AvatarView.tsx
+++ b/taehui-fe/src/components/AvatarView.tsx
@@ -3,12 +3,9 @@
import { useTaehuiStore } from "@/state/Stores";
import { observer } from "mobx-react-lite";
-import { useTranslations } from "next-intl";
export default observer(
({ isSessionLoading }: { isSessionLoading: boolean }) => {
- const t = useTranslations();
-
const { totem, taehuiAvatarID, taehuiAvatarName } = useTaehuiStore();
if (isSessionLoading) {
diff --git a/taehui-fe/src/components/CommentTitleView.tsx b/taehui-fe/src/components/CommentTitleView.tsx
new file mode 100644
index 0000000..e762758
--- /dev/null
+++ b/taehui-fe/src/components/CommentTitleView.tsx
@@ -0,0 +1,46 @@
+import AvatarDrawing from "@/components/AvatarDrawing";
+import { GetLatestCommentAPI } from "@/type/wwwAPI";
+import Link from "next/link";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import { getDatetime } from "taehui-ts/date";
+
+export default function CommentTitleView({
+ forumID,
+ essayID,
+ comment: { commentID, avatarID, avatarName, date, text },
+}: {
+ forumID?: string;
+ essayID?: number;
+ comment: GetLatestCommentAPI[number];
+}) {
+ const isLoading = !(
+ typeof forumID === "string" &&
+ commentID >= 0 &&
+ typeof essayID === "number"
+ );
+
+ return (
+
+
+
+
+
+
+ {avatarName}
+ {text}
+
+
+
+ {getDatetime(date)}
+
+
+ );
+}
diff --git a/taehui-fe/src/components/EnrollView.tsx b/taehui-fe/src/components/EnrollView.tsx
new file mode 100644
index 0000000..744af1a
--- /dev/null
+++ b/taehui-fe/src/components/EnrollView.tsx
@@ -0,0 +1,121 @@
+import usePostAvatar from "@/query/usePostAvatar";
+import { useTranslations } from "next-intl";
+import { useMemo, useState } from "react";
+import Button from "react-bootstrap/Button";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Stack from "react-bootstrap/Stack";
+import { toast } from "react-toastify";
+
+export default function EnrollView() {
+ const t = useTranslations();
+
+ const [avatarID, setAvatarID] = useState("");
+ const [avatarCipher, setAvatarCipher] = useState("");
+ const [avatarCipherTest, setAvatarCipherTest] = useState("");
+ const [avatarName, setAvatarName] = useState("");
+ const [fax, setFax] = useState("");
+
+ const isValidFax = useMemo(() => /^.+@.+$/.test(fax), [fax]);
+ const isValidAvatarID = useMemo(
+ () => /[a-zA-Z\d]/.test(avatarID),
+ [avatarID],
+ );
+
+ const { mutateAsync: postAvatar } = usePostAvatar();
+
+ return (
+
+
+ {t("avatarID")}
+ {
+ setAvatarID(value);
+ }}
+ />
+
+
+ {t("avatarCipher")}
+ {
+ setAvatarCipher(value);
+ }}
+ />
+
+
+ {t("avatarCipherTest")}
+ {
+ setAvatarCipherTest(value);
+ }}
+ />
+
+
+ {t("avatarName")}
+ 0 && avatarName.length <= 16}
+ isInvalid={avatarName.length > 16}
+ maxLength={16}
+ placeholder={t("avatarName")}
+ value={avatarName}
+ onChange={({ target: { value } }) => {
+ setAvatarName(value);
+ }}
+ />
+
+
+ {t("fax")}
+ {
+ setFax(value);
+ }}
+ />
+
+ {
+ if (
+ isValidAvatarID &&
+ avatarCipher &&
+ avatarCipher === avatarCipherTest &&
+ avatarName &&
+ (!fax || isValidFax)
+ ) {
+ await postAvatar({
+ avatarID,
+ avatarCipher,
+ avatarName,
+ fax,
+ });
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+ {t("enroll")}
+
+
+ );
+}
diff --git a/taehui-fe/src/components/EssayTitleView.tsx b/taehui-fe/src/components/EssayTitleView.tsx
new file mode 100644
index 0000000..49c1f92
--- /dev/null
+++ b/taehui-fe/src/components/EssayTitleView.tsx
@@ -0,0 +1,50 @@
+import AvatarDrawing from "@/components/AvatarDrawing";
+import { EssayAPIEssay } from "@/type/wwwAPI";
+import { useTranslations } from "next-intl";
+import Link from "next/link";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
+import { getDatetime } from "taehui-ts/date";
+
+export default function EssayTitleView({
+ forumID,
+ forumTitle,
+ essay: { essayID, title, avatarID, avatarName, date, commentCount, hitCount },
+}: {
+ forumID?: string;
+ forumTitle?: string;
+ essay: EssayAPIEssay;
+}) {
+ const t = useTranslations();
+
+ const isLoading = !(typeof forumID === "string" && essayID >= 0);
+
+ return (
+
+
+
+
+
+
+ {avatarName}
+
+ {forumTitle && `[${forumTitle}]`} {title} [{commentCount}]
+
+
+
+
+
+ {getDatetime(date)}
+ {t("hitCount", { hitCount })}
+
+
+
+ );
+}
diff --git a/taehui-fe/src/components/LoggedInAvatarView.tsx b/taehui-fe/src/components/LoggedInAvatarView.tsx
index a3db2ef..2ba7713 100644
--- a/taehui-fe/src/components/LoggedInAvatarView.tsx
+++ b/taehui-fe/src/components/LoggedInAvatarView.tsx
@@ -1,29 +1,68 @@
-import AvatarTitle from "@/components/AvatarTitle";
+import usePostDrawing from "@/query/usePostDrawing";
import useWipeTotem from "@/query/useWipeTotem";
import { useTaehuiStore } from "@/state/Stores";
+import { wwwAPIPath } from "@/utilities/wwwAPI";
+import dayjs from "dayjs";
import { observer } from "mobx-react-lite";
-import { useTranslations } from "next-intl";
-import { Button, Col, Row } from "reactstrap";
-import { useTo } from "taehui-ts/fe-utilities";
+import Image from "next/image";
+import { useRouter } from "next/navigation";
+import { Back, PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import ButtonGroup from "react-bootstrap/ButtonGroup";
+import Col from "react-bootstrap/Col";
+import Row from "react-bootstrap/Row";
+import Stack from "react-bootstrap/Stack";
export default observer<{ avatarID: string; avatarName: string }>(
({ avatarID, avatarName }) => {
const { totem, setAvatarCipher, setAutoLogIn } = useTaehuiStore();
- const t = useTranslations();
+ const { push } = useRouter();
- const to = useTo();
-
+ const { mutateAsync: postDrawing } = usePostDrawing();
const { mutateAsync: wipeTotem } = useWipeTotem();
return (
-
-
-
-
+
+
+ {
+ const inputElement = document.createElement("input");
+ inputElement.type = "file";
+ inputElement.accept = "image/png";
+ inputElement.addEventListener("change", async ({ target }) => {
+ const file = (target as HTMLInputElement).files?.[0];
+ if (file) {
+ await postDrawing({ file });
+ }
+ });
+ inputElement.click();
+ }}
+ />
+
+
+
+
+ {avatarName} ({avatarID})
+
+
+ {
+ push("/avatar");
+ }}
+ >
+
+
{
await wipeTotem({ totem });
window.localStorage.removeItem("avatarID");
@@ -33,21 +72,11 @@
setAutoLogIn(false);
}}
>
- {t("notLoggedIn")}
+
-
-
- {
- to("/avatar");
- }}
- >
- {t("doModifyAvatar")}
-
-
-
-
+
+
+
);
},
diff --git a/taehui-fe/src/components/ModifyAvatarView.tsx b/taehui-fe/src/components/ModifyAvatarView.tsx
index b65627f..261f60b 100644
--- a/taehui-fe/src/components/ModifyAvatarView.tsx
+++ b/taehui-fe/src/components/ModifyAvatarView.tsx
@@ -1,16 +1,16 @@
-import usePostDrawing from "@/query/usePostDrawing";
import usePutAvatar from "@/query/usePutAvatar";
import { useTaehuiStore } from "@/state/Stores";
-import { wwwAPIPath } from "@/utilities/wwwAPI";
-import dayjs from "dayjs";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import Image from "next/image";
import { useMemo, useState } from "react";
+import { PencilFill } from "react-bootstrap-icons";
+import Button from "react-bootstrap/Button";
+import FormControl from "react-bootstrap/FormControl";
+import InputGroup from "react-bootstrap/InputGroup";
+import InputGroupText from "react-bootstrap/InputGroupText";
+import Stack from "react-bootstrap/Stack";
import ReactTextareaAutosize from "react-textarea-autosize";
import { toast } from "react-toastify";
-import { Button, Col, Form, Input, Row } from "reactstrap";
-import { useTo } from "taehui-ts/fe-utilities";
export default observer(() => {
const { taehuiAvatarID, taehuiAvatarName, taehuiFax, taehuiAvatarIntro } =
@@ -23,143 +23,94 @@
const [fax, setFax] = useState(taehuiFax);
const [avatarIntro, setAvatarIntro] = useState(taehuiAvatarIntro);
- const to = useTo();
-
const isValidFax = useMemo(() => /^.+@.+$/.test(fax), [fax]);
const { mutateAsync: putAvatar } = usePutAvatar();
- const { mutateAsync: postDrawing } = usePostDrawing();
return (
-
+
+
+ {t("avatarID")}
+
+
+
+ {t("avatarCipher")}
+ {
+ setAvatarCipher(value);
+ }}
+ />
+
+
+ {t("avatarCipherModified")}
+ {
+ setAvatarCipherModified(value);
+ }}
+ />
+
+
+ {t("avatarName")}
+ 0}
+ isInvalid={avatarName.length === 0}
+ placeholder={t("avatarName")}
+ value={avatarName}
+ onChange={({ target: { value } }) => {
+ setAvatarName(value);
+ }}
+ />
+
+
+ {t("fax")}
+ 0 && isValidFax}
+ isInvalid={fax.length > 0 && !isValidFax}
+ placeholder={t("fax")}
+ value={fax}
+ onChange={({ target: { value } }) => {
+ setFax(value);
+ }}
+ />
+
+
+ {t("avatarIntro")}
+ {
+ setAvatarIntro(value);
+ }}
+ />
+
+ {
+ if (avatarCipher && avatarName && (!fax || isValidFax)) {
+ await putAvatar({
+ avatarCipher,
+ avatarCipherModified,
+ avatarName,
+ fax,
+ avatarIntro,
+ });
+ } else {
+ toast.error(t("failedValidation"));
+ }
+ }}
+ >
+
+
+
);
});
diff --git a/taehui-fe/src/components/NotLoggedInAvatarView.tsx b/taehui-fe/src/components/NotLoggedInAvatarView.tsx
index 8520a0e..d071f23 100644
--- a/taehui-fe/src/components/NotLoggedInAvatarView.tsx
+++ b/taehui-fe/src/components/NotLoggedInAvatarView.tsx
@@ -3,9 +3,12 @@
import CryptoJS from "crypto-js";
import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
-import Link from "next/link";
+import { useRouter } from "next/navigation";
import { useState } from "react";
-import { Button, Col, Form, Input, Row } from "reactstrap";
+import Button from "react-bootstrap/Button";
+import FormCheck from "react-bootstrap/FormCheck";
+import FormControl from "react-bootstrap/FormControl";
+import Stack from "react-bootstrap/Stack";
export default observer(() => {
const { autoLogIn, avatarCipher, setAvatarCipher, setAutoLogIn } =
@@ -17,6 +20,8 @@
const { mutateAsync: postGetTotem } = usePostGetTotem();
+ const { push } = useRouter();
+
const onLogIn = async () => {
await postGetTotem({ avatarID, avatarCipher });
if (autoLogIn) {
@@ -32,54 +37,47 @@
window.localStorage.setItem("autoLogIn", autoLogIn.toString());
};
+ const onEnroll = () => {
+ push("/avatar");
+ };
+
return (
-
+
+ {
+ setAvatarID(value);
+ }}
+ />
+ {
+ setAvatarCipher(value);
+ }}
+ />
+
+
+ {t("logIn")}
+
+
+ {t("enroll")}
+
+
+
+ {
+ setAutoLogIn(!autoLogIn);
+ }}
+ />
+
+
);
});
diff --git a/taehui-fe/src/components/SignUpView.tsx b/taehui-fe/src/components/SignUpView.tsx
deleted file mode 100644
index a6cf258..0000000
--- a/taehui-fe/src/components/SignUpView.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-import usePostAvatar from "@/query/usePostAvatar";
-import { useTranslations } from "next-intl";
-import { useMemo, useState } from "react";
-import { toast } from "react-toastify";
-import { Button, Col, Form, Input, Row } from "reactstrap";
-import { useTo } from "taehui-ts/fe-utilities";
-
-export default function SignUpView() {
- const t = useTranslations();
-
- const [avatarID, setAvatarID] = useState("");
- const [avatarCipher, setAvatarCipher] = useState("");
- const [avatarCipherTest, setAvatarCipherTest] = useState("");
- const [avatarName, setAvatarName] = useState("");
- const [fax, setFax] = useState("");
-
- const to = useTo();
-
- const isValidFax = useMemo(() => /^.+@.+$/.test(fax), [fax]);
- const isValidAvatarID = useMemo(
- () => /[a-zA-Z\d]/.test(avatarID),
- [avatarID],
- );
-
- const { mutateAsync: postAvatar } = usePostAvatar();
-
- return (
-
- );
-}
diff --git a/taehui-fe/src/components/TaehuiView.tsx b/taehui-fe/src/components/TaehuiView.tsx
index 7716fd8..654711b 100644
--- a/taehui-fe/src/components/TaehuiView.tsx
+++ b/taehui-fe/src/components/TaehuiView.tsx
@@ -2,133 +2,122 @@
import useSession from "@/app/[language]/query/useSession";
import vcs from "@/assets/vcs.png";
+import AvatarDrawing from "@/components/AvatarDrawing";
import AvatarView from "@/components/AvatarView";
import withQueryClient from "@/hoc/withQueryClient";
import { useTaehuiStore } from "@/state/Stores";
+import { observer } from "mobx-react-lite";
import { useTranslations } from "next-intl";
import Image from "next/image";
import Link from "next/link";
-import { ReactNode, useEffect, useMemo, useRef } from "react";
+import { ReactNode } from "react";
+import Container from "react-bootstrap/Container";
+import Nav from "react-bootstrap/Nav";
+import Navbar from "react-bootstrap/Navbar";
+import NavbarBrand from "react-bootstrap/NavbarBrand";
+import NavbarCollapse from "react-bootstrap/NavbarCollapse";
+import NavbarToggle from "react-bootstrap/NavbarToggle";
+import NavDropdown from "react-bootstrap/NavDropdown";
+import NavLink from "react-bootstrap/NavLink";
import { ToastContainer } from "react-toastify";
-import { Button, Col, Container, Navbar, NavbarBrand, Row } from "reactstrap";
import { useIsPath } from "taehui-ts/fe-utilities";
-export default withQueryClient(function TaehuiView({
- children,
-}: {
- children: ReactNode;
-}) {
- const t = useTranslations();
+export default withQueryClient(
+ observer(({ children }: { children: ReactNode }) => {
+ const { taehuiAvatarID } = useTaehuiStore();
- const { setTitleViewHeight, setAvatarViewHeight } = useTaehuiStore();
+ const t = useTranslations();
- const titleView = useRef(null);
- const avatarView = useRef(null);
+ const isSessionLoading = useSession();
- const isSessionLoading = useSession();
+ const isPath = useIsPath();
- const isPath = useIsPath();
-
- const isAvatarViewVisible = useMemo(
- () => !isPath("/avatar") && !isPath("/commentary"),
- [isPath],
- );
-
- useEffect(() => {
- setTitleViewHeight(titleView.current?.clientHeight ?? 0);
- setAvatarViewHeight(avatarView.current?.clientHeight ?? 0);
- }, [setAvatarViewHeight, setTitleViewHeight]);
-
- const getColor = (route: string, equals = false) =>
- isPath(route, equals) ? "primary" : "secondary";
-
- return (
- <>
-
-
-
-
+ return (
+ <>
+
+
+
-
-
-
-
- {t("forums")}
-
-
-
-
-
-
- {t("qwilightForum")}
-
-
-
-
-
-
- {t("softwareForum")}
-
-
-
-
-
-
- {t("assistForum")}
-
-
-
-
-
-
- {t("dateForum")}
-
-
-
-
-
- {t("ppt")}
-
-
-
-
-
- {t("commentary")}
-
-
-
-
-
- Qwilight
-
-
-
-
-
-
-
-
-
-
-
-
- {children}
- {isAvatarViewVisible && (
-
- )}
-
+
+
+
+
+
+
+ {children}
-
- >
- );
-});
+
+ >
+ );
+ }),
+);
diff --git a/taehui-fe/src/query/usePutAvatar.ts b/taehui-fe/src/query/usePutAvatar.ts
index 342a04a..1afef90 100644
--- a/taehui-fe/src/query/usePutAvatar.ts
+++ b/taehui-fe/src/query/usePutAvatar.ts
@@ -2,17 +2,17 @@
import { isClientFault, wwwAPI } from "@/utilities/wwwAPI";
import { useMutation } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
+import { useRouter } from "next/navigation";
import { toast } from "react-toastify";
import Swal from "sweetalert2";
import { getMillis } from "taehui-ts/date";
-import { useTo } from "taehui-ts/fe-utilities";
export default function usePutAvatar() {
const t = useTranslations();
const { totem, setSession, wipeSession, saveTotem } = useTaehuiStore();
- const to = useTo();
+ const { push } = useRouter();
return useMutation({
mutationFn: async ({
@@ -52,7 +52,7 @@
) => {
if (isAvatarCipherModified) {
wipeSession();
- await Swal.fire(t("doModifyAvatar"), t("doModifiedAvatar"), "success");
+ await Swal.fire("Taehui", t("doModifiedAvatar"), "success");
} else {
setSession({
avatarName,
@@ -61,7 +61,7 @@
});
}
saveTotem();
- to("/");
+ push("/");
},
onError: (e) => {
if (isClientFault(e)) {
diff --git a/taehui-fe/src/state/setTaehuiStore.ts b/taehui-fe/src/state/setTaehuiStore.ts
index cf7db4d..beaf338 100644
--- a/taehui-fe/src/state/setTaehuiStore.ts
+++ b/taehui-fe/src/state/setTaehuiStore.ts
@@ -3,8 +3,6 @@
export default function setTaehuiStore() {
return {
- titleViewHeight: 0,
- avatarViewHeight: 0,
avatarCipher: "",
autoLogIn: false,
totem: "",
@@ -14,14 +12,6 @@
taehuiFax: "",
taehuiAvatarIntro: "",
- setTitleViewHeight(titleViewHeight: number) {
- this.titleViewHeight = titleViewHeight;
- },
-
- setAvatarViewHeight(avatarViewHeight: number) {
- this.avatarViewHeight = avatarViewHeight;
- },
-
setAvatarCipher(avatarCipher: string) {
this.avatarCipher = avatarCipher;
},
diff --git a/taehui-fe/src/type/wwwAPI.d.ts b/taehui-fe/src/type/wwwAPI.d.ts
index 5327724..6b0da6f 100644
--- a/taehui-fe/src/type/wwwAPI.d.ts
+++ b/taehui-fe/src/type/wwwAPI.d.ts
@@ -59,11 +59,11 @@
essays: EssayAPIEssay[];
}[];
-export type GetLatestAvatarAPI = {
+export type GetLatestAPI = {
avatarID: string;
avatarName: string;
date: string;
-}[][];
+}[];
export type GetLatestCommentAPI = {
commentID: number;
diff --git a/taehui-ts/package.json b/taehui-ts/package.json
index 37a8426..64c1f3c 100644
--- a/taehui-ts/package.json
+++ b/taehui-ts/package.json
@@ -5,7 +5,8 @@
"exports": {
"./date": "./main/date.js",
"./fe-utilities": "./main/fe-utilities.js",
- "./language": "./main/language.js"
+ "./language": "./main/language.js",
+ "./globals": "./main/globals.css"
},
"typesVersions": {
"*": {
@@ -22,23 +23,20 @@
},
"devDependencies": {
"@rollup/plugin-typescript": "^11.1.6",
- "@types/qs": "^6.9.12",
- "@types/react": "^18.2.66",
+ "@types/react": "^18.2.74",
"dayjs": "^1.11.10",
- "eslint-config-next": "^14.1.3",
- "next": "^14.1.3",
- "next-intl": "^3.9.5",
- "qs": "^6.12.0",
+ "eslint-config-next": "^14.1.4",
+ "next": "^14.1.4",
+ "next-intl": "^3.11.1",
"react": "^18.2.0",
- "rollup": "^4.13.0",
- "tslib": "^2.6.2",
- "urlcat": "^3.1.0"
+ "rollup": "^4.14.0",
+ "rollup-plugin-scss": "^4.0.0",
+ "tslib": "^2.6.2"
},
"peerDependencies": {
"dayjs": "^1.11.10",
"next": "^14.1.3",
"next-intl": "^3.9.5",
- "qs": "^6.11.2",
"react": "^18.2.0"
},
"peerDependenciesMeta": {
@@ -51,9 +49,6 @@
"next-intl": {
"optional": true
},
- "qs": {
- "optional": true
- },
"react": {
"optional": true
}
diff --git a/taehui-ts/rollup.config.mjs b/taehui-ts/rollup.config.mjs
index a39046f..9645046 100644
--- a/taehui-ts/rollup.config.mjs
+++ b/taehui-ts/rollup.config.mjs
@@ -1,9 +1,10 @@
import {defineConfig} from "rollup";
import typescript from "@rollup/plugin-typescript";
+import scss from 'rollup-plugin-scss'
export default defineConfig({
- external: ["dayjs", "next", "next-intl", "qs", "react"],
- input: ["src/date.ts", "src/language.ts", "src/fe-utilities.ts"],
+ external: ["dayjs", "next", "next-intl", "react"],
+ input: ["src/date.ts", "src/language.ts", "src/fe-utilities.ts", "src/globals.scss"],
plugins: [
typescript({
compilerOptions: {
@@ -11,6 +12,7 @@
declaration: true,
},
}),
+ scss({ fileName: 'globals.css' })
],
output: {
dir: "main"
diff --git a/taehui-ts/src/date.ts b/taehui-ts/src/date.ts
index a54d8c6..e1418a5 100644
--- a/taehui-ts/src/date.ts
+++ b/taehui-ts/src/date.ts
@@ -2,8 +2,7 @@
export const getDate = (date?: string) => dayjs(date).format("YYYY-MM-DD");
-export const getDatetime = (date?: string) =>
+export const getDatetime = (date?: string | number) =>
dayjs(date).format("YYYY-MM-DD HH:mm:ss");
export const getMillis = () => dayjs().valueOf();
-
diff --git a/taehui-ts/src/fe-utilities.ts b/taehui-ts/src/fe-utilities.ts
index 8858488..66260cd 100644
--- a/taehui-ts/src/fe-utilities.ts
+++ b/taehui-ts/src/fe-utilities.ts
@@ -1,13 +1,7 @@
import { useLocale } from "next-intl";
-import {
- useParams,
- usePathname,
- useRouter,
- useSearchParams,
-} from "next/navigation";
-import { parse, stringify } from "qs";
+import { usePathname, useRouter, useSearchParams } from "next/navigation";
+import { stringify } from "querystring";
import { useCallback, useEffect, useState } from "react";
-import urlcat from "urlcat";
export function useWindowArea() {
const [windowLength, setWindowLength] = useState(
@@ -33,58 +27,48 @@
return { windowLength, windowHeight };
}
-export function useTo() {
+export function useParam(valueID: string, defaultValue: string) {
const { push } = useRouter();
-
- return useCallback(
- (pathname: string, search = "") => push(urlcat(pathname, parse(search))),
- [push],
- );
-}
-
-export function useParam(text: string, defaultValue: string) {
- const to = useTo();
const searchParams = useSearchParams();
- const param = searchParams.get(text) ?? defaultValue;
+ const value = searchParams.get(valueID) ?? defaultValue;
const pathname = usePathname();
return {
- param,
+ param: value,
setParam: useCallback(
- (param: string) => {
- to(pathname, stringify({ ...searchParams.entries(), [text]: param }));
+ (value: string) => {
+ const data: Record = {};
+ for (const searchParam of searchParams.entries()) {
+ data[searchParam[0]] = searchParam[1];
+ }
+ push(`${pathname}?${stringify({ ...data, [valueID]: value })}`);
},
- [pathname, searchParams, text, to],
+ [pathname, push, searchParams, valueID],
),
};
}
-export function useIntParam(text: string, defaultValue: number) {
- const { param, setParam } = useParam(text, defaultValue.toString());
+export function useIntParam(valueID: string, defaultValue: number) {
+ const { push } = useRouter();
+ const searchParams = useSearchParams();
+ const value = Number.parseInt(
+ searchParams.get(valueID) ?? defaultValue.toString(),
+ );
+
+ const pathname = usePathname();
return {
- param: Number(param),
+ param: value,
setParam: useCallback(
- (param: number) => {
- setParam(param.toString());
+ (value: number) => {
+ const data: Record = {};
+ for (const searchParam of searchParams.entries()) {
+ data[searchParam[0]] = searchParam[1];
+ }
+ push(`${pathname}?${stringify({ ...data, [valueID]: value })}`);
},
- [setParam],
- ),
- };
-}
-
-export function useWant(route: string) {
- const to = useTo();
- const { want = [""] } = useParams<{ want: string[] }>();
-
- return {
- want: decodeURIComponent(want[0]),
- setWant: useCallback(
- (want: string) => {
- to(route + "/" + want);
- },
- [to, route],
+ [pathname, push, searchParams, valueID],
),
};
}
diff --git a/taehui-ts/src/globals.scss b/taehui-ts/src/globals.scss
new file mode 100644
index 0000000..4e4bad3
--- /dev/null
+++ b/taehui-ts/src/globals.scss
@@ -0,0 +1,30 @@
+* {
+ font-family: "Century Gothic", sans-serif;
+ font-size: small;
+ line-break: anywhere;
+ white-space: break-spaces;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+div {
+ &.cc {
+ overflow: hidden;
+ }
+}
+
+span {
+ &.ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+}
+
+.route {
+ cursor: pointer;
+}
+