A website for the ATmosphereConf
1---
2import '../styles.css'
3import { getSession } from '../lib/session'
4import { getOAuthClient } from '../lib/context'
5import { Agent } from '@atproto/api'
6
7const session = getSession(Astro.cookies)
8const oauthClient = getOAuthClient(Astro.cookies)
9
10let agent: Agent | null = null
11let profile: any = null
12
13if (session.did) {
14 try {
15 const oauthSession = await oauthClient.restore(session.did)
16 if (oauthSession) {
17 agent = new Agent(oauthSession)
18
19 try {
20 const profileResponse = await agent.app.bsky.actor.getProfile({
21 actor: agent.assertDid,
22 })
23 profile = profileResponse.data
24 } catch (err) {
25 console.warn('Failed to fetch profile:', err)
26 }
27 }
28 } catch (err) {
29 console.warn('OAuth restore failed:', err)
30 session.destroy()
31 }
32}
33
34const displayName = profile?.displayName || agent?.assertDid || 'User'
35const handle = profile?.handle || agent?.assertDid || ''
36const avatar = profile?.avatar
37const description = profile?.description
38---
39
40<html lang="en" data-theme="dracula">
41 <head>
42 <meta charset="utf-8" />
43 <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
44 <meta name="viewport" content="width=device-width" />
45 <meta name="generator" content={Astro.generator} />
46 <title>ATmosphere Login</title>
47 </head>
48 <body>
49 <div class="min-h-screen flex items-center justify-center">
50 <div class="card w-96 bg-base-200 shadow-xl p-8">
51 <div class="card-body">
52 {
53 agent ? (
54 <>
55 <h2 class="card-title justify-center mb-4">Welcome!</h2>
56 <div class="space-y-4">
57 <div class="flex flex-col items-center text-center">
58 {avatar && (
59 <div class="avatar mb-4">
60 <div class="w-24 rounded-full">
61 <img src={avatar} alt={displayName} />
62 </div>
63 </div>
64 )}
65 <p class="text-lg font-semibold">{displayName}</p>
66 <p class="text-sm opacity-70">{handle}</p>
67 {description && <p class="text-sm mt-2 opacity-80">{description}</p>}
68 </div>
69 <div class="space-y-2 w-full">
70 <a href={`/profile/${handle}`} class="btn btn-primary w-full">
71 View Profile
72 </a>
73 <form method="POST" action="/api/logout" class="w-full">
74 <button type="submit" class="btn btn-error w-full">
75 Logout
76 </button>
77 </form>
78 </div>
79 </div>
80 </>
81 ) : (
82 <>
83 <h2 class="card-title justify-center mb-6">ATmosphere Login</h2>
84 <form method="POST" action="/api/login">
85 <div class="join join-vertical w-full">
86 <input
87 type="text"
88 placeholder="Enter your handle (e.g. alice.bsky.social)"
89 class="input input-bordered join-item w-full"
90 name="handle"
91 required
92 />
93 <button type="submit" class="btn btn-primary join-item w-full">
94 Login
95 </button>
96 </div>
97 </form>
98 </>
99 )
100 }
101 </div>
102 </div>
103 </div>
104 </body>
105</html>