atproto explorer pdsls.dev
atproto tool

switch to codemirror

Changed files
+252 -60
src
+6 -1
package.json
···
"@atcute/tangled": "^1.0.5",
"@atcute/tid": "^1.0.2",
"@atcute/uint8array": "^1.0.4",
"@mary/exif-rm": "jsr:^0.2.2",
"@skyware/firehose": "^0.5.2",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3",
"hls.js": "^1.6.11",
-
"monaco-editor": "^0.52.2",
"solid-js": "^1.9.9"
},
"packageManager": "pnpm@10.12.2+sha512.a32540185b964ee30bb4e979e405adc6af59226b438ee4cc19f9e8773667a66d302f5bfee60a39d3cac69e35e4b96e708a71dd002b7e9359c4112a1722ac323f",
···
"@atcute/tangled": "^1.0.5",
"@atcute/tid": "^1.0.2",
"@atcute/uint8array": "^1.0.4",
+
"@codemirror/lang-json": "^6.0.2",
+
"@codemirror/lint": "^6.8.5",
+
"@codemirror/state": "^6.5.2",
+
"@fsegurai/codemirror-theme-basic-dark": "^6.2.2",
+
"@fsegurai/codemirror-theme-basic-light": "^6.2.2",
"@mary/exif-rm": "jsr:^0.2.2",
"@skyware/firehose": "^0.5.2",
"@solidjs/meta": "^0.29.4",
"@solidjs/router": "^0.15.3",
+
"codemirror": "^6.0.2",
"hls.js": "^1.6.11",
"solid-js": "^1.9.9"
},
"packageManager": "pnpm@10.12.2+sha512.a32540185b964ee30bb4e979e405adc6af59226b438ee4cc19f9e8773667a66d302f5bfee60a39d3cac69e35e4b96e708a71dd002b7e9359c4112a1722ac323f",
+184 -8
pnpm-lock.yaml
···
'@atcute/uint8array':
specifier: ^1.0.4
version: 1.0.4
'@mary/exif-rm':
specifier: jsr:^0.2.2
version: '@jsr/mary__exif-rm@0.2.2'
···
'@solidjs/router':
specifier: ^0.15.3
version: 0.15.3(solid-js@1.9.9)
hls.js:
specifier: ^1.6.11
version: 1.6.11
-
monaco-editor:
-
specifier: ^0.52.2
-
version: 0.52.2
solid-js:
specifier: ^1.9.9
version: 1.9.9
···
'@badrap/valita@0.4.6':
resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==}
engines: {node: '>= 18'}
'@esbuild/aix-ppc64@0.23.1':
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
···
cpu: [x64]
os: [win32]
'@iconify-json/lucide@1.2.66':
resolution: {integrity: sha512-TrhmfThWY2FHJIckjz7g34gUx3+cmja61DcHNdmu0rVDBQHIjPMYO1O8mMjoDSqIXEllz9wDZxCqT3lFuI+f/A==}
···
'@jsr/mary__exif-rm@0.2.2':
resolution: {integrity: sha512-+ZpLaC+1CyqWhH608Sqd6/yTG0pOlokn2tCXha7s1SMQ+GLKo4Nn/PskTeeP9Pt+6gNYSu6ednoSlRvXb2ZGxg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__exif-rm/0.2.2.tgz}
'@noble/secp256k1@2.3.0':
resolution: {integrity: sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==}
···
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
···
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
···
mlly@1.8.0:
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
-
monaco-editor@0.52.2:
-
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
-
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
···
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
tailwindcss@4.1.12:
resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==}
···
vite:
optional: true
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
···
'@badrap/valita@0.4.6': {}
'@esbuild/aix-ppc64@0.23.1':
optional: true
···
'@esbuild/win32-x64@0.25.9':
optional: true
'@iconify-json/lucide@1.2.66':
dependencies:
'@iconify/types': 2.0.0
···
'@jsr/mary__exif-rm@0.2.2': {}
'@noble/secp256k1@2.3.0': {}
'@rollup/rollup-android-arm-eabi@4.50.0':
···
chownr@3.0.0: {}
confbox@0.1.8: {}
confbox@0.2.2: {}
convert-source-map@2.0.0: {}
csstype@3.1.3: {}
···
pkg-types: 1.3.1
ufo: 1.6.1
-
monaco-editor@0.52.2: {}
-
ms@2.1.3: {}
nanoevents@9.1.0: {}
···
source-map-js@1.2.1: {}
tailwindcss@4.1.12: {}
tapable@2.2.3: {}
···
vitefu@1.1.1(vite@7.1.4(@types/node@22.13.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.19.2)):
optionalDependencies:
vite: 7.1.4(@types/node@22.13.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.19.2)
yallist@3.1.1: {}
···
'@atcute/uint8array':
specifier: ^1.0.4
version: 1.0.4
+
'@codemirror/lang-json':
+
specifier: ^6.0.2
+
version: 6.0.2
+
'@codemirror/lint':
+
specifier: ^6.8.5
+
version: 6.8.5
+
'@codemirror/state':
+
specifier: ^6.5.2
+
version: 6.5.2
+
'@fsegurai/codemirror-theme-basic-dark':
+
specifier: ^6.2.2
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)
+
'@fsegurai/codemirror-theme-basic-light':
+
specifier: ^6.2.2
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)
'@mary/exif-rm':
specifier: jsr:^0.2.2
version: '@jsr/mary__exif-rm@0.2.2'
···
'@solidjs/router':
specifier: ^0.15.3
version: 0.15.3(solid-js@1.9.9)
+
codemirror:
+
specifier: ^6.0.2
+
version: 6.0.2
hls.js:
specifier: ^1.6.11
version: 1.6.11
solid-js:
specifier: ^1.9.9
version: 1.9.9
···
'@badrap/valita@0.4.6':
resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==}
engines: {node: '>= 18'}
+
+
'@codemirror/autocomplete@6.18.7':
+
resolution: {integrity: sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==}
+
+
'@codemirror/commands@6.8.1':
+
resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
+
+
'@codemirror/lang-json@6.0.2':
+
resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==}
+
+
'@codemirror/language@6.11.3':
+
resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==}
+
+
'@codemirror/lint@6.8.5':
+
resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==}
+
+
'@codemirror/search@6.5.11':
+
resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==}
+
+
'@codemirror/state@6.5.2':
+
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
+
+
'@codemirror/view@6.38.2':
+
resolution: {integrity: sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==}
'@esbuild/aix-ppc64@0.23.1':
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
···
cpu: [x64]
os: [win32]
+
'@fsegurai/codemirror-theme-basic-dark@6.2.2':
+
resolution: {integrity: sha512-cVK4VheF7ZkuV0sfy20lmH2S7Q2xIfKoqN2HdU5rpGH8mZM2LVG9Tl+oHT0XNPpsWFqNAAKLzjYFw0IPX95Biw==}
+
peerDependencies:
+
'@codemirror/language': ^6.0.0
+
'@codemirror/state': ^6.0.0
+
'@codemirror/view': ^6.0.0
+
'@lezer/highlight': ^1.0.0
+
+
'@fsegurai/codemirror-theme-basic-light@6.2.2':
+
resolution: {integrity: sha512-zFtJ6VwwEeZ/HAXMYdcJz6+DdW1aQkngFwbD3diku79cctpTglCWH49KRFO8Mifjzwylsynm7dLyOUnGhIu0NQ==}
+
peerDependencies:
+
'@codemirror/language': ^6.0.0
+
'@codemirror/state': ^6.0.0
+
'@codemirror/view': ^6.0.0
+
'@lezer/highlight': ^1.0.0
+
'@iconify-json/lucide@1.2.66':
resolution: {integrity: sha512-TrhmfThWY2FHJIckjz7g34gUx3+cmja61DcHNdmu0rVDBQHIjPMYO1O8mMjoDSqIXEllz9wDZxCqT3lFuI+f/A==}
···
'@jsr/mary__exif-rm@0.2.2':
resolution: {integrity: sha512-+ZpLaC+1CyqWhH608Sqd6/yTG0pOlokn2tCXha7s1SMQ+GLKo4Nn/PskTeeP9Pt+6gNYSu6ednoSlRvXb2ZGxg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__exif-rm/0.2.2.tgz}
+
'@lezer/common@1.2.3':
+
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
+
+
'@lezer/highlight@1.2.1':
+
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
+
+
'@lezer/json@1.0.3':
+
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
+
+
'@lezer/lr@1.4.2':
+
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
+
+
'@marijn/find-cluster-break@1.0.2':
+
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
+
'@noble/secp256k1@2.3.0':
resolution: {integrity: sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==}
···
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
engines: {node: '>=18'}
+
codemirror@6.0.2:
+
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
+
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
···
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+
crelt@1.0.6:
+
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
···
mlly@1.8.0:
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
···
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+
style-mod@4.1.2:
+
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
+
tailwindcss@4.1.12:
resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==}
···
vite:
optional: true
+
w3c-keyname@2.2.8:
+
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
···
'@badrap/valita@0.4.6': {}
+
'@codemirror/autocomplete@6.18.7':
+
dependencies:
+
'@codemirror/language': 6.11.3
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
'@lezer/common': 1.2.3
+
+
'@codemirror/commands@6.8.1':
+
dependencies:
+
'@codemirror/language': 6.11.3
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
'@lezer/common': 1.2.3
+
+
'@codemirror/lang-json@6.0.2':
+
dependencies:
+
'@codemirror/language': 6.11.3
+
'@lezer/json': 1.0.3
+
+
'@codemirror/language@6.11.3':
+
dependencies:
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
'@lezer/common': 1.2.3
+
'@lezer/highlight': 1.2.1
+
'@lezer/lr': 1.4.2
+
style-mod: 4.1.2
+
+
'@codemirror/lint@6.8.5':
+
dependencies:
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
crelt: 1.0.6
+
+
'@codemirror/search@6.5.11':
+
dependencies:
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
crelt: 1.0.6
+
+
'@codemirror/state@6.5.2':
+
dependencies:
+
'@marijn/find-cluster-break': 1.0.2
+
+
'@codemirror/view@6.38.2':
+
dependencies:
+
'@codemirror/state': 6.5.2
+
crelt: 1.0.6
+
style-mod: 4.1.2
+
w3c-keyname: 2.2.8
+
'@esbuild/aix-ppc64@0.23.1':
optional: true
···
'@esbuild/win32-x64@0.25.9':
optional: true
+
'@fsegurai/codemirror-theme-basic-dark@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)':
+
dependencies:
+
'@codemirror/language': 6.11.3
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
'@lezer/highlight': 1.2.1
+
+
'@fsegurai/codemirror-theme-basic-light@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)':
+
dependencies:
+
'@codemirror/language': 6.11.3
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
'@lezer/highlight': 1.2.1
+
'@iconify-json/lucide@1.2.66':
dependencies:
'@iconify/types': 2.0.0
···
'@jsr/mary__exif-rm@0.2.2': {}
+
'@lezer/common@1.2.3': {}
+
+
'@lezer/highlight@1.2.1':
+
dependencies:
+
'@lezer/common': 1.2.3
+
+
'@lezer/json@1.0.3':
+
dependencies:
+
'@lezer/common': 1.2.3
+
'@lezer/highlight': 1.2.1
+
'@lezer/lr': 1.4.2
+
+
'@lezer/lr@1.4.2':
+
dependencies:
+
'@lezer/common': 1.2.3
+
+
'@marijn/find-cluster-break@1.0.2': {}
+
'@noble/secp256k1@2.3.0': {}
'@rollup/rollup-android-arm-eabi@4.50.0':
···
chownr@3.0.0: {}
+
codemirror@6.0.2:
+
dependencies:
+
'@codemirror/autocomplete': 6.18.7
+
'@codemirror/commands': 6.8.1
+
'@codemirror/language': 6.11.3
+
'@codemirror/lint': 6.8.5
+
'@codemirror/search': 6.5.11
+
'@codemirror/state': 6.5.2
+
'@codemirror/view': 6.38.2
+
confbox@0.1.8: {}
confbox@0.2.2: {}
convert-source-map@2.0.0: {}
+
+
crelt@1.0.6: {}
csstype@3.1.3: {}
···
pkg-types: 1.3.1
ufo: 1.6.1
ms@2.1.3: {}
nanoevents@9.1.0: {}
···
source-map-js@1.2.1: {}
+
style-mod@4.1.2: {}
+
tailwindcss@4.1.12: {}
tapable@2.2.3: {}
···
vitefu@1.1.1(vite@7.1.4(@types/node@22.13.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.19.2)):
optionalDependencies:
vite: 7.1.4(@types/node@22.13.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.19.2)
+
+
w3c-keyname@2.2.8: {}
yallist@3.1.1: {}
+14 -23
src/components/create.tsx
···
import { createSignal, Show } from "solid-js";
import { Client } from "@atcute/client";
import { agent } from "../components/login.jsx";
-
import { editor, Editor } from "../components/editor.jsx";
-
import * as monaco from "monaco-editor";
import Tooltip from "./tooltip.jsx";
import { useNavigate, useParams } from "@solidjs/router";
import { remove } from "@mary/exif-rm";
···
const [openDialog, setOpenDialog] = createSignal(false);
const [notice, setNotice] = createSignal("");
const [uploading, setUploading] = createSignal(false);
-
let model: monaco.editor.IModel;
let formRef!: HTMLFormElement;
const placeholder = () => {
···
const validate = formData.get("validate")?.toString();
let record: any;
try {
-
record = JSON.parse(model.getValue());
} catch (e: any) {
setNotice(e.message);
return;
···
};
const editRecord = async (formData: FormData) => {
-
const record = model.getValue();
const validate =
formData.get("validate")?.toString() === "true" ? true
: formData.get("validate")?.toString() === "false" ? false
···
if (!record) return;
const rpc = new Client({ handler: agent()! });
try {
-
const editedRecord = JSON.parse(record.toString());
if (formData.get("recreate")) {
const res = await rpc.post("com.atproto.repo.applyWrites", {
input: {
···
setNotice(res.data.error);
return;
}
-
editor.executeEdits("editor", [
-
{
-
range: editor.getSelection() as monaco.IRange,
-
text: JSON.stringify(res.data.blob, null, 2),
},
-
]);
-
editor.trigger("editor", "editor.action.formatDocument", {});
-
};
-
-
const createModel = () => {
-
if (!model)
-
model = monaco.editor.createModel(
-
JSON.stringify(props.create ? placeholder() : props.record, null, 2),
-
"json",
-
);
};
return (
<>
-
<Modal open={openDialog()} onClose={() => setOpenDialog(false)}>
<div class="dark:bg-dark-800/70 dark:shadow-dark-900/80 absolute top-12 left-[50%] w-[22rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-200/70 p-2 text-neutral-900 shadow-md backdrop-blur-xs transition-opacity duration-300 sm:w-xl sm:p-4 lg:w-[48rem] dark:border-neutral-700 dark:text-neutral-200 starting:opacity-0">
<div class="mb-2 flex w-full justify-between">
<div class="flex items-center gap-1 font-semibold">
···
</div>
</div>
</div>
-
<Editor model={model!} />
<div class="flex flex-col gap-2">
<Show when={notice()}>
<div class="text-red-500 dark:text-red-400">{notice()}</div>
···
<button
class={`flex items-center p-1 hover:bg-neutral-200 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-700 ${props.create ? "rounded-lg" : "rounded-sm"}`}
onclick={() => {
-
createModel();
setOpenDialog(true);
}}
>
···
import { createSignal, Show } from "solid-js";
import { Client } from "@atcute/client";
import { agent } from "../components/login.jsx";
+
import { Editor, editorView } from "../components/editor.jsx";
import Tooltip from "./tooltip.jsx";
import { useNavigate, useParams } from "@solidjs/router";
import { remove } from "@mary/exif-rm";
···
const [openDialog, setOpenDialog] = createSignal(false);
const [notice, setNotice] = createSignal("");
const [uploading, setUploading] = createSignal(false);
let formRef!: HTMLFormElement;
const placeholder = () => {
···
const validate = formData.get("validate")?.toString();
let record: any;
try {
+
record = JSON.parse(editorView.state.doc.toString());
} catch (e: any) {
setNotice(e.message);
return;
···
};
const editRecord = async (formData: FormData) => {
+
const record = editorView.state.doc.toString();
const validate =
formData.get("validate")?.toString() === "true" ? true
: formData.get("validate")?.toString() === "false" ? false
···
if (!record) return;
const rpc = new Client({ handler: agent()! });
try {
+
const editedRecord = JSON.parse(record);
if (formData.get("recreate")) {
const res = await rpc.post("com.atproto.repo.applyWrites", {
input: {
···
setNotice(res.data.error);
return;
}
+
editorView.dispatch({
+
changes: {
+
from: editorView.state.selection.main.head,
+
insert: JSON.stringify(res.data.blob, null, 2),
},
+
});
};
return (
<>
+
<Modal open={openDialog()} onClose={() => setOpenDialog(false)} closeOnClick={false}>
<div class="dark:bg-dark-800/70 dark:shadow-dark-900/80 absolute top-12 left-[50%] w-[22rem] -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-200/70 p-2 text-neutral-900 shadow-md backdrop-blur-xs transition-opacity duration-300 sm:w-xl sm:p-4 lg:w-[48rem] dark:border-neutral-700 dark:text-neutral-200 starting:opacity-0">
<div class="mb-2 flex w-full justify-between">
<div class="flex items-center gap-1 font-semibold">
···
</div>
</div>
</div>
+
<Editor
+
content={JSON.stringify(props.create ? placeholder() : props.record, null, 2)}
+
/>
<div class="flex flex-col gap-2">
<Show when={notice()}>
<div class="text-red-500 dark:text-red-400">{notice()}</div>
···
<button
class={`flex items-center p-1 hover:bg-neutral-200 active:bg-neutral-200 dark:hover:bg-neutral-700 dark:active:bg-neutral-700 ${props.create ? "rounded-lg" : "rounded-sm"}`}
onclick={() => {
+
setNotice("");
setOpenDialog(true);
}}
>
+46 -27
src/components/editor.tsx
···
-
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
-
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
-
import * as monaco from "monaco-editor";
-
import { onMount } from "solid-js";
-
const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 1;
-
self.MonacoEnvironment = {
-
getWorker(_, label) {
-
if (label === "json") return new jsonWorker();
-
return new editorWorker();
-
},
-
};
-
let editor: monaco.editor.IStandaloneCodeEditor;
-
const Editor = (props: { model: monaco.editor.IModel }) => {
-
let editorDiv!: HTMLDivElement;
-
onMount(() => {
-
editor = monaco.editor.create(editorDiv, {
-
minimap: { enabled: false },
-
theme: document.documentElement.classList.contains("dark") ? "vs-dark" : "vs",
-
model: props.model,
-
wordWrap: "on",
-
automaticLayout: true,
-
fontFamily: "Roboto Mono",
-
lineNumbers: isTouchDevice ? "off" : "on",
-
fontSize: 12,
});
});
-
return (
-
<div ref={editorDiv} class="dark:shadow-dark-900/80 h-[20rem] shadow-sm sm:h-[24rem]"></div>
);
};
-
export { Editor, editor };
···
+
import { onCleanup, onMount } from "solid-js";
+
import { basicSetup, EditorView } from "codemirror";
+
import { json, jsonParseLinter } from "@codemirror/lang-json";
+
import { linter } from "@codemirror/lint";
+
import { basicLight } from "@fsegurai/codemirror-theme-basic-light";
+
import { basicDark } from "@fsegurai/codemirror-theme-basic-dark";
+
import { Compartment } from "@codemirror/state";
+
+
export let editorView: EditorView;
+
const Editor = (props: { content: string }) => {
+
let editorDiv!: HTMLDivElement;
+
let themeColor = new Compartment();
+
const themeEvent = () => {
+
editorView.dispatch({
+
effects: themeColor.reconfigure(
+
window.matchMedia("(prefers-color-scheme: dark)").matches ? basicDark : basicLight,
+
),
+
});
+
};
+
onMount(() => {
+
const theme = EditorView.theme({
+
".cm-content": {
+
fontFamily: "'Roboto Mono', monospace",
+
fontSize: "12px",
+
},
+
".cm-scroller": {
+
overflow: "auto",
+
maxHeight: "20rem",
+
},
+
});
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", themeEvent);
+
editorView = new EditorView({
+
doc: props.content,
+
parent: editorDiv,
+
extensions: [
+
basicSetup,
+
theme,
+
json(),
+
linter(jsonParseLinter()),
+
themeColor.of(document.documentElement.classList.contains("dark") ? basicDark : basicLight),
+
],
});
});
+
onCleanup(() =>
+
window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", themeEvent),
);
+
+
return <div ref={editorDiv} class="dark:shadow-dark-900/80 shadow-sm"></div>;
};
+
export { Editor };
+2 -1
src/components/modal.tsx
···
export interface ModalProps extends Pick<ComponentProps<"svg">, "children"> {
open?: boolean;
onClose?: () => void;
}
export const Modal = (props: ModalProps) => {
···
onCleanup(() => node.close());
}}
onClick={(ev) => {
-
if (ev.target === ev.currentTarget) {
if (props.onClose) props.onClose();
}
}}
···
export interface ModalProps extends Pick<ComponentProps<"svg">, "children"> {
open?: boolean;
onClose?: () => void;
+
closeOnClick?: boolean;
}
export const Modal = (props: ModalProps) => {
···
onCleanup(() => node.close());
}}
onClick={(ev) => {
+
if ((props.closeOnClick ?? true) && ev.target === ev.currentTarget) {
if (props.onClose) props.onClose();
}
}}