This is an automated email from the ASF dual-hosted git repository.
wangzx pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/echarts-theme-builder.git
The following commit(s) were added to refs/heads/master by this push:
new 18d2cc5 feat: simply support extracting theme colors from an image
new 0446847 Merge branch 'master' of
https://github.com/apache/echarts-theme-builder
18d2cc5 is described below
commit 18d2cc5bf47206ed4128bd1277bed60a3c2f6364
Author: plainheart <[email protected]>
AuthorDate: Tue Nov 11 02:01:56 2025 +0800
feat: simply support extracting theme colors from an image
---
.vscode/settings.json | 5 +-
package-lock.json | 819 +++++++++++++++++++++++++++++++++++
package.json | 2 +
src/components/ChartPreviewPanel.vue | 1 -
src/components/ThemePanel.vue | 105 ++++-
src/locales/en.json | 8 +-
src/locales/zh.json | 8 +-
src/stores/theme.ts | 3 -
8 files changed, 936 insertions(+), 15 deletions(-)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4e71344..d35cc5a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,6 @@
{
"i18n-ally.localesPaths": [
"src/locales"
- ]
-}
\ No newline at end of file
+ ],
+ "i18n-ally.keystyle": "nested"
+}
diff --git a/package-lock.json b/package-lock.json
index c69f70e..b7a4cfd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,12 +8,14 @@
"name": "echarts-theme-builder",
"version": "0.0.0",
"dependencies": {
+ "colorthief": "^2.6.0",
"vant": "^4.9.21",
"vue": "^3.5.24",
"vue-i18n": "^9.14.5",
"vue3-colorpicker": "^2.3.0"
},
"devDependencies": {
+ "@types/colorthief": "^2.6.0",
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.10.0",
"@vitejs/plugin-vue": "^6.0.1",
@@ -79,6 +81,23 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.7.0",
+ "resolved":
"https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.0.tgz",
+ "integrity":
"sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime/node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity":
"sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD",
+ "optional": true
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9",
"resolved":
"https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
@@ -521,6 +540,367 @@
"node": ">=18"
}
},
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity":
"sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity":
"sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity":
"sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity":
"sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity":
"sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity":
"sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity":
"sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity":
"sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity":
"sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity":
"sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity":
"sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity":
"sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity":
"sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity":
"sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity":
"sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity":
"sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity":
"sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity":
"sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved":
"https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity":
"sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@intlify/core-base": {
"version": "9.14.5",
"resolved":
"https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz",
@@ -571,6 +951,12 @@
"integrity":
"sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
+ "node_modules/@lokesh.dhakar/quantize": {
+ "version": "1.4.0",
+ "resolved":
"https://registry.npmjs.org/@lokesh.dhakar/quantize/-/quantize-1.4.0.tgz",
+ "integrity":
"sha512-+//cqVWKis//t0YH62EDtwaFSPG/CDtYNg4CZmzNmG2d5W17Iu3fuDAdpQXCDHUDrrU9q0veze4A7tPZXlR/mg==",
+ "license": "MIT"
+ },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved":
"https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -868,6 +1254,19 @@
"win32"
]
},
+ "node_modules/@tokenizer/token": {
+ "version": "0.3.0",
+ "resolved":
"https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
+ "integrity":
"sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/colorthief": {
+ "version": "2.6.0",
+ "resolved":
"https://registry.npmjs.org/@types/colorthief/-/colorthief-2.6.0.tgz",
+ "integrity":
"sha512-GZBHPzkgEsyZqO7a9rhqkcW2BJZW+UpRlIUorY8vfOk7BVFVZMuDvZRPyaExv7ML0DaeB/t78PUOTkGo/THDpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved":
"https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -896,6 +1295,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/ndarray": {
+ "version": "1.0.14",
+ "resolved":
"https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.14.tgz",
+ "integrity":
"sha512-oANmFZMnFQvb219SSBIhI1Ih/r4CvHDOzkWyJS/XRqkMrGH5/kaPSA1hQhdIBzouaE+5KpE/f5ylI9cujmckQg==",
+ "license": "MIT"
+ },
"node_modules/@types/node": {
"version": "24.10.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz",
@@ -1210,6 +1615,18 @@
}
}
},
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved":
"https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity":
"sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
"node_modules/alien-signals": {
"version": "3.0.6",
"resolved":
"https://registry.npmjs.org/alien-signals/-/alien-signals-3.0.6.tgz",
@@ -1244,6 +1661,26 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity":
"sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved":
"https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -1270,6 +1707,30 @@
"node": ">=8"
}
},
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity":
"sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1295,6 +1756,59 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity":
"sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved":
"https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity":
"sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved":
"https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity":
"sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved":
"https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity":
"sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/colorthief": {
+ "version": "2.6.0",
+ "resolved":
"https://registry.npmjs.org/colorthief/-/colorthief-2.6.0.tgz",
+ "integrity":
"sha512-yL3B7laeOr4kH9XasFF5rl+9Taz+Pmt/CRbaTI6XepZFyQvk4K/abaGKIAsngVpxKkgFeoJ2IwdRpS228icrig==",
+ "license": "MIT",
+ "dependencies": {
+ "@lokesh.dhakar/quantize": "^1.4.0",
+ "file-type": "^16.5.3",
+ "ndarray-pixels": "^4.1.0",
+ "sharp": "^0.33.5"
+ }
+ },
"node_modules/copy-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz",
@@ -1308,6 +1822,24 @@
"integrity":
"sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT"
},
+ "node_modules/cwise-compiler": {
+ "version": "1.1.3",
+ "resolved":
"https://registry.npmjs.org/cwise-compiler/-/cwise-compiler-1.1.3.tgz",
+ "integrity":
"sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "uniq": "^1.0.0"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved":
"https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity":
"sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/echarts": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz",
@@ -1379,6 +1911,24 @@
"integrity":
"sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT"
},
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved":
"https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity":
"sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity":
"sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -1397,6 +1947,23 @@
}
}
},
+ "node_modules/file-type": {
+ "version": "16.5.4",
+ "resolved":
"https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
+ "integrity":
"sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
+ "license": "MIT",
+ "dependencies": {
+ "readable-web-to-node-stream": "^3.0.0",
+ "strtok3": "^6.2.4",
+ "token-types": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/file-type?sponsor=1"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved":
"https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -1468,6 +2035,38 @@
"node": ">=0.10.0"
}
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity":
"sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/iota-array": {
+ "version": "1.0.0",
+ "resolved":
"https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
+ "integrity":
"sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==",
+ "license": "MIT"
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved":
"https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity":
"sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "license": "MIT"
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved":
"https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -1481,6 +2080,12 @@
"node": ">=8"
}
},
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity":
"sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "license": "MIT"
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved":
"https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1576,6 +2181,37 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/ndarray": {
+ "version": "1.0.19",
+ "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz",
+ "integrity":
"sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==",
+ "license": "MIT",
+ "dependencies": {
+ "iota-array": "^1.0.0",
+ "is-buffer": "^1.0.2"
+ }
+ },
+ "node_modules/ndarray-ops": {
+ "version": "1.2.2",
+ "resolved":
"https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz",
+ "integrity":
"sha512-BppWAFRjMYF7N/r6Ie51q6D4fs0iiGmeXIACKY66fLpnwIui3Wc3CXiD/30mgLbDjPpSLrsqcp3Z62+IcHZsDw==",
+ "license": "MIT",
+ "dependencies": {
+ "cwise-compiler": "^1.0.0"
+ }
+ },
+ "node_modules/ndarray-pixels": {
+ "version": "4.1.0",
+ "resolved":
"https://registry.npmjs.org/ndarray-pixels/-/ndarray-pixels-4.1.0.tgz",
+ "integrity":
"sha512-xKPI4zXJ2pkUcVX24zIN1AWqqPWvRWWhRuO6PlY4EdB2VNRauNwA6rDdsAQG/ldQp0sU7nTXgPR/io1duy3Zyg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ndarray": "^1.0.14",
+ "ndarray": "^1.0.19",
+ "ndarray-ops": "^1.2.2",
+ "sharp": "^0.33.4"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved":
"https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -1606,6 +2242,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/peek-readable": {
+ "version": "4.1.0",
+ "resolved":
"https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
+ "integrity":
"sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved":
"https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -1653,6 +2302,47 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity":
"sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved":
"https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity":
"sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/readable-web-to-node-stream": {
+ "version": "3.0.4",
+ "resolved":
"https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz",
+ "integrity":
"sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==",
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "^4.7.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -1719,6 +2409,86 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved":
"https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity":
"sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity":
"sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity":
"sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved":
"https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity":
"sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved":
"https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -1728,6 +2498,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved":
"https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity":
"sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/strtok3": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
+ "integrity":
"sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
+ "license": "MIT",
+ "dependencies": {
+ "@tokenizer/token": "^0.3.0",
+ "peek-readable": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
"node_modules/tinycolor2": {
"version": "1.6.0",
"resolved":
"https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
@@ -1764,6 +2560,23 @@
"node": ">=8.0"
}
},
+ "node_modules/token-types": {
+ "version": "4.2.1",
+ "resolved":
"https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
+ "integrity":
"sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@tokenizer/token": "^0.3.0",
+ "ieee754": "^1.2.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
"node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
@@ -1793,6 +2606,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity":
"sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==",
+ "license": "MIT"
+ },
"node_modules/universalify": {
"version": "2.0.1",
"resolved":
"https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
diff --git a/package.json b/package.json
index 8af3dce..623d1c4 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,14 @@
"release": "vue-tsc -b && vite build --mode app && node scripts/release.js"
},
"dependencies": {
+ "colorthief": "^2.6.0",
"vant": "^4.9.21",
"vue": "^3.5.24",
"vue-i18n": "^9.14.5",
"vue3-colorpicker": "^2.3.0"
},
"devDependencies": {
+ "@types/colorthief": "^2.6.0",
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.10.0",
"@vitejs/plugin-vue": "^6.0.1",
diff --git a/src/components/ChartPreviewPanel.vue
b/src/components/ChartPreviewPanel.vue
index 588b2d3..ffd685d 100644
--- a/src/components/ChartPreviewPanel.vue
+++ b/src/components/ChartPreviewPanel.vue
@@ -7,7 +7,6 @@
<div class="charts-grid">
<div
v-for="(config, index) in displayedCharts"
- v-once
:key="config.type + index"
class="chart-item"
>
diff --git a/src/components/ThemePanel.vue b/src/components/ThemePanel.vue
index d69c55e..2dc8285 100644
--- a/src/components/ThemePanel.vue
+++ b/src/components/ThemePanel.vue
@@ -80,6 +80,14 @@
:style="{ backgroundColor: color }"
/>
</div>
+ <div
+ class="theme-item new-theme"
+ :title="$t('panel.extractFromImageTitle')"
+ @click="uploadImageInputRef?.click()"
+ >
+ <van-icon name="plus" />
+ <span>{{ $t('panel.extractFromImage') }}</span>
+ </div>
</div>
</div>
</div>
@@ -457,12 +465,20 @@
<!-- Hidden file input for import -->
<input
- ref="fileInput"
+ ref="importFileInput"
type="file"
accept=".json"
style="display: none"
@change="handleFileImport"
/>
+
+ <input
+ ref="uploadImageInput"
+ type="file"
+ accept="image/jpeg, image/png, image/webp, image/avif, image/apng,
image/svg+xml"
+ style="display: none"
+ @change="handleImageUpload"
+ />
</div>
</template>
@@ -474,9 +490,10 @@ import ColorPicker from './ColorPicker.vue'
import ColorList from './ColorList.vue'
import type ChartPreviewPanel from './ChartPreviewPanel.vue'
import { downloadJsonFile, downloadJsFile } from '../utils/download'
-import { showToast, showDialog } from 'vant'
+import { showToast, showDialog, showLoadingToast } from 'vant'
import { useI18n } from 'vue-i18n'
import * as echarts from 'echarts'
+import ColorThief from 'colorthief'
// Initialize i18n and localization
const { t } = useI18n()
@@ -489,7 +506,8 @@ const props = defineProps<Props>()
// Component state
const activeNames = ref(['functions'])
-const fileInputRef = useTemplateRef('fileInput')
+const importFileInputRef = useTemplateRef('importFileInput')
+const uploadImageInputRef = useTemplateRef('uploadImageInput')
// Theme store
const themeStore = useThemeStore()
@@ -750,7 +768,7 @@ const showUsageInstructions = (format: 'js' | 'json',
filename: string) => {
}
const importConfig = () => {
- fileInputRef.value?.click()
+ importFileInputRef.value?.click()
}
const exportConfig = async () => {
@@ -800,7 +818,6 @@ const resetTheme = async () => {
}
}
-
const showHelp = () => {
showDialog({
title: t('modals.helpTitle'),
@@ -927,6 +944,62 @@ const handleFileImport = async (event: Event) => {
// Clear input
target.value = ''
}
+
+const handleImageUpload = async (event: Event) => {
+ const target = event.target as HTMLInputElement
+ const file = target.files?.[0]
+ if (!file) return
+
+ const loader = showLoadingToast({
+ message: t('modals.extractingColors'),
+ duration: 0,
+ forbidClick: true,
+ loadingType: 'spinner',
+ wordBreak: 'break-word',
+ className: 'ec-loading-toast'
+ })
+
+ let imgURL: string | undefined;
+ try {
+ imgURL = URL.createObjectURL(file)
+
+ const img = new Image()
+ img.src = imgURL
+
+ await new Promise((resolve, reject) => {
+ img.onload = resolve
+ img.onerror = (e) => {
+ console.error('Failed to load image')
+ reject(e)
+ }
+ })
+
+ const colorThief = new ColorThief()
+ const colors = colorThief.getPalette(img, 10, 1).map(
+ (rgb) => `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`
+ )
+
+ loader.close()
+
+ themeName.value = 'image-based'
+ theme.color = colors
+ // PENDING
+ theme.visualMapColor = colors.slice(0, 2)
+
+ props.chartPreviewRef?.updateCharts()
+
+ themeStore.activePreDefinedThemeIndex.value = null
+ } catch (e) {
+ console.error('Failed to extract image color:', e)
+ showToast({
+ message: t('modals.extractColorFailed'),
+ type: 'fail'
+ })
+ } finally {
+ imgURL && URL.revokeObjectURL(imgURL)
+ target.value = ''
+ }
+}
</script>
<style scoped>
@@ -992,6 +1065,18 @@ const handleFileImport = async (event: Event) => {
box-shadow: 0 0 4px var(--van-primary-color);
}
+.new-theme {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 5px;
+ height: auto;
+ font-size: 85%;
+ line-height: 1;
+ white-space: nowrap;
+ cursor: pointer;
+}
+
.color-dot {
width: 20px;
height: 20px;
@@ -1014,6 +1099,12 @@ const handleFileImport = async (event: Event) => {
color: rgb(41, 60, 85);
}
+@media (max-width: 1200px) {
+ .new-theme span {
+ display: none;
+ }
+}
+
/* Custom Vant styles */
:deep(.van-collapse) {
border: none;
@@ -1176,4 +1267,8 @@ const handleFileImport = async (event: Event) => {
:global(.modal-body a:hover) {
text-decoration: underline;
}
+
+:global(.ec-loading-toast) {
+ width: 200px;
+}
</style>
diff --git a/src/locales/en.json b/src/locales/en.json
index 8a86800..45f822b 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -36,7 +36,9 @@
"seriesCount": "Series",
"seriesPlaceholder": "Please enter series count",
"preDefinedThemes": "Predefined Themes",
- "separateAxisSetting": "Configure different axis types separately"
+ "separateAxisSetting": "Configure different axis types separately",
+ "extractFromImage": "From Image",
+ "extractFromImageTitle": "Extract theme colors from an image"
},
"colors": {
"background": "Background",
@@ -182,6 +184,8 @@
"oldVersionPrompt": "The imported theme is from an older version, some
properties may not be correctly set. Continue importing?",
"importSuccess": "Theme imported successfully!",
"invalidFormat": "Configuration file format error, please use a JSON file
exported from this site!",
- "fileReadFailed": "File read failed, please try again"
+ "fileReadFailed": "File read failed, please try again",
+ "extractingColors": "Please wait when extracting colors from image...",
+ "extractColorFailed": "Failed to extract colors from image"
}
}
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 0132c1b..fb6daae 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -36,7 +36,9 @@
"seriesCount": "系列数量",
"seriesPlaceholder": "请输入系列数量",
"preDefinedThemes": "默认方案",
- "separateAxisSetting": "为不同类型坐标轴分别设置"
+ "separateAxisSetting": "为不同类型坐标轴分别设置",
+ "extractFromImage": "从图片提取",
+ "extractFromImageTitle": "上传一张图片并从中提取颜色"
},
"colors": {
"background": "背景",
@@ -182,6 +184,8 @@
"oldVersionPrompt": "导入的主题版本较低,某些属性可能无法正确设置。是否继续导入?",
"importSuccess": "主题导入成功!",
"invalidFormat": "配置文件格式错误,请使用从本网站导出的 JSON 文件!",
- "fileReadFailed": "文件读取失败,请重试"
+ "fileReadFailed": "文件读取失败,请重试",
+ "extractingColors": "正在从图片中提取颜色...",
+ "extractColorFailed": "从图片提取颜色失败"
}
}
diff --git a/src/stores/theme.ts b/src/stores/theme.ts
index 05134dd..be26e92 100644
--- a/src/stores/theme.ts
+++ b/src/stores/theme.ts
@@ -284,9 +284,6 @@ const createThemeStore = () => {
// Update axis settings based on axisSeperateSetting
updateAxisSetting()
-
- // Force trigger reactive update by modifying a dummy property
- ;(theme as any).__forceUpdate = Date.now()
}
} catch (error) {
console.error('Error loading predefined theme:', error)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]