+25
bun.lock
+25
bun.lock
···
20
20
"@radix-ui/react-slot": "^1.2.3",
21
21
"@radix-ui/react-tabs": "^1.1.13",
22
22
"@tanstack/react-query": "^5.90.2",
23
+
"atproto-ui": "^0.11.1",
23
24
"class-variance-authority": "^0.7.1",
24
25
"clsx": "^2.1.1",
25
26
"elysia": "latest",
···
51
52
"protobufjs",
52
53
],
53
54
"packages": {
55
+
"@atcute/atproto": ["@atcute/atproto@3.1.9", "", { "dependencies": { "@atcute/lexicons": "^1.2.2" } }, "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w=="],
56
+
57
+
"@atcute/bluesky": ["@atcute/bluesky@3.2.10", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.2" } }, "sha512-qwQWTzRf3umnh2u41gdU+xWYkbzGlKDupc3zeOB+YjmuP1N9wEaUhwS8H7vgrqr0xC9SGNDjeUVcjC4m5BPLBg=="],
58
+
59
+
"@atcute/client": ["@atcute/client@4.0.5", "", { "dependencies": { "@atcute/identity": "^1.1.1", "@atcute/lexicons": "^1.2.2" } }, "sha512-R8Qen8goGmEkynYGg2m6XFlVmz0GTDvQ+9w+4QqOob+XMk8/WDpF4aImev7WKEde/rV2gjcqW7zM8E6W9NShDA=="],
60
+
61
+
"@atcute/identity": ["@atcute/identity@1.1.1", "", { "dependencies": { "@atcute/lexicons": "^1.2.2", "@badrap/valita": "^0.4.6" } }, "sha512-zax42n693VEhnC+5tndvO2KLDTMkHOz8UExwmklvJv7R9VujfEwiSWhcv6Jgwb3ellaG8wjiQ1lMOIjLLvwh0Q=="],
62
+
63
+
"@atcute/identity-resolver": ["@atcute/identity-resolver@1.1.4", "", { "dependencies": { "@atcute/lexicons": "^1.2.2", "@atcute/util-fetch": "^1.0.3", "@badrap/valita": "^0.4.6" }, "peerDependencies": { "@atcute/identity": "^1.0.0" } }, "sha512-/SVh8vf2cXFJenmBnGeYF2aY3WGQm3cJeew5NWTlkqoy3LvJ5wkvKq9PWu4Tv653VF40rPOp6LOdVr9Fa+q5rA=="],
64
+
65
+
"@atcute/lexicons": ["@atcute/lexicons@1.2.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "esm-env": "^1.2.2" } }, "sha512-bgEhJq5Z70/0TbK5sx+tAkrR8FsCODNiL2gUEvS5PuJfPxmFmRYNWaMGehxSPaXWpU2+Oa9ckceHiYbrItDTkA=="],
66
+
67
+
"@atcute/tangled": ["@atcute/tangled@1.0.10", "", { "dependencies": { "@atcute/atproto": "^3.1.8", "@atcute/lexicons": "^1.2.2" } }, "sha512-DGconZIN5TpLBah+aHGbWI1tMsL7XzyVEbr/fW4CbcLWYKICU6SAUZ0YnZ+5GvltjlORWHUy7hfftvoh4zodIA=="],
68
+
69
+
"@atcute/util-fetch": ["@atcute/util-fetch@1.0.3", "", { "dependencies": { "@badrap/valita": "^0.4.6" } }, "sha512-f8zzTb/xlKIwv2OQ31DhShPUNCmIIleX6p7qIXwWwEUjX6x8skUtpdISSjnImq01LXpltGV5y8yhV4/Mlb7CRQ=="],
70
+
54
71
"@atproto-labs/did-resolver": ["@atproto-labs/did-resolver@0.2.2", "", { "dependencies": { "@atproto-labs/fetch": "0.2.3", "@atproto-labs/pipe": "0.1.1", "@atproto-labs/simple-store": "0.3.0", "@atproto-labs/simple-store-memory": "0.1.4", "@atproto/did": "0.2.1", "zod": "^3.23.8" } }, "sha512-ca2B7xR43tVoQ8XxBvha58DXwIH8cIyKQl6lpOKGkPUrJuFoO4iCLlDiSDi2Ueh+yE1rMDPP/qveHdajgDX3WQ=="],
55
72
56
73
"@atproto-labs/fetch": ["@atproto-labs/fetch@0.2.3", "", { "dependencies": { "@atproto-labs/pipe": "0.1.1" } }, "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw=="],
···
100
117
"@atproto/xrpc": ["@atproto/xrpc@0.7.5", "", { "dependencies": { "@atproto/lexicon": "^0.5.1", "zod": "^3.23.8" } }, "sha512-MUYNn5d2hv8yVegRL0ccHvTHAVj5JSnW07bkbiaz96UH45lvYNRVwt44z+yYVnb0/mvBzyD3/ZQ55TRGt7fHkA=="],
101
118
102
119
"@atproto/xrpc-server": ["@atproto/xrpc-server@0.9.5", "", { "dependencies": { "@atproto/common": "^0.4.12", "@atproto/crypto": "^0.4.4", "@atproto/lexicon": "^0.5.1", "@atproto/xrpc": "^0.7.5", "cbor-x": "^1.5.1", "express": "^4.17.2", "http-errors": "^2.0.0", "mime-types": "^2.1.35", "rate-limiter-flexible": "^2.4.1", "uint8arrays": "3.0.0", "ws": "^8.12.0", "zod": "^3.23.8" } }, "sha512-V0srjUgy6mQ5yf9+MSNBLs457m4qclEaWZsnqIE7RfYywvntexTAbMoo7J7ONfTNwdmA9Gw4oLak2z2cDAET4w=="],
120
+
121
+
"@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="],
103
122
104
123
"@borewit/text-codec": ["@borewit/text-codec@0.1.1", "", {}, "sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA=="],
105
124
···
341
360
342
361
"@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="],
343
362
363
+
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
364
+
344
365
"@tanstack/query-core": ["@tanstack/query-core@5.90.7", "", {}, "sha512-6PN65csiuTNfBMXqQUxQhCNdtm1rV+9kC9YwWAIKcaxAauq3Wu7p18j3gQY3YIBJU70jT/wzCCZ2uqto/vQgiQ=="],
345
366
346
367
"@tanstack/react-query": ["@tanstack/react-query@5.90.7", "", { "dependencies": { "@tanstack/query-core": "5.90.7" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-wAHc/cgKzW7LZNFloThyHnV/AX9gTg3w5yAv0gvQHPZoCnepwqCMtzbuPbb2UvfvO32XZ46e8bPOYbfZhzVnnQ=="],
···
376
397
"array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="],
377
398
378
399
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
400
+
401
+
"atproto-ui": ["atproto-ui@0.11.1", "", { "dependencies": { "@atcute/atproto": "^3.1.7", "@atcute/bluesky": "^3.2.3", "@atcute/client": "^4.0.3", "@atcute/identity-resolver": "^1.1.3", "@atcute/tangled": "^1.0.10" }, "peerDependencies": { "react": "^18.2.0 || ^19.0.0", "react-dom": "^18.2.0 || ^19.0.0" }, "optionalPeers": ["react-dom"] }, "sha512-RpX9OGx3GDw0uL2X0Lw0bgzqEKKhfMeFuTUIgJuAa3W3MlLBH6h4qOWzaHXdrVQpru+6SQ0HznfRlQHK6nYRkQ=="],
379
402
380
403
"await-lock": ["await-lock@2.2.2", "", {}, "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="],
381
404
···
468
491
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
469
492
470
493
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
494
+
495
+
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
471
496
472
497
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
473
498
+1
package.json
+1
package.json
+1
-4
public/editor/editor.tsx
+1
-4
public/editor/editor.tsx
···
19
19
import { Label } from '@public/components/ui/label'
20
20
import { Badge } from '@public/components/ui/badge'
21
21
import {
22
-
Globe,
23
22
Loader2,
24
23
Trash2,
25
24
LogOut
···
189
188
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
190
189
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
191
190
<div className="flex items-center gap-2">
192
-
<div className="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
193
-
<Globe className="w-5 h-5 text-primary-foreground" />
194
-
</div>
191
+
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
195
192
<span className="text-xl font-semibold text-foreground">
196
193
wisp.place
197
194
</span>
+74
-6
public/index.tsx
+74
-6
public/index.tsx
···
13
13
import Layout from '@public/layouts'
14
14
import { Button } from '@public/components/ui/button'
15
15
import { Card } from '@public/components/ui/card'
16
+
import { BlueskyPostList, BlueskyProfile, BlueskyPost, AtProtoProvider, useLatestRecord, type AtProtoStyles, type FeedPostRecord } from 'atproto-ui'
17
+
import 'atproto-ui/styles.css'
18
+
19
+
const LatestPostWithPrefetch: React.FC<{ did: string }> = ({ did }) => {
20
+
// Fetch once with the hook
21
+
const { record, rkey, loading } = useLatestRecord<FeedPostRecord>(
22
+
did,
23
+
'app.bsky.feed.post'
24
+
)
25
+
26
+
if (loading) return <span>Loading…</span>
27
+
if (!record || !rkey) return <span>No posts yet.</span>
28
+
29
+
// Pass prefetched record—BlueskyPost won't re-fetch it
30
+
return <BlueskyPost did={did} rkey={rkey} record={record} showParent={true} />
31
+
}
16
32
17
33
function App() {
18
34
const [showForm, setShowForm] = useState(false)
···
63
79
<header className="border-b border-border/40 bg-background/80 backdrop-blur-sm sticky top-0 z-50">
64
80
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
65
81
<div className="flex items-center gap-2">
66
-
<div className="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
67
-
<Globe className="w-5 h-5 text-primary-foreground" />
68
-
</div>
82
+
<img src="/transparent-full-size-ico.png" alt="wisp.place" className="w-8 h-8" />
69
83
<span className="text-xl font-semibold text-foreground">
70
84
wisp.place
71
85
</span>
···
81
95
<Button
82
96
size="sm"
83
97
className="bg-accent text-accent-foreground hover:bg-accent/90"
98
+
onClick={() => setShowForm(true)}
84
99
>
85
100
Get Started
86
101
</Button>
···
318
333
319
334
{/* CTA Section */}
320
335
<section className="container mx-auto px-4 py-20">
336
+
<div className="max-w-6xl mx-auto">
337
+
<div className="text-center mb-12">
338
+
<h2 className="text-3xl md:text-4xl font-bold">
339
+
Follow on Bluesky for updates
340
+
</h2>
341
+
</div>
342
+
<div className="grid md:grid-cols-2 gap-8 items-center">
343
+
<Card
344
+
className="shadow-lg border-2 border-border overflow-hidden !py-3"
345
+
style={{
346
+
'--atproto-color-bg': 'var(--card)',
347
+
'--atproto-color-bg-elevated': 'hsl(var(--muted) / 0.3)',
348
+
'--atproto-color-text': 'hsl(var(--foreground))',
349
+
'--atproto-color-text-secondary': 'hsl(var(--muted-foreground))',
350
+
'--atproto-color-link': 'hsl(var(--accent))',
351
+
'--atproto-color-link-hover': 'hsl(var(--accent))',
352
+
'--atproto-color-border': 'transparent',
353
+
} as AtProtoStyles}
354
+
>
355
+
<BlueskyPostList did="wisp.place" />
356
+
</Card>
357
+
<div className="space-y-6 w-full max-w-md mx-auto">
358
+
<Card
359
+
className="shadow-lg border-2 overflow-hidden relative !py-3"
360
+
style={{
361
+
'--atproto-color-bg': 'var(--card)',
362
+
'--atproto-color-bg-elevated': 'hsl(var(--muted) / 0.3)',
363
+
'--atproto-color-text': 'hsl(var(--foreground))',
364
+
'--atproto-color-text-secondary': 'hsl(var(--muted-foreground))',
365
+
} as AtProtoStyles}
366
+
>
367
+
<BlueskyProfile did="wisp.place" />
368
+
</Card>
369
+
<Card
370
+
className="shadow-lg border-2 overflow-hidden relative !py-3"
371
+
style={{
372
+
'--atproto-color-bg': 'var(--card)',
373
+
'--atproto-color-bg-elevated': 'hsl(var(--muted) / 0.3)',
374
+
'--atproto-color-text': 'hsl(var(--foreground))',
375
+
'--atproto-color-text-secondary': 'hsl(var(--muted-foreground))',
376
+
} as AtProtoStyles}
377
+
>
378
+
<LatestPostWithPrefetch did="wisp.place" />
379
+
</Card>
380
+
</div>
381
+
</div>
382
+
</div>
383
+
</section>
384
+
385
+
{/* Ready to Deploy CTA */}
386
+
<section className="container mx-auto px-4 py-20">
321
387
<div className="max-w-3xl mx-auto text-center bg-accent/5 border border-accent/20 rounded-2xl p-12">
322
388
<h2 className="text-3xl md:text-4xl font-bold mb-4">
323
389
Ready to deploy?
···
362
428
363
429
const root = createRoot(document.getElementById('elysia')!)
364
430
root.render(
365
-
<Layout className="gap-6">
366
-
<App />
367
-
</Layout>
431
+
<AtProtoProvider>
432
+
<Layout className="gap-6">
433
+
<App />
434
+
</Layout>
435
+
</AtProtoProvider>
368
436
)
public/transparent-full-size-ico.png
public/transparent-full-size-ico.png
This is a binary file and will not be displayed.