tangled
alpha
login
or
join now
minito.dev
/
SkeetLonger.app
1
fork
atom
A web app for writing and sharing 301+ character Bluesky posts.
1
fork
atom
overview
issues
pulls
pipelines
Successful push to PDS
Minito
4 months ago
ed1f33e4
9830f505
+746
-28
8 changed files
expand all
collapse all
unified
split
package-lock.json
package.json
src
App.tsx
main.tsx
routeTree.gen.ts
routes
__root.tsx
about.tsx
index.tsx
+454
-1
package-lock.json
···
9
9
"version": "0.0.0",
10
10
"dependencies": {
11
11
"@atproto/api": "^0.16.11",
12
12
+
"@atproto/common": "^0.4.12",
12
13
"@atproto/oauth-client-browser": "^0.3.33",
13
14
"@tailwindcss/vite": "^4.1.14",
14
15
"react": "^19.1.1",
15
16
"react-dom": "^19.1.1",
16
16
-
"tailwindcss": "^4.1.14"
17
17
+
"tailwindcss": "^4.1.14",
17
18
},
18
19
"devDependencies": {
19
20
"@eslint/js": "^9.36.0",
···
146
147
"multiformats": "^9.9.0",
147
148
"tlds": "^1.234.0",
148
149
"zod": "^3.23.8"
150
150
+
}
151
151
+
},
152
152
+
"node_modules/@atproto/common": {
153
153
+
"version": "0.4.12",
154
154
+
"resolved": "https://registry.npmjs.org/@atproto/common/-/common-0.4.12.tgz",
155
155
+
"integrity": "sha512-NC+TULLQiqs6MvNymhQS5WDms3SlbIKGLf4n33tpftRJcalh507rI+snbcUb7TLIkKw7VO17qMqxEXtIdd5auQ==",
156
156
+
"license": "MIT",
157
157
+
"dependencies": {
158
158
+
"@atproto/common-web": "^0.4.3",
159
159
+
"@ipld/dag-cbor": "^7.0.3",
160
160
+
"cbor-x": "^1.5.1",
161
161
+
"iso-datestring-validator": "^2.2.2",
162
162
+
"multiformats": "^9.9.0",
163
163
+
"pino": "^8.21.0"
164
164
+
},
165
165
+
"engines": {
166
166
+
"node": ">=18.7.0"
149
167
}
150
168
},
151
169
"node_modules/@atproto/common-web": {
···
743
761
"node": ">=6.9.0"
744
762
}
745
763
},
764
764
+
"node_modules/@cbor-extract/cbor-extract-darwin-arm64": {
765
765
+
"version": "2.2.0",
766
766
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.0.tgz",
767
767
+
"integrity": "sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==",
768
768
+
"cpu": [
769
769
+
"arm64"
770
770
+
],
771
771
+
"license": "MIT",
772
772
+
"optional": true,
773
773
+
"os": [
774
774
+
"darwin"
775
775
+
]
776
776
+
},
777
777
+
"node_modules/@cbor-extract/cbor-extract-darwin-x64": {
778
778
+
"version": "2.2.0",
779
779
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.0.tgz",
780
780
+
"integrity": "sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==",
781
781
+
"cpu": [
782
782
+
"x64"
783
783
+
],
784
784
+
"license": "MIT",
785
785
+
"optional": true,
786
786
+
"os": [
787
787
+
"darwin"
788
788
+
]
789
789
+
},
790
790
+
"node_modules/@cbor-extract/cbor-extract-linux-arm": {
791
791
+
"version": "2.2.0",
792
792
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.0.tgz",
793
793
+
"integrity": "sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==",
794
794
+
"cpu": [
795
795
+
"arm"
796
796
+
],
797
797
+
"license": "MIT",
798
798
+
"optional": true,
799
799
+
"os": [
800
800
+
"linux"
801
801
+
]
802
802
+
},
803
803
+
"node_modules/@cbor-extract/cbor-extract-linux-arm64": {
804
804
+
"version": "2.2.0",
805
805
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.0.tgz",
806
806
+
"integrity": "sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==",
807
807
+
"cpu": [
808
808
+
"arm64"
809
809
+
],
810
810
+
"license": "MIT",
811
811
+
"optional": true,
812
812
+
"os": [
813
813
+
"linux"
814
814
+
]
815
815
+
},
816
816
+
"node_modules/@cbor-extract/cbor-extract-linux-x64": {
817
817
+
"version": "2.2.0",
818
818
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.0.tgz",
819
819
+
"integrity": "sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==",
820
820
+
"cpu": [
821
821
+
"x64"
822
822
+
],
823
823
+
"license": "MIT",
824
824
+
"optional": true,
825
825
+
"os": [
826
826
+
"linux"
827
827
+
]
828
828
+
},
829
829
+
"node_modules/@cbor-extract/cbor-extract-win32-x64": {
830
830
+
"version": "2.2.0",
831
831
+
"resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.0.tgz",
832
832
+
"integrity": "sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==",
833
833
+
"cpu": [
834
834
+
"x64"
835
835
+
],
836
836
+
"license": "MIT",
837
837
+
"optional": true,
838
838
+
"os": [
839
839
+
"win32"
840
840
+
]
841
841
+
},
746
842
"node_modules/@esbuild/aix-ppc64": {
747
843
"version": "0.25.11",
748
844
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz",
···
1403
1499
},
1404
1500
"funding": {
1405
1501
"url": "https://github.com/sponsors/sindresorhus"
1502
1502
+
}
1503
1503
+
},
1504
1504
+
"node_modules/@ipld/dag-cbor": {
1505
1505
+
"version": "7.0.3",
1506
1506
+
"resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-7.0.3.tgz",
1507
1507
+
"integrity": "sha512-1VVh2huHsuohdXC1bGJNE8WR72slZ9XE2T3wbBBq31dm7ZBatmKLLxrB+XAqafxfRFjv08RZmj/W/ZqaM13AuA==",
1508
1508
+
"license": "(Apache-2.0 AND MIT)",
1509
1509
+
"dependencies": {
1510
1510
+
"cborg": "^1.6.0",
1511
1511
+
"multiformats": "^9.5.4"
1406
1512
}
1407
1513
},
1408
1514
"node_modules/@isaacs/fs-minipass": {
···
2644
2750
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
2645
2751
}
2646
2752
},
2753
2753
+
"node_modules/abort-controller": {
2754
2754
+
"version": "3.0.0",
2755
2755
+
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
2756
2756
+
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
2757
2757
+
"license": "MIT",
2758
2758
+
"dependencies": {
2759
2759
+
"event-target-shim": "^5.0.0"
2760
2760
+
},
2761
2761
+
"engines": {
2762
2762
+
"node": ">=6.5"
2763
2763
+
}
2764
2764
+
},
2647
2765
"node_modules/acorn": {
2648
2766
"version": "8.15.0",
2649
2767
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
···
2744
2862
"node": ">=4"
2745
2863
}
2746
2864
},
2865
2865
+
"node_modules/atomic-sleep": {
2866
2866
+
"version": "1.0.0",
2867
2867
+
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
2868
2868
+
"integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
2869
2869
+
"license": "MIT",
2870
2870
+
"engines": {
2871
2871
+
"node": ">=8.0.0"
2872
2872
+
}
2873
2873
+
},
2747
2874
"node_modules/await-lock": {
2748
2875
"version": "2.2.2",
2749
2876
"resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz",
···
2780
2907
"dev": true,
2781
2908
"license": "MIT"
2782
2909
},
2910
2910
+
"node_modules/base64-js": {
2911
2911
+
"version": "1.5.1",
2912
2912
+
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
2913
2913
+
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
2914
2914
+
"funding": [
2915
2915
+
{
2916
2916
+
"type": "github",
2917
2917
+
"url": "https://github.com/sponsors/feross"
2918
2918
+
},
2919
2919
+
{
2920
2920
+
"type": "patreon",
2921
2921
+
"url": "https://www.patreon.com/feross"
2922
2922
+
},
2923
2923
+
{
2924
2924
+
"type": "consulting",
2925
2925
+
"url": "https://feross.org/support"
2926
2926
+
}
2927
2927
+
],
2928
2928
+
"license": "MIT"
2929
2929
+
},
2783
2930
"node_modules/baseline-browser-mapping": {
2784
2931
"version": "2.8.18",
2785
2932
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.18.tgz",
···
2861
3008
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
2862
3009
}
2863
3010
},
3011
3011
+
"node_modules/buffer": {
3012
3012
+
"version": "6.0.3",
3013
3013
+
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
3014
3014
+
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
3015
3015
+
"funding": [
3016
3016
+
{
3017
3017
+
"type": "github",
3018
3018
+
"url": "https://github.com/sponsors/feross"
3019
3019
+
},
3020
3020
+
{
3021
3021
+
"type": "patreon",
3022
3022
+
"url": "https://www.patreon.com/feross"
3023
3023
+
},
3024
3024
+
{
3025
3025
+
"type": "consulting",
3026
3026
+
"url": "https://feross.org/support"
3027
3027
+
}
3028
3028
+
],
3029
3029
+
"license": "MIT",
3030
3030
+
"dependencies": {
3031
3031
+
"base64-js": "^1.3.1",
3032
3032
+
"ieee754": "^1.2.1"
3033
3033
+
}
3034
3034
+
},
2864
3035
"node_modules/callsites": {
2865
3036
"version": "3.1.0",
2866
3037
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
···
2891
3062
}
2892
3063
],
2893
3064
"license": "CC-BY-4.0"
3065
3065
+
},
3066
3066
+
"node_modules/cbor-extract": {
3067
3067
+
"version": "2.2.0",
3068
3068
+
"resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.0.tgz",
3069
3069
+
"integrity": "sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==",
3070
3070
+
"hasInstallScript": true,
3071
3071
+
"license": "MIT",
3072
3072
+
"optional": true,
3073
3073
+
"dependencies": {
3074
3074
+
"node-gyp-build-optional-packages": "5.1.1"
3075
3075
+
},
3076
3076
+
"bin": {
3077
3077
+
"download-cbor-prebuilds": "bin/download-prebuilds.js"
3078
3078
+
},
3079
3079
+
"optionalDependencies": {
3080
3080
+
"@cbor-extract/cbor-extract-darwin-arm64": "2.2.0",
3081
3081
+
"@cbor-extract/cbor-extract-darwin-x64": "2.2.0",
3082
3082
+
"@cbor-extract/cbor-extract-linux-arm": "2.2.0",
3083
3083
+
"@cbor-extract/cbor-extract-linux-arm64": "2.2.0",
3084
3084
+
"@cbor-extract/cbor-extract-linux-x64": "2.2.0",
3085
3085
+
"@cbor-extract/cbor-extract-win32-x64": "2.2.0"
3086
3086
+
}
3087
3087
+
},
3088
3088
+
"node_modules/cbor-x": {
3089
3089
+
"version": "1.6.0",
3090
3090
+
"resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.0.tgz",
3091
3091
+
"integrity": "sha512-0kareyRwHSkL6ws5VXHEf8uY1liitysCVJjlmhaLG+IXLqhSaOO+t63coaso7yjwEzWZzLy8fJo06gZDVQM9Qg==",
3092
3092
+
"license": "MIT",
3093
3093
+
"optionalDependencies": {
3094
3094
+
"cbor-extract": "^2.2.0"
3095
3095
+
}
3096
3096
+
},
3097
3097
+
"node_modules/cborg": {
3098
3098
+
"version": "1.10.2",
3099
3099
+
"resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.2.tgz",
3100
3100
+
"integrity": "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==",
3101
3101
+
"license": "Apache-2.0",
3102
3102
+
"bin": {
3103
3103
+
"cborg": "cli.js"
3104
3104
+
}
2894
3105
},
2895
3106
"node_modules/chalk": {
2896
3107
"version": "4.1.2",
···
3366
3577
"node": ">=0.10.0"
3367
3578
}
3368
3579
},
3580
3580
+
"node_modules/event-target-shim": {
3581
3581
+
"version": "5.0.1",
3582
3582
+
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
3583
3583
+
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
3584
3584
+
"license": "MIT",
3585
3585
+
"engines": {
3586
3586
+
"node": ">=6"
3587
3587
+
}
3588
3588
+
},
3589
3589
+
"node_modules/events": {
3590
3590
+
"version": "3.3.0",
3591
3591
+
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
3592
3592
+
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
3593
3593
+
"license": "MIT",
3594
3594
+
"engines": {
3595
3595
+
"node": ">=0.8.x"
3596
3596
+
}
3597
3597
+
},
3369
3598
"node_modules/exsolve": {
3370
3599
"version": "1.0.7",
3371
3600
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
···
3423
3652
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
3424
3653
"dev": true,
3425
3654
"license": "MIT"
3655
3655
+
},
3656
3656
+
"node_modules/fast-redact": {
3657
3657
+
"version": "3.5.0",
3658
3658
+
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz",
3659
3659
+
"integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==",
3660
3660
+
"license": "MIT",
3661
3661
+
"engines": {
3662
3662
+
"node": ">=6"
3663
3663
+
}
3426
3664
},
3427
3665
"node_modules/fastq": {
3428
3666
"version": "1.19.1",
···
3582
3820
"engines": {
3583
3821
"node": ">=8"
3584
3822
}
3823
3823
+
},
3824
3824
+
"node_modules/ieee754": {
3825
3825
+
"version": "1.2.1",
3826
3826
+
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
3827
3827
+
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
3828
3828
+
"funding": [
3829
3829
+
{
3830
3830
+
"type": "github",
3831
3831
+
"url": "https://github.com/sponsors/feross"
3832
3832
+
},
3833
3833
+
{
3834
3834
+
"type": "patreon",
3835
3835
+
"url": "https://www.patreon.com/feross"
3836
3836
+
},
3837
3837
+
{
3838
3838
+
"type": "consulting",
3839
3839
+
"url": "https://feross.org/support"
3840
3840
+
}
3841
3841
+
],
3842
3842
+
"license": "BSD-3-Clause"
3585
3843
},
3586
3844
"node_modules/ignore": {
3587
3845
"version": "5.3.2",
···
4221
4479
"dev": true,
4222
4480
"license": "MIT"
4223
4481
},
4482
4482
+
"node_modules/node-gyp-build-optional-packages": {
4483
4483
+
"version": "5.1.1",
4484
4484
+
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
4485
4485
+
"integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==",
4486
4486
+
"license": "MIT",
4487
4487
+
"optional": true,
4488
4488
+
"dependencies": {
4489
4489
+
"detect-libc": "^2.0.1"
4490
4490
+
},
4491
4491
+
"bin": {
4492
4492
+
"node-gyp-build-optional-packages": "bin.js",
4493
4493
+
"node-gyp-build-optional-packages-optional": "optional.js",
4494
4494
+
"node-gyp-build-optional-packages-test": "build-test.js"
4495
4495
+
}
4496
4496
+
},
4224
4497
"node_modules/node-releases": {
4225
4498
"version": "2.0.25",
4226
4499
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz",
···
4236
4509
"license": "MIT",
4237
4510
"engines": {
4238
4511
"node": ">=0.10.0"
4512
4512
+
}
4513
4513
+
},
4514
4514
+
"node_modules/on-exit-leak-free": {
4515
4515
+
"version": "2.1.2",
4516
4516
+
"resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
4517
4517
+
"integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
4518
4518
+
"license": "MIT",
4519
4519
+
"engines": {
4520
4520
+
"node": ">=14.0.0"
4239
4521
}
4240
4522
},
4241
4523
"node_modules/optionator": {
···
4354
4636
"url": "https://github.com/sponsors/jonschlinkert"
4355
4637
}
4356
4638
},
4639
4639
+
"node_modules/pino": {
4640
4640
+
"version": "8.21.0",
4641
4641
+
"resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz",
4642
4642
+
"integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==",
4643
4643
+
"license": "MIT",
4644
4644
+
"dependencies": {
4645
4645
+
"atomic-sleep": "^1.0.0",
4646
4646
+
"fast-redact": "^3.1.1",
4647
4647
+
"on-exit-leak-free": "^2.1.0",
4648
4648
+
"pino-abstract-transport": "^1.2.0",
4649
4649
+
"pino-std-serializers": "^6.0.0",
4650
4650
+
"process-warning": "^3.0.0",
4651
4651
+
"quick-format-unescaped": "^4.0.3",
4652
4652
+
"real-require": "^0.2.0",
4653
4653
+
"safe-stable-stringify": "^2.3.1",
4654
4654
+
"sonic-boom": "^3.7.0",
4655
4655
+
"thread-stream": "^2.6.0"
4656
4656
+
},
4657
4657
+
"bin": {
4658
4658
+
"pino": "bin.js"
4659
4659
+
}
4660
4660
+
},
4661
4661
+
"node_modules/pino-abstract-transport": {
4662
4662
+
"version": "1.2.0",
4663
4663
+
"resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz",
4664
4664
+
"integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==",
4665
4665
+
"license": "MIT",
4666
4666
+
"dependencies": {
4667
4667
+
"readable-stream": "^4.0.0",
4668
4668
+
"split2": "^4.0.0"
4669
4669
+
}
4670
4670
+
},
4671
4671
+
"node_modules/pino-std-serializers": {
4672
4672
+
"version": "6.2.2",
4673
4673
+
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz",
4674
4674
+
"integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==",
4675
4675
+
"license": "MIT"
4676
4676
+
},
4357
4677
"node_modules/pkg-types": {
4358
4678
"version": "2.3.0",
4359
4679
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
···
4420
4740
"url": "https://github.com/prettier/prettier?sponsor=1"
4421
4741
}
4422
4742
},
4743
4743
+
"node_modules/process": {
4744
4744
+
"version": "0.11.10",
4745
4745
+
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
4746
4746
+
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
4747
4747
+
"license": "MIT",
4748
4748
+
"engines": {
4749
4749
+
"node": ">= 0.6.0"
4750
4750
+
}
4751
4751
+
},
4752
4752
+
"node_modules/process-warning": {
4753
4753
+
"version": "3.0.0",
4754
4754
+
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz",
4755
4755
+
"integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==",
4756
4756
+
"license": "MIT"
4757
4757
+
},
4423
4758
"node_modules/punycode": {
4424
4759
"version": "2.3.1",
4425
4760
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
···
4468
4803
],
4469
4804
"license": "MIT"
4470
4805
},
4806
4806
+
"node_modules/quick-format-unescaped": {
4807
4807
+
"version": "4.0.4",
4808
4808
+
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
4809
4809
+
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
4810
4810
+
"license": "MIT"
4811
4811
+
},
4471
4812
"node_modules/react": {
4472
4813
"version": "19.2.0",
4473
4814
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
···
4499
4840
"node": ">=0.10.0"
4500
4841
}
4501
4842
},
4843
4843
+
"node_modules/readable-stream": {
4844
4844
+
"version": "4.7.0",
4845
4845
+
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
4846
4846
+
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
4847
4847
+
"license": "MIT",
4848
4848
+
"dependencies": {
4849
4849
+
"abort-controller": "^3.0.0",
4850
4850
+
"buffer": "^6.0.3",
4851
4851
+
"events": "^3.3.0",
4852
4852
+
"process": "^0.11.10",
4853
4853
+
"string_decoder": "^1.3.0"
4854
4854
+
},
4855
4855
+
"engines": {
4856
4856
+
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
4857
4857
+
}
4858
4858
+
},
4502
4859
"node_modules/readdirp": {
4503
4860
"version": "3.6.0",
4504
4861
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
···
4510
4867
},
4511
4868
"engines": {
4512
4869
"node": ">=8.10.0"
4870
4870
+
}
4871
4871
+
},
4872
4872
+
"node_modules/real-require": {
4873
4873
+
"version": "0.2.0",
4874
4874
+
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
4875
4875
+
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
4876
4876
+
"license": "MIT",
4877
4877
+
"engines": {
4878
4878
+
"node": ">= 12.13.0"
4513
4879
}
4514
4880
},
4515
4881
"node_modules/recast": {
···
4635
5001
"queue-microtask": "^1.2.2"
4636
5002
}
4637
5003
},
5004
5004
+
"node_modules/safe-buffer": {
5005
5005
+
"version": "5.2.1",
5006
5006
+
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
5007
5007
+
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
5008
5008
+
"funding": [
5009
5009
+
{
5010
5010
+
"type": "github",
5011
5011
+
"url": "https://github.com/sponsors/feross"
5012
5012
+
},
5013
5013
+
{
5014
5014
+
"type": "patreon",
5015
5015
+
"url": "https://www.patreon.com/feross"
5016
5016
+
},
5017
5017
+
{
5018
5018
+
"type": "consulting",
5019
5019
+
"url": "https://feross.org/support"
5020
5020
+
}
5021
5021
+
],
5022
5022
+
"license": "MIT"
5023
5023
+
},
5024
5024
+
"node_modules/safe-stable-stringify": {
5025
5025
+
"version": "2.5.0",
5026
5026
+
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
5027
5027
+
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
5028
5028
+
"license": "MIT",
5029
5029
+
"engines": {
5030
5030
+
"node": ">=10"
5031
5031
+
}
5032
5032
+
},
4638
5033
"node_modules/scheduler": {
4639
5034
"version": "0.27.0",
4640
5035
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
···
4704
5099
"node": ">=8"
4705
5100
}
4706
5101
},
5102
5102
+
"node_modules/sonic-boom": {
5103
5103
+
"version": "3.8.1",
5104
5104
+
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz",
5105
5105
+
"integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==",
5106
5106
+
"license": "MIT",
5107
5107
+
"dependencies": {
5108
5108
+
"atomic-sleep": "^1.0.0"
5109
5109
+
}
5110
5110
+
},
4707
5111
"node_modules/source-map": {
4708
5112
"version": "0.7.6",
4709
5113
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
···
4723
5127
"node": ">=0.10.0"
4724
5128
}
4725
5129
},
5130
5130
+
"node_modules/split2": {
5131
5131
+
"version": "4.2.0",
5132
5132
+
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
5133
5133
+
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
5134
5134
+
"license": "ISC",
5135
5135
+
"engines": {
5136
5136
+
"node": ">= 10.x"
5137
5137
+
}
5138
5138
+
},
5139
5139
+
"node_modules/string_decoder": {
5140
5140
+
"version": "1.3.0",
5141
5141
+
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
5142
5142
+
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
5143
5143
+
"license": "MIT",
5144
5144
+
"dependencies": {
5145
5145
+
"safe-buffer": "~5.2.0"
5146
5146
+
}
5147
5147
+
},
4726
5148
"node_modules/strip-json-comments": {
4727
5149
"version": "3.1.1",
4728
5150
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
···
4811
5233
"license": "BlueOak-1.0.0",
4812
5234
"engines": {
4813
5235
"node": ">=18"
5236
5236
+
}
5237
5237
+
},
5238
5238
+
"node_modules/thread-stream": {
5239
5239
+
"version": "2.7.0",
5240
5240
+
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz",
5241
5241
+
"integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==",
5242
5242
+
"license": "MIT",
5243
5243
+
"dependencies": {
5244
5244
+
"real-require": "^0.2.0"
4814
5245
}
4815
5246
},
4816
5247
"node_modules/tiny-invariant": {
···
4952
5383
},
4953
5384
"engines": {
4954
5385
"node": ">= 0.8.0"
5386
5386
+
}
5387
5387
+
},
5388
5388
+
"node_modules/typeid-js": {
5389
5389
+
"version": "1.2.0",
5390
5390
+
"resolved": "https://registry.npmjs.org/typeid-js/-/typeid-js-1.2.0.tgz",
5391
5391
+
"integrity": "sha512-t76ZucAnvGC60ea/HjVsB0TSoB0cw9yjnfurUgtInXQWUI/VcrlZGpO23KN3iSe8yOGUgb1zr7W7uEzJ3hSljA==",
5392
5392
+
"license": "Apache-2.0",
5393
5393
+
"dependencies": {
5394
5394
+
"uuid": "^10.0.0"
4955
5395
}
4956
5396
},
4957
5397
"node_modules/typescript": {
···
5266
5706
"license": "MIT",
5267
5707
"peerDependencies": {
5268
5708
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
5709
5709
+
}
5710
5710
+
},
5711
5711
+
"node_modules/uuid": {
5712
5712
+
"version": "10.0.0",
5713
5713
+
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
5714
5714
+
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
5715
5715
+
"funding": [
5716
5716
+
"https://github.com/sponsors/broofa",
5717
5717
+
"https://github.com/sponsors/ctavan"
5718
5718
+
],
5719
5719
+
"license": "MIT",
5720
5720
+
"bin": {
5721
5721
+
"uuid": "dist/bin/uuid"
5269
5722
}
5270
5723
},
5271
5724
"node_modules/vite": {
+3
-1
package.json
···
11
11
},
12
12
"dependencies": {
13
13
"@atproto/api": "^0.16.11",
14
14
+
"@atproto/common": "^0.4.12",
14
15
"@atproto/oauth-client-browser": "^0.3.33",
15
16
"@tailwindcss/vite": "^4.1.14",
16
17
"react": "^19.1.1",
17
18
"react-dom": "^19.1.1",
18
18
-
"tailwindcss": "^4.1.14"
19
19
+
"tailwindcss": "^4.1.14",
20
20
+
"typeid-js": "^1.2.0"
19
21
},
20
22
"devDependencies": {
21
23
"@eslint/js": "^9.36.0",
+19
-2
src/App.tsx
···
2
2
import './App.css'
3
3
import Login from './components/Login'
4
4
import { UnifiedAuthProvider } from './providers/UnifiedAuthProvider'
5
5
+
import { AtpAgent } from '@atproto/api'
6
6
+
// import { TID } from '@atproto/common'
5
7
6
8
function App() {
9
9
+
const agent = new AtpAgent({ service: 'https://skeetlonger.app' })
10
10
+
7
11
const [postText, setPostText] = useState('')
8
12
const charCount = postText.length
9
13
10
10
-
const handleSubmit = async (e: React.FormEvent) => {
11
11
-
e.preventDefault();
14
14
+
const handleSubmit = async () => {
15
15
+
// Generate a time-based key for our record
16
16
+
const rkey = "self"
17
17
+
18
18
+
await agent.com.atproto.repo.putRecord({
19
19
+
repo: agent.assertDid, // The user
20
20
+
collection: 'app.skeetlonger.post', // The collection
21
21
+
rkey, // The record key
22
22
+
record: { // The record value
23
23
+
post: postText,
24
24
+
createdAt: new Date().toISOString()
25
25
+
}
26
26
+
})
27
27
+
12
28
// setError(null);
13
29
// try {
14
30
// localStorage.setItem("lastHandle", user);
···
53
69
</div>
54
70
55
71
<button
72
72
+
onClick={() => handleSubmit()}
56
73
type='submit'
57
74
disabled={charCount < 300}
58
75
style={{ padding: '0.625rem 1.5rem', borderRadius: '0.5rem', fontSize: '0.875rem', fontWeight: '600', border: 'none', cursor: charCount === 0 ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s', backgroundColor: charCount === 0 ? '#6b7280' : '#2563eb', color: 'white' }}
+14
-3
src/main.tsx
···
1
1
import { StrictMode } from 'react'
2
2
import { createRoot } from 'react-dom/client'
3
3
import './index.css'
4
4
-
import App from './App.tsx'
4
4
+
import { RouterProvider, createRouter } from '@tanstack/react-router'
5
5
+
import { routeTree } from './routeTree.gen'
6
6
+
7
7
+
// Create a new router instance
8
8
+
const router = createRouter({ routeTree })
9
9
+
10
10
+
// Register the router instance for type safety
11
11
+
declare module '@tanstack/react-router' {
12
12
+
interface Register {
13
13
+
router: typeof router
14
14
+
}
15
15
+
}
5
16
6
17
createRoot(document.getElementById('root')!).render(
7
18
<StrictMode>
8
8
-
<App />
19
19
+
<RouterProvider router={router} />
9
20
</StrictMode>,
10
10
-
)
21
21
+
)
+50
-8
src/routeTree.gen.ts
···
9
9
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
10
11
11
import { Route as rootRouteImport } from './routes/__root'
12
12
+
import { Route as AboutRouteImport } from './routes/about'
13
13
+
import { Route as IndexRouteImport } from './routes/index'
12
14
13
13
-
export interface FileRoutesByFullPath {}
14
14
-
export interface FileRoutesByTo {}
15
15
+
const AboutRoute = AboutRouteImport.update({
16
16
+
id: '/about',
17
17
+
path: '/about',
18
18
+
getParentRoute: () => rootRouteImport,
19
19
+
} as any)
20
20
+
const IndexRoute = IndexRouteImport.update({
21
21
+
id: '/',
22
22
+
path: '/',
23
23
+
getParentRoute: () => rootRouteImport,
24
24
+
} as any)
25
25
+
26
26
+
export interface FileRoutesByFullPath {
27
27
+
'/': typeof IndexRoute
28
28
+
'/about': typeof AboutRoute
29
29
+
}
30
30
+
export interface FileRoutesByTo {
31
31
+
'/': typeof IndexRoute
32
32
+
'/about': typeof AboutRoute
33
33
+
}
15
34
export interface FileRoutesById {
16
35
__root__: typeof rootRouteImport
36
36
+
'/': typeof IndexRoute
37
37
+
'/about': typeof AboutRoute
17
38
}
18
39
export interface FileRouteTypes {
19
40
fileRoutesByFullPath: FileRoutesByFullPath
20
20
-
fullPaths: never
41
41
+
fullPaths: '/' | '/about'
21
42
fileRoutesByTo: FileRoutesByTo
22
22
-
to: never
23
23
-
id: '__root__'
43
43
+
to: '/' | '/about'
44
44
+
id: '__root__' | '/' | '/about'
24
45
fileRoutesById: FileRoutesById
25
46
}
26
26
-
export interface RootRouteChildren {}
47
47
+
export interface RootRouteChildren {
48
48
+
IndexRoute: typeof IndexRoute
49
49
+
AboutRoute: typeof AboutRoute
50
50
+
}
27
51
28
52
declare module '@tanstack/react-router' {
29
29
-
interface FileRoutesByPath {}
53
53
+
interface FileRoutesByPath {
54
54
+
'/about': {
55
55
+
id: '/about'
56
56
+
path: '/about'
57
57
+
fullPath: '/about'
58
58
+
preLoaderRoute: typeof AboutRouteImport
59
59
+
parentRoute: typeof rootRouteImport
60
60
+
}
61
61
+
'/': {
62
62
+
id: '/'
63
63
+
path: '/'
64
64
+
fullPath: '/'
65
65
+
preLoaderRoute: typeof IndexRouteImport
66
66
+
parentRoute: typeof rootRouteImport
67
67
+
}
68
68
+
}
30
69
}
31
70
32
32
-
const rootRouteChildren: RootRouteChildren = {}
71
71
+
const rootRouteChildren: RootRouteChildren = {
72
72
+
IndexRoute: IndexRoute,
73
73
+
AboutRoute: AboutRoute,
74
74
+
}
33
75
export const routeTree = rootRouteImport
34
76
._addFileChildren(rootRouteChildren)
35
77
._addFileTypes<FileRouteTypes>()
+4
-13
src/routes/__root.tsx
···
1
1
-
import * as React from 'react'
2
1
import { Outlet, createRootRoute } from '@tanstack/react-router'
3
2
import { UnifiedAuthProvider } from '../providers/UnifiedAuthProvider'
4
4
-
import Login from '../components/Login'
5
3
6
4
export const Route = createRootRoute({
7
5
component: RootComponent,
···
9
7
10
8
function RootComponent() {
11
9
return (
12
12
-
<React.Fragment>
13
13
-
<h1>SkeetLonger</h1>
14
14
-
15
15
-
<div className="flex items-center gap-2">
16
16
-
<UnifiedAuthProvider>
17
17
-
<Login compact={false}></Login>
18
18
-
</UnifiedAuthProvider>
19
19
-
</div>
20
20
-
<Outlet />
21
21
-
</React.Fragment>
10
10
+
<UnifiedAuthProvider>
11
11
+
<Outlet />
12
12
+
</UnifiedAuthProvider>
22
13
)
23
23
-
}
14
14
+
}
+102
src/routes/about.tsx
···
1
1
+
import { createFileRoute } from '@tanstack/react-router'
2
2
+
import Login from '../components/Login'
3
3
+
4
4
+
export const Route = createFileRoute('/about')({
5
5
+
component: AboutComponent,
6
6
+
})
7
7
+
8
8
+
function AboutComponent() {
9
9
+
return (
10
10
+
<>
11
11
+
<div style={{ position: 'fixed', top: '1rem', right: '1rem', zIndex: 9999 }}>
12
12
+
<Login compact={true} />
13
13
+
</div>
14
14
+
15
15
+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', backgroundColor: '#242424' }}>
16
16
+
<div style={{ width: '100%', maxWidth: '72rem' }}>
17
17
+
{/* Title */}
18
18
+
<h1 style={{ fontSize: '2.25rem', fontWeight: 'bold', textAlign: 'center', marginBottom: '0.5rem', color: '#f3f4f6' }}>
19
19
+
About SkeetLonger
20
20
+
</h1>
21
21
+
<p style={{ textAlign: 'center', marginBottom: '2rem', color: '#9ca3af' }}>
22
22
+
Learn more about posting longer content to Bluesky
23
23
+
</p>
24
24
+
25
25
+
{/* Content Card */}
26
26
+
<div style={{ padding: '2rem', borderRadius: '0.75rem', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)', border: '1px solid #374151', backgroundColor: '#1a1a1a' }}>
27
27
+
28
28
+
{/* What is SkeetLonger */}
29
29
+
<section style={{ marginBottom: '2rem' }}>
30
30
+
<h2 style={{ fontSize: '1.5rem', fontWeight: '600', color: '#f3f4f6', marginBottom: '0.75rem' }}>
31
31
+
What is SkeetLonger?
32
32
+
</h2>
33
33
+
<p style={{ lineHeight: '1.75', color: '#d1d5db' }}>
34
34
+
SkeetLonger is a tool that allows you to post longer content to Bluesky,
35
35
+
bypassing the standard 300-character limit. Perfect for sharing detailed
36
36
+
thoughts, stories, or discussions without the constraints of short-form posts.
37
37
+
</p>
38
38
+
</section>
39
39
+
40
40
+
{/* How does it work */}
41
41
+
<section style={{ marginBottom: '2rem' }}>
42
42
+
<h2 style={{ fontSize: '1.5rem', fontWeight: '600', color: '#f3f4f6', marginBottom: '0.75rem' }}>
43
43
+
How does it work?
44
44
+
</h2>
45
45
+
<p style={{ lineHeight: '1.75', color: '#d1d5db' }}>
46
46
+
SkeetLonger stores your longer posts (300+ characters) as custom records in the AT Protocol.
47
47
+
These records are saved to your Personal Data Server (PDS) under the app.skeetlonger.post
48
48
+
collection, allowing you to write and preserve content beyond Bluesky's standard character
49
49
+
limits while maintaining full ownership of your data.
50
50
+
</p>
51
51
+
</section>
52
52
+
53
53
+
{/* Privacy & Security */}
54
54
+
<section style={{ marginBottom: '2rem' }}>
55
55
+
<h2 style={{ fontSize: '1.5rem', fontWeight: '600', color: '#f3f4f6', marginBottom: '0.75rem' }}>
56
56
+
Privacy & Security
57
57
+
</h2>
58
58
+
<p style={{ lineHeight: '1.75', color: '#d1d5db' }}>
59
59
+
SkeetLonger uses OAuth authentication, which means your password is never
60
60
+
shared with us. We only request the permissions necessary to post on your
61
61
+
behalf. You can revoke access at any time through your Bluesky settings.
62
62
+
</p>
63
63
+
</section>
64
64
+
65
65
+
{/* Open Source */}
66
66
+
<section style={{ marginBottom: '2rem' }}>
67
67
+
<h2 style={{ fontSize: '1.5rem', fontWeight: '600', color: '#f3f4f6', marginBottom: '0.75rem' }}>
68
68
+
Open Source
69
69
+
</h2>
70
70
+
<p style={{ lineHeight: '1.75', color: '#d1d5db' }}>
71
71
+
SkeetLonger is built with modern web technologies and is committed to
72
72
+
transparency. The AT Protocol (Authenticated Transfer Protocol) powers
73
73
+
Bluesky and enables tools like this to be built on top of the platform.
74
74
+
</p>
75
75
+
</section>
76
76
+
77
77
+
{/* Button */}
78
78
+
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: '1rem', borderTop: '1px solid #374151' }}>
79
79
+
<a
80
80
+
href="/"
81
81
+
style={{
82
82
+
display: 'inline-block',
83
83
+
padding: '0.75rem 2rem',
84
84
+
borderRadius: '0.5rem',
85
85
+
backgroundColor: '#2563eb',
86
86
+
color: 'white',
87
87
+
fontWeight: '600',
88
88
+
textDecoration: 'none',
89
89
+
transition: 'background-color 0.2s'
90
90
+
}}
91
91
+
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#1d4ed8'}
92
92
+
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = '#2563eb'}
93
93
+
>
94
94
+
Start Writing
95
95
+
</a>
96
96
+
</div>
97
97
+
</div>
98
98
+
</div>
99
99
+
</div>
100
100
+
</>
101
101
+
)
102
102
+
}
+100
src/routes/index.tsx
···
1
1
+
import { createFileRoute } from '@tanstack/react-router'
2
2
+
import { useState } from 'react'
3
3
+
import '../App.css'
4
4
+
import Login from '../components/Login'
5
5
+
import { useAuth } from "../providers/UnifiedAuthProvider";
6
6
+
import { AtUri } from '@atproto/api';
7
7
+
8
8
+
export const Route = createFileRoute('/')({
9
9
+
component: RouteComponent,
10
10
+
})
11
11
+
12
12
+
function RouteComponent() {
13
13
+
const { agent } = useAuth();
14
14
+
15
15
+
const [postText, setPostText] = useState('')
16
16
+
const charCount = postText.length
17
17
+
18
18
+
const handleSubmit = async () => {
19
19
+
if (!agent) {
20
20
+
console.error("Agent not available");
21
21
+
return;
22
22
+
}
23
23
+
24
24
+
try {
25
25
+
// Create the record and let the server generate the rkey (TID)
26
26
+
const response = await agent.com.atproto.repo.createRecord({
27
27
+
repo: agent.assertDid,
28
28
+
collection: 'app.skeetlonger.post',
29
29
+
record: {
30
30
+
post: postText,
31
31
+
createdAt: new Date().toISOString()
32
32
+
}
33
33
+
});
34
34
+
35
35
+
// Parse the URI to extract the rkey
36
36
+
const uri = new AtUri(response.data.uri);
37
37
+
const rkey = uri.rkey;
38
38
+
39
39
+
console.log("Record created successfully!");
40
40
+
console.log("Full URI:", response.data.uri);
41
41
+
console.log("Extracted rkey:", rkey);
42
42
+
console.log("CID:", response.data.cid);
43
43
+
44
44
+
//setPostText(''); // Clear the textarea after posting
45
45
+
} catch (error) {
46
46
+
console.error("Failed to create record:", error);
47
47
+
}
48
48
+
};
49
49
+
50
50
+
return (
51
51
+
<>
52
52
+
<div style={{ position: 'fixed', top: '1rem', right: '1rem', zIndex: 9999 }}>
53
53
+
<Login compact={true} />
54
54
+
</div>
55
55
+
56
56
+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '5rem 1rem', backgroundColor: '#242424' }}>
57
57
+
<div style={{ width: '100%', maxWidth: '72rem' }}>
58
58
+
{/* Title */}
59
59
+
<h1 style={{ fontSize: '2.25rem', fontWeight: 'bold', textAlign: 'center', marginBottom: '0.5rem', color: '#f3f4f6' }}>
60
60
+
SkeetLonger
61
61
+
</h1>
62
62
+
<p style={{ textAlign: 'center', marginBottom: '2rem', color: '#9ca3af' }}>
63
63
+
Post longer content to Bluesky
64
64
+
</p>
65
65
+
66
66
+
{/* Text Editor Card */}
67
67
+
<div style={{ padding: '1.5rem', borderRadius: '0.75rem', boxShadow: '0 10px 15px -3px rgb(0 0 0 / 0.1)', border: '1px solid #e5e7eb', backgroundColor: '#1a1a1a', borderColor: '#374151' }}>
68
68
+
<textarea
69
69
+
value={postText}
70
70
+
onChange={(e) => setPostText(e.target.value)}
71
71
+
placeholder="What's on your mind? Write as much as you'd like..."
72
72
+
style={{ width: '32rem', height: '32rem', padding: '0.75rem 1rem', borderRadius: '0.5rem', border: '1px solid #4b5563', fontSize: '1rem', lineHeight: '1.75', resize: 'none', backgroundColor: '#111827', color: '#f3f4f6', boxSizing: 'border-box' }}
73
73
+
className="placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500"
74
74
+
/>
75
75
+
76
76
+
{/* Footer with character count and post button */}
77
77
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: '1rem' }}>
78
78
+
<div style={{ fontSize: '0.875rem' }}>
79
79
+
<span style={{ fontWeight: '500', color: charCount > 300 ? '#3b82f6' : '#9ca3af' }}>
80
80
+
{charCount} characters
81
81
+
</span>
82
82
+
</div>
83
83
+
84
84
+
<button
85
85
+
onClick={() => handleSubmit()}
86
86
+
type='submit'
87
87
+
disabled={charCount < 300}
88
88
+
style={{ padding: '0.625rem 1.5rem', borderRadius: '0.5rem', fontSize: '0.875rem', fontWeight: '600', border: 'none', cursor: charCount === 0 ? 'not-allowed' : 'pointer', transition: 'background-color 0.2s', backgroundColor: charCount === 0 ? '#6b7280' : '#2563eb', color: 'white' }}
89
89
+
onMouseEnter={(e) => { if (charCount !== 0) e.currentTarget.style.backgroundColor = '#1d4ed8'; }}
90
90
+
onMouseLeave={(e) => { if (charCount !== 0) e.currentTarget.style.backgroundColor = '#2563eb'; }}
91
91
+
>
92
92
+
Post
93
93
+
</button>
94
94
+
</div>
95
95
+
</div>
96
96
+
</div>
97
97
+
</div>
98
98
+
</>
99
99
+
)
100
100
+
}