+1
index.html
+1
index.html
···
15
15
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
16
16
<link rel="preconnect" href="https://fonts.bunny.net" />
17
17
<link href="https://fonts.bunny.net/css?family=roboto-mono:400" rel="stylesheet" />
18
+
<link href="https://fonts.cdnfonts.com/css/pecita" rel="stylesheet" />
18
19
<script>
19
20
document.documentElement.classList.toggle(
20
21
"dark",
+2
-2
package.json
+2
-2
package.json
···
9
9
"serve": "vite preview"
10
10
},
11
11
"devDependencies": {
12
-
"@iconify-json/lucide": "^1.2.69",
12
+
"@iconify-json/lucide": "^1.2.70",
13
13
"@iconify/tailwind4": "^1.0.6",
14
14
"@tailwindcss/vite": "^4.1.14",
15
15
"prettier": "^3.6.2",
16
16
"prettier-plugin-organize-imports": "^4.3.0",
17
-
"prettier-plugin-tailwindcss": "^0.7.0",
17
+
"prettier-plugin-tailwindcss": "^0.7.1",
18
18
"tailwindcss": "^4.1.14",
19
19
"typescript": "^5.9.3",
20
20
"vite": "^7.1.10",
+127
-127
pnpm-lock.yaml
+127
-127
pnpm-lock.yaml
···
79
79
version: 6.38.6
80
80
'@fsegurai/codemirror-theme-basic-dark':
81
81
specifier: ^6.2.2
82
-
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.1)
82
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.2)
83
83
'@fsegurai/codemirror-theme-basic-light':
84
84
specifier: ^6.2.2
85
-
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.1)
85
+
version: 6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.2)
86
86
'@mary/exif-rm':
87
87
specifier: jsr:^0.2.2
88
88
version: '@jsr/mary__exif-rm@0.2.2'
···
103
103
version: 1.9.9
104
104
devDependencies:
105
105
'@iconify-json/lucide':
106
-
specifier: ^1.2.69
107
-
version: 1.2.69
106
+
specifier: ^1.2.70
107
+
version: 1.2.70
108
108
'@iconify/tailwind4':
109
109
specifier: ^1.0.6
110
110
version: 1.0.6(tailwindcss@4.1.14)
···
118
118
specifier: ^4.3.0
119
119
version: 4.3.0(prettier@3.6.2)(typescript@5.9.3)
120
120
prettier-plugin-tailwindcss:
121
-
specifier: ^0.7.0
122
-
version: 0.7.0(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2)
121
+
specifier: ^0.7.1
122
+
version: 0.7.1(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2)
123
123
tailwindcss:
124
124
specifier: ^4.1.14
125
125
version: 4.1.14
···
634
634
'@codemirror/view': ^6.0.0
635
635
'@lezer/highlight': ^1.0.0
636
636
637
-
'@iconify-json/lucide@1.2.69':
638
-
resolution: {integrity: sha512-xOhNf74m+C+nSCObfEqYi34dXk1GMfMUcOB+gfqKY/bn0RcsPLinGfgouOvrUFEreDEFbCti7sdheTf5HESLTA==}
637
+
'@iconify-json/lucide@1.2.70':
638
+
resolution: {integrity: sha512-56s9NdBKgshywVY1e4gOcxzAbU1J649e/jLHBJU1tyNqRs7mFLVEGwj2mmzHJ5YAZB5Tsngi4f/ocTBPlG06ZA==}
639
639
640
640
'@iconify/tailwind4@1.0.6':
641
641
resolution: {integrity: sha512-43ZXe+bC7CuE2LCgROdqbQeFYJi/J7L/k1UpSy8KDQlWVsWxPzLSWbWhlJx4uRYLOh1NRyw02YlDOgzBOFNd+A==}
···
671
671
'@jsr/mary__exif-rm@0.2.2':
672
672
resolution: {integrity: sha512-+ZpLaC+1CyqWhH608Sqd6/yTG0pOlokn2tCXha7s1SMQ+GLKo4Nn/PskTeeP9Pt+6gNYSu6ednoSlRvXb2ZGxg==, tarball: https://npm.jsr.io/~/11/@jsr/mary__exif-rm/0.2.2.tgz}
673
673
674
-
'@lezer/common@1.2.3':
675
-
resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
674
+
'@lezer/common@1.3.0':
675
+
resolution: {integrity: sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==}
676
676
677
-
'@lezer/highlight@1.2.1':
678
-
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
677
+
'@lezer/highlight@1.2.2':
678
+
resolution: {integrity: sha512-z8TQwaBXXQIvG6i2g3e9cgMwUUXu9Ib7jo2qRRggdhwKpM56Dw3PM3wmexn+EGaaOZ7az0K7sjc3/gcGW7sz7A==}
679
679
680
680
'@lezer/json@1.0.3':
681
681
resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==}
···
689
689
'@noble/secp256k1@2.3.0':
690
690
resolution: {integrity: sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw==}
691
691
692
-
'@rollup/rollup-android-arm-eabi@4.52.4':
693
-
resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==}
692
+
'@rollup/rollup-android-arm-eabi@4.52.5':
693
+
resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==}
694
694
cpu: [arm]
695
695
os: [android]
696
696
697
-
'@rollup/rollup-android-arm64@4.52.4':
698
-
resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==}
697
+
'@rollup/rollup-android-arm64@4.52.5':
698
+
resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==}
699
699
cpu: [arm64]
700
700
os: [android]
701
701
702
-
'@rollup/rollup-darwin-arm64@4.52.4':
703
-
resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==}
702
+
'@rollup/rollup-darwin-arm64@4.52.5':
703
+
resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==}
704
704
cpu: [arm64]
705
705
os: [darwin]
706
706
707
-
'@rollup/rollup-darwin-x64@4.52.4':
708
-
resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==}
707
+
'@rollup/rollup-darwin-x64@4.52.5':
708
+
resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==}
709
709
cpu: [x64]
710
710
os: [darwin]
711
711
712
-
'@rollup/rollup-freebsd-arm64@4.52.4':
713
-
resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==}
712
+
'@rollup/rollup-freebsd-arm64@4.52.5':
713
+
resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==}
714
714
cpu: [arm64]
715
715
os: [freebsd]
716
716
717
-
'@rollup/rollup-freebsd-x64@4.52.4':
718
-
resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==}
717
+
'@rollup/rollup-freebsd-x64@4.52.5':
718
+
resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==}
719
719
cpu: [x64]
720
720
os: [freebsd]
721
721
722
-
'@rollup/rollup-linux-arm-gnueabihf@4.52.4':
723
-
resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==}
722
+
'@rollup/rollup-linux-arm-gnueabihf@4.52.5':
723
+
resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
724
724
cpu: [arm]
725
725
os: [linux]
726
726
727
-
'@rollup/rollup-linux-arm-musleabihf@4.52.4':
728
-
resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==}
727
+
'@rollup/rollup-linux-arm-musleabihf@4.52.5':
728
+
resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
729
729
cpu: [arm]
730
730
os: [linux]
731
731
732
-
'@rollup/rollup-linux-arm64-gnu@4.52.4':
733
-
resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==}
732
+
'@rollup/rollup-linux-arm64-gnu@4.52.5':
733
+
resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
734
734
cpu: [arm64]
735
735
os: [linux]
736
736
737
-
'@rollup/rollup-linux-arm64-musl@4.52.4':
738
-
resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==}
737
+
'@rollup/rollup-linux-arm64-musl@4.52.5':
738
+
resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
739
739
cpu: [arm64]
740
740
os: [linux]
741
741
742
-
'@rollup/rollup-linux-loong64-gnu@4.52.4':
743
-
resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==}
742
+
'@rollup/rollup-linux-loong64-gnu@4.52.5':
743
+
resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
744
744
cpu: [loong64]
745
745
os: [linux]
746
746
747
-
'@rollup/rollup-linux-ppc64-gnu@4.52.4':
748
-
resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==}
747
+
'@rollup/rollup-linux-ppc64-gnu@4.52.5':
748
+
resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
749
749
cpu: [ppc64]
750
750
os: [linux]
751
751
752
-
'@rollup/rollup-linux-riscv64-gnu@4.52.4':
753
-
resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==}
752
+
'@rollup/rollup-linux-riscv64-gnu@4.52.5':
753
+
resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
754
754
cpu: [riscv64]
755
755
os: [linux]
756
756
757
-
'@rollup/rollup-linux-riscv64-musl@4.52.4':
758
-
resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==}
757
+
'@rollup/rollup-linux-riscv64-musl@4.52.5':
758
+
resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
759
759
cpu: [riscv64]
760
760
os: [linux]
761
761
762
-
'@rollup/rollup-linux-s390x-gnu@4.52.4':
763
-
resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==}
762
+
'@rollup/rollup-linux-s390x-gnu@4.52.5':
763
+
resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
764
764
cpu: [s390x]
765
765
os: [linux]
766
766
767
-
'@rollup/rollup-linux-x64-gnu@4.52.4':
768
-
resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==}
767
+
'@rollup/rollup-linux-x64-gnu@4.52.5':
768
+
resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
769
769
cpu: [x64]
770
770
os: [linux]
771
771
772
-
'@rollup/rollup-linux-x64-musl@4.52.4':
773
-
resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==}
772
+
'@rollup/rollup-linux-x64-musl@4.52.5':
773
+
resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
774
774
cpu: [x64]
775
775
os: [linux]
776
776
777
-
'@rollup/rollup-openharmony-arm64@4.52.4':
778
-
resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==}
777
+
'@rollup/rollup-openharmony-arm64@4.52.5':
778
+
resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
779
779
cpu: [arm64]
780
780
os: [openharmony]
781
781
782
-
'@rollup/rollup-win32-arm64-msvc@4.52.4':
783
-
resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==}
782
+
'@rollup/rollup-win32-arm64-msvc@4.52.5':
783
+
resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==}
784
784
cpu: [arm64]
785
785
os: [win32]
786
786
787
-
'@rollup/rollup-win32-ia32-msvc@4.52.4':
788
-
resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==}
787
+
'@rollup/rollup-win32-ia32-msvc@4.52.5':
788
+
resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==}
789
789
cpu: [ia32]
790
790
os: [win32]
791
791
792
-
'@rollup/rollup-win32-x64-gnu@4.52.4':
793
-
resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==}
792
+
'@rollup/rollup-win32-x64-gnu@4.52.5':
793
+
resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==}
794
794
cpu: [x64]
795
795
os: [win32]
796
796
797
-
'@rollup/rollup-win32-x64-msvc@4.52.4':
798
-
resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==}
797
+
'@rollup/rollup-win32-x64-msvc@4.52.5':
798
+
resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==}
799
799
cpu: [x64]
800
800
os: [win32]
801
801
···
1220
1220
vue-tsc:
1221
1221
optional: true
1222
1222
1223
-
prettier-plugin-tailwindcss@0.7.0:
1224
-
resolution: {integrity: sha512-zpRZhkfwq1cNmbKhmKzXKuKFdkgXZXlf6p+KttD75v6pGz1FxmcKMc4RKdw97GYBKBbout4113HSLaBJAomFDw==}
1223
+
prettier-plugin-tailwindcss@0.7.1:
1224
+
resolution: {integrity: sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ==}
1225
1225
engines: {node: '>=20.19'}
1226
1226
peerDependencies:
1227
1227
'@ianvs/prettier-plugin-sort-imports': '*'
···
1286
1286
resolve-pkg-maps@1.0.0:
1287
1287
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
1288
1288
1289
-
rollup@4.52.4:
1290
-
resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==}
1289
+
rollup@4.52.5:
1290
+
resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==}
1291
1291
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
1292
1292
hasBin: true
1293
1293
···
1317
1317
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
1318
1318
engines: {node: '>=0.10.0'}
1319
1319
1320
-
style-mod@4.1.2:
1321
-
resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==}
1320
+
style-mod@4.1.3:
1321
+
resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
1322
1322
1323
1323
tailwindcss@4.1.14:
1324
1324
resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==}
···
1680
1680
'@codemirror/language': 6.11.3
1681
1681
'@codemirror/state': 6.5.2
1682
1682
'@codemirror/view': 6.38.6
1683
-
'@lezer/common': 1.2.3
1683
+
'@lezer/common': 1.3.0
1684
1684
1685
1685
'@codemirror/commands@6.9.0':
1686
1686
dependencies:
1687
1687
'@codemirror/language': 6.11.3
1688
1688
'@codemirror/state': 6.5.2
1689
1689
'@codemirror/view': 6.38.6
1690
-
'@lezer/common': 1.2.3
1690
+
'@lezer/common': 1.3.0
1691
1691
1692
1692
'@codemirror/lang-json@6.0.2':
1693
1693
dependencies:
···
1698
1698
dependencies:
1699
1699
'@codemirror/state': 6.5.2
1700
1700
'@codemirror/view': 6.38.6
1701
-
'@lezer/common': 1.2.3
1702
-
'@lezer/highlight': 1.2.1
1701
+
'@lezer/common': 1.3.0
1702
+
'@lezer/highlight': 1.2.2
1703
1703
'@lezer/lr': 1.4.2
1704
-
style-mod: 4.1.2
1704
+
style-mod: 4.1.3
1705
1705
1706
1706
'@codemirror/lint@6.9.0':
1707
1707
dependencies:
···
1723
1723
dependencies:
1724
1724
'@codemirror/state': 6.5.2
1725
1725
crelt: 1.0.6
1726
-
style-mod: 4.1.2
1726
+
style-mod: 4.1.3
1727
1727
w3c-keyname: 2.2.8
1728
1728
1729
1729
'@esbuild/aix-ppc64@0.23.1':
···
1876
1876
'@esbuild/win32-x64@0.25.11':
1877
1877
optional: true
1878
1878
1879
-
'@fsegurai/codemirror-theme-basic-dark@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.1)':
1879
+
'@fsegurai/codemirror-theme-basic-dark@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.2)':
1880
1880
dependencies:
1881
1881
'@codemirror/language': 6.11.3
1882
1882
'@codemirror/state': 6.5.2
1883
1883
'@codemirror/view': 6.38.6
1884
-
'@lezer/highlight': 1.2.1
1884
+
'@lezer/highlight': 1.2.2
1885
1885
1886
-
'@fsegurai/codemirror-theme-basic-light@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.1)':
1886
+
'@fsegurai/codemirror-theme-basic-light@6.2.2(@codemirror/language@6.11.3)(@codemirror/state@6.5.2)(@codemirror/view@6.38.6)(@lezer/highlight@1.2.2)':
1887
1887
dependencies:
1888
1888
'@codemirror/language': 6.11.3
1889
1889
'@codemirror/state': 6.5.2
1890
1890
'@codemirror/view': 6.38.6
1891
-
'@lezer/highlight': 1.2.1
1891
+
'@lezer/highlight': 1.2.2
1892
1892
1893
-
'@iconify-json/lucide@1.2.69':
1893
+
'@iconify-json/lucide@1.2.70':
1894
1894
dependencies:
1895
1895
'@iconify/types': 2.0.0
1896
1896
···
1942
1942
1943
1943
'@jsr/mary__exif-rm@0.2.2': {}
1944
1944
1945
-
'@lezer/common@1.2.3': {}
1945
+
'@lezer/common@1.3.0': {}
1946
1946
1947
-
'@lezer/highlight@1.2.1':
1947
+
'@lezer/highlight@1.2.2':
1948
1948
dependencies:
1949
-
'@lezer/common': 1.2.3
1949
+
'@lezer/common': 1.3.0
1950
1950
1951
1951
'@lezer/json@1.0.3':
1952
1952
dependencies:
1953
-
'@lezer/common': 1.2.3
1954
-
'@lezer/highlight': 1.2.1
1953
+
'@lezer/common': 1.3.0
1954
+
'@lezer/highlight': 1.2.2
1955
1955
'@lezer/lr': 1.4.2
1956
1956
1957
1957
'@lezer/lr@1.4.2':
1958
1958
dependencies:
1959
-
'@lezer/common': 1.2.3
1959
+
'@lezer/common': 1.3.0
1960
1960
1961
1961
'@marijn/find-cluster-break@1.0.2': {}
1962
1962
1963
1963
'@noble/secp256k1@2.3.0': {}
1964
1964
1965
-
'@rollup/rollup-android-arm-eabi@4.52.4':
1965
+
'@rollup/rollup-android-arm-eabi@4.52.5':
1966
1966
optional: true
1967
1967
1968
-
'@rollup/rollup-android-arm64@4.52.4':
1968
+
'@rollup/rollup-android-arm64@4.52.5':
1969
1969
optional: true
1970
1970
1971
-
'@rollup/rollup-darwin-arm64@4.52.4':
1971
+
'@rollup/rollup-darwin-arm64@4.52.5':
1972
1972
optional: true
1973
1973
1974
-
'@rollup/rollup-darwin-x64@4.52.4':
1974
+
'@rollup/rollup-darwin-x64@4.52.5':
1975
1975
optional: true
1976
1976
1977
-
'@rollup/rollup-freebsd-arm64@4.52.4':
1977
+
'@rollup/rollup-freebsd-arm64@4.52.5':
1978
1978
optional: true
1979
1979
1980
-
'@rollup/rollup-freebsd-x64@4.52.4':
1980
+
'@rollup/rollup-freebsd-x64@4.52.5':
1981
1981
optional: true
1982
1982
1983
-
'@rollup/rollup-linux-arm-gnueabihf@4.52.4':
1983
+
'@rollup/rollup-linux-arm-gnueabihf@4.52.5':
1984
1984
optional: true
1985
1985
1986
-
'@rollup/rollup-linux-arm-musleabihf@4.52.4':
1986
+
'@rollup/rollup-linux-arm-musleabihf@4.52.5':
1987
1987
optional: true
1988
1988
1989
-
'@rollup/rollup-linux-arm64-gnu@4.52.4':
1989
+
'@rollup/rollup-linux-arm64-gnu@4.52.5':
1990
1990
optional: true
1991
1991
1992
-
'@rollup/rollup-linux-arm64-musl@4.52.4':
1992
+
'@rollup/rollup-linux-arm64-musl@4.52.5':
1993
1993
optional: true
1994
1994
1995
-
'@rollup/rollup-linux-loong64-gnu@4.52.4':
1995
+
'@rollup/rollup-linux-loong64-gnu@4.52.5':
1996
1996
optional: true
1997
1997
1998
-
'@rollup/rollup-linux-ppc64-gnu@4.52.4':
1998
+
'@rollup/rollup-linux-ppc64-gnu@4.52.5':
1999
1999
optional: true
2000
2000
2001
-
'@rollup/rollup-linux-riscv64-gnu@4.52.4':
2001
+
'@rollup/rollup-linux-riscv64-gnu@4.52.5':
2002
2002
optional: true
2003
2003
2004
-
'@rollup/rollup-linux-riscv64-musl@4.52.4':
2004
+
'@rollup/rollup-linux-riscv64-musl@4.52.5':
2005
2005
optional: true
2006
2006
2007
-
'@rollup/rollup-linux-s390x-gnu@4.52.4':
2007
+
'@rollup/rollup-linux-s390x-gnu@4.52.5':
2008
2008
optional: true
2009
2009
2010
-
'@rollup/rollup-linux-x64-gnu@4.52.4':
2010
+
'@rollup/rollup-linux-x64-gnu@4.52.5':
2011
2011
optional: true
2012
2012
2013
-
'@rollup/rollup-linux-x64-musl@4.52.4':
2013
+
'@rollup/rollup-linux-x64-musl@4.52.5':
2014
2014
optional: true
2015
2015
2016
-
'@rollup/rollup-openharmony-arm64@4.52.4':
2016
+
'@rollup/rollup-openharmony-arm64@4.52.5':
2017
2017
optional: true
2018
2018
2019
-
'@rollup/rollup-win32-arm64-msvc@4.52.4':
2019
+
'@rollup/rollup-win32-arm64-msvc@4.52.5':
2020
2020
optional: true
2021
2021
2022
-
'@rollup/rollup-win32-ia32-msvc@4.52.4':
2022
+
'@rollup/rollup-win32-ia32-msvc@4.52.5':
2023
2023
optional: true
2024
2024
2025
-
'@rollup/rollup-win32-x64-gnu@4.52.4':
2025
+
'@rollup/rollup-win32-x64-gnu@4.52.5':
2026
2026
optional: true
2027
2027
2028
-
'@rollup/rollup-win32-x64-msvc@4.52.4':
2028
+
'@rollup/rollup-win32-x64-msvc@4.52.5':
2029
2029
optional: true
2030
2030
2031
2031
'@skyware/firehose@0.5.2':
···
2427
2427
prettier: 3.6.2
2428
2428
typescript: 5.9.3
2429
2429
2430
-
prettier-plugin-tailwindcss@0.7.0(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2):
2430
+
prettier-plugin-tailwindcss@0.7.1(prettier-plugin-organize-imports@4.3.0(prettier@3.6.2)(typescript@5.9.3))(prettier@3.6.2):
2431
2431
dependencies:
2432
2432
prettier: 3.6.2
2433
2433
optionalDependencies:
···
2440
2440
resolve-pkg-maps@1.0.0:
2441
2441
optional: true
2442
2442
2443
-
rollup@4.52.4:
2443
+
rollup@4.52.5:
2444
2444
dependencies:
2445
2445
'@types/estree': 1.0.8
2446
2446
optionalDependencies:
2447
-
'@rollup/rollup-android-arm-eabi': 4.52.4
2448
-
'@rollup/rollup-android-arm64': 4.52.4
2449
-
'@rollup/rollup-darwin-arm64': 4.52.4
2450
-
'@rollup/rollup-darwin-x64': 4.52.4
2451
-
'@rollup/rollup-freebsd-arm64': 4.52.4
2452
-
'@rollup/rollup-freebsd-x64': 4.52.4
2453
-
'@rollup/rollup-linux-arm-gnueabihf': 4.52.4
2454
-
'@rollup/rollup-linux-arm-musleabihf': 4.52.4
2455
-
'@rollup/rollup-linux-arm64-gnu': 4.52.4
2456
-
'@rollup/rollup-linux-arm64-musl': 4.52.4
2457
-
'@rollup/rollup-linux-loong64-gnu': 4.52.4
2458
-
'@rollup/rollup-linux-ppc64-gnu': 4.52.4
2459
-
'@rollup/rollup-linux-riscv64-gnu': 4.52.4
2460
-
'@rollup/rollup-linux-riscv64-musl': 4.52.4
2461
-
'@rollup/rollup-linux-s390x-gnu': 4.52.4
2462
-
'@rollup/rollup-linux-x64-gnu': 4.52.4
2463
-
'@rollup/rollup-linux-x64-musl': 4.52.4
2464
-
'@rollup/rollup-openharmony-arm64': 4.52.4
2465
-
'@rollup/rollup-win32-arm64-msvc': 4.52.4
2466
-
'@rollup/rollup-win32-ia32-msvc': 4.52.4
2467
-
'@rollup/rollup-win32-x64-gnu': 4.52.4
2468
-
'@rollup/rollup-win32-x64-msvc': 4.52.4
2447
+
'@rollup/rollup-android-arm-eabi': 4.52.5
2448
+
'@rollup/rollup-android-arm64': 4.52.5
2449
+
'@rollup/rollup-darwin-arm64': 4.52.5
2450
+
'@rollup/rollup-darwin-x64': 4.52.5
2451
+
'@rollup/rollup-freebsd-arm64': 4.52.5
2452
+
'@rollup/rollup-freebsd-x64': 4.52.5
2453
+
'@rollup/rollup-linux-arm-gnueabihf': 4.52.5
2454
+
'@rollup/rollup-linux-arm-musleabihf': 4.52.5
2455
+
'@rollup/rollup-linux-arm64-gnu': 4.52.5
2456
+
'@rollup/rollup-linux-arm64-musl': 4.52.5
2457
+
'@rollup/rollup-linux-loong64-gnu': 4.52.5
2458
+
'@rollup/rollup-linux-ppc64-gnu': 4.52.5
2459
+
'@rollup/rollup-linux-riscv64-gnu': 4.52.5
2460
+
'@rollup/rollup-linux-riscv64-musl': 4.52.5
2461
+
'@rollup/rollup-linux-s390x-gnu': 4.52.5
2462
+
'@rollup/rollup-linux-x64-gnu': 4.52.5
2463
+
'@rollup/rollup-linux-x64-musl': 4.52.5
2464
+
'@rollup/rollup-openharmony-arm64': 4.52.5
2465
+
'@rollup/rollup-win32-arm64-msvc': 4.52.5
2466
+
'@rollup/rollup-win32-ia32-msvc': 4.52.5
2467
+
'@rollup/rollup-win32-x64-gnu': 4.52.5
2468
+
'@rollup/rollup-win32-x64-msvc': 4.52.5
2469
2469
fsevents: 2.3.3
2470
2470
2471
2471
semver@6.3.1: {}
···
2493
2493
2494
2494
source-map-js@1.2.1: {}
2495
2495
2496
-
style-mod@4.1.2: {}
2496
+
style-mod@4.1.3: {}
2497
2497
2498
2498
tailwindcss@4.1.14: {}
2499
2499
···
2556
2556
fdir: 6.5.0(picomatch@4.0.3)
2557
2557
picomatch: 4.0.3
2558
2558
postcss: 8.5.6
2559
-
rollup: 4.52.4
2559
+
rollup: 4.52.5
2560
2560
tinyglobby: 0.2.15
2561
2561
optionalDependencies:
2562
2562
'@types/node': 22.13.1
+3
-4
src/components/account.tsx
+3
-4
src/components/account.tsx
···
14
14
import { agent, Login, retrieveSession, Sessions, setAgent } from "./login.jsx";
15
15
import { Modal } from "./modal.jsx";
16
16
17
-
const AccountManager = () => {
17
+
export const [sessions, setSessions] = createStore<Sessions>();
18
+
19
+
export const AccountManager = () => {
18
20
const [openManager, setOpenManager] = createSignal(false);
19
-
const [sessions, setSessions] = createStore<Sessions>();
20
21
const [avatars, setAvatars] = createStore<Record<Did, string>>();
21
22
22
23
onMount(async () => {
···
160
161
</>
161
162
);
162
163
};
163
-
164
-
export { AccountManager };
+170
-62
src/components/create.tsx
+170
-62
src/components/create.tsx
···
1
1
import { Client } from "@atcute/client";
2
+
import { Did } from "@atcute/lexicons";
3
+
import { getSession, OAuthUserAgent } from "@atcute/oauth-browser-client";
2
4
import { remove } from "@mary/exif-rm";
3
5
import { useNavigate, useParams } from "@solidjs/router";
4
-
import { createSignal, onCleanup, Show } from "solid-js";
6
+
import { createEffect, createSignal, For, onCleanup, onMount, Show } from "solid-js";
5
7
import { Editor, editorView } from "../components/editor.jsx";
6
8
import { agent } from "../components/login.jsx";
7
9
import { setNotif } from "../layout.jsx";
10
+
import { sessions } from "./account.jsx";
8
11
import { Button } from "./button.jsx";
9
12
import { Modal } from "./modal.jsx";
10
13
import { TextInput } from "./text-input.jsx";
···
18
21
const [openDialog, setOpenDialog] = createSignal(false);
19
22
const [notice, setNotice] = createSignal("");
20
23
const [openUpload, setOpenUpload] = createSignal(false);
24
+
const [validate, setValidate] = createSignal<boolean | undefined>(undefined);
21
25
let blobInput!: HTMLInputElement;
22
26
let formRef!: HTMLFormElement;
23
27
···
38
42
};
39
43
};
40
44
45
+
const getValidateIcon = () => {
46
+
return (
47
+
validate() === true ? "lucide--circle-check"
48
+
: validate() === false ? "lucide--circle-x"
49
+
: "lucide--circle"
50
+
);
51
+
};
52
+
53
+
const getValidateLabel = () => {
54
+
return (
55
+
validate() === true ? "True"
56
+
: validate() === false ? "False"
57
+
: "Unset"
58
+
);
59
+
};
60
+
61
+
createEffect(() => {
62
+
if (openDialog()) setValidate(undefined);
63
+
});
64
+
41
65
const createRecord = async (formData: FormData) => {
42
-
const rpc = new Client({ handler: agent()! });
66
+
const repo = formData.get("repo")?.toString();
67
+
if (!repo) return;
68
+
const rpc = new Client({ handler: new OAuthUserAgent(await getSession(repo as Did)) });
43
69
const collection = formData.get("collection");
44
70
const rkey = formData.get("rkey");
45
-
const validate = formData.get("validate")?.toString();
46
71
let record: any;
47
72
try {
48
73
record = JSON.parse(editorView.state.doc.toString());
···
52
77
}
53
78
const res = await rpc.post("com.atproto.repo.createRecord", {
54
79
input: {
55
-
repo: agent()!.sub,
80
+
repo: repo as Did,
56
81
collection: collection ? collection.toString() : record.$type,
57
82
rkey: rkey?.toString().length ? rkey?.toString() : undefined,
58
83
record: record,
59
-
validate:
60
-
validate === "true" ? true
61
-
: validate === "false" ? false
62
-
: undefined,
84
+
validate: validate(),
63
85
},
64
86
});
65
87
if (!res.ok) {
···
71
93
navigate(`/${res.data.uri}`);
72
94
};
73
95
74
-
const editRecord = async (formData: FormData, recreate?: boolean) => {
96
+
const editRecord = async (recreate?: boolean) => {
75
97
const record = editorView.state.doc.toString();
76
-
const validate =
77
-
formData.get("validate")?.toString() === "true" ? true
78
-
: formData.get("validate")?.toString() === "false" ? false
79
-
: undefined;
80
98
if (!record) return;
81
99
const rpc = new Client({ handler: agent()! });
82
100
try {
···
85
103
const res = await rpc.post("com.atproto.repo.applyWrites", {
86
104
input: {
87
105
repo: agent()!.sub,
88
-
validate: validate,
106
+
validate: validate(),
89
107
writes: [
90
108
{
91
109
collection: params.collection as `${string}.${string}.${string}`,
···
112
130
collection: params.collection as `${string}.${string}.${string}`,
113
131
rkey: params.rkey,
114
132
record: editedRecord,
115
-
validate: validate,
133
+
validate: validate(),
116
134
},
117
135
});
118
136
if (!res.ok) {
···
128
146
}
129
147
};
130
148
149
+
const dragBox = (box: HTMLDivElement) => {
150
+
let currentBox: HTMLDivElement | null = null;
151
+
let isDragging = false;
152
+
let offsetX: number;
153
+
let offsetY: number;
154
+
155
+
const handleMouseDown = (e: MouseEvent) => {
156
+
if (!(e.target instanceof HTMLElement)) return;
157
+
158
+
const closestDraggable = e.target.closest("[data-draggable]") as HTMLElement;
159
+
if (closestDraggable && closestDraggable !== box) return;
160
+
161
+
if (
162
+
["INPUT", "SELECT", "BUTTON", "LABEL"].includes(e.target.tagName) ||
163
+
e.target.closest("#editor, #close")
164
+
)
165
+
return;
166
+
167
+
e.preventDefault();
168
+
isDragging = true;
169
+
box.classList.add("cursor-grabbing");
170
+
currentBox = box;
171
+
172
+
const rect = box.getBoundingClientRect();
173
+
174
+
box.style.left = rect.left + "px";
175
+
box.style.top = rect.top + "px";
176
+
177
+
box.classList.remove("-translate-x-1/2");
178
+
179
+
offsetX = e.clientX - rect.left;
180
+
offsetY = e.clientY - rect.top;
181
+
};
182
+
183
+
const handleMouseMove = (e: MouseEvent) => {
184
+
if (isDragging && box === currentBox) {
185
+
let newLeft = e.clientX - offsetX;
186
+
let newTop = e.clientY - offsetY;
187
+
188
+
const boxWidth = box.offsetWidth;
189
+
const boxHeight = box.offsetHeight;
190
+
191
+
const viewportWidth = window.innerWidth;
192
+
const viewportHeight = window.innerHeight;
193
+
194
+
newLeft = Math.max(0, Math.min(newLeft, viewportWidth - boxWidth));
195
+
newTop = Math.max(0, Math.min(newTop, viewportHeight - boxHeight));
196
+
197
+
box.style.left = newLeft + "px";
198
+
box.style.top = newTop + "px";
199
+
}
200
+
};
201
+
202
+
const handleMouseUp = () => {
203
+
if (isDragging && box === currentBox) {
204
+
isDragging = false;
205
+
box.classList.remove("cursor-grabbing");
206
+
currentBox = null;
207
+
}
208
+
};
209
+
210
+
onMount(() => {
211
+
box.addEventListener("mousedown", handleMouseDown);
212
+
document.addEventListener("mousemove", handleMouseMove);
213
+
document.addEventListener("mouseup", handleMouseUp);
214
+
});
215
+
216
+
onCleanup(() => {
217
+
box.removeEventListener("mousedown", handleMouseDown);
218
+
document.removeEventListener("mousemove", handleMouseMove);
219
+
document.removeEventListener("mouseup", handleMouseUp);
220
+
});
221
+
};
222
+
131
223
const FileUpload = (props: { file: File }) => {
132
224
const [uploading, setUploading] = createSignal(false);
133
225
const [error, setError] = createSignal("");
···
175
267
};
176
268
177
269
return (
178
-
<div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[20rem] -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">
270
+
<div
271
+
data-draggable
272
+
class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-70 left-[50%] w-[20rem] -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"
273
+
ref={dragBox}
274
+
>
179
275
<h2 class="mb-2 font-semibold">Upload blob</h2>
180
276
<div class="flex flex-col gap-2 text-sm">
181
277
<div class="flex flex-col gap-1">
···
229
325
return (
230
326
<>
231
327
<Modal open={openDialog()} onClose={() => setOpenDialog(false)} closeOnClick={false}>
232
-
<div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-16 left-[50%] w-screen -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 sm:w-xl lg:w-[48rem] dark:border-neutral-700 starting:opacity-0">
328
+
<div
329
+
data-draggable
330
+
class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-16 left-[50%] w-screen -translate-x-1/2 cursor-grab rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 sm:w-xl lg:w-[48rem] dark:border-neutral-700 starting:opacity-0"
331
+
ref={dragBox}
332
+
>
233
333
<div class="mb-2 flex w-full justify-between">
234
334
<div class="font-semibold">
235
-
<span>{props.create ? "Creating" : "Editing"} record</span>
335
+
<span class="select-none">{props.create ? "Creating" : "Editing"} record</span>
236
336
</div>
237
337
<button
338
+
id="close"
238
339
onclick={() => setOpenDialog(false)}
239
340
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
240
341
>
···
242
343
</button>
243
344
</div>
244
345
<form ref={formRef} class="flex flex-col gap-y-2">
245
-
<div class="flex w-fit flex-col gap-y-1 text-sm">
246
-
<Show when={props.create}>
247
-
<div class="flex items-center gap-x-2">
248
-
<label for="collection" class="min-w-20 select-none">
249
-
Collection
250
-
</label>
251
-
<TextInput
252
-
id="collection"
253
-
name="collection"
254
-
placeholder="Optional (default: $type)"
255
-
class="w-[15rem]"
256
-
/>
257
-
</div>
258
-
<div class="flex items-center gap-x-2">
259
-
<label for="rkey" class="min-w-20 select-none">
260
-
Record key
261
-
</label>
262
-
<TextInput
263
-
id="rkey"
264
-
name="rkey"
265
-
placeholder="Optional (default: TID)"
266
-
class="w-[15rem]"
267
-
/>
268
-
</div>
269
-
</Show>
270
-
<div class="flex items-center gap-x-2">
271
-
<label for="validate" class="min-w-20 select-none">
272
-
Validate
273
-
</label>
346
+
<Show when={props.create}>
347
+
<div class="flex flex-wrap items-center gap-1 text-sm">
348
+
<span>at://</span>
274
349
<select
275
-
name="validate"
276
-
id="validate"
277
-
class="dark:bg-dark-100 dark:shadow-dark-700 rounded-lg border-[0.5px] border-neutral-300 bg-white px-1 py-1 shadow-xs focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400"
350
+
class="dark:bg-dark-100 dark:shadow-dark-700 max-w-[10rem] truncate rounded-lg border-[0.5px] border-neutral-300 bg-white px-1 py-1 shadow-xs select-none focus:outline-[1px] focus:outline-neutral-600 dark:border-neutral-600 dark:focus:outline-neutral-400"
351
+
name="repo"
352
+
id="repo"
278
353
>
279
-
<option value="unset">Unset</option>
280
-
<option value="true">True</option>
281
-
<option value="false">False</option>
354
+
<For each={Object.keys(sessions)}>
355
+
{(session) => (
356
+
<option value={session} selected={session === agent()?.sub}>
357
+
{sessions[session].handle ?? session}
358
+
</option>
359
+
)}
360
+
</For>
282
361
</select>
362
+
<span>/</span>
363
+
<TextInput
364
+
id="collection"
365
+
name="collection"
366
+
placeholder="Collection (default: $type)"
367
+
class="w-[10rem] placeholder:text-xs lg:w-[13rem]"
368
+
/>
369
+
<span>/</span>
370
+
<TextInput
371
+
id="rkey"
372
+
name="rkey"
373
+
placeholder="Record key (default: TID)"
374
+
class="w-[10rem] placeholder:text-xs lg:w-[13rem]"
375
+
/>
283
376
</div>
284
-
</div>
377
+
</Show>
285
378
<Editor
286
379
content={JSON.stringify(
287
380
!props.create ? props.record
···
296
389
<div class="text-sm text-red-500 dark:text-red-400">{notice()}</div>
297
390
</Show>
298
391
<div class="flex justify-between gap-2">
299
-
<div class="dark:hover:bg-dark-200 dark:shadow-dark-700 dark:active:bg-dark-100 flex w-fit rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 text-xs shadow-xs hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-700 dark:bg-neutral-800">
392
+
<button
393
+
type="button"
394
+
class="dark:hover:bg-dark-200 dark:shadow-dark-700 dark:active:bg-dark-100 flex w-fit rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 text-xs shadow-xs hover:bg-neutral-100 active:bg-neutral-200 dark:border-neutral-700 dark:bg-neutral-800"
395
+
>
300
396
<input
301
397
type="file"
302
398
id="blob"
···
310
406
<span class="iconify lucide--upload"></span>
311
407
Upload
312
408
</label>
313
-
</div>
409
+
</button>
314
410
<Modal
315
411
open={openUpload()}
316
412
onClose={() => setOpenUpload(false)}
···
319
415
<FileUpload file={blobInput.files![0]} />
320
416
</Modal>
321
417
<div class="flex items-center justify-end gap-2">
418
+
<button
419
+
type="button"
420
+
class="flex items-center gap-1 rounded-sm p-1 text-sm hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
421
+
onClick={() =>
422
+
setValidate(
423
+
validate() === true ? false
424
+
: validate() === false ? undefined
425
+
: true,
426
+
)
427
+
}
428
+
>
429
+
<Tooltip text={getValidateLabel()}>
430
+
<span class={`iconify ${getValidateIcon()}`}></span>
431
+
</Tooltip>
432
+
<span>Validate</span>
433
+
</button>
322
434
<Show when={!props.create}>
323
-
<Button onClick={() => editRecord(new FormData(formRef), true)}>
324
-
Recreate
325
-
</Button>
435
+
<Button onClick={() => editRecord(true)}>Recreate</Button>
326
436
</Show>
327
437
<Button
328
438
onClick={() =>
329
-
props.create ?
330
-
createRecord(new FormData(formRef))
331
-
: editRecord(new FormData(formRef))
439
+
props.create ? createRecord(new FormData(formRef)) : editRecord()
332
440
}
333
441
>
334
442
{props.create ? "Create" : "Edit"}
+2
-1
src/components/editor.tsx
+2
-1
src/components/editor.tsx
···
57
57
return (
58
58
<div
59
59
ref={editorDiv}
60
-
class="dark:shadow-dark-700 border-[0.5px] border-neutral-300 shadow-xs dark:border-neutral-700"
60
+
id="editor"
61
+
class="dark:shadow-dark-700 cursor-auto border-[0.5px] border-neutral-300 shadow-xs dark:border-neutral-700"
61
62
></div>
62
63
);
63
64
};
+17
-19
src/components/login.tsx
+17
-19
src/components/login.tsx
···
64
64
65
65
return (
66
66
<form class="flex flex-col gap-y-2 px-1" onsubmit={(e) => e.preventDefault()}>
67
-
<div class="flex items-center gap-1">
68
-
<label for="handle" class="hidden">
69
-
Add account
70
-
</label>
71
-
<div class="dark:bg-dark-100 dark:shadow-dark-700 flex grow items-center gap-2 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 shadow-xs focus-within:outline-[1px] focus-within:outline-neutral-600 dark:border-neutral-600 dark:focus-within:outline-neutral-400">
72
-
<label
73
-
for="handle"
74
-
class="iconify lucide--user-round-plus text-neutral-500 dark:text-neutral-400"
75
-
></label>
76
-
<input
77
-
type="text"
78
-
spellcheck={false}
79
-
placeholder="user.bsky.social"
80
-
id="handle"
81
-
class="grow py-1 select-none placeholder:text-sm focus:outline-none"
82
-
onInput={(e) => setLoginInput(e.currentTarget.value)}
83
-
/>
84
-
</div>
67
+
<label for="handle" class="hidden">
68
+
Add account
69
+
</label>
70
+
<div class="dark:bg-dark-100 dark:shadow-dark-700 flex grow items-center gap-2 rounded-lg border-[0.5px] border-neutral-300 bg-white px-2 shadow-xs focus-within:outline-[1px] focus-within:outline-neutral-600 dark:border-neutral-600 dark:focus-within:outline-neutral-400">
71
+
<label
72
+
for="handle"
73
+
class="iconify lucide--user-round-plus text-neutral-500 dark:text-neutral-400"
74
+
></label>
75
+
<input
76
+
type="text"
77
+
spellcheck={false}
78
+
placeholder="user.bsky.social"
79
+
id="handle"
80
+
class="grow py-1 select-none placeholder:text-sm focus:outline-none"
81
+
onInput={(e) => setLoginInput(e.currentTarget.value)}
82
+
/>
85
83
<button
86
84
onclick={() => login(loginInput())}
87
-
class="flex items-center rounded-lg p-1.5 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
85
+
class="flex items-center rounded-lg p-1 hover:bg-neutral-100 active:bg-neutral-200 dark:hover:bg-neutral-600 dark:active:bg-neutral-500"
88
86
>
89
87
<span class="iconify lucide--log-in"></span>
90
88
</button>
+1
src/styles/index.css
+1
src/styles/index.css
+10
src/views/home.tsx
+10
src/views/home.tsx
···
54
54
<span class="iconify ri--bluesky"></span>
55
55
</a>
56
56
</div>
57
+
<div class="text-center text-sm italic">
58
+
Made by{" "}
59
+
<a
60
+
href="https://juli.ee"
61
+
class="font-pecita relative after:absolute after:bottom-0 after:left-0 after:h-[1px] after:w-0 after:bg-current after:transition-[width] after:duration-300 after:ease-out hover:after:w-full"
62
+
>
63
+
Juliet
64
+
</a>{" "}
65
+
with love
66
+
</div>
57
67
</div>
58
68
);
59
69
};
+7
-19
src/views/logs.tsx
+7
-19
src/views/logs.tsx
···
5
5
processIndexedEntryLog,
6
6
} from "@atcute/did-plc";
7
7
import { createResource, createSignal, For, Show } from "solid-js";
8
-
import Tooltip from "../components/tooltip.jsx";
9
8
import { localDateFromTimestamp } from "../utils/date.js";
10
9
import { createOperationHistory, DiffEntry, groupBy } from "../utils/plc-logs.js";
11
10
···
111
110
112
111
return (
113
112
<div class="flex w-full flex-col gap-2 wrap-anywhere">
114
-
<div class="flex items-center justify-between">
115
-
<div class="flex items-center gap-1">
116
-
<div class="iconify lucide--filter" />
117
-
<div class="dark:shadow-dark-700 dark:bg-dark-300 flex w-fit items-center rounded-full border-[0.5px] border-neutral-300 bg-neutral-50 shadow-xs dark:border-neutral-700">
118
-
<FilterButton icon="iconify lucide--at-sign" event="handle" />
119
-
<FilterButton icon="iconify lucide--key-round" event="rotation_key" />
120
-
<FilterButton icon="iconify lucide--hard-drive" event="service" />
121
-
<FilterButton icon="iconify lucide--shield-check" event="verification_method" />
122
-
</div>
113
+
<div class="flex items-center gap-1">
114
+
<div class="iconify lucide--filter" />
115
+
<div class="dark:shadow-dark-700 dark:bg-dark-300 flex w-fit items-center rounded-full border-[0.5px] border-neutral-300 bg-neutral-50 shadow-xs dark:border-neutral-700">
116
+
<FilterButton icon="iconify lucide--at-sign" event="handle" />
117
+
<FilterButton icon="iconify lucide--key-round" event="rotation_key" />
118
+
<FilterButton icon="iconify lucide--hard-drive" event="service" />
119
+
<FilterButton icon="iconify lucide--shield-check" event="verification_method" />
123
120
</div>
124
-
<Tooltip text="Audit log">
125
-
<a
126
-
href={`${localStorage.plcDirectory ?? "https://plc.directory"}/${props.did}/log/audit`}
127
-
target="_blank"
128
-
class="-mr-1 flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
129
-
>
130
-
<span class="iconify lucide--external-link"></span>
131
-
</a>
132
-
</Tooltip>
133
121
</div>
134
122
<div class="flex flex-col gap-1 text-sm">
135
123
<For each={plcOps()}>
+14
-18
src/views/pds.tsx
+14
-18
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";
8
9
import { Modal } from "../components/modal";
9
10
import { setPDS } from "../components/navbar";
10
11
import Tooltip from "../components/tooltip";
11
-
import { addToClipboard } from "../utils/copy";
12
12
import { localDateFromTimestamp } from "../utils/date";
13
13
14
14
const LIMIT = 1000;
···
133
133
<Tab tab="repos" label="Repositories" />
134
134
<Tab tab="info" label="Info" />
135
135
</div>
136
-
<div class="flex gap-1">
137
-
<Tooltip text="Copy PDS">
138
-
<button
139
-
onClick={() => addToClipboard(params.pds)}
140
-
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
141
-
>
142
-
<span class="iconify lucide--copy"></span>
143
-
</button>
144
-
</Tooltip>
145
-
<Tooltip text="Firehose">
146
-
<A
136
+
<MenuProvider>
137
+
<DropdownMenu
138
+
icon="lucide--ellipsis-vertical"
139
+
buttonClass="rounded-sm p-1"
140
+
menuClass="top-8 p-2 text-sm"
141
+
>
142
+
<CopyMenu copyContent={params.pds} label="Copy PDS" icon="lucide--copy" />
143
+
<NavMenu
147
144
href={`/firehose?instance=wss://${params.pds}`}
148
-
class="flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
149
-
>
150
-
<span class="iconify lucide--radio-tower"></span>
151
-
</A>
152
-
</Tooltip>
153
-
</div>
145
+
label="Firehose"
146
+
icon="lucide--radio-tower"
147
+
/>
148
+
</DropdownMenu>
149
+
</MenuProvider>
154
150
</div>
155
151
<div class="flex flex-col gap-1 px-2">
156
152
<Show when={!location.hash || location.hash === "#repos"}>
+1
-1
src/views/record.tsx
+1
-1
src/views/record.tsx
+23
-20
src/views/repo.tsx
+23
-20
src/views/repo.tsx
···
198
198
label="Jetstream"
199
199
icon="lucide--radio-tower"
200
200
/>
201
+
<NavMenu
202
+
href={
203
+
did.startsWith("did:plc") ?
204
+
`${localStorage.plcDirectory ?? "https://plc.directory"}/${did}`
205
+
: `https://${did.split("did:web:")[1]}/.well-known/did.json`
206
+
}
207
+
newTab
208
+
label="DID Document"
209
+
icon="lucide--external-link"
210
+
/>
211
+
<Show when={did.startsWith("did:plc")}>
212
+
<NavMenu
213
+
href={`${localStorage.plcDirectory ?? "https://plc.directory"}/${did}/log/audit`}
214
+
newTab
215
+
label="Audit Log"
216
+
icon="lucide--external-link"
217
+
/>
218
+
</Show>
201
219
<Show when={error()?.length === 0 || error() === undefined}>
202
220
<ActionMenu
203
221
label="Export Repo"
···
289
307
<Show when={didDoc()}>
290
308
{(didDocument) => (
291
309
<div class="flex flex-col gap-y-1 wrap-anywhere">
292
-
<div class="flex items-baseline justify-between gap-2">
293
-
<div>
294
-
<div class="flex items-center gap-1">
295
-
<div class="iconify lucide--id-card" />
296
-
<p class="font-semibold">ID</p>
297
-
</div>
298
-
<div class="text-sm">{didDocument().id}</div>
310
+
<div>
311
+
<div class="flex items-center gap-1">
312
+
<div class="iconify lucide--id-card" />
313
+
<p class="font-semibold">ID</p>
299
314
</div>
300
-
<Tooltip text="DID document">
301
-
<a
302
-
href={
303
-
did.startsWith("did:plc") ?
304
-
`${localStorage.plcDirectory ?? "https://plc.directory"}/${did}`
305
-
: `https://${did.split("did:web:")[1]}/.well-known/did.json`
306
-
}
307
-
target="_blank"
308
-
class="-mr-1 flex items-center rounded-lg p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
309
-
>
310
-
<span class="iconify lucide--external-link"></span>
311
-
</a>
312
-
</Tooltip>
315
+
<div class="text-sm">{didDocument().id}</div>
313
316
</div>
314
317
<div>
315
318
<div class="flex items-center gap-1">