tangled
alpha
login
or
join now
vielle.dev
/
pdsls
forked from
pds.ls/pdsls
0
fork
atom
atproto explorer
0
fork
atom
overview
issues
pulls
pipelines
switch to codemirror
handle.invalid
6 months ago
32c5c52b
10cdef46
+252
-60
5 changed files
expand all
collapse all
unified
split
package.json
pnpm-lock.yaml
src
components
create.tsx
editor.tsx
modal.tsx
+6
-1
package.json
···
36
36
"@atcute/tangled": "^1.0.5",
37
37
"@atcute/tid": "^1.0.2",
38
38
"@atcute/uint8array": "^1.0.4",
39
39
+
"@codemirror/lang-json": "^6.0.2",
40
40
+
"@codemirror/lint": "^6.8.5",
41
41
+
"@codemirror/state": "^6.5.2",
42
42
+
"@fsegurai/codemirror-theme-basic-dark": "^6.2.2",
43
43
+
"@fsegurai/codemirror-theme-basic-light": "^6.2.2",
39
44
"@mary/exif-rm": "jsr:^0.2.2",
40
45
"@skyware/firehose": "^0.5.2",
41
46
"@solidjs/meta": "^0.29.4",
42
47
"@solidjs/router": "^0.15.3",
48
48
+
"codemirror": "^6.0.2",
43
49
"hls.js": "^1.6.11",
44
44
-
"monaco-editor": "^0.52.2",
45
50
"solid-js": "^1.9.9"
46
51
},
47
52
"packageManager": "pnpm@10.12.2+sha512.a32540185b964ee30bb4e979e405adc6af59226b438ee4cc19f9e8773667a66d302f5bfee60a39d3cac69e35e4b96e708a71dd002b7e9359c4112a1722ac323f",
+184
-8
pnpm-lock.yaml
···
56
56
'@atcute/uint8array':
57
57
specifier: ^1.0.4
58
58
version: 1.0.4
59
59
+
'@codemirror/lang-json':
60
60
+
specifier: ^6.0.2
61
61
+
version: 6.0.2
62
62
+
'@codemirror/lint':
63
63
+
specifier: ^6.8.5
64
64
+
version: 6.8.5
65
65
+
'@codemirror/state':
66
66
+
specifier: ^6.5.2
67
67
+
version: 6.5.2
68
68
+
'@fsegurai/codemirror-theme-basic-dark':
69
69
+
specifier: ^6.2.2
70
70
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)
71
71
+
'@fsegurai/codemirror-theme-basic-light':
72
72
+
specifier: ^6.2.2
73
73
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.2)(@lezer/highlight@1.2.1)
59
74
'@mary/exif-rm':
60
75
specifier: jsr:^0.2.2
61
76
version: '@jsr/mary__exif-rm@0.2.2'
···
68
83
'@solidjs/router':
69
84
specifier: ^0.15.3
70
85
version: 0.15.3(solid-js@1.9.9)
86
86
+
codemirror:
87
87
+
specifier: ^6.0.2
88
88
+
version: 6.0.2
71
89
hls.js:
72
90
specifier: ^1.6.11
73
91
version: 1.6.11
74
74
-
monaco-editor:
75
75
-
specifier: ^0.52.2
76
76
-
version: 0.52.2
77
92
solid-js:
78
93
specifier: ^1.9.9
79
94
version: 1.9.9
···
261
276
'@badrap/valita@0.4.6':
262
277
resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==}
263
278
engines: {node: '>= 18'}
279
279
+
280
280
+
'@codemirror/autocomplete@6.18.7':
281
281
+
resolution: {integrity: sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==}
282
282
+
283
283
+
'@codemirror/commands@6.8.1':
284
284
+
resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
285
285
+
286
286
+
'@codemirror/lang-json@6.0.2':
287
287
+
resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==}
288
288
+
289
289
+
'@codemirror/language@6.11.3':
290
290
+
resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==}
291
291
+
292
292
+
'@codemirror/lint@6.8.5':
293
293
+
resolution: {integrity: sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==}
294
294
+
295
295
+
'@codemirror/search@6.5.11':
296
296
+
resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==}
297
297
+
298
298
+
'@codemirror/state@6.5.2':
299
299
+
resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
300
300
+
301
301
+
'@codemirror/view@6.38.2':
302
302
+
resolution: {integrity: sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==}
264
303
265
304
'@esbuild/aix-ppc64@0.23.1':
266
305
resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
···
562
601
cpu: [x64]
563
602
os: [win32]
564
603
604
604
+
'@fsegurai/codemirror-theme-basic-dark@6.2.2':
605
605
+
resolution: {integrity: sha512-cVK4VheF7ZkuV0sfy20lmH2S7Q2xIfKoqN2HdU5rpGH8mZM2LVG9Tl+oHT0XNPpsWFqNAAKLzjYFw0IPX95Biw==}
606
606
+
peerDependencies:
607
607
+
'@codemirror/language': ^6.0.0
608
608
+
'@codemirror/state': ^6.0.0
609
609
+
'@codemirror/view': ^6.0.0
610
610
+
'@lezer/highlight': ^1.0.0
611
611
+
612
612
+
'@fsegurai/codemirror-theme-basic-light@6.2.2':
613
613
+
resolution: {integrity: sha512-zFtJ6VwwEeZ/HAXMYdcJz6+DdW1aQkngFwbD3diku79cctpTglCWH49KRFO8Mifjzwylsynm7dLyOUnGhIu0NQ==}
614
614
+
peerDependencies:
615
615
+
'@codemirror/language': ^6.0.0
616
616
+
'@codemirror/state': ^6.0.0
617
617
+
'@codemirror/view': ^6.0.0
618
618
+
'@lezer/highlight': ^1.0.0
619
619
+
565
620
'@iconify-json/lucide@1.2.66':
566
621
resolution: {integrity: sha512-TrhmfThWY2FHJIckjz7g34gUx3+cmja61DcHNdmu0rVDBQHIjPMYO1O8mMjoDSqIXEllz9wDZxCqT3lFuI+f/A==}
567
622
···
599
654
'@jsr/mary__exif-rm@0.2.2':
600
655
resolution: {integrity: sha512-+ZpLaC+1CyqWhH608Sqd6/yTG0pOlokn2tCXha7s1SMQ+GLKo4Nn/PskTeeP9Pt+6gNYSu6ednoSlRvXb2ZGxg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__exif-rm/0.2.2.tgz}
601
656
657
657
+
'@lezer/common@1.2.3':
658
658
+
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
659
659
+
660
660
+
'@lezer/highlight@1.2.1':
661
661
+
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
662
662
+
663
663
+
'@lezer/json@1.0.3':
664
664
+
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
665
665
+
666
666
+
'@lezer/lr@1.4.2':
667
667
+
resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
668
668
+
669
669
+
'@marijn/find-cluster-break@1.0.2':
670
670
+
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
671
671
+
602
672
'@noble/secp256k1@2.3.0':
603
673
resolution: {integrity: sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==}
604
674
···
859
929
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
860
930
engines: {node: '>=18'}
861
931
932
932
+
codemirror@6.0.2:
933
933
+
resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==}
934
934
+
862
935
confbox@0.1.8:
863
936
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
864
937
···
867
940
868
941
convert-source-map@2.0.0:
869
942
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
943
943
+
944
944
+
crelt@1.0.6:
945
945
+
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
870
946
871
947
csstype@3.1.3:
872
948
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
···
1067
1143
mlly@1.8.0:
1068
1144
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
1069
1145
1070
1070
-
monaco-editor@0.52.2:
1071
1071
-
resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==}
1072
1072
-
1073
1146
ms@2.1.3:
1074
1147
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
1075
1148
···
1219
1292
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
1220
1293
engines: {node: '>=0.10.0'}
1221
1294
1295
1295
+
style-mod@4.1.2:
1296
1296
+
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
1297
1297
+
1222
1298
tailwindcss@4.1.12:
1223
1299
resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==}
1224
1300
···
1320
1396
vite:
1321
1397
optional: true
1322
1398
1399
1399
+
w3c-keyname@2.2.8:
1400
1400
+
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
1401
1401
+
1323
1402
yallist@3.1.1:
1324
1403
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
1325
1404
···
1556
1635
1557
1636
'@badrap/valita@0.4.6': {}
1558
1637
1638
1638
+
'@codemirror/autocomplete@6.18.7':
1639
1639
+
dependencies:
1640
1640
+
'@codemirror/language': 6.11.3
1641
1641
+
'@codemirror/state': 6.5.2
1642
1642
+
'@codemirror/view': 6.38.2
1643
1643
+
'@lezer/common': 1.2.3
1644
1644
+
1645
1645
+
'@codemirror/commands@6.8.1':
1646
1646
+
dependencies:
1647
1647
+
'@codemirror/language': 6.11.3
1648
1648
+
'@codemirror/state': 6.5.2
1649
1649
+
'@codemirror/view': 6.38.2
1650
1650
+
'@lezer/common': 1.2.3
1651
1651
+
1652
1652
+
'@codemirror/lang-json@6.0.2':
1653
1653
+
dependencies:
1654
1654
+
'@codemirror/language': 6.11.3
1655
1655
+
'@lezer/json': 1.0.3
1656
1656
+
1657
1657
+
'@codemirror/language@6.11.3':
1658
1658
+
dependencies:
1659
1659
+
'@codemirror/state': 6.5.2
1660
1660
+
'@codemirror/view': 6.38.2
1661
1661
+
'@lezer/common': 1.2.3
1662
1662
+
'@lezer/highlight': 1.2.1
1663
1663
+
'@lezer/lr': 1.4.2
1664
1664
+
style-mod: 4.1.2
1665
1665
+
1666
1666
+
'@codemirror/lint@6.8.5':
1667
1667
+
dependencies:
1668
1668
+
'@codemirror/state': 6.5.2
1669
1669
+
'@codemirror/view': 6.38.2
1670
1670
+
crelt: 1.0.6
1671
1671
+
1672
1672
+
'@codemirror/search@6.5.11':
1673
1673
+
dependencies:
1674
1674
+
'@codemirror/state': 6.5.2
1675
1675
+
'@codemirror/view': 6.38.2
1676
1676
+
crelt: 1.0.6
1677
1677
+
1678
1678
+
'@codemirror/state@6.5.2':
1679
1679
+
dependencies:
1680
1680
+
'@marijn/find-cluster-break': 1.0.2
1681
1681
+
1682
1682
+
'@codemirror/view@6.38.2':
1683
1683
+
dependencies:
1684
1684
+
'@codemirror/state': 6.5.2
1685
1685
+
crelt: 1.0.6
1686
1686
+
style-mod: 4.1.2
1687
1687
+
w3c-keyname: 2.2.8
1688
1688
+
1559
1689
'@esbuild/aix-ppc64@0.23.1':
1560
1690
optional: true
1561
1691
···
1706
1836
'@esbuild/win32-x64@0.25.9':
1707
1837
optional: true
1708
1838
1839
1839
+
'@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)':
1840
1840
+
dependencies:
1841
1841
+
'@codemirror/language': 6.11.3
1842
1842
+
'@codemirror/state': 6.5.2
1843
1843
+
'@codemirror/view': 6.38.2
1844
1844
+
'@lezer/highlight': 1.2.1
1845
1845
+
1846
1846
+
'@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)':
1847
1847
+
dependencies:
1848
1848
+
'@codemirror/language': 6.11.3
1849
1849
+
'@codemirror/state': 6.5.2
1850
1850
+
'@codemirror/view': 6.38.2
1851
1851
+
'@lezer/highlight': 1.2.1
1852
1852
+
1709
1853
'@iconify-json/lucide@1.2.66':
1710
1854
dependencies:
1711
1855
'@iconify/types': 2.0.0
···
1758
1902
1759
1903
'@jsr/mary__exif-rm@0.2.2': {}
1760
1904
1905
1905
+
'@lezer/common@1.2.3': {}
1906
1906
+
1907
1907
+
'@lezer/highlight@1.2.1':
1908
1908
+
dependencies:
1909
1909
+
'@lezer/common': 1.2.3
1910
1910
+
1911
1911
+
'@lezer/json@1.0.3':
1912
1912
+
dependencies:
1913
1913
+
'@lezer/common': 1.2.3
1914
1914
+
'@lezer/highlight': 1.2.1
1915
1915
+
'@lezer/lr': 1.4.2
1916
1916
+
1917
1917
+
'@lezer/lr@1.4.2':
1918
1918
+
dependencies:
1919
1919
+
'@lezer/common': 1.2.3
1920
1920
+
1921
1921
+
'@marijn/find-cluster-break@1.0.2': {}
1922
1922
+
1761
1923
'@noble/secp256k1@2.3.0': {}
1762
1924
1763
1925
'@rollup/rollup-android-arm-eabi@4.50.0':
···
1966
2128
1967
2129
chownr@3.0.0: {}
1968
2130
2131
2131
+
codemirror@6.0.2:
2132
2132
+
dependencies:
2133
2133
+
'@codemirror/autocomplete': 6.18.7
2134
2134
+
'@codemirror/commands': 6.8.1
2135
2135
+
'@codemirror/language': 6.11.3
2136
2136
+
'@codemirror/lint': 6.8.5
2137
2137
+
'@codemirror/search': 6.5.11
2138
2138
+
'@codemirror/state': 6.5.2
2139
2139
+
'@codemirror/view': 6.38.2
2140
2140
+
1969
2141
confbox@0.1.8: {}
1970
2142
1971
2143
confbox@0.2.2: {}
1972
2144
1973
2145
convert-source-map@2.0.0: {}
2146
2146
+
2147
2147
+
crelt@1.0.6: {}
1974
2148
1975
2149
csstype@3.1.3: {}
1976
2150
···
2164
2338
pkg-types: 1.3.1
2165
2339
ufo: 1.6.1
2166
2340
2167
2167
-
monaco-editor@0.52.2: {}
2168
2168
-
2169
2341
ms@2.1.3: {}
2170
2342
2171
2343
nanoevents@9.1.0: {}
···
2269
2441
2270
2442
source-map-js@1.2.1: {}
2271
2443
2444
2444
+
style-mod@4.1.2: {}
2445
2445
+
2272
2446
tailwindcss@4.1.12: {}
2273
2447
2274
2448
tapable@2.2.3: {}
···
2343
2517
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)):
2344
2518
optionalDependencies:
2345
2519
vite: 7.1.4(@types/node@22.13.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.19.2)
2520
2520
+
2521
2521
+
w3c-keyname@2.2.8: {}
2346
2522
2347
2523
yallist@3.1.1: {}
2348
2524
+14
-23
src/components/create.tsx
···
1
1
import { createSignal, Show } from "solid-js";
2
2
import { Client } from "@atcute/client";
3
3
import { agent } from "../components/login.jsx";
4
4
-
import { editor, Editor } from "../components/editor.jsx";
5
5
-
import * as monaco from "monaco-editor";
4
4
+
import { Editor, editorView } from "../components/editor.jsx";
6
5
import Tooltip from "./tooltip.jsx";
7
6
import { useNavigate, useParams } from "@solidjs/router";
8
7
import { remove } from "@mary/exif-rm";
···
17
16
const [openDialog, setOpenDialog] = createSignal(false);
18
17
const [notice, setNotice] = createSignal("");
19
18
const [uploading, setUploading] = createSignal(false);
20
20
-
let model: monaco.editor.IModel;
21
19
let formRef!: HTMLFormElement;
22
20
23
21
const placeholder = () => {
···
44
42
const validate = formData.get("validate")?.toString();
45
43
let record: any;
46
44
try {
47
47
-
record = JSON.parse(model.getValue());
45
45
+
record = JSON.parse(editorView.state.doc.toString());
48
46
} catch (e: any) {
49
47
setNotice(e.message);
50
48
return;
···
71
69
};
72
70
73
71
const editRecord = async (formData: FormData) => {
74
74
-
const record = model.getValue();
72
72
+
const record = editorView.state.doc.toString();
75
73
const validate =
76
74
formData.get("validate")?.toString() === "true" ? true
77
75
: formData.get("validate")?.toString() === "false" ? false
···
79
77
if (!record) return;
80
78
const rpc = new Client({ handler: agent()! });
81
79
try {
82
82
-
const editedRecord = JSON.parse(record.toString());
80
80
+
const editedRecord = JSON.parse(record);
83
81
if (formData.get("recreate")) {
84
82
const res = await rpc.post("com.atproto.repo.applyWrites", {
85
83
input: {
···
155
153
setNotice(res.data.error);
156
154
return;
157
155
}
158
158
-
editor.executeEdits("editor", [
159
159
-
{
160
160
-
range: editor.getSelection() as monaco.IRange,
161
161
-
text: JSON.stringify(res.data.blob, null, 2),
156
156
+
editorView.dispatch({
157
157
+
changes: {
158
158
+
from: editorView.state.selection.main.head,
159
159
+
insert: JSON.stringify(res.data.blob, null, 2),
162
160
},
163
163
-
]);
164
164
-
editor.trigger("editor", "editor.action.formatDocument", {});
165
165
-
};
166
166
-
167
167
-
const createModel = () => {
168
168
-
if (!model)
169
169
-
model = monaco.editor.createModel(
170
170
-
JSON.stringify(props.create ? placeholder() : props.record, null, 2),
171
171
-
"json",
172
172
-
);
161
161
+
});
173
162
};
174
163
175
164
return (
176
165
<>
177
177
-
<Modal open={openDialog()} onClose={() => setOpenDialog(false)}>
166
166
+
<Modal open={openDialog()} onClose={() => setOpenDialog(false)} closeOnClick={false}>
178
167
<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">
179
168
<div class="mb-2 flex w-full justify-between">
180
169
<div class="flex items-center gap-1 font-semibold">
···
251
240
</div>
252
241
</div>
253
242
</div>
254
254
-
<Editor model={model!} />
243
243
+
<Editor
244
244
+
content={JSON.stringify(props.create ? placeholder() : props.record, null, 2)}
245
245
+
/>
255
246
<div class="flex flex-col gap-2">
256
247
<Show when={notice()}>
257
248
<div class="text-red-500 dark:text-red-400">{notice()}</div>
···
283
274
<button
284
275
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"}`}
285
276
onclick={() => {
286
286
-
createModel();
277
277
+
setNotice("");
287
278
setOpenDialog(true);
288
279
}}
289
280
>
+46
-27
src/components/editor.tsx
···
1
1
-
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
2
2
-
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
3
3
-
import * as monaco from "monaco-editor";
4
4
-
import { onMount } from "solid-js";
1
1
+
import { onCleanup, onMount } from "solid-js";
2
2
+
import { basicSetup, EditorView } from "codemirror";
3
3
+
import { json, jsonParseLinter } from "@codemirror/lang-json";
4
4
+
import { linter } from "@codemirror/lint";
5
5
+
import { basicLight } from "@fsegurai/codemirror-theme-basic-light";
6
6
+
import { basicDark } from "@fsegurai/codemirror-theme-basic-dark";
7
7
+
import { Compartment } from "@codemirror/state";
8
8
+
9
9
+
export let editorView: EditorView;
5
10
6
6
-
const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 1;
11
11
+
const Editor = (props: { content: string }) => {
12
12
+
let editorDiv!: HTMLDivElement;
13
13
+
let themeColor = new Compartment();
7
14
8
8
-
self.MonacoEnvironment = {
9
9
-
getWorker(_, label) {
10
10
-
if (label === "json") return new jsonWorker();
11
11
-
return new editorWorker();
12
12
-
},
13
13
-
};
15
15
+
const themeEvent = () => {
16
16
+
editorView.dispatch({
17
17
+
effects: themeColor.reconfigure(
18
18
+
window.matchMedia("(prefers-color-scheme: dark)").matches ? basicDark : basicLight,
19
19
+
),
20
20
+
});
21
21
+
};
14
22
15
15
-
let editor: monaco.editor.IStandaloneCodeEditor;
23
23
+
onMount(() => {
24
24
+
const theme = EditorView.theme({
25
25
+
".cm-content": {
26
26
+
fontFamily: "'Roboto Mono', monospace",
27
27
+
fontSize: "12px",
28
28
+
},
29
29
+
".cm-scroller": {
30
30
+
overflow: "auto",
31
31
+
maxHeight: "20rem",
32
32
+
},
33
33
+
});
16
34
17
17
-
const Editor = (props: { model: monaco.editor.IModel }) => {
18
18
-
let editorDiv!: HTMLDivElement;
35
35
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", themeEvent);
19
36
20
20
-
onMount(() => {
21
21
-
editor = monaco.editor.create(editorDiv, {
22
22
-
minimap: { enabled: false },
23
23
-
theme: document.documentElement.classList.contains("dark") ? "vs-dark" : "vs",
24
24
-
model: props.model,
25
25
-
wordWrap: "on",
26
26
-
automaticLayout: true,
27
27
-
fontFamily: "Roboto Mono",
28
28
-
lineNumbers: isTouchDevice ? "off" : "on",
29
29
-
fontSize: 12,
37
37
+
editorView = new EditorView({
38
38
+
doc: props.content,
39
39
+
parent: editorDiv,
40
40
+
extensions: [
41
41
+
basicSetup,
42
42
+
theme,
43
43
+
json(),
44
44
+
linter(jsonParseLinter()),
45
45
+
themeColor.of(document.documentElement.classList.contains("dark") ? basicDark : basicLight),
46
46
+
],
30
47
});
31
48
});
32
49
33
33
-
return (
34
34
-
<div ref={editorDiv} class="dark:shadow-dark-900/80 h-[20rem] shadow-sm sm:h-[24rem]"></div>
50
50
+
onCleanup(() =>
51
51
+
window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", themeEvent),
35
52
);
53
53
+
54
54
+
return <div ref={editorDiv} class="dark:shadow-dark-900/80 shadow-sm"></div>;
36
55
};
37
56
38
38
-
export { Editor, editor };
57
57
+
export { Editor };
+2
-1
src/components/modal.tsx
···
3
3
export interface ModalProps extends Pick<ComponentProps<"svg">, "children"> {
4
4
open?: boolean;
5
5
onClose?: () => void;
6
6
+
closeOnClick?: boolean;
6
7
}
7
8
8
9
export const Modal = (props: ModalProps) => {
···
18
19
onCleanup(() => node.close());
19
20
}}
20
21
onClick={(ev) => {
21
21
-
if (ev.target === ev.currentTarget) {
22
22
+
if ((props.closeOnClick ?? true) && ev.target === ev.currentTarget) {
22
23
if (props.onClose) props.onClose();
23
24
}
24
25
}}