Andrew commited on
Commit
245b57f
·
1 Parent(s): 70c72fa

feat(auth): add multi-provider login modal with password form

Browse files
Files changed (1) hide show
  1. src/lib/components/LoginModal.svelte +105 -15
src/lib/components/LoginModal.svelte CHANGED
@@ -5,16 +5,57 @@
5
  import LogoHuggingFaceBorderless from "$lib/components/icons/LogoHuggingFaceBorderless.svelte";
6
  import Modal from "$lib/components/Modal.svelte";
7
  import { cookiesAreEnabled } from "$lib/utils/cookiesAreEnabled";
8
- import Logo from "./icons/Logo.svelte";
9
- import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
10
 
11
- const publicConfig = usePublicConfig();
12
 
13
- interface Props {
14
- onclose?: () => void;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
- let { onclose }: Props = $props();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  </script>
19
 
20
  <Modal onclose={() => onclose?.()} width="!max-w-[400px] !m-4">
@@ -25,26 +66,75 @@
25
  <Logo classNames="mr-1" />
26
  {publicConfig.PUBLIC_APP_NAME}
27
  </h2>
28
- <p class="text-balance text-lg font-semibold leading-snug text-gray-800">
29
  {publicConfig.PUBLIC_APP_DESCRIPTION}
30
  </p>
31
  <p class="text-balance rounded-xl border bg-white/80 p-2 text-base text-gray-800">
32
  {publicConfig.PUBLIC_APP_GUEST_MESSAGE}
33
- </p>
34
 
35
- <div class="flex w-full flex-col items-center gap-2">
36
  {#if page.data.loginRequired}
37
  <a
38
  href="{base}/login"
39
  class="flex w-full flex-wrap items-center justify-center whitespace-nowrap rounded-full bg-black px-5 py-2 text-center text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
40
  >
41
- Sign in
42
- {#if publicConfig.isHuggingChat}
43
- <span class="flex items-center">
44
- &nbsp;with <LogoHuggingFaceBorderless classNames="text-xl mr-1 ml-1.5" /> Hugging Face
45
- </span>
46
- {/if}
47
  </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  {:else}
49
  <button
50
  class="flex w-full items-center justify-center whitespace-nowrap rounded-full border-2 border-black bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
 
5
  import LogoHuggingFaceBorderless from "$lib/components/icons/LogoHuggingFaceBorderless.svelte";
6
  import Modal from "$lib/components/Modal.svelte";
7
  import { cookiesAreEnabled } from "$lib/utils/cookiesAreEnabled";
8
+ import Logo from "./icons/Logo.svelte";
9
+ import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
10
 
11
+ const publicConfig = usePublicConfig();
12
 
13
+ interface Props {
14
+ onclose?: () => void;
15
+ }
16
+
17
+ let { onclose }: Props = $props();
18
+
19
+ let showPasswordForm = $state(false);
20
+ let passwordErrorMessage = $state(false);
21
+ let isSubmitting = $state(false);
22
+
23
+ async function handlePasswordSubmit(event: SubmitEvent) {
24
+ event.preventDefault();
25
+ if (isSubmitting) return;
26
+
27
+ if (!cookiesAreEnabled()) {
28
+ window.open(window.location.href, "_blank");
29
+ return;
30
  }
31
 
32
+ isSubmitting = true;
33
+ passwordErrorMessage = false;
34
+
35
+ const formData = new FormData(event.target as HTMLFormElement);
36
+ const body = Object.fromEntries(formData.entries());
37
+
38
+ try {
39
+ const response = await fetch(`${base}/login/password`, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify(body),
43
+ });
44
+
45
+ if (response.ok) {
46
+ window.location.href = `${base}/`;
47
+ } else {
48
+ const result = await response.json();
49
+ console.error(result.message);
50
+ passwordErrorMessage = true;
51
+ }
52
+ } catch (e) {
53
+ console.error(e);
54
+ passwordErrorMessage = true;
55
+ } finally {
56
+ isSubmitting = false;
57
+ }
58
+ }
59
  </script>
60
 
61
  <Modal onclose={() => onclose?.()} width="!max-w-[400px] !m-4">
 
66
  <Logo classNames="mr-1" />
67
  {publicConfig.PUBLIC_APP_NAME}
68
  </h2>
69
+ <!-- <p class="text-balance text-lg font-semibold leading-snug text-gray-800">
70
  {publicConfig.PUBLIC_APP_DESCRIPTION}
71
  </p>
72
  <p class="text-balance rounded-xl border bg-white/80 p-2 text-base text-gray-800">
73
  {publicConfig.PUBLIC_APP_GUEST_MESSAGE}
74
+ </p> -->
75
 
76
+ <div class="flex w-full flex-col items-center gap-3">
77
  {#if page.data.loginRequired}
78
  <a
79
  href="{base}/login"
80
  class="flex w-full flex-wrap items-center justify-center whitespace-nowrap rounded-full bg-black px-5 py-2 text-center text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"
81
  >
82
+ Sign in with
83
+ <span class="flex items-center">
84
+ &nbsp;<LogoHuggingFaceBorderless classNames="text-xl mr-1" /> Hugging Face
85
+ </span>
 
 
86
  </a>
87
+
88
+ <button
89
+ type="button"
90
+ onclick={() => {
91
+ showPasswordForm = !showPasswordForm;
92
+ if (!showPasswordForm) {
93
+ passwordErrorMessage = false;
94
+ }
95
+ }}
96
+ class="flex w-full items-center justify-center whitespace-nowrap rounded-full border-2 border-black bg-white px-5 py-2 text-lg font-semibold text-gray-800 transition-colors hover:bg-gray-100"
97
+ >
98
+ Sign in with username/password
99
+ </button>
100
+
101
+ {#if showPasswordForm}
102
+ <form
103
+ onsubmit={handlePasswordSubmit}
104
+ class="flex w-full flex-col gap-2 rounded-xl border border-gray-200 bg-white/80 p-3 text-left shadow-sm"
105
+ >
106
+ <label class="text-sm font-medium text-gray-700">
107
+ Username or email
108
+ <input
109
+ type="text"
110
+ name="username"
111
+ autocomplete="username"
112
+ required
113
+ class="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-base text-gray-900 focus:border-black focus:outline-none focus:ring-2 focus:ring-black/50"
114
+ />
115
+ </label>
116
+ <label class="text-sm font-medium text-gray-700">
117
+ Password
118
+ <input
119
+ type="password"
120
+ name="password"
121
+ autocomplete="current-password"
122
+ required
123
+ class="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-base text-gray-900 focus:border-black focus:outline-none focus:ring-2 focus:ring-black/50"
124
+ />
125
+ </label>
126
+ {#if passwordErrorMessage}
127
+ <p class="text-sm text-red-600">Invalid username or password. Please try again.</p>
128
+ {/if}
129
+ <button
130
+ type="submit"
131
+ disabled={isSubmitting}
132
+ class="mt-1 flex w-full items-center justify-center whitespace-nowrap rounded-full bg-black px-4 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900 disabled:cursor-not-allowed disabled:bg-gray-500"
133
+ >
134
+ {#if isSubmitting}Submitting...{:else}Continue{/if}
135
+ </button>
136
+ </form>
137
+ {/if}
138
  {:else}
139
  <button
140
  class="flex w-full items-center justify-center whitespace-nowrap rounded-full border-2 border-black bg-black px-5 py-2 text-lg font-semibold text-gray-100 transition-colors hover:bg-gray-900"