dashboard design is fixed

This commit is contained in:
NishantRajputRN
2026-06-04 10:32:23 +05:30
parent 16a7fba7cf
commit 533e2cd561
5 changed files with 222 additions and 172 deletions
+36
View File
@@ -0,0 +1,36 @@
# name: Deploy GenBi App
# on:
# push:
# branches:
# - main
# jobs:
# deploy:
# runs-on: ubuntu-latest
# steps:
# - name: Checkout Code
# uses: actions/checkout@v3
# - name: Copy files to VPS
# uses: appleboy/scp-action@master
# with:
# host: 172.236.185.26
# username: root
# password: LinodeUser#26
# port: 22
# source: "./*"
# target: "/root/IR-Node-Setup"
# - name: Execute SSH Commands
# uses: appleboy/ssh-action@master
# with:
# host: 172.236.185.26
# username: root
# password: LinodeUser#26
# port: 22
# script: |
# cd /root/genbi-UI
# npm install
# npm run build
# sudo cp -r dist/* /var/www/react-app/
+32 -20
View File
@@ -160,7 +160,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
@@ -717,6 +716,29 @@
"@noble/ciphers": "^1.0.0" "@noble/ciphers": "^1.0.0"
} }
}, },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/wasi-threads": { "node_modules/@emnapi/wasi-threads": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
@@ -1195,7 +1217,6 @@
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz",
"integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": "^14.21.3 || >=16" "node": "^14.21.3 || >=16"
}, },
@@ -3205,7 +3226,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
@@ -3228,7 +3248,6 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
"integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.2.2" "csstype": "^3.2.2"
} }
@@ -3239,7 +3258,6 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
@@ -3323,7 +3341,6 @@
"integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==", "integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/scope-manager": "8.59.4",
"@typescript-eslint/types": "8.59.4", "@typescript-eslint/types": "8.59.4",
@@ -3607,7 +3624,6 @@
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -3992,7 +4008,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.10.12", "baseline-browser-mapping": "^2.10.12",
"caniuse-lite": "^1.0.30001782", "caniuse-lite": "^1.0.30001782",
@@ -5203,7 +5218,6 @@
"integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==", "integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.2", "@eslint-community/regexpp": "^4.12.2",
@@ -5622,7 +5636,8 @@
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz",
"integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==",
"license": "MIT" "license": "MIT",
"peer": true
}, },
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
@@ -6256,7 +6271,6 @@
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz",
"integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=16.9.0" "node": ">=16.9.0"
} }
@@ -8721,7 +8735,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.12", "nanoid": "^3.3.12",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@@ -9139,7 +9152,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz",
"integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -9149,7 +9161,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz",
"integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -10540,7 +10551,6 @@
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -10835,7 +10845,6 @@
"resolved": "https://registry.npmjs.org/vega/-/vega-6.2.0.tgz", "resolved": "https://registry.npmjs.org/vega/-/vega-6.2.0.tgz",
"integrity": "sha512-BIwalIcEGysJdQDjeVUmMWB3e50jPDNAMfLJscjEvpunU9bSt7X1OYnQxkg3uBwuRRI4nWfFZO9uIW910nLeGw==", "integrity": "sha512-BIwalIcEGysJdQDjeVUmMWB3e50jPDNAMfLJscjEvpunU9bSt7X1OYnQxkg3uBwuRRI4nWfFZO9uIW910nLeGw==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"vega-crossfilter": "~5.1.0", "vega-crossfilter": "~5.1.0",
"vega-dataflow": "~6.1.0", "vega-dataflow": "~6.1.0",
@@ -10902,6 +10911,7 @@
"resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-7.1.0.tgz", "resolved": "https://registry.npmjs.org/vega-embed/-/vega-embed-7.1.0.tgz",
"integrity": "sha512-ZmEIn5XJrQt7fSh2lwtSdXG/9uf3yIqZnvXFEwBJRppiBgrEWZcZbj6VK3xn8sNTFQ+sQDXW5sl/6kmbAW3s5A==", "integrity": "sha512-ZmEIn5XJrQt7fSh2lwtSdXG/9uf3yIqZnvXFEwBJRppiBgrEWZcZbj6VK3xn8sNTFQ+sQDXW5sl/6kmbAW3s5A==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"fast-json-patch": "^3.1.1", "fast-json-patch": "^3.1.1",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^4.0.0",
@@ -10925,6 +10935,7 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
"integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
"license": "ISC", "license": "ISC",
"peer": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
}, },
@@ -11036,6 +11047,7 @@
"resolved": "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-2.2.1.tgz", "resolved": "https://registry.npmjs.org/vega-interpreter/-/vega-interpreter-2.2.1.tgz",
"integrity": "sha512-o+4ZEme2mdFLewlpF76dwPWW2VkZ3TAF3DMcq75/NzA5KPvnN4wnlCM8At2FVawbaHRyGdVkJSS5ROF5KwpHPQ==", "integrity": "sha512-o+4ZEme2mdFLewlpF76dwPWW2VkZ3TAF3DMcq75/NzA5KPvnN4wnlCM8At2FVawbaHRyGdVkJSS5ROF5KwpHPQ==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"vega-util": "^2.1.0" "vega-util": "^2.1.0"
} }
@@ -11057,7 +11069,6 @@
"resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.3.tgz", "resolved": "https://registry.npmjs.org/vega-lite/-/vega-lite-6.4.3.tgz",
"integrity": "sha512-d/7hPjfz560UERaQuTmGgIVfXAe3g2hJWeC+igDeaGohUdEoNrHLXgR/yTOBT8vV/lIuuKnw+0/xWWblkDwkMQ==", "integrity": "sha512-d/7hPjfz560UERaQuTmGgIVfXAe3g2hJWeC+igDeaGohUdEoNrHLXgR/yTOBT8vV/lIuuKnw+0/xWWblkDwkMQ==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"json-stringify-pretty-compact": "~4.0.0", "json-stringify-pretty-compact": "~4.0.0",
"tslib": "~2.8.1", "tslib": "~2.8.1",
@@ -11172,7 +11183,8 @@
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz", "resolved": "https://registry.npmjs.org/vega-schema-url-parser/-/vega-schema-url-parser-3.0.2.tgz",
"integrity": "sha512-xAnR7KAvNPYewI3O0l5QGdT8Tv0+GCZQjqfP39cW/hbe/b3aYMAQ39vm8O2wfXUHzm04xTe7nolcsx8WQNVLRQ==", "integrity": "sha512-xAnR7KAvNPYewI3O0l5QGdT8Tv0+GCZQjqfP39cW/hbe/b3aYMAQ39vm8O2wfXUHzm04xTe7nolcsx8WQNVLRQ==",
"license": "BSD-3-Clause" "license": "BSD-3-Clause",
"peer": true
}, },
"node_modules/vega-selections": { "node_modules/vega-selections": {
"version": "6.1.2", "version": "6.1.2",
@@ -11199,6 +11211,7 @@
"resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-3.0.0.tgz", "resolved": "https://registry.npmjs.org/vega-themes/-/vega-themes-3.0.0.tgz",
"integrity": "sha512-1iFiI3BNmW9FrsLnDLx0ZKEddsCitRY3XmUAwp6qmp+p+IXyJYc9pfjlVj9E6KXBPfm4cQyU++s0smKNiWzO4g==", "integrity": "sha512-1iFiI3BNmW9FrsLnDLx0ZKEddsCitRY3XmUAwp6qmp+p+IXyJYc9pfjlVj9E6KXBPfm4cQyU++s0smKNiWzO4g==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"funding": { "funding": {
"url": "https://app.hubspot.com/payments/GyPC972GD9Rt" "url": "https://app.hubspot.com/payments/GyPC972GD9Rt"
}, },
@@ -11223,6 +11236,7 @@
"resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-1.0.0.tgz", "resolved": "https://registry.npmjs.org/vega-tooltip/-/vega-tooltip-1.0.0.tgz",
"integrity": "sha512-P1R0JP29v0qnTuwzCQ0SPJlkjAzr6qeyj+H4VgUFSykHmHc1OBxda//XBaFDl/bZgIscEMvjKSjZpXd84x3aZQ==", "integrity": "sha512-P1R0JP29v0qnTuwzCQ0SPJlkjAzr6qeyj+H4VgUFSykHmHc1OBxda//XBaFDl/bZgIscEMvjKSjZpXd84x3aZQ==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"peer": true,
"dependencies": { "dependencies": {
"vega-util": "^2.0.0" "vega-util": "^2.0.0"
}, },
@@ -11346,7 +11360,6 @@
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"picomatch": "^4.0.4", "picomatch": "^4.0.4",
@@ -11633,7 +11646,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"funding": { "funding": {
"url": "https://github.com/sponsors/colinhacks" "url": "https://github.com/sponsors/colinhacks"
} }
+1 -1
View File
@@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
const api = axios.create({ const api = axios.create({
baseURL: "http://172.237.44.156:3000", baseURL: "http://172.236.185.26:3000",
timeout: 120000, timeout: 120000,
}); });
+48 -40
View File
@@ -420,7 +420,7 @@ function VegaLiteArtifact({
const chartRef = const chartRef =
useRef<HTMLDivElement | null>(null); useRef<HTMLDivElement | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(false);
const [renderError, setRenderError] = useState(""); const [renderError, setRenderError] = useState("");
@@ -429,7 +429,7 @@ function VegaLiteArtifact({
const [activeTab, setActiveTab] = useState< const [activeTab, setActiveTab] = useState<
"answer" | "chart" | "sql" "answer" | "chart" | "sql"
>("chart"); >("answer");
const safeSpec = useMemo( const safeSpec = useMemo(
() => sanitizeSpec(spec), () => sanitizeSpec(spec),
@@ -444,7 +444,15 @@ function VegaLiteArtifact({
let result: Result | undefined; let result: Result | undefined;
const renderChart = async () => { const renderChart = async () => {
if (!chartRef.current) return; if (activeTab !== "chart") {
setLoading(false);
return;
}
if (!chartRef.current) {
setLoading(false);
return;
}
try { try {
setLoading(true); setLoading(true);
@@ -514,7 +522,7 @@ function VegaLiteArtifact({
return () => { return () => {
result?.view.finalize(); result?.view.finalize();
}; };
}, [safeSpec,activeTab]); }, [safeSpec, activeTab]);
/* ===================================================== /* =====================================================
GET VALUES GET VALUES
@@ -778,22 +786,22 @@ function VegaLiteArtifact({
===================================================== */ ===================================================== */
return ( return (
<div className="overflow-hidden rounded-[28px] border border-white/20 bg-white/80 shadow-[0_20px_100px_rgba(0,0,0,0.15)] backdrop-blur-xl"> <div className="w-full overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
{/* ====================================== {/* ======================================
HEADER HEADER
====================================== */} ====================================== */}
<div className="border-b bg-gradient-to-r from-slate-50 via-blue-50 to-indigo-50 px-6 py-5"> <div className="border-b border-slate-200 bg-slate-50 px-3 py-3 sm:px-5 sm:py-4">
<div className="flex flex-col gap-4"> <div className="flex min-w-0 flex-col gap-4">
{/* TOP TABS */} {/* TOP TABS */}
<div className="flex items-center gap-2"> <div className="flex min-w-0 flex-wrap items-center gap-2">
<button <button
onClick={() => setActiveTab("answer")} onClick={() => setActiveTab("answer")}
className={`flex items-center gap-2 rounded-xl px-4 py-2 text-sm font-medium transition ${ className={`flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-medium transition sm:px-4 ${
activeTab === "answer" activeTab === "answer"
? "bg-cyan-500 text-white" ? "bg-cyan-600 text-white"
: "bg-white border border-slate-200 text-black hover:bg-slate-50" : "bg-white border border-slate-200 text-black hover:bg-slate-50"
}`} }`}
> >
@@ -806,9 +814,9 @@ function VegaLiteArtifact({
<button <button
onClick={() => setActiveTab("chart")} onClick={() => setActiveTab("chart")}
className={`flex items-center gap-2 rounded-xl px-4 py-2 text-sm font-medium transition ${ className={`flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-medium transition sm:px-4 ${
activeTab === "chart" activeTab === "chart"
? "bg-cyan-500 text-white" ? "bg-cyan-600 text-white"
: "bg-white border border-slate-200 text-black hover:bg-slate-50" : "bg-white border border-slate-200 text-black hover:bg-slate-50"
}`} }`}
> >
@@ -821,9 +829,9 @@ function VegaLiteArtifact({
<button <button
onClick={() => setActiveTab("sql")} onClick={() => setActiveTab("sql")}
className={`flex items-center gap-2 rounded-xl px-4 py-2 text-sm font-medium transition ${ className={`flex h-10 items-center gap-2 rounded-xl px-3 text-sm font-medium transition sm:px-4 ${
activeTab === "sql" activeTab === "sql"
? "bg-cyan-500 text-white" ? "bg-cyan-600 text-white"
: "bg-white border border-slate-200 text-black hover:bg-slate-50" : "bg-white border border-slate-200 text-black hover:bg-slate-50"
}`} }`}
> >
@@ -879,20 +887,20 @@ function VegaLiteArtifact({
====================================== */} ====================================== */}
<div className="bg-gradient-to-br from-slate-50 via-white to-indigo-50 p-6"> <div className="bg-white p-3 sm:p-5">
<div className="rounded-3xl border border-slate-200 bg-white p-5 shadow-inner"> <div className="rounded-2xl border border-slate-200 bg-white p-3 sm:p-4">
<div className="relative min-h-[500px] w-full"> <div className="relative min-h-[360px] w-full sm:min-h-[460px]">
{/* LOADER */} {/* LOADER */}
{loading && ( {activeTab === "chart" && loading && (
<div className="absolute inset-0 z-20 flex items-center justify-center rounded-3xl bg-white/80 backdrop-blur-sm"> <div className="absolute inset-0 z-20 flex items-center justify-center rounded-2xl bg-white/80 backdrop-blur-sm">
<div className="space-y-5 text-center"> <div className="space-y-5 text-center">
<div className="mx-auto flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-r from-indigo-500 to-cyan-500 shadow-2xl"> <div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-r from-indigo-500 to-cyan-500 shadow-lg sm:h-20 sm:w-20">
<Sparkles className="h-10 w-10 animate-pulse text-white" /> <Sparkles className="h-8 w-8 animate-pulse text-white sm:h-10 sm:w-10" />
</div> </div>
<div> <div>
<h2 className="text-xl font-bold text-slate-700"> <h2 className="text-lg font-bold text-slate-700 sm:text-xl">
Generating Generating
Visualization Visualization
</h2> </h2>
@@ -921,32 +929,32 @@ function VegaLiteArtifact({
{activeTab === "chart" && ( {activeTab === "chart" && (
<div <div
ref={chartRef} ref={chartRef}
className="min-h-[500px] w-full max-w-none overflow-hidden rounded-2xl" className="min-h-[360px] w-full max-w-none overflow-auto rounded-xl sm:min-h-[460px]"
/> />
)} )}
{activeTab === "answer" && ( {activeTab === "answer" && (
<div className="space-y-6 p-6"> <div className="space-y-4 p-1 sm:p-3">
{/* Summary Cards */} {/* Summary Cards */}
<div className="grid gap-4 md:grid-cols-3"> <div className="grid gap-3 sm:grid-cols-3">
<div className="rounded-xl border bg-white p-6 shadow-sm"> <div className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
<p className="text-sm text-slate-500">Rows</p> <p className="text-sm text-slate-500">Rows</p>
<h2 className="mt-2 text-4xl font-bold"> <h2 className="mt-2 text-3xl font-bold text-slate-950">
{answer?.data?.length ?? answer?.totalRows ?? 0} {answer?.data?.length ?? answer?.totalRows ?? 0}
</h2> </h2>
</div> </div>
<div className="rounded-xl border bg-white p-6 shadow-sm"> <div className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
<p className="text-sm text-slate-500">Columns</p> <p className="text-sm text-slate-500">Columns</p>
<h2 className="mt-2 text-4xl font-bold"> <h2 className="mt-2 text-3xl font-bold text-slate-950">
{answer?.columns?.length ?? 0} {answer?.columns?.length ?? 0}
</h2> </h2>
</div> </div>
<div className="rounded-xl border bg-white p-6 shadow-sm"> <div className="rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
<p className="text-sm text-slate-500">Chart</p> <p className="text-sm text-slate-500">Chart</p>
<h2 className="mt-2 text-lg font-semibold"> <h2 className="mt-2 text-base font-semibold text-slate-950">
{spec ? "Available" : "Not Available"} {spec ? "Available" : "Not Available"}
</h2> </h2>
</div> </div>
@@ -956,14 +964,14 @@ function VegaLiteArtifact({
{/* Data Table */} {/* Data Table */}
{Array.isArray(answer?.data) && {Array.isArray(answer?.data) &&
answer.data.length > 0 && ( answer.data.length > 0 && (
<div className="overflow-auto rounded-xl border"> <div className="max-h-[460px] overflow-auto rounded-xl border border-slate-200">
<table className="w-full border-collapse"> <table className="min-w-full border-collapse text-sm">
<thead> <thead>
<tr className="bg-slate-100"> <tr className="bg-slate-100">
{Object.keys(answer.data[0]).map((key) => ( {Object.keys(answer.data[0]).map((key) => (
<th <th
key={key} key={key}
className="border px-4 py-3 text-left font-semibold" className="whitespace-nowrap border-b border-r border-slate-200 px-4 py-3 text-left font-semibold text-slate-800"
> >
{key} {key}
</th> </th>
@@ -985,7 +993,7 @@ function VegaLiteArtifact({
(value: any, idx: number) => ( (value: any, idx: number) => (
<td <td
key={idx} key={idx}
className="border px-4 py-3" className="whitespace-nowrap border-b border-r border-slate-200 px-4 py-3 text-slate-700"
> >
{String(value)} {String(value)}
</td> </td>
@@ -1003,12 +1011,12 @@ function VegaLiteArtifact({
)} )}
{activeTab === "sql" && ( {activeTab === "sql" && (
<div className="p-6"> <div className="p-1 sm:p-3">
<h3 className="mb-3 text-lg font-semibold"> <h3 className="mb-3 text-lg font-semibold">
SQL Query SQL Query
</h3> </h3>
<pre className="overflow-auto rounded-xl bg-slate-900 p-4 text-sm text-green-400"> <pre className="max-h-[460px] overflow-auto rounded-xl bg-slate-950 p-4 text-sm text-green-300">
{sql} {sql}
</pre> </pre>
</div> </div>
@@ -1076,8 +1084,8 @@ export default function ChartArtifact({
console.log("FINAL SPEC =>", finalSpec); console.log("FINAL SPEC =>", finalSpec);
return ( return (
<div className="w-full"> <div className="w-full min-w-0">
<Card className="overflow-hidden border border-white/20 bg-white/70 shadow-[0_20px_100px_rgba(0,0,0,0.15)] backdrop-blur-xl"> <Card className="overflow-hidden border-0 bg-transparent shadow-none">
<CardContent className="p-0"> <CardContent className="p-0">
{finalSpec ? ( {finalSpec ? (
<ErrorBoundary> <ErrorBoundary>
@@ -1088,7 +1096,7 @@ export default function ChartArtifact({
/> />
</ErrorBoundary> </ErrorBoundary>
) : ( ) : (
<div className="prose prose-sm max-w-none rounded-3xl bg-white p-8 shadow-inner"> <div className="prose prose-sm max-w-none overflow-auto rounded-2xl bg-white p-4 sm:p-6">
<ReactMarkdown> <ReactMarkdown>
{typeof content === {typeof content ===
"string" "string"
+104 -110
View File
@@ -6,7 +6,7 @@ import ChartArtifact from "@/components/ChartArtifact";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { AlertTriangle } from "lucide-react"; import { AlertTriangle, ChevronDown, LogOut, Menu } from "lucide-react";
type ChatMessage = { type ChatMessage = {
id: string; id: string;
@@ -239,21 +239,22 @@ export default function ChatCanvas() {
}; };
return ( return (
<main className="min-h-screen bg-gradient-to-br from-white via-slate-50 to-gray-100 pb-36"> <main className="min-h-screen bg-slate-50 pb-32 xl:pb-6">
{/* <header className="sticky top-0 z-10 border-b bg-background px-6 py-3"> */} {/* <header className="sticky top-0 z-10 border-b bg-background px-6 py-3"> */}
<header className="sticky top-0 z-50 border-b border-slate-200 bg-white px-6 py-3"> <header className="sticky top-0 z-50 border-b border-slate-200 bg-white/95 px-4 py-3 backdrop-blur sm:px-6">
<div className="flex items-center justify-between"> <div className="mx-auto flex max-w-[1520px] items-center justify-between">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<button <button
onClick={() => setShowHistory(!showHistory)} onClick={() => setShowHistory(!showHistory)}
className="rounded-lg border px-3 py-1.5 text-sm hover:bg-slate-100" className="inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-200 bg-white text-slate-700 shadow-sm transition hover:bg-slate-100"
aria-label="Toggle recent prompts"
> >
<Menu className="h-5 w-5" />
</button> </button>
<h1 className="text-xl font-semibold"> <h1 className="text-lg font-semibold sm:text-xl">
Yoda Yoda
</h1> </h1>
</div> </div>
@@ -262,93 +263,65 @@ export default function ChatCanvas() {
</header> </header>
{/* <section className="mx-auto flex flex-col gap-4 px-4 py-6 lg:flex-row"> */} {/* <section className="mx-auto flex flex-col gap-4 px-4 py-6 lg:flex-row"> */}
<section className="mx-auto flex gap-6 px-4 py-6"> <section
className={cn(
"mx-auto grid max-w-[1520px] grid-cols-1 gap-4 px-3 py-4 sm:px-4 sm:py-5 lg:gap-5 xl:gap-6",
showHistory
? "lg:grid-cols-[18rem_minmax(0,1fr)] xl:grid-cols-[18rem_minmax(0,1fr)_22rem]"
: "xl:grid-cols-[minmax(0,1fr)_22rem]",
)}
>
{showHistory && ( {showHistory && (
<>
// <aside <button
// className="hidden lg:flex lg:w-80 lg:flex-col lg:sticky lg:top-24 h-[calc(100vh-140px)] overflow-y-auto rounded-3xl border border-slate-200 bg-white/90 backdrop-blur-xl p-5 shadow-[0_10px_40px_rgba(0,0,0,0.08)]"> aria-label="Close recent prompts"
// <div className="mb-4"> className="fixed inset-0 z-40 bg-slate-950/20 backdrop-blur-[1px] lg:hidden"
// <p className="text-xs uppercase tracking-[0.25em] text-muted-foreground"> onClick={() => setShowHistory(false)}
// History type="button"
// </p> />
// <h2 className="mt-2 text-xl font-bold text-slate-900">
// Recent prompts
// </h2>
// <p className="mt-2 text-sm text-muted-foreground">
// Tap a prompt to reload it into the composer.
// </p>
// </div>
// <div className="space-y-2">
// {historyQuestions.length === 0 ? (
// <div className="rounded-3xl border border-border/80 bg-muted/70 p-4 text-sm text-muted-foreground">
// No recent prompts found.
// </div>
// ) : (
// historyQuestions.map((item, index) => (
// <button
// key={item.response_id}
// type="button"
// onClick={() => handleHistoryClick(item)}
// className="w-full rounded-2xl border border-slate-200 bg-white px-4 py-3 text-left text-sm transition-all duration-200 hover:-translate-y-1 hover:border-indigo-200 hover:bg-indigo-50/40 hover:shadow-lg"
// >
// <span className="block text-sm text-foreground">
// {item.prompt}
// </span>
// <p className="text-xs text-slate-500 mt-1">
// {new Date(item.created_at).toLocaleString()}
// </p>
// </button>
// ))
// )}
// </div>
// <div className="border-t p-4">
// <Button
// // variant="outline"
// onClick={logout}
// className="w-full"
// >
// Logout
// </Button>
// </div>
// </aside>
<aside <aside
className=" className="
hidden fixed
lg:flex bottom-3
lg:w-72 left-3
top-3
z-50
flex
w-[min(18rem,calc(100vw-1.5rem))]
flex-col
lg:bottom-auto
lg:left-auto
lg:z-auto
lg:w-auto
lg:flex-col lg:flex-col
lg:sticky lg:sticky
lg:top-20 lg:top-20
h-[calc(100vh-90px)] lg:h-[calc(100vh-96px)]
overflow-hidden overflow-hidden
rounded-3xl rounded-2xl
border border
border-slate-200 border-slate-200
bg-white/80 bg-white
backdrop-blur-xl backdrop-blur-xl
shadow-[0_8px_30px_rgba(0,0,0,0.06)] shadow-sm
" "
> >
{/* Header */} {/* Header */}
<div className="border-b border-slate-100 px-4 py-4"> <div className="border-b border-slate-100 px-4 py-3">
<p className="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400"> <p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">
Recents Recents
</p> </p>
</div> </div>
{/* History List */} {/* History List */}
<div className="flex-1 overflow-y-auto p-3"> <div className="min-h-0 flex-1 overflow-y-auto p-2">
{historyQuestions.length === 0 ? ( {historyQuestions.length === 0 ? (
<div className="rounded-xl bg-slate-50 p-4 text-sm text-slate-500"> <div className="rounded-xl bg-slate-50 p-4 text-sm text-slate-500">
No recent prompts found No recent prompts found
</div> </div>
) : ( ) : (
<div className="space-y-1"> <div className="space-y-0.5">
{historyQuestions.map((item) => ( {historyQuestions.map((item) => (
<button <button
key={item.response_id} key={item.response_id}
@@ -357,7 +330,7 @@ export default function ChatCanvas() {
w-full w-full
rounded-xl rounded-xl
px-3 px-3
py-3 py-2.5
text-left text-left
transition-all transition-all
duration-200 duration-200
@@ -365,11 +338,11 @@ export default function ChatCanvas() {
hover:text-indigo-700 hover:text-indigo-700
" "
> >
<div className="truncate text-sm font-medium"> <div className="truncate text-sm font-medium leading-5 text-slate-900">
{item.prompt} {item.prompt}
</div> </div>
<div className="mt-1 text-xs text-slate-400"> <div className="mt-0.5 text-xs leading-4 text-slate-400">
{new Date(item.created_at).toLocaleDateString()} {new Date(item.created_at).toLocaleDateString()}
</div> </div>
</button> </button>
@@ -379,7 +352,7 @@ export default function ChatCanvas() {
</div> </div>
{/* Profile Section */} {/* Profile Section */}
<div className="relative border-t border-slate-100 p-3 bg-gradient-to-r from-slate-50 to-white"> <div className="relative border-t border-slate-100 bg-slate-50 p-2.5">
<button <button
onClick={() => setShowProfileMenu(!showProfileMenu)} onClick={() => setShowProfileMenu(!showProfileMenu)}
className=" className="
@@ -391,28 +364,29 @@ export default function ChatCanvas() {
border border
border-slate-100 border-slate-100
bg-white bg-white
p-3 p-2.5
shadow-sm shadow-sm
transition-all transition-all
duration-200 duration-200
hover:border-indigo-200 hover:border-indigo-200
hover:bg-indigo-50/40 hover:bg-indigo-50/40
hover:shadow-md hover:shadow-md
" "
> >
{/* Avatar */} {/* Avatar */}
<div <div
className=" className="
flex flex
h-10 h-9
w-10 w-9
shrink-0
items-center items-center
justify-center justify-center
rounded-full rounded-full
bg-gradient-to-br bg-gradient-to-br
from-indigo-500 from-indigo-500
to-cyan-500 to-cyan-500
text-sm text-xs
font-semibold font-semibold
text-white text-white
" "
@@ -422,30 +396,20 @@ export default function ChatCanvas() {
{/* User Info */} {/* User Info */}
<div className="flex flex-1 flex-col text-left"> <div className="flex flex-1 flex-col text-left">
<span className="text-sm font-semibold text-slate-800"> <span className="text-sm font-semibold leading-5 text-slate-800">
Logged In Logged In
</span> </span>
<span className="text-xs text-slate-500"> <span className="truncate text-xs leading-4 text-slate-500">
Yoda Workspace Yoda Workspace
</span> </span>
</div> </div>
{/* Arrow */} {/* Arrow */}
<svg <ChevronDown
className={`h-4 w-4 text-slate-400 transition-transform ${showProfileMenu ? "rotate-180" : "" className={`h-4 w-4 text-slate-400 transition-transform ${showProfileMenu ? "rotate-180" : ""
}`} }`}
fill="none" />
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 9l-7 7-7-7"
/>
</svg>
</button> </button>
{/* Dropdown */} {/* Dropdown */}
@@ -468,7 +432,10 @@ export default function ChatCanvas() {
<button <button
onClick={logout} onClick={logout}
className=" className="
flex
w-full w-full
items-center
gap-2
px-4 px-4
py-3 py-3
text-left text-left
@@ -479,36 +446,38 @@ export default function ChatCanvas() {
hover:bg-red-50 hover:bg-red-50
" "
> >
<LogOut className="h-4 w-4" />
Logout Logout
</button> </button>
</div> </div>
)} )}
</div> </div>
</aside> </aside>
</>
)} )}
<div className="flex-1 min-w-0 flex flex-col gap-4"> <div className="min-w-0 flex flex-col gap-4">
{messages.length === 0 ? ( {messages.length === 0 ? (
<div className="flex min-h-[65vh] flex-col items-center justify-center text-center"> <div className="flex min-h-[56vh] flex-col items-center justify-center rounded-2xl border border-slate-200 bg-white px-4 py-10 text-center shadow-sm sm:px-8">
<h2 className="mb-3 text-4xl font-extrabold tracking-tight text-slate-900"> <h2 className="mb-3 text-3xl font-extrabold tracking-tight text-slate-900 sm:text-4xl">
Welcome to Yoda Welcome to Yoda
</h2> </h2>
<p className="mb-10 text-lg text-slate-500"> <p className="mb-8 max-w-xl text-base text-slate-500 sm:text-lg">
Ask questions about your business data Ask questions about your business data
</p> </p>
<div className="grid gap-3 md:grid-cols-2 max-w-2xl w-full"> <div className="grid w-full max-w-2xl gap-3 md:grid-cols-2">
{[ {[
"What was the total stock availability across different store types last month?", "What was the total stock availability across different store types last month?",
"what is the OSA percentage for the month of march 2026?", "what is the OSA percentage for the month of march 2026?",
"Which products had the highest OSA percentage in March 2026?", "what is the OSA percentage for the month of April 2026?",
].map((item) => ( ].map((item) => (
<button <button
key={item} key={item}
onClick={() => setInput(item)} onClick={() => setInput(item)}
className="rounded-2xl border border-slate-200 bg-white p-5 text-left shadow-sm transition-all duration-200 hover:-translate-y-1 hover:border-indigo-200 hover:bg-indigo-50/40 hover:shadow-xl" className="rounded-xl border border-slate-200 bg-white p-4 text-left text-sm shadow-sm transition-all duration-200 hover:border-indigo-200 hover:bg-indigo-50/40 hover:shadow-md sm:p-5"
> >
{item} {item}
</button> </button>
@@ -529,10 +498,10 @@ export default function ChatCanvas() {
<div <div
className={cn( className={cn(
"max-w-[900px] mx-auto", "mx-auto max-w-[920px]",
isUser isUser
? "rounded-3xl bg-gradient-to-r from-indigo-600 to-cyan-600 px-5 py-3 text-sm text-white shadow-lg" ? "max-w-[min(720px,85vw)] rounded-2xl bg-gradient-to-r from-indigo-600 to-cyan-600 px-4 py-3 text-sm text-white shadow-sm sm:px-5"
: "w-full min-w-0 rounded-3xl border border-slate-200 bg-white p-4 shadow-sm", : "w-full min-w-0 rounded-2xl border border-slate-200 bg-white p-2 shadow-sm sm:p-3",
)} )}
> >
{/* {isUser ? ( {/* {isUser ? (
@@ -598,7 +567,7 @@ export default function ChatCanvas() {
{isSending ? ( {isSending ? (
<article className="flex justify-start"> <article className="flex justify-start">
<div className="max-w-[760px] rounded-3xl border border-slate-200 bg-white px-5 py-4 shadow-lg"> <div className="max-w-[760px] rounded-2xl border border-slate-200 bg-white px-5 py-4 shadow-sm">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="flex items-center gap-2 rounded-full bg-background px-3 py-2 shadow-inner shadow-black/5"> <div className="flex items-center gap-2 rounded-full bg-background px-3 py-2 shadow-inner shadow-black/5">
<span className="typing-dot" /> <span className="typing-dot" />
@@ -685,11 +654,11 @@ export default function ChatCanvas() {
</aside> */} </aside> */}
{/* RIGHT PANEL */} {/* RIGHT PANEL */}
<aside className="hidden xl:block w-[380px] shrink-0"> <aside className="hidden min-w-0 xl:block">
<div className="fixed right-6 bottom-4 w-[380px] z-40 space-y-4"> <div className="sticky top-20 space-y-4">
{/* Quick Prompts */} {/* Quick Prompts */}
<div className="rounded-3xl border border-slate-200 bg-white p-6 shadow-[0_10px_40px_rgba(0,0,0,0.08)]"> <div className="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
<h4 className="mb-3 font-medium"> <h4 className="mb-3 font-medium">
Quick Prompts Quick Prompts
</h4> </h4>
@@ -698,12 +667,12 @@ export default function ChatCanvas() {
{[ {[
"What was the total stock availability across different store types last month?", "What was the total stock availability across different store types last month?",
"what is the OSA percentage for the month of march 2026?", "what is the OSA percentage for the month of march 2026?",
"Which products had the highest OSA percentage in March 2026?", "what is the OSA percentage for the month of April 2026?"
].map((item) => ( ].map((item) => (
<button <button
key={item} key={item}
onClick={() => setInput(item)} onClick={() => setInput(item)}
className="w-full rounded-lg border p-2 text-left text-sm transition hover:bg-slate-100" className="w-full rounded-xl border border-slate-200 p-3 text-left text-sm leading-snug transition hover:bg-slate-100"
> >
{item} {item}
</button> </button>
@@ -712,7 +681,7 @@ export default function ChatCanvas() {
</div> </div>
{/* Ask GenBI */} {/* Ask GenBI */}
<div className="rounded-3xl border border-slate-200 bg-white p-6 shadow-[0_10px_40px_rgba(0,0,0,0.08)]"> <div className="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm">
<h3 className="text-lg font-semibold"> <h3 className="text-lg font-semibold">
Ask Yoda Ask Yoda
</h3> </h3>
@@ -746,6 +715,31 @@ export default function ChatCanvas() {
</aside> </aside>
</section> </section>
<form
onSubmit={onSubmit}
className="fixed inset-x-0 bottom-0 z-40 border-t border-slate-200 bg-white/95 px-3 py-3 shadow-[0_-8px_30px_rgba(15,23,42,0.08)] backdrop-blur xl:hidden"
>
<div className="mx-auto flex max-w-3xl gap-2">
<Input
value={input}
disabled={isSending}
onChange={(e) => {
setInput(e.target.value);
setError("");
}}
placeholder="Type your question..."
className="h-11 min-w-0 rounded-xl"
/>
<Button
className="h-11 shrink-0 rounded-xl bg-gradient-to-r from-indigo-600 to-cyan-600 px-5 text-white hover:opacity-90"
type="submit"
disabled={isSending || !input.trim()}
>
{isSending ? "Sending..." : "Send"}
</Button>
</div>
</form>
{/* <form className="fixed inset-x-0 bottom-0 z-20 px-3 pb-4" onSubmit={onSubmit}> */} {/* <form className="fixed inset-x-0 bottom-0 z-20 px-3 pb-4" onSubmit={onSubmit}> */}