From 8790b20354b4a5b6545759aa53529956ac5fb07c Mon Sep 17 00:00:00 2001 From: Lim Chee Aun Date: Tue, 15 Aug 2023 20:14:09 +0800 Subject: [PATCH] Experimental Shortcuts settings import/export --- package-lock.json | 280 ++++++++++++---------- package.json | 15 +- src/app.css | 5 + src/components/icon.jsx | 5 + src/components/shortcuts-settings.css | 49 ++++ src/components/shortcuts-settings.jsx | 331 +++++++++++++++++++++++++- src/index.css | 10 +- 7 files changed, 551 insertions(+), 144 deletions(-) diff --git a/package-lock.json b/package-lock.json index d6d42f9e..bf4ef226 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,21 +10,22 @@ "dependencies": { "@formatjs/intl-localematcher": "~0.4.0", "@github/text-expander-element": "~2.5.0", - "@iconify-icons/mingcute": "~1.2.6", + "@iconify-icons/mingcute": "~1.2.7", "@justinribeiro/lite-youtube": "~1.5.0", - "@szhsin/react-menu": "~4.0.2", - "@uidotdev/usehooks": "~2.0.1", + "@szhsin/react-menu": "~4.0.3", + "@uidotdev/usehooks": "~2.1.0", "dayjs": "~1.11.9", "dayjs-twitter": "~0.5.0", "fast-blurhash": "~1.1.2", "fast-deep-equal": "~3.1.3", "idb-keyval": "~6.2.1", "just-debounce-it": "~3.2.0", + "lz-string": "^1.5.0", "masto": "~5.11.4", "mem": "~9.0.2", "p-retry": "~5.1.2", "p-throttle": "~5.1.0", - "preact": "~10.16.0", + "preact": "~10.17.0", "react-hotkeys-hook": "~4.4.1", "react-intersection-observer": "~9.5.2", "react-quick-pinch-zoom": "~4.9.0", @@ -42,10 +43,10 @@ "@preact/preset-vite": "~2.5.0", "@trivago/prettier-plugin-sort-imports": "~4.2.0", "postcss": "~8.4.27", - "postcss-dark-theme-class": "~0.7.3", - "postcss-preset-env": "~9.1.0", + "postcss-dark-theme-class": "~0.8.0", + "postcss-preset-env": "~9.1.1", "twitter-text": "~3.1.0", - "vite": "~4.4.7", + "vite": "~4.4.9", "vite-plugin-generate-file": "~0.0.4", "vite-plugin-html-config": "~1.0.11", "vite-plugin-pwa": "~0.16.4", @@ -1965,9 +1966,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.3.tgz", - "integrity": "sha512-ATul1u+pic4aVpstgueqxEv4MsObEbszAxfTXpx9LHaeD3LAh+wFqdCteyegWmjk0k5rkSCAvIOaJe9U3DD09w==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.4.tgz", + "integrity": "sha512-V/OUXYX91tAC1CDsiY+HotIcJR+vPtzrX8pCplCpT++i8ThZZsq5F5dzZh/bDM3WUOjrvC1ljed1oSJxMfjqhw==", "dev": true, "funding": [ { @@ -2301,9 +2302,9 @@ } }, "node_modules/@csstools/postcss-media-minmax": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.6.tgz", - "integrity": "sha512-BmwKkqEzzQz6D+5ctoacsiGrq4kVgd1PMEPwkwdR0qFaL2C2nguGsWG87xEw+HIts/2yxhIPTm7Jp3DQq+wn3Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.7.tgz", + "integrity": "sha512-5LGLdu8cJgRPmvkjUNqOPKIKeHbyQmoGKooB5Rh0mp5mLaNI9bl+IjFZ2keY0cztZYsriJsGf6Lu8R5XetuwoQ==", "dev": true, "funding": [ { @@ -2319,7 +2320,7 @@ "@csstools/css-calc": "^1.1.3", "@csstools/css-parser-algorithms": "^2.3.1", "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.3" + "@csstools/media-query-list-parser": "^2.1.4" }, "engines": { "node": "^14 || ^16 || >=18" @@ -2329,9 +2330,9 @@ } }, "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.1.tgz", - "integrity": "sha512-UvMYxXT3R011whbxzRwLx7d7eNGyVsnZo7waAmf10ZGnT34XidY+rsdFnk6OdFwuG6FYqw3/tptQEAZOmUgvLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.2.tgz", + "integrity": "sha512-kQJR6NvTRidsaRjCdHGjra2+fLoFiDQOm5B2aZrhmXqng/hweXjruboKzB326rxQO2L0m0T+gCKbZgyuncyhLg==", "dev": true, "funding": [ { @@ -2346,7 +2347,7 @@ "dependencies": { "@csstools/css-parser-algorithms": "^2.3.1", "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.3" + "@csstools/media-query-list-parser": "^2.1.4" }, "engines": { "node": "^14 || ^16 || >=18" @@ -3009,9 +3010,9 @@ } }, "node_modules/@iconify-icons/mingcute": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.6.tgz", - "integrity": "sha512-ToWyd3IuI+bU+q51T0GMEv7utgVksEAlzVoTSEK9GmxYG6qvUX0rKo2wMrRA4X+cv9WqDRJqJZN0pue9uUszDQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.7.tgz", + "integrity": "sha512-GObX5YACRhYunL6L8nJ3PGQ+vs9vzvsx8FBZSCs2S3awMwIPKpWPVnjIlx7urnyN5qJoHZGV0iiEVjOmdHDTuw==", "dependencies": { "@iconify/types": "*" } @@ -3249,9 +3250,9 @@ } }, "node_modules/@szhsin/react-menu": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.2.tgz", - "integrity": "sha512-cYpktkWng7jCTPKog33w5iYldbaHQso5aJFd+7j3SkhInqYWjxiG0TtxUS0c5yFqLm6woGQEJHiBpiYHIaYMxg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.3.tgz", + "integrity": "sha512-TPsOKLEkesE79802evnLt2Mbv/+zwRJdX8776/vxK5ST9SK8SO0A8kRrus6JuxijLxZxFpmY/3VMdoyeCWQHKA==", "dependencies": { "prop-types": "^15.7.2", "react-transition-state": "^2.1.0" @@ -3395,9 +3396,9 @@ "dev": true }, "node_modules/@uidotdev/usehooks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.0.1.tgz", - "integrity": "sha512-rJXxE3Y8g9utRbOS9Pj9tIvrnOdaakHIhLbMxBlErV8HydnGD0DveD82aLBfVTh1hBp5IXqpeHpMrPE9WIT7vQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.1.0.tgz", + "integrity": "sha512-D7SJiNQC1BOHgtE2dy2KvOtnRNaLWTFFHvcBLg7lZ8Jz7YcimxdUY3spqpvf/mVkGCuUHee8i/79p5vVkBgsYQ==", "engines": { "node": ">=16" }, @@ -3710,9 +3711,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -3729,9 +3730,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" }, "bin": { @@ -3781,9 +3782,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001512", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", - "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "version": "1.0.30001519", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", + "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", "dev": true, "funding": [ { @@ -4139,9 +4140,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.451", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz", - "integrity": "sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA==", + "version": "1.4.490", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz", + "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", "dev": true }, "node_modules/es-abstract": { @@ -5280,6 +5281,14 @@ "node": ">=10" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -5485,9 +5494,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/normalize-range": { @@ -5862,16 +5871,22 @@ } }, "node_modules/postcss-dark-theme-class": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/postcss-dark-theme-class/-/postcss-dark-theme-class-0.7.3.tgz", - "integrity": "sha512-M9vtfh8ORzQsVdT9BWb+xpEDAzC7nHBn7wVc988/JkEVLPupKcUnV0jw7RZ8sSj0ovpqN1POf6PLdt19JCHfhQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/postcss-dark-theme-class/-/postcss-dark-theme-class-0.8.0.tgz", + "integrity": "sha512-/zyywenvSJVlG1Ie/MLkQBhoh0sTOKPQa+3exaBVAmeITuGscGZu1NuJc5qpv2+ywIkBujL9OU26bj0DdUgY2Q==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=18.0" }, "peerDependencies": { "postcss": "^8.2.14" @@ -6097,9 +6112,9 @@ } }, "node_modules/postcss-nesting": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.0.tgz", - "integrity": "sha512-knqwW65kxssmyIFadRSimaiRyLVRd0MdwfabesKw6XvGLwSOCJ+4zfvNQQCOOYij5obwpZzDpODuGRv2PCyiUw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.1.tgz", + "integrity": "sha512-6LCqCWP9pqwXw/njMvNK0hGY44Fxc4B2EsGbn6xDcxbNRzP8GYoxT7yabVVMLrX3quqOJ9hg2jYMsnkedOf8pA==", "dev": true, "funding": [ { @@ -6204,9 +6219,9 @@ } }, "node_modules/postcss-preset-env": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.1.0.tgz", - "integrity": "sha512-G+x9BD7jb9uHBB7o720emXV00CP+VdWeirJsHC5ERSpbTd2e6Xg7vHzT+a6UkxFyddALuV+Q8wJMgeTKaau+Pg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.1.1.tgz", + "integrity": "sha512-rMPEqyTLm8JLbvaHnDAdQg6SN4Z/NDOsm+CRefg4HmSOiNpTcBXaw4RAaQbfTNe8BB75l4NpoQ6sMdrutdEpdQ==", "dev": true, "funding": [ { @@ -6231,8 +6246,8 @@ "@csstools/postcss-logical-float-and-clear": "^2.0.0", "@csstools/postcss-logical-resize": "^2.0.0", "@csstools/postcss-logical-viewport-units": "^2.0.1", - "@csstools/postcss-media-minmax": "^1.0.6", - "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.1", + "@csstools/postcss-media-minmax": "^1.0.7", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.2", "@csstools/postcss-nested-calc": "^3.0.0", "@csstools/postcss-normalize-display-values": "^3.0.0", "@csstools/postcss-oklab-function": "^3.0.1", @@ -6244,7 +6259,7 @@ "@csstools/postcss-trigonometric-functions": "^3.0.1", "@csstools/postcss-unset-value": "^3.0.0", "autoprefixer": "^10.4.14", - "browserslist": "^4.21.9", + "browserslist": "^4.21.10", "css-blank-pseudo": "^6.0.0", "css-has-pseudo": "^6.0.0", "css-prefers-color-scheme": "^9.0.0", @@ -6267,7 +6282,7 @@ "postcss-initial": "^4.0.1", "postcss-lab-function": "^6.0.1", "postcss-logical": "^7.0.0", - "postcss-nesting": "^12.0.0", + "postcss-nesting": "^12.0.1", "postcss-opacity-percentage": "^2.0.0", "postcss-overflow-shorthand": "^5.0.0", "postcss-page-break": "^3.0.4", @@ -6357,9 +6372,9 @@ "dev": true }, "node_modules/preact": { - "version": "10.16.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.16.0.tgz", - "integrity": "sha512-XTSj3dJ4roKIC93pald6rWuB2qQJO9gO2iLLyTe87MrjQN+HklueLsmskbywEWqCHlclgz3/M4YLL2iBr9UmMA==", + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.17.0.tgz", + "integrity": "sha512-SNsI8cbaCcUS5tbv9nlXuCfIXnJ9ysBMWk0WnB6UWwcVA3qZ2O6FxqDFECMAMttvLQcW/HaNZUe2BLidyvrVYw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -6699,9 +6714,9 @@ } }, "node_modules/rollup": { - "version": "3.26.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", - "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", + "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -7362,14 +7377,14 @@ } }, "node_modules/vite": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", - "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "dev": true, "dependencies": { "esbuild": "^0.18.10", - "postcss": "^8.4.26", - "rollup": "^3.25.2" + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -9230,9 +9245,9 @@ "dev": true }, "@csstools/media-query-list-parser": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.3.tgz", - "integrity": "sha512-ATul1u+pic4aVpstgueqxEv4MsObEbszAxfTXpx9LHaeD3LAh+wFqdCteyegWmjk0k5rkSCAvIOaJe9U3DD09w==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.4.tgz", + "integrity": "sha512-V/OUXYX91tAC1CDsiY+HotIcJR+vPtzrX8pCplCpT++i8ThZZsq5F5dzZh/bDM3WUOjrvC1ljed1oSJxMfjqhw==", "dev": true, "requires": {} }, @@ -9359,26 +9374,26 @@ } }, "@csstools/postcss-media-minmax": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.6.tgz", - "integrity": "sha512-BmwKkqEzzQz6D+5ctoacsiGrq4kVgd1PMEPwkwdR0qFaL2C2nguGsWG87xEw+HIts/2yxhIPTm7Jp3DQq+wn3Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-1.0.7.tgz", + "integrity": "sha512-5LGLdu8cJgRPmvkjUNqOPKIKeHbyQmoGKooB5Rh0mp5mLaNI9bl+IjFZ2keY0cztZYsriJsGf6Lu8R5XetuwoQ==", "dev": true, "requires": { "@csstools/css-calc": "^1.1.3", "@csstools/css-parser-algorithms": "^2.3.1", "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.3" + "@csstools/media-query-list-parser": "^2.1.4" } }, "@csstools/postcss-media-queries-aspect-ratio-number-values": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.1.tgz", - "integrity": "sha512-UvMYxXT3R011whbxzRwLx7d7eNGyVsnZo7waAmf10ZGnT34XidY+rsdFnk6OdFwuG6FYqw3/tptQEAZOmUgvLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-2.0.2.tgz", + "integrity": "sha512-kQJR6NvTRidsaRjCdHGjra2+fLoFiDQOm5B2aZrhmXqng/hweXjruboKzB326rxQO2L0m0T+gCKbZgyuncyhLg==", "dev": true, "requires": { "@csstools/css-parser-algorithms": "^2.3.1", "@csstools/css-tokenizer": "^2.2.0", - "@csstools/media-query-list-parser": "^2.1.3" + "@csstools/media-query-list-parser": "^2.1.4" } }, "@csstools/postcss-nested-calc": { @@ -9663,9 +9678,9 @@ } }, "@iconify-icons/mingcute": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.6.tgz", - "integrity": "sha512-ToWyd3IuI+bU+q51T0GMEv7utgVksEAlzVoTSEK9GmxYG6qvUX0rKo2wMrRA4X+cv9WqDRJqJZN0pue9uUszDQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@iconify-icons/mingcute/-/mingcute-1.2.7.tgz", + "integrity": "sha512-GObX5YACRhYunL6L8nJ3PGQ+vs9vzvsx8FBZSCs2S3awMwIPKpWPVnjIlx7urnyN5qJoHZGV0iiEVjOmdHDTuw==", "requires": { "@iconify/types": "*" } @@ -9865,9 +9880,9 @@ } }, "@szhsin/react-menu": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.2.tgz", - "integrity": "sha512-cYpktkWng7jCTPKog33w5iYldbaHQso5aJFd+7j3SkhInqYWjxiG0TtxUS0c5yFqLm6woGQEJHiBpiYHIaYMxg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@szhsin/react-menu/-/react-menu-4.0.3.tgz", + "integrity": "sha512-TPsOKLEkesE79802evnLt2Mbv/+zwRJdX8776/vxK5ST9SK8SO0A8kRrus6JuxijLxZxFpmY/3VMdoyeCWQHKA==", "requires": { "prop-types": "^15.7.2", "react-transition-state": "^2.1.0" @@ -9987,9 +10002,9 @@ "dev": true }, "@uidotdev/usehooks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.0.1.tgz", - "integrity": "sha512-rJXxE3Y8g9utRbOS9Pj9tIvrnOdaakHIhLbMxBlErV8HydnGD0DveD82aLBfVTh1hBp5IXqpeHpMrPE9WIT7vQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@uidotdev/usehooks/-/usehooks-2.1.0.tgz", + "integrity": "sha512-D7SJiNQC1BOHgtE2dy2KvOtnRNaLWTFFHvcBLg7lZ8Jz7YcimxdUY3spqpvf/mVkGCuUHee8i/79p5vVkBgsYQ==", "requires": {} }, "@vue/compiler-core": { @@ -10229,14 +10244,14 @@ } }, "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" } }, @@ -10271,9 +10286,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001512", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", - "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "version": "1.0.30001519", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", + "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", "dev": true }, "capital-case": { @@ -10505,9 +10520,9 @@ } }, "electron-to-chromium": { - "version": "1.4.451", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz", - "integrity": "sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA==", + "version": "1.4.490", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz", + "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", "dev": true }, "es-abstract": { @@ -11357,6 +11372,11 @@ "yallist": "^4.0.0" } }, + "lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -11507,9 +11527,9 @@ } }, "node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "normalize-range": { @@ -11719,9 +11739,9 @@ } }, "postcss-dark-theme-class": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/postcss-dark-theme-class/-/postcss-dark-theme-class-0.7.3.tgz", - "integrity": "sha512-M9vtfh8ORzQsVdT9BWb+xpEDAzC7nHBn7wVc988/JkEVLPupKcUnV0jw7RZ8sSj0ovpqN1POf6PLdt19JCHfhQ==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/postcss-dark-theme-class/-/postcss-dark-theme-class-0.8.0.tgz", + "integrity": "sha512-/zyywenvSJVlG1Ie/MLkQBhoh0sTOKPQa+3exaBVAmeITuGscGZu1NuJc5qpv2+ywIkBujL9OU26bj0DdUgY2Q==", "dev": true, "requires": {} }, @@ -11814,9 +11834,9 @@ } }, "postcss-nesting": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.0.tgz", - "integrity": "sha512-knqwW65kxssmyIFadRSimaiRyLVRd0MdwfabesKw6XvGLwSOCJ+4zfvNQQCOOYij5obwpZzDpODuGRv2PCyiUw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.0.1.tgz", + "integrity": "sha512-6LCqCWP9pqwXw/njMvNK0hGY44Fxc4B2EsGbn6xDcxbNRzP8GYoxT7yabVVMLrX3quqOJ9hg2jYMsnkedOf8pA==", "dev": true, "requires": { "@csstools/selector-specificity": "^3.0.0", @@ -11856,9 +11876,9 @@ } }, "postcss-preset-env": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.1.0.tgz", - "integrity": "sha512-G+x9BD7jb9uHBB7o720emXV00CP+VdWeirJsHC5ERSpbTd2e6Xg7vHzT+a6UkxFyddALuV+Q8wJMgeTKaau+Pg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-9.1.1.tgz", + "integrity": "sha512-rMPEqyTLm8JLbvaHnDAdQg6SN4Z/NDOsm+CRefg4HmSOiNpTcBXaw4RAaQbfTNe8BB75l4NpoQ6sMdrutdEpdQ==", "dev": true, "requires": { "@csstools/postcss-cascade-layers": "^4.0.0", @@ -11873,8 +11893,8 @@ "@csstools/postcss-logical-float-and-clear": "^2.0.0", "@csstools/postcss-logical-resize": "^2.0.0", "@csstools/postcss-logical-viewport-units": "^2.0.1", - "@csstools/postcss-media-minmax": "^1.0.6", - "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.1", + "@csstools/postcss-media-minmax": "^1.0.7", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^2.0.2", "@csstools/postcss-nested-calc": "^3.0.0", "@csstools/postcss-normalize-display-values": "^3.0.0", "@csstools/postcss-oklab-function": "^3.0.1", @@ -11886,7 +11906,7 @@ "@csstools/postcss-trigonometric-functions": "^3.0.1", "@csstools/postcss-unset-value": "^3.0.0", "autoprefixer": "^10.4.14", - "browserslist": "^4.21.9", + "browserslist": "^4.21.10", "css-blank-pseudo": "^6.0.0", "css-has-pseudo": "^6.0.0", "css-prefers-color-scheme": "^9.0.0", @@ -11909,7 +11929,7 @@ "postcss-initial": "^4.0.1", "postcss-lab-function": "^6.0.1", "postcss-logical": "^7.0.0", - "postcss-nesting": "^12.0.0", + "postcss-nesting": "^12.0.1", "postcss-opacity-percentage": "^2.0.0", "postcss-overflow-shorthand": "^5.0.0", "postcss-page-break": "^3.0.4", @@ -11962,9 +11982,9 @@ "dev": true }, "preact": { - "version": "10.16.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.16.0.tgz", - "integrity": "sha512-XTSj3dJ4roKIC93pald6rWuB2qQJO9gO2iLLyTe87MrjQN+HklueLsmskbywEWqCHlclgz3/M4YLL2iBr9UmMA==" + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.17.0.tgz", + "integrity": "sha512-SNsI8cbaCcUS5tbv9nlXuCfIXnJ9ysBMWk0WnB6UWwcVA3qZ2O6FxqDFECMAMttvLQcW/HaNZUe2BLidyvrVYw==" }, "prettier": { "version": "2.8.0", @@ -12191,9 +12211,9 @@ "dev": true }, "rollup": { - "version": "3.26.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", - "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", + "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -12662,15 +12682,15 @@ } }, "vite": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz", - "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==", + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", + "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", "dev": true, "requires": { "esbuild": "^0.18.10", "fsevents": "~2.3.2", - "postcss": "^8.4.26", - "rollup": "^3.25.2" + "postcss": "^8.4.27", + "rollup": "^3.27.1" } }, "vite-plugin-generate-file": { diff --git a/package.json b/package.json index 0f08ee32..87c680db 100644 --- a/package.json +++ b/package.json @@ -12,21 +12,22 @@ "dependencies": { "@formatjs/intl-localematcher": "~0.4.0", "@github/text-expander-element": "~2.5.0", - "@iconify-icons/mingcute": "~1.2.6", + "@iconify-icons/mingcute": "~1.2.7", "@justinribeiro/lite-youtube": "~1.5.0", - "@szhsin/react-menu": "~4.0.2", - "@uidotdev/usehooks": "~2.0.1", + "@szhsin/react-menu": "~4.0.3", + "@uidotdev/usehooks": "~2.1.0", "dayjs": "~1.11.9", "dayjs-twitter": "~0.5.0", "fast-blurhash": "~1.1.2", "fast-deep-equal": "~3.1.3", "idb-keyval": "~6.2.1", "just-debounce-it": "~3.2.0", + "lz-string": "^1.5.0", "masto": "~5.11.4", "mem": "~9.0.2", "p-retry": "~5.1.2", "p-throttle": "~5.1.0", - "preact": "~10.16.0", + "preact": "~10.17.0", "react-hotkeys-hook": "~4.4.1", "react-intersection-observer": "~9.5.2", "react-quick-pinch-zoom": "~4.9.0", @@ -44,10 +45,10 @@ "@preact/preset-vite": "~2.5.0", "@trivago/prettier-plugin-sort-imports": "~4.2.0", "postcss": "~8.4.27", - "postcss-dark-theme-class": "~0.7.3", - "postcss-preset-env": "~9.1.0", + "postcss-dark-theme-class": "~0.8.0", + "postcss-preset-env": "~9.1.1", "twitter-text": "~3.1.0", - "vite": "~4.4.7", + "vite": "~4.4.9", "vite-plugin-generate-file": "~0.0.4", "vite-plugin-html-config": "~1.0.11", "vite-plugin-pwa": "~0.16.4", diff --git a/src/app.css b/src/app.css index dfb3b66a..bf1834d0 100644 --- a/src/app.css +++ b/src/app.css @@ -1417,6 +1417,11 @@ body:has(.media-modal-container + .status-deck) .media-post-link { .tag.collapsed { margin: 0; } +.tag.insignificant { + border: 1px solid var(--outline-color); + color: var(--text-insignificant-color); + background-color: var(--bg-faded-color); +} .tag.danger { background-color: var(--red-color); } diff --git a/src/components/icon.jsx b/src/components/icon.jsx index a0b5e483..47599177 100644 --- a/src/components/icon.jsx +++ b/src/components/icon.jsx @@ -90,6 +90,11 @@ export const ICONS = { announce: () => import('@iconify-icons/mingcute/announcement-line'), alert: () => import('@iconify-icons/mingcute/alert-line'), round: () => import('@iconify-icons/mingcute/round-fill'), + 'arrow-up-circle': () => + import('@iconify-icons/mingcute/arrow-up-circle-line'), + 'arrow-down-circle': () => + import('@iconify-icons/mingcute/arrow-down-circle-line'), + clipboard: () => import('@iconify-icons/mingcute/clipboard-line'), }; function Icon({ diff --git a/src/components/shortcuts-settings.css b/src/components/shortcuts-settings.css index 79a09da8..5078a377 100644 --- a/src/components/shortcuts-settings.css +++ b/src/components/shortcuts-settings.css @@ -126,3 +126,52 @@ display: flex; gap: 16px; } + +/* Import/Export */ + +#import-export-container input[type='text'] { + font-family: var(--monospace-font); +} +#import-export-container section { + margin: 8px 0; + background-color: var(--bg-faded-color); + border-radius: 16px; + padding: 8px; +} +#import-export-container section h3 { + margin: 0 0 8px; +} +#import-export-container section h3 * { + vertical-align: middle; +} +#import-export-container section p { + margin: 8px 0; +} +#import-export-container section details > summary { + cursor: pointer; +} +#import-export-container .import-settings-list { + border-radius: 8px; + overflow: hidden; + margin: 8px 0 0; + padding: 0; + counter-reset: index; +} +#import-export-container .import-settings-list li { + background-color: var(--bg-blur-color); + margin: 0 0 2px; + padding: 8px 4px; + display: flex; + gap: 4px; +} +#import-export-container .import-settings-list li::before { + content: counter(index); + counter-increment: index; + display: inline-block; + width: 1.2em; + text-align: right; + margin-right: 8px; + color: var(--text-insignificant-color); + font-size: 90%; + flex-shrink: 0; +} diff --git a/src/components/shortcuts-settings.jsx b/src/components/shortcuts-settings.jsx index fdb19115..586c773d 100644 --- a/src/components/shortcuts-settings.jsx +++ b/src/components/shortcuts-settings.jsx @@ -1,17 +1,23 @@ import './shortcuts-settings.css'; +import { + compressToEncodedURIComponent, + decompressFromEncodedURIComponent, +} from 'lz-string'; import mem from 'mem'; -import { useEffect, useRef, useState } from 'preact/hooks'; +import { useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useSnapshot } from 'valtio'; import floatingButtonUrl from '../assets/floating-button.svg'; import multiColumnUrl from '../assets/multi-column.svg'; import tabMenuBarUrl from '../assets/tab-menu-bar.svg'; import { api } from '../utils/api'; +import showToast from '../utils/show-toast'; import states from '../utils/states'; import AsyncText from './AsyncText'; import Icon from './icon'; +import MenuConfirm from './menu-confirm'; import Modal from './modal'; const SHORTCUTS_LIMIT = 9; @@ -202,6 +208,7 @@ function ShortcutsSettings({ onClose }) { const [lists, setLists] = useState([]); const [followedHashtags, setFollowedHashtags] = useState([]); const [showForm, setShowForm] = useState(false); + const [showImportExport, setShowImportExport] = useState(false); useEffect(() => { (async () => { @@ -432,6 +439,10 @@ function ShortcutsSettings({ onClose }) {

)} +

