svelte-firekit 0.0.1
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/README.md +58 -0
- package/dist/auth/reset-password.svelte +20 -0
- package/dist/auth/reset-password.svelte.d.ts +18 -0
- package/dist/auth/sign-in.svelte +30 -0
- package/dist/auth/sign-in.svelte.d.ts +4 -0
- package/dist/auth/sign-up.svelte +30 -0
- package/dist/auth/sign-up.svelte.d.ts +4 -0
- package/dist/auth/uid.d.ts +1 -0
- package/dist/auth/uid.js +7 -0
- package/dist/auth/user-button.svelte +117 -0
- package/dist/auth/user-button.svelte.d.ts +5 -0
- package/dist/auth/user.svelte.d.ts +10 -0
- package/dist/auth/user.svelte.js +21 -0
- package/dist/auth.d.ts +39 -0
- package/dist/auth.js +100 -0
- package/dist/components/auth/google-sign-in.svelte +46 -0
- package/dist/components/auth/google-sign-in.svelte.d.ts +4 -0
- package/dist/components/auth/reset-password-form.svelte +58 -0
- package/dist/components/auth/reset-password-form.svelte.d.ts +18 -0
- package/dist/components/auth/sign-in-form.svelte +77 -0
- package/dist/components/auth/sign-in-form.svelte.d.ts +18 -0
- package/dist/components/auth/sign-up-form.svelte +112 -0
- package/dist/components/auth/sign-up-form.svelte.d.ts +18 -0
- package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +13 -0
- package/dist/components/ui/alert-dialog/alert-dialog-action.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +17 -0
- package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/alert-dialog-content.svelte +23 -0
- package/dist/components/ui/alert-dialog/alert-dialog-content.svelte.d.ts +2 -0
- package/dist/components/ui/alert-dialog/alert-dialog-description.svelte +16 -0
- package/dist/components/ui/alert-dialog/alert-dialog-description.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
- package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
- package/dist/components/ui/alert-dialog/alert-dialog-header.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte +19 -0
- package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/alert-dialog-title.svelte +18 -0
- package/dist/components/ui/alert-dialog/alert-dialog-title.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/index.js +15 -0
- package/dist/components/ui/avatar/avatar-fallback.svelte +16 -0
- package/dist/components/ui/avatar/avatar-fallback.svelte.d.ts +3 -0
- package/dist/components/ui/avatar/avatar-image.svelte +20 -0
- package/dist/components/ui/avatar/avatar-image.svelte.d.ts +3 -0
- package/dist/components/ui/avatar/avatar.svelte +18 -0
- package/dist/components/ui/avatar/avatar.svelte.d.ts +3 -0
- package/dist/components/ui/avatar/index.d.ts +4 -0
- package/dist/components/ui/avatar/index.js +6 -0
- package/dist/components/ui/button/button.svelte +75 -0
- package/dist/components/ui/button/button.svelte.d.ts +117 -0
- package/dist/components/ui/button/index.d.ts +2 -0
- package/dist/components/ui/button/index.js +4 -0
- package/dist/components/ui/card/card-content.svelte +16 -0
- package/dist/components/ui/card/card-content.svelte.d.ts +4 -0
- package/dist/components/ui/card/card-description.svelte +16 -0
- package/dist/components/ui/card/card-description.svelte.d.ts +4 -0
- package/dist/components/ui/card/card-footer.svelte +16 -0
- package/dist/components/ui/card/card-footer.svelte.d.ts +4 -0
- package/dist/components/ui/card/card-header.svelte +16 -0
- package/dist/components/ui/card/card-header.svelte.d.ts +4 -0
- package/dist/components/ui/card/card-title.svelte +25 -0
- package/dist/components/ui/card/card-title.svelte.d.ts +7 -0
- package/dist/components/ui/card/card.svelte +20 -0
- package/dist/components/ui/card/card.svelte.d.ts +4 -0
- package/dist/components/ui/card/index.d.ts +7 -0
- package/dist/components/ui/card/index.js +9 -0
- package/dist/components/ui/checkbox/checkbox.svelte +33 -0
- package/dist/components/ui/checkbox/checkbox.svelte.d.ts +3 -0
- package/dist/components/ui/checkbox/index.d.ts +2 -0
- package/dist/components/ui/checkbox/index.js +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +37 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +5 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +22 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +19 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +11 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +23 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +17 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +23 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +30 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +16 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +20 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +19 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +28 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +5 -0
- package/dist/components/ui/dropdown-menu/index.js +17 -0
- package/dist/components/ui/form/form-button.svelte +7 -0
- package/dist/components/ui/form/form-button.svelte.d.ts +3 -0
- package/dist/components/ui/form/form-description.svelte +17 -0
- package/dist/components/ui/form/form-description.svelte.d.ts +3 -0
- package/dist/components/ui/form/form-element-field.svelte +30 -0
- package/dist/components/ui/form/form-element-field.svelte.d.ts +22 -0
- package/dist/components/ui/form/form-field-errors.svelte +30 -0
- package/dist/components/ui/form/form-field-errors.svelte.d.ts +5 -0
- package/dist/components/ui/form/form-field.svelte +30 -0
- package/dist/components/ui/form/form-field.svelte.d.ts +21 -0
- package/dist/components/ui/form/form-fieldset.svelte +21 -0
- package/dist/components/ui/form/form-fieldset.svelte.d.ts +19 -0
- package/dist/components/ui/form/form-label.svelte +21 -0
- package/dist/components/ui/form/form-label.svelte.d.ts +3 -0
- package/dist/components/ui/form/form-legend.svelte +17 -0
- package/dist/components/ui/form/form-legend.svelte.d.ts +3 -0
- package/dist/components/ui/form/index.d.ts +11 -0
- package/dist/components/ui/form/index.js +13 -0
- package/dist/components/ui/input/index.d.ts +2 -0
- package/dist/components/ui/input/index.js +4 -0
- package/dist/components/ui/input/input.svelte +22 -0
- package/dist/components/ui/input/input.svelte.d.ts +4 -0
- package/dist/components/ui/label/index.d.ts +2 -0
- package/dist/components/ui/label/index.js +4 -0
- package/dist/components/ui/label/label.svelte +19 -0
- package/dist/components/ui/label/label.svelte.d.ts +3 -0
- package/dist/components/ui/sonner/index.d.ts +1 -0
- package/dist/components/ui/sonner/index.js +1 -0
- package/dist/components/ui/sonner/sonner.svelte +20 -0
- package/dist/components/ui/sonner/sonner.svelte.d.ts +3 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +39 -0
- package/dist/firebase.d.ts +43 -0
- package/dist/firebase.js +110 -0
- package/dist/firestore/Collection.svelte +148 -0
- package/dist/firestore/Collection.svelte.d.ts +27 -0
- package/dist/firestore/collection.svelte.js +207 -0
- package/dist/firestore/doc.svelte.d.ts +1 -0
- package/dist/firestore/doc.svelte.js +1 -0
- package/dist/firestore/firestore.d.ts +31 -0
- package/dist/firestore/firestore.js +100 -0
- package/dist/firestore/perf.d.ts +3 -0
- package/dist/firestore/perf.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/schemas/reset-password.d.ts +4 -0
- package/dist/schemas/reset-password.js +4 -0
- package/dist/schemas/sign-in.d.ts +5 -0
- package/dist/schemas/sign-in.js +5 -0
- package/dist/schemas/sign-up.d.ts +8 -0
- package/dist/schemas/sign-up.js +8 -0
- package/dist/types/nav.d.ts +9 -0
- package/dist/types/nav.js +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +16 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# create-svelte
|
|
2
|
+
|
|
3
|
+
Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
|
4
|
+
|
|
5
|
+
Read more about creating a library [in the docs](https://svelte.dev/docs/kit/packaging).
|
|
6
|
+
|
|
7
|
+
## Creating a project
|
|
8
|
+
|
|
9
|
+
If you're seeing this, you've probably already done this step. Congrats!
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# create a new project in the current directory
|
|
13
|
+
npx sv create
|
|
14
|
+
|
|
15
|
+
# create a new project in my-app
|
|
16
|
+
npx sv create my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Developing
|
|
20
|
+
|
|
21
|
+
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run dev
|
|
25
|
+
|
|
26
|
+
# or start the server and open the app in a new browser tab
|
|
27
|
+
npm run dev -- --open
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
|
|
31
|
+
|
|
32
|
+
## Building
|
|
33
|
+
|
|
34
|
+
To build your library:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run package
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
To create a production version of your showcase app:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm run build
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can preview the production build with `npm run preview`.
|
|
47
|
+
|
|
48
|
+
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
|
49
|
+
|
|
50
|
+
## Publishing
|
|
51
|
+
|
|
52
|
+
Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
|
|
53
|
+
|
|
54
|
+
To publish your library to [npm](https://www.npmjs.com):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm publish
|
|
58
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ResetPasswordForm from "../components/auth/reset-password-form.svelte";
|
|
3
|
+
import Button from "../components/ui/button/button.svelte";
|
|
4
|
+
import * as Card from "../components/ui/card";
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<Card.Root class="sm:w-[448px]">
|
|
8
|
+
<Card.Header>
|
|
9
|
+
<Card.Title class="text-center text-2xl">Forgot password?</Card.Title>
|
|
10
|
+
<Card.Description class="text-center">
|
|
11
|
+
Remember your password?
|
|
12
|
+
<Button variant="link" href="/sign-in" class="p-0"
|
|
13
|
+
>Sign in here</Button
|
|
14
|
+
>
|
|
15
|
+
</Card.Description>
|
|
16
|
+
</Card.Header>
|
|
17
|
+
<Card.Content>
|
|
18
|
+
<ResetPasswordForm />
|
|
19
|
+
</Card.Content>
|
|
20
|
+
</Card.Root>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const ResetPassword: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type ResetPassword = InstanceType<typeof ResetPassword>;
|
|
18
|
+
export default ResetPassword;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import SignInWithGoogle from "../components/auth/google-sign-in.svelte";
|
|
3
|
+
import SignInForm from "../components/auth/sign-in-form.svelte";
|
|
4
|
+
import Button from "../components/ui/button/button.svelte";
|
|
5
|
+
import * as Card from "../components/ui/card";
|
|
6
|
+
let { title = "Sign in" }: { title: string } = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<Card.Root class="sm:w-[448px]">
|
|
10
|
+
<Card.Header>
|
|
11
|
+
<Card.Title class="text-center text-2xl">{title}</Card.Title>
|
|
12
|
+
<Card.Description class="text-center">
|
|
13
|
+
Don't have an account yet?
|
|
14
|
+
<Button variant="link" href="/sign-up" class="p-0"
|
|
15
|
+
>Sign up here</Button
|
|
16
|
+
>
|
|
17
|
+
</Card.Description>
|
|
18
|
+
</Card.Header>
|
|
19
|
+
<Card.Content class="space-y-5">
|
|
20
|
+
<SignInWithGoogle label="Sign in" />
|
|
21
|
+
|
|
22
|
+
<div
|
|
23
|
+
class="before:muted-foreground after:muted-foreground flex items-center text-xs uppercase text-muted-foreground before:me-6 before:flex-1 before:border-t after:ms-6 after:flex-1 after:border-t dark:before:border-muted-foreground dark:after:border-muted-foreground"
|
|
24
|
+
>
|
|
25
|
+
Or
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<SignInForm />
|
|
29
|
+
</Card.Content>
|
|
30
|
+
</Card.Root>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import SignInWithGoogle from "../components/auth/google-sign-in.svelte";
|
|
3
|
+
import SignUpForm from "../components/auth/sign-up-form.svelte";
|
|
4
|
+
import Button from "../components/ui/button/button.svelte";
|
|
5
|
+
import * as Card from "../components/ui/card";
|
|
6
|
+
let { title = "Sign up" }: { title: string } = $props();
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<Card.Root class="sm:w-[448px]">
|
|
10
|
+
<Card.Header>
|
|
11
|
+
<Card.Title class="text-center text-2xl">{title}</Card.Title>
|
|
12
|
+
<Card.Description class="text-center">
|
|
13
|
+
Already have an account?
|
|
14
|
+
<Button variant="link" href="/sign-in" class="p-0"
|
|
15
|
+
>Sign in here</Button
|
|
16
|
+
>
|
|
17
|
+
</Card.Description>
|
|
18
|
+
</Card.Header>
|
|
19
|
+
<Card.Content class="space-y-5">
|
|
20
|
+
<SignInWithGoogle label="Sign up" />
|
|
21
|
+
|
|
22
|
+
<div
|
|
23
|
+
class="before:muted-foreground after:muted-foreground flex items-center text-xs uppercase text-muted-foreground before:me-6 before:flex-1 before:border-t after:ms-6 after:flex-1 after:border-t dark:before:border-muted-foreground dark:after:border-muted-foreground"
|
|
24
|
+
>
|
|
25
|
+
Or
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<SignUpForm />
|
|
29
|
+
</Card.Content>
|
|
30
|
+
</Card.Root>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/auth/uid.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { get } from "svelte/store";
|
|
3
|
+
// import { authState } from "./user";
|
|
4
|
+
// export const getUid = () => {
|
|
5
|
+
// const u = get(authState);
|
|
6
|
+
// return (u && u.uid) || "anonymous"; // 'anonymous' allows support messages to be saved by non-logged-in users
|
|
7
|
+
// };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as DropdownMenu from "../components/ui/dropdown-menu/index.js";
|
|
3
|
+
import * as Avatar from "../components/ui/avatar/index.js";
|
|
4
|
+
import { authUser } from "./user.svelte.js";
|
|
5
|
+
import { getInitials } from "../utils.js";
|
|
6
|
+
import { LogOut } from "lucide-svelte";
|
|
7
|
+
import { logOut } from "../auth.js";
|
|
8
|
+
import type { NavItem } from "../types/nav.js";
|
|
9
|
+
let { nav }: { nav: NavItem[] } = $props();
|
|
10
|
+
import * as AlertDialog from "../components/ui/alert-dialog/index.js";
|
|
11
|
+
import Button from "../components/ui/button/button.svelte";
|
|
12
|
+
let isOpen = $state(false);
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
{#if authUser.currentUser}
|
|
16
|
+
<DropdownMenu.Root>
|
|
17
|
+
<DropdownMenu.Trigger>
|
|
18
|
+
<Avatar.Root>
|
|
19
|
+
<Avatar.Image
|
|
20
|
+
src={authUser.currentUser?.photoURL}
|
|
21
|
+
alt="Avatar"
|
|
22
|
+
/>
|
|
23
|
+
<Avatar.Fallback>
|
|
24
|
+
{getInitials(authUser.currentUser?.displayName)}
|
|
25
|
+
</Avatar.Fallback>
|
|
26
|
+
</Avatar.Root>
|
|
27
|
+
</DropdownMenu.Trigger>
|
|
28
|
+
<DropdownMenu.Content>
|
|
29
|
+
<DropdownMenu.Group>
|
|
30
|
+
<DropdownMenu.GroupHeading>
|
|
31
|
+
<div class="flex items-center gap-3">
|
|
32
|
+
<Avatar.Root>
|
|
33
|
+
<Avatar.Image
|
|
34
|
+
src={authUser.currentUser?.photoURL}
|
|
35
|
+
alt="Avatar"
|
|
36
|
+
/>
|
|
37
|
+
<Avatar.Fallback>
|
|
38
|
+
{getInitials(authUser.currentUser?.displayName)}
|
|
39
|
+
</Avatar.Fallback>
|
|
40
|
+
</Avatar.Root>
|
|
41
|
+
<div class="grow">
|
|
42
|
+
<span
|
|
43
|
+
class="block font-medium text-sm text-gray-800 dark:text-neutral-200"
|
|
44
|
+
>
|
|
45
|
+
{authUser.currentUser?.displayName}
|
|
46
|
+
</span>
|
|
47
|
+
<p class="text-xs text-foreground-500">
|
|
48
|
+
{authUser.currentUser?.email}
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</DropdownMenu.GroupHeading>
|
|
53
|
+
<DropdownMenu.Separator />
|
|
54
|
+
<DropdownMenu.Item onclick={() => (isOpen = true)}>
|
|
55
|
+
Profile
|
|
56
|
+
</DropdownMenu.Item>
|
|
57
|
+
{#each nav as { href, label }}
|
|
58
|
+
<DropdownMenu.Item>
|
|
59
|
+
<a {href}>
|
|
60
|
+
{label}
|
|
61
|
+
</a>
|
|
62
|
+
</DropdownMenu.Item>
|
|
63
|
+
{/each}
|
|
64
|
+
|
|
65
|
+
<DropdownMenu.Separator />
|
|
66
|
+
<DropdownMenu.Item onclick={logOut}>
|
|
67
|
+
<LogOut /> Logout
|
|
68
|
+
</DropdownMenu.Item>
|
|
69
|
+
</DropdownMenu.Group>
|
|
70
|
+
</DropdownMenu.Content>
|
|
71
|
+
</DropdownMenu.Root>
|
|
72
|
+
<AlertDialog.Root bind:open={isOpen}>
|
|
73
|
+
<AlertDialog.Content>
|
|
74
|
+
<AlertDialog.Header>
|
|
75
|
+
<AlertDialog.Title>
|
|
76
|
+
<div class="flex justify-between items-center">
|
|
77
|
+
<div class="flex items-center gap-3">
|
|
78
|
+
<Avatar.Root>
|
|
79
|
+
<Avatar.Image
|
|
80
|
+
src={authUser.currentUser?.photoURL}
|
|
81
|
+
alt="Avatar"
|
|
82
|
+
/>
|
|
83
|
+
<Avatar.Fallback>
|
|
84
|
+
{getInitials(
|
|
85
|
+
authUser.currentUser?.displayName,
|
|
86
|
+
)}
|
|
87
|
+
</Avatar.Fallback>
|
|
88
|
+
</Avatar.Root>
|
|
89
|
+
<div class="grow">
|
|
90
|
+
<span
|
|
91
|
+
class="block font-medium text-sm text-gray-800 dark:text-neutral-200"
|
|
92
|
+
>
|
|
93
|
+
{authUser.currentUser?.displayName}
|
|
94
|
+
</span>
|
|
95
|
+
<p class="text-xs text-foreground-500">
|
|
96
|
+
{authUser.currentUser?.email}
|
|
97
|
+
</p>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
<Button onclick={logOut} variant="link">
|
|
101
|
+
<LogOut />Logout
|
|
102
|
+
</Button>
|
|
103
|
+
</div>
|
|
104
|
+
</AlertDialog.Title>
|
|
105
|
+
<AlertDialog.Description>
|
|
106
|
+
Manage your name, password and account settings.
|
|
107
|
+
</AlertDialog.Description>
|
|
108
|
+
</AlertDialog.Header>
|
|
109
|
+
<AlertDialog.Footer>
|
|
110
|
+
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
|
|
111
|
+
<AlertDialog.Action>Continue</AlertDialog.Action>
|
|
112
|
+
</AlertDialog.Footer>
|
|
113
|
+
</AlertDialog.Content>
|
|
114
|
+
</AlertDialog.Root>
|
|
115
|
+
{:else}
|
|
116
|
+
<Button href="/login">Login</Button>
|
|
117
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type User } from "firebase/auth";
|
|
2
|
+
export declare class FirebaseAuthUser {
|
|
3
|
+
#private;
|
|
4
|
+
constructor();
|
|
5
|
+
get isAuthenticated(): boolean;
|
|
6
|
+
get isAnonymousUser(): boolean | undefined;
|
|
7
|
+
get userId(): string | undefined;
|
|
8
|
+
get currentUser(): User | null | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare const authUser: FirebaseAuthUser;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getAuthInstance } from "../firebase.js";
|
|
2
|
+
import { onAuthStateChanged } from "firebase/auth";
|
|
3
|
+
export class FirebaseAuthUser {
|
|
4
|
+
#currentUser = $state();
|
|
5
|
+
constructor() {
|
|
6
|
+
onAuthStateChanged(getAuthInstance(), (user) => (this.#currentUser = user));
|
|
7
|
+
}
|
|
8
|
+
get isAuthenticated() {
|
|
9
|
+
return this.currentUser !== null;
|
|
10
|
+
}
|
|
11
|
+
get isAnonymousUser() {
|
|
12
|
+
return this.currentUser?.isAnonymous;
|
|
13
|
+
}
|
|
14
|
+
get userId() {
|
|
15
|
+
return this.currentUser?.uid;
|
|
16
|
+
}
|
|
17
|
+
get currentUser() {
|
|
18
|
+
return this.#currentUser;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const authUser = new FirebaseAuthUser();
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles Google Sign-In.
|
|
3
|
+
*/
|
|
4
|
+
export declare function signInWithGoogle(): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Signs in with email and password.
|
|
7
|
+
*/
|
|
8
|
+
export declare function signInWithEmail(email: string, password: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Registers a new user and updates Firestore.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerWithEmail(email: string, password: string, displayName: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Signs out the user and redirects.
|
|
15
|
+
*/
|
|
16
|
+
export declare function logOut(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Sends a password reset email.
|
|
19
|
+
*/
|
|
20
|
+
export declare function sendPasswordReset(email: string): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Verifies email for current user.
|
|
23
|
+
*/
|
|
24
|
+
export declare function sendEmailVerificationToUser(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Updates user profile with display name and photo URL.
|
|
27
|
+
*/
|
|
28
|
+
export declare function updateUserProfile(profile: {
|
|
29
|
+
displayName?: string;
|
|
30
|
+
photoURL?: string;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Updates password for current user.
|
|
34
|
+
*/
|
|
35
|
+
export declare function updateUserPassword(newPassword: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Checks onboarding completion by verifying profile data.
|
|
38
|
+
*/
|
|
39
|
+
export declare function checkOnboardingCompletion(uid: string): Promise<void>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// firebaseAuthService.ts
|
|
2
|
+
import { GoogleAuthProvider, sendPasswordResetEmail, signInWithEmailAndPassword, signInWithPopup, signOut, createUserWithEmailAndPassword, sendEmailVerification, updateProfile, updatePassword } from 'firebase/auth';
|
|
3
|
+
import { doc, getDoc, setDoc } from 'firebase/firestore';
|
|
4
|
+
import { getAuthInstance, getDb } from './firebase.js';
|
|
5
|
+
import { goto } from '$app/navigation';
|
|
6
|
+
const auth = getAuthInstance();
|
|
7
|
+
const firestore = getDb();
|
|
8
|
+
/**
|
|
9
|
+
* Handles Google Sign-In.
|
|
10
|
+
*/
|
|
11
|
+
export async function signInWithGoogle() {
|
|
12
|
+
const provider = new GoogleAuthProvider();
|
|
13
|
+
const result = await signInWithPopup(auth, provider);
|
|
14
|
+
await updateUserInFirestore(result.user);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Signs in with email and password.
|
|
18
|
+
*/
|
|
19
|
+
export async function signInWithEmail(email, password) {
|
|
20
|
+
const result = await signInWithEmailAndPassword(auth, email, password);
|
|
21
|
+
await updateUserInFirestore(result.user);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Registers a new user and updates Firestore.
|
|
25
|
+
*/
|
|
26
|
+
export async function registerWithEmail(email, password, displayName) {
|
|
27
|
+
const result = await createUserWithEmailAndPassword(auth, email, password);
|
|
28
|
+
const user = result.user;
|
|
29
|
+
if (user) {
|
|
30
|
+
await updateProfile(user, { displayName });
|
|
31
|
+
await updateUserInFirestore(user);
|
|
32
|
+
await sendEmailVerification(user);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Updates Firestore with user data.
|
|
37
|
+
*/
|
|
38
|
+
async function updateUserInFirestore(user) {
|
|
39
|
+
const ref = doc(firestore, 'users', user.uid);
|
|
40
|
+
const userData = {
|
|
41
|
+
uid: user.uid,
|
|
42
|
+
email: user.email,
|
|
43
|
+
emailVerified: user.emailVerified,
|
|
44
|
+
displayName: user.displayName,
|
|
45
|
+
photoURL: user.photoURL,
|
|
46
|
+
isAnonymous: user.isAnonymous,
|
|
47
|
+
providerId: user.providerId,
|
|
48
|
+
phoneNumber: user.phoneNumber,
|
|
49
|
+
providerData: user.providerData
|
|
50
|
+
};
|
|
51
|
+
await setDoc(ref, userData, { merge: true });
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Signs out the user and redirects.
|
|
55
|
+
*/
|
|
56
|
+
export async function logOut() {
|
|
57
|
+
await signOut(auth);
|
|
58
|
+
goto('/sign-in');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Sends a password reset email.
|
|
62
|
+
*/
|
|
63
|
+
export async function sendPasswordReset(email) {
|
|
64
|
+
await sendPasswordResetEmail(auth, email);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Verifies email for current user.
|
|
68
|
+
*/
|
|
69
|
+
export async function sendEmailVerificationToUser() {
|
|
70
|
+
if (auth.currentUser) {
|
|
71
|
+
await sendEmailVerification(auth.currentUser);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Updates user profile with display name and photo URL.
|
|
76
|
+
*/
|
|
77
|
+
export async function updateUserProfile(profile) {
|
|
78
|
+
if (auth.currentUser) {
|
|
79
|
+
await updateProfile(auth.currentUser, profile);
|
|
80
|
+
await updateUserInFirestore(auth.currentUser);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Updates password for current user.
|
|
85
|
+
*/
|
|
86
|
+
export async function updateUserPassword(newPassword) {
|
|
87
|
+
if (auth.currentUser) {
|
|
88
|
+
await updatePassword(auth.currentUser, newPassword);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Checks onboarding completion by verifying profile data.
|
|
93
|
+
*/
|
|
94
|
+
export async function checkOnboardingCompletion(uid) {
|
|
95
|
+
const profileDoc = await getDoc(doc(firestore, 'profiles', uid));
|
|
96
|
+
if (!profileDoc.exists() || !profileDoc.data()?.username) {
|
|
97
|
+
alert("Please complete onboarding");
|
|
98
|
+
goto('/onboarding');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { signInWithGoogle } from "../../auth.js";
|
|
3
|
+
import Button from "../ui/button/button.svelte";
|
|
4
|
+
let { label = "Sign in" }: { label: string } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<Button onclick={signInWithGoogle} class="w-full gap-2" variant="outline">
|
|
8
|
+
<svg
|
|
9
|
+
class="h-4 w-4 flex-shrink-0"
|
|
10
|
+
width="33"
|
|
11
|
+
height="32"
|
|
12
|
+
viewBox="0 0 33 32"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
>
|
|
16
|
+
<g clip-path="url(#clip0_4132_5805)">
|
|
17
|
+
<path
|
|
18
|
+
d="M32.2566 16.36C32.2566 15.04 32.1567 14.08 31.9171 13.08H16.9166V19.02H25.7251C25.5454 20.5 24.5866 22.72 22.4494 24.22L22.4294 24.42L27.1633 28.1L27.4828 28.14C30.5189 25.34 32.2566 21.22 32.2566 16.36Z"
|
|
19
|
+
fill="#4285F4"
|
|
20
|
+
/>
|
|
21
|
+
<path
|
|
22
|
+
d="M16.9166 32C21.231 32 24.8463 30.58 27.5028 28.12L22.4694 24.2C21.1111 25.14 19.3135 25.8 16.9366 25.8C12.7021 25.8 9.12677 23 7.84844 19.16L7.66867 19.18L2.71513 23L2.65521 23.18C5.2718 28.4 10.6648 32 16.9166 32Z"
|
|
23
|
+
fill="#34A853"
|
|
24
|
+
/>
|
|
25
|
+
<path
|
|
26
|
+
d="M7.82845 19.16C7.48889 18.16 7.28915 17.1 7.28915 16C7.28915 14.9 7.48889 13.84 7.80848 12.84V12.62L2.81499 8.73999L2.6552 8.81999C1.55663 10.98 0.937439 13.42 0.937439 16C0.937439 18.58 1.55663 21.02 2.63522 23.18L7.82845 19.16Z"
|
|
27
|
+
fill="#FBBC05"
|
|
28
|
+
/>
|
|
29
|
+
<path
|
|
30
|
+
d="M16.9166 6.18C19.9127 6.18 21.9501 7.48 23.0886 8.56L27.6027 4.16C24.8263 1.58 21.231 0 16.9166 0C10.6648 0 5.27181 3.6 2.63525 8.82L7.80851 12.84C9.10681 8.98 12.6821 6.18 16.9166 6.18Z"
|
|
31
|
+
fill="#EB4335"
|
|
32
|
+
/>
|
|
33
|
+
</g>
|
|
34
|
+
<defs>
|
|
35
|
+
<clipPath id="clip0_4132_5805">
|
|
36
|
+
<rect
|
|
37
|
+
width="32"
|
|
38
|
+
height="32"
|
|
39
|
+
fill="white"
|
|
40
|
+
transform="translate(0.937439)"
|
|
41
|
+
/>
|
|
42
|
+
</clipPath>
|
|
43
|
+
</defs>
|
|
44
|
+
</svg>
|
|
45
|
+
{label} with Google
|
|
46
|
+
</Button>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { goto } from "$app/navigation";
|
|
3
|
+
import { sendPasswordReset } from "../../auth.js";
|
|
4
|
+
import * as Form from "../ui/form/index.js";
|
|
5
|
+
import { Input } from "../ui/input/index.js";
|
|
6
|
+
import {
|
|
7
|
+
resetPasswordSchema,
|
|
8
|
+
} from "../../schemas/reset-password.js";
|
|
9
|
+
import { toast } from "svelte-sonner";
|
|
10
|
+
import {
|
|
11
|
+
superForm,defaults
|
|
12
|
+
} from "sveltekit-superforms";
|
|
13
|
+
import { zodClient } from "sveltekit-superforms/adapters";
|
|
14
|
+
import { valibot } from 'sveltekit-superforms/adapters';
|
|
15
|
+
|
|
16
|
+
const data = defaults(valibot(resetPasswordSchema));
|
|
17
|
+
|
|
18
|
+
const form = superForm(data, {
|
|
19
|
+
validators: valibot(resetPasswordSchema),
|
|
20
|
+
dataType: "json",
|
|
21
|
+
SPA: true,
|
|
22
|
+
resetForm: false,
|
|
23
|
+
clearOnSubmit: "errors-and-message",
|
|
24
|
+
async onUpdate({ form }) {
|
|
25
|
+
if (!form.valid) return;
|
|
26
|
+
try {
|
|
27
|
+
const { data } = form;
|
|
28
|
+
const { email } = data;
|
|
29
|
+
await sendPasswordReset(email);
|
|
30
|
+
toast.success("Password reset email sent");
|
|
31
|
+
goto("/sign-in");
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
toast.error(error.message);
|
|
35
|
+
} else {
|
|
36
|
+
toast.error("An error occurred");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const { form: formData, enhance } = form;
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<form method="POST" use:enhance class="space-y-4">
|
|
46
|
+
<Form.Field {form} name="email">
|
|
47
|
+
<Form.Control >
|
|
48
|
+
{#snippet children({ props })}
|
|
49
|
+
<Form.Label>Email address</Form.Label>
|
|
50
|
+
<Input {...props} bind:value={$formData.email} placeholder="you@email.com"/>
|
|
51
|
+
{/snippet}
|
|
52
|
+
|
|
53
|
+
</Form.Control>
|
|
54
|
+
<Form.FieldErrors />
|
|
55
|
+
</Form.Field>
|
|
56
|
+
|
|
57
|
+
<Form.Button class="w-full">Send Email</Form.Button>
|
|
58
|
+
</form>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const ResetPasswordForm: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type ResetPasswordForm = InstanceType<typeof ResetPasswordForm>;
|
|
18
|
+
export default ResetPasswordForm;
|