mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-12 14:45:42 +08:00
refactor: update chat ui (#13269)
### What problem does this PR solve? Update **Chat** UI: - Align to the design. - Update `<AudioButton>` visualizer logic. - Fix keyboard navigation issue. ### Type of change - [x] Refactoring
This commit is contained in:
163
web/package-lock.json
generated
163
web/package-lock.json
generated
@@ -34,9 +34,9 @@
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-select": "2.1.4",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slider": "^1.2.1",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.1.1",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-toast": "^1.2.6",
|
||||
@@ -56,7 +56,7 @@
|
||||
"ajv-formats": "^3.0.1",
|
||||
"antd": "^5.12.7",
|
||||
"axios": "^1.12.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"classnames": "^2.5.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.4",
|
||||
@@ -105,7 +105,7 @@
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-math": "^6.0.0",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwind-merge": "^2.6.1",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"umi-request": "^1.4.0",
|
||||
@@ -915,6 +915,7 @@
|
||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.5",
|
||||
@@ -1678,6 +1679,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
@@ -1812,6 +1814,7 @@
|
||||
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@@ -7949,6 +7952,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3",
|
||||
"@swc/types": "^0.1.25"
|
||||
@@ -8212,6 +8216,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@tanstack/react-query/-/react-query-5.90.14.tgz",
|
||||
"integrity": "sha512-JAMuULej09hrZ14W9+mxoRZ44rR2BuZfCd6oKTQVNfynQxCN3muH3jh3W46gqZNw5ZqY0ZVaS43Imb3dMr6tgw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.90.14"
|
||||
},
|
||||
@@ -8879,6 +8884,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-24.10.4.tgz",
|
||||
"integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -8916,6 +8922,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
@@ -8937,6 +8944,7 @@
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
@@ -9089,6 +9097,7 @@
|
||||
"integrity": "sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.52.0",
|
||||
"@typescript-eslint/types": "8.52.0",
|
||||
@@ -9519,7 +9528,6 @@
|
||||
"integrity": "sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.5",
|
||||
"@vue/shared": "3.5.26",
|
||||
@@ -9534,7 +9542,6 @@
|
||||
"integrity": "sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
@@ -9547,8 +9554,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.26",
|
||||
@@ -9556,7 +9562,6 @@
|
||||
"integrity": "sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.26",
|
||||
"@vue/shared": "3.5.26"
|
||||
@@ -9568,7 +9573,6 @@
|
||||
"integrity": "sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.28.5",
|
||||
"@vue/compiler-core": "3.5.26",
|
||||
@@ -9586,8 +9590,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.26",
|
||||
@@ -9595,7 +9598,6 @@
|
||||
"integrity": "sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.26",
|
||||
"@vue/shared": "3.5.26"
|
||||
@@ -9607,7 +9609,6 @@
|
||||
"integrity": "sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.5.26"
|
||||
}
|
||||
@@ -9618,7 +9619,6 @@
|
||||
"integrity": "sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.26",
|
||||
"@vue/shared": "3.5.26"
|
||||
@@ -9630,7 +9630,6 @@
|
||||
"integrity": "sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.5.26",
|
||||
"@vue/runtime-core": "3.5.26",
|
||||
@@ -9644,7 +9643,6 @@
|
||||
"integrity": "sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.5.26",
|
||||
"@vue/shared": "3.5.26"
|
||||
@@ -9658,8 +9656,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.26.tgz",
|
||||
"integrity": "sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.14.1",
|
||||
@@ -9891,6 +9888,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -10011,6 +10009,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -10124,6 +10123,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/antd/-/antd-5.29.3.tgz",
|
||||
"integrity": "sha512-3DdbGCa9tWAJGcCJ6rzR8EJFsv2CtyEbkVabZE14pfgUHfCicWCj0/QzQVLDYg8CPfQk9BH7fHCoTXHTy7MP/A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^7.2.1",
|
||||
"@ant-design/cssinjs": "^1.23.0",
|
||||
@@ -10774,7 +10774,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz",
|
||||
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -10845,6 +10844,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -12226,6 +12226,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -12394,6 +12395,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
@@ -12952,7 +12954,8 @@
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/embla-carousel/-/embla-carousel-8.6.0.tgz",
|
||||
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/embla-carousel-react": {
|
||||
"version": "8.6.0",
|
||||
@@ -13001,7 +13004,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
@@ -13011,6 +13013,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
}
|
||||
@@ -13326,6 +13329,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@@ -13436,6 +13440,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -15810,6 +15815,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
}
|
||||
@@ -15883,6 +15889,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/immer/-/immer-10.2.0.tgz",
|
||||
"integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
@@ -16164,7 +16171,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -16680,7 +16686,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
|
||||
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
@@ -18189,7 +18194,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/lib0/-/lib0-0.2.117.tgz",
|
||||
"integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"isomorphic.js": "^0.2.4"
|
||||
},
|
||||
@@ -18837,7 +18841,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/marked/-/marked-14.0.0.tgz",
|
||||
"integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"marked": "bin/marked.js"
|
||||
},
|
||||
@@ -20098,23 +20101,11 @@
|
||||
"ml-array-rescale": "^1.3.7"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.30.1",
|
||||
"resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.55.1",
|
||||
"resolved": "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.55.1.tgz",
|
||||
"integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dompurify": "3.2.7",
|
||||
"marked": "14.0.0"
|
||||
@@ -20125,7 +20116,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.7.tgz",
|
||||
"integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"peer": true,
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
@@ -20136,7 +20126,6 @@
|
||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -21133,6 +21122,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -21406,6 +21396,7 @@
|
||||
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -21778,6 +21769,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/rc-field-form/-/rc-field-form-2.7.1.tgz",
|
||||
"integrity": "sha512-vKeSifSJ6HoLaAB+B8aq/Qgm8a3dyxROzCtKNCsBQgiverpc4kWDQihoUwzUj+zNWJOykwSY4dNX3QrGwtVb9A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.0",
|
||||
"@rc-component/async-validator": "^5.0.3",
|
||||
@@ -22319,6 +22311,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -22457,6 +22450,7 @@
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -22768,6 +22762,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -22846,6 +22841,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/react-hook-form/-/react-hook-form-7.69.0.tgz",
|
||||
"integrity": "sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
@@ -23057,6 +23053,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.11.0.tgz",
|
||||
"integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
"set-cookie-parser": "^2.6.0"
|
||||
@@ -23824,7 +23821,6 @@
|
||||
"integrity": "sha512-bfmJW1dmR2LvaMJuAnE88pZP9DktIFYXazkTfOIKZzi3Knk9lT0roItIA24ydOucI3bV/g/tXBA6hzqq3FV9Ew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"remark-parse": "^10.0.0",
|
||||
@@ -23974,7 +23970,6 @@
|
||||
"integrity": "sha512-koyOzCMYoUHudypbj4XpnAKFbkddRMYZHwghnxd7ue5210WzGw6kOBwauJTRUMq16jsovXx8dYNvSSWP89kZ3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"mdast-util-to-markdown": "^1.0.0",
|
||||
@@ -23991,7 +23986,6 @@
|
||||
"integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2"
|
||||
}
|
||||
@@ -24001,8 +23995,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark-stringify/node_modules/mdast-util-phrasing": {
|
||||
"version": "3.0.1",
|
||||
@@ -24010,7 +24003,6 @@
|
||||
"integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"unist-util-is": "^5.0.0"
|
||||
@@ -24026,7 +24018,6 @@
|
||||
"integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"@types/unist": "^2.0.0",
|
||||
@@ -24048,7 +24039,6 @@
|
||||
"integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0"
|
||||
},
|
||||
@@ -24073,7 +24063,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
@@ -24095,7 +24084,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
@@ -24116,7 +24104,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"decode-named-character-reference": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
@@ -24139,8 +24126,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark-stringify/node_modules/micromark-util-types": {
|
||||
"version": "1.1.0",
|
||||
@@ -24157,8 +24143,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark-stringify/node_modules/unified": {
|
||||
"version": "10.1.2",
|
||||
@@ -24166,7 +24151,6 @@
|
||||
"integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"bail": "^2.0.0",
|
||||
@@ -24187,7 +24171,6 @@
|
||||
"integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0"
|
||||
},
|
||||
@@ -24202,7 +24185,6 @@
|
||||
"integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0"
|
||||
},
|
||||
@@ -24217,7 +24199,6 @@
|
||||
"integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-is": "^5.0.0",
|
||||
@@ -24234,7 +24215,6 @@
|
||||
"integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-is": "^5.0.0"
|
||||
@@ -24250,7 +24230,6 @@
|
||||
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"is-buffer": "^2.0.0",
|
||||
@@ -24268,7 +24247,6 @@
|
||||
"integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-stringify-position": "^3.0.0"
|
||||
@@ -24284,7 +24262,6 @@
|
||||
"integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2"
|
||||
}
|
||||
@@ -24294,8 +24271,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark/node_modules/mdast-util-from-markdown": {
|
||||
"version": "1.3.1",
|
||||
@@ -24303,7 +24279,6 @@
|
||||
"integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"@types/unist": "^2.0.0",
|
||||
@@ -24329,7 +24304,6 @@
|
||||
"integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0"
|
||||
},
|
||||
@@ -24354,7 +24328,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/debug": "^4.0.0",
|
||||
"debug": "^4.0.0",
|
||||
@@ -24391,7 +24364,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"decode-named-character-reference": "^1.0.0",
|
||||
"micromark-factory-destination": "^1.0.0",
|
||||
@@ -24427,7 +24399,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
@@ -24450,7 +24421,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
@@ -24474,7 +24444,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
@@ -24496,7 +24465,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
@@ -24520,7 +24488,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-factory-space": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
@@ -24544,7 +24511,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
@@ -24566,7 +24532,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
@@ -24587,7 +24552,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
@@ -24610,7 +24574,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-types": "^1.0.0"
|
||||
@@ -24632,7 +24595,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
@@ -24653,7 +24615,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"decode-named-character-reference": "^1.0.0",
|
||||
"micromark-util-character": "^1.0.0",
|
||||
@@ -24676,8 +24637,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark/node_modules/micromark-util-html-tag-name": {
|
||||
"version": "1.2.0",
|
||||
@@ -24694,8 +24654,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark/node_modules/micromark-util-normalize-identifier": {
|
||||
"version": "1.1.0",
|
||||
@@ -24713,7 +24672,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-symbol": "^1.0.0"
|
||||
}
|
||||
@@ -24734,7 +24692,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-types": "^1.0.0"
|
||||
}
|
||||
@@ -24755,7 +24712,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-character": "^1.0.0",
|
||||
"micromark-util-encode": "^1.0.0",
|
||||
@@ -24778,7 +24734,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"micromark-util-chunked": "^1.0.0",
|
||||
"micromark-util-symbol": "^1.0.0",
|
||||
@@ -24801,8 +24756,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark/node_modules/micromark-util-types": {
|
||||
"version": "1.1.0",
|
||||
@@ -24819,8 +24773,7 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/remark/node_modules/remark-parse": {
|
||||
"version": "10.0.2",
|
||||
@@ -24828,7 +24781,6 @@
|
||||
"integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdast": "^3.0.0",
|
||||
"mdast-util-from-markdown": "^1.0.0",
|
||||
@@ -24845,7 +24797,6 @@
|
||||
"integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"bail": "^2.0.0",
|
||||
@@ -24866,7 +24817,6 @@
|
||||
"integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0"
|
||||
},
|
||||
@@ -24881,7 +24831,6 @@
|
||||
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"is-buffer": "^2.0.0",
|
||||
@@ -24899,7 +24848,6 @@
|
||||
"integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"unist-util-stringify-position": "^3.0.0"
|
||||
@@ -25110,6 +25058,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.54.0.tgz",
|
||||
"integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
@@ -25181,7 +25130,6 @@
|
||||
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mri": "^1.1.0"
|
||||
},
|
||||
@@ -25334,6 +25282,7 @@
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -25818,6 +25767,7 @@
|
||||
"integrity": "sha512-kfr6kxQAjA96ADlH6FMALJwJ+eM80UqXy106yVHNgdsAP/CdzkkicglRAhZAvUycXK9AeadF6KZ00CWLtVMN4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
@@ -26369,9 +26319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-2.6.0.tgz",
|
||||
"integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==",
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-2.6.1.tgz",
|
||||
"integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -26395,6 +26345,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
@@ -26477,6 +26428,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
@@ -26973,6 +26925,7 @@
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
@@ -27188,6 +27141,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -27574,7 +27528,6 @@
|
||||
"integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.0",
|
||||
"diff": "^5.0.0",
|
||||
@@ -27594,7 +27547,6 @@
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
@@ -27605,7 +27557,6 @@
|
||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -27733,6 +27684,7 @@
|
||||
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -28620,6 +28572,7 @@
|
||||
"resolved": "https://registry.npmmirror.com/webpack/-/webpack-5.104.1.tgz",
|
||||
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
@@ -29010,7 +28963,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/workerize-loader/-/workerize-loader-2.0.2.tgz",
|
||||
"integrity": "sha512-HoZ6XY4sHWxA2w0WpzgBwUiR3dv1oo7bS+oCwIpb6n54MclQ/7KXdXsVIChTCygyuHtVuGBO1+i3HzTt699UJQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
@@ -29023,7 +28975,6 @@
|
||||
"resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-select": "2.1.4",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"@radix-ui/react-slider": "^1.2.1",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@radix-ui/react-switch": "^1.1.1",
|
||||
"@radix-ui/react-tabs": "^1.1.1",
|
||||
"@radix-ui/react-toast": "^1.2.6",
|
||||
@@ -72,7 +72,7 @@
|
||||
"ajv-formats": "^3.0.1",
|
||||
"antd": "^5.12.7",
|
||||
"axios": "^1.12.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"classnames": "^2.5.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.4",
|
||||
@@ -121,7 +121,7 @@
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-math": "^6.0.0",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwind-merge": "^2.6.1",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"umi-request": "^1.4.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { transformFile2Base64 } from '@/utils/file-util';
|
||||
import { Pencil, Plus, XIcon } from 'lucide-react';
|
||||
import { LucidePencil, LucidePlus, LucideX } from 'lucide-react';
|
||||
import {
|
||||
ChangeEventHandler,
|
||||
forwardRef,
|
||||
@@ -45,7 +45,7 @@ export const AvatarUpload = forwardRef<HTMLInputElement, AvatarUploadProps>(
|
||||
}
|
||||
ev.target.value = '';
|
||||
},
|
||||
[onChange],
|
||||
[],
|
||||
);
|
||||
|
||||
const handleRemove = useCallback(() => {
|
||||
@@ -249,30 +249,36 @@ export const AvatarUpload = forwardRef<HTMLInputElement, AvatarUploadProps>(
|
||||
};
|
||||
}
|
||||
}, 100);
|
||||
}, [handleWheel, containerRef.current]);
|
||||
}, [handleWheel, imageToCrop, isCropModalOpen]);
|
||||
|
||||
return (
|
||||
<div className="flex justify-start items-end space-x-2">
|
||||
<div className="relative group">
|
||||
{!avatarBase64Str ? (
|
||||
<div className="w-[64px] h-[64px] grid place-content-center border border-dashed bg-bg-input rounded-md">
|
||||
<div className="flex flex-col items-center">
|
||||
<Plus />
|
||||
<p>{t('common.upload')}</p>
|
||||
</div>
|
||||
<div
|
||||
className="
|
||||
border border-dashed border-borer-button rounded-md size-16
|
||||
flex flex-col gap-1 justify-center items-center text-sm text-text-secondary transition-colors
|
||||
group-has-[input:focus-visible]:border-accent-primary group-has-[input:focus-visible]:text-text-primary"
|
||||
>
|
||||
<LucidePlus className="size-4" />
|
||||
<span>{t('common.upload')}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-[64px] h-[64px] relative grid place-content-center">
|
||||
<Avatar className="w-[64px] h-[64px] rounded-md">
|
||||
<div className="size-16 relative grid place-content-center">
|
||||
<Avatar className="size-16 rounded-md">
|
||||
<AvatarImage className="block" src={avatarBase64Str} alt="" />
|
||||
<AvatarFallback></AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="absolute inset-0 bg-[#000]/20 group-hover:bg-[#000]/60">
|
||||
<Pencil
|
||||
size={20}
|
||||
className="absolute right-2 bottom-0 opacity-50 hidden group-hover:block"
|
||||
/>
|
||||
|
||||
<div
|
||||
className="
|
||||
absolute inset-0 bg-black/50 flex items-center justify-center
|
||||
transition-opacity opacity-0 group-hover:opacity-100 group-has-[input:focus-visible]:opacity-100"
|
||||
>
|
||||
<LucidePencil className="size-5 opacity-75" />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onClick={handleRemove}
|
||||
size="icon"
|
||||
@@ -280,10 +286,11 @@ export const AvatarUpload = forwardRef<HTMLInputElement, AvatarUploadProps>(
|
||||
aria-label="Remove image"
|
||||
type="button"
|
||||
>
|
||||
<XIcon className="size-3.5" />
|
||||
<LucideX className="size-3" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Input
|
||||
placeholder=""
|
||||
type="file"
|
||||
@@ -294,7 +301,7 @@ export const AvatarUpload = forwardRef<HTMLInputElement, AvatarUploadProps>(
|
||||
ref={ref}
|
||||
/>
|
||||
</div>
|
||||
<div className="margin-1 text-text-secondary">
|
||||
<div className="margin-1 text-sm text-text-secondary">
|
||||
{tips ?? t('knowledgeConfiguration.photoTip')}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { AlertDialogOverlay } from '@radix-ui/react-alert-dialog';
|
||||
|
||||
import { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { X } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -55,53 +55,48 @@ export function ConfirmDeleteDialog({
|
||||
defaultOpen={defaultOpen}
|
||||
>
|
||||
{children && <AlertDialogTrigger asChild>{children}</AlertDialogTrigger>}
|
||||
<AlertDialogOverlay
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
|
||||
<AlertDialogContent
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="bg-bg-base "
|
||||
>
|
||||
<AlertDialogContent
|
||||
onSelect={(e) => e.preventDefault()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="bg-bg-base "
|
||||
>
|
||||
<AlertDialogHeader className="space-y-5">
|
||||
<AlertDialogTitle>
|
||||
{title ?? t('common.deleteModalTitle')}
|
||||
<AlertDialogCancel
|
||||
onClick={onCancel}
|
||||
className="border-none bg-transparent hover:border-none hover:bg-transparent absolute right-3 top-3 hover:text-text-primary"
|
||||
>
|
||||
<X size={16} />
|
||||
</AlertDialogCancel>
|
||||
</AlertDialogTitle>
|
||||
{content && (
|
||||
<>
|
||||
<Separator className="w-[calc(100%+48px)] -translate-x-6"></Separator>
|
||||
<AlertDialogDescription className="mt-5">
|
||||
<div className="flex flex-col gap-5 text-base mb-10 px-5">
|
||||
<div className="text-text-primary">
|
||||
{content.title || t('common.deleteModalTitle')}
|
||||
</div>
|
||||
{content.node}
|
||||
</div>
|
||||
</AlertDialogDescription>
|
||||
</>
|
||||
)}
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter className="px-5 flex items-center gap-2">
|
||||
<AlertDialogCancel onClick={onCancel}>
|
||||
{cancelButtonText || t('common.cancel')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error"
|
||||
onClick={onOk}
|
||||
<AlertDialogHeader className="space-y-5">
|
||||
<AlertDialogTitle>
|
||||
{title ?? t('common.deleteModalTitle')}
|
||||
<AlertDialogCancel
|
||||
onClick={onCancel}
|
||||
className="border-none bg-transparent hover:border-none hover:bg-transparent absolute right-3 top-3 hover:text-text-primary"
|
||||
>
|
||||
{okButtonText || t('common.delete')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogOverlay>
|
||||
<X size={16} />
|
||||
</AlertDialogCancel>
|
||||
</AlertDialogTitle>
|
||||
{content && (
|
||||
<>
|
||||
<Separator className="w-[calc(100%+48px)] -translate-x-6"></Separator>
|
||||
<AlertDialogDescription className="mt-5">
|
||||
<div className="flex flex-col gap-5 text-base mb-10 px-5">
|
||||
<div className="text-text-primary">
|
||||
{content.title || t('common.deleteModalTitle')}
|
||||
</div>
|
||||
{content.node}
|
||||
</div>
|
||||
</AlertDialogDescription>
|
||||
</>
|
||||
)}
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter className="px-5 flex items-center gap-2">
|
||||
<AlertDialogCancel onClick={onCancel}>
|
||||
{cancelButtonText || t('common.cancel')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className="bg-state-error text-text-primary hover:text-text-primary hover:bg-state-error"
|
||||
onClick={onOk}
|
||||
>
|
||||
{okButtonText || t('common.delete')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { CheckOutlined, CopyOutlined } from '@ant-design/icons';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { LucideCheck, LucideCopy } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { CopyToClipboard as Clipboard, Props } from 'react-copy-to-clipboard';
|
||||
import { CopyToClipboard as Clipboard } from 'react-copy-to-clipboard';
|
||||
import { Button, ButtonProps } from './ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
|
||||
|
||||
const CopyToClipboard = ({ text }: Props) => {
|
||||
const CopyToClipboard = ({
|
||||
text,
|
||||
className,
|
||||
...buttonProps
|
||||
}: { text: string } & ButtonProps) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const { t } = useTranslate('common');
|
||||
|
||||
@@ -16,12 +22,19 @@ const CopyToClipboard = ({ text }: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Clipboard text={text} onCopy={handleCopy}>
|
||||
{copied ? <CheckOutlined /> : <CopyOutlined />}
|
||||
</Clipboard>
|
||||
</TooltipTrigger>
|
||||
<Tooltip open={copied ? true : undefined}>
|
||||
<Clipboard text={text} onCopy={handleCopy}>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-sm"
|
||||
{...buttonProps}
|
||||
className={cn(className, copied && '!text-state-success')}
|
||||
>
|
||||
{copied ? <LucideCheck /> : <LucideCopy />}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
</Clipboard>
|
||||
<TooltipContent>{copied ? t('copied') : t('copy')}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
} from '@/components/file-upload';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { t } from 'i18next';
|
||||
import {
|
||||
Atom,
|
||||
@@ -159,7 +158,7 @@ export function NextMessageInput({
|
||||
onValueChange={setFiles}
|
||||
onUpload={onUpload}
|
||||
onFileReject={onFileReject}
|
||||
className="relative w-full items-center "
|
||||
className="relative w-full items-center"
|
||||
disabled={isUploading || disabled}
|
||||
>
|
||||
<FileUploadDropzone
|
||||
@@ -178,9 +177,14 @@ export function NextMessageInput({
|
||||
</p>
|
||||
</div>
|
||||
</FileUploadDropzone>
|
||||
|
||||
<form
|
||||
onSubmit={onSubmit}
|
||||
className="relative flex w-full flex-col gap-2.5 rounded-md border border-input px-3 py-2 outline-none focus-within:ring-1 focus-within:ring-ring/50"
|
||||
className="
|
||||
relative flex w-full flex-col gap-2.5 rounded-md
|
||||
border-0.5 border-border-default bg-bg-card p-2 outline-none
|
||||
has-[textarea:focus]:outline-accent-primary has-[textarea:focus]:outline-1 has-[textarea:focus]:outline-offset-2
|
||||
"
|
||||
>
|
||||
<FileUploadList
|
||||
orientation="horizontal"
|
||||
@@ -205,25 +209,29 @@ export function NextMessageInput({
|
||||
</FileUploadItem>
|
||||
))}
|
||||
</FileUploadList>
|
||||
|
||||
<Textarea
|
||||
value={value}
|
||||
onChange={onInputChange}
|
||||
placeholder={t('chat.messagePlaceholder')}
|
||||
className="min-h-10 max-h-40 w-full border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 dark:bg-transparent"
|
||||
className="
|
||||
min-h-10 max-h-40 w-full p-0 overflow-auto
|
||||
!outline-none !border-transparent !bg-transparent !shadow-none !ring-transparent !ring-offset-transparent
|
||||
"
|
||||
disabled={isUploading || disabled || sendLoading}
|
||||
onKeyDown={handleKeyDown}
|
||||
autoSize={{ minRows: 1, maxRows: 8 }}
|
||||
resize={resize}
|
||||
autoSize={{ minRows: 2, maxRows: 8 }}
|
||||
/>
|
||||
<div className={cn('flex items-center justify-between gap-1.5')}>
|
||||
<div className="flex items-center gap-3">
|
||||
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
{showUploadIcon && (
|
||||
<FileUploadTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="size-7 rounded-sm"
|
||||
size="icon-xs"
|
||||
variant="transparent"
|
||||
className="rounded-sm border-0"
|
||||
disabled={isUploading || sendLoading}
|
||||
>
|
||||
<Paperclip className="size-3.5" />
|
||||
@@ -231,40 +239,35 @@ export function NextMessageInput({
|
||||
</Button>
|
||||
</FileUploadTrigger>
|
||||
)}
|
||||
|
||||
{showReasoning && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
'rounded-sm h-7 focus-visible:bg-none! hover:bg-none!',
|
||||
{
|
||||
'bg-accent-primary text-white': enableThinking,
|
||||
},
|
||||
)}
|
||||
size="sm"
|
||||
variant={enableThinking ? 'accent' : 'transparent'}
|
||||
className="border-0 h-7 text-sm"
|
||||
onClick={handleThinkingToggle}
|
||||
>
|
||||
<Atom />
|
||||
<span>Thinking</span>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{showInternet && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
'rounded-sm h-7 focus-visible:bg-none! hover:bg-none!',
|
||||
{
|
||||
'bg-accent-primary text-white': enableInternet,
|
||||
},
|
||||
)}
|
||||
variant={enableInternet ? 'accent' : 'transparent'}
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={handleInternetToggle}
|
||||
>
|
||||
<Globe />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{sendLoading ? (
|
||||
<Button onClick={stopOutputMessage} className="size-5 rounded-sm">
|
||||
<Button onClick={stopOutputMessage} size="icon-xs">
|
||||
<CircleStop />
|
||||
</Button>
|
||||
) : (
|
||||
@@ -274,8 +277,9 @@ export function NextMessageInput({
|
||||
setAudioInputValue(value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="size-5 rounded-sm"
|
||||
size="icon-xs"
|
||||
disabled={
|
||||
sendDisabled || isUploading || sendLoading || !value.trim()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PromptIcon } from '@/assets/icon/next-icon';
|
||||
import CopyToClipboard from '@/components/copy-to-clipboard';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
@@ -8,18 +7,20 @@ import {
|
||||
} from '@/components/ui/tooltip';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { IRemoveMessageById } from '@/hooks/logic-hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
DislikeOutlined,
|
||||
LikeOutlined,
|
||||
PauseCircleOutlined,
|
||||
SoundOutlined,
|
||||
SyncOutlined,
|
||||
} from '@ant-design/icons';
|
||||
LucidePauseCircle,
|
||||
LucideRefreshCw,
|
||||
LucideThumbsDown,
|
||||
LucideThumbsUp,
|
||||
LucideTrash2,
|
||||
LucideVolume2,
|
||||
} from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import FeedbackDialog from '../feedback-dialog';
|
||||
import { PromptDialog } from '../prompt-dialog';
|
||||
import { Button } from '../ui/button';
|
||||
import { useRemoveMessage, useSendFeedback, useSpeech } from './hooks';
|
||||
|
||||
interface IProps {
|
||||
@@ -55,44 +56,57 @@ export const AssistantGroupButton = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="space-x-1"
|
||||
>
|
||||
<ToggleGroupItem value="a">
|
||||
<CopyToClipboard text={content}></CopyToClipboard>
|
||||
</ToggleGroupItem>
|
||||
<div className="flex gap-1" role="toolbar">
|
||||
<CopyToClipboard text={content} className="border-0" size="icon-xs" />
|
||||
|
||||
{showLoudspeaker && (
|
||||
<ToggleGroupItem value="b" onClick={handleRead}>
|
||||
<>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span>
|
||||
{isPlaying ? <PauseCircleOutlined /> : <SoundOutlined />}
|
||||
</span>
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={handleRead}
|
||||
>
|
||||
<span>
|
||||
{isPlaying ? <LucidePauseCircle /> : <LucideVolume2 />}
|
||||
</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('chat.read')}</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
<audio src="" ref={ref}></audio>
|
||||
</ToggleGroupItem>
|
||||
</>
|
||||
)}
|
||||
{showLikeButton && (
|
||||
<>
|
||||
<ToggleGroupItem value="c" onClick={handleLike}>
|
||||
<LikeOutlined />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="d" onClick={showModal}>
|
||||
<DislikeOutlined />
|
||||
</ToggleGroupItem>
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={handleLike}
|
||||
>
|
||||
<LucideThumbsUp />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={showModal}
|
||||
>
|
||||
<LucideThumbsDown />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{prompt && (
|
||||
<ToggleGroupItem value="e" onClick={showPromptModal}>
|
||||
<Button onClick={showPromptModal}>
|
||||
<PromptIcon style={{ fontSize: '16px' }} />
|
||||
</ToggleGroupItem>
|
||||
</Button>
|
||||
)}
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
{visible && (
|
||||
<FeedbackDialog
|
||||
visible={visible}
|
||||
@@ -133,39 +147,41 @@ export const UserGroupButton = ({
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="space-x-1"
|
||||
>
|
||||
<ToggleGroupItem value="a">
|
||||
<CopyToClipboard text={content}></CopyToClipboard>
|
||||
</ToggleGroupItem>
|
||||
<div className="flex gap-1">
|
||||
<CopyToClipboard text={content} className="border-0" size="icon-xs" />
|
||||
|
||||
{regenerateMessage && (
|
||||
<ToggleGroupItem
|
||||
value="b"
|
||||
onClick={regenerateMessage}
|
||||
disabled={sendLoading}
|
||||
>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<SyncOutlined spin={sendLoading} />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('chat.regenerate')}</TooltipContent>
|
||||
</Tooltip>
|
||||
</ToggleGroupItem>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={regenerateMessage}
|
||||
disabled={sendLoading}
|
||||
>
|
||||
<LucideRefreshCw className={cn(sendLoading && 'animate-spin')} />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('chat.regenerate')}</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{removeMessageById && (
|
||||
<ToggleGroupItem value="c" onClick={onRemoveMessage} disabled={loading}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<DeleteOutlined spin={loading} />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('common.delete')}</TooltipContent>
|
||||
</Tooltip>
|
||||
</ToggleGroupItem>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
className="border-0"
|
||||
onClick={onRemoveMessage}
|
||||
disabled={loading}
|
||||
>
|
||||
<LucideTrash2 />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{t('common.delete')}</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
.messageTextDark {
|
||||
.chunkText();
|
||||
.messageTextBase();
|
||||
padding: 0;
|
||||
word-break: break-word;
|
||||
:global(section.think) {
|
||||
color: rgb(166, 166, 166);
|
||||
|
||||
@@ -4,14 +4,15 @@ import React from 'react';
|
||||
import { Button, ButtonProps } from './ui/button';
|
||||
|
||||
export const MoreButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, size, ...props }, ref) => {
|
||||
function MoreButton({ className, size, ...props }, ref) {
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
variant="ghost"
|
||||
size={size || 'icon'}
|
||||
className={cn(
|
||||
'invisible group-hover:visible size-3.5 bg-transparent group-hover:bg-transparent',
|
||||
'invisible size-3.5 bg-transparent group-hover:bg-transparent',
|
||||
'group-focus-within:visible group-hover:visible aria-expanded:visible',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -5,11 +5,13 @@ import { Authorization } from '@/constants/authorization';
|
||||
import { cn } from '@/lib/utils';
|
||||
import api from '@/utils/api';
|
||||
import { getAuthorization } from '@/utils/authorization-util';
|
||||
import { chain, sum } from 'lodash';
|
||||
import { Loader2, Mic, Square } from 'lucide-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useIsDarkTheme } from '../theme-provider';
|
||||
import { Input } from './input';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from './popover';
|
||||
|
||||
const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const audioContextRef = useRef<AudioContext | null>(null);
|
||||
@@ -18,7 +20,79 @@ const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
const streamRef = useRef<MediaStream | null>(null);
|
||||
const isDark = useIsDarkTheme();
|
||||
|
||||
const startVisualization = async () => {
|
||||
const draw = useCallback(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const analyser = analyserRef.current;
|
||||
if (!analyser) return;
|
||||
|
||||
// Set canvas dimensions
|
||||
const width = canvas.clientWidth * window.devicePixelRatio;
|
||||
const height = canvas.clientHeight * window.devicePixelRatio;
|
||||
const centerY = height / 2;
|
||||
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
|
||||
// Clear canvas
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Get frequency data
|
||||
const bufferLength = analyser.frequencyBinCount;
|
||||
const dataArray = new Uint8Array(bufferLength);
|
||||
|
||||
/**
|
||||
* The frequencies are spread linearly from 0Hz to 1/2 of the sample rate
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/getByteFrequencyData
|
||||
*/
|
||||
analyser.getByteFrequencyData(dataArray);
|
||||
|
||||
const desiredBarCount = 6;
|
||||
const freqSpanPerPole =
|
||||
analyser.context.sampleRate / 2 / analyser.frequencyBinCount;
|
||||
const freqMinIndex = Math.max(1, Math.floor(100 / freqSpanPerPole));
|
||||
const freqMaxIndex =
|
||||
Math.max(freqMinIndex, Math.ceil(3500 / freqSpanPerPole)) + 1;
|
||||
|
||||
const freqData = dataArray.slice(
|
||||
freqMinIndex,
|
||||
Math.max(freqMinIndex + desiredBarCount, freqMaxIndex),
|
||||
);
|
||||
|
||||
const reducedFreqData = chain(freqData)
|
||||
.chunk(Math.floor(freqData.length / desiredBarCount))
|
||||
.take(desiredBarCount)
|
||||
.map(sum)
|
||||
.value();
|
||||
|
||||
// Draw waveform
|
||||
const barGap = 1 * window.devicePixelRatio;
|
||||
const barWidth = (width - barGap * (desiredBarCount - 1)) / desiredBarCount;
|
||||
|
||||
// Create gradient
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, height);
|
||||
gradient.addColorStop(0, '#3ba05c'); // Blue
|
||||
gradient.addColorStop(1, '#3ba05c'); // Light blue
|
||||
// gradient.addColorStop(0, isDark ? '#fff' : '#000'); // Blue
|
||||
// gradient.addColorStop(1, isDark ? '#eee' : '#eee'); // Light blue
|
||||
|
||||
for (let i = 0, x = 0; i < desiredBarCount; i++, x += barWidth + barGap) {
|
||||
const barHeight = (reducedFreqData[i] / 255) * centerY;
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(x, centerY - barHeight, barWidth, barHeight * 2);
|
||||
}
|
||||
|
||||
animationFrameRef.current = requestAnimationFrame(draw);
|
||||
}, []);
|
||||
|
||||
const startVisualization = useCallback(async () => {
|
||||
try {
|
||||
// Check if the browser supports getUserMedia
|
||||
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
||||
@@ -30,13 +104,14 @@ const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
streamRef.current = stream;
|
||||
|
||||
// Create audio context and analyzer
|
||||
const audioContext = new (window.AudioContext ||
|
||||
(window as any).webkitAudioContext)();
|
||||
const audioContext = new (
|
||||
window.AudioContext || (window as any).webkitAudioContext
|
||||
)();
|
||||
audioContextRef.current = audioContext;
|
||||
|
||||
const analyser = audioContext.createAnalyser();
|
||||
analyserRef.current = analyser;
|
||||
analyser.fftSize = 32;
|
||||
analyser.fftSize = 256;
|
||||
|
||||
// Connect audio nodes
|
||||
const source = audioContext.createMediaStreamSource(stream);
|
||||
@@ -50,9 +125,9 @@ const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
error,
|
||||
);
|
||||
}
|
||||
};
|
||||
}, [draw]);
|
||||
|
||||
const stopVisualization = () => {
|
||||
const stopVisualization = useCallback(() => {
|
||||
// Stop animation frame
|
||||
if (animationFrameRef.current) {
|
||||
cancelAnimationFrame(animationFrameRef.current);
|
||||
@@ -76,7 +151,8 @@ const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isRecording) {
|
||||
startVisualization();
|
||||
@@ -87,68 +163,9 @@ const VoiceVisualizer = ({ isRecording }: { isRecording: boolean }) => {
|
||||
return () => {
|
||||
stopVisualization();
|
||||
};
|
||||
}, [isRecording]);
|
||||
const draw = () => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
}, [isRecording, startVisualization, stopVisualization]);
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const analyser = analyserRef.current;
|
||||
if (!analyser) return;
|
||||
|
||||
// Set canvas dimensions
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
const centerY = height / 2;
|
||||
|
||||
if (canvas.width !== width || canvas.height !== height) {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
|
||||
// Clear canvas
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Get frequency data
|
||||
const bufferLength = analyser.frequencyBinCount;
|
||||
const dataArray = new Uint8Array(bufferLength);
|
||||
analyser.getByteFrequencyData(dataArray);
|
||||
|
||||
// Draw waveform
|
||||
const barWidth = (width / bufferLength) * 1.5;
|
||||
let x = 0;
|
||||
|
||||
for (let i = 0; i < bufferLength; i = i + 2) {
|
||||
const barHeight = (dataArray[i] / 255) * centerY;
|
||||
|
||||
// Create gradient
|
||||
const gradient = ctx.createLinearGradient(
|
||||
0,
|
||||
centerY - barHeight,
|
||||
0,
|
||||
centerY + barHeight,
|
||||
);
|
||||
gradient.addColorStop(0, '#3ba05c'); // Blue
|
||||
gradient.addColorStop(1, '#3ba05c'); // Light blue
|
||||
// gradient.addColorStop(0, isDark ? '#fff' : '#000'); // Blue
|
||||
// gradient.addColorStop(1, isDark ? '#eee' : '#eee'); // Light blue
|
||||
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(x, centerY - barHeight, barWidth, barHeight * 2);
|
||||
|
||||
x += barWidth + 2;
|
||||
}
|
||||
|
||||
animationFrameRef.current = requestAnimationFrame(draw);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full h-6 bg-transparent flex items-center justify-center overflow-hidden ">
|
||||
<canvas ref={canvasRef} className="w-full h-full" />
|
||||
</div>
|
||||
);
|
||||
return <canvas ref={canvasRef} className="block size-full" />;
|
||||
};
|
||||
|
||||
const VoiceInputBox = ({
|
||||
@@ -363,21 +380,22 @@ export const AudioButton = ({
|
||||
|
||||
<div className=" relative w-6 h-6 flex items-center justify-center">
|
||||
{isRecording && (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute inset-0 w-full h-6 rounded-full overflow-hidden flex items-center justify-center p-1',
|
||||
{ 'bg-state-success-5': isRecording },
|
||||
)}
|
||||
>
|
||||
<div className="absolute inset-0 size-full overflow-hidden flex items-center justify-center p-1">
|
||||
<VoiceVisualizer isRecording={isRecording} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isRecording && (
|
||||
<div className="absolute inset-0 rounded-full border-2 border-state-success animate-ping opacity-75"></div>
|
||||
<div
|
||||
className="
|
||||
absolute inset-0 rounded-full border-2 border-state-success
|
||||
animate-ping duration-[4s] opacity-75 pointer-events-none"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
variant="transparent"
|
||||
size="icon-xs"
|
||||
// onMouseDown={() => {
|
||||
// startRecording();
|
||||
// }}
|
||||
@@ -391,11 +409,11 @@ export const AudioButton = ({
|
||||
startRecording();
|
||||
}
|
||||
}}
|
||||
className={`w-6 h-6 p-2 rounded-md border-none bg-transparent hover:bg-state-success-5 ${
|
||||
isRecording
|
||||
? 'animate-pulse bg-state-success-5 text-state-success'
|
||||
: ''
|
||||
}`}
|
||||
className={cn(
|
||||
'border-0 p-2 rounded-md border-none bg-transparent hover:bg-state-success-5',
|
||||
isRecording &&
|
||||
'animate-pulse !bg-state-success/20 text-state-success rounded-full',
|
||||
)}
|
||||
disabled={isProcessing}
|
||||
>
|
||||
{isProcessing ? (
|
||||
|
||||
@@ -53,7 +53,10 @@ const BreadcrumbLink = React.forwardRef<
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn('transition-colors hover:text-foreground', className)}
|
||||
className={cn(
|
||||
'transition-colors hover:text-foreground focus-visible:text-foreground',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
83
web/src/components/ui/button-group.tsx
Normal file
83
web/src/components/ui/button-group.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const buttonGroupVariants = cva(
|
||||
"flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
||||
{
|
||||
variants: {
|
||||
orientation: {
|
||||
horizontal:
|
||||
'[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none',
|
||||
vertical:
|
||||
'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
orientation: 'horizontal',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function ButtonGroup({
|
||||
className,
|
||||
orientation,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof buttonGroupVariants>) {
|
||||
return (
|
||||
<div
|
||||
role="group"
|
||||
data-slot="button-group"
|
||||
data-orientation={orientation}
|
||||
className={cn(buttonGroupVariants({ orientation }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ButtonGroupText({
|
||||
className,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & {
|
||||
asChild?: boolean;
|
||||
}) {
|
||||
const Comp = asChild ? Slot : 'div';
|
||||
|
||||
return (
|
||||
<Comp
|
||||
className={cn(
|
||||
"bg-muted shadow-xs flex items-center gap-2 rounded-md border px-4 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ButtonGroupSeparator({
|
||||
className,
|
||||
orientation = 'vertical',
|
||||
...props
|
||||
}: React.ComponentProps<typeof Separator>) {
|
||||
return (
|
||||
<Separator
|
||||
data-slot="button-group-separator"
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
'bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
ButtonGroup,
|
||||
ButtonGroupSeparator,
|
||||
ButtonGroupText,
|
||||
buttonGroupVariants,
|
||||
};
|
||||
@@ -36,7 +36,7 @@ const buttonVariants = cva(
|
||||
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
icon: 'bg-colors-background-inverse-standard text-foreground hover:bg-colors-background-inverse-standard/80',
|
||||
dashed: 'border border-dashed border-input hover:bg-accent',
|
||||
dashed: 'border border-dashed border-border-button hover:bg-accent',
|
||||
|
||||
transparent: `
|
||||
text-text-secondary bg-transparent border-0.5 border-border-button
|
||||
@@ -49,10 +49,16 @@ const buttonVariants = cva(
|
||||
hover:bg-state-error/10 focus-visible:bg-state-error/10
|
||||
`,
|
||||
|
||||
accent: `
|
||||
bg-accent-primary text-white
|
||||
hover:bg-accent-primary/90 focus-visible:bg-accent-primary/90
|
||||
`,
|
||||
|
||||
highlighted: `
|
||||
bg-text-primary text-bg-base border-b-4 border-b-accent-primary
|
||||
hover:bg-text-primary/90 focus-visible:bg-text-primary/90
|
||||
`,
|
||||
|
||||
delete: `
|
||||
text-text-secondary
|
||||
hover:bg-state-error-5 hover:text-state-error
|
||||
@@ -65,6 +71,8 @@ const buttonVariants = cva(
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10',
|
||||
auto: 'h-full px-1',
|
||||
'icon-sm': 'size-8',
|
||||
'icon-xs': 'size-7',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
@@ -75,7 +83,8 @@ const buttonVariants = cva(
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
extends
|
||||
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
loading?: boolean;
|
||||
@@ -126,7 +135,7 @@ ButtonLoading.displayName = 'ButtonLoading';
|
||||
export { Button, buttonVariants };
|
||||
|
||||
export const BlockButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
function BlockButton({ children, className, ...props }, ref) {
|
||||
return (
|
||||
<Button
|
||||
variant={'outline'}
|
||||
|
||||
@@ -5,8 +5,9 @@ import * as React from 'react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface DualRangeSliderProps
|
||||
extends React.ComponentProps<typeof SliderPrimitive.Root> {
|
||||
interface DualRangeSliderProps extends React.ComponentProps<
|
||||
typeof SliderPrimitive.Root
|
||||
> {
|
||||
labelPosition?: 'top' | 'bottom';
|
||||
label?: (value: number | undefined) => React.ReactNode;
|
||||
}
|
||||
@@ -33,7 +34,12 @@ const DualRangeSlider = React.forwardRef<
|
||||
</SliderPrimitive.Track>
|
||||
{initialValue.map((value, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<SliderPrimitive.Thumb className="relative block h-2.5 w-2.5 rounded-full border-2 border-accent-primary bg-white ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 cursor-pointer">
|
||||
<SliderPrimitive.Thumb
|
||||
className="
|
||||
relative block h-2.5 w-2.5 rounded-full border-2 border-accent-primary bg-white ring-offset-background transition-colors
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-2
|
||||
disabled:pointer-events-none disabled:opacity-50 cursor-pointer"
|
||||
>
|
||||
{label && (
|
||||
<span
|
||||
className={cn(
|
||||
|
||||
@@ -20,7 +20,13 @@ const Slider = React.forwardRef<
|
||||
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-colors-background-inverse-strong">
|
||||
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
||||
</SliderPrimitive.Track>
|
||||
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-colors-text-core-standard ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
|
||||
|
||||
<SliderPrimitive.Thumb
|
||||
className="
|
||||
block h-5 w-5 rounded-full border-2 border-primary bg-colors-text-core-standard transition-colors ring-offset-background
|
||||
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-2
|
||||
disabled:pointer-events-none disabled:opacity-50"
|
||||
/>
|
||||
</SliderPrimitive.Root>
|
||||
));
|
||||
Slider.displayName = SliderPrimitive.Root.displayName;
|
||||
@@ -33,16 +39,18 @@ type SliderProps = Omit<
|
||||
const FormSlider = React.forwardRef<
|
||||
React.ElementRef<typeof SliderPrimitive.Root>,
|
||||
SliderProps
|
||||
>(({ onChange, value, ...props }, ref) => (
|
||||
<Slider
|
||||
ref={ref}
|
||||
{...props}
|
||||
value={[value]}
|
||||
onValueChange={(vals) => {
|
||||
onChange(vals[0]);
|
||||
}}
|
||||
></Slider>
|
||||
));
|
||||
>(function FormSlider({ onChange, value, ...props }, ref) {
|
||||
return (
|
||||
<Slider
|
||||
ref={ref}
|
||||
{...props}
|
||||
value={[value]}
|
||||
onValueChange={(vals) => {
|
||||
onChange(vals[0]);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Slider.displayName = SliderPrimitive.Root.displayName;
|
||||
|
||||
|
||||
@@ -891,7 +891,7 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
||||
tocEnhance: 'PageIndex',
|
||||
tocEnhanceTip: ` During the parsing of the document, table of contents information was generated (see the 'Enable Table of Contents Extraction' option in the General method). This allows the large model to return table of contents items relevant to the user's query, thereby using these items to retrieve related chunks and apply weighting to these chunks during the sorting process. This approach mimics human information-searching behavior in books.`,
|
||||
batchDeleteSessions: 'Batch delete',
|
||||
deleteSelectedConfirm: 'Delete the selected {count} session(s)?',
|
||||
deleteSelectedConfirm: 'Delete the selected {{count}} session(s)?',
|
||||
},
|
||||
setting: {
|
||||
Verify: 'Verify',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Form } from '@/components/ui/form';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { DatasetMetadata } from '@/constants/chat';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
@@ -10,7 +11,7 @@ import {
|
||||
} from '@/utils/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { isEmpty, omit } from 'lodash';
|
||||
import { PanelRightClose, Settings } from 'lucide-react';
|
||||
import { LucidePanelRightClose, LucideSettings } from 'lucide-react';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -103,39 +104,51 @@ export function ChatSettings({ hasSingleChatBox }: ChatSettingsProps) {
|
||||
return (
|
||||
<div className="p-5">
|
||||
<Button
|
||||
className="w-full"
|
||||
onClick={switchSettingVisible}
|
||||
disabled={!hasSingleChatBox}
|
||||
variant={'ghost'}
|
||||
size="icon-sm"
|
||||
>
|
||||
<Settings />
|
||||
<LucideSettings />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="p-5 w-[440px] flex flex-col">
|
||||
<div className="flex justify-between items-center text-base pb-2">
|
||||
<section className="w-[440px] flex flex-col">
|
||||
<div className="p-5 pb-2 flex justify-between items-center text-base">
|
||||
{t('chat.chatSetting')}
|
||||
<PanelRightClose
|
||||
className="size-4 cursor-pointer"
|
||||
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-sm"
|
||||
className="border-0"
|
||||
onClick={switchSettingVisible}
|
||||
/>
|
||||
>
|
||||
<LucidePanelRightClose
|
||||
className="size-4 cursor-pointer"
|
||||
onClick={switchSettingVisible}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit, onInvalid)}
|
||||
className="flex-1 flex flex-col min-h-0"
|
||||
>
|
||||
<section className="space-y-6 overflow-auto flex-1 pr-4 min-h-0">
|
||||
<ChatBasicSetting></ChatBasicSetting>
|
||||
<Separator />
|
||||
<ChatPromptEngine></ChatPromptEngine>
|
||||
<Separator />
|
||||
<ChatModelSettings></ChatModelSettings>
|
||||
</section>
|
||||
<div className="space-x-5 text-right pt-4">
|
||||
<ScrollArea>
|
||||
<section className="p-5 space-y-6 overflow-auto flex-1 min-h-0">
|
||||
<ChatBasicSetting></ChatBasicSetting>
|
||||
<Separator />
|
||||
<ChatPromptEngine></ChatPromptEngine>
|
||||
<Separator />
|
||||
<ChatModelSettings></ChatModelSettings>
|
||||
</section>
|
||||
</ScrollArea>
|
||||
|
||||
<div className="p-5 pt-4 space-x-5 text-right">
|
||||
<Button variant={'outline'} onClick={switchSettingVisible}>
|
||||
{t('chat.cancel')}
|
||||
</Button>
|
||||
|
||||
@@ -38,25 +38,33 @@ export function DynamicVariableForm() {
|
||||
<FormLabel tooltip={t('chat.variableTip')}>
|
||||
{t('chat.variable')}
|
||||
</FormLabel>
|
||||
<Button variant={'ghost'} type="button" onClick={add}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
className="border-0"
|
||||
type="button"
|
||||
onClick={add}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-2 pr-12 text-text-secondary text-xs">
|
||||
<span className="flex-1">{t('chat.key')}</span>
|
||||
<span className="w-3"></span>
|
||||
<span className="flex-1">{t('chat.optional')}</span>
|
||||
</div>
|
||||
<div className="space-y-5">
|
||||
{fields.map((field, index) => {
|
||||
const typeField = `${name}.${index}.key`;
|
||||
return (
|
||||
<div key={field.id} className="flex w-full items-center gap-2">
|
||||
|
||||
<div className="grid grid-cols-[1fr_auto_auto_auto] items-center gap-2">
|
||||
<div className="contents text-text-secondary text-xs">
|
||||
<span>{t('chat.key')}</span>
|
||||
<span />
|
||||
<span>{t('chat.optional')}</span>
|
||||
<span />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-subgrid items-center col-span-4 gap-y-4">
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.id} className="contents">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={typeField}
|
||||
name={`${name}.${index}.key`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1 overflow-hidden">
|
||||
<FormItem className="flex-1">
|
||||
<FormControl>
|
||||
<BlurInput
|
||||
{...field}
|
||||
@@ -67,12 +75,14 @@ export function DynamicVariableForm() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Separator className="w-3 text-text-secondary" />
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`${name}.${index}.optional`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex-1 overflow-hidden">
|
||||
<FormItem className="flex-1">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
@@ -83,12 +93,19 @@ export function DynamicVariableForm() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button variant={'ghost'} onClick={() => remove(index)}>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
className="border-0"
|
||||
type="button"
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
<X className="text-text-sub-title-invert " />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -163,7 +163,7 @@ const ChatCard = forwardRef(function ChatCard(
|
||||
|
||||
return (
|
||||
<Card className="bg-transparent border flex-1 flex flex-col">
|
||||
<CardHeader className="border-b px-5 py-3">
|
||||
<CardHeader className="border-b-0.5 px-5 py-3">
|
||||
<CardTitle className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-base">{idx + 1}</span>
|
||||
@@ -175,7 +175,8 @@ const ChatCard = forwardRef(function ChatCard(
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
disabled={isEmpty(llmId)}
|
||||
onClick={handleApplyConfig}
|
||||
>
|
||||
@@ -187,12 +188,16 @@ const ChatCard = forwardRef(function ChatCard(
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
{!isLatestChat || chatBoxIds.length === 3 ? (
|
||||
<Button variant={'ghost'} onClick={handleRemoveChatBox}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={handleRemoveChatBox}
|
||||
>
|
||||
<Trash2 />
|
||||
</Button>
|
||||
) : (
|
||||
<Button variant={'ghost'} onClick={addChatBox}>
|
||||
<Plus></Plus>
|
||||
<Button variant="ghost" size="icon-sm" onClick={addChatBox}>
|
||||
<Plus />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -73,67 +73,71 @@ export function SingleChatBox({
|
||||
}, [conversationId, setDerivedMessages]);
|
||||
|
||||
return (
|
||||
<section className="flex flex-col p-5 h-full">
|
||||
<div ref={messageContainerRef} className="flex-1 overflow-auto min-h-0">
|
||||
<section className="flex flex-col h-full gap-4">
|
||||
<div
|
||||
ref={messageContainerRef}
|
||||
className="p-5 flex-1 overflow-auto min-h-0 scrollbar-auto"
|
||||
>
|
||||
<div className="w-full pr-5">
|
||||
{derivedMessages?.map((message, i) => {
|
||||
return (
|
||||
<MessageItem
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
derivedMessages.length - 1 === i
|
||||
}
|
||||
key={buildMessageUuidWithRole(message)}
|
||||
item={message}
|
||||
nickname={userInfo.nickname}
|
||||
avatar={userInfo.avatar}
|
||||
avatarDialog={currentDialog.icon}
|
||||
reference={buildMessageItemReference(
|
||||
{
|
||||
message: derivedMessages,
|
||||
reference: conversation.reference,
|
||||
},
|
||||
message,
|
||||
)}
|
||||
clickDocumentButton={clickDocumentButton}
|
||||
index={i}
|
||||
removeMessageById={removeMessageById}
|
||||
regenerateMessage={regenerateMessage}
|
||||
sendLoading={sendLoading}
|
||||
></MessageItem>
|
||||
);
|
||||
})}
|
||||
{derivedMessages?.map((message, i) => (
|
||||
<MessageItem
|
||||
loading={
|
||||
message.role === MessageType.Assistant &&
|
||||
sendLoading &&
|
||||
derivedMessages.length - 1 === i
|
||||
}
|
||||
key={buildMessageUuidWithRole(message)}
|
||||
item={message}
|
||||
nickname={userInfo.nickname}
|
||||
avatar={userInfo.avatar}
|
||||
avatarDialog={currentDialog.icon}
|
||||
reference={buildMessageItemReference(
|
||||
{
|
||||
message: derivedMessages,
|
||||
reference: conversation.reference,
|
||||
},
|
||||
message,
|
||||
)}
|
||||
clickDocumentButton={clickDocumentButton}
|
||||
index={i}
|
||||
removeMessageById={removeMessageById}
|
||||
regenerateMessage={regenerateMessage}
|
||||
sendLoading={sendLoading}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div ref={scrollRef} />
|
||||
</div>
|
||||
<NextMessageInput
|
||||
disabled={disabled}
|
||||
sendDisabled={sendDisabled}
|
||||
sendLoading={sendLoading}
|
||||
value={value}
|
||||
resize="vertical"
|
||||
onInputChange={handleInputChange}
|
||||
onPressEnter={handlePressEnter}
|
||||
conversationId={conversationId}
|
||||
createConversationBeforeUploadDocument={
|
||||
createConversationBeforeUploadDocument
|
||||
}
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
onUpload={handleUploadFile}
|
||||
isUploading={isUploading}
|
||||
removeFile={removeFile}
|
||||
showReasoning
|
||||
showInternet={showInternet}
|
||||
/>
|
||||
{visible && (
|
||||
<PdfSheet
|
||||
visible={visible}
|
||||
hideModal={hideModal}
|
||||
documentId={documentId}
|
||||
chunk={selectedChunk}
|
||||
></PdfSheet>
|
||||
)}
|
||||
|
||||
<div className="p-5 pt-0">
|
||||
<NextMessageInput
|
||||
disabled={disabled}
|
||||
sendDisabled={sendDisabled}
|
||||
sendLoading={sendLoading}
|
||||
value={value}
|
||||
resize="vertical"
|
||||
onInputChange={handleInputChange}
|
||||
onPressEnter={handlePressEnter}
|
||||
conversationId={conversationId}
|
||||
createConversationBeforeUploadDocument={
|
||||
createConversationBeforeUploadDocument
|
||||
}
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
onUpload={handleUploadFile}
|
||||
isUploading={isUploading}
|
||||
removeFile={removeFile}
|
||||
showReasoning
|
||||
showInternet={showInternet}
|
||||
/>
|
||||
{visible && (
|
||||
<PdfSheet
|
||||
visible={visible}
|
||||
hideModal={hideModal}
|
||||
documentId={documentId}
|
||||
chunk={selectedChunk}
|
||||
></PdfSheet>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { SharedFrom } from '@/constants/chat';
|
||||
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
|
||||
import {
|
||||
useFetchConversationList,
|
||||
useFetchConversationManually,
|
||||
@@ -21,9 +20,14 @@ import {
|
||||
} from '@/hooks/use-chat-request';
|
||||
import { IClientConversation } from '@/interfaces/database/chat';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Routes } from '@/routes';
|
||||
import { useMount } from 'ahooks';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { ArrowUpRight, LogOut, Send } from 'lucide-react';
|
||||
import {
|
||||
LucideArrowBigLeft,
|
||||
LucideArrowUpRight,
|
||||
LucideSend,
|
||||
} from 'lucide-react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useParams } from 'react-router';
|
||||
@@ -37,7 +41,6 @@ import { useSwitchDebugMode } from './use-switch-debug-mode';
|
||||
|
||||
export default function Chat() {
|
||||
const { id } = useParams();
|
||||
const { navigateToChatList } = useNavigatePage();
|
||||
const { data } = useFetchDialog();
|
||||
const { t } = useTranslation();
|
||||
const [currentConversation, setCurrentConversation] =
|
||||
@@ -89,15 +92,20 @@ export default function Chat() {
|
||||
|
||||
if (isDebugMode) {
|
||||
return (
|
||||
<section className="pt-14 h-[100vh] pb-24">
|
||||
<div className="flex items-center justify-between px-10 pb-5">
|
||||
<section className="pt-5 pb-16 h-[100vh] flex flex-col">
|
||||
<header className="px-10 pb-5">
|
||||
<div className="mb-5">
|
||||
<Button variant="outline" onClick={switchDebugMode}>
|
||||
<LucideArrowBigLeft />
|
||||
<span>{t('common.back')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<span className="text-2xl">
|
||||
{t('chat.multipleModels')} ({chatBoxIds.length}/3)
|
||||
</span>
|
||||
<Button variant={'ghost'} onClick={switchDebugMode}>
|
||||
{t('chat.exit')} <LogOut />
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<MultipleChatBox
|
||||
chatBoxIds={chatBoxIds}
|
||||
controller={controller}
|
||||
@@ -116,7 +124,11 @@ export default function Chat() {
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink onClick={navigateToChatList}>
|
||||
<BreadcrumbLink
|
||||
// Not friendly for keyboard navigation
|
||||
// onClick={navigateToChatList}
|
||||
href={Routes.Chats}
|
||||
>
|
||||
{t('chat.chat')}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
@@ -127,23 +139,26 @@ export default function Chat() {
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
<Button onClick={showEmbedModal}>
|
||||
<Send />
|
||||
<LucideSend />
|
||||
{t('common.embedIntoSite')}
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<div className="flex flex-1 min-h-0 pb-9">
|
||||
|
||||
<article className="flex flex-1 min-h-0 pb-9">
|
||||
<Sessions handleConversationCardClick={handleSessionClick}></Sessions>
|
||||
|
||||
<Card className="flex-1 min-w-0 bg-transparent border-none shadow-none h-full">
|
||||
<CardContent className="flex p-0 h-full">
|
||||
<Card className="flex flex-col flex-1 bg-transparent min-w-0">
|
||||
<CardHeader
|
||||
className={cn('p-5', { 'border-b': hasSingleChatBox })}
|
||||
className={cn('p-5', {
|
||||
'border-b-0.5 border-border-button': hasSingleChatBox,
|
||||
})}
|
||||
>
|
||||
<CardTitle className="flex justify-between items-center text-base">
|
||||
<CardTitle className="flex justify-between items-center text-base gap-2">
|
||||
<div className="truncate">{currentConversationName}</div>
|
||||
<Button variant={'ghost'} onClick={switchDebugMode}>
|
||||
<ArrowUpRight /> {t('chat.multipleModels')}
|
||||
<LucideArrowUpRight /> {t('chat.multipleModels')}
|
||||
</Button>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
@@ -152,13 +167,15 @@ export default function Chat() {
|
||||
controller={controller}
|
||||
stopOutputMessage={stopOutputMessage}
|
||||
conversation={currentConversation}
|
||||
></SingleChatBox>
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<ChatSettings hasSingleChatBox={hasSingleChatBox}></ChatSettings>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{embedVisible && (
|
||||
<EmbedDialog
|
||||
visible={embedVisible}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog';
|
||||
import { MoreButton } from '@/components/more-button';
|
||||
import { RAGFlowAvatar } from '@/components/ragflow-avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { SearchInput } from '@/components/ui/input';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
@@ -11,14 +10,13 @@ import {
|
||||
useGetChatSearchParams,
|
||||
useRemoveConversation,
|
||||
} from '@/hooks/use-chat-request';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
Check,
|
||||
CopyX,
|
||||
PanelLeftClose,
|
||||
Plus,
|
||||
Trash2,
|
||||
Undo2,
|
||||
LucideCopyX,
|
||||
LucideListChecks,
|
||||
LucidePanelLeftClose,
|
||||
LucidePlus,
|
||||
LucideTrash2,
|
||||
LucideUndo2,
|
||||
} from 'lucide-react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -91,72 +89,80 @@ export function Sessions({ handleConversationCardClick }: SessionProps) {
|
||||
}, [selectedIds, removeConversation, exitSelectionMode]);
|
||||
|
||||
const selectedCount = useMemo(() => selectedIds.size, [selectedIds]);
|
||||
const allSelected = useMemo(
|
||||
() =>
|
||||
selectedCount === conversationList.length && conversationList.length > 0,
|
||||
[selectedCount, conversationList.length],
|
||||
);
|
||||
|
||||
const handleCardClick = useCallback(
|
||||
(conversationId: string, isNew: boolean) => () => {
|
||||
if (selectionMode) {
|
||||
toggleSelection(conversationId);
|
||||
} else {
|
||||
handleConversationCardClick(conversationId, isNew);
|
||||
}
|
||||
},
|
||||
[handleConversationCardClick, selectionMode, toggleSelection],
|
||||
);
|
||||
|
||||
const { conversationId } = useGetChatSearchParams();
|
||||
|
||||
if (!visible) {
|
||||
return (
|
||||
<div className="p-5">
|
||||
<RAGFlowAvatar
|
||||
avatar={data.icon}
|
||||
name={data.name}
|
||||
className="size-8 cursor-pointer"
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-sm"
|
||||
className="border-0"
|
||||
onClick={switchVisible}
|
||||
></RAGFlowAvatar>
|
||||
>
|
||||
<RAGFlowAvatar
|
||||
avatar={data.icon}
|
||||
name={data.name}
|
||||
className="size-8 cursor-pointer"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="p-5 w-[296px] flex flex-col">
|
||||
<section className="flex items-center text-base justify-between gap-2">
|
||||
<aside className="p-5 w-[296px] flex flex-col" role="complementary">
|
||||
<header className="flex items-center text-base justify-between gap-2">
|
||||
<div className="flex gap-3 items-center min-w-0">
|
||||
<RAGFlowAvatar
|
||||
avatar={data.icon}
|
||||
name={data.name}
|
||||
className="size-8"
|
||||
></RAGFlowAvatar>
|
||||
/>
|
||||
|
||||
<span className="flex-1 truncate">{data.name}</span>
|
||||
</div>
|
||||
<PanelLeftClose
|
||||
className="cursor-pointer size-4"
|
||||
|
||||
<Button
|
||||
variant="transparent"
|
||||
size="icon-sm"
|
||||
className="border-0"
|
||||
onClick={switchVisible}
|
||||
/>
|
||||
</section>
|
||||
>
|
||||
<LucidePanelLeftClose />
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
<div className="flex justify-between items-center mb-4 pt-10">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-base font-bold">{t('chat.conversations')}</span>
|
||||
<span className="text-text-secondary text-xs">
|
||||
<data
|
||||
className="text-text-secondary text-xs"
|
||||
value={conversationList.length}
|
||||
>
|
||||
{conversationList.length}
|
||||
</span>
|
||||
</data>
|
||||
</div>
|
||||
{selectionMode && selectedCount > 0 ? (
|
||||
// Selection mode with items selected: show return and delete
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{selectionMode ? (
|
||||
// Exit selection mode
|
||||
<Button variant="ghost" size="icon-xs" onClick={exitSelectionMode}>
|
||||
<LucideUndo2 size={16} />
|
||||
</Button>
|
||||
) : (
|
||||
// New conversation
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6"
|
||||
onClick={exitSelectionMode}
|
||||
size="icon-xs"
|
||||
onClick={addTemporaryConversation}
|
||||
>
|
||||
<Undo2 size={16} />
|
||||
<LucidePlus className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{selectionMode && selectedCount > 0 ? (
|
||||
// Delete selected items
|
||||
<ConfirmDeleteDialog
|
||||
onOk={handleBatchDelete}
|
||||
title={t('chat.batchDeleteSessions')}
|
||||
@@ -166,89 +172,82 @@ export function Sessions({ handleConversationCardClick }: SessionProps) {
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6 text-state-error"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
<Button variant="delete" size="icon-xs">
|
||||
<LucideTrash2 />
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
</div>
|
||||
) : (
|
||||
// Default or selection mode without selection: show plus and batch delete
|
||||
<div className="flex items-center gap-1">
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6"
|
||||
onClick={addTemporaryConversation}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-6"
|
||||
size="icon-xs"
|
||||
onClick={selectionMode ? toggleSelectAll : toggleSelectionMode}
|
||||
>
|
||||
{selectionMode && allSelected ? (
|
||||
<Check className="h-4 w-4" />
|
||||
) : (
|
||||
<CopyX className="h-4 w-4" />
|
||||
// <img
|
||||
// src="/batch_delete2.png"
|
||||
// alt="批量删除"
|
||||
// className="h-4 w-4"
|
||||
// />
|
||||
)}
|
||||
{selectionMode ? <LucideListChecks /> : <LucideCopyX />}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
|
||||
<div className="pb-4" role="search">
|
||||
<SearchInput
|
||||
onChange={handleInputChange}
|
||||
value={searchString}
|
||||
></SearchInput>
|
||||
</div>
|
||||
<div className="space-y-4 flex-1 overflow-auto">
|
||||
{conversationList.map((x) => (
|
||||
<Card
|
||||
key={x.id}
|
||||
onClick={handleCardClick(x.id, x.is_new)}
|
||||
className={cn('cursor-pointer bg-transparent relative', {
|
||||
'bg-bg-card': conversationId === x.id && !selectionMode,
|
||||
})}
|
||||
>
|
||||
<CardContent className="px-3 py-2 flex justify-between items-center group gap-1">
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
{selectionMode && (
|
||||
<span
|
||||
className="flex-shrink-0"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Checkbox
|
||||
checked={selectedIds.has(x.id)}
|
||||
onCheckedChange={() => toggleSelection(x.id)}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
<div className="truncate">{x.name}</div>
|
||||
</div>
|
||||
{!selectionMode && (
|
||||
<ConversationDropdown
|
||||
conversation={x}
|
||||
removeTemporaryConversation={removeTemporaryConversation}
|
||||
|
||||
<div className="flex-1 overflow-auto">
|
||||
{selectionMode ? (
|
||||
<ul className="space-y-2" role="listbox" aria-multiselectable>
|
||||
{conversationList.map((x) => (
|
||||
<li
|
||||
key={x.id}
|
||||
className="py-2"
|
||||
role="option"
|
||||
aria-selected={selectedIds.has(x.id)}
|
||||
>
|
||||
<label className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={selectedIds.has(x.id)}
|
||||
onCheckedChange={() => toggleSelection(x.id)}
|
||||
/>
|
||||
|
||||
<span className="truncate">{x.name}</span>
|
||||
</label>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<nav aria-label={t('chat.conversations')}>
|
||||
<ul className="space-y-2">
|
||||
{conversationList.map((x) => (
|
||||
<li
|
||||
key={x.id}
|
||||
className="
|
||||
group pr-3 flex items-center gap-1 rounded-lg
|
||||
aria-selected:bg-bg-card has-[>button:focus-visible]:bg-bg-card
|
||||
"
|
||||
aria-selected={conversationId === x.id}
|
||||
>
|
||||
<MoreButton></MoreButton>
|
||||
</ConversationDropdown>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
className="focus-visible:outline-none px-3 py-2 text-left flex-1 truncate"
|
||||
onClick={() => handleConversationCardClick(x.id, x.is_new)}
|
||||
>
|
||||
{x.name}
|
||||
</button>
|
||||
|
||||
<ConversationDropdown
|
||||
conversation={x}
|
||||
removeTemporaryConversation={removeTemporaryConversation}
|
||||
>
|
||||
<MoreButton></MoreButton>
|
||||
</ConversationDropdown>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -172,14 +172,26 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
id,
|
||||
content: value.trim(),
|
||||
role: MessageType.User,
|
||||
files: files,
|
||||
files,
|
||||
conversationId: targetConversationId,
|
||||
},
|
||||
enableInternet,
|
||||
enableThinking,
|
||||
});
|
||||
}
|
||||
|
||||
clearFiles();
|
||||
|
||||
// Auto scroll to bottom when sending new message
|
||||
if (messageContainerRef.current) {
|
||||
const el = messageContainerRef.current;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
el.scrollTo({
|
||||
top: el.scrollHeight,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
value,
|
||||
@@ -190,6 +202,7 @@ export const useSendMessage = (controller: AbortController) => {
|
||||
clearFiles,
|
||||
setValue,
|
||||
sendMessage,
|
||||
messageContainerRef,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user