+ {shortcuts.length >= SHORTCUTS_LIMIT && + `Max ${SHORTCUTS_LIMIT} shortcuts`} +

- - {shortcuts.length >= SHORTCUTS_LIMIT && - `Max ${SHORTCUTS_LIMIT} shortcuts`} - + + )} +

+

+ Import/Export{' '} + Shortcuts settings +

+
+
+
+

+ {' '} + Import +

+

+ { + setImportShortcutStr(e.target.value); + }} + /> +

+ {!!parsedImportShortcutStr && + Array.isArray(parsedImportShortcutStr) && ( + <> +

+ {parsedImportShortcutStr.length} shortcut + {parsedImportShortcutStr.length > 1 ? 's' : ''}{' '} + + ({importShortcutStr.length} characters) + +

+
    + {parsedImportShortcutStr.map((shortcut) => ( +
  1. + + // Compare all properties + Object.keys(s).every( + (key) => s[key] === shortcut[key], + ), + ) + ? 1 + : 0, + }} + > + * + + + {TYPE_TEXT[shortcut.type]} + {shortcut.type === 'list' && ' ⚠️'}{' '} + {TYPE_PARAMS[shortcut.type]?.map?.( + ({ text, name, type }) => + shortcut[name] ? ( + <> + {' '} + + ) : null, + )} + +
  2. + ))} +
+

+ * Exists in current settings +
+ + ⚠️ List may not work if it's from a different account. + +

+ + )} + {importUIState === 'error' && ( +

+ ⚠️ Invalid settings format +

+ )} +

