Compare changes

Choose any two refs to compare.

+22
.tangled/workflows/deploy.yml
··· 1 + ## need this for commit idk what else to change 2 + 3 + when: 4 + - event: ["push"] 5 + branch: ["main"] 6 + 7 + engine: "nixery" 8 + 9 + clone: 10 + skip: true 11 + 12 + dependencies: 13 + nixpkgs: 14 + - curl 15 + 16 + steps: 17 + - name: "Trigger Deploy" 18 + command: | 19 + curl -X POST \ 20 + -H "Authorization: Bearer $SCANS_HOST_API_KEY" \ 21 + -H "Authorization: Bearer $SCANS_HOST_API_KEY" \ 22 + https://free.scan.blue/api/v1/sites/jy35AeguTwaqDy_3ufq09/deploy?wait=true
+25
0001-ok.patch
··· 1 + From baf405c82fb23f9274a35384286bac2b901d45af Mon Sep 17 00:00:00 2001 2 + From: scanash00 <scan@scanash.com> 3 + Date: Tue, 30 Dec 2025 22:12:13 -0900 4 + Subject: [PATCH] add ?wait=true 5 + 6 + --- 7 + .tangled/workflows/deploy.yml | 3 ++- 8 + 1 file changed, 2 insertions(+), 1 deletion(-) 9 + 10 + diff --git a/.tangled/workflows/deploy.yml b/.tangled/workflows/deploy.yml 11 + index a44c51b..b7edfea 100644 12 + --- a/.tangled/workflows/deploy.yml 13 + +++ b/.tangled/workflows/deploy.yml 14 + @@ -16,4 +16,5 @@ steps: 15 + command: | 16 + curl -X POST \ 17 + -H "Authorization: Bearer $SCANS_HOST_API_KEY" \ 18 + - https://free.scan.blue/api/v1/sites/jy35AeguTwaqDy_3ufq09/deploy 19 + \ No newline at end of file 20 + + -H "Authorization: Bearer $SCANS_HOST_API_KEY" \ 21 + + https://free.scan.blue/api/v1/sites/YOUR_SITE_ID/deploy?wait=true 22 + \ No newline at end of file 23 + -- 24 + 2.50.1 (Apple Git-155) 25 +
+12 -12
package.json
··· 9 9 "serve": "vite preview" 10 10 }, 11 11 "devDependencies": { 12 - "@iconify-json/lucide": "^1.2.81", 12 + "@iconify-json/lucide": "^1.2.82", 13 13 "@iconify/tailwind4": "^1.2.0", 14 14 "@tailwindcss/vite": "^4.1.18", 15 15 "prettier": "^3.7.4", ··· 17 17 "prettier-plugin-tailwindcss": "^0.7.2", 18 18 "tailwindcss": "^4.1.18", 19 19 "typescript": "^5.9.3", 20 - "vite": "^7.2.7", 20 + "vite": "^7.3.0", 21 21 "vite-plugin-solid": "^2.11.10" 22 22 }, 23 23 "dependencies": { 24 24 "@atcute/atproto": "^3.1.9", 25 25 "@atcute/bluesky": "^3.2.14", 26 - "@atcute/client": "^4.1.1", 26 + "@atcute/client": "^4.1.2", 27 27 "@atcute/crypto": "^2.3.0", 28 - "@atcute/did-plc": "^0.2.0", 28 + "@atcute/did-plc": "^0.3.1", 29 29 "@atcute/identity": "^1.1.3", 30 - "@atcute/identity-resolver": "^1.2.0", 30 + "@atcute/identity-resolver": "^1.2.1", 31 31 "@atcute/leaflet": "^1.0.14", 32 - "@atcute/lexicon-doc": "^2.0.5", 32 + "@atcute/lexicon-doc": "^2.0.6", 33 33 "@atcute/lexicon-resolver": "^0.1.5", 34 - "@atcute/lexicons": "^1.2.5", 34 + "@atcute/lexicons": "^1.2.6", 35 35 "@atcute/multibase": "^1.1.6", 36 36 "@atcute/oauth-browser-client": "^2.0.3", 37 - "@atcute/repo": "^0.1.0", 37 + "@atcute/repo": "^0.1.1", 38 38 "@atcute/tangled": "^1.0.13", 39 - "@atcute/tid": "^1.0.3", 40 - "@codemirror/commands": "^6.10.0", 39 + "@atcute/tid": "^1.1.0", 40 + "@codemirror/commands": "^6.10.1", 41 41 "@codemirror/lang-json": "^6.0.2", 42 42 "@codemirror/lint": "^6.9.2", 43 - "@codemirror/state": "^6.5.2", 44 - "@codemirror/view": "^6.39.4", 43 + "@codemirror/state": "^6.5.3", 44 + "@codemirror/view": "^6.39.7", 45 45 "@fsegurai/codemirror-theme-basic-dark": "^6.2.3", 46 46 "@fsegurai/codemirror-theme-basic-light": "^6.2.3", 47 47 "@mary/exif-rm": "jsr:^0.2.2",
+410 -365
pnpm-lock.yaml
··· 15 15 specifier: ^3.2.14 16 16 version: 3.2.14 17 17 '@atcute/client': 18 - specifier: ^4.1.1 19 - version: 4.1.1 18 + specifier: ^4.1.2 19 + version: 4.1.2 20 20 '@atcute/crypto': 21 21 specifier: ^2.3.0 22 22 version: 2.3.0 23 23 '@atcute/did-plc': 24 - specifier: ^0.2.0 25 - version: 0.2.0 24 + specifier: ^0.3.1 25 + version: 0.3.1 26 26 '@atcute/identity': 27 27 specifier: ^1.1.3 28 28 version: 1.1.3 29 29 '@atcute/identity-resolver': 30 - specifier: ^1.2.0 31 - version: 1.2.0(@atcute/identity@1.1.3) 30 + specifier: ^1.2.1 31 + version: 1.2.1(@atcute/identity@1.1.3) 32 32 '@atcute/leaflet': 33 33 specifier: ^1.0.14 34 34 version: 1.0.14 35 35 '@atcute/lexicon-doc': 36 - specifier: ^2.0.5 37 - version: 2.0.5 36 + specifier: ^2.0.6 37 + version: 2.0.6 38 38 '@atcute/lexicon-resolver': 39 39 specifier: ^0.1.5 40 - version: 0.1.5(@atcute/identity-resolver@1.2.0(@atcute/identity@1.1.3))(@atcute/identity@1.1.3) 40 + version: 0.1.5(@atcute/identity-resolver@1.2.1(@atcute/identity@1.1.3))(@atcute/identity@1.1.3) 41 41 '@atcute/lexicons': 42 - specifier: ^1.2.5 43 - version: 1.2.5 42 + specifier: ^1.2.6 43 + version: 1.2.6 44 44 '@atcute/multibase': 45 45 specifier: ^1.1.6 46 46 version: 1.1.6 ··· 48 48 specifier: ^2.0.3 49 49 version: 2.0.3(@atcute/identity@1.1.3) 50 50 '@atcute/repo': 51 - specifier: ^0.1.0 52 - version: 0.1.0 51 + specifier: ^0.1.1 52 + version: 0.1.1 53 53 '@atcute/tangled': 54 54 specifier: ^1.0.13 55 55 version: 1.0.13 56 56 '@atcute/tid': 57 - specifier: ^1.0.3 58 - version: 1.0.3 57 + specifier: ^1.1.0 58 + version: 1.1.0 59 59 '@codemirror/commands': 60 - specifier: ^6.10.0 61 - version: 6.10.0 60 + specifier: ^6.10.1 61 + version: 6.10.1 62 62 '@codemirror/lang-json': 63 63 specifier: ^6.0.2 64 64 version: 6.0.2 ··· 66 66 specifier: ^6.9.2 67 67 version: 6.9.2 68 68 '@codemirror/state': 69 - specifier: ^6.5.2 70 - version: 6.5.2 69 + specifier: ^6.5.3 70 + version: 6.5.3 71 71 '@codemirror/view': 72 - specifier: ^6.39.4 73 - version: 6.39.4 72 + specifier: ^6.39.7 73 + version: 6.39.7 74 74 '@fsegurai/codemirror-theme-basic-dark': 75 75 specifier: ^6.2.3 76 - version: 6.2.3(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.39.4)(@lezer/highlight@1.2.3) 76 + version: 6.2.3(@codemirror/language@6.12.1)(@codemirror/state@6.5.3)(@codemirror/view@6.39.7)(@lezer/highlight@1.2.3) 77 77 '@fsegurai/codemirror-theme-basic-light': 78 78 specifier: ^6.2.3 79 - version: 6.2.3(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.39.4)(@lezer/highlight@1.2.3) 79 + version: 6.2.3(@codemirror/language@6.12.1)(@codemirror/state@6.5.3)(@codemirror/view@6.39.7)(@lezer/highlight@1.2.3) 80 80 '@mary/exif-rm': 81 81 specifier: jsr:^0.2.2 82 82 version: '@jsr/mary__exif-rm@0.2.2' ··· 97 97 version: 1.9.10 98 98 devDependencies: 99 99 '@iconify-json/lucide': 100 - specifier: ^1.2.81 101 - version: 1.2.81 100 + specifier: ^1.2.82 101 + version: 1.2.82 102 102 '@iconify/tailwind4': 103 103 specifier: ^1.2.0 104 104 version: 1.2.0(tailwindcss@4.1.18) 105 105 '@tailwindcss/vite': 106 106 specifier: ^4.1.18 107 - version: 4.1.18(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 107 + version: 4.1.18(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 108 108 prettier: 109 109 specifier: ^3.7.4 110 110 version: 3.7.4 ··· 121 121 specifier: ^5.9.3 122 122 version: 5.9.3 123 123 vite: 124 - specifier: ^7.2.7 125 - version: 7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 124 + specifier: ^7.3.0 125 + version: 7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 126 126 vite-plugin-solid: 127 127 specifier: ^2.11.10 128 - version: 2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 128 + version: 2.11.10(solid-js@1.9.10)(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 129 129 130 130 packages: 131 131 ··· 147 147 '@atcute/cbor@2.2.8': 148 148 resolution: {integrity: sha512-UzOAN9BuN6JCXgn0ryV8qZuRJUDrNqrbLd6EFM8jc6RYssjRyGRxNy6RZ1NU/07Hd8Tq/0pz8+nQiMu5Zai5uw==} 149 149 150 - '@atcute/cid@2.2.6': 151 - resolution: {integrity: sha512-bTAHHbJ24p+E//V4KCS4xdmd39o211jJswvqQOevj7vk+5IYcgDLx1ryZWZ1sEPOo9x875li/kj5gpKL14RDwQ==} 150 + '@atcute/cid@2.3.0': 151 + resolution: {integrity: sha512-1SRdkTuMs/l5arQ+7Ag0F7JAueZqtzYE0d2gmbkuzi8EPweNU1kYlQs0CE4dSd81YF8PMDTOQty0K2ATq9CW9g==} 152 152 153 - '@atcute/client@4.1.1': 154 - resolution: {integrity: sha512-FROCbTTCeL5u4tO/n72jDEKyKqjdlXMB56Ehve3W/gnnLGCYWvN42sS7tvL1Mgu6sbO3yZwsXKDrmM2No4XpjA==} 153 + '@atcute/client@4.1.2': 154 + resolution: {integrity: sha512-DOJ0hpdBA4QVl4SGUeOUyz5FfYhdjRW1h0XIH9YDgNTipeA0tnUbRs8hWh9Nb7nyn6zMKzO5RpaWyWWWSx9Yxw==} 155 155 156 156 '@atcute/crypto@2.3.0': 157 157 resolution: {integrity: sha512-w5pkJKCjbNMQu+F4JRHbR3ROQyhi1wbn+GSC6WDQamcYHkZmEZk1/eoI354bIQOOfkEM6aFLv718iskrkon4GQ==} 158 158 159 - '@atcute/did-plc@0.2.0': 160 - resolution: {integrity: sha512-1sGek8GRM/Ph7nLVRREm8FqM7g4shGckItvdVwJcRbUa8Rh0zOsXQa0QyYWAC0k40BhkqO9FwKXhJEaXCmF5oQ==} 159 + '@atcute/did-plc@0.3.1': 160 + resolution: {integrity: sha512-KsuVdRtaaIPMmlcCDcxZzLg6OWm7rajczquhIHfA3s57+c34PFQbdY4Lsc2BvDwZ0fUjmbwzvQI3Zio2VcZa7w==} 161 161 162 - '@atcute/identity-resolver@1.2.0': 163 - resolution: {integrity: sha512-5UbSJfdV3JIkF8ksXz7g4nKBWasf2wROvzM66cfvTIWydWFO6/oS1KZd+zo9Eokje5Scf5+jsY9ZfgVARLepXg==} 162 + '@atcute/identity-resolver@1.2.1': 163 + resolution: {integrity: sha512-LqWFFf8D8bqW8l0zUV9oZxcXYZ8+uQTZfjURoxH1TLmtmZFSXredtQHsY70k/iSMNDPxWHJXebdlKxJm5ioNIg==} 164 164 peerDependencies: 165 165 '@atcute/identity': ^1.0.0 166 166 ··· 170 170 '@atcute/leaflet@1.0.14': 171 171 resolution: {integrity: sha512-TWbtB7b73GChBaYwfd7aWFyGVObZ/DqrRtwkpWGm1GO8zZmQ9eJyKDUnXim7NOAs2hmKQ1u2wk2AM4AYzkF5Gg==} 172 172 173 - '@atcute/lexicon-doc@2.0.5': 174 - resolution: {integrity: sha512-fNCp94ehGjWFZMIqP6pWD1F9MOJogNCyqsaMVZluPSIclZ+lDL528iXB56aW4u0eSiD6Y9WJB1OI/lElG39cSA==} 173 + '@atcute/lexicon-doc@2.0.6': 174 + resolution: {integrity: sha512-iDYJkuom+tIw3zIvU1ggCEVFfReXKfOUtIhpY2kEg2kQeSfMB75F+8k1QOpeAQBetyWYmjsHqBuSUX9oQS6L1Q==} 175 175 176 176 '@atcute/lexicon-resolver@0.1.5': 177 177 resolution: {integrity: sha512-0bx1/zdMQPuxvRcHW6ykAxRxktC2rEZLoAVSFoLSWDAA92Tf09F9QPK5wgXSF4MNODm1dvzMEdWSMIvlg8sr3A==} ··· 179 179 '@atcute/identity': ^1.1.0 180 180 '@atcute/identity-resolver': ^1.1.3 181 181 182 - '@atcute/lexicons@1.2.5': 183 - resolution: {integrity: sha512-9yO9WdgxW8jZ7SbzUycH710z+JmsQ9W9n5S6i6eghYju32kkluFmgBeS47r8e8p2+Dv4DemS7o/3SUGsX9FR5Q==} 182 + '@atcute/lexicons@1.2.6': 183 + resolution: {integrity: sha512-s76UQd8D+XmHIzrjD9CJ9SOOeeLPHc+sMmcj7UFakAW/dDFXc579fcRdRfuUKvXBL5v1Gs2VgDdlh/IvvQZAwA==} 184 184 185 - '@atcute/mst@0.1.0': 186 - resolution: {integrity: sha512-h+iDToKEnBpigk2DOHjSqY63vJtjYKUIztqu1CZ0P+I54wV2SrgoqAXAT1xrW6A1Iup8cjTv+U2H5WVG4KxPLw==} 185 + '@atcute/mst@0.1.1': 186 + resolution: {integrity: sha512-NZ/lZ68GOjmAgBSeGf6WHyKM5wo1Hhc7PNt9uwsViswGPMNEEKNj9cw+0YGziXee/Qbnvc+CKqbRSPwruhXFQg==} 187 187 188 188 '@atcute/multibase@1.1.6': 189 189 resolution: {integrity: sha512-HBxuCgYLKPPxETV0Rot4VP9e24vKl8JdzGCZOVsDaOXJgbRZoRIF67Lp0H/OgnJeH/Xpva8Z5ReoTNJE5dn3kg==} ··· 191 191 '@atcute/oauth-browser-client@2.0.3': 192 192 resolution: {integrity: sha512-rzUjwhjE4LRRKdQnCFQag/zXRZMEAB1hhBoLfnoQuHwWbmDUCL7fzwC3jRhDPp3om8XaYNDj8a/iqRip0wRqoQ==} 193 193 194 - '@atcute/repo@0.1.0': 195 - resolution: {integrity: sha512-INiYAuma8dydBu7cqd2WVpcXh3mzhIepYBUqFWAK5MqMulPRLTRCc/9GW3G9pxYrOdlvLCVamG2Jf8XK0nuFEw==} 194 + '@atcute/repo@0.1.1': 195 + resolution: {integrity: sha512-P5aWjt3bvcquUkUmGPslF0naAfLGRHse5Qdz9/RJYrFuoH0iiEMyRnW6M+3ksOe20GPsMnbq71WbzzFkRFPBtg==} 196 196 197 197 '@atcute/tangled@1.0.13': 198 198 resolution: {integrity: sha512-K95jmjDXl/f1FFzOJkk07ibNbFsPmn64sdrMACxQmUibO9WcfSjzjZLPXuH6WHFnCNtIBG3x1FQ7ndQgLoZAmw==} 199 199 200 - '@atcute/tid@1.0.3': 201 - resolution: {integrity: sha512-wfMJx1IMdnu0CZgWl0uR4JO2s6PGT1YPhpytD4ZHzEYKKQVuqV6Eb/7vieaVo1eYNMp2FrY67FZObeR7utRl2w==} 200 + '@atcute/tid@1.1.0': 201 + resolution: {integrity: sha512-U/YKL9BsBi/bcVXaIwdUBfglnjFxRfqoPd2f1uLsEIDQk1EyxepwdDQYOQ5t/aQctmtywl7lQn6KESQNG+mdfg==} 202 + 203 + '@atcute/time-ms@1.0.0': 204 + resolution: {integrity: sha512-iWEOlMBcO3ktB+zQPC2kXka9H/798we+IWq2sjhb+hQJNNfcJrwejzvNi/68Q3jKo/hdfwZjRU9iF8U6D32/2Q==} 202 205 203 206 '@atcute/uint8array@1.0.6': 204 207 resolution: {integrity: sha512-ucfRBQc7BFT8n9eCyGOzDHEMKF/nZwhS2pPao4Xtab1ML3HdFYcX2DM1tadCzas85QTGxHe5urnUAAcNKGRi9A==} ··· 206 209 '@atcute/util-fetch@1.0.4': 207 210 resolution: {integrity: sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg==} 208 211 212 + '@atcute/util-text@0.0.1': 213 + resolution: {integrity: sha512-t1KZqvn0AYy+h2KcJyHnKF9aEqfRfMUmyY8j1ELtAEIgqN9CxINAjxnoRCJIFUlvWzb+oY3uElQL/Vyk3yss0g==} 214 + 209 215 '@atcute/varint@1.0.3': 210 216 resolution: {integrity: sha512-fdvMPyBB+McDT+Ai5e9RwEbwYV4yjZ60S2Dn5PTjGqUyxvoCH1z42viuheDZRUDkmfQehXJTZ5az7dSozVNtog==} 211 217 ··· 297 303 '@codemirror/autocomplete@6.20.0': 298 304 resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} 299 305 300 - '@codemirror/commands@6.10.0': 301 - resolution: {integrity: sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==} 306 + '@codemirror/commands@6.10.1': 307 + resolution: {integrity: sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==} 302 308 303 309 '@codemirror/lang-json@6.0.2': 304 310 resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} 305 311 306 - '@codemirror/language@6.11.3': 307 - resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} 312 + '@codemirror/language@6.12.1': 313 + resolution: {integrity: sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==} 308 314 309 315 '@codemirror/lint@6.9.2': 310 316 resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} ··· 312 318 '@codemirror/search@6.5.11': 313 319 resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} 314 320 315 - '@codemirror/state@6.5.2': 316 - resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==} 321 + '@codemirror/state@6.5.3': 322 + resolution: {integrity: sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==} 317 323 318 - '@codemirror/view@6.39.4': 319 - resolution: {integrity: sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==} 324 + '@codemirror/view@6.39.7': 325 + resolution: {integrity: sha512-3Vif9hnNHJnl2YgOtkR/wzGzhYcQ8gy3LGdUhkLUU8xSBbgsTxrE8he/CMTpeINm5TgxLe2FmzvF6IYQL/BSAg==} 320 326 321 327 '@cyberalien/svg-utils@1.0.11': 322 328 resolution: {integrity: sha512-qEE9mnyI+avfGT3emKuRs3ucYkITeaV0Xi7VlYN41f+uGnZBecQP3jwz/AF437H9J4Q7qPClHKm4NiTYpNE6hA==} ··· 327 333 cpu: [ppc64] 328 334 os: [aix] 329 335 330 - '@esbuild/aix-ppc64@0.25.12': 331 - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 336 + '@esbuild/aix-ppc64@0.27.2': 337 + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} 332 338 engines: {node: '>=18'} 333 339 cpu: [ppc64] 334 340 os: [aix] ··· 339 345 cpu: [arm64] 340 346 os: [android] 341 347 342 - '@esbuild/android-arm64@0.25.12': 343 - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 348 + '@esbuild/android-arm64@0.27.2': 349 + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} 344 350 engines: {node: '>=18'} 345 351 cpu: [arm64] 346 352 os: [android] ··· 351 357 cpu: [arm] 352 358 os: [android] 353 359 354 - '@esbuild/android-arm@0.25.12': 355 - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 360 + '@esbuild/android-arm@0.27.2': 361 + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} 356 362 engines: {node: '>=18'} 357 363 cpu: [arm] 358 364 os: [android] ··· 363 369 cpu: [x64] 364 370 os: [android] 365 371 366 - '@esbuild/android-x64@0.25.12': 367 - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 372 + '@esbuild/android-x64@0.27.2': 373 + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} 368 374 engines: {node: '>=18'} 369 375 cpu: [x64] 370 376 os: [android] ··· 375 381 cpu: [arm64] 376 382 os: [darwin] 377 383 378 - '@esbuild/darwin-arm64@0.25.12': 379 - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 384 + '@esbuild/darwin-arm64@0.27.2': 385 + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} 380 386 engines: {node: '>=18'} 381 387 cpu: [arm64] 382 388 os: [darwin] ··· 387 393 cpu: [x64] 388 394 os: [darwin] 389 395 390 - '@esbuild/darwin-x64@0.25.12': 391 - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 396 + '@esbuild/darwin-x64@0.27.2': 397 + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} 392 398 engines: {node: '>=18'} 393 399 cpu: [x64] 394 400 os: [darwin] ··· 399 405 cpu: [arm64] 400 406 os: [freebsd] 401 407 402 - '@esbuild/freebsd-arm64@0.25.12': 403 - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 408 + '@esbuild/freebsd-arm64@0.27.2': 409 + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} 404 410 engines: {node: '>=18'} 405 411 cpu: [arm64] 406 412 os: [freebsd] ··· 411 417 cpu: [x64] 412 418 os: [freebsd] 413 419 414 - '@esbuild/freebsd-x64@0.25.12': 415 - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 420 + '@esbuild/freebsd-x64@0.27.2': 421 + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} 416 422 engines: {node: '>=18'} 417 423 cpu: [x64] 418 424 os: [freebsd] ··· 423 429 cpu: [arm64] 424 430 os: [linux] 425 431 426 - '@esbuild/linux-arm64@0.25.12': 427 - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 432 + '@esbuild/linux-arm64@0.27.2': 433 + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} 428 434 engines: {node: '>=18'} 429 435 cpu: [arm64] 430 436 os: [linux] ··· 435 441 cpu: [arm] 436 442 os: [linux] 437 443 438 - '@esbuild/linux-arm@0.25.12': 439 - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 444 + '@esbuild/linux-arm@0.27.2': 445 + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} 440 446 engines: {node: '>=18'} 441 447 cpu: [arm] 442 448 os: [linux] ··· 447 453 cpu: [ia32] 448 454 os: [linux] 449 455 450 - '@esbuild/linux-ia32@0.25.12': 451 - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 456 + '@esbuild/linux-ia32@0.27.2': 457 + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} 452 458 engines: {node: '>=18'} 453 459 cpu: [ia32] 454 460 os: [linux] ··· 459 465 cpu: [loong64] 460 466 os: [linux] 461 467 462 - '@esbuild/linux-loong64@0.25.12': 463 - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 468 + '@esbuild/linux-loong64@0.27.2': 469 + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} 464 470 engines: {node: '>=18'} 465 471 cpu: [loong64] 466 472 os: [linux] ··· 471 477 cpu: [mips64el] 472 478 os: [linux] 473 479 474 - '@esbuild/linux-mips64el@0.25.12': 475 - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 480 + '@esbuild/linux-mips64el@0.27.2': 481 + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} 476 482 engines: {node: '>=18'} 477 483 cpu: [mips64el] 478 484 os: [linux] ··· 483 489 cpu: [ppc64] 484 490 os: [linux] 485 491 486 - '@esbuild/linux-ppc64@0.25.12': 487 - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 492 + '@esbuild/linux-ppc64@0.27.2': 493 + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} 488 494 engines: {node: '>=18'} 489 495 cpu: [ppc64] 490 496 os: [linux] ··· 495 501 cpu: [riscv64] 496 502 os: [linux] 497 503 498 - '@esbuild/linux-riscv64@0.25.12': 499 - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 504 + '@esbuild/linux-riscv64@0.27.2': 505 + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} 500 506 engines: {node: '>=18'} 501 507 cpu: [riscv64] 502 508 os: [linux] ··· 507 513 cpu: [s390x] 508 514 os: [linux] 509 515 510 - '@esbuild/linux-s390x@0.25.12': 511 - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 516 + '@esbuild/linux-s390x@0.27.2': 517 + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} 512 518 engines: {node: '>=18'} 513 519 cpu: [s390x] 514 520 os: [linux] ··· 519 525 cpu: [x64] 520 526 os: [linux] 521 527 522 - '@esbuild/linux-x64@0.25.12': 523 - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 528 + '@esbuild/linux-x64@0.27.2': 529 + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} 524 530 engines: {node: '>=18'} 525 531 cpu: [x64] 526 532 os: [linux] 527 533 528 - '@esbuild/netbsd-arm64@0.25.12': 529 - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 534 + '@esbuild/netbsd-arm64@0.27.2': 535 + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} 530 536 engines: {node: '>=18'} 531 537 cpu: [arm64] 532 538 os: [netbsd] ··· 537 543 cpu: [x64] 538 544 os: [netbsd] 539 545 540 - '@esbuild/netbsd-x64@0.25.12': 541 - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 546 + '@esbuild/netbsd-x64@0.27.2': 547 + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} 542 548 engines: {node: '>=18'} 543 549 cpu: [x64] 544 550 os: [netbsd] ··· 549 555 cpu: [arm64] 550 556 os: [openbsd] 551 557 552 - '@esbuild/openbsd-arm64@0.25.12': 553 - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 558 + '@esbuild/openbsd-arm64@0.27.2': 559 + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} 554 560 engines: {node: '>=18'} 555 561 cpu: [arm64] 556 562 os: [openbsd] ··· 561 567 cpu: [x64] 562 568 os: [openbsd] 563 569 564 - '@esbuild/openbsd-x64@0.25.12': 565 - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 570 + '@esbuild/openbsd-x64@0.27.2': 571 + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} 566 572 engines: {node: '>=18'} 567 573 cpu: [x64] 568 574 os: [openbsd] 569 575 570 - '@esbuild/openharmony-arm64@0.25.12': 571 - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 576 + '@esbuild/openharmony-arm64@0.27.2': 577 + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} 572 578 engines: {node: '>=18'} 573 579 cpu: [arm64] 574 580 os: [openharmony] ··· 579 585 cpu: [x64] 580 586 os: [sunos] 581 587 582 - '@esbuild/sunos-x64@0.25.12': 583 - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 588 + '@esbuild/sunos-x64@0.27.2': 589 + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} 584 590 engines: {node: '>=18'} 585 591 cpu: [x64] 586 592 os: [sunos] ··· 591 597 cpu: [arm64] 592 598 os: [win32] 593 599 594 - '@esbuild/win32-arm64@0.25.12': 595 - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 600 + '@esbuild/win32-arm64@0.27.2': 601 + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} 596 602 engines: {node: '>=18'} 597 603 cpu: [arm64] 598 604 os: [win32] ··· 603 609 cpu: [ia32] 604 610 os: [win32] 605 611 606 - '@esbuild/win32-ia32@0.25.12': 607 - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 612 + '@esbuild/win32-ia32@0.27.2': 613 + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} 608 614 engines: {node: '>=18'} 609 615 cpu: [ia32] 610 616 os: [win32] ··· 615 621 cpu: [x64] 616 622 os: [win32] 617 623 618 - '@esbuild/win32-x64@0.25.12': 619 - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 624 + '@esbuild/win32-x64@0.27.2': 625 + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} 620 626 engines: {node: '>=18'} 621 627 cpu: [x64] 622 628 os: [win32] ··· 637 643 '@codemirror/view': ^6.0.0 638 644 '@lezer/highlight': ^1.0.0 639 645 640 - '@iconify-json/lucide@1.2.81': 641 - resolution: {integrity: sha512-6Kz/+SEuD5bkg0KImi0yFem9l6njKp4e1qF1LpQbgRfk7ngsJR/qjlB4y5rM8N1iKiDR/p19cqhmwZxyCWek+w==} 646 + '@iconify-json/lucide@1.2.82': 647 + resolution: {integrity: sha512-fHZWegspOZonl5GNTvOkHsjnTMdSslFh3EzpzUtRyLxO8bOonqk2OTU3hCl0k4VXzViMjqpRK3X1sotnuBXkFA==} 642 648 643 649 '@iconify/tailwind4@1.2.0': 644 650 resolution: {integrity: sha512-+t7XqfojOB0zzZdd8gV7IQZGq1AaIHTlsxMVzagxYR0hAlJCLUD63o3iSlNKRMH3ZR7gZ8y5c9dJ7J431avRbA==} 645 651 peerDependencies: 646 652 tailwindcss: '>= 4.0.0' 647 653 648 - '@iconify/tools@5.0.0': 649 - resolution: {integrity: sha512-GY/FsuNdWA/FbkLqgQ8b1PHFkNvjMeSFWaVJdLldYGHBp0lZ64HJlcS0qzLfglacHTd8zYdfQjF74RxGqyGMgw==} 654 + '@iconify/tools@5.0.1': 655 + resolution: {integrity: sha512-/znhBN9WIpJd9UtKhyEDfRKwNo8rrOy8dShF8bwSZ1i27ukTSHjeS6bmVK4tTYBYriwFhBf70JT6g8GIRwFvbw==} 650 656 651 657 '@iconify/types@2.0.0': 652 658 resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} ··· 673 679 '@jsr/mary__exif-rm@0.2.2': 674 680 resolution: {integrity: sha512-+ZpLaC+1CyqWhH608Sqd6/yTG0pOlokn2tCXha7s1SMQ+GLKo4Nn/PskTeeP9Pt+6gNYSu6ednoSlRvXb2ZGxg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__exif-rm/0.2.2.tgz} 675 681 676 - '@lezer/common@1.4.0': 677 - resolution: {integrity: sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==} 682 + '@lezer/common@1.5.0': 683 + resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==} 678 684 679 685 '@lezer/highlight@1.2.3': 680 686 resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} ··· 691 697 '@noble/secp256k1@3.0.0': 692 698 resolution: {integrity: sha512-NJBaR352KyIvj3t6sgT/+7xrNyF9Xk9QlLSIqUGVUYlsnDTAUqY8LOmwpcgEx4AMJXRITQ5XEVHD+mMaPfr3mg==} 693 699 694 - '@rollup/rollup-android-arm-eabi@4.53.3': 695 - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} 700 + '@rollup/rollup-android-arm-eabi@4.54.0': 701 + resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} 696 702 cpu: [arm] 697 703 os: [android] 698 704 699 - '@rollup/rollup-android-arm64@4.53.3': 700 - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} 705 + '@rollup/rollup-android-arm64@4.54.0': 706 + resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} 701 707 cpu: [arm64] 702 708 os: [android] 703 709 704 - '@rollup/rollup-darwin-arm64@4.53.3': 705 - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} 710 + '@rollup/rollup-darwin-arm64@4.54.0': 711 + resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} 706 712 cpu: [arm64] 707 713 os: [darwin] 708 714 709 - '@rollup/rollup-darwin-x64@4.53.3': 710 - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} 715 + '@rollup/rollup-darwin-x64@4.54.0': 716 + resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} 711 717 cpu: [x64] 712 718 os: [darwin] 713 719 714 - '@rollup/rollup-freebsd-arm64@4.53.3': 715 - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} 720 + '@rollup/rollup-freebsd-arm64@4.54.0': 721 + resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} 716 722 cpu: [arm64] 717 723 os: [freebsd] 718 724 719 - '@rollup/rollup-freebsd-x64@4.53.3': 720 - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} 725 + '@rollup/rollup-freebsd-x64@4.54.0': 726 + resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} 721 727 cpu: [x64] 722 728 os: [freebsd] 723 729 724 - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 725 - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} 730 + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': 731 + resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} 726 732 cpu: [arm] 727 733 os: [linux] 728 734 729 - '@rollup/rollup-linux-arm-musleabihf@4.53.3': 730 - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} 735 + '@rollup/rollup-linux-arm-musleabihf@4.54.0': 736 + resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} 731 737 cpu: [arm] 732 738 os: [linux] 733 739 734 - '@rollup/rollup-linux-arm64-gnu@4.53.3': 735 - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} 740 + '@rollup/rollup-linux-arm64-gnu@4.54.0': 741 + resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} 736 742 cpu: [arm64] 737 743 os: [linux] 738 744 739 - '@rollup/rollup-linux-arm64-musl@4.53.3': 740 - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} 745 + '@rollup/rollup-linux-arm64-musl@4.54.0': 746 + resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} 741 747 cpu: [arm64] 742 748 os: [linux] 743 749 744 - '@rollup/rollup-linux-loong64-gnu@4.53.3': 745 - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} 750 + '@rollup/rollup-linux-loong64-gnu@4.54.0': 751 + resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} 746 752 cpu: [loong64] 747 753 os: [linux] 748 754 749 - '@rollup/rollup-linux-ppc64-gnu@4.53.3': 750 - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} 755 + '@rollup/rollup-linux-ppc64-gnu@4.54.0': 756 + resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} 751 757 cpu: [ppc64] 752 758 os: [linux] 753 759 754 - '@rollup/rollup-linux-riscv64-gnu@4.53.3': 755 - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} 760 + '@rollup/rollup-linux-riscv64-gnu@4.54.0': 761 + resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} 756 762 cpu: [riscv64] 757 763 os: [linux] 758 764 759 - '@rollup/rollup-linux-riscv64-musl@4.53.3': 760 - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} 765 + '@rollup/rollup-linux-riscv64-musl@4.54.0': 766 + resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} 761 767 cpu: [riscv64] 762 768 os: [linux] 763 769 764 - '@rollup/rollup-linux-s390x-gnu@4.53.3': 765 - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} 770 + '@rollup/rollup-linux-s390x-gnu@4.54.0': 771 + resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} 766 772 cpu: [s390x] 767 773 os: [linux] 768 774 769 - '@rollup/rollup-linux-x64-gnu@4.53.3': 770 - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} 775 + '@rollup/rollup-linux-x64-gnu@4.54.0': 776 + resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} 771 777 cpu: [x64] 772 778 os: [linux] 773 779 774 - '@rollup/rollup-linux-x64-musl@4.53.3': 775 - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} 780 + '@rollup/rollup-linux-x64-musl@4.54.0': 781 + resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} 776 782 cpu: [x64] 777 783 os: [linux] 778 784 779 - '@rollup/rollup-openharmony-arm64@4.53.3': 780 - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} 785 + '@rollup/rollup-openharmony-arm64@4.54.0': 786 + resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} 781 787 cpu: [arm64] 782 788 os: [openharmony] 783 789 784 - '@rollup/rollup-win32-arm64-msvc@4.53.3': 785 - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} 790 + '@rollup/rollup-win32-arm64-msvc@4.54.0': 791 + resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} 786 792 cpu: [arm64] 787 793 os: [win32] 788 794 789 - '@rollup/rollup-win32-ia32-msvc@4.53.3': 790 - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} 795 + '@rollup/rollup-win32-ia32-msvc@4.54.0': 796 + resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} 791 797 cpu: [ia32] 792 798 os: [win32] 793 799 794 - '@rollup/rollup-win32-x64-gnu@4.53.3': 795 - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} 800 + '@rollup/rollup-win32-x64-gnu@4.54.0': 801 + resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} 796 802 cpu: [x64] 797 803 os: [win32] 798 804 799 - '@rollup/rollup-win32-x64-msvc@4.53.3': 800 - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} 805 + '@rollup/rollup-win32-x64-msvc@4.54.0': 806 + resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} 801 807 cpu: [x64] 802 808 os: [win32] 803 809 ··· 814 820 peerDependencies: 815 821 solid-js: ^1.8.6 816 822 817 - '@standard-schema/spec@1.0.0': 818 - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} 823 + '@standard-schema/spec@1.1.0': 824 + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} 819 825 820 826 '@tailwindcss/node@4.1.18': 821 827 resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} ··· 922 928 '@types/estree@1.0.8': 923 929 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 924 930 931 + '@types/node@22.19.3': 932 + resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} 933 + 925 934 '@types/node@24.10.1': 926 935 resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} 927 936 ··· 944 953 solid-js: 945 954 optional: true 946 955 947 - baseline-browser-mapping@2.9.7: 948 - resolution: {integrity: sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==} 956 + baseline-browser-mapping@2.9.11: 957 + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} 949 958 hasBin: true 950 959 951 960 boolbase@1.0.0: ··· 956 965 engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 957 966 hasBin: true 958 967 959 - caniuse-lite@1.0.30001760: 960 - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} 968 + caniuse-lite@1.0.30001761: 969 + resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} 961 970 962 971 codemirror@6.0.2: 963 972 resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} ··· 1043 1052 engines: {node: '>=18'} 1044 1053 hasBin: true 1045 1054 1046 - esbuild@0.25.12: 1047 - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 1055 + esbuild@0.27.2: 1056 + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} 1048 1057 engines: {node: '>=18'} 1049 1058 hasBin: true 1050 1059 ··· 1195 1204 mlly@1.8.0: 1196 1205 resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} 1197 1206 1198 - modern-tar@0.7.2: 1199 - resolution: {integrity: sha512-TGG1ZRk1TAQ3neuZwahAHke3rKsSlro+ooMYtjh9sl2gGPVMLMuWiHgwC7im9T5bSM566RSo2Dko56ETgEvZcA==} 1207 + modern-tar@0.7.3: 1208 + resolution: {integrity: sha512-4W79zekKGyYU4JXVmB78DOscMFaJth2gGhgfTl2alWE4rNe3nf4N2pqenQ0rEtIewrnD79M687Ouba3YGTLOvg==} 1200 1209 engines: {node: '>=18.0.0'} 1201 1210 1202 1211 ms@2.1.3: ··· 1214 1223 nanoid@5.1.6: 1215 1224 resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} 1216 1225 engines: {node: ^18 || >=20} 1226 + hasBin: true 1227 + 1228 + node-gyp-build@4.8.4: 1229 + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} 1217 1230 hasBin: true 1218 1231 1219 1232 node-releases@2.0.27: ··· 1318 1331 resolve-pkg-maps@1.0.0: 1319 1332 resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 1320 1333 1321 - rollup@4.53.3: 1322 - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} 1334 + rollup@4.54.0: 1335 + resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} 1323 1336 engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1324 1337 hasBin: true 1325 1338 ··· 1388 1401 ufo@1.6.1: 1389 1402 resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 1390 1403 1404 + undici-types@6.21.0: 1405 + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 1406 + 1391 1407 undici-types@7.16.0: 1392 1408 resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 1393 1409 1394 - update-browserslist-db@1.2.2: 1395 - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} 1410 + unicode-segmenter@0.14.4: 1411 + resolution: {integrity: sha512-pR5VCiCrLrKOL6FRW61jnk9+wyMtKKowq+jyFY9oc6uHbWKhDL4yVRiI4YZPksGMK72Pahh8m0cn/0JvbDDyJg==} 1412 + 1413 + update-browserslist-db@1.2.3: 1414 + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} 1396 1415 hasBin: true 1397 1416 peerDependencies: 1398 1417 browserslist: '>= 4.21.0' ··· 1407 1426 '@testing-library/jest-dom': 1408 1427 optional: true 1409 1428 1410 - vite@7.2.7: 1411 - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} 1429 + vite@7.3.0: 1430 + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} 1412 1431 engines: {node: ^20.19.0 || >=22.12.0} 1413 1432 hasBin: true 1414 1433 peerDependencies: ··· 1474 1493 1475 1494 '@atcute/atproto@3.1.9': 1476 1495 dependencies: 1477 - '@atcute/lexicons': 1.2.5 1496 + '@atcute/lexicons': 1.2.6 1478 1497 1479 1498 '@atcute/bluesky@3.2.14': 1480 1499 dependencies: 1481 1500 '@atcute/atproto': 3.1.9 1482 - '@atcute/lexicons': 1.2.5 1501 + '@atcute/lexicons': 1.2.6 1483 1502 1484 1503 '@atcute/car@3.1.3': 1485 1504 dependencies: 1486 1505 '@atcute/cbor': 2.2.8 1487 - '@atcute/cid': 2.2.6 1506 + '@atcute/cid': 2.3.0 1488 1507 '@atcute/uint8array': 1.0.6 1489 1508 '@atcute/varint': 1.0.3 1490 1509 yocto-queue: 1.2.2 ··· 1492 1511 '@atcute/car@5.0.0': 1493 1512 dependencies: 1494 1513 '@atcute/cbor': 2.2.8 1495 - '@atcute/cid': 2.2.6 1514 + '@atcute/cid': 2.3.0 1496 1515 '@atcute/uint8array': 1.0.6 1497 1516 '@atcute/varint': 1.0.3 1498 1517 1499 1518 '@atcute/cbor@2.2.8': 1500 1519 dependencies: 1501 - '@atcute/cid': 2.2.6 1520 + '@atcute/cid': 2.3.0 1502 1521 '@atcute/multibase': 1.1.6 1503 1522 '@atcute/uint8array': 1.0.6 1504 1523 1505 - '@atcute/cid@2.2.6': 1524 + '@atcute/cid@2.3.0': 1506 1525 dependencies: 1507 1526 '@atcute/multibase': 1.1.6 1508 1527 '@atcute/uint8array': 1.0.6 1509 1528 1510 - '@atcute/client@4.1.1': 1529 + '@atcute/client@4.1.2': 1511 1530 dependencies: 1512 1531 '@atcute/identity': 1.1.3 1513 - '@atcute/lexicons': 1.2.5 1532 + '@atcute/lexicons': 1.2.6 1514 1533 1515 1534 '@atcute/crypto@2.3.0': 1516 1535 dependencies: ··· 1518 1537 '@atcute/uint8array': 1.0.6 1519 1538 '@noble/secp256k1': 3.0.0 1520 1539 1521 - '@atcute/did-plc@0.2.0': 1540 + '@atcute/did-plc@0.3.1': 1522 1541 dependencies: 1523 1542 '@atcute/cbor': 2.2.8 1524 - '@atcute/cid': 2.2.6 1543 + '@atcute/cid': 2.3.0 1525 1544 '@atcute/crypto': 2.3.0 1526 1545 '@atcute/identity': 1.1.3 1527 - '@atcute/lexicons': 1.2.5 1546 + '@atcute/lexicons': 1.2.6 1528 1547 '@atcute/multibase': 1.1.6 1529 1548 '@atcute/uint8array': 1.0.6 1549 + '@atcute/util-fetch': 1.0.4 1530 1550 '@badrap/valita': 0.4.6 1531 1551 1532 - '@atcute/identity-resolver@1.2.0(@atcute/identity@1.1.3)': 1552 + '@atcute/identity-resolver@1.2.1(@atcute/identity@1.1.3)': 1533 1553 dependencies: 1534 1554 '@atcute/identity': 1.1.3 1535 - '@atcute/lexicons': 1.2.5 1555 + '@atcute/lexicons': 1.2.6 1536 1556 '@atcute/util-fetch': 1.0.4 1537 1557 '@badrap/valita': 0.4.6 1538 1558 1539 1559 '@atcute/identity@1.1.3': 1540 1560 dependencies: 1541 - '@atcute/lexicons': 1.2.5 1561 + '@atcute/lexicons': 1.2.6 1542 1562 '@badrap/valita': 0.4.6 1543 1563 1544 1564 '@atcute/leaflet@1.0.14': 1545 1565 dependencies: 1546 1566 '@atcute/atproto': 3.1.9 1547 - '@atcute/lexicons': 1.2.5 1567 + '@atcute/lexicons': 1.2.6 1548 1568 1549 - '@atcute/lexicon-doc@2.0.5': 1569 + '@atcute/lexicon-doc@2.0.6': 1550 1570 dependencies: 1551 1571 '@atcute/identity': 1.1.3 1552 - '@atcute/lexicons': 1.2.5 1572 + '@atcute/lexicons': 1.2.6 1573 + '@atcute/uint8array': 1.0.6 1574 + '@atcute/util-text': 0.0.1 1553 1575 '@badrap/valita': 0.4.6 1554 1576 1555 - '@atcute/lexicon-resolver@0.1.5(@atcute/identity-resolver@1.2.0(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)': 1577 + '@atcute/lexicon-resolver@0.1.5(@atcute/identity-resolver@1.2.1(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)': 1556 1578 dependencies: 1557 1579 '@atcute/crypto': 2.3.0 1558 1580 '@atcute/identity': 1.1.3 1559 - '@atcute/identity-resolver': 1.2.0(@atcute/identity@1.1.3) 1560 - '@atcute/lexicon-doc': 2.0.5 1561 - '@atcute/lexicons': 1.2.5 1562 - '@atcute/repo': 0.1.0 1581 + '@atcute/identity-resolver': 1.2.1(@atcute/identity@1.1.3) 1582 + '@atcute/lexicon-doc': 2.0.6 1583 + '@atcute/lexicons': 1.2.6 1584 + '@atcute/repo': 0.1.1 1563 1585 '@atcute/util-fetch': 1.0.4 1564 1586 '@badrap/valita': 0.4.6 1565 1587 1566 - '@atcute/lexicons@1.2.5': 1588 + '@atcute/lexicons@1.2.6': 1567 1589 dependencies: 1568 - '@standard-schema/spec': 1.0.0 1590 + '@atcute/uint8array': 1.0.6 1591 + '@atcute/util-text': 0.0.1 1592 + '@standard-schema/spec': 1.1.0 1569 1593 esm-env: 1.2.2 1570 1594 1571 - '@atcute/mst@0.1.0': 1595 + '@atcute/mst@0.1.1': 1572 1596 dependencies: 1573 1597 '@atcute/cbor': 2.2.8 1574 - '@atcute/cid': 2.2.6 1598 + '@atcute/cid': 2.3.0 1575 1599 '@atcute/uint8array': 1.0.6 1576 1600 1577 1601 '@atcute/multibase@1.1.6': ··· 1580 1604 1581 1605 '@atcute/oauth-browser-client@2.0.3(@atcute/identity@1.1.3)': 1582 1606 dependencies: 1583 - '@atcute/client': 4.1.1 1584 - '@atcute/identity-resolver': 1.2.0(@atcute/identity@1.1.3) 1585 - '@atcute/lexicons': 1.2.5 1607 + '@atcute/client': 4.1.2 1608 + '@atcute/identity-resolver': 1.2.1(@atcute/identity@1.1.3) 1609 + '@atcute/lexicons': 1.2.6 1586 1610 '@atcute/multibase': 1.1.6 1587 1611 '@atcute/uint8array': 1.0.6 1588 1612 nanoid: 5.1.6 1589 1613 transitivePeerDependencies: 1590 1614 - '@atcute/identity' 1591 1615 1592 - '@atcute/repo@0.1.0': 1616 + '@atcute/repo@0.1.1': 1593 1617 dependencies: 1594 1618 '@atcute/car': 5.0.0 1595 1619 '@atcute/cbor': 2.2.8 1596 - '@atcute/cid': 2.2.6 1620 + '@atcute/cid': 2.3.0 1597 1621 '@atcute/crypto': 2.3.0 1598 - '@atcute/lexicons': 1.2.5 1599 - '@atcute/mst': 0.1.0 1622 + '@atcute/lexicons': 1.2.6 1623 + '@atcute/mst': 0.1.1 1600 1624 '@atcute/uint8array': 1.0.6 1601 1625 1602 1626 '@atcute/tangled@1.0.13': 1603 1627 dependencies: 1604 1628 '@atcute/atproto': 3.1.9 1605 - '@atcute/lexicons': 1.2.5 1629 + '@atcute/lexicons': 1.2.6 1606 1630 1607 - '@atcute/tid@1.0.3': {} 1631 + '@atcute/tid@1.1.0': 1632 + dependencies: 1633 + '@atcute/time-ms': 1.0.0 1634 + 1635 + '@atcute/time-ms@1.0.0': 1636 + dependencies: 1637 + '@types/node': 22.19.3 1638 + node-gyp-build: 4.8.4 1608 1639 1609 1640 '@atcute/uint8array@1.0.6': {} 1610 1641 1611 1642 '@atcute/util-fetch@1.0.4': 1612 1643 dependencies: 1613 1644 '@badrap/valita': 0.4.6 1645 + 1646 + '@atcute/util-text@0.0.1': 1647 + dependencies: 1648 + unicode-segmenter: 0.14.4 1614 1649 1615 1650 '@atcute/varint@1.0.3': {} 1616 1651 ··· 1729 1764 1730 1765 '@codemirror/autocomplete@6.20.0': 1731 1766 dependencies: 1732 - '@codemirror/language': 6.11.3 1733 - '@codemirror/state': 6.5.2 1734 - '@codemirror/view': 6.39.4 1735 - '@lezer/common': 1.4.0 1767 + '@codemirror/language': 6.12.1 1768 + '@codemirror/state': 6.5.3 1769 + '@codemirror/view': 6.39.7 1770 + '@lezer/common': 1.5.0 1736 1771 1737 - '@codemirror/commands@6.10.0': 1772 + '@codemirror/commands@6.10.1': 1738 1773 dependencies: 1739 - '@codemirror/language': 6.11.3 1740 - '@codemirror/state': 6.5.2 1741 - '@codemirror/view': 6.39.4 1742 - '@lezer/common': 1.4.0 1774 + '@codemirror/language': 6.12.1 1775 + '@codemirror/state': 6.5.3 1776 + '@codemirror/view': 6.39.7 1777 + '@lezer/common': 1.5.0 1743 1778 1744 1779 '@codemirror/lang-json@6.0.2': 1745 1780 dependencies: 1746 - '@codemirror/language': 6.11.3 1781 + '@codemirror/language': 6.12.1 1747 1782 '@lezer/json': 1.0.3 1748 1783 1749 - '@codemirror/language@6.11.3': 1784 + '@codemirror/language@6.12.1': 1750 1785 dependencies: 1751 - '@codemirror/state': 6.5.2 1752 - '@codemirror/view': 6.39.4 1753 - '@lezer/common': 1.4.0 1786 + '@codemirror/state': 6.5.3 1787 + '@codemirror/view': 6.39.7 1788 + '@lezer/common': 1.5.0 1754 1789 '@lezer/highlight': 1.2.3 1755 1790 '@lezer/lr': 1.4.5 1756 1791 style-mod: 4.1.3 1757 1792 1758 1793 '@codemirror/lint@6.9.2': 1759 1794 dependencies: 1760 - '@codemirror/state': 6.5.2 1761 - '@codemirror/view': 6.39.4 1795 + '@codemirror/state': 6.5.3 1796 + '@codemirror/view': 6.39.7 1762 1797 crelt: 1.0.6 1763 1798 1764 1799 '@codemirror/search@6.5.11': 1765 1800 dependencies: 1766 - '@codemirror/state': 6.5.2 1767 - '@codemirror/view': 6.39.4 1801 + '@codemirror/state': 6.5.3 1802 + '@codemirror/view': 6.39.7 1768 1803 crelt: 1.0.6 1769 1804 1770 - '@codemirror/state@6.5.2': 1805 + '@codemirror/state@6.5.3': 1771 1806 dependencies: 1772 1807 '@marijn/find-cluster-break': 1.0.2 1773 1808 1774 - '@codemirror/view@6.39.4': 1809 + '@codemirror/view@6.39.7': 1775 1810 dependencies: 1776 - '@codemirror/state': 6.5.2 1811 + '@codemirror/state': 6.5.3 1777 1812 crelt: 1.0.6 1778 1813 style-mod: 4.1.3 1779 1814 w3c-keyname: 2.2.8 ··· 1785 1820 '@esbuild/aix-ppc64@0.23.1': 1786 1821 optional: true 1787 1822 1788 - '@esbuild/aix-ppc64@0.25.12': 1823 + '@esbuild/aix-ppc64@0.27.2': 1789 1824 optional: true 1790 1825 1791 1826 '@esbuild/android-arm64@0.23.1': 1792 1827 optional: true 1793 1828 1794 - '@esbuild/android-arm64@0.25.12': 1829 + '@esbuild/android-arm64@0.27.2': 1795 1830 optional: true 1796 1831 1797 1832 '@esbuild/android-arm@0.23.1': 1798 1833 optional: true 1799 1834 1800 - '@esbuild/android-arm@0.25.12': 1835 + '@esbuild/android-arm@0.27.2': 1801 1836 optional: true 1802 1837 1803 1838 '@esbuild/android-x64@0.23.1': 1804 1839 optional: true 1805 1840 1806 - '@esbuild/android-x64@0.25.12': 1841 + '@esbuild/android-x64@0.27.2': 1807 1842 optional: true 1808 1843 1809 1844 '@esbuild/darwin-arm64@0.23.1': 1810 1845 optional: true 1811 1846 1812 - '@esbuild/darwin-arm64@0.25.12': 1847 + '@esbuild/darwin-arm64@0.27.2': 1813 1848 optional: true 1814 1849 1815 1850 '@esbuild/darwin-x64@0.23.1': 1816 1851 optional: true 1817 1852 1818 - '@esbuild/darwin-x64@0.25.12': 1853 + '@esbuild/darwin-x64@0.27.2': 1819 1854 optional: true 1820 1855 1821 1856 '@esbuild/freebsd-arm64@0.23.1': 1822 1857 optional: true 1823 1858 1824 - '@esbuild/freebsd-arm64@0.25.12': 1859 + '@esbuild/freebsd-arm64@0.27.2': 1825 1860 optional: true 1826 1861 1827 1862 '@esbuild/freebsd-x64@0.23.1': 1828 1863 optional: true 1829 1864 1830 - '@esbuild/freebsd-x64@0.25.12': 1865 + '@esbuild/freebsd-x64@0.27.2': 1831 1866 optional: true 1832 1867 1833 1868 '@esbuild/linux-arm64@0.23.1': 1834 1869 optional: true 1835 1870 1836 - '@esbuild/linux-arm64@0.25.12': 1871 + '@esbuild/linux-arm64@0.27.2': 1837 1872 optional: true 1838 1873 1839 1874 '@esbuild/linux-arm@0.23.1': 1840 1875 optional: true 1841 1876 1842 - '@esbuild/linux-arm@0.25.12': 1877 + '@esbuild/linux-arm@0.27.2': 1843 1878 optional: true 1844 1879 1845 1880 '@esbuild/linux-ia32@0.23.1': 1846 1881 optional: true 1847 1882 1848 - '@esbuild/linux-ia32@0.25.12': 1883 + '@esbuild/linux-ia32@0.27.2': 1849 1884 optional: true 1850 1885 1851 1886 '@esbuild/linux-loong64@0.23.1': 1852 1887 optional: true 1853 1888 1854 - '@esbuild/linux-loong64@0.25.12': 1889 + '@esbuild/linux-loong64@0.27.2': 1855 1890 optional: true 1856 1891 1857 1892 '@esbuild/linux-mips64el@0.23.1': 1858 1893 optional: true 1859 1894 1860 - '@esbuild/linux-mips64el@0.25.12': 1895 + '@esbuild/linux-mips64el@0.27.2': 1861 1896 optional: true 1862 1897 1863 1898 '@esbuild/linux-ppc64@0.23.1': 1864 1899 optional: true 1865 1900 1866 - '@esbuild/linux-ppc64@0.25.12': 1901 + '@esbuild/linux-ppc64@0.27.2': 1867 1902 optional: true 1868 1903 1869 1904 '@esbuild/linux-riscv64@0.23.1': 1870 1905 optional: true 1871 1906 1872 - '@esbuild/linux-riscv64@0.25.12': 1907 + '@esbuild/linux-riscv64@0.27.2': 1873 1908 optional: true 1874 1909 1875 1910 '@esbuild/linux-s390x@0.23.1': 1876 1911 optional: true 1877 1912 1878 - '@esbuild/linux-s390x@0.25.12': 1913 + '@esbuild/linux-s390x@0.27.2': 1879 1914 optional: true 1880 1915 1881 1916 '@esbuild/linux-x64@0.23.1': 1882 1917 optional: true 1883 1918 1884 - '@esbuild/linux-x64@0.25.12': 1919 + '@esbuild/linux-x64@0.27.2': 1885 1920 optional: true 1886 1921 1887 - '@esbuild/netbsd-arm64@0.25.12': 1922 + '@esbuild/netbsd-arm64@0.27.2': 1888 1923 optional: true 1889 1924 1890 1925 '@esbuild/netbsd-x64@0.23.1': 1891 1926 optional: true 1892 1927 1893 - '@esbuild/netbsd-x64@0.25.12': 1928 + '@esbuild/netbsd-x64@0.27.2': 1894 1929 optional: true 1895 1930 1896 1931 '@esbuild/openbsd-arm64@0.23.1': 1897 1932 optional: true 1898 1933 1899 - '@esbuild/openbsd-arm64@0.25.12': 1934 + '@esbuild/openbsd-arm64@0.27.2': 1900 1935 optional: true 1901 1936 1902 1937 '@esbuild/openbsd-x64@0.23.1': 1903 1938 optional: true 1904 1939 1905 - '@esbuild/openbsd-x64@0.25.12': 1940 + '@esbuild/openbsd-x64@0.27.2': 1906 1941 optional: true 1907 1942 1908 - '@esbuild/openharmony-arm64@0.25.12': 1943 + '@esbuild/openharmony-arm64@0.27.2': 1909 1944 optional: true 1910 1945 1911 1946 '@esbuild/sunos-x64@0.23.1': 1912 1947 optional: true 1913 1948 1914 - '@esbuild/sunos-x64@0.25.12': 1949 + '@esbuild/sunos-x64@0.27.2': 1915 1950 optional: true 1916 1951 1917 1952 '@esbuild/win32-arm64@0.23.1': 1918 1953 optional: true 1919 1954 1920 - '@esbuild/win32-arm64@0.25.12': 1955 + '@esbuild/win32-arm64@0.27.2': 1921 1956 optional: true 1922 1957 1923 1958 '@esbuild/win32-ia32@0.23.1': 1924 1959 optional: true 1925 1960 1926 - '@esbuild/win32-ia32@0.25.12': 1961 + '@esbuild/win32-ia32@0.27.2': 1927 1962 optional: true 1928 1963 1929 1964 '@esbuild/win32-x64@0.23.1': 1930 1965 optional: true 1931 1966 1932 - '@esbuild/win32-x64@0.25.12': 1967 + '@esbuild/win32-x64@0.27.2': 1933 1968 optional: true 1934 1969 1935 - '@fsegurai/codemirror-theme-basic-dark@6.2.3(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.39.4)(@lezer/highlight@1.2.3)': 1970 + '@fsegurai/codemirror-theme-basic-dark@6.2.3(@codemirror/language@6.12.1)(@codemirror/state@6.5.3)(@codemirror/view@6.39.7)(@lezer/highlight@1.2.3)': 1936 1971 dependencies: 1937 - '@codemirror/language': 6.11.3 1938 - '@codemirror/state': 6.5.2 1939 - '@codemirror/view': 6.39.4 1972 + '@codemirror/language': 6.12.1 1973 + '@codemirror/state': 6.5.3 1974 + '@codemirror/view': 6.39.7 1940 1975 '@lezer/highlight': 1.2.3 1941 1976 1942 - '@fsegurai/codemirror-theme-basic-light@6.2.3(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.39.4)(@lezer/highlight@1.2.3)': 1977 + '@fsegurai/codemirror-theme-basic-light@6.2.3(@codemirror/language@6.12.1)(@codemirror/state@6.5.3)(@codemirror/view@6.39.7)(@lezer/highlight@1.2.3)': 1943 1978 dependencies: 1944 - '@codemirror/language': 6.11.3 1945 - '@codemirror/state': 6.5.2 1946 - '@codemirror/view': 6.39.4 1979 + '@codemirror/language': 6.12.1 1980 + '@codemirror/state': 6.5.3 1981 + '@codemirror/view': 6.39.7 1947 1982 '@lezer/highlight': 1.2.3 1948 1983 1949 - '@iconify-json/lucide@1.2.81': 1984 + '@iconify-json/lucide@1.2.82': 1950 1985 dependencies: 1951 1986 '@iconify/types': 2.0.0 1952 1987 1953 1988 '@iconify/tailwind4@1.2.0(tailwindcss@4.1.18)': 1954 1989 dependencies: 1955 - '@iconify/tools': 5.0.0 1990 + '@iconify/tools': 5.0.1 1956 1991 '@iconify/types': 2.0.0 1957 1992 '@iconify/utils': 3.1.0 1958 1993 tailwindcss: 4.1.18 1959 1994 1960 - '@iconify/tools@5.0.0': 1995 + '@iconify/tools@5.0.1': 1961 1996 dependencies: 1962 1997 '@cyberalien/svg-utils': 1.0.11 1963 1998 '@iconify/types': 2.0.0 1964 1999 '@iconify/utils': 3.1.0 1965 2000 fflate: 0.8.2 1966 - modern-tar: 0.7.2 2001 + modern-tar: 0.7.3 1967 2002 pathe: 2.0.3 1968 2003 svgo: 4.0.0 1969 2004 ··· 1996 2031 1997 2032 '@jsr/mary__exif-rm@0.2.2': {} 1998 2033 1999 - '@lezer/common@1.4.0': {} 2034 + '@lezer/common@1.5.0': {} 2000 2035 2001 2036 '@lezer/highlight@1.2.3': 2002 2037 dependencies: 2003 - '@lezer/common': 1.4.0 2038 + '@lezer/common': 1.5.0 2004 2039 2005 2040 '@lezer/json@1.0.3': 2006 2041 dependencies: 2007 - '@lezer/common': 1.4.0 2042 + '@lezer/common': 1.5.0 2008 2043 '@lezer/highlight': 1.2.3 2009 2044 '@lezer/lr': 1.4.5 2010 2045 2011 2046 '@lezer/lr@1.4.5': 2012 2047 dependencies: 2013 - '@lezer/common': 1.4.0 2048 + '@lezer/common': 1.5.0 2014 2049 2015 2050 '@marijn/find-cluster-break@1.0.2': {} 2016 2051 2017 2052 '@noble/secp256k1@3.0.0': {} 2018 2053 2019 - '@rollup/rollup-android-arm-eabi@4.53.3': 2054 + '@rollup/rollup-android-arm-eabi@4.54.0': 2020 2055 optional: true 2021 2056 2022 - '@rollup/rollup-android-arm64@4.53.3': 2057 + '@rollup/rollup-android-arm64@4.54.0': 2023 2058 optional: true 2024 2059 2025 - '@rollup/rollup-darwin-arm64@4.53.3': 2060 + '@rollup/rollup-darwin-arm64@4.54.0': 2026 2061 optional: true 2027 2062 2028 - '@rollup/rollup-darwin-x64@4.53.3': 2063 + '@rollup/rollup-darwin-x64@4.54.0': 2029 2064 optional: true 2030 2065 2031 - '@rollup/rollup-freebsd-arm64@4.53.3': 2066 + '@rollup/rollup-freebsd-arm64@4.54.0': 2032 2067 optional: true 2033 2068 2034 - '@rollup/rollup-freebsd-x64@4.53.3': 2069 + '@rollup/rollup-freebsd-x64@4.54.0': 2035 2070 optional: true 2036 2071 2037 - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 2072 + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': 2038 2073 optional: true 2039 2074 2040 - '@rollup/rollup-linux-arm-musleabihf@4.53.3': 2075 + '@rollup/rollup-linux-arm-musleabihf@4.54.0': 2041 2076 optional: true 2042 2077 2043 - '@rollup/rollup-linux-arm64-gnu@4.53.3': 2078 + '@rollup/rollup-linux-arm64-gnu@4.54.0': 2044 2079 optional: true 2045 2080 2046 - '@rollup/rollup-linux-arm64-musl@4.53.3': 2081 + '@rollup/rollup-linux-arm64-musl@4.54.0': 2047 2082 optional: true 2048 2083 2049 - '@rollup/rollup-linux-loong64-gnu@4.53.3': 2084 + '@rollup/rollup-linux-loong64-gnu@4.54.0': 2050 2085 optional: true 2051 2086 2052 - '@rollup/rollup-linux-ppc64-gnu@4.53.3': 2087 + '@rollup/rollup-linux-ppc64-gnu@4.54.0': 2053 2088 optional: true 2054 2089 2055 - '@rollup/rollup-linux-riscv64-gnu@4.53.3': 2090 + '@rollup/rollup-linux-riscv64-gnu@4.54.0': 2056 2091 optional: true 2057 2092 2058 - '@rollup/rollup-linux-riscv64-musl@4.53.3': 2093 + '@rollup/rollup-linux-riscv64-musl@4.54.0': 2059 2094 optional: true 2060 2095 2061 - '@rollup/rollup-linux-s390x-gnu@4.53.3': 2096 + '@rollup/rollup-linux-s390x-gnu@4.54.0': 2062 2097 optional: true 2063 2098 2064 - '@rollup/rollup-linux-x64-gnu@4.53.3': 2099 + '@rollup/rollup-linux-x64-gnu@4.54.0': 2065 2100 optional: true 2066 2101 2067 - '@rollup/rollup-linux-x64-musl@4.53.3': 2102 + '@rollup/rollup-linux-x64-musl@4.54.0': 2068 2103 optional: true 2069 2104 2070 - '@rollup/rollup-openharmony-arm64@4.53.3': 2105 + '@rollup/rollup-openharmony-arm64@4.54.0': 2071 2106 optional: true 2072 2107 2073 - '@rollup/rollup-win32-arm64-msvc@4.53.3': 2108 + '@rollup/rollup-win32-arm64-msvc@4.54.0': 2074 2109 optional: true 2075 2110 2076 - '@rollup/rollup-win32-ia32-msvc@4.53.3': 2111 + '@rollup/rollup-win32-ia32-msvc@4.54.0': 2077 2112 optional: true 2078 2113 2079 - '@rollup/rollup-win32-x64-gnu@4.53.3': 2114 + '@rollup/rollup-win32-x64-gnu@4.54.0': 2080 2115 optional: true 2081 2116 2082 - '@rollup/rollup-win32-x64-msvc@4.53.3': 2117 + '@rollup/rollup-win32-x64-msvc@4.54.0': 2083 2118 optional: true 2084 2119 2085 2120 '@skyware/firehose@0.5.2': ··· 2096 2131 dependencies: 2097 2132 solid-js: 1.9.10 2098 2133 2099 - '@standard-schema/spec@1.0.0': {} 2134 + '@standard-schema/spec@1.1.0': {} 2100 2135 2101 2136 '@tailwindcss/node@4.1.18': 2102 2137 dependencies: ··· 2159 2194 '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 2160 2195 '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 2161 2196 2162 - '@tailwindcss/vite@4.1.18(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2))': 2197 + '@tailwindcss/vite@4.1.18(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2))': 2163 2198 dependencies: 2164 2199 '@tailwindcss/node': 4.1.18 2165 2200 '@tailwindcss/oxide': 4.1.18 2166 2201 tailwindcss: 4.1.18 2167 - vite: 7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2202 + vite: 7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2168 2203 2169 2204 '@types/babel__core@7.20.5': 2170 2205 dependencies: ··· 2188 2223 '@babel/types': 7.28.5 2189 2224 2190 2225 '@types/estree@1.0.8': {} 2226 + 2227 + '@types/node@22.19.3': 2228 + dependencies: 2229 + undici-types: 6.21.0 2191 2230 2192 2231 '@types/node@24.10.1': 2193 2232 dependencies: ··· 2212 2251 optionalDependencies: 2213 2252 solid-js: 1.9.10 2214 2253 2215 - baseline-browser-mapping@2.9.7: {} 2254 + baseline-browser-mapping@2.9.11: {} 2216 2255 2217 2256 boolbase@1.0.0: {} 2218 2257 2219 2258 browserslist@4.28.1: 2220 2259 dependencies: 2221 - baseline-browser-mapping: 2.9.7 2222 - caniuse-lite: 1.0.30001760 2260 + baseline-browser-mapping: 2.9.11 2261 + caniuse-lite: 1.0.30001761 2223 2262 electron-to-chromium: 1.5.267 2224 2263 node-releases: 2.0.27 2225 - update-browserslist-db: 1.2.2(browserslist@4.28.1) 2264 + update-browserslist-db: 1.2.3(browserslist@4.28.1) 2226 2265 2227 - caniuse-lite@1.0.30001760: {} 2266 + caniuse-lite@1.0.30001761: {} 2228 2267 2229 2268 codemirror@6.0.2: 2230 2269 dependencies: 2231 2270 '@codemirror/autocomplete': 6.20.0 2232 - '@codemirror/commands': 6.10.0 2233 - '@codemirror/language': 6.11.3 2271 + '@codemirror/commands': 6.10.1 2272 + '@codemirror/language': 6.12.1 2234 2273 '@codemirror/lint': 6.9.2 2235 2274 '@codemirror/search': 6.5.11 2236 - '@codemirror/state': 6.5.2 2237 - '@codemirror/view': 6.39.4 2275 + '@codemirror/state': 6.5.3 2276 + '@codemirror/view': 6.39.7 2238 2277 2239 2278 commander@11.1.0: {} 2240 2279 ··· 2333 2372 '@esbuild/win32-x64': 0.23.1 2334 2373 optional: true 2335 2374 2336 - esbuild@0.25.12: 2375 + esbuild@0.27.2: 2337 2376 optionalDependencies: 2338 - '@esbuild/aix-ppc64': 0.25.12 2339 - '@esbuild/android-arm': 0.25.12 2340 - '@esbuild/android-arm64': 0.25.12 2341 - '@esbuild/android-x64': 0.25.12 2342 - '@esbuild/darwin-arm64': 0.25.12 2343 - '@esbuild/darwin-x64': 0.25.12 2344 - '@esbuild/freebsd-arm64': 0.25.12 2345 - '@esbuild/freebsd-x64': 0.25.12 2346 - '@esbuild/linux-arm': 0.25.12 2347 - '@esbuild/linux-arm64': 0.25.12 2348 - '@esbuild/linux-ia32': 0.25.12 2349 - '@esbuild/linux-loong64': 0.25.12 2350 - '@esbuild/linux-mips64el': 0.25.12 2351 - '@esbuild/linux-ppc64': 0.25.12 2352 - '@esbuild/linux-riscv64': 0.25.12 2353 - '@esbuild/linux-s390x': 0.25.12 2354 - '@esbuild/linux-x64': 0.25.12 2355 - '@esbuild/netbsd-arm64': 0.25.12 2356 - '@esbuild/netbsd-x64': 0.25.12 2357 - '@esbuild/openbsd-arm64': 0.25.12 2358 - '@esbuild/openbsd-x64': 0.25.12 2359 - '@esbuild/openharmony-arm64': 0.25.12 2360 - '@esbuild/sunos-x64': 0.25.12 2361 - '@esbuild/win32-arm64': 0.25.12 2362 - '@esbuild/win32-ia32': 0.25.12 2363 - '@esbuild/win32-x64': 0.25.12 2377 + '@esbuild/aix-ppc64': 0.27.2 2378 + '@esbuild/android-arm': 0.27.2 2379 + '@esbuild/android-arm64': 0.27.2 2380 + '@esbuild/android-x64': 0.27.2 2381 + '@esbuild/darwin-arm64': 0.27.2 2382 + '@esbuild/darwin-x64': 0.27.2 2383 + '@esbuild/freebsd-arm64': 0.27.2 2384 + '@esbuild/freebsd-x64': 0.27.2 2385 + '@esbuild/linux-arm': 0.27.2 2386 + '@esbuild/linux-arm64': 0.27.2 2387 + '@esbuild/linux-ia32': 0.27.2 2388 + '@esbuild/linux-loong64': 0.27.2 2389 + '@esbuild/linux-mips64el': 0.27.2 2390 + '@esbuild/linux-ppc64': 0.27.2 2391 + '@esbuild/linux-riscv64': 0.27.2 2392 + '@esbuild/linux-s390x': 0.27.2 2393 + '@esbuild/linux-x64': 0.27.2 2394 + '@esbuild/netbsd-arm64': 0.27.2 2395 + '@esbuild/netbsd-x64': 0.27.2 2396 + '@esbuild/openbsd-arm64': 0.27.2 2397 + '@esbuild/openbsd-x64': 0.27.2 2398 + '@esbuild/openharmony-arm64': 0.27.2 2399 + '@esbuild/sunos-x64': 0.27.2 2400 + '@esbuild/win32-arm64': 0.27.2 2401 + '@esbuild/win32-ia32': 0.27.2 2402 + '@esbuild/win32-x64': 0.27.2 2364 2403 2365 2404 escalade@3.2.0: {} 2366 2405 ··· 2468 2507 pkg-types: 1.3.1 2469 2508 ufo: 1.6.1 2470 2509 2471 - modern-tar@0.7.2: {} 2510 + modern-tar@0.7.3: {} 2472 2511 2473 2512 ms@2.1.3: {} 2474 2513 ··· 2477 2516 nanoid@3.3.11: {} 2478 2517 2479 2518 nanoid@5.1.6: {} 2519 + 2520 + node-gyp-build@4.8.4: {} 2480 2521 2481 2522 node-releases@2.0.27: {} 2482 2523 ··· 2524 2565 resolve-pkg-maps@1.0.0: 2525 2566 optional: true 2526 2567 2527 - rollup@4.53.3: 2568 + rollup@4.54.0: 2528 2569 dependencies: 2529 2570 '@types/estree': 1.0.8 2530 2571 optionalDependencies: 2531 - '@rollup/rollup-android-arm-eabi': 4.53.3 2532 - '@rollup/rollup-android-arm64': 4.53.3 2533 - '@rollup/rollup-darwin-arm64': 4.53.3 2534 - '@rollup/rollup-darwin-x64': 4.53.3 2535 - '@rollup/rollup-freebsd-arm64': 4.53.3 2536 - '@rollup/rollup-freebsd-x64': 4.53.3 2537 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 2538 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 2539 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 2540 - '@rollup/rollup-linux-arm64-musl': 4.53.3 2541 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 2542 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 2543 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 2544 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 2545 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 2546 - '@rollup/rollup-linux-x64-gnu': 4.53.3 2547 - '@rollup/rollup-linux-x64-musl': 4.53.3 2548 - '@rollup/rollup-openharmony-arm64': 4.53.3 2549 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 2550 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 2551 - '@rollup/rollup-win32-x64-gnu': 4.53.3 2552 - '@rollup/rollup-win32-x64-msvc': 4.53.3 2572 + '@rollup/rollup-android-arm-eabi': 4.54.0 2573 + '@rollup/rollup-android-arm64': 4.54.0 2574 + '@rollup/rollup-darwin-arm64': 4.54.0 2575 + '@rollup/rollup-darwin-x64': 4.54.0 2576 + '@rollup/rollup-freebsd-arm64': 4.54.0 2577 + '@rollup/rollup-freebsd-x64': 4.54.0 2578 + '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 2579 + '@rollup/rollup-linux-arm-musleabihf': 4.54.0 2580 + '@rollup/rollup-linux-arm64-gnu': 4.54.0 2581 + '@rollup/rollup-linux-arm64-musl': 4.54.0 2582 + '@rollup/rollup-linux-loong64-gnu': 4.54.0 2583 + '@rollup/rollup-linux-ppc64-gnu': 4.54.0 2584 + '@rollup/rollup-linux-riscv64-gnu': 4.54.0 2585 + '@rollup/rollup-linux-riscv64-musl': 4.54.0 2586 + '@rollup/rollup-linux-s390x-gnu': 4.54.0 2587 + '@rollup/rollup-linux-x64-gnu': 4.54.0 2588 + '@rollup/rollup-linux-x64-musl': 4.54.0 2589 + '@rollup/rollup-openharmony-arm64': 4.54.0 2590 + '@rollup/rollup-win32-arm64-msvc': 4.54.0 2591 + '@rollup/rollup-win32-ia32-msvc': 4.54.0 2592 + '@rollup/rollup-win32-x64-gnu': 4.54.0 2593 + '@rollup/rollup-win32-x64-msvc': 4.54.0 2553 2594 fsevents: 2.3.3 2554 2595 2555 2596 sax@1.4.3: {} ··· 2614 2655 2615 2656 ufo@1.6.1: {} 2616 2657 2658 + undici-types@6.21.0: {} 2659 + 2617 2660 undici-types@7.16.0: 2618 2661 optional: true 2619 2662 2620 - update-browserslist-db@1.2.2(browserslist@4.28.1): 2663 + unicode-segmenter@0.14.4: {} 2664 + 2665 + update-browserslist-db@1.2.3(browserslist@4.28.1): 2621 2666 dependencies: 2622 2667 browserslist: 4.28.1 2623 2668 escalade: 3.2.0 2624 2669 picocolors: 1.1.1 2625 2670 2626 - vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2671 + vite-plugin-solid@2.11.10(solid-js@1.9.10)(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2627 2672 dependencies: 2628 2673 '@babel/core': 7.28.5 2629 2674 '@types/babel__core': 7.20.5 ··· 2631 2676 merge-anything: 5.1.7 2632 2677 solid-js: 1.9.10 2633 2678 solid-refresh: 0.6.3(solid-js@1.9.10) 2634 - vite: 7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2635 - vitefu: 1.1.1(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 2679 + vite: 7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2680 + vitefu: 1.1.1(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)) 2636 2681 transitivePeerDependencies: 2637 2682 - supports-color 2638 2683 2639 - vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2): 2684 + vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2): 2640 2685 dependencies: 2641 - esbuild: 0.25.12 2686 + esbuild: 0.27.2 2642 2687 fdir: 6.5.0(picomatch@4.0.3) 2643 2688 picomatch: 4.0.3 2644 2689 postcss: 8.5.6 2645 - rollup: 4.53.3 2690 + rollup: 4.54.0 2646 2691 tinyglobby: 0.2.15 2647 2692 optionalDependencies: 2648 2693 '@types/node': 24.10.1 ··· 2651 2696 lightningcss: 1.30.2 2652 2697 tsx: 4.19.2 2653 2698 2654 - vitefu@1.1.1(vite@7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2699 + vitefu@1.1.1(vite@7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2)): 2655 2700 optionalDependencies: 2656 - vite: 7.2.7(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2701 + vite: 7.3.0(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.19.2) 2657 2702 2658 2703 w3c-keyname@2.2.8: {} 2659 2704
+1 -1
src/auth/account.tsx
··· 140 140 > 141 141 <span class="truncate">{sessions[did]?.handle || did}</span> 142 142 <Show when={did === agent()?.sub && sessions[did].signedIn}> 143 - <span class="iconify lucide--check shrink-0 text-green-500 dark:text-green-400"></span> 143 + <span class="iconify lucide--circle-check shrink-0 text-blue-500 dark:text-blue-400"></span> 144 144 </Show> 145 145 <Show when={!sessions[did].signedIn}> 146 146 <span class="iconify lucide--circle-alert shrink-0 text-red-500 dark:text-red-400"></span>
+1 -1
src/auth/login.tsx
··· 49 49 <label for="username" class="hidden"> 50 50 Add account 51 51 </label> 52 - <div class="dark:bg-dark-100 dark:inset-shadow-dark-200 flex grow items-center gap-2 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 inset-shadow-xs focus-within:outline-[1px] focus-within:outline-neutral-600 dark:border-neutral-600 dark:focus-within:outline-neutral-400"> 52 + <div class="dark:bg-dark-100 flex grow items-center gap-2 rounded-lg bg-white px-2 outline-1 outline-neutral-200 focus-within:outline-[1.5px] focus-within:outline-neutral-600 dark:outline-neutral-600 dark:focus-within:outline-neutral-400"> 53 53 <label 54 54 for="username" 55 55 class="iconify lucide--user-round-plus shrink-0 text-neutral-500 dark:text-neutral-400"
+117 -173
src/components/backlinks.tsx
··· 1 1 import * as TID from "@atcute/tid"; 2 2 import { createResource, createSignal, For, onMount, Show } from "solid-js"; 3 - import { 4 - getAllBacklinks, 5 - getDidBacklinks, 6 - getRecordBacklinks, 7 - LinksWithDids, 8 - LinksWithRecords, 9 - } from "../utils/api.js"; 3 + import { getAllBacklinks, getRecordBacklinks, LinksWithRecords } from "../utils/api.js"; 10 4 import { localDateFromTimestamp } from "../utils/date.js"; 11 5 import { Button } from "./button.jsx"; 12 6 13 - type Backlink = { 7 + type BacklinksProps = { 8 + target: string; 9 + collection: string; 10 + path: string; 11 + }; 12 + 13 + type BacklinkEntry = { 14 + collection: string; 14 15 path: string; 15 16 counts: { distinct_dids: number; records: number }; 16 17 }; 17 18 18 - const linksBySource = (links: Record<string, any>) => { 19 - let out: Record<string, Backlink[]> = {}; 19 + const flattenLinks = (links: Record<string, any>): BacklinkEntry[] => { 20 + const entries: BacklinkEntry[] = []; 20 21 Object.keys(links) 21 22 .toSorted() 22 23 .forEach((collection) => { ··· 24 25 Object.keys(paths) 25 26 .toSorted() 26 27 .forEach((path) => { 27 - if (paths[path].records === 0) return; 28 - if (out[collection]) out[collection].push({ path, counts: paths[path] }); 29 - else out[collection] = [{ path, counts: paths[path] }]; 28 + if (paths[path].records > 0) { 29 + entries.push({ collection, path, counts: paths[path] }); 30 + } 30 31 }); 31 32 }); 32 - return out; 33 + return entries; 33 34 }; 34 35 35 - const Backlinks = (props: { target: string }) => { 36 - const fetchBacklinks = async () => { 37 - const res = await getAllBacklinks(props.target); 38 - return linksBySource(res.links); 39 - }; 36 + const BacklinkRecords = (props: BacklinksProps & { cursor?: string }) => { 37 + const [links, setLinks] = createSignal<LinksWithRecords>(); 38 + const [more, setMore] = createSignal(false); 40 39 41 - const [response] = createResource(fetchBacklinks); 42 - 43 - const [show, setShow] = createSignal<{ 44 - collection: string; 45 - path: string; 46 - showDids: boolean; 47 - } | null>(); 40 + onMount(async () => { 41 + const res = await getRecordBacklinks(props.target, props.collection, props.path, props.cursor); 42 + setLinks(res); 43 + }); 48 44 49 45 return ( 50 - <div class="flex w-full flex-col gap-1 text-sm wrap-anywhere"> 51 - <Show 52 - when={response() && Object.keys(response()!).length} 53 - fallback={<p>No backlinks found.</p>} 54 - > 55 - <For each={Object.keys(response()!)}> 56 - {(collection) => ( 57 - <div> 58 - <div class="flex items-center gap-1"> 59 - <span class="iconify lucide--book-text shrink-0"></span> 60 - {collection} 61 - </div> 62 - <For each={response()![collection]}> 63 - {({ path, counts }) => ( 64 - <div class="ml-4.5"> 65 - <div class="flex items-center gap-1"> 66 - <span class="iconify lucide--route shrink-0"></span> 67 - {path.slice(1)} 68 - </div> 69 - <div class="ml-4.5"> 70 - <p> 71 - <button 72 - class="text-blue-400 hover:underline active:underline" 73 - onclick={() => 74 - ( 75 - show()?.collection === collection && 76 - show()?.path === path && 77 - !show()?.showDids 78 - ) ? 79 - setShow(null) 80 - : setShow({ collection, path, showDids: false }) 81 - } 82 - > 83 - {counts.records} record{counts.records < 2 ? "" : "s"} 84 - </button> 85 - {" from "} 86 - <button 87 - class="text-blue-400 hover:underline active:underline" 88 - onclick={() => 89 - ( 90 - show()?.collection === collection && 91 - show()?.path === path && 92 - show()?.showDids 93 - ) ? 94 - setShow(null) 95 - : setShow({ collection, path, showDids: true }) 96 - } 97 - > 98 - {counts.distinct_dids} DID 99 - {counts.distinct_dids < 2 ? "" : "s"} 100 - </button> 101 - </p> 102 - <Show when={show()?.collection === collection && show()?.path === path}> 103 - <Show when={show()?.showDids}> 104 - <p class="w-full font-semibold">Distinct identities</p> 105 - <BacklinkItems 106 - target={props.target} 107 - collection={collection} 108 - path={path} 109 - dids={true} 110 - /> 111 - </Show> 112 - <Show when={!show()?.showDids}> 113 - <p class="w-full font-semibold">Records</p> 114 - <BacklinkItems 115 - target={props.target} 116 - collection={collection} 117 - path={path} 118 - dids={false} 119 - /> 120 - </Show> 121 - </Show> 122 - </div> 123 - </div> 124 - )} 125 - </For> 46 + <Show when={links()} fallback={<p class="px-3 py-2 text-neutral-500">Loadingโ€ฆ</p>}> 47 + <For each={links()!.linking_records}> 48 + {({ did, collection, rkey }) => { 49 + const timestamp = 50 + TID.validate(rkey) ? localDateFromTimestamp(TID.parse(rkey).timestamp / 1000) : null; 51 + return ( 52 + <a 53 + href={`/at://${did}/${collection}/${rkey}`} 54 + class="grid grid-cols-[auto_1fr_auto] items-center gap-x-1 px-2 py-1.5 font-mono text-xs select-none hover:bg-neutral-200/50 active:bg-neutral-200/50 sm:gap-x-3 sm:px-3 dark:hover:bg-neutral-700/50 dark:active:bg-neutral-700/50" 55 + > 56 + <span class="text-blue-500 dark:text-blue-400">{rkey}</span> 57 + <span class="truncate text-neutral-700 dark:text-neutral-300" title={did}> 58 + {did} 59 + </span> 60 + <span class="text-neutral-500 tabular-nums dark:text-neutral-400"> 61 + {timestamp ?? ""} 62 + </span> 63 + </a> 64 + ); 65 + }} 66 + </For> 67 + <Show when={links()?.cursor}> 68 + <Show 69 + when={more()} 70 + fallback={ 71 + <div class="p-2"> 72 + <Button 73 + onClick={() => setMore(true)} 74 + class="dark:hover:bg-dark-200 dark:shadow-dark-700 dark:active:bg-dark-100 box-border flex h-7 w-full items-center justify-center gap-1 rounded border-[0.5px] border-neutral-300 bg-neutral-50 px-2 py-1.5 text-xs shadow-xs select-none hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-700 dark:bg-neutral-800" 75 + > 76 + Load More 77 + </Button> 126 78 </div> 127 - )} 128 - </For> 79 + } 80 + > 81 + <BacklinkRecords 82 + target={props.target} 83 + collection={props.collection} 84 + path={props.path} 85 + cursor={links()!.cursor} 86 + /> 87 + </Show> 129 88 </Show> 130 - </div> 89 + </Show> 131 90 ); 132 91 }; 133 92 134 - // switching on !!did everywhere is pretty annoying, this could probably be two components 135 - // but i don't want to duplicate or think about how to extract the paging logic 136 - const BacklinkItems = ({ 137 - target, 138 - collection, 139 - path, 140 - dids, 141 - cursor, 142 - }: { 143 - target: string; 144 - collection: string; 145 - path: string; 146 - dids: boolean; 147 - cursor?: string; 148 - }) => { 149 - const [links, setLinks] = createSignal<LinksWithDids | LinksWithRecords>(); 150 - const [more, setMore] = createSignal<boolean>(false); 151 - 152 - onMount(async () => { 153 - const links = await (dids ? getDidBacklinks : getRecordBacklinks)( 154 - target, 155 - collection, 156 - path, 157 - cursor, 158 - ); 159 - setLinks(links); 93 + const Backlinks = (props: { target: string }) => { 94 + const [response] = createResource(async () => { 95 + const res = await getAllBacklinks(props.target); 96 + return flattenLinks(res.links); 160 97 }); 161 98 162 - // TODO: could pass the `total` into this component, which can be checked against each call to this endpoint to find if it's stale. 163 - // also hmm 'total' is misleading/wrong on that api 164 - 165 99 return ( 166 - <Show when={links()} fallback={<p>Loading&hellip;</p>}> 167 - <Show when={dids}> 168 - <For each={(links() as LinksWithDids).linking_dids}> 169 - {(did) => ( 170 - <a 171 - href={`/at://${did}`} 172 - class="relative flex w-full font-mono text-blue-400 hover:underline active:underline" 173 - > 174 - {did} 175 - </a> 100 + <div class="flex w-full flex-col gap-3 text-sm"> 101 + <Show when={response()} fallback={<p class="text-neutral-500">Loadingโ€ฆ</p>}> 102 + <Show when={response()!.length === 0}> 103 + <p class="text-neutral-500">No backlinks found.</p> 104 + </Show> 105 + <For each={response()}> 106 + {(entry) => ( 107 + <BacklinkSection 108 + target={props.target} 109 + collection={entry.collection} 110 + path={entry.path} 111 + counts={entry.counts} 112 + /> 176 113 )} 177 114 </For> 178 115 </Show> 179 - <Show when={!dids}> 180 - <For each={(links() as LinksWithRecords).linking_records}> 181 - {({ did, collection, rkey }) => ( 182 - <p class="relative flex w-full items-center gap-1 font-mono"> 183 - <a 184 - href={`/at://${did}/${collection}/${rkey}`} 185 - class="text-blue-400 hover:underline active:underline" 186 - > 187 - {rkey} 188 - </a> 189 - <span class="text-xs text-neutral-500 dark:text-neutral-400"> 190 - {TID.validate(rkey) ? 191 - localDateFromTimestamp(TID.parse(rkey).timestamp / 1000) 192 - : undefined} 193 - </span> 194 - </p> 195 - )} 196 - </For> 197 - </Show> 198 - <Show when={links()?.cursor}> 199 - <Show when={more()} fallback={<Button onClick={() => setMore(true)}>Load More</Button>}> 200 - <BacklinkItems 201 - target={target} 202 - collection={collection} 203 - path={path} 204 - dids={dids} 205 - cursor={links()!.cursor} 116 + </div> 117 + ); 118 + }; 119 + 120 + const BacklinkSection = ( 121 + props: BacklinksProps & { counts: { distinct_dids: number; records: number } }, 122 + ) => { 123 + const [expanded, setExpanded] = createSignal(false); 124 + 125 + return ( 126 + <div class="overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-700"> 127 + <button 128 + class="flex w-full items-center justify-between gap-3 px-3 py-2 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/50" 129 + onClick={() => setExpanded(!expanded())} 130 + > 131 + <div class="flex min-w-0 flex-1 flex-col"> 132 + <span class="w-full truncate">{props.collection}</span> 133 + <span class="w-full text-xs wrap-break-word text-neutral-500 dark:text-neutral-400"> 134 + {props.path.slice(1)} 135 + </span> 136 + </div> 137 + <div class="flex shrink-0 items-center gap-2 text-neutral-700 dark:text-neutral-300"> 138 + <span class="text-xs"> 139 + {props.counts.records} from {props.counts.distinct_dids} repo 140 + {props.counts.distinct_dids > 1 ? "s" : ""} 141 + </span> 142 + <span 143 + class="iconify lucide--chevron-down transition-transform" 144 + classList={{ "rotate-180": expanded() }} 206 145 /> 207 - </Show> 146 + </div> 147 + </button> 148 + <Show when={expanded()}> 149 + <div class="border-t border-neutral-200 bg-neutral-50/50 dark:border-neutral-700 dark:bg-neutral-800/30"> 150 + <BacklinkRecords target={props.target} collection={props.collection} path={props.path} /> 151 + </div> 208 152 </Show> 209 - </Show> 153 + </div> 210 154 ); 211 155 }; 212 156
+90
src/components/create/confirm-submit.tsx
··· 1 + import { createSignal, Show } from "solid-js"; 2 + import { Button } from "../button.jsx"; 3 + 4 + export const ConfirmSubmit = (props: { 5 + isCreate: boolean; 6 + onConfirm: (validate: boolean | undefined, recreate: boolean) => void; 7 + onClose: () => void; 8 + }) => { 9 + const [validate, setValidate] = createSignal<boolean | undefined>(undefined); 10 + const [recreate, setRecreate] = createSignal(false); 11 + 12 + const getValidateLabel = () => { 13 + return ( 14 + validate() === true ? "True" 15 + : validate() === false ? "False" 16 + : "Unset" 17 + ); 18 + }; 19 + 20 + const cycleValidate = () => { 21 + setValidate( 22 + validate() === undefined ? true 23 + : validate() === true ? false 24 + : undefined, 25 + ); 26 + }; 27 + 28 + return ( 29 + <div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[24rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0"> 30 + <div class="flex flex-col gap-3 text-sm"> 31 + <h2 class="font-semibold">{props.isCreate ? "Create" : "Edit"} record</h2> 32 + <div class="flex flex-col gap-1.5"> 33 + <div class="flex items-center gap-2"> 34 + <button 35 + type="button" 36 + class="-ml-2 flex min-w-30 items-center gap-1.5 rounded-lg px-2 py-1 text-xs hover:bg-neutral-200/50 dark:hover:bg-neutral-700" 37 + onClick={cycleValidate} 38 + > 39 + <span 40 + classList={{ 41 + iconify: true, 42 + "lucide--square-check text-green-500 dark:text-green-400": validate() === true, 43 + "lucide--square-x text-red-500 dark:text-red-400": validate() === false, 44 + "lucide--square text-neutral-500 dark:text-neutral-400": validate() === undefined, 45 + }} 46 + ></span> 47 + <span>Validate: {getValidateLabel()}</span> 48 + </button> 49 + </div> 50 + <p class="text-xs text-neutral-600 dark:text-neutral-400"> 51 + Set to 'false' to skip lexicon schema validation by the PDS, 'true' to require it, or 52 + leave unset to validate only for known lexicons. 53 + </p> 54 + </div> 55 + <Show when={!props.isCreate}> 56 + <div class="flex flex-col gap-1.5"> 57 + <div class="flex items-center gap-2"> 58 + <button 59 + type="button" 60 + class="-ml-2 flex items-center gap-1.5 rounded-lg px-2 py-1 text-xs hover:bg-neutral-200/50 dark:hover:bg-neutral-700" 61 + onClick={() => setRecreate(!recreate())} 62 + > 63 + <span 64 + classList={{ 65 + iconify: true, 66 + "lucide--square-check text-green-500 dark:text-green-400": recreate(), 67 + "lucide--square text-neutral-500 dark:text-neutral-400": !recreate(), 68 + }} 69 + ></span> 70 + <span>Recreate</span> 71 + </button> 72 + </div> 73 + <p class="text-xs text-neutral-600 dark:text-neutral-400"> 74 + Delete the existing record and create a new one with the same record key. 75 + </p> 76 + </div> 77 + </Show> 78 + <div class="flex justify-between gap-2"> 79 + <Button onClick={props.onClose}>Cancel</Button> 80 + <Button 81 + onClick={() => props.onConfirm(validate(), recreate())} 82 + class="dark:shadow-dark-700 min-w-12 rounded-lg bg-blue-500 px-2 py-1.5 text-xs text-white shadow-xs select-none hover:bg-blue-600 active:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-500 dark:active:bg-blue-400" 83 + > 84 + {props.isCreate ? "Create" : "Edit"} 85 + </Button> 86 + </div> 87 + </div> 88 + </div> 89 + ); 90 + };
+29 -48
src/components/create/index.tsx
··· 20 20 import { addNotification, removeNotification } from "../notification.jsx"; 21 21 import { TextInput } from "../text-input.jsx"; 22 22 import Tooltip from "../tooltip.jsx"; 23 + import { ConfirmSubmit } from "./confirm-submit"; 23 24 import { FileUpload } from "./file-upload"; 24 25 import { HandleInput } from "./handle-input"; 25 26 import { MenuItem } from "./menu-item"; ··· 37 38 const [openUpload, setOpenUpload] = createSignal(false); 38 39 const [openInsertMenu, setOpenInsertMenu] = createSignal(false); 39 40 const [openHandleDialog, setOpenHandleDialog] = createSignal(false); 40 - const [validate, setValidate] = createSignal<boolean | undefined>(undefined); 41 + const [openConfirmDialog, setOpenConfirmDialog] = createSignal(false); 41 42 const [isMaximized, setIsMaximized] = createSignal(false); 42 43 const [isMinimized, setIsMinimized] = createSignal(false); 43 44 const [collectionError, setCollectionError] = createSignal(""); ··· 96 97 }; 97 98 }; 98 99 99 - const getValidateIcon = () => { 100 - return ( 101 - validate() === true ? "lucide--circle-check" 102 - : validate() === false ? "lucide--circle-x" 103 - : "lucide--circle" 104 - ); 105 - }; 106 - 107 - const getValidateLabel = () => { 108 - return ( 109 - validate() === true ? "True" 110 - : validate() === false ? "False" 111 - : "Unset" 112 - ); 113 - }; 114 - 115 100 createEffect(() => { 116 101 if (openDialog()) { 117 - setValidate(undefined); 118 102 setCollectionError(""); 119 103 setRkeyError(""); 120 104 } 121 105 }); 122 106 123 - const createRecord = async (formData: FormData) => { 107 + const createRecord = async (validate: boolean | undefined) => { 108 + const formData = new FormData(formRef); 124 109 const repo = formData.get("repo")?.toString(); 125 110 if (!repo) return; 126 111 const rpc = new Client({ handler: new OAuthUserAgent(await getSession(repo as Did)) }); ··· 139 124 collection: collection ? collection.toString() : record.$type, 140 125 rkey: rkey?.toString().length ? rkey?.toString() : undefined, 141 126 record: record, 142 - validate: validate(), 127 + validate: validate, 143 128 }, 144 129 }); 145 130 if (!res.ok) { 146 131 setNotice(`${res.data.error}: ${res.data.message}`); 147 132 return; 148 133 } 134 + setOpenConfirmDialog(false); 149 135 setOpenDialog(false); 150 136 const id = addNotification({ 151 137 message: "Record created", ··· 155 141 navigate(`/${res.data.uri}`); 156 142 }; 157 143 158 - const editRecord = async (recreate?: boolean) => { 144 + const editRecord = async (validate: boolean | undefined, recreate: boolean) => { 159 145 const record = editorInstance.view.state.doc.toString(); 160 146 if (!record) return; 161 147 const rpc = new Client({ handler: agent()! }); ··· 165 151 const res = await rpc.post("com.atproto.repo.applyWrites", { 166 152 input: { 167 153 repo: agent()!.sub, 168 - validate: validate(), 154 + validate: validate, 169 155 writes: [ 170 156 { 171 157 collection: params.collection as `${string}.${string}.${string}`, ··· 189 175 const res = await rpc.post("com.atproto.repo.applyWrites", { 190 176 input: { 191 177 repo: agent()!.sub, 192 - validate: validate(), 178 + validate: validate, 193 179 writes: [ 194 180 { 195 181 collection: params.collection as `${string}.${string}.${string}`, ··· 205 191 return; 206 192 } 207 193 } 194 + setOpenConfirmDialog(false); 208 195 setOpenDialog(false); 209 196 const id = addNotification({ 210 197 message: "Record edited", ··· 418 405 > 419 406 <HandleInput onClose={() => setOpenHandleDialog(false)} /> 420 407 </Modal> 408 + <Modal 409 + open={openConfirmDialog()} 410 + onClose={() => setOpenConfirmDialog(false)} 411 + closeOnClick={false} 412 + > 413 + <ConfirmSubmit 414 + isCreate={props.create} 415 + onConfirm={(validate, recreate) => { 416 + if (props.create) { 417 + createRecord(validate); 418 + } else { 419 + editRecord(validate, recreate); 420 + } 421 + }} 422 + onClose={() => setOpenConfirmDialog(false)} 423 + /> 424 + </Modal> 421 425 <div class="flex items-center justify-end gap-2"> 422 - <button 423 - type="button" 424 - class="flex items-center gap-1 rounded-sm p-1.5 text-xs hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 425 - onClick={() => 426 - setValidate( 427 - validate() === true ? false 428 - : validate() === false ? undefined 429 - : true, 430 - ) 431 - } 432 - > 433 - <Tooltip text={getValidateLabel()}> 434 - <span class={`iconify ${getValidateIcon()}`}></span> 435 - </Tooltip> 436 - <span>Validate</span> 437 - </button> 438 - <Show when={!props.create && hasUserScope("create") && hasUserScope("delete")}> 439 - <Button onClick={() => editRecord(true)}>Recreate</Button> 440 - </Show> 441 - <Button 442 - onClick={() => 443 - props.create ? createRecord(new FormData(formRef)) : editRecord() 444 - } 445 - > 446 - {props.create ? "Create" : "Edit"} 426 + <Button onClick={() => setOpenConfirmDialog(true)}> 427 + {props.create ? "Create..." : "Edit..."} 447 428 </Button> 448 429 </div> 449 430 </div>
+7 -2
src/components/dropdown.tsx
··· 75 75 export const ActionMenu = (props: { 76 76 label: string; 77 77 icon: string; 78 - onClick: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>; 78 + onClick: () => void; 79 79 }) => { 80 + const ctx = useContext(MenuContext); 81 + 80 82 return ( 81 83 <button 82 - onClick={props.onClick} 84 + onClick={() => { 85 + props.onClick(); 86 + ctx?.setShowMenu(false); 87 + }} 83 88 class="flex items-center gap-2 rounded-md p-1.5 whitespace-nowrap hover:bg-neutral-200/50 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 84 89 > 85 90 <Show when={props.icon}>
+1
src/components/editor.tsx
··· 48 48 keymap.of([indentWithTab]), 49 49 linter(jsonParseLinter()), 50 50 themeColor.of(document.documentElement.classList.contains("dark") ? basicDark : basicLight), 51 + EditorView.lineWrapping, 51 52 ], 52 53 }); 53 54 editorInstance.view = view;
+70 -56
src/components/json.tsx
··· 1 1 import { isCid, isDid, isNsid, isResourceUri, Nsid } from "@atcute/lexicons/syntax"; 2 2 import { A, useNavigate, useParams } from "@solidjs/router"; 3 - import { createEffect, createSignal, ErrorBoundary, For, on, Show } from "solid-js"; 3 + import { 4 + createContext, 5 + createEffect, 6 + createSignal, 7 + ErrorBoundary, 8 + For, 9 + on, 10 + Show, 11 + useContext, 12 + } from "solid-js"; 4 13 import { resolveLexiconAuthority } from "../utils/api"; 5 14 import { hideMedia } from "../views/settings"; 6 15 import { pds } from "./navbar"; 7 16 import { addNotification, removeNotification } from "./notification"; 8 17 import VideoPlayer from "./video-player"; 9 18 19 + interface JSONContext { 20 + repo: string; 21 + truncate?: boolean; 22 + parentIsBlob?: boolean; 23 + } 24 + 25 + const JSONCtx = createContext<JSONContext>(); 26 + const useJSONCtx = () => useContext(JSONCtx)!; 27 + 10 28 interface AtBlob { 11 29 $type: string; 12 30 ref: { $link: string }; 13 31 mimeType: string; 14 32 } 15 33 16 - const JSONString = (props: { 17 - data: string; 18 - isType?: boolean; 19 - isLink?: boolean; 20 - parentIsBlob?: boolean; 21 - }) => { 34 + const isURL = 35 + URL.canParse ?? 36 + ((url, base) => { 37 + try { 38 + new URL(url, base); 39 + return true; 40 + } catch { 41 + return false; 42 + } 43 + }); 44 + 45 + const JSONString = (props: { data: string; isType?: boolean; isLink?: boolean }) => { 46 + const ctx = useJSONCtx(); 22 47 const navigate = useNavigate(); 23 48 const params = useParams(); 24 49 25 - const isURL = 26 - URL.canParse ?? 27 - ((url, base) => { 28 - try { 29 - new URL(url, base); 30 - return true; 31 - } catch { 32 - return false; 33 - } 34 - }); 35 - 36 50 const handleClick = async (lex: string) => { 37 51 try { 38 52 const [nsid, anchor] = lex.split("#"); ··· 50 64 } 51 65 }; 52 66 67 + const MAX_LENGTH = 200; 68 + const isTruncated = () => ctx.truncate && props.data.length > MAX_LENGTH; 69 + const displayData = () => (isTruncated() ? props.data.slice(0, MAX_LENGTH) : props.data); 70 + const remainingChars = () => props.data.length - MAX_LENGTH; 71 + 53 72 return ( 54 73 <span> 55 74 " 56 - <For each={props.data.split(/(\s)/)}> 75 + <For each={displayData().split(/(\s)/)}> 57 76 {(part) => ( 58 77 <> 59 78 {isResourceUri(part) ? ··· 72 91 > 73 92 {part} 74 93 </button> 75 - : isCid(part) && props.isLink && props.parentIsBlob && params.repo ? 94 + : isCid(part) && props.isLink && ctx.parentIsBlob && params.repo ? 76 95 <A 77 96 class="text-blue-400 hover:underline active:underline" 78 97 rel="noopener" ··· 93 112 </> 94 113 )} 95 114 </For> 115 + <Show when={isTruncated()}> 116 + <span>โ€ฆ</span> 117 + </Show> 96 118 " 119 + <Show when={isTruncated()}> 120 + <span class="ml-1 text-neutral-500 dark:text-neutral-400"> 121 + (+{remainingChars().toLocaleString()}) 122 + </span> 123 + </Show> 97 124 </span> 98 125 ); 99 126 }; ··· 110 137 return <span>null</span>; 111 138 }; 112 139 113 - const JSONObject = (props: { 114 - data: { [x: string]: JSONType }; 115 - repo: string; 116 - parentIsBlob?: boolean; 117 - }) => { 140 + const JSONObject = (props: { data: { [x: string]: JSONType } }) => { 141 + const ctx = useJSONCtx(); 118 142 const params = useParams(); 119 143 const [hide, setHide] = createSignal( 120 144 localStorage.hideMedia === "true" || params.rkey === undefined, ··· 136 160 ); 137 161 138 162 const isBlob = props.data.$type === "blob"; 139 - const isBlobContext = isBlob || props.parentIsBlob; 163 + const isBlobContext = isBlob || ctx.parentIsBlob; 140 164 141 165 const Obj = ({ key, value }: { key: string; value: JSONType }) => { 142 166 const [show, setShow] = createSignal(true); ··· 169 193 "self-center": value !== Object(value), 170 194 "pl-[calc(2ch-0.5px)] border-l-[0.5px] border-neutral-500/50 dark:border-neutral-400/50 has-hover:group-hover/indent:border-neutral-700 transition-colors dark:has-hover:group-hover/indent:border-neutral-300": 171 195 value === Object(value), 172 - "invisible h-0": !show(), 196 + "invisible h-0 overflow-hidden": !show(), 173 197 }} 174 198 > 175 - <JSONValue 176 - data={value} 177 - repo={props.repo} 178 - isType={key === "$type"} 179 - isLink={key === "$link"} 180 - parentIsBlob={isBlobContext} 181 - /> 199 + <JSONCtx.Provider value={{ ...ctx, parentIsBlob: isBlobContext }}> 200 + <JSONValueInner data={value} isType={key === "$type"} isLink={key === "$link"} /> 201 + </JSONCtx.Provider> 182 202 </span> 183 203 </span> 184 204 ); ··· 200 220 <Show when={blob.mimeType.startsWith("image/")}> 201 221 <img 202 222 class="h-auto max-h-48 max-w-48 object-contain sm:max-h-64 sm:max-w-64" 203 - src={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${props.repo}&cid=${blob.ref.$link}`} 223 + src={`https://${pds()}/xrpc/com.atproto.sync.getBlob?did=${ctx.repo}&cid=${blob.ref.$link}`} 204 224 onLoad={() => setMediaLoaded(true)} 205 225 /> 206 226 </Show> 207 227 <Show when={blob.mimeType === "video/mp4"}> 208 228 <ErrorBoundary fallback={() => <span>Failed to load video</span>}> 209 229 <VideoPlayer 210 - did={props.repo} 230 + did={ctx.repo} 211 231 cid={blob.ref.$link} 212 232 onLoad={() => setMediaLoaded(true)} 213 233 /> ··· 241 261 return rawObj; 242 262 }; 243 263 244 - const JSONArray = (props: { data: JSONType[]; repo: string; parentIsBlob?: boolean }) => { 264 + const JSONArray = (props: { data: JSONType[] }) => { 245 265 return ( 246 266 <For each={props.data}> 247 267 {(value, index) => ( ··· 252 272 }} 253 273 > 254 274 <span class="ml-[1ch] w-full"> 255 - <JSONValue data={value} repo={props.repo} parentIsBlob={props.parentIsBlob} /> 275 + <JSONValueInner data={value} /> 256 276 </span> 257 277 </span> 258 278 )} ··· 260 280 ); 261 281 }; 262 282 263 - export const JSONValue = (props: { 264 - data: JSONType; 265 - repo: string; 266 - isType?: boolean; 267 - isLink?: boolean; 268 - parentIsBlob?: boolean; 269 - }) => { 283 + const JSONValueInner = (props: { data: JSONType; isType?: boolean; isLink?: boolean }) => { 270 284 const data = props.data; 271 285 if (typeof data === "string") 272 - return ( 273 - <JSONString 274 - data={data} 275 - isType={props.isType} 276 - isLink={props.isLink} 277 - parentIsBlob={props.parentIsBlob} 278 - /> 279 - ); 286 + return <JSONString data={data} isType={props.isType} isLink={props.isLink} />; 280 287 if (typeof data === "number") return <JSONNumber data={data} />; 281 288 if (typeof data === "boolean") return <JSONBoolean data={data} />; 282 289 if (data === null) return <JSONNull />; 283 - if (Array.isArray(data)) 284 - return <JSONArray data={data} repo={props.repo} parentIsBlob={props.parentIsBlob} />; 285 - return <JSONObject data={data} repo={props.repo} parentIsBlob={props.parentIsBlob} />; 290 + if (Array.isArray(data)) return <JSONArray data={data} />; 291 + return <JSONObject data={data} />; 292 + }; 293 + 294 + export const JSONValue = (props: { data: JSONType; repo: string; truncate?: boolean }) => { 295 + return ( 296 + <JSONCtx.Provider value={{ repo: props.repo, truncate: props.truncate }}> 297 + <JSONValueInner data={props.data} /> 298 + </JSONCtx.Provider> 299 + ); 286 300 }; 287 301 288 302 export type JSONType = string | number | boolean | null | { [x: string]: JSONType } | JSONType[];
+28 -28
src/components/navbar.tsx
··· 18 18 e.stopPropagation(); 19 19 addToClipboard(props.content); 20 20 }} 21 - class={`-mr-2 hidden items-center rounded px-2 py-1.5 text-neutral-500 transition-all duration-200 group-hover:flex hover:bg-neutral-200/70 hover:text-neutral-600 active:bg-neutral-300/70 dark:text-neutral-400 dark:hover:bg-neutral-700/70 dark:hover:text-neutral-300 dark:active:bg-neutral-600/70`} 21 + class={`-mr-2 hidden items-center rounded px-2 py-1 text-neutral-500 transition-all duration-200 group-hover:flex hover:bg-neutral-200/70 hover:text-neutral-600 active:bg-neutral-300/70 sm:py-1.5 dark:text-neutral-400 dark:hover:bg-neutral-700/70 dark:hover:text-neutral-300 dark:active:bg-neutral-600/70`} 22 22 aria-label="Copy to clipboard" 23 23 > 24 24 <span class="iconify lucide--link"></span> ··· 30 30 31 31 export const NavBar = (props: { params: Params }) => { 32 32 const [handle, setHandle] = createSignal(props.params.repo); 33 - const [showHandle, setShowHandle] = createSignal(localStorage.showHandle === "true"); 34 33 35 34 createEffect(() => { 36 35 if (pds() !== undefined && props.params.repo) { ··· 88 87 <Show when={props.params.repo}> 89 88 {/* Repository Level */} 90 89 <div class="group relative flex items-center justify-between gap-1 rounded-md border-[0.5px] border-transparent bg-transparent px-2 transition-all duration-200 hover:border-neutral-300 hover:bg-neutral-50/40 dark:hover:border-neutral-600 dark:hover:bg-neutral-800/40"> 91 - <div class="flex basis-full items-center gap-2"> 90 + <div class="flex min-w-0 basis-full items-center gap-2"> 92 91 <Tooltip text="Repository"> 93 92 <span class="iconify lucide--book-user shrink-0 text-neutral-500 transition-colors duration-200 group-hover:text-neutral-700 dark:text-neutral-400 dark:group-hover:text-neutral-200"></span> 94 93 </Tooltip> 95 - {props.params.collection ? 94 + <Show 95 + when={props.params.collection} 96 + fallback={ 97 + <span class="flex min-w-0 gap-1 py-0.5 font-medium"> 98 + <Show 99 + when={handle() !== props.params.repo} 100 + fallback={<span class="truncate">{props.params.repo}</span>} 101 + > 102 + <span class="shrink-0">{handle()}</span> 103 + <span class="truncate text-neutral-500 dark:text-neutral-400"> 104 + ({props.params.repo}) 105 + </span> 106 + </Show> 107 + </span> 108 + } 109 + > 96 110 <A 97 111 end 98 112 href={`/at://${props.params.repo}`} 99 - inactiveClass="text-blue-400 w-full py-0.5 font-medium hover:text-blue-500 transition-colors duration-150 dark:hover:text-blue-300" 113 + inactiveClass="flex grow min-w-0 gap-1 py-0.5 font-medium text-blue-400 hover:text-blue-500 transition-colors duration-150 dark:hover:text-blue-300" 100 114 > 101 - {showHandle() ? handle() : props.params.repo} 115 + <Show 116 + when={handle() !== props.params.repo} 117 + fallback={<span class="truncate">{props.params.repo}</span>} 118 + > 119 + <span class="shrink-0">{handle()}</span> 120 + <span class="truncate">({props.params.repo})</span> 121 + </Show> 102 122 </A> 103 - : <span class="py-0.5 font-medium"> 104 - {showHandle() ? handle() : props.params.repo} 105 - </span> 106 - } 107 - </div> 108 - <div class="flex"> 109 - <Tooltip text={showHandle() ? "Show DID" : "Show handle"}> 110 - <button 111 - type="button" 112 - class={`items-center rounded px-1.25 py-1.25 text-neutral-500 transition-all duration-200 hover:bg-neutral-200/70 hover:text-neutral-700 active:bg-neutral-300/70 sm:px-2 sm:py-1.5 dark:text-neutral-400 dark:hover:bg-neutral-700/70 dark:hover:text-neutral-200 dark:active:bg-neutral-600/70 ${isTouchDevice ? "flex" : "hidden group-hover:flex"}`} 113 - onclick={() => { 114 - localStorage.showHandle = !showHandle(); 115 - setShowHandle(!showHandle()); 116 - }} 117 - aria-label="Switch DID/Handle" 118 - > 119 - <span 120 - class={`iconify shrink-0 duration-200 ${showHandle() ? "rotate-y-180" : ""} lucide--arrow-left-right`} 121 - ></span> 122 - </button> 123 - </Tooltip> 124 - <CopyButton content={props.params.repo!} label="Copy DID" /> 123 + </Show> 125 124 </div> 125 + <CopyButton content={props.params.repo!} label="Copy DID" /> 126 126 </div> 127 127 </Show> 128 128
+5 -5
src/components/search.tsx
··· 188 188 <label for="input" class="hidden"> 189 189 PDS URL, AT URI, NSID, DID, or handle 190 190 </label> 191 - <div class="dark:bg-dark-100 dark:inset-shadow-dark-200 flex items-center gap-2 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 inset-shadow-xs focus-within:outline-[1px] focus-within:outline-neutral-600 dark:border-neutral-600 dark:focus-within:outline-neutral-400"> 191 + <div class="dark:bg-dark-100 flex items-center gap-2 rounded-lg bg-white px-2 outline-1 outline-neutral-200 focus-within:outline-[1.5px] focus-within:outline-neutral-600 dark:outline-neutral-600 dark:focus-within:outline-neutral-400"> 192 192 <label 193 193 for="input" 194 194 class="iconify lucide--search text-neutral-500 dark:text-neutral-400" ··· 312 312 src={actor.avatar?.replace("img/avatar/", "img/avatar_thumbnail/")} 313 313 class="size-9 rounded-full" 314 314 /> 315 - <div class="flex flex-col"> 315 + <div class="flex min-w-0 flex-col"> 316 316 <Show when={actor.displayName}> 317 - <span class="text-sm font-medium">{actor.displayName}</span> 317 + <span class="truncate text-sm font-medium">{actor.displayName}</span> 318 318 </Show> 319 - <span class="text-xs text-neutral-600 dark:text-neutral-400"> 319 + <span class="truncate text-xs text-neutral-600 dark:text-neutral-400"> 320 320 @{actor.handle} 321 321 </span> 322 322 </div> ··· 382 382 class="flex items-center rounded-md p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-600 dark:active:bg-neutral-500" 383 383 onClick={() => setOpenList(true)} 384 384 > 385 - <span class="iconify lucide--help-circle"></span> 385 + <span class="iconify lucide--help-circle text-neutral-600 dark:text-neutral-300"></span> 386 386 </button> 387 387 </> 388 388 );
+2 -2
src/components/sticky.tsx
··· 29 29 /> 30 30 31 31 <div 32 - class="sticky top-2 z-10 flex w-full flex-col items-center justify-center gap-2 rounded-lg p-3 transition-colors" 32 + class="sticky top-2 z-10 flex w-full flex-col items-center justify-center gap-2 rounded-lg border-[0.5px] p-3 transition-colors" 33 33 classList={{ 34 - "bg-neutral-50 dark:bg-dark-300 border-[0.5px] border-neutral-300 dark:border-neutral-700 shadow-md": 34 + "bg-neutral-50 dark:bg-dark-300 border-neutral-300 dark:border-neutral-700 shadow-md": 35 35 filterStuck(), 36 36 "bg-transparent border-transparent shadow-none": !filterStuck(), 37 37 }}
+1 -1
src/components/text-input.tsx
··· 25 25 disabled={props.disabled} 26 26 required={props.required} 27 27 class={ 28 - "dark:bg-dark-100 dark:inset-shadow-dark-200 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 py-1 inset-shadow-xs select-none placeholder:text-sm focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400 " + 28 + "dark:bg-dark-100 rounded-lg bg-white px-2 py-1 outline-1 outline-neutral-200 select-none placeholder:text-sm focus:outline-[1.5px] focus:outline-neutral-600 dark:outline-neutral-600 dark:focus:outline-neutral-400 " + 29 29 props.class 30 30 } 31 31 onInput={props.onInput}
+11 -2
src/layout.tsx
··· 118 118 }); 119 119 120 120 return ( 121 - <div id="main" class="mx-auto mb-8 flex max-w-lg flex-col items-center p-4"> 121 + <div id="main" class="mx-auto mb-8 flex max-w-lg flex-col items-center p-3"> 122 122 <MetaProvider> 123 123 <Show when={location.pathname !== "/"}> 124 124 <Meta name="robots" content="noindex, nofollow" /> ··· 151 151 <DropdownMenu icon="lucide--menu text-lg" buttonClass="rounded-lg p-1.5"> 152 152 <NavMenu href="/jetstream" label="Jetstream" icon="lucide--radio-tower" /> 153 153 <NavMenu href="/firehose" label="Firehose" icon="lucide--droplet" /> 154 - <NavMenu href="/labels" label="Labels" icon="lucide--tags" /> 154 + <NavMenu href="/labels" label="Labels" icon="lucide--tag" /> 155 155 <NavMenu href="/settings" label="Settings" icon="lucide--settings" /> 156 156 <MenuSeparator /> 157 157 <NavMenu ··· 192 192 </Show> 193 193 </div> 194 194 <NotificationContainer /> 195 + <Show 196 + when={localStorage.plcDirectory && localStorage.plcDirectory !== "https://plc.directory"} 197 + > 198 + <div class="dark:bg-dark-500 fixed right-0 bottom-0 left-0 z-10 flex items-center justify-center bg-neutral-100 px-3 py-1 text-xs"> 199 + <span> 200 + PLC directory: <span class="font-medium">{localStorage.plcDirectory}</span> 201 + </span> 202 + </div> 203 + </Show> 195 204 </div> 196 205 ); 197 206 };
-17
src/utils/api.ts
··· 133 133 linking_records: Array<{ did: string; collection: string; rkey: string }>; 134 134 }; 135 135 136 - type LinksWithDids = { 137 - cursor: string; 138 - total: number; 139 - linking_dids: Array<string>; 140 - }; 141 - 142 136 const getConstellation = async ( 143 137 endpoint: string, 144 138 target: string, ··· 175 169 ): Promise<LinksWithRecords> => 176 170 getConstellation("/links", target, collection, path, cursor, limit || 100); 177 171 178 - const getDidBacklinks = ( 179 - target: string, 180 - collection: string, 181 - path: string, 182 - cursor?: string, 183 - limit?: number, 184 - ): Promise<LinksWithDids> => 185 - getConstellation("/links/distinct-dids", target, collection, path, cursor, limit || 100); 186 - 187 172 export { 188 173 didDocCache, 189 174 getAllBacklinks, 190 - getDidBacklinks, 191 175 getPDS, 192 176 getRecordBacklinks, 193 177 labelerCache, ··· 198 182 resolvePDS, 199 183 validateHandle, 200 184 type LinkData, 201 - type LinksWithDids, 202 185 type LinksWithRecords, 203 186 };
+24
src/utils/route-cache.ts
··· 1 + import { createStore } from "solid-js/store"; 2 + 3 + export interface CollectionCacheEntry { 4 + records: unknown[]; 5 + cursor: string | undefined; 6 + scrollY: number; 7 + reverse: boolean; 8 + } 9 + 10 + type RouteCache = Record<string, CollectionCacheEntry>; 11 + 12 + const [routeCache, setRouteCache] = createStore<RouteCache>({}); 13 + 14 + export const getCollectionCache = (key: string): CollectionCacheEntry | undefined => { 15 + return routeCache[key]; 16 + }; 17 + 18 + export const setCollectionCache = (key: string, entry: CollectionCacheEntry): void => { 19 + setRouteCache(key, entry); 20 + }; 21 + 22 + export const clearCollectionCache = (key: string): void => { 23 + setRouteCache(key, undefined!); 24 + };
+5 -4
src/views/blob.tsx
··· 30 30 return ( 31 31 <div class="flex flex-col items-center gap-2"> 32 32 <Show when={blobs() || response()}> 33 - <div class="flex w-full flex-col gap-0.5 font-mono text-xs wrap-anywhere"> 33 + <div class="flex w-full flex-col gap-0.5 pb-20 font-mono text-xs sm:text-sm"> 34 34 <For each={blobs()}> 35 35 {(cid) => ( 36 36 <a 37 37 href={`${props.pds}/xrpc/com.atproto.sync.getBlob?did=${props.repo}&cid=${cid}`} 38 38 target="_blank" 39 - class="w-fit rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 39 + class="truncate rounded px-0.5 text-left text-blue-400 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 40 + dir="rtl" 40 41 > 41 - <span class="text-blue-400">{cid}</span> 42 + {cid} 42 43 </a> 43 44 )} 44 45 </For> 45 46 </div> 46 47 </Show> 47 - <div class="dark:bg-dark-500 fixed bottom-0 z-5 flex w-screen justify-center bg-neutral-100 py-2"> 48 + <div class="dark:bg-dark-500 fixed bottom-0 z-5 flex w-screen justify-center bg-neutral-100 pt-2 pb-4"> 48 49 <div class="flex flex-col items-center gap-1 pb-2"> 49 50 <p> 50 51 {blobs()?.length} blob{(blobs()?.length ?? 0 > 1) ? "s" : ""}
+78 -23
src/views/collection.tsx
··· 2 2 import { Client, simpleFetchHandler } from "@atcute/client"; 3 3 import { $type, ActorIdentifier, InferXRPCBodyOutput } from "@atcute/lexicons"; 4 4 import * as TID from "@atcute/tid"; 5 - import { A, useParams } from "@solidjs/router"; 6 - import { createEffect, createMemo, createResource, createSignal, For, Show } from "solid-js"; 5 + import { A, useBeforeLeave, useParams } from "@solidjs/router"; 6 + import { 7 + createEffect, 8 + createMemo, 9 + createResource, 10 + createSignal, 11 + For, 12 + onMount, 13 + Show, 14 + } from "solid-js"; 7 15 import { createStore } from "solid-js/store"; 8 16 import { hasUserScope } from "../auth/scope-utils"; 9 17 import { agent } from "../auth/state"; ··· 14 22 import { StickyOverlay } from "../components/sticky.jsx"; 15 23 import { TextInput } from "../components/text-input.jsx"; 16 24 import Tooltip from "../components/tooltip.jsx"; 25 + import { isTouchDevice } from "../layout.jsx"; 17 26 import { resolvePDS } from "../utils/api.js"; 18 27 import { localDateFromTimestamp } from "../utils/date.js"; 28 + import { 29 + clearCollectionCache, 30 + getCollectionCache, 31 + setCollectionCache, 32 + } from "../utils/route-cache.js"; 19 33 20 34 interface AtprotoRecord { 21 35 rkey: string; ··· 42 56 43 57 return ( 44 58 <span 45 - class="relative flex w-full min-w-0 items-baseline rounded px-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 59 + class="relative flex w-full min-w-0 items-baseline rounded p-0.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 46 60 ref={rkeyRef} 47 - onmouseover={() => setHover(true)} 48 - onmouseleave={() => setHover(false)} 61 + onmouseover={() => !isTouchDevice && setHover(true)} 62 + onmouseleave={() => !isTouchDevice && setHover(false)} 49 63 > 50 64 <span class="flex items-baseline truncate"> 51 - <span class="shrink-0 text-sm text-blue-400 sm:text-base">{props.record.rkey}</span> 65 + <span class="shrink-0 text-sm text-blue-400">{props.record.rkey}</span> 52 66 <span class="ml-1 truncate text-xs text-neutral-500 dark:text-neutral-400" dir="rtl"> 53 67 {props.record.cid} 54 68 </span> ··· 66 80 <JSONValue 67 81 data={props.record.record.value as JSONType} 68 82 repo={props.record.record.uri.split("/")[2]} 83 + truncate 69 84 /> 70 85 </span> 71 86 </Show> ··· 83 98 const [reverse, setReverse] = createSignal(false); 84 99 const [recreate, setRecreate] = createSignal(false); 85 100 const [openDelete, setOpenDelete] = createSignal(false); 101 + const [restoredFromCache, setRestoredFromCache] = createSignal(false); 86 102 const did = params.repo; 87 103 let pds: string; 88 104 let rpc: Client; 89 105 106 + const cacheKey = () => `${params.pds}/${params.repo}/${params.collection}`; 107 + 108 + onMount(() => { 109 + const cached = getCollectionCache(cacheKey()); 110 + if (cached) { 111 + setRecords(cached.records as AtprotoRecord[]); 112 + setCursor(cached.cursor); 113 + setReverse(cached.reverse); 114 + setRestoredFromCache(true); 115 + requestAnimationFrame(() => { 116 + window.scrollTo(0, cached.scrollY); 117 + }); 118 + } 119 + }); 120 + 121 + useBeforeLeave((e) => { 122 + const recordPathPrefix = `/at://${did}/${params.collection}/`; 123 + const isNavigatingToRecord = typeof e.to === "string" && e.to.startsWith(recordPathPrefix); 124 + 125 + if (isNavigatingToRecord && records.length > 0) { 126 + setCollectionCache(cacheKey(), { 127 + records: [...records], 128 + cursor: cursor(), 129 + scrollY: window.scrollY, 130 + reverse: reverse(), 131 + }); 132 + } else { 133 + clearCollectionCache(cacheKey()); 134 + } 135 + }); 136 + 90 137 const fetchRecords = async () => { 138 + if (restoredFromCache() && records.length > 0 && !cursor()) { 139 + setRestoredFromCache(false); 140 + return records; 141 + } 142 + if (restoredFromCache()) setRestoredFromCache(false); 143 + 91 144 if (!pds) pds = await resolvePDS(did!); 92 145 if (!rpc) rpc = new Client({ handler: simpleFetchHandler({ service: pds }) }); 93 146 const res = await rpc.get("com.atproto.repo.listRecords", { ··· 166 219 setCursor(undefined); 167 220 setOpenDelete(false); 168 221 setRecreate(false); 222 + clearCollectionCache(cacheKey()); 169 223 refetch(); 170 224 }; 171 225 ··· 210 264 setLastSelected(undefined); 211 265 setBatchDelete(!batchDelete()); 212 266 }} 213 - class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 267 + class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 214 268 > 215 269 <span 216 - class={`iconify text-lg ${batchDelete() ? "lucide--circle-x" : "lucide--trash-2"} `} 270 + class={`iconify ${batchDelete() ? "lucide--circle-x" : "lucide--trash-2"} `} 217 271 ></span> 218 272 </button> 219 273 } ··· 224 278 children={ 225 279 <button 226 280 onclick={() => selectAll()} 227 - class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 281 + class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 228 282 > 229 - <span class="iconify lucide--copy-check text-lg"></span> 283 + <span class="iconify lucide--copy-check"></span> 230 284 </button> 231 285 } 232 286 /> ··· 239 293 setRecreate(true); 240 294 setOpenDelete(true); 241 295 }} 242 - class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 296 + class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 243 297 > 244 - <span class="iconify lucide--recycle text-lg text-green-500 dark:text-green-400"></span> 298 + <span class="iconify lucide--recycle text-green-500 dark:text-green-400"></span> 245 299 </button> 246 300 } 247 301 /> ··· 254 308 setRecreate(false); 255 309 setOpenDelete(true); 256 310 }} 257 - class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 311 + class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 258 312 > 259 - <span class="iconify lucide--trash-2 text-lg text-red-500 dark:text-red-400"></span> 313 + <span class="iconify lucide--trash-2 text-red-500 dark:text-red-400"></span> 260 314 </button> 261 315 } 262 316 /> ··· 280 334 </div> 281 335 </Modal> 282 336 </Show> 337 + <TextInput 338 + name="Filter" 339 + placeholder="Filter by substring" 340 + onInput={(e) => setFilter(e.currentTarget.value)} 341 + class="grow" 342 + /> 283 343 <Tooltip text="Jetstream"> 284 344 <A 285 345 href={`/jetstream?collections=${params.collection}&dids=${params.repo}`} 286 - class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 346 + class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 287 347 > 288 - <span class="iconify lucide--radio-tower text-lg"></span> 348 + <span class="iconify lucide--radio-tower"></span> 289 349 </A> 290 350 </Tooltip> 291 - <TextInput 292 - name="Filter" 293 - placeholder="Filter by substring" 294 - onInput={(e) => setFilter(e.currentTarget.value)} 295 - class="grow" 296 - /> 297 351 </div> 298 352 <Show when={records.length > 1}> 299 353 <div class="flex items-center justify-between gap-x-2"> ··· 302 356 setReverse(!reverse()); 303 357 setRecords([]); 304 358 setCursor(undefined); 359 + clearCollectionCache(cacheKey()); 305 360 refetch(); 306 361 }} 307 362 > ··· 349 404 </label> 350 405 </Show> 351 406 <Show when={!batchDelete()}> 352 - <A href={`/at://${did}/${params.collection}/${record.rkey}`}> 407 + <A href={`/at://${did}/${params.collection}/${record.rkey}`} class="select-none"> 353 408 <RecordLink record={record} /> 354 409 </A> 355 410 </Show>
+9 -9
src/views/home.tsx
··· 1 1 export const Home = () => { 2 2 return ( 3 3 <div class="flex w-full flex-col gap-3 wrap-break-word"> 4 - <div class="flex flex-col gap-0.5"> 4 + <div class="flex flex-col gap-1"> 5 5 <div> 6 6 <span class="text-xl font-semibold">AT Protocol Explorer</span> 7 7 </div> ··· 16 16 </span> 17 17 </div> 18 18 <div class="flex items-center gap-1"> 19 - <div class="iconify lucide--user-round" /> 20 - <span>Login to manage records in your repository.</span> 21 - </div> 22 - <div class="flex items-center gap-1"> 23 - <div class="iconify lucide--radio-tower" /> 24 - <span>Jetstream and firehose streaming.</span> 25 - </div> 26 - <div class="flex items-center gap-1"> 27 19 <div class="iconify lucide--link" /> 28 20 <span> 29 21 Backlinks support with{" "} ··· 36 28 </a> 37 29 . 38 30 </span> 31 + </div> 32 + <div class="flex items-center gap-1"> 33 + <div class="iconify lucide--user-round" /> 34 + <span>Login to manage records in your repository.</span> 35 + </div> 36 + <div class="flex items-center gap-1"> 37 + <div class="iconify lucide--radio-tower" /> 38 + <span>Jetstream and firehose streaming.</span> 39 39 </div> 40 40 <div class="flex items-center gap-1"> 41 41 <div class="iconify lucide--tag" />
+1 -1
src/views/labels.tsx
··· 228 228 rows={2} 229 229 value={searchParams.uriPatterns ?? "*"} 230 230 placeholder="at://did:web:example.com/app.bsky.feed.post/*" 231 - class="dark:bg-dark-100 dark:inset-shadow-dark-200 grow rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 py-1.5 text-sm inset-shadow-xs focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400" 231 + class="dark:bg-dark-100 grow rounded-lg bg-white px-2 py-1.5 text-sm outline-1 outline-neutral-200 focus:outline-[1.5px] focus:outline-neutral-600 dark:outline-neutral-600 dark:focus:outline-neutral-400" 232 232 /> 233 233 </label> 234 234 </div>
+11 -20
src/views/logs.tsx
··· 55 55 } 56 56 }); 57 57 58 - const FilterButton = (props: { icon: string; event: PlcEvent; label: string }) => { 58 + const FilterButton = (props: { event: PlcEvent; label: string }) => { 59 59 const isActive = () => activePlcEvent() === props.event; 60 60 const toggleFilter = () => setActivePlcEvent(isActive() ? undefined : props.event); 61 61 62 62 return ( 63 63 <button 64 64 classList={{ 65 - "flex items-center gap-1 sm:gap-1.5 rounded-lg px-3 py-2 sm:px-2 sm:py-1.5 text-base sm:text-sm transition-colors": true, 66 - "bg-neutral-700 text-white dark:bg-neutral-200 dark:text-neutral-900": isActive(), 65 + "font-medium rounded-lg px-2 py-1.5 text-xs sm:text-sm transition-colors": true, 66 + "bg-neutral-700 text-white dark:bg-neutral-300 dark:text-neutral-900": isActive(), 67 67 "bg-neutral-200 text-neutral-700 hover:bg-neutral-300 dark:bg-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-600": 68 68 !isActive(), 69 69 }} 70 70 onclick={toggleFilter} 71 71 > 72 - <span class={props.icon}></span> 73 - <span class="hidden font-medium sm:inline">{props.label}</span> 72 + {props.label} 74 73 </button> 75 74 ); 76 75 }; ··· 255 254 <div class="iconify lucide--filter" /> 256 255 <p class="font-medium">Filter by type</p> 257 256 </div> 258 - <div class="flex flex-wrap gap-1 sm:gap-2"> 259 - <FilterButton icon="iconify lucide--at-sign" event="handle" label="Alias" /> 260 - <FilterButton icon="iconify lucide--hard-drive" event="service" label="Service" /> 261 - <FilterButton 262 - icon="iconify lucide--shield-check" 263 - event="verification_method" 264 - label="Verification" 265 - /> 266 - <FilterButton 267 - icon="iconify lucide--key-round" 268 - event="rotation_key" 269 - label="Rotation Key" 270 - /> 257 + <div class="flex flex-wrap gap-1"> 258 + <FilterButton event="handle" label="Alias" /> 259 + <FilterButton event="service" label="Service" /> 260 + <FilterButton event="verification_method" label="Verification" /> 261 + <FilterButton event="rotation_key" label="Rotation Key" /> 271 262 </div> 272 263 </div> 273 264 <div class="flex items-center gap-1.5 text-sm font-medium"> 274 265 <Show when={validLog() === true}> 275 - <span class="iconify lucide--check-circle-2 text-green-500 dark:text-green-400"></span> 266 + <span class="iconify lucide--check text-green-600 dark:text-green-400"></span> 276 267 <span>Valid log</span> 277 268 </Show> 278 269 <Show when={validLog() === false}> 279 - <span class="iconify lucide--x-circle text-red-500 dark:text-red-400"></span> 270 + <span class="iconify lucide--x text-red-500 dark:text-red-400"></span> 280 271 <span>Log validation failed</span> 281 272 </Show> 282 273 <Show when={validLog() === undefined}>
+55 -37
src/views/pds.tsx
··· 5 5 import { A, useLocation, useParams } from "@solidjs/router"; 6 6 import { createResource, createSignal, For, Show } from "solid-js"; 7 7 import { Button } from "../components/button"; 8 - import { CopyMenu, DropdownMenu, MenuProvider, NavMenu } from "../components/dropdown"; 9 8 import { Modal } from "../components/modal"; 10 9 import { setPDS } from "../components/navbar"; 11 10 import Tooltip from "../components/tooltip"; 11 + import { resolveDidDoc } from "../utils/api"; 12 12 import { localDateFromTimestamp } from "../utils/date"; 13 13 14 14 const LIMIT = 1000; ··· 54 54 55 55 const RepoCard = (repo: ComAtprotoSyncListRepos.Repo) => { 56 56 const [openInfo, setOpenInfo] = createSignal(false); 57 + const [handle, setHandle] = createSignal<string>(); 58 + 59 + const fetchHandle = async () => { 60 + try { 61 + const doc = await resolveDidDoc(repo.did); 62 + const aka = doc.alsoKnownAs?.find((a) => a.startsWith("at://")); 63 + if (aka) setHandle(aka.replace("at://", "")); 64 + } catch {} 65 + }; 57 66 58 67 return ( 59 68 <div class="flex items-center gap-0.5"> ··· 69 78 </Tooltip> 70 79 </Show> 71 80 <button 72 - onclick={() => setOpenInfo(true)} 81 + onclick={() => { 82 + setOpenInfo(true); 83 + if (!handle()) fetchHandle(); 84 + }} 73 85 class="flex items-center rounded-md p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 74 86 > 75 - <span class="iconify lucide--info"></span> 87 + <span class="iconify lucide--info text-neutral-600 dark:text-neutral-400"></span> 76 88 </button> 77 89 <Modal open={openInfo()} onClose={() => setOpenInfo(false)}> 78 90 <div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-max max-w-[90vw] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-white p-3 shadow-md transition-opacity duration-200 sm:max-w-xl dark:border-neutral-700 starting:opacity-0"> ··· 86 98 </button> 87 99 </div> 88 100 <div class="grid grid-cols-[auto_1fr] items-baseline gap-x-1 gap-y-0.5 text-sm"> 101 + <span class="font-medium">Handle:</span> 102 + <span class="text-neutral-700 dark:text-neutral-300">{handle()}</span> 89 103 <span class="font-medium">Head:</span> 90 104 <span class="wrap-anywhere text-neutral-700 dark:text-neutral-300">{repo.head}</span> 91 105 ··· 122 136 ); 123 137 }; 124 138 125 - const Tab = (props: { tab: "repos" | "info"; label: string }) => ( 139 + const Tab = (props: { tab: "repos" | "info" | "firehose"; label: string }) => ( 126 140 <A 127 141 classList={{ 128 - "border-b-2": true, 129 - "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": 142 + "border-b-2 font-medium": true, 143 + "border-transparent dark:text-neutral-300/80 text-neutral-600 hover:border-neutral-600 dark:hover:border-neutral-300/80": 130 144 (!!location.hash && location.hash !== `#${props.tab}`) || 131 145 (!location.hash && props.tab !== "repos"), 132 146 }} 133 - href={`/${params.pds}#${props.tab}`} 147 + href={ 148 + props.tab === "firehose" ? 149 + `/firehose?instance=wss://${params.pds}` 150 + : `/${params.pds}#${props.tab}` 151 + } 134 152 > 135 153 {props.label} 136 154 </A> ··· 138 156 139 157 return ( 140 158 <Show when={repos() || response()}> 141 - <div class="flex w-full flex-col"> 142 - <div class="dark:shadow-dark-700 dark:bg-dark-300 mb-2 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-2 text-sm shadow-xs dark:border-neutral-700"> 143 - <div class="ml-1 flex items-center gap-3"> 144 - <Tab tab="repos" label="Repositories" /> 145 - <Tab tab="info" label="Info" /> 146 - </div> 147 - <MenuProvider> 148 - <DropdownMenu icon="lucide--ellipsis-vertical" buttonClass="rounded-sm p-1.5"> 149 - <CopyMenu content={params.pds!} label="Copy PDS" icon="lucide--copy" /> 150 - <NavMenu 151 - href={`/firehose?instance=wss://${params.pds}`} 152 - label="Firehose" 153 - icon="lucide--radio-tower" 154 - /> 155 - </DropdownMenu> 156 - </MenuProvider> 159 + <div class="flex w-full flex-col px-2"> 160 + <div class="mb-3 flex gap-4 text-sm sm:text-base"> 161 + <Tab tab="repos" label="Repositories" /> 162 + <Tab tab="info" label="Info" /> 163 + <Tab tab="firehose" label="Firehose" /> 157 164 </div> 158 - <div class="flex flex-col gap-1 px-2"> 159 - <Show when={!location.hash || location.hash === "#repos"}> 160 - <div class="flex flex-col divide-y-[0.5px] divide-neutral-300 dark:divide-neutral-700"> 161 - <For each={repos()}>{(repo) => <RepoCard {...repo} />}</For> 162 - </div> 163 - </Show> 165 + <Show when={!location.hash || location.hash === "#repos"}> 166 + <div class="flex flex-col divide-y-[0.5px] divide-neutral-300 pb-20 dark:divide-neutral-700"> 167 + <For each={repos()}>{(repo) => <RepoCard {...repo} />}</For> 168 + </div> 169 + </Show> 170 + <div class="flex flex-col gap-2"> 164 171 <Show when={location.hash === "#info"}> 165 172 <Show when={version()}> 166 173 {(version) => ( 167 - <div class="flex items-baseline gap-x-1"> 174 + <div class="flex flex-col"> 168 175 <span class="font-semibold">Version</span> 169 - <span class="truncate text-sm">{version()}</span> 176 + <span class="text-sm text-neutral-700 dark:text-neutral-300">{version()}</span> 170 177 </div> 171 178 )} 172 179 </Show> 173 180 <Show when={serverInfos()}> 174 181 {(server) => ( 175 182 <> 176 - <div class="flex items-baseline gap-x-1"> 183 + <div class="flex flex-col"> 177 184 <span class="font-semibold">DID</span> 178 - <span class="truncate text-sm">{server().did}</span> 185 + <span class="text-sm">{server().did}</span> 179 186 </div> 180 - <Show when={server().inviteCodeRequired}> 187 + <div class="flex items-center gap-1"> 181 188 <span class="font-semibold">Invite Code Required</span> 182 - </Show> 189 + <span 190 + classList={{ 191 + "iconify lucide--check text-green-500 dark:text-green-400": 192 + server().inviteCodeRequired === true, 193 + "iconify lucide--x text-red-500 dark:text-red-400": 194 + !server().inviteCodeRequired, 195 + }} 196 + ></span> 197 + </div> 183 198 <Show when={server().phoneVerificationRequired}> 184 - <span class="font-semibold">Phone Verification Required</span> 199 + <div class="flex items-center gap-1"> 200 + <span class="font-semibold">Phone Verification Required</span> 201 + <span class="iconify lucide--check text-green-500 dark:text-green-400"></span> 202 + </div> 185 203 </Show> 186 204 <Show when={server().availableUserDomains.length}> 187 205 <div class="flex flex-col"> ··· 232 250 </div> 233 251 </div> 234 252 <Show when={!location.hash || location.hash === "#repos"}> 235 - <div class="dark:bg-dark-500 fixed bottom-0 z-5 flex w-screen justify-center bg-neutral-100 py-2"> 253 + <div class="dark:bg-dark-500 fixed bottom-0 z-5 flex w-screen justify-center bg-neutral-100 pt-2 pb-4"> 236 254 <div class="flex flex-col items-center gap-1 pb-2"> 237 255 <p>{repos()?.length} loaded</p> 238 256 <Show when={!response.loading && cursor()}>
+7 -18
src/views/record.tsx
··· 363 363 <div class="flex items-center gap-0.5"> 364 364 <A 365 365 classList={{ 366 - "border-b-2": true, 367 - "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": 366 + "border-b-2 font-medium": true, 367 + "border-transparent text-neutral-600 dark:text-neutral-300/80 hover:border-neutral-600 dark:hover:border-neutral-300/80": 368 368 !isActive(), 369 369 }} 370 370 href={`/at://${did}/${params.collection}/${params.rkey}#${props.tab}`} ··· 381 381 return ( 382 382 <Show when={record()} keyed> 383 383 <div class="flex w-full flex-col items-center"> 384 - <div class="dark:shadow-dark-700 dark:bg-dark-300 mb-3 flex w-full justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-2 text-sm shadow-xs dark:border-neutral-700"> 385 - <div class="ml-1 flex items-center gap-3"> 384 + <div class="mb-3 flex w-full justify-between px-2 text-sm sm:text-base"> 385 + <div class="flex items-center gap-4"> 386 386 <RecordTab tab="record" label="Record" /> 387 387 <RecordTab tab="schema" label="Schema" /> 388 388 <RecordTab tab="backlinks" label="Backlinks" /> ··· 490 490 <Show when={location.hash === "#info"}> 491 491 <div class="flex w-full flex-col gap-2 px-2 text-sm"> 492 492 <div> 493 - <div class="flex items-center gap-1"> 494 - <span class="iconify lucide--at-sign"></span> 495 - <p class="font-semibold">AT URI</p> 496 - </div> 493 + <p class="font-semibold">AT URI</p> 497 494 <div class="truncate text-xs">{record()?.uri}</div> 498 495 </div> 499 496 <Show when={record()?.cid}> 500 497 <div> 501 - <div class="flex items-center gap-1"> 502 - <span class="iconify lucide--box"></span> 503 - <p class="font-semibold">CID</p> 504 - </div> 498 + <p class="font-semibold">CID</p> 505 499 <div class="truncate text-left text-xs" dir="rtl"> 506 500 {record()?.cid} 507 501 </div> ··· 509 503 </Show> 510 504 <div> 511 505 <div class="flex items-center gap-1"> 512 - <span class="iconify lucide--lock-keyhole"></span> 513 506 <p class="font-semibold">Record verification</p> 514 507 <span 515 508 classList={{ ··· 526 519 </div> 527 520 <div> 528 521 <div class="flex items-center gap-1"> 529 - <span class="iconify lucide--file-check"></span> 530 522 <p class="font-semibold">Schema validation</p> 531 523 <span 532 524 classList={{ ··· 556 548 </div> 557 549 <Show when={lexiconUri()}> 558 550 <div> 559 - <div class="flex items-center gap-1"> 560 - <span class="iconify lucide--scroll-text"></span> 561 - <p class="font-semibold">Lexicon schema</p> 562 - </div> 551 + <p class="font-semibold">Lexicon schema</p> 563 552 <div class="truncate text-xs"> 564 553 <A 565 554 href={`/${lexiconUri()}`}
+76 -88
src/views/repo.tsx
··· 88 88 return ( 89 89 <A 90 90 classList={{ 91 - "border-b-2": true, 92 - "border-transparent hover:border-neutral-400 dark:hover:border-neutral-600": !isActive(), 91 + "border-b-2 font-medium": true, 92 + "border-transparent text-neutral-600 dark:text-neutral-300/80 hover:border-neutral-600 dark:hover:border-neutral-300/80": 93 + !isActive(), 93 94 }} 94 95 href={`/at://${params.repo}#${props.tab}`} 95 96 > ··· 211 212 let loaded = 0; 212 213 213 214 const reader = response.body?.getReader(); 214 - const chunks: Uint8Array[] = []; 215 + const chunks: BlobPart[] = []; 215 216 216 217 if (reader) { 217 218 while (true) { ··· 275 276 return ( 276 277 <Show when={repo()}> 277 278 <div class="flex w-full flex-col gap-3 wrap-break-word"> 278 - <div class="dark:shadow-dark-700 dark:bg-dark-300 flex justify-between rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-2 text-sm shadow-xs dark:border-neutral-700"> 279 - <div class="ml-1 flex items-center gap-2 text-xs sm:gap-4 sm:text-sm"> 279 + <div class="flex justify-between px-2 text-sm sm:text-base"> 280 + <div class="flex items-center gap-3 sm:gap-4"> 280 281 <Show when={!error()}> 281 282 <RepoTab tab="collections" label="Collections" /> 282 283 </Show> ··· 289 290 </Show> 290 291 <RepoTab tab="backlinks" label="Backlinks" /> 291 292 </div> 292 - <div class="flex gap-0.5"> 293 + <div class="flex gap-1"> 293 294 <Show when={error() && error() !== "Missing PDS"}> 294 295 <div class="flex items-center gap-1 text-red-500 dark:text-red-400"> 295 296 <span class="iconify lucide--alert-triangle"></span> 296 297 <span>{error()}</span> 297 298 </div> 298 299 </Show> 299 - <Show when={!error() && (!location.hash || location.hash.startsWith("#collections"))}> 300 - <Tooltip text="Filter collections"> 301 - <button 302 - class="flex items-center rounded-sm p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600" 303 - onClick={() => setShowFilter(!showFilter())} 304 - > 305 - <span class="iconify lucide--filter"></span> 306 - </button> 307 - </Tooltip> 308 - </Show> 309 300 <MenuProvider> 310 301 <DropdownMenu icon="lucide--ellipsis-vertical" buttonClass="rounded-sm p-1.5"> 302 + <Show 303 + when={!error() && (!location.hash || location.hash.startsWith("#collections"))} 304 + > 305 + <ActionMenu 306 + label="Filter collections" 307 + icon="lucide--filter" 308 + onClick={() => setShowFilter(!showFilter())} 309 + /> 310 + </Show> 311 311 <CopyMenu content={params.repo!} label="Copy DID" icon="lucide--copy" /> 312 312 <NavMenu 313 313 href={`/jetstream?dids=${params.repo}`} ··· 323 323 </Show> 324 324 <Show when={error()?.length === 0 || error() === undefined}> 325 325 <ActionMenu 326 - label="Export Repo" 326 + label="Export repo" 327 327 icon={downloading() ? "lucide--loader-circle animate-spin" : "lucide--download"} 328 328 onClick={() => downloadRepo()} 329 329 /> ··· 336 336 : `https://${did.split("did:web:")[1]}/.well-known/did.json` 337 337 } 338 338 newTab 339 - label="DID Document" 339 + label="DID document" 340 340 icon="lucide--external-link" 341 341 /> 342 342 <Show when={did.startsWith("did:plc")}> 343 343 <NavMenu 344 344 href={`${localStorage.plcDirectory ?? "https://plc.directory"}/${did}/log/audit`} 345 345 newTab 346 - label="Audit Log" 346 + label="Audit log" 347 347 icon="lucide--external-link" 348 348 /> 349 349 </Show> ··· 406 406 <div class="flex flex-col text-sm wrap-anywhere" classList={{ "-mt-1": !showFilter() }}> 407 407 <Show 408 408 when={Object.keys(nsids() ?? {}).length != 0} 409 - fallback={<span class="text-center text-base mt-3">No collections found.</span>} 409 + fallback={<span class="mt-3 text-center text-base">No collections found.</span>} 410 410 > 411 411 <For 412 412 each={Object.keys(nsids() ?? {}).filter((authority) => ··· 486 486 <div class="flex flex-col gap-3 wrap-anywhere"> 487 487 {/* ID Section */} 488 488 <div> 489 - <div class="flex items-center gap-1"> 490 - <div class="iconify lucide--id-card" /> 491 - <p class="font-semibold">ID</p> 489 + <div class="font-semibold">DID</div> 490 + <div class="text-sm text-neutral-700 dark:text-neutral-300"> 491 + {didDocument().id} 492 492 </div> 493 - <div class="text-sm">{didDocument().id}</div> 494 493 </div> 495 494 496 495 {/* Aliases Section */} 497 496 <div> 498 - <div class="flex items-center gap-1"> 499 - <div class="iconify lucide--at-sign" /> 500 - <p class="font-semibold">Aliases</p> 501 - </div> 502 - <div class="flex flex-col gap-0.5"> 503 - <For each={didDocument().alsoKnownAs}> 504 - {(alias) => ( 505 - <div class="flex items-center gap-1 text-sm"> 506 - <span>{alias}</span> 507 - <Show when={alias.startsWith("at://")}> 508 - <Tooltip 509 - text={ 510 - validHandles[alias] === true ? "Valid handle" 511 - : validHandles[alias] === undefined ? 512 - "Validating" 513 - : "Invalid handle" 514 - } 515 - > 516 - <span 517 - classList={{ 518 - "iconify lucide--circle-check text-green-600 dark:text-green-400": 519 - validHandles[alias] === true, 520 - "iconify lucide--circle-x text-red-500 dark:text-red-400": 521 - validHandles[alias] === false, 522 - "iconify lucide--loader-circle animate-spin": 523 - validHandles[alias] === undefined, 524 - }} 525 - ></span> 526 - </Tooltip> 527 - </Show> 528 - </div> 529 - )} 530 - </For> 531 - </div> 497 + <p class="font-semibold">Aliases</p> 498 + <For each={didDocument().alsoKnownAs}> 499 + {(alias) => ( 500 + <div class="flex items-center gap-1 text-sm text-neutral-700 dark:text-neutral-300"> 501 + <span>{alias}</span> 502 + <Show when={alias.startsWith("at://")}> 503 + <Tooltip 504 + text={ 505 + validHandles[alias] === true ? "Valid handle" 506 + : validHandles[alias] === undefined ? 507 + "Validating" 508 + : "Invalid handle" 509 + } 510 + > 511 + <span 512 + classList={{ 513 + "iconify lucide--check text-green-600 dark:text-green-400": 514 + validHandles[alias] === true, 515 + "iconify lucide--x text-red-500 dark:text-red-400": 516 + validHandles[alias] === false, 517 + "iconify lucide--loader-circle animate-spin": 518 + validHandles[alias] === undefined, 519 + }} 520 + ></span> 521 + </Tooltip> 522 + </Show> 523 + </div> 524 + )} 525 + </For> 532 526 </div> 533 527 534 528 {/* Services Section */} 535 529 <div> 536 - <div class="flex items-center gap-1"> 537 - <div class="iconify lucide--hard-drive" /> 538 - <p class="font-semibold">Services</p> 539 - </div> 540 - <div class="flex flex-col gap-0.5"> 530 + <p class="font-semibold">Services</p> 531 + <div class="flex flex-col gap-1"> 541 532 <For each={didDocument().service}> 542 533 {(service) => ( 543 - <div class="text-sm"> 544 - <div class="font-medium text-neutral-700 dark:text-neutral-300"> 545 - #{service.id.split("#")[1]} 546 - </div> 534 + <div class="grid grid-cols-[auto_1fr] items-center gap-x-1 text-sm text-neutral-700 dark:text-neutral-300"> 535 + <span class="iconify lucide--hash"></span> 536 + <span>{service.id.split("#")[1]}</span> 537 + <span></span> 547 538 <a 548 - class="underline hover:text-blue-400" 539 + class="w-fit underline hover:text-blue-400" 549 540 href={service.serviceEndpoint.toString()} 550 541 target="_blank" 551 542 rel="noopener" ··· 560 551 561 552 {/* Verification Methods Section */} 562 553 <div> 563 - <div class="flex items-center gap-1"> 564 - <div class="iconify lucide--shield-check" /> 565 - <p class="font-semibold">Verification Methods</p> 566 - </div> 567 - <div class="flex flex-col gap-0.5"> 554 + <p class="font-semibold">Verification Methods</p> 555 + <div class="flex flex-col gap-1"> 568 556 <For each={didDocument().verificationMethod}> 569 557 {(verif) => ( 570 558 <Show when={verif.publicKeyMultibase}> 571 559 {(key) => ( 572 - <div class="text-sm"> 573 - <div class="flex items-baseline gap-1"> 574 - <span class="font-medium text-neutral-700 dark:text-neutral-300"> 575 - #{verif.id.split("#")[1]} 576 - </span> 577 - <span class="rounded bg-neutral-200 px-1 py-0.5 text-xs text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300"> 578 - {detectKeyType(key())} 579 - </span> 560 + <div class="grid grid-cols-[auto_1fr] items-center gap-x-1 text-sm text-neutral-700 dark:text-neutral-300"> 561 + <span class="iconify lucide--hash"></span> 562 + <div class="flex items-center gap-2"> 563 + <span>{verif.id.split("#")[1]}</span> 564 + <div class="flex items-center gap-1 text-neutral-500 dark:text-neutral-400"> 565 + <span class="iconify lucide--key-round"></span> 566 + <span>{detectKeyType(key())}</span> 567 + </div> 580 568 </div> 569 + <span></span> 581 570 <div class="font-mono break-all">{key()}</div> 582 571 </div> 583 572 )} ··· 590 579 {/* Rotation Keys Section */} 591 580 <Show when={rotationKeys().length > 0}> 592 581 <div> 593 - <div class="flex items-center gap-1"> 594 - <div class="iconify lucide--key-round" /> 595 - <p class="font-semibold">Rotation Keys</p> 596 - </div> 597 - <div class="flex flex-col gap-0.5"> 582 + <p class="font-semibold">Rotation Keys</p> 583 + <div class="flex flex-col gap-1"> 598 584 <For each={rotationKeys()}> 599 585 {(key) => ( 600 - <div class="text-sm"> 601 - <span class="rounded bg-neutral-200 px-1 py-0.5 text-xs text-neutral-800 dark:bg-neutral-700 dark:text-neutral-300"> 586 + <div class="grid grid-cols-[auto_1fr] items-center gap-x-1 text-sm text-neutral-700 dark:text-neutral-300"> 587 + <span class="iconify lucide--key-round text-neutral-500 dark:text-neutral-400"></span> 588 + <span class="text-neutral-500 dark:text-neutral-400"> 602 589 {detectDidKeyType(key)} 603 590 </span> 591 + <span></span> 604 592 <div class="font-mono break-all">{key.replace("did:key:", "")}</div> 605 593 </div> 606 594 )}
+8 -8
src/views/stream.tsx
··· 143 143 144 144 return ( 145 145 <div class="flex w-full flex-col items-center"> 146 - <div class="flex gap-2 text-sm"> 146 + <div class="mb-1 flex gap-4 font-medium"> 147 147 <A 148 - class="flex items-center gap-1 border-b-2 p-1" 149 - inactiveClass="border-transparent hover:border-neutral-400 dark:hover:border-neutral-600" 148 + class="flex items-center gap-1 border-b-2" 149 + inactiveClass="border-transparent text-neutral-600 dark:text-neutral-400 hover:border-neutral-400 dark:hover:border-neutral-600" 150 150 href="/jetstream" 151 151 > 152 152 Jetstream 153 153 </A> 154 154 <A 155 - class="flex items-center gap-1 border-b-2 p-1" 156 - inactiveClass="border-transparent hover:border-neutral-400 dark:hover:border-neutral-600" 155 + class="flex items-center gap-1 border-b-2" 156 + inactiveClass="border-transparent text-neutral-600 dark:text-neutral-400 hover:border-neutral-400 dark:hover:border-neutral-600" 157 157 href="/firehose" 158 158 > 159 159 Firehose 160 160 </A> 161 161 </div> 162 162 <StickyOverlay> 163 - <form ref={formRef} class="flex w-full flex-col gap-1 text-sm"> 163 + <form ref={formRef} class="flex w-full flex-col gap-1.5 text-sm"> 164 164 <Show when={!connected()}> 165 165 <label class="flex items-center justify-end gap-x-1"> 166 166 <span class="min-w-20">Instance</span> ··· 183 183 spellcheck={false} 184 184 placeholder="Comma-separated list of collections" 185 185 value={searchParams.collections ?? ""} 186 - class="dark:bg-dark-100 dark:inset-shadow-dark-200 grow rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 py-1 inset-shadow-xs focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400" 186 + class="dark:bg-dark-100 grow rounded-lg bg-white px-2 py-1 outline-1 outline-neutral-200 focus:outline-[1.5px] focus:outline-neutral-600 dark:outline-neutral-600 dark:focus:outline-neutral-400" 187 187 /> 188 188 </label> 189 189 </Show> ··· 195 195 spellcheck={false} 196 196 placeholder="Comma-separated list of DIDs" 197 197 value={searchParams.dids ?? ""} 198 - class="dark:bg-dark-100 dark:inset-shadow-dark-200 grow rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 py-1 inset-shadow-xs focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400" 198 + class="dark:bg-dark-100 grow rounded-lg bg-white px-2 py-1 outline-1 outline-neutral-200 focus:outline-[1.5px] focus:outline-neutral-600 dark:outline-neutral-600 dark:focus:outline-neutral-400" 199 199 /> 200 200 </label> 201 201 </Show>