1
Fork 0

Compare commits

...

10 Commits

21 changed files with 875 additions and 166 deletions

View File

@ -18,7 +18,7 @@ Large parts of the original Tildes Extended have been removed for various reason
Some functionality has also been extended more:
* [x] The **Back To Top** button has been separated out into its own feature. It used to be apart of the "Jump To New Comments" one.
* [ ] The **Random Tildes Logo** feature now picks from theme-appropriate logos instead of a regular tilde character. [*WIP](https://gitlab.com/tildes-community/tildes-reextended/issues/7)
* [x] The **Themed Tildes Logo** feature now picks from theme-appropriate logos instead of a regular tilde character.
* [x] The **Jump To New Comment** button now uncollapses comments if the new one is collapsed or is deeper inside a collapsed one.
#### User Labels
@ -27,7 +27,7 @@ Some functionality has also been extended more:
* [x] Specify priority of labels.
* [x] A dropdown with theme-appropriate colors for easy access.
* [x] Pick any hex color you want.
* [ ] Dedicated interface to add, edit, and remove labels. [*WIP](https://gitlab.com/tildes-community/tildes-reextended/issues/1)
* [x] Dedicated interface to add, edit, and remove labels.
### New Functionality
@ -35,8 +35,8 @@ And various new features have been added such as:
* [ ] Hide (and unhide) topics from the topic listing. [*WIP](https://gitlab.com/tildes-community/tildes-reextended/issues/3)
* [x] Hide your own and/or other people's vote counts.
* [ ] Anonymize usernames. [*WIP](https://gitlab.com/tildes-community/tildes-reextended/issues/5)
* [ ] Assign unique colors to people's usernames. [*WIP](https://gitlab.com/tildes-community/tildes-reextended/issues/6)
* [x] Anonymize usernames.
* [x] Assign unique colors to people's usernames.
* [x] Export and import your extension settings.
## License

View File

@ -18,6 +18,7 @@
"caret-pos": "^2.0.0",
"debounce": "^1.2.1",
"htm": "^3.1.0",
"migration-helper": "^0.1.2",
"modern-normalize": "^1.1.0",
"platform": "^1.3.6",
"preact": "^10.6.6",
@ -28,14 +29,14 @@
"@types/debounce": "^1.2.1",
"@types/platform": "^1.3.4",
"@types/webextension-polyfill": "^0.8.2",
"postcss": "^8.4.6",
"sass": "^1.49.8",
"stylelint": "^14.5.1",
"postcss": "^8.4.8",
"sass": "^1.49.9",
"stylelint": "^14.5.3",
"stylelint-config-standard-scss": "^3.0.0",
"trash-cli": "^5.0.0",
"typescript": "^4.5.5",
"vite": "^2.8.4",
"vite-plugin-web-extension": "^1.1.2",
"typescript": "^4.6.2",
"vite": "^2.8.6",
"vite-plugin-web-extension": "^1.1.3",
"web-ext": "^6.7.0",
"xo": "^0.48.0"
},

View File

@ -8,17 +8,18 @@ specifiers:
caret-pos: ^2.0.0
debounce: ^1.2.1
htm: ^3.1.0
migration-helper: ^0.1.2
modern-normalize: ^1.1.0
platform: ^1.3.6
postcss: ^8.4.6
postcss: ^8.4.8
preact: ^10.6.6
sass: ^1.49.8
stylelint: ^14.5.1
sass: ^1.49.9
stylelint: ^14.5.3
stylelint-config-standard-scss: ^3.0.0
trash-cli: ^5.0.0
typescript: ^4.5.5
vite: ^2.8.4
vite-plugin-web-extension: ^1.1.2
typescript: ^4.6.2
vite: ^2.8.6
vite-plugin-web-extension: ^1.1.3
web-ext: ^6.7.0
webextension-polyfill: ^0.8.0
xo: ^0.48.0
@ -27,24 +28,25 @@ dependencies:
caret-pos: 2.0.0
debounce: 1.2.1
htm: 3.1.0
migration-helper: 0.1.2
modern-normalize: 1.1.0
platform: 1.3.6
preact: 10.6.6
webextension-polyfill: 0.8.0
devDependencies:
'@preact/preset-vite': 2.1.7_preact@10.6.6+vite@2.8.4
'@preact/preset-vite': 2.1.7_preact@10.6.6+vite@2.8.6
'@types/debounce': 1.2.1
'@types/platform': 1.3.4
'@types/webextension-polyfill': 0.8.2
postcss: 8.4.6
sass: 1.49.8
stylelint: 14.5.2
stylelint-config-standard-scss: 3.0.0_postcss@8.4.6+stylelint@14.5.2
postcss: 8.4.8
sass: 1.49.9
stylelint: 14.5.3
stylelint-config-standard-scss: 3.0.0_postcss@8.4.8+stylelint@14.5.3
trash-cli: 5.0.0
typescript: 4.5.5
vite: 2.8.4_sass@1.49.8
vite-plugin-web-extension: 1.1.2_vite@2.8.4
typescript: 4.6.2
vite: 2.8.6_sass@1.49.9
vite-plugin-web-extension: 1.1.3_vite@2.8.6
web-ext: 6.7.0
xo: 0.48.0
@ -391,20 +393,20 @@ packages:
fastq: 1.13.0
dev: true
/@preact/preset-vite/2.1.7_preact@10.6.6+vite@2.8.4:
/@preact/preset-vite/2.1.7_preact@10.6.6+vite@2.8.6:
resolution: {integrity: sha512-/Ii+aN1Jm8TK5YzDVrj5UOVRZ91F2Nik1P3FbmZyQ5VJAg1ZCkOBBkmLrz9YhiMbbGl+U35yaZNUDMcO8Xlp2g==}
peerDependencies:
'@babel/core': 7.x
vite: 2.x
dependencies:
'@babel/plugin-transform-react-jsx': 7.17.3
'@prefresh/vite': 2.2.8_preact@10.6.6+vite@2.8.4
'@prefresh/vite': 2.2.8_preact@10.6.6+vite@2.8.6
'@rollup/pluginutils': 4.1.2
babel-plugin-transform-hook-names: 1.0.2
debug: 4.3.3
kolorist: 1.5.1
resolve: 1.22.0
vite: 2.8.4_sass@1.49.8
vite: 2.8.6_sass@1.49.9
transitivePeerDependencies:
- preact
- supports-color
@ -426,7 +428,7 @@ packages:
resolution: {integrity: sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A==}
dev: true
/@prefresh/vite/2.2.8_preact@10.6.6+vite@2.8.4:
/@prefresh/vite/2.2.8_preact@10.6.6+vite@2.8.6:
resolution: {integrity: sha512-yGGa+PKPYPTzMlxgQ8aBgxw9K69I8X4iQ0E6KOcIvls96WKqKLLOYZW9SUgCve446jpUXvc9udviPBZjCeZIIQ==}
peerDependencies:
preact: ^10.4.0
@ -438,7 +440,7 @@ packages:
'@prefresh/utils': 1.1.3
'@rollup/pluginutils': 4.1.2
preact: 10.6.6
vite: 2.8.4_sass@1.49.8
vite: 2.8.6_sass@1.49.9
transitivePeerDependencies:
- supports-color
dev: true
@ -542,6 +544,132 @@ packages:
'@types/node': 17.0.19
dev: true
/@typescript-eslint/eslint-plugin/5.15.0_cc54e6b4b042742f55878e58a699999f:
resolution: {integrity: sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.15.0_eslint@8.9.0+typescript@4.6.2
'@typescript-eslint/scope-manager': 5.15.0
'@typescript-eslint/type-utils': 5.15.0_eslint@8.9.0+typescript@4.6.2
'@typescript-eslint/utils': 5.15.0_eslint@8.9.0+typescript@4.6.2
debug: 4.3.3
eslint: 8.9.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
semver: 7.3.5
tsutils: 3.21.0_typescript@4.6.2
typescript: 4.6.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser/5.15.0_eslint@8.9.0+typescript@4.6.2:
resolution: {integrity: sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 5.15.0
'@typescript-eslint/types': 5.15.0
'@typescript-eslint/typescript-estree': 5.15.0_typescript@4.6.2
debug: 4.3.3
eslint: 8.9.0
typescript: 4.6.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/scope-manager/5.15.0:
resolution: {integrity: sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.15.0
'@typescript-eslint/visitor-keys': 5.15.0
dev: true
/@typescript-eslint/type-utils/5.15.0_eslint@8.9.0+typescript@4.6.2:
resolution: {integrity: sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.15.0_eslint@8.9.0+typescript@4.6.2
debug: 4.3.3
eslint: 8.9.0
tsutils: 3.21.0_typescript@4.6.2
typescript: 4.6.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/types/5.15.0:
resolution: {integrity: sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree/5.15.0_typescript@4.6.2:
resolution: {integrity: sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.15.0
'@typescript-eslint/visitor-keys': 5.15.0
debug: 4.3.3
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.5
tsutils: 3.21.0_typescript@4.6.2
typescript: 4.6.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils/5.15.0_eslint@8.9.0+typescript@4.6.2:
resolution: {integrity: sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@types/json-schema': 7.0.9
'@typescript-eslint/scope-manager': 5.15.0
'@typescript-eslint/types': 5.15.0
'@typescript-eslint/typescript-estree': 5.15.0_typescript@4.6.2
eslint: 8.9.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.9.0
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/visitor-keys/5.15.0:
resolution: {integrity: sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.15.0
eslint-visitor-keys: 3.3.0
dev: true
/acorn-jsx/5.3.2_acorn@8.7.0:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -1587,8 +1715,17 @@ packages:
engines: {node: '>=6'}
dev: true
/esbuild-android-arm64/0.14.23:
resolution: {integrity: sha512-k9sXem++mINrZty1v4FVt6nC5BQCFG4K2geCIUUqHNlTdFnuvcqsY7prcKZLFhqVC1rbcJAr9VSUGFL/vD4vsw==}
/esbuild-android-64/0.14.27:
resolution: {integrity: sha512-LuEd4uPuj/16Y8j6kqy3Z2E9vNY9logfq8Tq+oTE2PZVuNs3M1kj5Qd4O95ee66yDGb3isaOCV7sOLDwtMfGaQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-android-arm64/0.14.27:
resolution: {integrity: sha512-E8Ktwwa6vX8q7QeJmg8yepBYXaee50OdQS3BFtEHKrzbV45H4foMOeEE7uqdjGQZFBap5VAqo7pvjlyA92wznQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
@ -1596,8 +1733,8 @@ packages:
dev: true
optional: true
/esbuild-darwin-64/0.14.23:
resolution: {integrity: sha512-lB0XRbtOYYL1tLcYw8BoBaYsFYiR48RPrA0KfA/7RFTr4MV7Bwy/J4+7nLsVnv9FGuQummM3uJ93J3ptaTqFug==}
/esbuild-darwin-64/0.14.27:
resolution: {integrity: sha512-czw/kXl/1ZdenPWfw9jDc5iuIYxqUxgQ/Q+hRd4/3udyGGVI31r29LCViN2bAJgGvQkqyLGVcG03PJPEXQ5i2g==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
@ -1605,8 +1742,8 @@ packages:
dev: true
optional: true
/esbuild-darwin-arm64/0.14.23:
resolution: {integrity: sha512-yat73Z/uJ5tRcfRiI4CCTv0FSnwErm3BJQeZAh+1tIP0TUNh6o+mXg338Zl5EKChD+YGp6PN+Dbhs7qa34RxSw==}
/esbuild-darwin-arm64/0.14.27:
resolution: {integrity: sha512-BEsv2U2U4o672oV8+xpXNxN9bgqRCtddQC6WBh4YhXKDcSZcdNh7+6nS+DM2vu7qWIWNA4JbRG24LUUYXysimQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
@ -1614,8 +1751,8 @@ packages:
dev: true
optional: true
/esbuild-freebsd-64/0.14.23:
resolution: {integrity: sha512-/1xiTjoLuQ+LlbfjJdKkX45qK/M7ARrbLmyf7x3JhyQGMjcxRYVR6Dw81uH3qlMHwT4cfLW4aEVBhP1aNV7VsA==}
/esbuild-freebsd-64/0.14.27:
resolution: {integrity: sha512-7FeiFPGBo+ga+kOkDxtPmdPZdayrSzsV9pmfHxcyLKxu+3oTcajeZlOO1y9HW+t5aFZPiv7czOHM4KNd0tNwCA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
@ -1623,8 +1760,8 @@ packages:
dev: true
optional: true
/esbuild-freebsd-arm64/0.14.23:
resolution: {integrity: sha512-uyPqBU/Zcp6yEAZS4LKj5jEE0q2s4HmlMBIPzbW6cTunZ8cyvjG6YWpIZXb1KK3KTJDe62ltCrk3VzmWHp+iLg==}
/esbuild-freebsd-arm64/0.14.27:
resolution: {integrity: sha512-8CK3++foRZJluOWXpllG5zwAVlxtv36NpHfsbWS7TYlD8S+QruXltKlXToc/5ZNzBK++l6rvRKELu/puCLc7jA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
@ -1632,8 +1769,8 @@ packages:
dev: true
optional: true
/esbuild-linux-32/0.14.23:
resolution: {integrity: sha512-37R/WMkQyUfNhbH7aJrr1uCjDVdnPeTHGeDhZPUNhfoHV0lQuZNCKuNnDvlH/u/nwIYZNdVvz1Igv5rY/zfrzQ==}
/esbuild-linux-32/0.14.27:
resolution: {integrity: sha512-qhNYIcT+EsYSBClZ5QhLzFzV5iVsP1YsITqblSaztr3+ZJUI+GoK8aXHyzKd7/CKKuK93cxEMJPpfi1dfsOfdw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
@ -1641,8 +1778,8 @@ packages:
dev: true
optional: true
/esbuild-linux-64/0.14.23:
resolution: {integrity: sha512-H0gztDP60qqr8zoFhAO64waoN5yBXkmYCElFklpd6LPoobtNGNnDe99xOQm28+fuD75YJ7GKHzp/MLCLhw2+vQ==}
/esbuild-linux-64/0.14.27:
resolution: {integrity: sha512-ESjck9+EsHoTaKWlFKJpPZRN26uiav5gkI16RuI8WBxUdLrrAlYuYSndxxKgEn1csd968BX/8yQZATYf/9+/qg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
@ -1650,8 +1787,8 @@ packages:
dev: true
optional: true
/esbuild-linux-arm/0.14.23:
resolution: {integrity: sha512-x64CEUxi8+EzOAIpCUeuni0bZfzPw/65r8tC5cy5zOq9dY7ysOi5EVQHnzaxS+1NmV+/RVRpmrzGw1QgY2Xpmw==}
/esbuild-linux-arm/0.14.27:
resolution: {integrity: sha512-JnnmgUBdqLQO9hoNZQqNHFWlNpSX82vzB3rYuCJMhtkuaWQEmQz6Lec1UIxJdC38ifEghNTBsF9bbe8dFilnCw==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
@ -1659,8 +1796,8 @@ packages:
dev: true
optional: true
/esbuild-linux-arm64/0.14.23:
resolution: {integrity: sha512-c4MLOIByNHR55n3KoYf9hYDfBRghMjOiHLaoYLhkQkIabb452RWi+HsNgB41sUpSlOAqfpqKPFNg7VrxL3UX9g==}
/esbuild-linux-arm64/0.14.27:
resolution: {integrity: sha512-no6Mi17eV2tHlJnqBHRLekpZ2/VYx+NfGxKcBE/2xOMYwctsanCaXxw4zapvNrGE9X38vefVXLz6YCF8b1EHiQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
@ -1668,8 +1805,8 @@ packages:
dev: true
optional: true
/esbuild-linux-mips64le/0.14.23:
resolution: {integrity: sha512-kHKyKRIAedYhKug2EJpyJxOUj3VYuamOVA1pY7EimoFPzaF3NeY7e4cFBAISC/Av0/tiV0xlFCt9q0HJ68IBIw==}
/esbuild-linux-mips64le/0.14.27:
resolution: {integrity: sha512-NolWP2uOvIJpbwpsDbwfeExZOY1bZNlWE/kVfkzLMsSgqeVcl5YMen/cedRe9mKnpfLli+i0uSp7N+fkKNU27A==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
@ -1677,8 +1814,8 @@ packages:
dev: true
optional: true
/esbuild-linux-ppc64le/0.14.23:
resolution: {integrity: sha512-7ilAiJEPuJJnJp/LiDO0oJm5ygbBPzhchJJh9HsHZzeqO+3PUzItXi+8PuicY08r0AaaOe25LA7sGJ0MzbfBag==}
/esbuild-linux-ppc64le/0.14.27:
resolution: {integrity: sha512-/7dTjDvXMdRKmsSxKXeWyonuGgblnYDn0MI1xDC7J1VQXny8k1qgNp6VmrlsawwnsymSUUiThhkJsI+rx0taNA==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
@ -1686,8 +1823,8 @@ packages:
dev: true
optional: true
/esbuild-linux-riscv64/0.14.23:
resolution: {integrity: sha512-fbL3ggK2wY0D8I5raPIMPhpCvODFE+Bhb5QGtNP3r5aUsRR6TQV+ZBXIaw84iyvKC8vlXiA4fWLGhghAd/h/Zg==}
/esbuild-linux-riscv64/0.14.27:
resolution: {integrity: sha512-D+aFiUzOJG13RhrSmZgrcFaF4UUHpqj7XSKrIiCXIj1dkIkFqdrmqMSOtSs78dOtObWiOrFCDDzB24UyeEiNGg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
@ -1695,8 +1832,8 @@ packages:
dev: true
optional: true
/esbuild-linux-s390x/0.14.23:
resolution: {integrity: sha512-GHMDCyfy7+FaNSO8RJ8KCFsnax8fLUsOrj9q5Gi2JmZMY0Zhp75keb5abTFCq2/Oy6KVcT0Dcbyo/bFb4rIFJA==}
/esbuild-linux-s390x/0.14.27:
resolution: {integrity: sha512-CD/D4tj0U4UQjELkdNlZhQ8nDHU5rBn6NGp47Hiz0Y7/akAY5i0oGadhEIg0WCY/HYVXFb3CsSPPwaKcTOW3bg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
@ -1704,8 +1841,8 @@ packages:
dev: true
optional: true
/esbuild-netbsd-64/0.14.23:
resolution: {integrity: sha512-ovk2EX+3rrO1M2lowJfgMb/JPN1VwVYrx0QPUyudxkxLYrWeBxDKQvc6ffO+kB4QlDyTfdtAURrVzu3JeNdA2g==}
/esbuild-netbsd-64/0.14.27:
resolution: {integrity: sha512-h3mAld69SrO1VoaMpYl3a5FNdGRE/Nqc+E8VtHOag4tyBwhCQXxtvDDOAKOUQexBGca0IuR6UayQ4ntSX5ij1Q==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
@ -1713,8 +1850,8 @@ packages:
dev: true
optional: true
/esbuild-openbsd-64/0.14.23:
resolution: {integrity: sha512-uYYNqbVR+i7k8ojP/oIROAHO9lATLN7H2QeXKt2H310Fc8FJj4y3Wce6hx0VgnJ4k1JDrgbbiXM8rbEgQyg8KA==}
/esbuild-openbsd-64/0.14.27:
resolution: {integrity: sha512-xwSje6qIZaDHXWoPpIgvL+7fC6WeubHHv18tusLYMwL+Z6bEa4Pbfs5IWDtQdHkArtfxEkIZz77944z8MgDxGw==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
@ -1722,8 +1859,8 @@ packages:
dev: true
optional: true
/esbuild-sunos-64/0.14.23:
resolution: {integrity: sha512-hAzeBeET0+SbScknPzS2LBY6FVDpgE+CsHSpe6CEoR51PApdn2IB0SyJX7vGelXzlyrnorM4CAsRyb9Qev4h9g==}
/esbuild-sunos-64/0.14.27:
resolution: {integrity: sha512-/nBVpWIDjYiyMhuqIqbXXsxBc58cBVH9uztAOIfWShStxq9BNBik92oPQPJ57nzWXRNKQUEFWr4Q98utDWz7jg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
@ -1731,8 +1868,8 @@ packages:
dev: true
optional: true
/esbuild-windows-32/0.14.23:
resolution: {integrity: sha512-Kttmi3JnohdaREbk6o9e25kieJR379TsEWF0l39PQVHXq3FR6sFKtVPgY8wk055o6IB+rllrzLnbqOw/UV60EA==}
/esbuild-windows-32/0.14.27:
resolution: {integrity: sha512-Q9/zEjhZJ4trtWhFWIZvS/7RUzzi8rvkoaS9oiizkHTTKd8UxFwn/Mm2OywsAfYymgUYm8+y2b+BKTNEFxUekw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
@ -1740,8 +1877,8 @@ packages:
dev: true
optional: true
/esbuild-windows-64/0.14.23:
resolution: {integrity: sha512-JtIT0t8ymkpl6YlmOl6zoSWL5cnCgyLaBdf/SiU/Eg3C13r0NbHZWNT/RDEMKK91Y6t79kTs3vyRcNZbfu5a8g==}
/esbuild-windows-64/0.14.27:
resolution: {integrity: sha512-b3y3vTSl5aEhWHK66ngtiS/c6byLf6y/ZBvODH1YkBM+MGtVL6jN38FdHUsZasCz9gFwYs/lJMVY9u7GL6wfYg==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
@ -1749,8 +1886,8 @@ packages:
dev: true
optional: true
/esbuild-windows-arm64/0.14.23:
resolution: {integrity: sha512-cTFaQqT2+ik9e4hePvYtRZQ3pqOvKDVNarzql0VFIzhc0tru/ZgdLoXd6epLiKT+SzoSce6V9YJ+nn6RCn6SHw==}
/esbuild-windows-arm64/0.14.27:
resolution: {integrity: sha512-I/reTxr6TFMcR5qbIkwRGvldMIaiBu2+MP0LlD7sOlNXrfqIl9uNjsuxFPGEG4IRomjfQ5q8WT+xlF/ySVkqKg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
@ -1758,31 +1895,32 @@ packages:
dev: true
optional: true
/esbuild/0.14.23:
resolution: {integrity: sha512-XjnIcZ9KB6lfonCa+jRguXyRYcldmkyZ99ieDksqW/C8bnyEX299yA4QH2XcgijCgaddEZePPTgvx/2imsq7Ig==}
/esbuild/0.14.27:
resolution: {integrity: sha512-MZQt5SywZS3hA9fXnMhR22dv0oPGh6QtjJRIYbgL1AeqAoQZE+Qn5ppGYQAoHv/vq827flj4tIJ79Mrdiwk46Q==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
esbuild-android-arm64: 0.14.23
esbuild-darwin-64: 0.14.23
esbuild-darwin-arm64: 0.14.23
esbuild-freebsd-64: 0.14.23
esbuild-freebsd-arm64: 0.14.23
esbuild-linux-32: 0.14.23
esbuild-linux-64: 0.14.23
esbuild-linux-arm: 0.14.23
esbuild-linux-arm64: 0.14.23
esbuild-linux-mips64le: 0.14.23
esbuild-linux-ppc64le: 0.14.23
esbuild-linux-riscv64: 0.14.23
esbuild-linux-s390x: 0.14.23
esbuild-netbsd-64: 0.14.23
esbuild-openbsd-64: 0.14.23
esbuild-sunos-64: 0.14.23
esbuild-windows-32: 0.14.23
esbuild-windows-64: 0.14.23
esbuild-windows-arm64: 0.14.23
esbuild-android-64: 0.14.27
esbuild-android-arm64: 0.14.27
esbuild-darwin-64: 0.14.27
esbuild-darwin-arm64: 0.14.27
esbuild-freebsd-64: 0.14.27
esbuild-freebsd-arm64: 0.14.27
esbuild-linux-32: 0.14.27
esbuild-linux-64: 0.14.27
esbuild-linux-arm: 0.14.27
esbuild-linux-arm64: 0.14.27
esbuild-linux-mips64le: 0.14.27
esbuild-linux-ppc64le: 0.14.27
esbuild-linux-riscv64: 0.14.27
esbuild-linux-s390x: 0.14.27
esbuild-netbsd-64: 0.14.27
esbuild-openbsd-64: 0.14.27
esbuild-sunos-64: 0.14.27
esbuild-windows-32: 0.14.27
esbuild-windows-64: 0.14.27
esbuild-windows-arm64: 0.14.27
dev: true
/escalade/3.1.1:
@ -1819,6 +1957,19 @@ packages:
eslint: 8.9.0
dev: true
/eslint-config-xo-typescript/0.50.0_fc7c666e395dca26d08d6b4005aa0a6a:
resolution: {integrity: sha512-Ru2tXB8y2w9fFHLm4v2AVfY6P81UbfEuDZuxEpeXlfV65Ezlk0xO4nBaT899ojIFkWfr60rP9Ye4CdVUUT1UYg==}
engines: {node: '>=12'}
peerDependencies:
'@typescript-eslint/eslint-plugin': '>=5.8.0'
eslint: '>=8.0.0'
typescript: '>=4.4'
dependencies:
'@typescript-eslint/eslint-plugin': 5.15.0_cc54e6b4b042742f55878e58a699999f
eslint: 8.9.0
typescript: 4.6.2
dev: true
/eslint-config-xo/0.40.0_eslint@8.9.0:
resolution: {integrity: sha512-msI1O0JGxeK2bbExg3U6EGaWKcjhOFzEjwzObywG/DC5GSNZTOyJT+b2l9MZGBeZsVdxfIGwdXTNeWXl8cN9iw==}
engines: {node: '>=12'}
@ -2017,6 +2168,14 @@ packages:
resolution: {integrity: sha512-egHz9A1WG7b8CS0x1P6P/Rj5FqZOjray/VjpJa14tMZalfRKvpE2ONJ3plCM7+PcinmU4tcmbPLv0VtwzSdLVA==}
dev: true
/eslint-scope/5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
dependencies:
esrecurse: 4.3.0
estraverse: 4.3.0
dev: true
/eslint-scope/7.1.1:
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -2206,6 +2365,11 @@ packages:
estraverse: 5.3.0
dev: true
/estraverse/4.3.0:
resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
engines: {node: '>=4.0'}
dev: true
/estraverse/5.3.0:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
@ -3633,6 +3797,10 @@ packages:
picomatch: 2.3.1
dev: true
/migration-helper/0.1.2:
resolution: {integrity: sha512-2ZiOVWqKwGL/hx5xCOXKqfNc7aB6Kz/YC4W/vlVd3v1mmnAl4wQb9jGfBZYnKS8Yc+EBCMYsbAhZJFsqcmqyfg==}
dev: false
/mime-db/1.51.0:
resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==}
engines: {node: '>= 0.6'}
@ -4260,22 +4428,22 @@ packages:
resolution: {integrity: sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=}
dev: true
/postcss-safe-parser/6.0.0_postcss@8.4.6:
/postcss-safe-parser/6.0.0_postcss@8.4.8:
resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.3.3
dependencies:
postcss: 8.4.6
postcss: 8.4.8
dev: true
/postcss-scss/4.0.3_postcss@8.4.6:
/postcss-scss/4.0.3_postcss@8.4.8:
resolution: {integrity: sha512-j4KxzWovfdHsyxwl1BxkUal/O4uirvHgdzMKS1aWJBAV0qh2qj5qAZqpeBfVUYGWv+4iK9Az7SPyZ4fyNju1uA==}
engines: {node: '>=12.0'}
peerDependencies:
postcss: ^8.3.3
dependencies:
postcss: 8.4.6
postcss: 8.4.8
dev: true
/postcss-selector-parser/6.0.9:
@ -4299,6 +4467,15 @@ packages:
source-map-js: 1.0.2
dev: true
/postcss/8.4.8:
resolution: {integrity: sha512-2tXEqGxrjvAO6U+CJzDL2Fk2kPHTv1jQsYkSoMeOis2SsYaXRO2COxTdQp99cYvif9JTXaAk9lYGc3VhJt7JPQ==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.1
picocolors: 1.0.0
source-map-js: 1.0.2
dev: true
/preact/10.6.6:
resolution: {integrity: sha512-dgxpTFV2vs4vizwKohYKkk7g7rmp1wOOcfd4Tz3IB3Wi+ivZzsn/SpeKJhRENSE+n8sUfsAl4S3HiCVT923ABw==}
dev: false
@ -4615,8 +4792,8 @@ packages:
glob: 7.2.0
dev: true
/rollup/2.68.0:
resolution: {integrity: sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==}
/rollup/2.70.1:
resolution: {integrity: sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
@ -4658,8 +4835,8 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: true
/sass/1.49.8:
resolution: {integrity: sha512-NoGOjvDDOU9og9oAxhRnap71QaTjjlzrvLnKecUJ3GxhaQBrV6e7gPuSPF28u1OcVAArVojPAe4ZhOXwwC4tGw==}
/sass/1.49.9:
resolution: {integrity: sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==}
engines: {node: '>=12.0.0'}
hasBin: true
dependencies:
@ -4997,49 +5174,49 @@ packages:
resolution: {integrity: sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=}
dev: true
/stylelint-config-recommended-scss/5.0.2_postcss@8.4.6+stylelint@14.5.2:
/stylelint-config-recommended-scss/5.0.2_postcss@8.4.8+stylelint@14.5.3:
resolution: {integrity: sha512-b14BSZjcwW0hqbzm9b0S/ScN2+3CO3O4vcMNOw2KGf8lfVSwJ4p5TbNEXKwKl1+0FMtgRXZj6DqVUe/7nGnuBg==}
peerDependencies:
stylelint: ^14.0.0
dependencies:
postcss-scss: 4.0.3_postcss@8.4.6
stylelint: 14.5.2
stylelint-config-recommended: 6.0.0_stylelint@14.5.2
stylelint-scss: 4.1.0_stylelint@14.5.2
postcss-scss: 4.0.3_postcss@8.4.8
stylelint: 14.5.3
stylelint-config-recommended: 6.0.0_stylelint@14.5.3
stylelint-scss: 4.1.0_stylelint@14.5.3
transitivePeerDependencies:
- postcss
dev: true
/stylelint-config-recommended/6.0.0_stylelint@14.5.2:
/stylelint-config-recommended/6.0.0_stylelint@14.5.3:
resolution: {integrity: sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw==}
peerDependencies:
stylelint: ^14.0.0
dependencies:
stylelint: 14.5.2
stylelint: 14.5.3
dev: true
/stylelint-config-standard-scss/3.0.0_postcss@8.4.6+stylelint@14.5.2:
/stylelint-config-standard-scss/3.0.0_postcss@8.4.8+stylelint@14.5.3:
resolution: {integrity: sha512-zt3ZbzIbllN1iCmc94e4pDxqpkzeR6CJo5DDXzltshuXr+82B8ylHyMMARNnUYrZH80B7wgY7UkKTYCFM0UUyw==}
peerDependencies:
stylelint: ^14.0.0
dependencies:
stylelint: 14.5.2
stylelint-config-recommended-scss: 5.0.2_postcss@8.4.6+stylelint@14.5.2
stylelint-config-standard: 24.0.0_stylelint@14.5.2
stylelint: 14.5.3
stylelint-config-recommended-scss: 5.0.2_postcss@8.4.8+stylelint@14.5.3
stylelint-config-standard: 24.0.0_stylelint@14.5.3
transitivePeerDependencies:
- postcss
dev: true
/stylelint-config-standard/24.0.0_stylelint@14.5.2:
/stylelint-config-standard/24.0.0_stylelint@14.5.3:
resolution: {integrity: sha512-+RtU7fbNT+VlNbdXJvnjc3USNPZRiRVp/d2DxOF/vBDDTi0kH5RX2Ny6errdtZJH3boO+bmqIYEllEmok4jiuw==}
peerDependencies:
stylelint: ^14.0.0
dependencies:
stylelint: 14.5.2
stylelint-config-recommended: 6.0.0_stylelint@14.5.2
stylelint: 14.5.3
stylelint-config-recommended: 6.0.0_stylelint@14.5.3
dev: true
/stylelint-scss/4.1.0_stylelint@14.5.2:
/stylelint-scss/4.1.0_stylelint@14.5.3:
resolution: {integrity: sha512-BNYTo7MMamhFOlcaAWp2dMpjg6hPyM/FFqfDIYzmYVLMmQJqc8lWRIiTqP4UX5bresj9Vo0dKC6odSh43VP2NA==}
peerDependencies:
stylelint: ^14.0.0
@ -5049,11 +5226,11 @@ packages:
postcss-resolve-nested-selector: 0.1.1
postcss-selector-parser: 6.0.9
postcss-value-parser: 4.2.0
stylelint: 14.5.2
stylelint: 14.5.3
dev: true
/stylelint/14.5.2:
resolution: {integrity: sha512-ZmZhIosMgFgAEe7+F8z4rlJq+12mmqPK0cN3SyNZhMiHZrZzfsd7WJ2WFZ14AMgQFZ61Dn6RYkEy51U/Lg4MQA==}
/stylelint/14.5.3:
resolution: {integrity: sha512-omHETL+kGHR+fCXFK1SkZD/A+emCP9esggAdWEl8GPjTNeyRYj+H6uetRDcU+7E451zwWiUYGVAX+lApsAZgsQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
hasBin: true
dependencies:
@ -5082,10 +5259,10 @@ packages:
normalize-path: 3.0.0
normalize-selector: 0.2.0
picocolors: 1.0.0
postcss: 8.4.6
postcss: 8.4.8
postcss-media-query-parser: 0.2.3
postcss-resolve-nested-selector: 0.1.1
postcss-safe-parser: 6.0.0_postcss@8.4.6
postcss-safe-parser: 6.0.0_postcss@8.4.8
postcss-selector-parser: 6.0.9
postcss-value-parser: 4.2.0
resolve-from: 5.0.0
@ -5263,10 +5440,24 @@ packages:
strip-bom: 3.0.0
dev: true
/tslib/1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib/2.3.1:
resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
dev: true
/tsutils/3.21.0_typescript@4.6.2:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
typescript: 4.6.2
dev: true
/tunnel-agent/0.6.0:
resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=}
dependencies:
@ -5334,8 +5525,8 @@ packages:
resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=}
dev: true
/typescript/4.5.5:
resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==}
/typescript/4.6.2:
resolution: {integrity: sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
@ -5451,13 +5642,13 @@ packages:
extsprintf: 1.3.0
dev: true
/vite-plugin-web-extension/1.1.2_vite@2.8.4:
resolution: {integrity: sha512-41HwvGT1KNonA4/S8nODABJNukc8CgIeQNLPU6pUcNx7KFenOqf7vHh7WUxf9DymA1F3gyX4kGJmkhfByqhmTA==}
/vite-plugin-web-extension/1.1.3_vite@2.8.6:
resolution: {integrity: sha512-5W5WGhUovXRujogzPgrSP6F0A+e2mJwZM+LpsEBVMHOgnTkrGI931kPQe55XNbyWTHbWrKR8+lMcuHPV9BSOdA==}
peerDependencies:
vite: ^2.6
dependencies:
ajv: 8.10.0
vite: 2.8.4_sass@1.49.8
vite: 2.8.6_sass@1.49.9
web-ext: 6.7.0
transitivePeerDependencies:
- '@types/download'
@ -5470,8 +5661,8 @@ packages:
- utf-8-validate
dev: true
/vite/2.8.4_sass@1.49.8:
resolution: {integrity: sha512-GwtOkkaT2LDI82uWZKcrpRQxP5tymLnC7hVHHqNkhFNknYr0hJUlDLfhVRgngJvAy3RwypkDCWtTKn1BjO96Dw==}
/vite/2.8.6_sass@1.49.9:
resolution: {integrity: sha512-e4H0QpludOVKkmOsRyqQ7LTcMUDF3mcgyNU4lmi0B5JUbe0ZxeBBl8VoZ8Y6Rfn9eFKYtdXNPcYK97ZwH+K2ug==}
engines: {node: '>=12.2.0'}
hasBin: true
peerDependencies:
@ -5486,11 +5677,11 @@ packages:
stylus:
optional: true
dependencies:
esbuild: 0.14.23
postcss: 8.4.6
esbuild: 0.14.27
postcss: 8.4.8
resolve: 1.22.0
rollup: 2.68.0
sass: 1.49.8
rollup: 2.70.1
sass: 1.49.9
optionalDependencies:
fsevents: 2.3.2
dev: true
@ -5689,12 +5880,15 @@ packages:
hasBin: true
dependencies:
'@eslint/eslintrc': 1.1.0
'@typescript-eslint/eslint-plugin': 5.15.0_cc54e6b4b042742f55878e58a699999f
'@typescript-eslint/parser': 5.15.0_eslint@8.9.0+typescript@4.6.2
arrify: 3.0.0
cosmiconfig: 7.0.1
define-lazy-prop: 3.0.0
eslint: 8.9.0
eslint-config-prettier: 8.4.0_eslint@8.9.0
eslint-config-xo: 0.40.0_eslint@8.9.0
eslint-config-xo-typescript: 0.50.0_fc7c666e395dca26d08d6b4005aa0a6a
eslint-formatter-pretty: 4.1.0
eslint-import-resolver-webpack: 0.13.2_eslint-plugin-import@2.25.4
eslint-plugin-ava: 13.2.0_eslint@8.9.0
@ -5720,7 +5914,7 @@ packages:
semver: 7.3.5
slash: 4.0.0
to-absolute-glob: 2.0.2
typescript: 4.5.5
typescript: 4.6.2
transitivePeerDependencies:
- supports-color
- webpack
@ -5749,8 +5943,8 @@ packages:
engines: {node: '>=10'}
dev: true
/yargs-parser/21.0.0:
resolution: {integrity: sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==}
/yargs-parser/21.0.1:
resolution: {integrity: sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==}
engines: {node: '>=12'}
dev: true
@ -5777,7 +5971,7 @@ packages:
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.0.0
yargs-parser: 21.0.1
dev: true
/yauzl/2.10.0:

View File

@ -1,5 +1,3 @@
import './scss/scripts.scss';
import {html} from 'htm/preact';
import {render} from 'preact';
@ -11,6 +9,7 @@ import {
runAnonymizeUsernamesFeature,
runHideVotesFeature,
runMarkdownToolbarFeature,
runThemedLogoFeature,
runUsernameColorsFeature,
} from './scripts/exports.js';
import Settings from './settings.js';
@ -48,6 +47,7 @@ async function initialize() {
function startObserver() {
observer.observe(document.body, {
attributes: true,
childList: true,
subtree: true,
});
@ -71,6 +71,12 @@ async function initialize() {
});
}
if (settings.features.themedLogo) {
observerFeatures.push(() => {
runThemedLogoFeature();
});
}
if (settings.features.usernameColors) {
observerFeatures.push(() => {
runUsernameColorsFeature(settings);

View File

@ -3,7 +3,7 @@
"manifest_version": 2,
"name": "Tildes ReExtended",
"description": "An updated and reimagined recreation of Tildes Extended to enhance and improve the experience of Tildes.net.",
"version": "1.0.4",
"version": "1.1.2",
"permissions": [
"downloads",
"storage",
@ -37,7 +37,7 @@
],
"run_at": "document_end",
"css": [
"generated:style.css"
"scss/scripts.scss"
],
"js": [
"content-scripts.ts"

50
source/migrations.ts Normal file
View File

@ -0,0 +1,50 @@
import {Migration} from 'migration-helper';
export const migrations: Array<Migration<string>> = [
{
version: '1.1.2',
async migrate(data: Record<string, any>) {
const migrated: Record<string, any> = {
data: {
hideVotes: data.data.hideVotes as Record<string, boolean>,
knownGroups: data.data.knownGroups as string[],
latestActiveFeatureTab: data.data.latestActiveFeatureTab as string,
},
features: (data.features as Record<string, string>) ?? {},
version: '1.1.2',
};
const userLabels = data.data.userLabels as UserLabel[];
for (const label of userLabels) {
migrated[`userLabel${label.id}`] = label;
}
const usernameColors = data.data.usernameColors as UsernameColor[];
for (const color of usernameColors) {
migrated[`usernameColor${color.id}`] = color;
}
return migrated;
},
},
];
export function deserializeData(data: Record<string, any>): {
userLabels: UserLabel[];
usernameColors: UsernameColor[];
} {
const deserialized: ReturnType<typeof deserializeData> = {
userLabels: [],
usernameColors: [],
};
for (const [key, value] of Object.entries(data)) {
if (key.startsWith('userLabel')) {
deserialized.userLabels.push(value);
} else if (key.startsWith('usernameColor')) {
deserialized.usernameColors.push(value);
}
}
return deserialized;
}

View File

@ -5,5 +5,6 @@ export {BackToTopSetting} from './back-to-top.js';
export {HideVotesSetting} from './hide-votes.js';
export {JumpToNewCommentSetting} from './jump-to-new-comment.js';
export {MarkdownToolbarSetting} from './markdown-toolbar.js';
export {ThemedLogoSetting} from './themed-logo.js';
export {UserLabelsSetting} from './user-labels.js';
export {UsernameColorsSetting} from './username-colors.js';

View File

@ -0,0 +1,14 @@
import {html} from 'htm/preact';
import {Setting, SettingProps} from './index.js';
export function ThemedLogoSetting(props: SettingProps): TRXComponent {
return html`
<${Setting} ...${props}>
<p class="info">
Replaces the Tildes logo in the site header with a dynamic one that uses
the colors of your chosen Tildes theme.
</p>
<//>
`;
}

View File

@ -10,6 +10,10 @@ export function UserLabelsSetting(props: SettingProps): TRXComponent {
person's profile is available, a <code>[+]</code> will be put next to
it. Clicking on that will bring up a dialog to add a new label and
clicking on existing labels will bring up the same dialog to edit them.
<br />
Or you can use the dedicated${' '}
<a href="./user-label-editor.html">User Label Editor</a>
to add, edit, or remove user labels.
</p>
<details>

View File

@ -114,8 +114,18 @@ export class UsernameColorsSetting extends Component<SettingProps, State> {
return html`
<div class="username-colors-editor" key=${id}>
<input style=${style} value=${username} onInput=${usernameHandler} />
<input style=${style} value=${color} onInput=${colorHandler} />
<input
style=${style}
placeholder="Username(s)"
value=${username}
onInput=${usernameHandler}
/>
<input
style=${style}
placeholder="Color"
value=${color}
onInput=${colorHandler}
/>
<button class="button destructive" onClick=${removeHandler}>
Remove
</button>

View File

@ -7,6 +7,7 @@ import {
HideVotesSetting,
JumpToNewCommentSetting,
MarkdownToolbarSetting,
ThemedLogoSetting,
UserLabelsSetting,
UsernameColorsSetting,
} from './components/exports.js';
@ -62,6 +63,13 @@ export const features: Feature[] = [
title: 'Markdown Toolbar',
component: () => MarkdownToolbarSetting,
},
{
availableSince: new Date('2022-02-27'),
index: 0,
key: 'themedLogo',
title: 'Themed Logo',
component: () => ThemedLogoSetting,
},
{
availableSince: new Date('2019-11-10'),
index: 0,

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tildes ReExtended</title>
<link rel="shortcut icon" href="../assets/tildes-reextended-128.png"
type="image/png">
<link rel="stylesheet" href="../scss/modern-normalize.scss">
<link rel="stylesheet" href="../scss/index.scss">
<link rel="stylesheet" href="../scss/user-label-editor.scss">
</head>
<body>
<noscript>
This web extension does not work without JavaScript, sorry. :(
</noscript>
<script type="module" src="./user-label-editor.ts"></script>
</body>
</html>

View File

@ -0,0 +1,241 @@
import {html} from 'htm/preact';
import {Component, render} from 'preact';
import Settings from '../settings.js';
import {
initializeGlobals,
isValidTildesUsername,
log,
} from '../utilities/exports.js';
window.addEventListener('load', async () => {
initializeGlobals();
const settings = await Settings.fromSyncStorage();
render(html`<${App} settings=${settings} />`, document.body);
});
type Props = {
settings: Settings;
};
type State = {
hasUnsavedChanges: boolean;
newLabelUsername: string;
userLabels: UserLabel[];
};
class App extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
hasUnsavedChanges: false,
newLabelUsername: '',
userLabels: props.settings.data.userLabels,
};
}
addNewLabel = () => {
const {newLabelUsername, userLabels} = this.state;
if (!isValidTildesUsername(newLabelUsername)) {
return;
}
const existingUserLabel = userLabels.find(
({username}) => username.toLowerCase() === newLabelUsername.toLowerCase(),
);
let id = 1;
if (userLabels.length > 0) {
id = userLabels.sort((a, b) => b.id - a.id)[0].id + 1;
}
userLabels.push({
color: '#ff00ff',
id,
priority: 0,
text: 'New Label',
username: existingUserLabel?.username ?? newLabelUsername,
});
this.setState({userLabels});
};
onNewUsernameInput = (event: Event) => {
const username = (event.target as HTMLInputElement).value;
this.setState({newLabelUsername: username});
};
editUserLabel = (event: Event, targetId: number, key: keyof UserLabel) => {
const index = this.state.userLabels.findIndex(({id}) => id === targetId);
if (index === -1) {
log(`Tried to edit UserLabel with unknown ID: ${targetId}`);
return;
}
const newValue = (event.target as HTMLInputElement).value;
if (key === 'id' || key === 'priority') {
this.state.userLabels[index][key] = Number(newValue);
} else {
this.state.userLabels[index][key] = newValue;
}
this.setState({
hasUnsavedChanges: true,
userLabels: this.state.userLabels,
});
};
removeUserLabel = (targetId: number) => {
const userLabels = this.state.userLabels.filter(({id}) => id !== targetId);
this.setState({
hasUnsavedChanges: true,
userLabels,
});
};
saveUserLabels = () => {
const {settings} = this.props;
const {userLabels} = this.state;
settings.data.userLabels = userLabels;
void settings.save();
this.setState({hasUnsavedChanges: false});
};
render() {
const {hasUnsavedChanges, newLabelUsername, userLabels} = this.state;
userLabels.sort((a, b) => a.username.localeCompare(b.username));
const labelGroups: Map<string, UserLabel[]> = new Map();
for (const label of userLabels) {
const group = labelGroups.get(label.username) ?? [];
group.push(label);
labelGroups.set(label.username, group);
}
const labels: TRXComponent[] = [];
for (const [username, group] of labelGroups) {
group.sort((a, b) =>
a.priority === b.priority
? a.text.localeCompare(b.text)
: b.priority - a.priority,
);
const labelPreviews: TRXComponent[] = group.map(
({color, text}) => html`
<span style=${{background: color}} class="label-preview">
${text}
</span>
`,
);
group.sort((a, b) => a.id - b.id);
const userLabels: TRXComponent[] = [];
for (const [index, label] of group.entries()) {
const textHandler = (event: Event) => {
this.editUserLabel(event, label.id, 'text');
};
const colorHandler = (event: Event) => {
this.editUserLabel(event, label.id, 'color');
};
const priorityHandler = (event: Event) => {
this.editUserLabel(event, label.id, 'priority');
};
const removeHandler = () => {
this.removeUserLabel(label.id);
};
userLabels.push(
html`
<li key=${label.id}>
<div>
${index === 0 ? html`<label>Text</label>` : undefined}
<input
onInput=${textHandler}
placeholder="Text"
value=${label.text}
/>
</div>
<div>
${index === 0 ? html`<label>Color</label>` : undefined}
<input
onInput=${colorHandler}
placeholder="Color"
value=${label.color}
/>
</div>
<div>
${index === 0 ? html`<label>Priority</label>` : undefined}
<input
onInput=${priorityHandler}
placeholder="Priority"
type="number"
value=${label.priority}
/>
</div>
<div>
${index === 0 ? html`<label>Controls</label>` : undefined}
<button class="button destructive" onClick=${removeHandler}>
Remove
</button>
</div>
</li>
`,
);
}
labels.push(html`
<div class="group">
<h2>${username} ${labelPreviews}</h2>
<ul>
${userLabels}
</ul>
</div>
`);
}
return html`
<header class="page-header">
<h1>
<img src="/assets/tildes-reextended-128.png" />
User Label Editor
</h1>
</header>
<main class="page-main user-label-editor">
<p class="info">
To add a new label, enter the username for who you'd like to add the
label for, then press the Add New Label button.
<br />
<b>Changes are not automatically saved!</b>
<br />
If there are any unsaved changes an asterisk will appear in the Save
All Changes button. To undo all unsaved changes simply refresh the
page.
</p>
<div class="main-controls">
<input
onInput=${this.onNewUsernameInput}
placeholder="Username"
value=${newLabelUsername}
/>
<button class="button" onClick=${this.addNewLabel}>
Add New Label
</button>
<button class="button" onClick=${this.saveUserLabels}>
Save All Changes${hasUnsavedChanges ? '*' : ''}
</button>
</div>
<div class="groups">${labels}</div>
</main>
`;
}
}

View File

@ -4,5 +4,6 @@ export * from './back-to-top.js';
export * from './hide-votes.js';
export * from './jump-to-new-comment.js';
export * from './markdown-toolbar.js';
export * from './themed-logo.js';
export * from './user-labels.js';
export * from './username-colors.js';

View File

@ -0,0 +1,38 @@
import {log, querySelector} from '../utilities/exports.js';
export function runThemedLogoFeature() {
themedLogo();
log('Themed Logo: Initialized.');
}
const tildesLogo = `
<svg xmlns="http://www.w3.org/2000/svg" width="32px" height="32px" viewBox="0 0 100 100">
<rect fill="var(--background-primary-color)" width="100" height="100"/>
<rect fill="var(--comment-label-joke-color)" width="12.5" height="12.5" x="0" y="50"/>
<rect fill="var(--comment-label-offtopic-color)" width="12.5" height="12.5" x="12.5" y="37.5"/>
<rect fill="var(--comment-label-exemplary-color)" width="12.5" height="12.5" x="25" y="25"/>
<rect fill="var(--stripe-mine-color)" width="12.5" height="12.5" x="37.5" y="37.5"/>
<rect fill="var(--button-used-color)" width="12.5" height="12.5" x="50" y="50"/>
<rect fill="var(--comment-label-malice-color)" width="12.5" height="12.5" x="62.5" y="62.5"/>
<rect fill="var(--alert-color)" width="12.5" height="12.5" x="75" y="50"/>
<rect fill="var(--comment-label-noise-color)" width="12.5" height="12.5" x="87.5" y="37.5"/>
</svg>
`;
function themedLogo() {
let themedLogo = tildesLogo;
for (const customProperty of tildesLogo.match(/var\(--.+\)/g) ?? []) {
let color = window
.getComputedStyle(document.body)
.getPropertyValue(customProperty.slice('var('.length, -1));
if (color === '') {
color = '#f0f';
}
themedLogo = themedLogo.replace(customProperty, color);
}
const encodedSvg = encodeURIComponent(themedLogo);
const siteHeader = querySelector<HTMLElement>('.site-header-logo');
siteHeader.style.backgroundImage = `url("data:image/svg+xml,${encodedSvg}")`;
}

21
source/scss/_button.scss Normal file
View File

@ -0,0 +1,21 @@
@mixin button {
--button-color: var(--blue);
--button-color-alt: var(--dark-blue);
background-color: var(--button-color);
border: none;
color: var(--foreground);
font-weight: bold;
min-width: 15rem;
padding: 8px 0;
&:hover {
background-color: var(--button-color-alt);
cursor: pointer;
}
&.destructive {
--button-color: var(--red);
--button-color-alt: var(--dark-red);
}
}

View File

@ -60,25 +60,7 @@
}
.button {
--button-color: var(--blue);
--button-color-alt: var(--dark-blue);
background-color: var(--button-color);
border: none;
color: var(--foreground);
font-weight: bold;
min-width: 15rem;
padding: 8px 0;
&:hover {
background-color: var(--button-color-alt);
cursor: pointer;
}
&.destructive {
--button-color: var(--red);
--button-color-alt: var(--dark-red);
}
@include button;
}
.import-export {

View File

@ -1,6 +1,7 @@
@import 'reset';
@import 'variables';
@import 'colors';
@import 'button';
html {
font-size: 62.5%;
@ -47,7 +48,8 @@ details {
.main-wrapper,
.page-header,
.page-footer {
.page-footer,
.user-label-editor {
margin-left: auto;
margin-right: auto;
width: $large-breakpoint;

View File

@ -0,0 +1,74 @@
@import 'button';
.user-label-editor {
input {
background-color: var(--background-primary);
border: 1px solid var(--blue);
color: var(--foreground);
padding: 8px;
}
.button {
@include button;
}
.info {
border: 1px solid var(--blue);
margin-bottom: 8px;
padding: 8px;
}
.main-controls {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
}
.groups {
display: grid;
gap: 8px;
grid-template-columns: repeat(1, 1fr);
}
.group {
border: 1px solid var(--blue);
padding: 16px;
h2 {
align-items: center;
display: flex;
gap: 8px;
margin-bottom: 16px;
}
input {
width: 100%;
}
label {
background-color: var(--blue);
display: flex;
flex-direction: column;
padding: 4px;
}
li {
display: grid;
gap: 8px;
grid-template-columns: 40% 30% auto auto;
list-style: none;
}
ul {
display: grid;
gap: 8px;
grid-template-columns: repeat(1, 1fr);
}
}
.label-preview {
font-size: 60%;
padding: 4px 8px;
text-shadow: 0 0 2px #000, 0 0 4px #000;
}

View File

@ -1,20 +1,35 @@
import {migrate} from 'migration-helper';
import browser from 'webextension-polyfill';
import {migrations, deserializeData} from './migrations.js';
import {log} from './utilities/exports.js';
export default class Settings {
public static async fromSyncStorage(): Promise<Settings> {
const settings = new Settings();
const defaultsObject = {
data: settings.data,
features: settings.features,
const sync = {
...settings,
...(await browser.storage.sync.get(null)),
};
const sync = (await browser.storage.sync.get(
defaultsObject,
)) as typeof defaultsObject;
settings.data = {...settings.data, ...sync.data};
settings.features = {...settings.features, ...sync.features};
const migrated = (await migrate(
sync,
sync.version ?? settings.version,
migrations,
)) as Record<string, any>;
const deserialized = deserializeData(migrated);
settings.data = migrated.data as Settings['data'];
settings.data.userLabels = deserialized.userLabels;
settings.data.usernameColors = deserialized.usernameColors;
settings.features = migrated.features as Settings['features'];
settings.version = migrated.version as Settings['version'];
if (sync.version !== settings.version) {
await settings.save();
}
return settings;
}
@ -68,10 +83,13 @@ export default class Settings {
hideVotes: boolean;
jumpToNewComment: boolean;
markdownToolbar: boolean;
themedLogo: boolean;
userLabels: boolean;
usernameColors: boolean;
};
public version: string;
private constructor() {
this.data = {
hideVotes: {
@ -131,9 +149,12 @@ export default class Settings {
hideVotes: false,
jumpToNewComment: true,
markdownToolbar: true,
themedLogo: false,
userLabels: true,
usernameColors: false,
};
this.version = '0.0.0';
}
public manifest(): TRXManifest {
@ -145,6 +166,24 @@ export default class Settings {
}
public async save(): Promise<void> {
await browser.storage.sync.set(this);
const sync: Record<string, any> = {
data: {
hideVotes: this.data.hideVotes,
knownGroups: this.data.knownGroups,
latestActiveFeatureTab: this.data.latestActiveFeatureTab,
},
features: this.features,
version: this.version,
};
for (const label of this.data.userLabels) {
sync[`userLabel${label.id}`] = {...label};
}
for (const color of this.data.usernameColors) {
sync[`usernameColor${color.id}`] = {...color};
}
await browser.storage.sync.set(sync);
}
}

View File

@ -18,6 +18,7 @@ export default defineConfig({
plugins: [
preact(),
webExtension({
additionalInputs: ['options/user-label-editor.html'],
assets: 'assets',
browser: 'firefox',
manifest: path.join(sourceDir, 'manifest.json'),