+ {hasCurrentSettings && ( + <> + + Only shortcuts that don’t exist in current settings will + be appended. + + } + onClick={() => { + // states.shortcuts = [ + // ...states.shortcuts, + // ...parsedImportShortcutStr, + // ]; + // Append non-unique shortcuts only + const nonUniqueShortcuts = parsedImportShortcutStr.filter( + (shortcut) => + !states.shortcuts.some((s) => + // Compare all properties + Object.keys(s).every( + (key) => s[key] === shortcut[key], + ), + ), + ); + if (!nonUniqueShortcuts.length) { + showToast('No new shortcuts to import'); + return; + } + let newShortcuts = [ + ...states.shortcuts, + ...nonUniqueShortcuts, + ]; + const exceededLimit = newShortcuts.length > SHORTCUTS_LIMIT; + if (exceededLimit) { + // If exceeded, trim it + newShortcuts = newShortcuts.slice(0, SHORTCUTS_LIMIT); + } + states.shortcuts = newShortcuts; + showToast( + exceededLimit + ? `Shortcuts settings imported. Exceeded max ${SHORTCUTS_LIMIT}, so the rest are not imported.` + : 'Shortcuts settings imported', + ); + onClose?.(); + }} + > + + {' '} + + )} + { + states.shortcuts = parsedImportShortcutStr; + showToast('Shortcuts settings imported'); + onClose?.(); + }} + > + + +

+
+
+

+ {' '} + Export +

+

+ { + e.target.select(); + // Copy url to clipboard + try { + navigator.clipboard.writeText(e.target.value); + showToast('Shortcuts settings copied'); + } catch (e) { + console.error(e); + showToast('Unable to copy shortcuts settings'); + } + }} + /> +

+

+ {' '} + {navigator?.share && + navigator?.canShare?.({ + text: shortcutsStr, + }) && ( + + )}{' '} + {shortcutsStr.length > 0 && ( + + {shortcutsStr.length} characters + + )} +

+
+ + Raw Shortcuts settings JSON + + +
+
+
+ + ); +} + export default ShortcutsSettings; diff --git a/src/index.css b/src/index.css index 8a4af70f..d65914e0 100644 --- a/src/index.css +++ b/src/index.css @@ -11,6 +11,8 @@ --main-width: 40em; text-size-adjust: none; --hairline-width: 1px; + --monospace-font: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', + Menlo, Courier, monospace; --blue-color: royalblue; --purple-color: blueviolet; @@ -288,6 +290,11 @@ button.large { padding: 12px; } +:is(input[type='text'], textarea, select).block { + display: block; + width: 100%; +} + button.small { font-size: 90%; padding: 4px 8px; @@ -304,8 +311,7 @@ pre { pre code, code { font-size: 90%; - font-family: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', - Menlo, Courier, monospace; + font-family: var(--monospace-font); } @media (prefers-color-scheme: dark) {