forked from
tangled.org/core
Monorepo for Tangled
3.2 kB
106 lines
1<script lang="ts">
2 import { browser } from '$app/environment';
3 import { resolve } from '$app/paths';
4 import { page } from '$app/state';
5 import { getAuth } from '$lib/auth.svelte';
6 import Button from '$lib/components/ui/Button.svelte';
7 import CircleAlert from '$icon/circle-alert';
8 import { onMount } from 'svelte';
9 import { SvelteURL } from 'svelte/reactivity';
10
11 const appPath = (path: string) => resolve(path as '/');
12 const auth = getAuth();
13 const returnTo = $derived(page.url.searchParams.get('return_url') ?? '/');
14
15 let identifier = $state(page.url.searchParams.get('identifier') ?? '');
16 let isSubmitting = $state(false);
17
18 onMount(() => {
19 if (browser && location.hostname === 'localhost') {
20 const url = new SvelteURL(location.href);
21 url.hostname = '127.0.0.1';
22 location.replace(url);
23 }
24 });
25
26 const submit = async (event: SubmitEvent) => {
27 event.preventDefault();
28 isSubmitting = true;
29 try {
30 await auth.signIn(identifier, returnTo);
31 } finally {
32 isSubmitting = false;
33 }
34 };
35</script>
36
37<svelte:head>
38 <title>Login · Tangled</title>
39</svelte:head>
40
41<section class="w-full max-w-md">
42 <div class="mb-4 flex flex-col items-center">
43 <a href={appPath('/')} class="flex items-center gap-2 no-underline hover:no-underline">
44 <img src="/logos/logotype.svg" alt="tangled" class="h-24 w-48 dark:invert" />
45 </a>
46 <p class="text-center text-xl italic text-fg-strong">tightly-knit social coding.</p>
47 </div>
48
49 <form class="mt-4" onsubmit={submit}>
50 <div class="flex flex-col">
51 <label for="identifier" class="py-2 text-sm text-fg">Handle</label>
52 <input
53 id="identifier"
54 bind:value={identifier}
55 disabled={isSubmitting}
56 type="text"
57 autocomplete="username"
58 autocapitalize="none"
59 spellcheck="false"
60 inputmode="url"
61 required
62 placeholder="akshay.tngl.sh"
63 class="w-full rounded border border-border bg-surface p-3 text-lg text-fg placeholder:text-fg-faint focus:outline-none focus:ring-1 focus:ring-border-strong md:text-base"
64 />
65 <p class="mt-1 text-sm text-fg-subtle">
66 Use your <span class="text-fg">AT Protocol</span> handle to log in. If you're unsure, this
67 is likely your Tangled
68 <code class="rounded bg-surface-muted px-1 font-mono text-xs text-fg">(.tngl.sh)</code>
69 or Bluesky
70 <code class="rounded bg-surface-muted px-1 font-mono text-xs text-fg">(.bsky.social)</code>
71 account.
72 </p>
73 </div>
74
75 <Button
76 type="submit"
77 size="sm"
78 disabled={isSubmitting}
79 loading={isSubmitting}
80 spinnerClass="size-4"
81 aria-label={isSubmitting ? 'Logging in' : undefined}
82 class="my-2 mt-6 w-full text-base disabled:opacity-100"
83 >
84 Login
85 </Button>
86 </form>
87
88 <p class="text-sm text-fg-subtle">
89 Don't have an account? <a href={appPath('/signup')} class="text-fg underline"
90 >Create an account</a
91 >
92 on Tangled now!
93 </p>
94
95 {#if auth.error}
96 <div
97 class="my-2 flex gap-2 rounded border border-danger bg-danger-soft px-3 py-2 text-danger drop-shadow-sm"
98 >
99 <span class="py-1" aria-hidden="true"><CircleAlert class="size-4" /></span>
100 <div>
101 <h5 class="font-medium">Login error</h5>
102 <p class="text-sm">{auth.error} Please try again.</p>
103 </div>
104 </div>
105 {/if}
106</section>