@atmo-dev/kit 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -2
- package/dist/components/Avatar.svelte +35 -0
- package/dist/components/Avatar.svelte.d.ts +9 -0
- package/dist/components/Badge.svelte +21 -0
- package/dist/components/Badge.svelte.d.ts +7 -0
- package/dist/components/Button.svelte +94 -0
- package/dist/components/Button.svelte.d.ts +13 -0
- package/dist/components/Checkbox.svelte +29 -0
- package/dist/components/Checkbox.svelte.d.ts +8 -0
- package/dist/components/Heading.svelte +24 -0
- package/dist/components/Heading.svelte.d.ts +8 -0
- package/dist/components/Icon.svelte +24 -0
- package/dist/components/Icon.svelte.d.ts +8 -0
- package/dist/components/IconButton.svelte +24 -0
- package/dist/components/IconButton.svelte.d.ts +8 -0
- package/dist/components/IconRail.svelte +183 -0
- package/dist/components/IconRail.svelte.d.ts +26 -0
- package/dist/components/InlineEditor.svelte +120 -0
- package/dist/components/InlineEditor.svelte.d.ts +19 -0
- package/dist/components/Input.svelte +32 -0
- package/dist/components/Input.svelte.d.ts +9 -0
- package/dist/components/InsetImage.svelte +29 -0
- package/dist/components/InsetImage.svelte.d.ts +9 -0
- package/dist/components/Label.svelte +19 -0
- package/dist/components/Label.svelte.d.ts +7 -0
- package/dist/components/LinkCard.svelte +47 -0
- package/dist/components/LinkCard.svelte.d.ts +12 -0
- package/dist/components/Modal.svelte +93 -0
- package/dist/components/Modal.svelte.d.ts +12 -0
- package/dist/components/NestedComments.svelte +61 -0
- package/dist/components/NestedComments.svelte.d.ts +8 -0
- package/dist/components/PageTitle.svelte +22 -0
- package/dist/components/PageTitle.svelte.d.ts +8 -0
- package/dist/components/Popover.svelte +49 -0
- package/dist/components/Popover.svelte.d.ts +12 -0
- package/dist/components/PostComposer.svelte +41 -0
- package/dist/components/PostComposer.svelte.d.ts +16 -0
- package/dist/components/PostContent.svelte +62 -0
- package/dist/components/PostContent.svelte.d.ts +8 -0
- package/dist/components/PostVideo.svelte +74 -0
- package/dist/components/PostVideo.svelte.d.ts +9 -0
- package/dist/components/Select.svelte +34 -0
- package/dist/components/Select.svelte.d.ts +9 -0
- package/dist/components/Subheading.svelte +22 -0
- package/dist/components/Subheading.svelte.d.ts +8 -0
- package/dist/components/Surface.svelte +40 -0
- package/dist/components/Surface.svelte.d.ts +11 -0
- package/dist/components/Tabs.svelte +47 -0
- package/dist/components/Tabs.svelte.d.ts +16 -0
- package/dist/components/Textarea.svelte +20 -0
- package/dist/components/Textarea.svelte.d.ts +7 -0
- package/dist/components/ToggleGroup.svelte +32 -0
- package/dist/components/ToggleGroup.svelte.d.ts +12 -0
- package/dist/components/ToggleGroupItem.svelte +26 -0
- package/dist/components/ToggleGroupItem.svelte.d.ts +8 -0
- package/dist/components/WorkspaceSidebar.svelte +82 -0
- package/dist/components/WorkspaceSidebar.svelte.d.ts +10 -0
- package/dist/components/login/ActorSearchField.svelte +238 -0
- package/dist/components/login/ActorSearchField.svelte.d.ts +19 -0
- package/dist/components/login/AtmosphereApps.svelte +19 -0
- package/dist/components/login/AtmosphereApps.svelte.d.ts +18 -0
- package/dist/components/login/LoginDialog.svelte +78 -0
- package/dist/components/login/LoginDialog.svelte.d.ts +9 -0
- package/dist/components/login/LoginForm.svelte +402 -0
- package/dist/components/login/LoginForm.svelte.d.ts +28 -0
- package/dist/components/login/RecentAccounts.svelte +57 -0
- package/dist/components/login/RecentAccounts.svelte.d.ts +10 -0
- package/dist/components/login/brands/README.md +7 -0
- package/dist/components/login/brands/blacksky.svg +3 -0
- package/dist/components/login/brands/bluesky.svg +3 -0
- package/dist/components/login/brands/bookhive.svg +3 -0
- package/dist/components/login/brands/graze.svg +3 -0
- package/dist/components/login/brands/leaflet.svg +3 -0
- package/dist/components/login/brands/pckt.svg +3 -0
- package/dist/components/login/brands/surf.svg +3 -0
- package/dist/components/login/brands/tangled.svg +3 -0
- package/dist/components/login/handle.d.ts +3 -0
- package/dist/components/login/handle.js +11 -0
- package/dist/components/login/permissions.d.ts +3 -0
- package/dist/components/login/permissions.js +13 -0
- package/dist/components/login/recent-accounts.d.ts +16 -0
- package/dist/components/login/recent-accounts.js +87 -0
- package/dist/components/login/search.d.ts +9 -0
- package/dist/components/login/search.js +47 -0
- package/dist/components/login/types.d.ts +27 -0
- package/dist/components/login/types.js +1 -0
- package/dist/confetti.d.ts +2 -0
- package/dist/confetti.js +13 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +40 -0
- package/dist/palettes.d.ts +2 -0
- package/dist/palettes.js +30 -0
- package/dist/social/mention-suggestions.d.ts +35 -0
- package/dist/social/mention-suggestions.js +122 -0
- package/dist/social/posts.d.ts +95 -0
- package/dist/social/posts.js +59 -0
- package/dist/social/richtext.d.ts +25 -0
- package/dist/social/richtext.js +100 -0
- package/dist/styles.d.ts +2 -0
- package/dist/styles.js +3 -0
- package/dist/theme.css +499 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.js +23 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +6 -0
- package/package.json +108 -3
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLFormAttributes } from 'svelte/elements';
|
|
4
|
+
import type {
|
|
5
|
+
ActorSearch,
|
|
6
|
+
ActorSummary,
|
|
7
|
+
LoginCallback,
|
|
8
|
+
LoginResult,
|
|
9
|
+
LoginPermission,
|
|
10
|
+
LoginStep
|
|
11
|
+
} from './types.js';
|
|
12
|
+
import type { RecentAccountStorageOptions } from './recent-accounts.js';
|
|
13
|
+
export type LoginFormProps = Omit<
|
|
14
|
+
HTMLFormAttributes,
|
|
15
|
+
'children' | 'onsubmit' | 'action' | 'method' | 'title'
|
|
16
|
+
> & {
|
|
17
|
+
login: LoginCallback;
|
|
18
|
+
signup?: () => LoginResult | Promise<LoginResult>;
|
|
19
|
+
searchActors?: ActorSearch;
|
|
20
|
+
initialHandle?: string;
|
|
21
|
+
loginOnSelect?: boolean;
|
|
22
|
+
recentAccounts?: ActorSummary[];
|
|
23
|
+
persistRecentAccounts?: boolean;
|
|
24
|
+
recentAccountOptions?: RecentAccountStorageOptions;
|
|
25
|
+
permissions?: readonly LoginPermission[];
|
|
26
|
+
baseScopes?: readonly string[];
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
showHeader?: boolean;
|
|
30
|
+
showApps?: boolean;
|
|
31
|
+
onSuccess?: (handle: string, actor?: ActorSummary) => void;
|
|
32
|
+
onStepChange?: (step: LoginStep) => void;
|
|
33
|
+
children?: Snippet;
|
|
34
|
+
footer?: Snippet<[LoginStep]>;
|
|
35
|
+
ref?: HTMLFormElement | null;
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script lang="ts">
|
|
40
|
+
import { onMount, onDestroy, tick, untrack } from 'svelte';
|
|
41
|
+
import { X, ShieldCheck, TriangleAlert, ArrowRight } from '@sketchyicons/svelte';
|
|
42
|
+
import Button from '../Button.svelte';
|
|
43
|
+
import IconButton from '../IconButton.svelte';
|
|
44
|
+
import Icon from '../Icon.svelte';
|
|
45
|
+
import Avatar from '../Avatar.svelte';
|
|
46
|
+
import Checkbox from '../Checkbox.svelte';
|
|
47
|
+
import Label from '../Label.svelte';
|
|
48
|
+
import Heading from '../Heading.svelte';
|
|
49
|
+
import ActorSearchField from './ActorSearchField.svelte';
|
|
50
|
+
import RecentAccounts from './RecentAccounts.svelte';
|
|
51
|
+
import AtmosphereApps from './AtmosphereApps.svelte';
|
|
52
|
+
import { actorName } from './types.js';
|
|
53
|
+
import { handleError, normalizeHandle } from './handle.js';
|
|
54
|
+
import { isPermissionSelected, resolveLoginOptions } from './permissions.js';
|
|
55
|
+
import {
|
|
56
|
+
loadRecentAccounts,
|
|
57
|
+
writeRecentAccounts,
|
|
58
|
+
recentAccountLimit
|
|
59
|
+
} from './recent-accounts.js';
|
|
60
|
+
import { cn } from '../../utils.js';
|
|
61
|
+
let {
|
|
62
|
+
login,
|
|
63
|
+
signup,
|
|
64
|
+
searchActors,
|
|
65
|
+
initialHandle = '',
|
|
66
|
+
loginOnSelect = true,
|
|
67
|
+
recentAccounts = $bindable([]),
|
|
68
|
+
persistRecentAccounts = false,
|
|
69
|
+
recentAccountOptions = {},
|
|
70
|
+
permissions = [],
|
|
71
|
+
baseScopes = ['atproto'],
|
|
72
|
+
title = 'Log in with your Atmosphere account',
|
|
73
|
+
description,
|
|
74
|
+
showHeader = true,
|
|
75
|
+
showApps = true,
|
|
76
|
+
onSuccess,
|
|
77
|
+
onStepChange,
|
|
78
|
+
children,
|
|
79
|
+
footer,
|
|
80
|
+
ref = $bindable(null),
|
|
81
|
+
class: className,
|
|
82
|
+
...rest
|
|
83
|
+
}: LoginFormProps = $props();
|
|
84
|
+
const uid = $props.id();
|
|
85
|
+
let value = $state(untrack(() => initialHandle));
|
|
86
|
+
let selected = $state<ActorSummary>();
|
|
87
|
+
let step = $state<LoginStep>('login');
|
|
88
|
+
let busy = $state(false);
|
|
89
|
+
let error = $state('');
|
|
90
|
+
let useRecent = $state(true);
|
|
91
|
+
let choices = $state<Record<string, boolean>>({});
|
|
92
|
+
let pending = $state<{ handle: string; actor?: ActorSummary }>();
|
|
93
|
+
let input = $state<HTMLInputElement | null>(null);
|
|
94
|
+
let submitRef = $state<HTMLButtonElement | HTMLAnchorElement | null>(null);
|
|
95
|
+
let heading = $state<HTMLHeadingElement | null>(null);
|
|
96
|
+
let alive = true;
|
|
97
|
+
let previous = untrack(() => value);
|
|
98
|
+
const recentLimit = $derived(recentAccountLimit(recentAccountOptions.max));
|
|
99
|
+
const showRecent = $derived(
|
|
100
|
+
useRecent && recentAccounts.length > 0 && !initialHandle && !selected
|
|
101
|
+
);
|
|
102
|
+
const headingText = $derived(
|
|
103
|
+
step === 'permissions'
|
|
104
|
+
? 'Requested permissions'
|
|
105
|
+
: step === 'signup'
|
|
106
|
+
? 'Already have an account?'
|
|
107
|
+
: title
|
|
108
|
+
);
|
|
109
|
+
const descriptionText = $derived(
|
|
110
|
+
step === 'permissions'
|
|
111
|
+
? 'Choose what this app can access. Required permissions stay on.'
|
|
112
|
+
: step === 'signup'
|
|
113
|
+
? 'You can use a Bluesky, Blacksky, or other Atmosphere account here. Otherwise, continue to create one.'
|
|
114
|
+
: description
|
|
115
|
+
);
|
|
116
|
+
$effect(() => {
|
|
117
|
+
const current = step;
|
|
118
|
+
untrack(() => onStepChange?.(current));
|
|
119
|
+
});
|
|
120
|
+
$effect(() => {
|
|
121
|
+
const next = value;
|
|
122
|
+
if (next !== previous) {
|
|
123
|
+
previous = next;
|
|
124
|
+
error = '';
|
|
125
|
+
if (selected && normalizeHandle(selected.handle) !== normalizeHandle(next))
|
|
126
|
+
selected = undefined;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
onMount(() => {
|
|
130
|
+
if (persistRecentAccounts) {
|
|
131
|
+
const stored = loadRecentAccounts(recentAccountOptions);
|
|
132
|
+
const accounts = [...recentAccounts, ...stored];
|
|
133
|
+
recentAccounts = accounts
|
|
134
|
+
.filter((actor, index) => accounts.findIndex((other) => other.did === actor.did) === index)
|
|
135
|
+
.slice(0, recentLimit);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
onDestroy(() => {
|
|
139
|
+
alive = false;
|
|
140
|
+
});
|
|
141
|
+
async function focusAccount() {
|
|
142
|
+
await tick();
|
|
143
|
+
if (!alive) return;
|
|
144
|
+
if (selected) submitRef?.focus();
|
|
145
|
+
else if (showRecent) ref?.querySelector<HTMLButtonElement>('[data-account]')?.focus();
|
|
146
|
+
else input?.focus();
|
|
147
|
+
}
|
|
148
|
+
async function changeStep(next: LoginStep) {
|
|
149
|
+
error = '';
|
|
150
|
+
step = next;
|
|
151
|
+
await tick();
|
|
152
|
+
if (!alive) return;
|
|
153
|
+
if (next === 'login') await focusAccount();
|
|
154
|
+
else if (showHeader) heading?.focus();
|
|
155
|
+
}
|
|
156
|
+
async function authenticate(request: { handle: string; actor?: ActorSummary }) {
|
|
157
|
+
if (busy) return;
|
|
158
|
+
busy = true;
|
|
159
|
+
error = '';
|
|
160
|
+
try {
|
|
161
|
+
const result = permissions.length
|
|
162
|
+
? await login(
|
|
163
|
+
request.handle,
|
|
164
|
+
request.actor,
|
|
165
|
+
resolveLoginOptions(permissions, choices, baseScopes)
|
|
166
|
+
)
|
|
167
|
+
: await login(request.handle, request.actor);
|
|
168
|
+
if (!alive) return;
|
|
169
|
+
if (result === false) return;
|
|
170
|
+
if (request.actor?.did) {
|
|
171
|
+
const next = [
|
|
172
|
+
{ ...request.actor, lastUsedAt: new Date().toISOString() },
|
|
173
|
+
...recentAccounts.filter(
|
|
174
|
+
(actor) => actor.did !== request.actor?.did && actor.handle !== request.handle
|
|
175
|
+
)
|
|
176
|
+
].slice(0, recentLimit);
|
|
177
|
+
recentAccounts = persistRecentAccounts
|
|
178
|
+
? writeRecentAccounts(next, recentAccountOptions)
|
|
179
|
+
: next;
|
|
180
|
+
}
|
|
181
|
+
onSuccess?.(request.handle, request.actor);
|
|
182
|
+
} catch (caught) {
|
|
183
|
+
if (alive)
|
|
184
|
+
error = caught instanceof Error ? caught.message : 'Login failed. Please try again.';
|
|
185
|
+
} finally {
|
|
186
|
+
if (alive) {
|
|
187
|
+
busy = false;
|
|
188
|
+
await tick();
|
|
189
|
+
if (alive && error) submitRef?.focus();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function beginLogin(handle = value, actor = selected) {
|
|
194
|
+
if (busy) return;
|
|
195
|
+
const normalized = normalizeHandle(handle);
|
|
196
|
+
const problem = handleError(normalized);
|
|
197
|
+
if (problem) {
|
|
198
|
+
error = problem;
|
|
199
|
+
await focusAccount();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
previous = normalized;
|
|
203
|
+
value = normalized;
|
|
204
|
+
const request = {
|
|
205
|
+
handle: normalized,
|
|
206
|
+
actor: actor && normalizeHandle(actor.handle) === normalized ? actor : undefined
|
|
207
|
+
};
|
|
208
|
+
pending = request;
|
|
209
|
+
if (permissions.length) await changeStep('permissions');
|
|
210
|
+
else await authenticate(request);
|
|
211
|
+
}
|
|
212
|
+
function select(actor: ActorSummary, start = loginOnSelect) {
|
|
213
|
+
if (busy) return;
|
|
214
|
+
selected = actor;
|
|
215
|
+
value = actor.handle;
|
|
216
|
+
error = '';
|
|
217
|
+
useRecent = false;
|
|
218
|
+
if (start) void beginLogin(actor.handle, actor);
|
|
219
|
+
else void focusAccount();
|
|
220
|
+
}
|
|
221
|
+
async function removeRecent(actor: ActorSummary) {
|
|
222
|
+
recentAccounts = recentAccounts.filter((account) => account.did !== actor.did);
|
|
223
|
+
if (persistRecentAccounts) writeRecentAccounts(recentAccounts, recentAccountOptions);
|
|
224
|
+
if (!recentAccounts.length) {
|
|
225
|
+
useRecent = false;
|
|
226
|
+
await focusAccount();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function createAccount() {
|
|
230
|
+
if (!signup || busy) return;
|
|
231
|
+
busy = true;
|
|
232
|
+
error = '';
|
|
233
|
+
try {
|
|
234
|
+
await signup();
|
|
235
|
+
} catch (caught) {
|
|
236
|
+
if (alive)
|
|
237
|
+
error =
|
|
238
|
+
caught instanceof Error
|
|
239
|
+
? caught.message
|
|
240
|
+
: 'Could not open account creation. Please try again.';
|
|
241
|
+
} finally {
|
|
242
|
+
if (alive) busy = false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
</script>
|
|
246
|
+
|
|
247
|
+
<form
|
|
248
|
+
{...rest}
|
|
249
|
+
bind:this={ref}
|
|
250
|
+
aria-label={rest['aria-label'] ?? headingText}
|
|
251
|
+
aria-busy={busy}
|
|
252
|
+
class={cn('grid w-full min-w-0 gap-4 text-ink', className)}
|
|
253
|
+
data-slot="login-form"
|
|
254
|
+
novalidate
|
|
255
|
+
onsubmit={(event) => {
|
|
256
|
+
event.preventDefault();
|
|
257
|
+
if (step === 'permissions' && pending) void authenticate(pending);
|
|
258
|
+
else if (step === 'login') void beginLogin();
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{#if showHeader}<header class="grid gap-2">
|
|
262
|
+
<Heading
|
|
263
|
+
level={2}
|
|
264
|
+
bind:ref={heading}
|
|
265
|
+
tabindex={step === 'login' ? undefined : -1}
|
|
266
|
+
class="text-[1.375rem] leading-snug tracking-tight outline-none">{headingText}</Heading
|
|
267
|
+
>
|
|
268
|
+
{#if descriptionText}<p class="text-[.8125rem] leading-relaxed text-muted">
|
|
269
|
+
{descriptionText}
|
|
270
|
+
</p>{/if}
|
|
271
|
+
</header>{/if}
|
|
272
|
+
{#if step === 'login'}
|
|
273
|
+
{#if showApps}<AtmosphereApps />{/if}
|
|
274
|
+
{#if showRecent}
|
|
275
|
+
<RecentAccounts
|
|
276
|
+
accounts={recentAccounts}
|
|
277
|
+
disabled={busy}
|
|
278
|
+
onSelect={(actor) => select(actor, true)}
|
|
279
|
+
onRemove={removeRecent}
|
|
280
|
+
/>
|
|
281
|
+
<Button
|
|
282
|
+
variant="secondary"
|
|
283
|
+
disabled={busy}
|
|
284
|
+
class="w-full"
|
|
285
|
+
onclick={() => {
|
|
286
|
+
useRecent = false;
|
|
287
|
+
void focusAccount();
|
|
288
|
+
}}>Use another handle</Button
|
|
289
|
+
>
|
|
290
|
+
{:else}
|
|
291
|
+
{#if selected}<div
|
|
292
|
+
class="flex min-h-15 items-center gap-3 rounded-ui border border-line bg-field py-2 pr-2 pl-3"
|
|
293
|
+
data-slot="selected-account"
|
|
294
|
+
>
|
|
295
|
+
<Avatar
|
|
296
|
+
name={actorName(selected)}
|
|
297
|
+
src={selected.avatar}
|
|
298
|
+
size={34}
|
|
299
|
+
aria-hidden="true"
|
|
300
|
+
/><span class="grid min-w-0 flex-1 gap-0.5"
|
|
301
|
+
><strong class="truncate text-[.8125rem] font-medium">{actorName(selected)}</strong
|
|
302
|
+
>{#if selected.displayName}<span class="truncate text-xs text-muted"
|
|
303
|
+
>@{selected.handle}</span
|
|
304
|
+
>{/if}</span
|
|
305
|
+
><IconButton
|
|
306
|
+
label={`Clear @${selected.handle}`}
|
|
307
|
+
size="sm"
|
|
308
|
+
disabled={busy}
|
|
309
|
+
onclick={() => {
|
|
310
|
+
selected = undefined;
|
|
311
|
+
value = '';
|
|
312
|
+
error = '';
|
|
313
|
+
void focusAccount();
|
|
314
|
+
}}><Icon img={X} size={17} /></IconButton
|
|
315
|
+
>
|
|
316
|
+
</div>
|
|
317
|
+
{:else}<div class="space-y-2">
|
|
318
|
+
<Label for={`${uid}-handle`} class="sr-only">Your handle</Label><ActorSearchField
|
|
319
|
+
id={`${uid}-handle`}
|
|
320
|
+
bind:value
|
|
321
|
+
bind:ref={input}
|
|
322
|
+
{searchActors}
|
|
323
|
+
onSelect={select}
|
|
324
|
+
disabled={busy}
|
|
325
|
+
invalid={!!error}
|
|
326
|
+
describedby={error ? `${uid}-error` : undefined}
|
|
327
|
+
class={error ? 'red' : undefined}
|
|
328
|
+
/>
|
|
329
|
+
</div>{/if}
|
|
330
|
+
{@render children?.()}
|
|
331
|
+
<Button bind:ref={submitRef} type="submit" loading={busy} class="w-full"
|
|
332
|
+
>{busy ? 'Logging in…' : 'Log in'}{#if !busy}<Icon
|
|
333
|
+
img={ArrowRight}
|
|
334
|
+
size={17}
|
|
335
|
+
/>{/if}</Button
|
|
336
|
+
>
|
|
337
|
+
{/if}
|
|
338
|
+
{#if signup}<div class="grid gap-3 border-t border-line pt-4">
|
|
339
|
+
<p class="text-[.8125rem] text-muted">Don't have an account?</p>
|
|
340
|
+
<Button
|
|
341
|
+
variant="secondary"
|
|
342
|
+
disabled={busy}
|
|
343
|
+
class="w-full"
|
|
344
|
+
onclick={() => changeStep('signup')}>Sign up</Button
|
|
345
|
+
>
|
|
346
|
+
</div>{/if}
|
|
347
|
+
{:else if step === 'permissions'}
|
|
348
|
+
{#if pending}<div class="flex items-center gap-3">
|
|
349
|
+
{#if pending.actor}<Avatar
|
|
350
|
+
name={actorName(pending.actor)}
|
|
351
|
+
src={pending.actor.avatar}
|
|
352
|
+
size={32}
|
|
353
|
+
aria-hidden="true"
|
|
354
|
+
/>{/if}
|
|
355
|
+
<p class="min-w-0 truncate text-xs text-muted">Logging in as @{pending.handle}</p>
|
|
356
|
+
</div>{/if}
|
|
357
|
+
<fieldset class="grid min-w-0 gap-5 border-0 py-1" disabled={busy}>
|
|
358
|
+
<legend class="sr-only">Requested permissions</legend>
|
|
359
|
+
{#each permissions as permission, index (permission.id)}<div class="flex items-start gap-3">
|
|
360
|
+
<Icon img={permission.icon ?? ShieldCheck} size={20} class="mt-1 shrink-0 text-muted" />
|
|
361
|
+
<div class="min-w-0 flex-1 space-y-1.5">
|
|
362
|
+
<Label for={`${uid}-permission-${index}`} class="leading-snug"
|
|
363
|
+
>{permission.label}{permission.required ? ' (required)' : ''}</Label
|
|
364
|
+
>
|
|
365
|
+
<p
|
|
366
|
+
id={`${uid}-permission-${index}-description`}
|
|
367
|
+
class="text-xs leading-relaxed text-muted"
|
|
368
|
+
>
|
|
369
|
+
{permission.description}
|
|
370
|
+
</p>
|
|
371
|
+
</div>
|
|
372
|
+
<Checkbox
|
|
373
|
+
id={`${uid}-permission-${index}`}
|
|
374
|
+
class="mt-1"
|
|
375
|
+
checked={isPermissionSelected(permission, choices)}
|
|
376
|
+
disabled={busy || permission.required}
|
|
377
|
+
aria-describedby={`${uid}-permission-${index}-description`}
|
|
378
|
+
onchange={(event) =>
|
|
379
|
+
(choices = { ...choices, [permission.id]: event.currentTarget.checked })}
|
|
380
|
+
/>
|
|
381
|
+
</div>{/each}
|
|
382
|
+
</fieldset>
|
|
383
|
+
<Button type="submit" bind:ref={submitRef} loading={busy} class="w-full"
|
|
384
|
+
>{busy ? 'Logging in…' : 'Continue to log in'}</Button
|
|
385
|
+
><Button variant="secondary" disabled={busy} class="w-full" onclick={() => changeStep('login')}
|
|
386
|
+
>Back to log in</Button
|
|
387
|
+
>
|
|
388
|
+
{:else}
|
|
389
|
+
<Button loading={busy} class="w-full" onclick={createAccount}>Continue to sign up</Button
|
|
390
|
+
><Button variant="secondary" disabled={busy} class="w-full" onclick={() => changeStep('login')}
|
|
391
|
+
>Back to log in</Button
|
|
392
|
+
>
|
|
393
|
+
{/if}
|
|
394
|
+
{#if error}<p
|
|
395
|
+
id={`${uid}-error`}
|
|
396
|
+
role="alert"
|
|
397
|
+
class="red flex items-start gap-2 text-xs leading-relaxed text-action"
|
|
398
|
+
>
|
|
399
|
+
<Icon img={TriangleAlert} size={16} class="mt-0.5 shrink-0" />{error}
|
|
400
|
+
</p>{/if}
|
|
401
|
+
{@render footer?.(step)}
|
|
402
|
+
</form>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLFormAttributes } from 'svelte/elements';
|
|
3
|
+
import type { ActorSearch, ActorSummary, LoginCallback, LoginResult, LoginPermission, LoginStep } from './types.js';
|
|
4
|
+
import type { RecentAccountStorageOptions } from './recent-accounts.js';
|
|
5
|
+
export type LoginFormProps = Omit<HTMLFormAttributes, 'children' | 'onsubmit' | 'action' | 'method' | 'title'> & {
|
|
6
|
+
login: LoginCallback;
|
|
7
|
+
signup?: () => LoginResult | Promise<LoginResult>;
|
|
8
|
+
searchActors?: ActorSearch;
|
|
9
|
+
initialHandle?: string;
|
|
10
|
+
loginOnSelect?: boolean;
|
|
11
|
+
recentAccounts?: ActorSummary[];
|
|
12
|
+
persistRecentAccounts?: boolean;
|
|
13
|
+
recentAccountOptions?: RecentAccountStorageOptions;
|
|
14
|
+
permissions?: readonly LoginPermission[];
|
|
15
|
+
baseScopes?: readonly string[];
|
|
16
|
+
title?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
showHeader?: boolean;
|
|
19
|
+
showApps?: boolean;
|
|
20
|
+
onSuccess?: (handle: string, actor?: ActorSummary) => void;
|
|
21
|
+
onStepChange?: (step: LoginStep) => void;
|
|
22
|
+
children?: Snippet;
|
|
23
|
+
footer?: Snippet<[LoginStep]>;
|
|
24
|
+
ref?: HTMLFormElement | null;
|
|
25
|
+
};
|
|
26
|
+
declare const LoginForm: import("svelte").Component<LoginFormProps, {}, "ref" | "recentAccounts">;
|
|
27
|
+
type LoginForm = ReturnType<typeof LoginForm>;
|
|
28
|
+
export default LoginForm;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick } from 'svelte';
|
|
3
|
+
import type { ActorSummary } from './types.js';
|
|
4
|
+
import { actorName } from './types.js';
|
|
5
|
+
import Avatar from '../Avatar.svelte';
|
|
6
|
+
import Button from '../Button.svelte';
|
|
7
|
+
import IconButton from '../IconButton.svelte';
|
|
8
|
+
import Icon from '../Icon.svelte';
|
|
9
|
+
import { X, ArrowRight } from '@sketchyicons/svelte';
|
|
10
|
+
let {
|
|
11
|
+
accounts,
|
|
12
|
+
disabled = false,
|
|
13
|
+
onSelect,
|
|
14
|
+
onRemove
|
|
15
|
+
}: {
|
|
16
|
+
accounts: readonly ActorSummary[];
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
onSelect: (actor: ActorSummary) => void;
|
|
19
|
+
onRemove?: (actor: ActorSummary) => void;
|
|
20
|
+
} = $props();
|
|
21
|
+
let root: HTMLDivElement;
|
|
22
|
+
async function remove(actor: ActorSummary, index: number) {
|
|
23
|
+
onRemove?.(actor);
|
|
24
|
+
await tick();
|
|
25
|
+
const buttons = root?.querySelectorAll<HTMLButtonElement>('[data-account]');
|
|
26
|
+
buttons?.[Math.min(index, buttons.length - 1)]?.focus();
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<div class="grid gap-2" bind:this={root} aria-label="Recent accounts">
|
|
31
|
+
{#each accounts as actor, index (actor.did)}<div
|
|
32
|
+
class="flex min-w-0 items-center gap-1 rounded-ui border border-line bg-field"
|
|
33
|
+
>
|
|
34
|
+
<Button
|
|
35
|
+
data-account
|
|
36
|
+
data-autofocus={index === 0 ? true : undefined}
|
|
37
|
+
variant="ghost"
|
|
38
|
+
{disabled}
|
|
39
|
+
class="min-h-16 min-w-0 flex-1 justify-start gap-3 px-3 py-2 text-left"
|
|
40
|
+
onclick={() => onSelect(actor)}
|
|
41
|
+
>
|
|
42
|
+
<Avatar name={actorName(actor)} src={actor.avatar} size={34} aria-hidden="true" />
|
|
43
|
+
<span class="grid min-w-0 flex-1 gap-0.5"
|
|
44
|
+
><strong class="truncate text-[.8125rem] font-medium text-ink">{actorName(actor)}</strong
|
|
45
|
+
>{#if actor.displayName}<span class="truncate text-xs text-muted">@{actor.handle}</span
|
|
46
|
+
>{/if}</span
|
|
47
|
+
><Icon img={ArrowRight} size={16} />
|
|
48
|
+
</Button>
|
|
49
|
+
{#if onRemove}<IconButton
|
|
50
|
+
label={`Forget @${actor.handle}`}
|
|
51
|
+
{disabled}
|
|
52
|
+
size="sm"
|
|
53
|
+
class="mr-1.5"
|
|
54
|
+
onclick={() => remove(actor, index)}><Icon img={X} size={16} /></IconButton
|
|
55
|
+
>{/if}
|
|
56
|
+
</div>{/each}
|
|
57
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ActorSummary } from './types.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
accounts: readonly ActorSummary[];
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
onSelect: (actor: ActorSummary) => void;
|
|
6
|
+
onRemove?: (actor: ActorSummary) => void;
|
|
7
|
+
};
|
|
8
|
+
declare const RecentAccounts: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type RecentAccounts = ReturnType<typeof RecentAccounts>;
|
|
10
|
+
export default RecentAccounts;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Atmosphere brand marks
|
|
2
|
+
|
|
3
|
+
Bluesky, Blacksky, Graze, Leaflet, Tangled, BookHive, Surf, and Pckt marks were copied from Florian’s existing Atmo UI login assets (`11-atmo-ui/codebase/src/lib/login/icons/`). The login implementation is covered by the package's root MIT `LICENSE`, which retains the original copyright notice.
|
|
4
|
+
|
|
5
|
+
Brand marks remain the property of their respective owners; the source-code license is not a grant of trademark rights. They are used only as decorative examples of compatible Atmosphere services, not to imply endorsement. Surf’s opaque background rectangle was removed so the existing mark can render transparently like its neighbors. The other geometry is unchanged.
|
|
6
|
+
|
|
7
|
+
`AtmosphereApps.svelte` renders these as a static, monochrome, decorative row. Set `showApps={false}` to omit it. Interactive controls and permission icons use Sketchyicons instead.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M33.4007 30.251V37.2108C33.4007 40.3527 35.9477 42.8997 39.0896 42.8997H46.05V45.8872H39.0896C35.9477 45.8872 33.4008 48.4342 33.4007 51.576V58.5365H30.4132V51.576C30.4131 48.4344 27.866 45.8873 24.7243 45.8872H17.7639V42.8997H24.7243C27.866 42.8995 30.4132 40.3525 30.4132 37.2108V30.2504L33.4007 30.251ZM19.65 15.2004L17.9292 21.9448C17.1524 24.9891 18.9905 28.0867 22.0347 28.8635L28.7792 30.5844L28.0403 33.4795L21.2965 31.7587C18.2522 30.9819 15.1539 32.8199 14.3771 35.8642L12.6562 42.6087L9.7618 41.8698L11.4826 35.1254C12.2593 32.0811 10.4213 28.9835 7.37707 28.2066L0.632629 26.4858L1.37152 23.5913L8.11527 25.3122C11.1596 26.089 14.2572 24.2503 15.034 21.2059L16.7549 14.4629L19.65 15.2004ZM48.9653 21.2059C49.7421 24.2502 52.8397 26.0889 55.884 25.3122L62.6285 23.5913L63.3674 26.4858L56.6229 28.2066C53.5786 28.9834 51.74 32.0811 52.5167 35.1254L54.2382 41.8698L51.343 42.6087L49.6222 35.8642C48.8454 32.8199 45.7478 30.9819 42.7035 31.7587L35.959 33.4795L35.2208 30.5844L41.9646 28.8635C45.0089 28.0867 46.8476 24.9891 46.0708 21.9448L44.3493 15.2004L47.2444 14.4629L48.9653 21.2059ZM42.9639 7.57605L38.0417 12.4976C35.8202 14.7192 35.8202 18.3211 38.0417 20.5427L42.9639 25.4642L40.8514 27.5767L35.9292 22.6552C33.7075 20.4337 30.1056 20.4336 27.884 22.6552L22.9625 27.5767L20.85 25.4642L25.7715 20.5427C27.9931 18.3211 27.9931 14.7192 25.7715 12.4976L20.85 7.57605L22.9625 5.46355L27.884 10.3851C30.1056 12.6067 33.7075 12.6066 35.9292 10.3851L40.8514 5.46355L42.9639 7.57605Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M14.6366 7.81116C21.8491 13.3459 29.607 24.5681 32.4553 30.5905C35.3038 24.5685 43.0612 13.3458 50.2739 7.81116C55.4781 3.81752 63.9102 0.727462 63.9102 10.5602C63.9102 12.5239 62.8087 27.0565 62.1627 29.4158C59.9171 37.6184 51.7344 39.7106 44.4557 38.4443C57.1787 40.6577 60.4153 47.9893 53.4255 55.3209C40.1504 69.2451 34.3454 51.8273 32.8572 47.3642C32.4543 46.1554 32.4558 46.1554 32.0529 47.3642C30.5654 51.8273 24.7605 69.2455 11.4847 55.3209C4.49475 47.9893 7.73124 40.6573 20.4544 38.4443C13.1755 39.7106 4.99271 37.6184 2.74748 29.4158C2.10144 27.0563 1 12.5237 1 10.5602C1 0.727462 9.43267 3.81752 14.6366 7.81116Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M52.0483 0.93099C53.1501 0.921438 53.8535 1.06037 54.7446 1.75893C55.4873 2.51347 56.0296 3.42362 56.0224 4.50009C56.0668 18.0153 55.9707 31.5308 56.0122 45.0458C56.0104 47.5675 54.4686 47.3201 54.4661 47.3197C54.4917 50.3233 54.4674 53.3311 54.5447 56.3337C54.5377 57.548 54.2466 58.5049 52.4863 58.5064L25.7792 58.5727C25.5946 58.5638 25.5946 58.5638 25.5037 58.6744C25.4938 58.9353 25.556 61.6779 25.5561 61.6808C25.5465 62.144 25.5531 62.9893 24.5112 63C22.8066 63.0173 21.1565 60.7507 20.2706 60.7471C19.5918 60.7443 17.8008 63.0001 15.9265 62.9913C15.4985 62.9893 15.1922 62.6836 15.0376 62.3692C14.9527 62.0605 14.9636 61.7672 14.9759 61.4491C14.9864 60.4343 15.009 59.4184 15.0376 58.404L14.8658 58.4065C13.433 58.4097 7.98682 58.5339 7.98736 52.2753C7.9386 37.3459 7.96021 22.4163 7.93185 7.48695C7.91841 0.890681 13.5317 0.96174 14.244 0.963904L14.2441 0.963816C26.8455 0.919962 39.4471 1.04933 52.0483 0.93099ZM17.2031 59.9361C18.0694 59.417 18.9226 58.7165 19.8728 58.3675C20.4465 58.2263 20.8562 58.4527 21.3546 58.7478C21.6127 58.9016 23.0463 59.846 23.3384 60.0262V52.8169H17.2031V59.9361ZM15.4946 47.828C14.4598 47.8221 13.5842 47.8236 12.6684 48.3886C11.3934 49.2216 10.5772 50.4986 10.5146 52.0667C10.5581 55.439 12.7708 56.2239 14.2018 56.2472C14.4503 56.2452 14.6988 56.2438 14.9473 56.2413C14.9699 54.7203 14.992 53.1994 15.0191 51.6785C15.0259 51.2477 15.0446 51.1028 15.3475 50.7816C15.661 50.5291 15.9258 50.5093 16.3203 50.5029C18.8985 50.5305 21.4781 50.5048 24.0565 50.5057C24.4337 50.5016 24.7923 50.479 25.1362 50.6507C25.3693 50.8243 25.4919 50.9727 25.5717 51.2522L25.5841 55.4208C25.5834 55.6761 25.5701 55.8331 25.6842 56.061C25.8799 56.1848 26.0249 56.2391 26.256 56.2636C34.8173 56.2573 43.3785 56.2521 51.9398 56.2413V56.061C50.6253 53.3866 50.8985 50.5477 51.9398 47.8604C47.2275 47.8544 16.0841 47.8265 15.4946 47.828ZM13.3397 3.28933C12.4325 3.36836 10.0574 3.73972 10.1655 7.98162C10.1696 8.15242 10.2369 41.5329 10.2557 47.3197V47.4099C11.1579 46.5988 11.6431 46.0768 13.2331 45.7878C13.2331 30.2549 13.3397 17.9797 13.3397 3.28933ZM50.3365 3.15107C48.4414 3.15161 17.5151 3.18598 15.5332 3.25861L15.5516 45.7417C21.1475 45.811 50.6824 45.7303 51.4888 45.6977C53.3652 45.6221 53.7518 45.0956 53.7449 43.0277C53.7162 34.341 53.665 9.58593 53.6781 6.36745C53.6894 3.60523 53.4421 3.15009 50.3365 3.15107ZM29.9248 4.69475C30.8644 4.69476 31.6539 5.51957 31.5369 6.46232C32.4026 7.41817 33.0369 8.63188 33.5401 9.78791C33.6893 10.1309 33.8146 10.4575 33.99 10.7738C34.5922 10.398 37.7986 10.5099 38.1152 10.8594L38.1807 10.4479C38.4829 9.04123 39.2361 7.92084 40.3014 7.08591C40.2725 6.14568 41.1018 5.41571 42.015 5.41568C42.9618 5.41569 43.7293 6.14192 43.7293 7.03778C43.7293 8.19237 42.4891 8.91219 41.4507 8.56984C40.8876 8.99859 40.7576 9.09367 40.1033 10.6914C40.0479 10.8267 39.9062 11.0117 40.043 11.094C45.13 14.151 45.7123 16.9707 45.7682 20.076L45.9645 20.0541C49.3503 19.1903 51.9897 19.8251 52.4776 22.7094C52.5577 23.7237 52.3694 24.602 51.9236 25.506C50.8378 27.5413 46.4796 30.5203 44.1957 29.951L44.2067 30.3422C43.9504 46.0599 29.3295 40.2729 29.3091 40.2648C29.3009 40.27 27.3183 41.5417 26.9916 41.4083C26.6049 41.336 27.4322 39.6021 27.5268 39.2773L27.3114 39.0357C24.4702 37.2377 23.9692 34.9197 23.8575 32.8038L23.6004 32.9106C17.0555 35.3729 18.0353 26.8788 21.5512 26.001L21.3218 25.7609C11.2829 15.4735 20.5036 10.6607 27.422 16.7844C27.4229 16.7794 28.1502 12.7938 32.0348 11.2983C31.5022 10.0545 30.8877 8.99646 30.2278 7.82128C29.2712 7.99657 28.3007 7.27154 28.3007 6.27179C28.3007 5.40083 29.0279 4.69477 29.9248 4.69475ZM26.8979 30.0607C23.5884 38.2578 40.4533 43.2877 41.8894 33.6816C39.6793 34.3829 31.953 36.0684 27.0351 30.2549L26.8979 30.0607ZM24.7736 27.2341C23.3243 26.9989 22.1689 27.7022 22.0472 27.765C20.2551 28.6908 19.4806 33.3183 23.2802 31.4185C23.8598 31.217 23.9631 30.0229 24.2466 29.456C24.3874 29.1715 25.036 27.8224 25.4301 27.3177C25.1065 27.2496 25.0382 27.277 24.7736 27.2341ZM30.2526 25.3427C28.9557 25.9328 28.2918 27.8003 28.2906 27.8038C28.3011 27.8227 31.6274 33.7806 41.8894 30.7191C42.0919 29.6972 41.7578 27.5658 41.1546 27.118C35.5948 28.8958 31.9491 27.1244 30.2526 25.3427ZM50.8069 22.1813C48.742 19.9078 45.4885 22.4437 45.2873 22.7107C44.95 24.1274 43.9692 25.058 43.0228 25.8091C42.8865 25.905 42.7532 26.0057 42.6231 26.1107C42.6232 26.3302 43.7375 28.4638 43.929 28.7153C43.9383 28.715 46.1981 28.6274 48.7523 26.4433C48.7653 26.4318 52.0258 23.5235 50.8069 22.1813ZM41.2457 14.5195C37.3692 10.7942 29.9837 12.9105 29.3624 17.939C29.1447 19.7002 29.6713 21.3039 30.672 22.7094L30.8816 22.9289C31.7128 23.8894 32.8151 24.6313 33.962 25.1032C36.2257 25.8783 38.5669 25.7495 40.7078 24.6468C42.1238 23.8195 43.0442 22.8138 43.579 20.8295C44.1959 16.7171 41.61 14.833 41.2457 14.5195ZM23.8765 16.9841C18.1211 13.6901 16.1166 20.3808 25.4116 24.9413C25.4169 24.9451 26.4861 25.7192 27.5192 25.2656C28.0798 24.9605 28.6565 24.5529 28.8896 23.9164C28.0922 22.8984 27.4276 21.8552 27.232 20.5424C27.1994 20.2719 27.1609 20.0146 27.1075 19.7469C26.4768 18.4447 24.9091 17.5788 23.8765 16.9841ZM36.6935 22.4214C36.1914 21.7363 37.1875 21.1485 37.4735 21.7041C37.7164 22.176 38.2534 22.4599 38.7605 22.4398C39.307 22.4181 39.7609 22.1519 40.0795 21.7229C40.3222 21.3958 41.1377 21.8847 40.8264 22.341C39.8869 23.718 37.5936 23.6497 36.6935 22.4214ZM36.4843 17.9797C37.0215 17.9797 37.457 18.5762 37.457 19.312C37.457 20.0478 37.0215 20.6442 36.4843 20.6443C35.9471 20.6443 35.5115 20.0478 35.5115 19.312C35.5115 18.5762 35.9471 17.9797 36.4843 17.9797ZM40.77 17.9797C41.2324 17.9797 41.6074 18.5359 41.6074 19.2219C41.6074 19.9079 41.2324 20.464 40.77 20.464C40.3075 20.464 39.9326 19.9079 39.9326 19.2219C39.9326 18.5359 40.3075 17.9797 40.77 17.9797Z" fill="#210E03"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M45.7619 7.87587C60.1702 10.6391 63.4775 22.3307 63.4775 27.9181H36.1258C36.1258 27.5617 35.364 26.8039 32.9584 26.9237C29.966 27.0728 28.9088 29.7137 28.9088 32.4192C28.9088 35.1247 29.1685 37.4479 30.3502 38.2959C31.6616 39.237 32.8425 39.2668 34.2072 39.129C36.0651 38.9415 36.654 37.7064 36.7601 37.0344H30.7655V29.7137H63.4775V56.026H38.5107L37.6353 41.2621C37.6805 42.5161 36.6411 47.4777 35.5375 49.4641C33.5007 53.1304 31.2195 57.7008 18.1616 57.3492C2.86694 56.9373 0.522465 43.9029 0.522461 36.2991C0.522456 26.9237 1.96649 21.2534 7.07669 15.5318C14.7563 6.93337 30.7655 4.99983 45.7619 7.87587Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M47.1477 0.845986C48.4137 0.811044 50.6635 0.97768 52.1135 2.96513C52.3836 3.33523 52.5782 3.71105 52.72 4.06767C53.7645 3.97079 55.2184 3.84808 56.5706 3.9622C57.8708 4.07194 60.4995 4.49573 62.0325 6.9202C63.3831 9.05643 63.0424 11.2398 62.3821 12.7259C62.0015 13.5824 61.4495 14.3592 61.0149 14.9173C61.4813 15.3251 62.007 15.8782 62.4202 16.5804C63.4141 18.2695 63.4603 20.1398 63.0178 21.9065C62.2415 25.006 59.6512 26.3588 58.0745 26.9641C56.4535 27.5865 54.5555 27.9267 53.138 28.1809C53.0826 28.1909 53.0277 28.2006 52.9739 28.2102C52.8617 28.2304 52.7524 28.2505 52.6458 28.2698C52.994 29.4787 52.9193 30.7579 52.5159 31.9759C51.3992 35.3469 48.8535 36.9475 46.4329 37.6233C44.3585 38.2024 42.038 38.2006 40.3889 38.1995H39.7971C40.2081 39.8678 39.7384 41.5108 39.2756 42.6233C37.5661 46.7333 33.6992 48.2682 30.5745 48.9173C27.4514 49.566 23.8296 49.5859 20.8235 49.6028L20.6165 49.6048C18.9682 49.6143 17.5063 49.6244 16.2278 49.6956C15.0926 51.8854 14.1546 54.3171 13.0667 57.1585L13.0637 57.1653C12.778 57.9114 12.4819 58.6839 12.1751 59.4681C10.9629 62.5654 7.53377 64.0676 4.51588 62.8235C1.49818 61.5794 0.0343291 58.0604 1.24635 54.9632C2.79896 50.9959 4.40634 48.2307 6.55104 43.9798C7.12736 42.8375 7.61458 41.918 8.0403 41.0618C8.0403 38.4802 8.22871 36.6558 8.59987 34.344C9.22395 30.4568 9.74958 28.9618 10.5198 25.4163C11.2283 22.9658 12.2688 19.6743 13.9046 17.8626C14.8446 16.8215 16.2978 15.2998 18.4846 15.1956C19.8116 15.1326 20.6411 16.2275 21.3421 16.6956C23.3761 13.8707 25.0979 10.1107 27.3215 7.18974C29.1054 4.84653 31.0244 2.79935 34.1223 3.28935C35.7179 3.54171 37.9874 4.77215 37.9876 7.18974C38.5787 6.51509 40.385 3.92331 41.1438 3.28935C42.5899 2.08134 44.5901 0.916609 47.1477 0.845986ZM46.5188 2.87333C43.74 2.95003 41.783 5.37595 40.1399 7.41239C38.9504 8.88662 37.9246 10.157 36.8713 10.1849C35.8379 10.212 35.9145 9.50097 36.012 8.60087C36.1511 7.3172 36.3322 5.64751 33.3948 5.1829C30.9596 4.79776 28.3907 9.42128 26.1604 13.4358C24.6347 16.1823 23.2674 18.6439 22.2092 19.0218C20.5909 19.5996 19.8405 18.9231 19.2005 18.346C18.4269 17.6485 17.8135 17.0961 16.0227 19.0794C14.1363 21.1687 12.8496 26.8812 11.6028 33.1058C11.4434 33.9014 12.5506 34.4155 13.0569 33.7913C15.9279 30.2496 20.5931 25.3779 26.1604 21.7757C31.2791 18.4638 36.2177 15.1777 41.804 13.5208C42.6271 13.2767 42.861 14.2224 42.0725 14.5667C35.7739 17.317 30.3617 20.9421 24.6946 25.7845C18.3256 31.1069 12.3027 38.1916 9.24733 43.9661C7.37512 47.1673 5.66312 50.6552 4.17897 54.4475C3.78072 55.4656 4.2614 56.6225 5.25319 57.0315C6.24528 57.4405 7.37326 56.9462 7.77174 55.928C8.07314 55.1579 8.36431 54.3971 8.65162 53.6468C9.9596 50.2308 11.1854 47.0281 12.9143 44.1165C13.0267 43.9272 13.2174 43.8009 13.4319 43.7747C15.3108 43.5455 17.5457 43.5331 19.8587 43.5198C26.1668 43.4835 33.0575 43.4433 34.9046 39.0022C35.8695 36.6819 34.7053 36.3487 33.6546 36.0481C32.7961 35.8026 32.0136 35.5786 32.5305 34.3108C33.4259 32.115 36.3462 32.1146 39.4407 32.1145C43.0459 32.1145 46.8871 32.1143 48.0374 28.6419C48.5293 27.1566 47.652 26.5729 46.8743 26.0559C46.2236 25.6234 45.6426 25.2374 45.9924 24.4085C46.5507 23.0863 48.9821 22.6496 51.5569 22.1868C54.6304 21.6344 57.9094 21.0445 58.4544 18.8684C58.9697 16.8107 58.0095 16.1463 57.0169 15.4593C56.4098 15.0391 55.7902 14.6096 55.4885 13.8489C55.1192 12.9167 55.9275 11.9187 56.7669 10.8831C57.758 9.66019 58.7923 8.38457 57.9807 7.10087C57.0575 5.64067 54.3027 5.89748 52.0237 6.10966C50.6025 6.24197 49.3661 6.35688 48.8743 6.02763C48.3752 5.69324 48.3953 5.1263 48.4153 4.56474C48.4467 3.6861 48.4776 2.81938 46.5188 2.87333Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M35.041 0.551758C41.0481 0.551758 46.1485 2.56568 49.6504 6.89062C49.9931 7.31394 50.315 7.75525 50.6191 8.21191C52.0141 9.12394 53.2734 10.2549 54.374 11.6143C57.7728 15.8123 59.2539 21.686 59.2539 28.6182C59.2539 34.128 58.3166 38.9766 56.2295 42.8506C56.4406 42.9955 56.6442 43.1574 56.8379 43.3359C57.7639 44.1892 58.3014 45.2583 58.6396 46.2061L58.6592 46.2617L58.6777 46.3184C59.1151 47.6862 59.4065 49.6752 58.2637 51.5166C58.0281 51.8961 57.7581 52.2242 57.4668 52.5088C57.5285 52.8965 57.5506 53.3054 57.5186 53.7344C57.3557 55.9063 55.9375 57.3619 54.7139 58.2334L54.7119 58.2344C53.8016 58.8816 52.5028 59.5937 50.8721 59.5938C49.9274 59.5937 49.1175 59.3627 48.4287 58.998C47.7315 59.3642 46.9174 59.5937 45.9766 59.5938C44.4174 59.5936 43.0831 58.8815 42.1729 58.2344L42.1309 58.2051C41.1221 57.4655 39.9085 56.2837 39.4883 54.5723C38.6863 54.3051 37.992 53.8976 37.4492 53.5117L37.4082 53.4814C36.7851 53.0245 36.0834 52.3989 35.5391 51.584C35.046 51.4755 34.562 51.3494 34.0879 51.2041V57.6387C34.0878 58.9405 33.7583 60.5905 32.4424 61.874C31.1432 63.1415 29.4987 63.4482 28.2021 63.4482H15.2793C13.9776 63.4482 12.3507 63.1196 11.0742 61.8438C10.1137 60.8831 9.68988 59.724 9.53906 58.6543C8.46977 58.5034 7.31092 58.0804 6.35059 57.1201C5.07429 55.8437 4.74614 54.2167 4.74609 52.915V7.11719C4.74612 5.81551 5.0743 4.18856 6.35059 2.91211C7.62704 1.6358 9.25396 1.30765 10.5557 1.30762H23.4785C24.5331 1.30762 25.8013 1.51075 26.9316 2.24512C29.3473 1.12897 32.0767 0.551852 35.041 0.551758ZM35.042 4.09473C31.3391 4.09478 28.2406 5.15272 25.8223 7.04199C25.8223 5.6062 25.0663 4.85071 23.4795 4.85059H10.5566C9.04529 4.85062 8.28912 5.60588 8.28906 7.11719V52.915C8.28916 54.4263 9.04532 55.1826 10.5566 55.1826H23.4795C25.0662 55.1825 25.8221 54.4262 25.8223 52.915V40.748C28.2744 42.6057 31.3111 43.7313 34.8604 43.7686C34.8793 43.2064 35.0046 42.6497 35.1836 42.1309C35.4462 41.3085 35.8431 40.5051 36.4932 39.8975C37.2067 39.2308 38.0825 38.9316 39.0029 38.9316C39.1289 38.9317 39.2559 38.9399 39.3828 38.9521C39.5147 38.3741 39.7651 37.8161 40.1914 37.3271C41.1123 36.2713 42.4587 35.9775 43.7197 35.9775C44.9652 35.9776 46.3153 36.2726 47.2314 37.334C47.36 37.4829 47.4701 37.6399 47.5674 37.7998C49.8206 34.489 50.9883 29.8302 50.9883 23.8945C50.9882 10.896 45.3955 4.09476 35.042 4.09473ZM43.7188 37.749C41.6464 37.7491 40.8241 38.7341 41.0742 40.7393L41.2178 41.4775L40.5391 41.126C39.9673 40.8445 39.4308 40.7041 39.002 40.7041C37.9657 40.7041 37.2862 41.337 36.8574 42.709C36.2143 44.5733 36.9294 45.6637 38.9658 46.0156L39.7168 46.1211L39.1807 46.7197C37.7156 48.1269 37.8225 49.3937 39.502 50.625C40.145 51.0822 40.7527 51.328 41.2529 51.3281C42.0748 51.3281 42.7896 50.7653 43.3613 49.6748L43.7188 49.0059L44.0762 49.6748C44.6479 50.7654 45.3275 51.3281 46.1494 51.3281C46.721 51.328 47.2926 51.0821 47.9355 50.625C49.615 49.4289 49.687 48.1269 48.2578 46.6846L47.7568 46.1211L48.4717 46.0156C50.5443 45.6638 51.1876 44.5736 50.5801 42.6738C50.1155 41.3722 49.4365 40.7393 48.4717 40.7393C48.0072 40.7393 47.5069 40.8797 46.8994 41.1611L46.1846 41.4775L46.292 40.7393C46.6136 38.734 45.7556 37.749 43.7188 37.749ZM30.1348 17.3389C33.6879 17.3389 34.8583 19.9894 34.8584 24.4238C34.8583 28.8583 33.6879 31.5087 30.1348 31.5088C26.5815 31.5088 25.4112 28.8583 25.4111 24.4238C25.4112 19.9893 26.5815 17.3389 30.1348 17.3389Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M1.1106 63.1671H62.6904V56.7437C40.2089 56.7437 36.3543 49.0834 35.1047 41.8962C33.666 33.6213 37.5348 27.0374 40.0017 25.129C39.5828 27.5028 40.105 32.4311 42.5909 34.5793C45.5322 37.1212 57.6484 40.035 61.4916 29.3363C66.6581 14.9538 56.686 4.93859 44.9565 2.00622C33.227 -0.926145 23.0588 1.54355 12.8653 10.4803C4.71056 17.6297 1.1106 29.3363 1.1106 35.6587V63.1671Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M42.1942 62.2061C40.1132 62.1895 38.5255 61.5978 36.8033 60.5694C34.3336 59.2985 32.4473 57.1634 31.0995 54.8093C28.9577 57.4086 26.0952 58.9857 22.8906 59.8767C21.5261 60.2643 19.1362 60.6575 15.1747 59.2536C9.46554 57.3775 5.30684 51.5664 5.77946 45.6454C5.693 43.191 6.60783 40.782 7.90455 38.7112C4.44529 36.8949 1.6245 33.8461 0.544296 30.1071C-0.112146 28.0602 -0.084542 25.8552 0.157525 23.751C1.02443 18.7831 4.83393 14.4631 9.73824 12.9093C11.6958 8.54547 15.9676 5.29133 20.8073 4.62882C24.0207 4.1911 27.3471 4.84916 30.1583 6.44676C34.2544 2.00297 41.3903 0.689689 46.8391 3.41949C50.9955 5.36113 53.9678 9.41209 54.6894 13.8295C58.6443 15.3794 61.9754 18.5401 63.2827 22.5526C64.1568 25.0368 64.1857 27.7732 63.6196 30.324C62.6082 34.3042 59.7359 37.6927 56.0181 39.5447C56.0271 40.2531 58.4075 45.3603 58.0093 49.2145C57.9223 54.0331 54.798 58.5998 50.465 60.818C47.9366 62.2616 44.9403 62.2344 42.1942 62.2061ZM30.3466 48.3357C33.8511 47.9539 36.1485 44.9649 37.9329 42.273C38.7765 41.0468 39.4209 39.6743 40.0612 38.3689C40.8915 39.1134 41.5951 40.5159 42.9082 40.8499C44.2914 41.2713 45.9131 40.929 46.7599 39.6999C48.3805 36.7431 47.5817 33.1753 46.638 30.1112C46.0569 28.3514 45.2944 26.546 43.8436 25.2985C44.153 23.1635 42.8597 20.9952 41.0211 19.8776C39.4543 21.0998 37.0703 21.0924 35.5588 19.7851C32.6618 22.6753 30.0069 22.5794 27.4425 20.2888C26.8661 19.774 25.7664 23.431 21.907 21.3594C19.6898 23.1767 17.9705 24.9249 16.4471 27.4421C14.9668 30.1558 13.4166 32.5658 13.283 35.5127C13.2188 37.2351 14.5946 39.0397 16.4588 38.8996C18.3221 39.0624 19.5904 37.2686 21.0012 36.5235C21.2116 38.9272 21.4486 41.5098 22.279 43.8565C23.2322 46.8932 26.5893 48.8233 29.767 48.3813C29.9918 48.3642 30.3466 48.3354 30.3466 48.3357ZM32.1657 39.2678C30.4611 38.2458 31.2814 36.0279 31.2131 34.417C31.3827 32.4731 31.5188 30.4293 32.4122 28.6583C33.3577 27.3957 35.6635 27.8828 35.7653 29.5027C35.6975 31.1323 34.9328 32.7544 35.0242 34.4436C34.8258 35.8542 35.1678 37.4385 34.5299 38.7277C34.0066 39.4411 32.9406 39.6484 32.1657 39.2678ZM24.7212 38.3393C23.1157 37.4871 23.6258 35.343 23.3739 33.8523C23.5827 32.1264 23.4089 29.9371 24.8861 28.7268C26.3307 27.7413 28.297 29.4289 27.6138 30.9783C26.8852 32.9363 27.3627 35.0756 27.3781 37.061C27.1025 38.2321 25.822 38.8538 24.7212 38.3393Z" fill="black"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isHandle } from '@atcute/lexicons/syntax';
|
|
2
|
+
export const normalizeHandle = (value) => value.trim().replace(/^@+/, '').toLowerCase();
|
|
3
|
+
export const isValidHandle = (value) => isHandle(normalizeHandle(value));
|
|
4
|
+
export function handleError(value) {
|
|
5
|
+
const handle = normalizeHandle(value);
|
|
6
|
+
if (!handle)
|
|
7
|
+
return 'Enter your handle.';
|
|
8
|
+
if (!isHandle(handle))
|
|
9
|
+
return 'Enter a valid handle, such as alice.bsky.social.';
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { LoginOptions, LoginPermission } from './types.js';
|
|
2
|
+
export declare function isPermissionSelected(permission: LoginPermission, choices: Readonly<Record<string, boolean>>): boolean;
|
|
3
|
+
export declare function resolveLoginOptions(permissions: readonly LoginPermission[], choices: Readonly<Record<string, boolean>>, baseScopes?: readonly string[]): LoginOptions;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function isPermissionSelected(permission, choices) {
|
|
2
|
+
const choice = Object.hasOwn(choices, permission.id) ? choices[permission.id] : undefined;
|
|
3
|
+
return permission.required === true || (choice ?? permission.defaultSelected ?? true);
|
|
4
|
+
}
|
|
5
|
+
export function resolveLoginOptions(permissions, choices, baseScopes = ['atproto']) {
|
|
6
|
+
if (new Set(permissions.map((permission) => permission.id)).size !== permissions.length)
|
|
7
|
+
throw new Error('Permission IDs must be unique.');
|
|
8
|
+
const selected = permissions.filter((permission) => isPermissionSelected(permission, choices));
|
|
9
|
+
return {
|
|
10
|
+
permissionIds: selected.map((permission) => permission.id),
|
|
11
|
+
scopes: [...new Set([...baseScopes, ...selected.flatMap((permission) => permission.scopes)])]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ActorSummary } from './types.js';
|
|
2
|
+
export type RecentAccount = ActorSummary & {
|
|
3
|
+
lastUsedAt: string;
|
|
4
|
+
};
|
|
5
|
+
export type RecentAccountStorage = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;
|
|
6
|
+
export type RecentAccountStorageOptions = {
|
|
7
|
+
storage?: RecentAccountStorage | null;
|
|
8
|
+
key?: string;
|
|
9
|
+
max?: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const RECENT_ACCOUNTS_STORAGE_KEY = "atmo-kit:recent-accounts:v1";
|
|
12
|
+
export declare function recentAccountLimit(max?: number): number;
|
|
13
|
+
export declare function loadRecentAccounts({ storage, key, max }?: RecentAccountStorageOptions): RecentAccount[];
|
|
14
|
+
export declare function writeRecentAccounts(accounts: readonly ActorSummary[], { storage, key, max }?: RecentAccountStorageOptions): RecentAccount[];
|
|
15
|
+
export declare function saveRecentAccount(actor: ActorSummary, options?: RecentAccountStorageOptions): RecentAccount[];
|
|
16
|
+
export declare function removeRecentAccount(did: string, options?: RecentAccountStorageOptions): RecentAccount[];
|