this repo has no description
1<script lang="ts">
2 import { getAuthState, logout } from '../lib/auth.svelte'
3 import { navigate } from '../lib/router.svelte'
4
5 const auth = getAuthState()
6
7 $effect(() => {
8 if (!auth.loading && !auth.session) {
9 navigate('/login')
10 }
11 })
12
13 async function handleLogout() {
14 await logout()
15 navigate('/login')
16 }
17</script>
18
19{#if auth.session}
20 <div class="dashboard">
21 <header>
22 <h1>Dashboard</h1>
23 <button class="logout" onclick={handleLogout}>Sign Out</button>
24 </header>
25
26 <section class="account-overview">
27 <h2>Account Overview</h2>
28 <dl>
29 <dt>Handle</dt>
30 <dd>@{auth.session.handle}</dd>
31
32 <dt>DID</dt>
33 <dd class="mono">{auth.session.did}</dd>
34
35 {#if auth.session.email}
36 <dt>Email</dt>
37 <dd>
38 {auth.session.email}
39 {#if auth.session.emailConfirmed}
40 <span class="badge success">Verified</span>
41 {:else}
42 <span class="badge warning">Unverified</span>
43 {/if}
44 </dd>
45 {/if}
46 </dl>
47 </section>
48
49 <nav class="nav-grid">
50 <a href="#/app-passwords" class="nav-card">
51 <h3>App Passwords</h3>
52 <p>Manage passwords for third-party apps</p>
53 </a>
54
55 <a href="#/invite-codes" class="nav-card">
56 <h3>Invite Codes</h3>
57 <p>View and create invite codes</p>
58 </a>
59
60 <a href="#/settings" class="nav-card">
61 <h3>Account Settings</h3>
62 <p>Email, password, handle, and more</p>
63 </a>
64
65 <a href="#/notifications" class="nav-card">
66 <h3>Notification Preferences</h3>
67 <p>Discord, Telegram, Signal channels</p>
68 </a>
69
70 <a href="#/repo" class="nav-card">
71 <h3>Repository Explorer</h3>
72 <p>Browse and manage raw AT Protocol records</p>
73 </a>
74 </nav>
75 </div>
76{:else if auth.loading}
77 <div class="loading">Loading...</div>
78{/if}
79
80<style>
81 .dashboard {
82 max-width: 800px;
83 margin: 0 auto;
84 padding: 2rem;
85 }
86
87 header {
88 display: flex;
89 justify-content: space-between;
90 align-items: center;
91 margin-bottom: 2rem;
92 }
93
94 header h1 {
95 margin: 0;
96 }
97
98 .logout {
99 padding: 0.5rem 1rem;
100 background: transparent;
101 border: 1px solid var(--border-color-light);
102 border-radius: 4px;
103 cursor: pointer;
104 color: var(--text-primary);
105 }
106
107 .logout:hover {
108 background: var(--bg-secondary);
109 }
110
111 section {
112 background: var(--bg-secondary);
113 padding: 1.5rem;
114 border-radius: 8px;
115 margin-bottom: 2rem;
116 }
117
118 section h2 {
119 margin: 0 0 1rem 0;
120 font-size: 1.25rem;
121 }
122
123 dl {
124 display: grid;
125 grid-template-columns: auto 1fr;
126 gap: 0.5rem 1rem;
127 margin: 0;
128 }
129
130 dt {
131 font-weight: 500;
132 color: var(--text-secondary);
133 }
134
135 dd {
136 margin: 0;
137 }
138
139 .mono {
140 font-family: monospace;
141 font-size: 0.875rem;
142 word-break: break-all;
143 }
144
145 .badge {
146 display: inline-block;
147 padding: 0.125rem 0.5rem;
148 border-radius: 4px;
149 font-size: 0.75rem;
150 margin-left: 0.5rem;
151 }
152
153 .badge.success {
154 background: var(--success-bg);
155 color: var(--success-text);
156 }
157
158 .badge.warning {
159 background: var(--warning-bg);
160 color: var(--warning-text);
161 }
162
163 .nav-grid {
164 display: grid;
165 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
166 gap: 1rem;
167 }
168
169 .nav-card {
170 display: block;
171 padding: 1.5rem;
172 background: var(--bg-card);
173 border: 1px solid var(--border-color);
174 border-radius: 8px;
175 text-decoration: none;
176 color: inherit;
177 transition: border-color 0.15s, box-shadow 0.15s;
178 }
179
180 .nav-card:hover {
181 border-color: var(--accent);
182 box-shadow: 0 2px 8px rgba(77, 166, 255, 0.15);
183 }
184
185 .nav-card h3 {
186 margin: 0 0 0.5rem 0;
187 color: var(--accent);
188 }
189
190 .nav-card p {
191 margin: 0;
192 color: var(--text-secondary);
193 font-size: 0.875rem;
194 }
195
196 .loading {
197 text-align: center;
198 padding: 4rem;
199 color: var(--text-secondary);
200 }
201</style>