feat: 官网首页 liquid-glass 与布局优化,并改进批量邮件发信体验
All checks were successful
Build and Deploy Front / deploy (push) Successful in 8m13s
All checks were successful
Build and Deploy Front / deploy (push) Successful in 8m13s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c2861157af
commit
0910538e6b
@ -49,6 +49,7 @@
|
||||
"@codemirror/theme-one-dark": "^6.1.3",
|
||||
"@codemirror/view": "^6.39.17",
|
||||
"@fontsource/zcool-qingke-huangyou": "^5.3.0",
|
||||
"@glass-sdk/liquid-glass": "~0.0.2",
|
||||
"@handsontable/vue3": "^16.2.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@vueuse/core": "^9.3.0",
|
||||
|
||||
275
pnpm-lock.yaml
generated
275
pnpm-lock.yaml
generated
@ -39,6 +39,9 @@ importers:
|
||||
'@fontsource/zcool-qingke-huangyou':
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0
|
||||
'@glass-sdk/liquid-glass':
|
||||
specifier: ~0.0.2
|
||||
version: 0.0.2(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
|
||||
'@handsontable/vue3':
|
||||
specifier: ^16.2.0
|
||||
version: 16.2.0(handsontable@16.2.0)(vue@3.5.18(typescript@4.9.5))
|
||||
@ -443,6 +446,9 @@ packages:
|
||||
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/runtime@8.1.0':
|
||||
resolution: {integrity: sha512-MQye/pU7gzXerMzlhScFNH1u4Je6rR8cqJWSgAfD+rIwbbtwG8tVDegoI7sWfcXkfVRW09G7vk2vjxGIuKFfwg==}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -455,6 +461,33 @@ packages:
|
||||
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@base-ui/react@1.9.0':
|
||||
resolution: {integrity: sha512-S8CSYosASBKtpL8SWUfS78rFElfLijiCgA7oHOK22jCJ95FULsYyKwBNFOgudt0RA+/7yNc7F81bOvQnRgbBiQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@date-fns/tz': ^1.2.0
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
date-fns: ^4.0.0
|
||||
react: ^17 || ^18 || ^19
|
||||
react-dom: ^17 || ^18 || ^19
|
||||
peerDependenciesMeta:
|
||||
'@date-fns/tz':
|
||||
optional: true
|
||||
'@types/react':
|
||||
optional: true
|
||||
date-fns:
|
||||
optional: true
|
||||
|
||||
'@base-ui/utils@0.5.0':
|
||||
resolution: {integrity: sha512-dYGGcEttjkYiMoa5nHm8vLaJ2UcuTWxo3BFAwOYXeRg/q7UVVvA6cacEIXEs3FgBfK1CGtW1ptElqs7wsx+t9A==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
react: ^17 || ^18 || ^19
|
||||
react-dom: ^17 || ^18 || ^19
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@braintree/sanitize-url@7.1.2':
|
||||
resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==}
|
||||
|
||||
@ -929,15 +962,36 @@ packages:
|
||||
'@floating-ui/core@1.7.4':
|
||||
resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==}
|
||||
|
||||
'@floating-ui/core@1.8.0':
|
||||
resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==}
|
||||
|
||||
'@floating-ui/dom@1.7.5':
|
||||
resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==}
|
||||
|
||||
'@floating-ui/dom@1.8.0':
|
||||
resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==}
|
||||
|
||||
'@floating-ui/react-dom@2.1.9':
|
||||
resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@floating-ui/utils@0.2.10':
|
||||
resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
|
||||
|
||||
'@floating-ui/utils@0.2.12':
|
||||
resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
|
||||
|
||||
'@fontsource/zcool-qingke-huangyou@5.3.0':
|
||||
resolution: {integrity: sha512-6/ld8x/knq1NjDQxLSyg9pDnBPOmtWDb30ZTFk+n8OxfkBoUvPAxh3aV/6+UFGmA5CekJfcgpUwd2/x/weLvSQ==}
|
||||
|
||||
'@glass-sdk/liquid-glass@0.0.2':
|
||||
resolution: {integrity: sha512-bDVDBXj6Cw++U0k9fcrSPEexnVnj/S4BjxF1t7NVQqW8La1gSVtxzPl9dG2VQxKs7Ik9kWR8Zi32JzyggI5Seg==}
|
||||
peerDependencies:
|
||||
react: '>=19.0.0'
|
||||
react-dom: '>=19.0.0'
|
||||
|
||||
'@handsontable/pikaday@1.0.0':
|
||||
resolution: {integrity: sha512-1VN6N38t5/DcjJ7y7XUYrDx1LuzvvzlrFdBdMG90Qo1xc8+LXHqbWbsTEm5Ec5gXTEbDEO53vUT35R+2COmOyg==}
|
||||
|
||||
@ -1027,12 +1081,24 @@ packages:
|
||||
'@lezer/xml@1.0.6':
|
||||
resolution: {integrity: sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==}
|
||||
|
||||
'@lisse/core@0.7.3':
|
||||
resolution: {integrity: sha512-WJWGskrOInlIs+DqK1CfAHNIjWBJ8t4AtM1cPn5RZfu2OmQumBdNGAhFuaIg+tgpibqP17GSwEiMq/fT+NCoIw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@marijn/find-cluster-break@1.0.2':
|
||||
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
|
||||
|
||||
'@mermaid-js/parser@1.2.0':
|
||||
resolution: {integrity: sha512-oYPyv8A4As1yH5Bx+04iQEQxXuIQDe0GKCNSRgao6z8AM9jixXIfP0vsppRLvGf+nKIOb9/LdpWA4YuJiVvESA==}
|
||||
|
||||
'@modelcontextprotocol/core@2.0.0':
|
||||
resolution: {integrity: sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
'@modelcontextprotocol/server@2.0.0':
|
||||
resolution: {integrity: sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
'@mrmlnc/readdir-enhanced@2.2.1':
|
||||
resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==}
|
||||
engines: {node: '>=4'}
|
||||
@ -1841,6 +1907,26 @@ packages:
|
||||
'@upsetjs/venn.js@2.0.0':
|
||||
resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==}
|
||||
|
||||
'@vgpu/adapter-mock@0.5.0':
|
||||
resolution: {integrity: sha512-YtgXOFn1qI+8oTJenG2wWbQPA28V0CfE5UJs5Xqbt6qyR/xaZ5LHH2XWTwFcjnqn2b1xQCyTatJCMyyOdweUnw==}
|
||||
|
||||
'@vgpu/adapter-node@0.5.0':
|
||||
resolution: {integrity: sha512-lgzqFcLDejwRgwlaNStzkwLNU9b4aN2OoPpWqT1UyPmK521BSw2OIQKzAuDIkzNlREla6KNC12G6bthhOzZKzw==}
|
||||
|
||||
'@vgpu/core@0.5.0':
|
||||
resolution: {integrity: sha512-z80DHRHViv6+FKKkPzggEtT1ZZs/WCKRQbzJuwYdA135DZaSbCMoRK4anhM+I/nOHuDpf7H3xjkwE6rfolWZUw==}
|
||||
|
||||
'@vgpu/wgsl-std@0.5.0':
|
||||
resolution: {integrity: sha512-NjMyJxwy4evFNCSqFQy4EqAbZ7iU+NUyJYyG9tLUhbdDLzBmfZlk1S3PyRZ9olBFFfEiVW2JNVw10maPKLEs1A==}
|
||||
|
||||
'@vgpu/wgsl@0.5.0':
|
||||
resolution: {integrity: sha512-PDlDJem7J28C9bk+vPy2kYZEoW8+nYIx2oN4nu7/WF2V7ETx32BtmWcawwMbhiu/CVsobFafML0h0eqLRBNa3Q==}
|
||||
peerDependencies:
|
||||
'@vgpu/adapter-node': '>=0.1.6 <1.0.0 || ^0.5.0-rc.0'
|
||||
peerDependenciesMeta:
|
||||
'@vgpu/adapter-node':
|
||||
optional: true
|
||||
|
||||
'@vitejs/plugin-vue-jsx@2.1.1':
|
||||
resolution: {integrity: sha512-JgDhxstQlwnHBvZ1BSnU5mbmyQ14/t5JhREc6YH5kWyu2QdAAOsLF6xgHoIWarj8tddaiwFrNzLbWJPudpXKYA==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@ -1947,6 +2033,9 @@ packages:
|
||||
'@vueuse/shared@9.13.0':
|
||||
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
|
||||
|
||||
'@webgpu/types@0.1.74':
|
||||
resolution: {integrity: sha512-lgiI4hbuLcI9unnm2cL/tvCaQU45dp0xcLWJh5uB/9MBGvIA4F8XIk7nSiBeg+K4xWGYwgZKn80LmERI5CxoTA==}
|
||||
|
||||
'@wtto00/html2canvas@1.4.3':
|
||||
resolution: {integrity: sha512-jwsb+xL8N+gjrSNABSaFdxmWtE4c7RNFjP20lo1G7gs63Qqo1phhxVBTzxc/apDVh6LgXsU2l5bwKtXd9uz65w==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@ -5469,6 +5558,10 @@ packages:
|
||||
resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
pixelmatch@7.2.0:
|
||||
resolution: {integrity: sha512-xhcb4yHu9sM/G7foGzoLtXYcC0zHEaOXXjRKhGup0fw78Nf2Tkiapv4EQyMzrbcmQPsllAI7DbFY2UT7PlI9Pg==}
|
||||
hasBin: true
|
||||
|
||||
pkg-types@1.3.1:
|
||||
resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
|
||||
|
||||
@ -5479,6 +5572,10 @@ packages:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
pngjs@7.0.0:
|
||||
resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==}
|
||||
engines: {node: '>=14.19.0'}
|
||||
|
||||
pngquant-bin@6.0.1:
|
||||
resolution: {integrity: sha512-Q3PUyolfktf+hYio6wsg3SanQzEU/v8aICg/WpzxXcuCMRb7H2Q81okfpcEztbMvw25ILjd3a87doj2N9kvbpQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -5679,6 +5776,15 @@ packages:
|
||||
raf@3.4.1:
|
||||
resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
|
||||
|
||||
react-dom@19.3.1:
|
||||
resolution: {integrity: sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==}
|
||||
peerDependencies:
|
||||
react: ^19.3.1
|
||||
|
||||
react@19.3.1:
|
||||
resolution: {integrity: sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
read-pkg-up@1.0.1:
|
||||
resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -5791,6 +5897,9 @@ packages:
|
||||
require-main-filename@2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
|
||||
reselect@5.3.0:
|
||||
resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==}
|
||||
|
||||
reserved-words@0.1.2:
|
||||
resolution: {integrity: sha512-0S5SrIUJ9LfpbVl4Yzij6VipUdafHrOTzvmfazSw/jeZrZtQK303OPZW+obtkaw7jQlTQppy0UvZWm9872PbRw==}
|
||||
|
||||
@ -6044,6 +6153,9 @@ packages:
|
||||
sax@1.4.1:
|
||||
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
|
||||
|
||||
scheduler@0.28.0:
|
||||
resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
|
||||
|
||||
screenfull@5.2.0:
|
||||
resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -6919,6 +7031,11 @@ packages:
|
||||
resolution: {integrity: sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
use-sync-external-store@1.7.0:
|
||||
resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
use@3.1.1:
|
||||
resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -6966,6 +7083,15 @@ packages:
|
||||
resolution: {integrity: sha512-KoJRp8V2EsmeW2pg33CVEOEfGDTmcVLL0wk0fOQJjgXfAunciPylOueKovuzlbWSrTQap1UzgNn8xr5zbBsnPA==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
||||
vgpu@0.5.0:
|
||||
resolution: {integrity: sha512-isQfMHRTysYFfT8UWTzqQI/ROw2L7lVkj7xoUJlvIF6FjYxBNS/YNG7qp3tZ7ZvZZ3uwYjso+geQv/bEq5Hl3w==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
three: '>=0.180.0 <0.200.0'
|
||||
peerDependenciesMeta:
|
||||
three:
|
||||
optional: true
|
||||
|
||||
vite-plugin-compression@0.5.1:
|
||||
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
|
||||
peerDependencies:
|
||||
@ -7152,12 +7278,18 @@ packages:
|
||||
w3c-keyname@2.2.8:
|
||||
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
|
||||
|
||||
webgpu@0.4.0:
|
||||
resolution: {integrity: sha512-F5pimn3Aoi0zWjuRdiVs5TnrUwSzD2lESBohsIUsqyitWkGRQlXU2fhV6ycXlQTa1bvAf3sjqiUpBEpmSQ5ptA==}
|
||||
|
||||
webidl-conversions@3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
|
||||
webpack-virtual-modules@0.6.2:
|
||||
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
||||
|
||||
wgpu-matrix@3.4.2:
|
||||
resolution: {integrity: sha512-IfZFbG7olEYBD76VCZy2TzqM57GKy3LT++AZh37tMHPPByO6R2h61zXGBZFNPi2IzxNivNi8y5dvze5PjaczjA==}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
|
||||
@ -7325,6 +7457,9 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
zod@4.6.7:
|
||||
resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==}
|
||||
|
||||
zrender@5.6.1:
|
||||
resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
|
||||
|
||||
@ -7517,6 +7652,8 @@ snapshots:
|
||||
|
||||
'@babel/runtime@7.28.6': {}
|
||||
|
||||
'@babel/runtime@8.1.0': {}
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
@ -7540,6 +7677,25 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.27.1
|
||||
|
||||
'@base-ui/react@1.9.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 8.1.0
|
||||
'@base-ui/utils': 0.5.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
|
||||
'@floating-ui/react-dom': 2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
|
||||
'@floating-ui/utils': 0.2.12
|
||||
react: 19.3.1
|
||||
react-dom: 19.3.1(react@19.3.1)
|
||||
use-sync-external-store: 1.7.0(react@19.3.1)
|
||||
|
||||
'@base-ui/utils@0.5.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1)':
|
||||
dependencies:
|
||||
'@babel/runtime': 8.1.0
|
||||
'@floating-ui/utils': 0.2.12
|
||||
react: 19.3.1
|
||||
react-dom: 19.3.1(react@19.3.1)
|
||||
reselect: 5.3.0
|
||||
use-sync-external-store: 1.7.0(react@19.3.1)
|
||||
|
||||
'@braintree/sanitize-url@7.1.2': {}
|
||||
|
||||
'@bufbuild/protobuf@2.10.1': {}
|
||||
@ -7955,15 +8111,46 @@ snapshots:
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
||||
'@floating-ui/core@1.8.0':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.12
|
||||
|
||||
'@floating-ui/dom@1.7.5':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.7.4
|
||||
'@floating-ui/utils': 0.2.10
|
||||
|
||||
'@floating-ui/dom@1.8.0':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.8.0
|
||||
'@floating-ui/utils': 0.2.12
|
||||
|
||||
'@floating-ui/react-dom@2.1.9(react-dom@19.3.1(react@19.3.1))(react@19.3.1)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.8.0
|
||||
react: 19.3.1
|
||||
react-dom: 19.3.1(react@19.3.1)
|
||||
|
||||
'@floating-ui/utils@0.2.10': {}
|
||||
|
||||
'@floating-ui/utils@0.2.12': {}
|
||||
|
||||
'@fontsource/zcool-qingke-huangyou@5.3.0': {}
|
||||
|
||||
'@glass-sdk/liquid-glass@0.0.2(react-dom@19.3.1(react@19.3.1))(react@19.3.1)':
|
||||
dependencies:
|
||||
'@base-ui/react': 1.9.0(react-dom@19.3.1(react@19.3.1))(react@19.3.1)
|
||||
'@lisse/core': 0.7.3
|
||||
react: 19.3.1
|
||||
react-dom: 19.3.1(react@19.3.1)
|
||||
vgpu: 0.5.0
|
||||
transitivePeerDependencies:
|
||||
- '@date-fns/tz'
|
||||
- '@types/react'
|
||||
- date-fns
|
||||
- supports-color
|
||||
- three
|
||||
|
||||
'@handsontable/pikaday@1.0.0': {}
|
||||
|
||||
'@handsontable/vue3@16.2.0(handsontable@16.2.0)(vue@3.5.18(typescript@4.9.5))':
|
||||
@ -8078,12 +8265,23 @@ snapshots:
|
||||
'@lezer/highlight': 1.2.3
|
||||
'@lezer/lr': 1.4.8
|
||||
|
||||
'@lisse/core@0.7.3': {}
|
||||
|
||||
'@marijn/find-cluster-break@1.0.2': {}
|
||||
|
||||
'@mermaid-js/parser@1.2.0':
|
||||
dependencies:
|
||||
'@chevrotain/types': 11.1.2
|
||||
|
||||
'@modelcontextprotocol/core@2.0.0':
|
||||
dependencies:
|
||||
zod: 4.6.7
|
||||
|
||||
'@modelcontextprotocol/server@2.0.0':
|
||||
dependencies:
|
||||
'@modelcontextprotocol/core': 2.0.0
|
||||
zod: 4.6.7
|
||||
|
||||
'@mrmlnc/readdir-enhanced@2.2.1':
|
||||
dependencies:
|
||||
call-me-maybe: 1.0.2
|
||||
@ -8907,6 +9105,33 @@ snapshots:
|
||||
d3-selection: 3.0.0
|
||||
d3-transition: 3.0.1(d3-selection@3.0.0)
|
||||
|
||||
'@vgpu/adapter-mock@0.5.0(@vgpu/adapter-node@0.5.0)':
|
||||
dependencies:
|
||||
'@vgpu/core': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
transitivePeerDependencies:
|
||||
- '@vgpu/adapter-node'
|
||||
|
||||
'@vgpu/adapter-node@0.5.0':
|
||||
dependencies:
|
||||
'@vgpu/core': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
webgpu: 0.4.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vgpu/core@0.5.0(@vgpu/adapter-node@0.5.0)':
|
||||
dependencies:
|
||||
'@vgpu/wgsl': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
transitivePeerDependencies:
|
||||
- '@vgpu/adapter-node'
|
||||
|
||||
'@vgpu/wgsl-std@0.5.0': {}
|
||||
|
||||
'@vgpu/wgsl@0.5.0(@vgpu/adapter-node@0.5.0)':
|
||||
dependencies:
|
||||
'@vgpu/wgsl-std': 0.5.0
|
||||
optionalDependencies:
|
||||
'@vgpu/adapter-node': 0.5.0
|
||||
|
||||
'@vitejs/plugin-vue-jsx@2.1.1(vite@6.3.5(@types/node@20.5.1)(jiti@1.21.7)(less@4.4.0)(sass-embedded@1.93.3)(sass@1.93.3)(sugarss@2.0.0)(tsx@4.20.3))(vue@3.5.18(typescript@4.9.5))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.0
|
||||
@ -9090,6 +9315,8 @@ snapshots:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@webgpu/types@0.1.74': {}
|
||||
|
||||
'@wtto00/html2canvas@1.4.3':
|
||||
dependencies:
|
||||
css-line-break: 2.1.0
|
||||
@ -12931,6 +13158,10 @@ snapshots:
|
||||
|
||||
pinkie@2.0.4: {}
|
||||
|
||||
pixelmatch@7.2.0:
|
||||
dependencies:
|
||||
pngjs: 7.0.0
|
||||
|
||||
pkg-types@1.3.1:
|
||||
dependencies:
|
||||
confbox: 0.1.8
|
||||
@ -12945,6 +13176,8 @@ snapshots:
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
pngjs@7.0.0: {}
|
||||
|
||||
pngquant-bin@6.0.1:
|
||||
dependencies:
|
||||
bin-build: 3.0.0
|
||||
@ -13129,6 +13362,13 @@ snapshots:
|
||||
dependencies:
|
||||
performance-now: 2.1.0
|
||||
|
||||
react-dom@19.3.1(react@19.3.1):
|
||||
dependencies:
|
||||
react: 19.3.1
|
||||
scheduler: 0.28.0
|
||||
|
||||
react@19.3.1: {}
|
||||
|
||||
read-pkg-up@1.0.1:
|
||||
dependencies:
|
||||
find-up: 1.1.2
|
||||
@ -13293,6 +13533,8 @@ snapshots:
|
||||
|
||||
require-main-filename@2.0.0: {}
|
||||
|
||||
reselect@5.3.0: {}
|
||||
|
||||
reserved-words@0.1.2: {}
|
||||
|
||||
resize-detector@0.3.0: {}
|
||||
@ -13535,6 +13777,8 @@ snapshots:
|
||||
sax@1.4.1:
|
||||
optional: true
|
||||
|
||||
scheduler@0.28.0: {}
|
||||
|
||||
screenfull@5.2.0: {}
|
||||
|
||||
scroll-into-view-if-needed@2.2.31:
|
||||
@ -14610,6 +14854,10 @@ snapshots:
|
||||
|
||||
url-to-options@1.0.1: {}
|
||||
|
||||
use-sync-external-store@1.7.0(react@19.3.1):
|
||||
dependencies:
|
||||
react: 19.3.1
|
||||
|
||||
use@3.1.1: {}
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
@ -14680,6 +14928,22 @@ snapshots:
|
||||
- typescript
|
||||
- utf-8-validate
|
||||
|
||||
vgpu@0.5.0:
|
||||
dependencies:
|
||||
'@modelcontextprotocol/server': 2.0.0
|
||||
'@vgpu/adapter-mock': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
'@vgpu/adapter-node': 0.5.0
|
||||
'@vgpu/core': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
'@vgpu/wgsl': 0.5.0(@vgpu/adapter-node@0.5.0)
|
||||
'@vgpu/wgsl-std': 0.5.0
|
||||
'@webgpu/types': 0.1.74
|
||||
pixelmatch: 7.2.0
|
||||
pngjs: 7.0.0
|
||||
wgpu-matrix: 3.4.2
|
||||
zod: 4.6.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite-plugin-compression@0.5.1(vite@6.3.5(@types/node@20.5.1)(jiti@1.21.7)(less@4.4.0)(sass-embedded@1.93.3)(sass@1.93.3)(sugarss@2.0.0)(tsx@4.20.3)):
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
@ -14893,10 +15157,19 @@ snapshots:
|
||||
|
||||
w3c-keyname@2.2.8: {}
|
||||
|
||||
webgpu@0.4.0:
|
||||
dependencies:
|
||||
'@webgpu/types': 0.1.74
|
||||
debug: 4.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
webpack-virtual-modules@0.6.2: {}
|
||||
|
||||
wgpu-matrix@3.4.2: {}
|
||||
|
||||
whatwg-url@5.0.0:
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
@ -15076,6 +15349,8 @@ snapshots:
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
zod@4.6.7: {}
|
||||
|
||||
zrender@5.6.1:
|
||||
dependencies:
|
||||
tslib: 2.3.0
|
||||
|
||||
@ -4451,6 +4451,33 @@ export default {
|
||||
'system.batchEmail.logSendFail': 'failed - {msg}',
|
||||
'system.batchEmail.logSendDone': 'Done: {total} total, {successCount} ok, {failCount} failed',
|
||||
'system.batchEmail.msgSendDone': 'Done: {successCount} succeeded, {failCount} failed',
|
||||
'system.batchEmail.accountReady': 'Mailbox ready · {account}',
|
||||
'system.batchEmail.accountNotReady': 'Mailbox not configured — set it up before sending',
|
||||
'system.batchEmail.templateEdit': 'Edit template',
|
||||
'system.batchEmail.placeholderInsertHint': 'Click to insert a placeholder at the subject/body cursor',
|
||||
'system.batchEmail.sendProgressTitle': 'Batch send progress',
|
||||
'system.batchEmail.sendProgressMeta': '{current}/{total} processed · {success} ok · {fail} failed',
|
||||
'system.batchEmail.sendProgressCurrent': 'Current: {email}',
|
||||
'system.batchEmail.sendConfirmTitle': 'Confirm batch send',
|
||||
'system.batchEmail.sendConfirmOk': 'Send now',
|
||||
'system.batchEmail.sendConfirmAccount': 'From',
|
||||
'system.batchEmail.sendConfirmCount': 'Recipients',
|
||||
'system.batchEmail.sendConfirmHint': 'Messages are sent one by one with the current template. You can cancel remaining sends; already sent emails cannot be recalled.',
|
||||
'system.batchEmail.cancelSend': 'Cancel remaining',
|
||||
'system.batchEmail.sendFailList': 'Failures ({n})',
|
||||
'system.batchEmail.copyFailList': 'Copy list',
|
||||
'system.batchEmail.msgCopyFailOk': 'Failure list copied',
|
||||
'system.batchEmail.errCopyFail': 'Copy failed — select the text manually',
|
||||
'system.batchEmail.failInvalidEmail': 'Invalid email',
|
||||
'system.batchEmail.failEmptyBody': 'Empty body',
|
||||
'system.batchEmail.msgSendCancelled': 'Cancelled: {successCount} ok, {failCount} failed',
|
||||
'system.batchEmail.replacePreview': 'Placeholder preview',
|
||||
'system.batchEmail.replacePreviewEmpty': 'Add recipients to preview placeholder replacement',
|
||||
'system.batchEmail.replacePreviewManual': 'Based on {email} (manual emails leave order/track placeholders empty)',
|
||||
'system.batchEmail.replacePreviewSample': 'Preview using first recipient {email}',
|
||||
'system.batchEmail.confirmSwitchTplTitle': 'Switch template?',
|
||||
'system.batchEmail.confirmSwitchTplBody': 'Subject/body were edited. Switching will discard unsaved changes.',
|
||||
'system.batchEmail.removeRecipient': 'Remove this email',
|
||||
|
||||
// System - Announcement
|
||||
'system.announcement.search.placeholder': 'Search title or content',
|
||||
|
||||
@ -4475,6 +4475,33 @@ export default {
|
||||
'system.batchEmail.logSendFail': '收件人, 发送失败 - {msg}',
|
||||
'system.batchEmail.logSendDone': '结束发送: 共发送{total}封邮箱, 成功{successCount}, 失败{failCount}',
|
||||
'system.batchEmail.msgSendDone': '发送完成:成功 {successCount},失败 {failCount}',
|
||||
'system.batchEmail.accountReady': '邮箱已配置 · {account}',
|
||||
'system.batchEmail.accountNotReady': '邮箱未配置,发送前请先完成设置',
|
||||
'system.batchEmail.templateEdit': '模板编辑',
|
||||
'system.batchEmail.placeholderInsertHint': '点击插入占位符(插入到主题或正文光标处)',
|
||||
'system.batchEmail.sendProgressTitle': '批量发送进度',
|
||||
'system.batchEmail.sendProgressMeta': '已处理 {current}/{total} · 成功 {success} · 失败 {fail}',
|
||||
'system.batchEmail.sendProgressCurrent': '当前:{email}',
|
||||
'system.batchEmail.sendConfirmTitle': '确认批量发送',
|
||||
'system.batchEmail.sendConfirmOk': '确认发送',
|
||||
'system.batchEmail.sendConfirmAccount': '发件账号',
|
||||
'system.batchEmail.sendConfirmCount': '收件人数',
|
||||
'system.batchEmail.sendConfirmHint': '将按当前模板逐一发送,发送过程可取消;已发出的邮件无法撤回。',
|
||||
'system.batchEmail.cancelSend': '取消剩余',
|
||||
'system.batchEmail.sendFailList': '失败明细({n})',
|
||||
'system.batchEmail.copyFailList': '复制明细',
|
||||
'system.batchEmail.msgCopyFailOk': '失败明细已复制',
|
||||
'system.batchEmail.errCopyFail': '复制失败,请手动选择文本',
|
||||
'system.batchEmail.failInvalidEmail': '邮箱无效',
|
||||
'system.batchEmail.failEmptyBody': '正文为空',
|
||||
'system.batchEmail.msgSendCancelled': '已取消:成功 {successCount},失败 {failCount}',
|
||||
'system.batchEmail.replacePreview': '替换预览',
|
||||
'system.batchEmail.replacePreviewEmpty': '添加收件人后,可预览占位符替换效果',
|
||||
'system.batchEmail.replacePreviewManual': '基于 {email}(手动邮箱无单号/轨迹时,对应占位符会为空)',
|
||||
'system.batchEmail.replacePreviewSample': '基于首个收件人 {email} 的替换效果',
|
||||
'system.batchEmail.confirmSwitchTplTitle': '切换模板?',
|
||||
'system.batchEmail.confirmSwitchTplBody': '当前主题/正文已修改,切换将覆盖未保存的内容。',
|
||||
'system.batchEmail.removeRecipient': '移除该邮箱',
|
||||
|
||||
// 系统 - 公告通知
|
||||
'system.announcement.search.placeholder': '搜索标题或正文',
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
IconCopy,
|
||||
IconSettings,
|
||||
} from '@arco-design/web-vue/es/icon';
|
||||
import SlidingTabs from '@/components/SlidingTabs/index.vue';
|
||||
import ExcelFileIcon from '@/components/icons/ExcelFileIcon.vue';
|
||||
import SlidingTabs from '@/components/SlidingTabs/index.vue';
|
||||
import CustomTemplateModal from './components/CustomTemplateModal.vue';
|
||||
import SelectDeclarationSkuModal from './components/SelectDeclarationSkuModal.vue';
|
||||
import SelectDeclarationSkuModal from './components/SelectDeclarationSkuModal.vue';
|
||||
import FormLabelWithPreview from '@/views/channel/salesProducts/components/FormLabelWithPreview.vue';
|
||||
import CustomerGuideDrawer from '@/views/order/priceCheck/components/CustomerGuideDrawer.vue';
|
||||
import ExportCustoms9610GuideModal from './components/ExportCustoms9610GuideModal.vue';
|
||||
@ -5777,6 +5777,7 @@ import SelectDeclarationSkuModal from './components/SelectDeclarationSkuModal.vu
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@ -5787,6 +5788,22 @@ import SelectDeclarationSkuModal from './components/SelectDeclarationSkuModal.vu
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
:deep(.t-tab[aria-selected='true'] .t-tab__label) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #22c55e;
|
||||
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.place-order-pane {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
|
||||
@ -367,6 +367,9 @@ void main() {
|
||||
const w = Math.max(1, Math.floor(rect.width * scale));
|
||||
const h = Math.max(1, Math.floor(rect.height * scale));
|
||||
renderer.setSize(w, h);
|
||||
// OGL setSize writes pixel style width/height; keep CSS 100% so parent resize always fills.
|
||||
canvas.style.width = '100%';
|
||||
canvas.style.height = '100%';
|
||||
const res = mu.iResolution.value;
|
||||
res[0] = gl.drawingBufferWidth;
|
||||
res[1] = gl.drawingBufferHeight;
|
||||
|
||||
@ -1,33 +1,8 @@
|
||||
<template>
|
||||
<div id="ai-advisor-shell" :class="{ 'ai-history-open': historyOpen }">
|
||||
<div class="ai-shell-bg" aria-hidden="true">
|
||||
<GradientWaves
|
||||
class="ai-shell-bg__waves"
|
||||
horizon-color="#023e8a"
|
||||
wave-color="#0077b6"
|
||||
crest-color="#caf0f8"
|
||||
:speed="0.34"
|
||||
:amplitude="3.3"
|
||||
:wave-scale="0.72"
|
||||
:wave-ratio="0.82"
|
||||
:swell="42"
|
||||
:turbulence="26"
|
||||
:tilt="1.08"
|
||||
:zoom="0.92"
|
||||
:height="4.8"
|
||||
:fog-depth="22"
|
||||
detail="low"
|
||||
:brightness="1.08"
|
||||
:opacity="1.0"
|
||||
:mouse-interaction="true"
|
||||
:parallax-strength="0.4"
|
||||
:grain="false"
|
||||
:fps="30"
|
||||
:render-scale="0.72"
|
||||
:max-dpr="1.25"
|
||||
/>
|
||||
<div class="ai-shell-bg__veil" aria-hidden="true"></div>
|
||||
</div>
|
||||
<div
|
||||
id="ai-advisor-shell"
|
||||
:class="{ 'ai-history-open': historyOpen }"
|
||||
>
|
||||
<div class="ai-advisor-layout">
|
||||
<div class="ai-advisor-app">
|
||||
<div v-if="chatting" class="ai-stage-tools">
|
||||
@ -57,7 +32,7 @@
|
||||
<div class="ai-welcome__intro">
|
||||
<h2 class="ai-welcome-title" :aria-label="shortTitle ? copy.titleShort : copy.title">
|
||||
<span class="ai-welcome-title__brand" aria-hidden="true">
|
||||
IDE<span class="ai-welcome-title__dot">.</span>
|
||||
IDE<span class="ai-welcome-title__dot"> · </span>
|
||||
</span>
|
||||
<TextType
|
||||
v-if="titleAnimate"
|
||||
@ -128,7 +103,11 @@
|
||||
v-for="door in primaryDoors"
|
||||
:key="door.id"
|
||||
type="button"
|
||||
class="ai-intent-door is-primary"
|
||||
class="ai-intent-door is-primary lg-surface"
|
||||
:class="{
|
||||
'is-glass-ready': glassReady,
|
||||
'is-glass-fallback': glassFallback,
|
||||
}"
|
||||
:disabled="busy"
|
||||
@click="onHomeDoor(door)"
|
||||
>
|
||||
@ -149,25 +128,25 @@
|
||||
v-for="door in growthDoors"
|
||||
:key="door.id"
|
||||
type="button"
|
||||
class="ai-intent-door"
|
||||
class="ai-intent-door lg-surface"
|
||||
:class="{
|
||||
'is-agent-tall': door.id === 'agent',
|
||||
'is-growth-wide': door.id === 'newcomer',
|
||||
'is-glass-ready': glassReady,
|
||||
'is-glass-fallback': glassFallback,
|
||||
}"
|
||||
:disabled="busy"
|
||||
@click="onHomeDoor(door)"
|
||||
>
|
||||
<span class="ai-intent-door__head">
|
||||
<span class="ai-intent-door__icon">
|
||||
<SiteIllusIcon :name="door.icon" />
|
||||
</span>
|
||||
<span class="ai-intent-door__copy">
|
||||
<span class="ai-intent-door__title">{{
|
||||
isZh ? door.zh.title : door.en.title
|
||||
}}</span>
|
||||
</span>
|
||||
<span class="ai-intent-door__hint">{{
|
||||
isZh ? door.zh.hint : door.en.hint
|
||||
}}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -287,7 +266,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import SiteComposer from './SiteComposer.vue';
|
||||
import SitePartnerMarquee from './SitePartnerMarquee.vue';
|
||||
import SiteMessageCard from './SiteMessageCard.vue';
|
||||
@ -295,8 +274,7 @@
|
||||
import TextType from './TextType.vue';
|
||||
import { HOME_DOORS, HERO_STATS, SITE_FOLLOWUP_INTENTS, WELCOME_COPY } from './lib/site-welcome';
|
||||
import { ROUTE_DEST_PRESETS } from './lib/portal-catalog';
|
||||
|
||||
const GradientWaves = defineAsyncComponent(() => import('./GradientWaves.vue'));
|
||||
import { SITE_GLASS_PANEL_OPTS, useSiteLiquidGlass } from './lib/site-liquid-glass';
|
||||
|
||||
export type SiteChatMessage = {
|
||||
role: 'user' | 'assistant';
|
||||
@ -342,11 +320,35 @@
|
||||
choice: [payload: { id: string; label: string; flowId: string }];
|
||||
}>();
|
||||
|
||||
const siteGlass = useSiteLiquidGlass();
|
||||
const glassReady = computed(() => !!siteGlass?.ready.value);
|
||||
const glassFallback = computed(() => !!siteGlass?.fallback.value);
|
||||
let removeGlassSurfaces: Array<() => void> = [];
|
||||
|
||||
function teardownLiquidGlass() {
|
||||
removeGlassSurfaces.forEach((remove) => remove());
|
||||
removeGlassSurfaces = [];
|
||||
}
|
||||
|
||||
async function setupLiquidGlass() {
|
||||
await nextTick();
|
||||
if (!siteGlass || props.chatting) return;
|
||||
teardownLiquidGlass();
|
||||
const doorSurfaces = Array.from(
|
||||
document.querySelectorAll<HTMLElement>(
|
||||
'#ai-advisor-shell .ai-welcome__command .ai-intent-door.lg-surface',
|
||||
),
|
||||
);
|
||||
removeGlassSurfaces = doorSurfaces.map((el) =>
|
||||
siteGlass.registerSurface(el, SITE_GLASS_PANEL_OPTS),
|
||||
);
|
||||
}
|
||||
|
||||
const copy = computed(() => (props.isZh ? WELCOME_COPY.zh : WELCOME_COPY.en));
|
||||
const homeDests = ROUTE_DEST_PRESETS.filter((item) => item.id !== 'all');
|
||||
const primaryDoors = HOME_DOORS.filter((d) => d.primary);
|
||||
const growthDoors = HOME_DOORS.filter((d) => !d.primary);
|
||||
// 首屏即按视口决定短标题,避免挂载后再切导致 TextType 卡住只剩「IDE.」
|
||||
// 首屏即按视口决定短标题,避免挂载后再切导致 TextType 卡住只剩品牌前缀
|
||||
const shortTitle = ref(
|
||||
typeof window !== 'undefined' && window.matchMedia('(max-width: 640px)').matches,
|
||||
);
|
||||
@ -397,16 +399,30 @@
|
||||
titleAnimate.value = !mqReduce?.matches;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.chatting,
|
||||
async (chatting) => {
|
||||
if (chatting) {
|
||||
teardownLiquidGlass();
|
||||
return;
|
||||
}
|
||||
await nextTick();
|
||||
void setupLiquidGlass();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
mqNarrow = window.matchMedia('(max-width: 640px)');
|
||||
mqReduce = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
syncMediaPrefs();
|
||||
mqNarrow.addEventListener('change', syncMediaPrefs);
|
||||
mqReduce.addEventListener('change', syncMediaPrefs);
|
||||
void setupLiquidGlass();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
mqNarrow?.removeEventListener('change', syncMediaPrefs);
|
||||
mqReduce?.removeEventListener('change', syncMediaPrefs);
|
||||
teardownLiquidGlass();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -29,12 +29,7 @@
|
||||
<ul>
|
||||
<li ref="dockRef" class="site-nav-dock">
|
||||
<span class="site-nav-dock__glass" aria-hidden="true"></span>
|
||||
<span
|
||||
class="site-nav-dock__slider"
|
||||
:class="{ 'is-ready': sliderReady }"
|
||||
:style="sliderStyle"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<span ref="sliderRef" class="site-nav-dock__slider" aria-hidden="true"></span>
|
||||
<a
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
@ -210,61 +205,61 @@
|
||||
];
|
||||
|
||||
const dockRef = ref<HTMLElement | null>(null);
|
||||
const sliderReady = ref(false);
|
||||
const sliderStyle = ref<Record<string, string>>({
|
||||
left: '0px',
|
||||
width: '0px',
|
||||
opacity: '0',
|
||||
});
|
||||
const sliderPos = { x: 0, w: 0 };
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let sliderRaf = 0;
|
||||
|
||||
const sliderRef = ref<HTMLElement | null>(null);
|
||||
const SLIDER_INSET = 4;
|
||||
const sliderPos = { x: 0, w: 0, visible: false };
|
||||
let sliderReady = false;
|
||||
let sliderRaf = 0;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let mqNarrow: MediaQueryList | null = null;
|
||||
let mqReduce: MediaQueryList | null = null;
|
||||
|
||||
function paintSlider(x: number, w: number, visible: boolean, animate: boolean) {
|
||||
const el = sliderRef.value;
|
||||
if (!el) return;
|
||||
|
||||
const reduce = !!mqReduce?.matches;
|
||||
const canAnimate = animate && sliderReady && sliderPos.visible && !reduce && sliderPos.w > 0;
|
||||
el.style.transition = canAnimate
|
||||
? 'transform 0.28s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.18s ease'
|
||||
: 'none';
|
||||
el.style.width = `${w}px`;
|
||||
el.style.transform = `translate3d(${x}px, 0, 0)`;
|
||||
el.style.opacity = visible ? '1' : '0';
|
||||
|
||||
function applySlider(x: number, w: number, opacity = '1') {
|
||||
sliderPos.x = x;
|
||||
sliderPos.w = w;
|
||||
sliderStyle.value = {
|
||||
left: `${x}px`,
|
||||
width: `${w}px`,
|
||||
opacity,
|
||||
};
|
||||
sliderPos.visible = visible;
|
||||
|
||||
if (!sliderReady && visible) {
|
||||
requestAnimationFrame(() => {
|
||||
sliderReady = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateSlider(animate: boolean) {
|
||||
const dock = dockRef.value;
|
||||
const active = dock?.querySelector<HTMLElement>('.site-nav-dock__item.is-active');
|
||||
if (!dock || !active || window.matchMedia('(max-width: 1279px)').matches) {
|
||||
sliderStyle.value = { ...sliderStyle.value, opacity: '0' };
|
||||
if (!dock || !active || mqNarrow?.matches) {
|
||||
paintSlider(sliderPos.x, sliderPos.w, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const x = active.offsetLeft + SLIDER_INSET;
|
||||
const w = Math.max(active.offsetWidth - SLIDER_INSET * 2, 0);
|
||||
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// 首帧或关动画:先贴到位再开 transition,避免初次跳动
|
||||
if (!animate || !sliderReady.value || sliderPos.w <= 0 || reduceMotion) {
|
||||
sliderReady.value = false;
|
||||
applySlider(x, w);
|
||||
requestAnimationFrame(() => {
|
||||
sliderReady.value = true;
|
||||
});
|
||||
if (
|
||||
animate &&
|
||||
Math.abs(sliderPos.x - x) < 0.5 &&
|
||||
Math.abs(sliderPos.w - w) < 0.5 &&
|
||||
sliderPos.visible
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(sliderPos.x - x) < 0.5 && Math.abs(sliderPos.w - w) < 0.5) {
|
||||
applySlider(x, w);
|
||||
return;
|
||||
paintSlider(x, w, true, animate);
|
||||
}
|
||||
|
||||
// 单段滑移:left/width 一次到位,交给 CSS 缓动
|
||||
applySlider(x, w);
|
||||
}
|
||||
|
||||
async function syncSlider(animate: boolean) {
|
||||
await nextTick();
|
||||
function syncSlider(animate: boolean) {
|
||||
if (sliderRaf) cancelAnimationFrame(sliderRaf);
|
||||
sliderRaf = requestAnimationFrame(() => {
|
||||
sliderRaf = 0;
|
||||
@ -273,17 +268,20 @@
|
||||
}
|
||||
|
||||
function onViewportResize() {
|
||||
updateSlider(false);
|
||||
sliderReady = false;
|
||||
syncSlider(false);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void hydrateSession();
|
||||
void syncSlider(false);
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
mqNarrow = window.matchMedia('(max-width: 1279px)');
|
||||
mqReduce = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
void nextTick(() => syncSlider(false));
|
||||
if (typeof ResizeObserver !== 'undefined' && dockRef.value) {
|
||||
resizeObserver = new ResizeObserver(onViewportResize);
|
||||
if (dockRef.value) resizeObserver.observe(dockRef.value);
|
||||
resizeObserver.observe(dockRef.value);
|
||||
}
|
||||
window.addEventListener('resize', onViewportResize);
|
||||
window.addEventListener('resize', onViewportResize, { passive: true });
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -301,8 +299,9 @@
|
||||
|
||||
watch(
|
||||
() => [props.nav, props.isZh] as const,
|
||||
() => {
|
||||
void syncSlider(true);
|
||||
async () => {
|
||||
await nextTick();
|
||||
syncSlider(true);
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -1,13 +1,55 @@
|
||||
<template>
|
||||
<div
|
||||
class="official-site"
|
||||
ref="glassSceneEl"
|
||||
class="official-site lg-scene"
|
||||
:class="{
|
||||
'is-routes-open': panel === 'routes',
|
||||
'is-services-open': panel === 'services',
|
||||
'is-topic-open': panel === 'pricing' || panel === 'about' || panel === 'contact',
|
||||
'is-glass-ready': glass.ready.value,
|
||||
'is-glass-fallback': glass.fallback.value,
|
||||
}"
|
||||
@click.capture="onOfficialLoginCapture"
|
||||
>
|
||||
<!--
|
||||
lg-content 会被 liquid-glass 在 resize 时改写 left/right/宽高;
|
||||
波浪放在固定视口 __paint 层,避免缩窗后右侧留白。
|
||||
-->
|
||||
<div
|
||||
ref="glassContentEl"
|
||||
class="ai-shell-bg lg-content"
|
||||
data-layout="overlay"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="ai-shell-bg__paint">
|
||||
<GradientWaves
|
||||
class="ai-shell-bg__waves"
|
||||
horizon-color="#023e8a"
|
||||
wave-color="#0077b6"
|
||||
crest-color="#caf0f8"
|
||||
:speed="0.34"
|
||||
:amplitude="3.3"
|
||||
:wave-scale="0.72"
|
||||
:wave-ratio="0.82"
|
||||
:swell="42"
|
||||
:turbulence="26"
|
||||
:tilt="1.08"
|
||||
:zoom="0.92"
|
||||
:height="4.8"
|
||||
:fog-depth="22"
|
||||
detail="low"
|
||||
:brightness="1.08"
|
||||
:opacity="1.0"
|
||||
:mouse-interaction="true"
|
||||
:parallax-strength="0.4"
|
||||
:grain="false"
|
||||
:fps="30"
|
||||
:render-scale="0.72"
|
||||
:max-dpr="1.25"
|
||||
/>
|
||||
<div class="ai-shell-bg__veil" aria-hidden="true"></div>
|
||||
</div>
|
||||
</div>
|
||||
<SiteHeader
|
||||
:nav="nav"
|
||||
:is-zh="isZh"
|
||||
@ -91,7 +133,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import SiteHeader from './SiteHeader.vue';
|
||||
import SiteAdvisorShell from './SiteAdvisorShell.vue';
|
||||
@ -105,12 +147,18 @@
|
||||
warmupOfficialLogin,
|
||||
} from './lib/site-urls';
|
||||
import { shouldOpenWecomDirect, WECOM_KF_URL } from './lib/site-wecom';
|
||||
import { provideSiteLiquidGlass } from './lib/site-liquid-glass';
|
||||
import { useSiteAdvisor } from './useSiteAdvisor';
|
||||
import './styles/vendor.css';
|
||||
import './styles/icons.css';
|
||||
import './styles/main.css';
|
||||
import './styles/ai-advisor.css';
|
||||
|
||||
const GradientWaves = defineAsyncComponent(() => import('./GradientWaves.vue'));
|
||||
const glass = provideSiteLiquidGlass();
|
||||
const glassSceneEl = ref<HTMLElement | null>(null);
|
||||
const glassContentEl = ref<HTMLElement | null>(null);
|
||||
|
||||
type PanelId = 'routes' | 'services' | 'pricing' | 'about' | 'contact' | null;
|
||||
const NAV_PANELS: PanelId[] = ['routes', 'services', 'pricing', 'about', 'contact'];
|
||||
|
||||
@ -378,9 +426,15 @@
|
||||
if (hash === '9610' || hash === 'services') openPanel('services');
|
||||
else if (NAV_PANELS.includes(hash as PanelId)) openPanel(hash as Exclude<PanelId, null>);
|
||||
else if (hash) nav.value = hash;
|
||||
void nextTick(() => {
|
||||
if (glassSceneEl.value && glassContentEl.value) {
|
||||
glass.init(glassSceneEl.value, glassContentEl.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
glass.dispose();
|
||||
window.removeEventListener('keydown', onKeydown);
|
||||
window.removeEventListener('resize', syncHeaderOffset);
|
||||
window.removeEventListener('resize', syncVisualViewport);
|
||||
@ -395,7 +449,9 @@
|
||||
|
||||
<style scoped>
|
||||
.official-site {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
isolation: isolate;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -419,7 +475,7 @@
|
||||
|
||||
.site-fade-enter-active,
|
||||
.site-fade-leave-active {
|
||||
transition: opacity 0.32s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: opacity 0.22s ease;
|
||||
}
|
||||
|
||||
.site-fade-enter-from,
|
||||
@ -430,9 +486,8 @@
|
||||
.site-sheet-enter-active,
|
||||
.site-sheet-leave-active {
|
||||
transition:
|
||||
opacity 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
filter 0.34s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
opacity 0.24s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.site-sheet-leave-active {
|
||||
@ -441,25 +496,21 @@
|
||||
|
||||
.site-sheet-enter-from {
|
||||
opacity: 0;
|
||||
filter: blur(2px);
|
||||
transform: translateX(-50%) translateY(-10px);
|
||||
transform: translateX(-50%) translateY(-8px);
|
||||
}
|
||||
|
||||
.site-sheet-leave-to {
|
||||
opacity: 0;
|
||||
filter: blur(1px);
|
||||
transform: translateX(-50%) translateY(-6px);
|
||||
transform: translateX(-50%) translateY(-4px);
|
||||
}
|
||||
|
||||
@media (max-width: 780px) {
|
||||
.site-sheet-enter-from {
|
||||
filter: none;
|
||||
transform: translateY(16px);
|
||||
transform: translateY(12px);
|
||||
}
|
||||
|
||||
.site-sheet-leave-to {
|
||||
filter: none;
|
||||
transform: translateY(10px);
|
||||
transform: translateY(8px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
231
src/views/site/lib/site-liquid-glass.ts
Normal file
231
src/views/site/lib/site-liquid-glass.ts
Normal file
@ -0,0 +1,231 @@
|
||||
import { inject, provide, ref, type InjectionKey, type Ref } from 'vue';
|
||||
import {
|
||||
attachSelectionLens,
|
||||
createGlassScene,
|
||||
type GlassSceneController,
|
||||
type SurfaceOptions,
|
||||
} from '@glass-sdk/liquid-glass/dom';
|
||||
import '@glass-sdk/liquid-glass/styles.css';
|
||||
|
||||
export type SiteGlassSurfaceOpts = SurfaceOptions;
|
||||
|
||||
type QueuedJob =
|
||||
| { kind: 'surface'; el: HTMLElement; opts?: SiteGlassSurfaceOpts; setRemove: (fn: () => void) => void }
|
||||
| { kind: 'indicator'; el: HTMLElement; opts?: SiteGlassSurfaceOpts; setRemove: (fn: () => void) => void };
|
||||
|
||||
export type SiteLiquidGlassApi = {
|
||||
ready: Ref<boolean>;
|
||||
fallback: Ref<boolean>;
|
||||
init: (root: HTMLElement, content: HTMLElement) => void;
|
||||
registerSurface: (el: HTMLElement | null | undefined, opts?: SiteGlassSurfaceOpts) => () => void;
|
||||
registerTabIndicator: (el: HTMLElement | null | undefined, opts?: SiteGlassSurfaceOpts) => () => void;
|
||||
dispose: () => void;
|
||||
};
|
||||
|
||||
const SITE_LIQUID_GLASS_KEY: InjectionKey<SiteLiquidGlassApi> = Symbol('site-liquid-glass');
|
||||
|
||||
/** 履约 / 权益门卡:低折射 + 关闭 fluid,减轻矮卡左右竖边光学校弯 */
|
||||
export const SITE_GLASS_PANEL_OPTS: SiteGlassSurfaceOpts = {
|
||||
material: 'clear',
|
||||
appearance: 'light',
|
||||
radius: 12,
|
||||
refraction: 20,
|
||||
fluid: false,
|
||||
interactive: false,
|
||||
};
|
||||
|
||||
export const SITE_GLASS_TABS_OPTS: SiteGlassSurfaceOpts = {
|
||||
material: 'clear',
|
||||
appearance: 'light',
|
||||
radius: 'capsule',
|
||||
refraction: 56,
|
||||
interactive: true,
|
||||
};
|
||||
|
||||
export const SITE_GLASS_TAB_INDICATOR_OPTS: SiteGlassSurfaceOpts = {
|
||||
material: 'clear',
|
||||
appearance: 'light',
|
||||
radius: 'capsule',
|
||||
refraction: 40,
|
||||
interactive: false,
|
||||
};
|
||||
|
||||
/** Welcome input — frosted glass, no tint */
|
||||
export const SITE_GLASS_COMPOSER_OPTS: SiteGlassSurfaceOpts = {
|
||||
material: 'regular',
|
||||
appearance: 'light',
|
||||
radius: 12,
|
||||
refraction: 32,
|
||||
fluid: true,
|
||||
interactive: false,
|
||||
};
|
||||
|
||||
export function provideSiteLiquidGlass(): SiteLiquidGlassApi {
|
||||
const ready = ref(false);
|
||||
const fallback = ref(false);
|
||||
|
||||
let scene: GlassSceneController | null = null;
|
||||
let removers: Array<() => void> = [];
|
||||
let queue: QueuedJob[] = [];
|
||||
let readyObserver: MutationObserver | null = null;
|
||||
let fallbackTimer: number | null = null;
|
||||
const trackedSurfaces = new Set<HTMLElement>();
|
||||
|
||||
function clearFallbackTimer() {
|
||||
if (fallbackTimer != null) {
|
||||
window.clearTimeout(fallbackTimer);
|
||||
fallbackTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function isClipReady(el: HTMLElement) {
|
||||
return !!el.getAttribute('style')?.includes('clip-path');
|
||||
}
|
||||
|
||||
function syncReady() {
|
||||
if ([...trackedSurfaces].some(isClipReady)) {
|
||||
ready.value = true;
|
||||
fallback.value = false;
|
||||
clearFallbackTimer();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function observeSurface(el: HTMLElement) {
|
||||
trackedSurfaces.add(el);
|
||||
if (!readyObserver) {
|
||||
readyObserver = new MutationObserver(() => {
|
||||
syncReady();
|
||||
});
|
||||
}
|
||||
readyObserver.observe(el, { attributes: true, attributeFilter: ['style'] });
|
||||
}
|
||||
|
||||
function bindSurface(el: HTMLElement, opts?: SiteGlassSurfaceOpts) {
|
||||
if (!scene) return () => undefined;
|
||||
const remove = scene.addSurface(el, opts);
|
||||
observeSurface(el);
|
||||
syncReady();
|
||||
return () => {
|
||||
trackedSurfaces.delete(el);
|
||||
remove();
|
||||
};
|
||||
}
|
||||
|
||||
function bindIndicator(el: HTMLElement, opts?: SiteGlassSurfaceOpts) {
|
||||
if (!scene) return () => undefined;
|
||||
const removeSurface = bindSurface(el, opts ?? SITE_GLASS_TAB_INDICATOR_OPTS);
|
||||
const removeAnimator = scene.addAnimator(attachSelectionLens(el, () => 'full'));
|
||||
return () => {
|
||||
removeAnimator();
|
||||
removeSurface();
|
||||
};
|
||||
}
|
||||
|
||||
function enqueue(
|
||||
kind: 'surface' | 'indicator',
|
||||
el: HTMLElement,
|
||||
opts?: SiteGlassSurfaceOpts,
|
||||
) {
|
||||
let removeFn = () => undefined;
|
||||
let flushed = false;
|
||||
const job: QueuedJob = {
|
||||
kind,
|
||||
el,
|
||||
opts,
|
||||
setRemove: (fn) => {
|
||||
flushed = true;
|
||||
removeFn = fn;
|
||||
},
|
||||
};
|
||||
queue.push(job);
|
||||
return () => {
|
||||
if (!flushed) {
|
||||
queue = queue.filter((item) => item !== job);
|
||||
return;
|
||||
}
|
||||
removeFn();
|
||||
};
|
||||
}
|
||||
|
||||
function registerSurface(el: HTMLElement | null | undefined, opts?: SiteGlassSurfaceOpts) {
|
||||
if (!el) return () => undefined;
|
||||
if (scene) {
|
||||
const remove = bindSurface(el, opts);
|
||||
removers.push(remove);
|
||||
return remove;
|
||||
}
|
||||
return enqueue('surface', el, opts);
|
||||
}
|
||||
|
||||
function registerTabIndicator(el: HTMLElement | null | undefined, opts?: SiteGlassSurfaceOpts) {
|
||||
if (!el) return () => undefined;
|
||||
if (scene) {
|
||||
const remove = bindIndicator(el, opts);
|
||||
removers.push(remove);
|
||||
return remove;
|
||||
}
|
||||
return enqueue('indicator', el, opts);
|
||||
}
|
||||
|
||||
function init(root: HTMLElement, content: HTMLElement) {
|
||||
if (scene) return;
|
||||
|
||||
fallbackTimer = window.setTimeout(() => {
|
||||
if (!ready.value) fallback.value = true;
|
||||
}, 2200);
|
||||
|
||||
scene = createGlassScene(root, {
|
||||
maxSurfaces: 16,
|
||||
onDiagnostic: (diagnostic) => {
|
||||
if (diagnostic.error) {
|
||||
fallback.value = true;
|
||||
ready.value = false;
|
||||
} else if (diagnostic.maps > 0) {
|
||||
syncReady();
|
||||
}
|
||||
},
|
||||
});
|
||||
scene.setContent(content);
|
||||
|
||||
for (const job of queue) {
|
||||
const remove =
|
||||
job.kind === 'indicator' ? bindIndicator(job.el, job.opts) : bindSurface(job.el, job.opts);
|
||||
job.setRemove(remove);
|
||||
removers.push(remove);
|
||||
}
|
||||
queue = [];
|
||||
syncReady();
|
||||
}
|
||||
|
||||
function dispose() {
|
||||
clearFallbackTimer();
|
||||
readyObserver?.disconnect();
|
||||
readyObserver = null;
|
||||
removers.forEach((remove) => remove());
|
||||
removers = [];
|
||||
queue = [];
|
||||
trackedSurfaces.clear();
|
||||
scene?.dispose();
|
||||
scene = null;
|
||||
ready.value = false;
|
||||
fallback.value = false;
|
||||
}
|
||||
|
||||
const api: SiteLiquidGlassApi = {
|
||||
ready,
|
||||
fallback,
|
||||
init,
|
||||
registerSurface,
|
||||
registerTabIndicator,
|
||||
dispose,
|
||||
};
|
||||
|
||||
provide(SITE_LIQUID_GLASS_KEY, api);
|
||||
return api;
|
||||
}
|
||||
|
||||
export function useSiteLiquidGlass(): SiteLiquidGlassApi | null {
|
||||
return inject(SITE_LIQUID_GLASS_KEY, null);
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
export const WELCOME_COPY = {
|
||||
en: {
|
||||
title: 'IDE. Your cross-border logistics advisor',
|
||||
titleShort: 'IDE. Logistics advisor',
|
||||
titleRest: ' Your cross-border logistics advisor',
|
||||
titleRestShort: ' Logistics advisor',
|
||||
title: 'IDE · One-stop cross-border logistics advisor',
|
||||
titleShort: 'IDE · Logistics advisor',
|
||||
titleRest: 'One-stop cross-border logistics advisor',
|
||||
titleRestShort: 'Logistics advisor',
|
||||
placeholder: 'e.g. 5 kg general cargo to the US, how many days?',
|
||||
sendLabel: 'Ask',
|
||||
human: 'Talk to an advisor',
|
||||
@ -26,9 +26,9 @@ export const WELCOME_COPY = {
|
||||
fallback: 'Quotes are in the customer system after you register. You can also talk to an advisor.',
|
||||
},
|
||||
zh: {
|
||||
title: 'IDE.您身边的跨境物流顾问',
|
||||
titleShort: 'IDE.跨境物流顾问',
|
||||
titleRest: '您身边的跨境物流顾问',
|
||||
title: 'IDE · 一站式跨境物流顾问',
|
||||
titleShort: 'IDE · 跨境物流顾问',
|
||||
titleRest: '一站式跨境物流顾问',
|
||||
titleRestShort: '跨境物流顾问',
|
||||
placeholder: '例如:发美国普货,5kg,要几天',
|
||||
sendLabel: '提问',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user