svelte-firekit 0.0.4 → 0.0.6
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 +5 -0
- package/dist/auth/sign-up.svelte +1 -1
- package/dist/components/auth/user-button/settings-dialog.svelte +95 -0
- package/dist/components/auth/user-button/settings-dialog.svelte.d.ts +2 -0
- package/dist/components/auth/{user-button.svelte → user-button/user-button.svelte} +12 -9
- package/dist/components/auth/{user-button.svelte.d.ts → user-button/user-button.svelte.d.ts} +1 -1
- package/dist/components/nav/nav.js +27 -27
- package/dist/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +1 -1
- package/dist/components/ui/dialog/dialog-content.svelte +36 -0
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +6 -0
- package/dist/components/ui/dialog/dialog-description.svelte +16 -0
- package/dist/components/ui/dialog/dialog-description.svelte.d.ts +3 -0
- package/dist/components/ui/dialog/dialog-footer.svelte +20 -0
- package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-header.svelte +20 -0
- package/dist/components/ui/dialog/dialog-header.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte +19 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +3 -0
- package/dist/components/ui/dialog/dialog-title.svelte +16 -0
- package/dist/components/ui/dialog/dialog-title.svelte.d.ts +3 -0
- package/dist/components/ui/dialog/index.d.ts +12 -0
- package/dist/components/ui/dialog/index.js +14 -0
- package/dist/components/ui/sheet/sheet-content.svelte +2 -2
- package/dist/firebase/auth/auth-guard.svelte.d.ts +13 -7
- package/dist/firebase/auth/auth-guard.svelte.js +47 -24
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Firekit is a powerful Firebase toolkit for SvelteKit applications, providing a comprehensive set of utilities, stores, and components for Firebase integration.
|
|
4
4
|
|
|
5
|
+
<h2>🚧 Under Development 🚧</h2>
|
|
6
|
+
|
|
7
|
+
<p>
|
|
8
|
+
Please note that this library is still under development. Although it's functional and can be used, some features might be incomplete or subject to changes.
|
|
9
|
+
</p>
|
|
5
10
|
## Features
|
|
6
11
|
|
|
7
12
|
- 🔥 **Firebase Integration** - Seamless Firebase setup and configuration
|
package/dist/auth/sign-up.svelte
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import SignInWithGoogle from "../components/auth/google-sign-in.svelte";
|
|
3
3
|
import SignUpForm from "../components/auth/sign-up-form.svelte";
|
|
4
4
|
import Button from "../components/ui/button/button.svelte";
|
|
5
|
-
import * as Card from "../components/ui/card";
|
|
5
|
+
import * as Card from "../components/ui/card/index.js";
|
|
6
6
|
let { title = "Sign up" }: { title: string } = $props();
|
|
7
7
|
</script>
|
|
8
8
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Breadcrumb from "../../ui/breadcrumb/index.js";
|
|
3
|
+
import { Button } from "../../ui/button/index.js";
|
|
4
|
+
import * as Dialog from "../../ui/dialog/index.js";
|
|
5
|
+
import * as Sidebar from "../../ui/sidebar/index.js";
|
|
6
|
+
|
|
7
|
+
import Lock from "lucide-svelte/icons/lock";
|
|
8
|
+
|
|
9
|
+
import { firekitUser } from "../../../firebase/auth/user.svelte.js";
|
|
10
|
+
import { User2 } from "lucide-svelte";
|
|
11
|
+
|
|
12
|
+
const data = {
|
|
13
|
+
nav: [
|
|
14
|
+
{ name: "Profile", icon: User2 },
|
|
15
|
+
{ name: "Security", icon: Lock },
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
let open = $state(false);
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<Dialog.Root bind:open>
|
|
23
|
+
<Dialog.Trigger>
|
|
24
|
+
{#snippet child({ props })}
|
|
25
|
+
<Button size="sm" {...props}>Profile</Button>
|
|
26
|
+
{/snippet}
|
|
27
|
+
</Dialog.Trigger>
|
|
28
|
+
<Dialog.Content
|
|
29
|
+
class="overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]"
|
|
30
|
+
>
|
|
31
|
+
<Dialog.Title class="sr-only">Settings</Dialog.Title>
|
|
32
|
+
<Dialog.Description class="sr-only"
|
|
33
|
+
>Customize your settings here.</Dialog.Description
|
|
34
|
+
>
|
|
35
|
+
<Sidebar.Provider class="items-start">
|
|
36
|
+
<Sidebar.Root collapsible="none" class="hidden md:flex">
|
|
37
|
+
<Sidebar.Content>
|
|
38
|
+
<Sidebar.Group>
|
|
39
|
+
<Sidebar.GroupContent>
|
|
40
|
+
<Sidebar.Menu>
|
|
41
|
+
{#each data.nav as item (item.name)}
|
|
42
|
+
<Sidebar.MenuItem>
|
|
43
|
+
<Sidebar.MenuButton
|
|
44
|
+
isActive={item.name ===
|
|
45
|
+
"Messages & media"}
|
|
46
|
+
>
|
|
47
|
+
{#snippet child({ props })}
|
|
48
|
+
<a href="##" {...props}>
|
|
49
|
+
<item.icon />
|
|
50
|
+
<span>{item.name}</span>
|
|
51
|
+
</a>
|
|
52
|
+
{/snippet}
|
|
53
|
+
</Sidebar.MenuButton>
|
|
54
|
+
</Sidebar.MenuItem>
|
|
55
|
+
{/each}
|
|
56
|
+
</Sidebar.Menu>
|
|
57
|
+
</Sidebar.GroupContent>
|
|
58
|
+
</Sidebar.Group>
|
|
59
|
+
</Sidebar.Content>
|
|
60
|
+
</Sidebar.Root>
|
|
61
|
+
<main class="flex h-[480px] flex-1 flex-col overflow-hidden">
|
|
62
|
+
<header
|
|
63
|
+
class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12"
|
|
64
|
+
>
|
|
65
|
+
<div class="flex items-center gap-2 px-4">
|
|
66
|
+
<Breadcrumb.Root>
|
|
67
|
+
<Breadcrumb.List>
|
|
68
|
+
<Breadcrumb.Item class="hidden md:block">
|
|
69
|
+
<Breadcrumb.Link href="#"
|
|
70
|
+
>Settings</Breadcrumb.Link
|
|
71
|
+
>
|
|
72
|
+
</Breadcrumb.Item>
|
|
73
|
+
<Breadcrumb.Separator class="hidden md:block" />
|
|
74
|
+
<Breadcrumb.Item>
|
|
75
|
+
<Breadcrumb.Page
|
|
76
|
+
>Messages & media</Breadcrumb.Page
|
|
77
|
+
>
|
|
78
|
+
</Breadcrumb.Item>
|
|
79
|
+
</Breadcrumb.List>
|
|
80
|
+
</Breadcrumb.Root>
|
|
81
|
+
</div>
|
|
82
|
+
</header>
|
|
83
|
+
<div
|
|
84
|
+
class="flex flex-1 flex-col gap-4 overflow-y-auto p-4 pt-0"
|
|
85
|
+
>
|
|
86
|
+
{#each Array.from({ length: 10 }) as _, i (i)}
|
|
87
|
+
<div
|
|
88
|
+
class="bg-muted/50 aspect-video max-w-3xl rounded-xl"
|
|
89
|
+
></div>
|
|
90
|
+
{/each}
|
|
91
|
+
</div>
|
|
92
|
+
</main>
|
|
93
|
+
</Sidebar.Provider>
|
|
94
|
+
</Dialog.Content>
|
|
95
|
+
</Dialog.Root>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import * as DropdownMenu from "
|
|
3
|
-
import * as Avatar from "
|
|
4
|
-
import { getInitials } from "
|
|
5
|
-
import type { NavItem } from "
|
|
2
|
+
import * as DropdownMenu from "../../ui/dropdown-menu/index.js";
|
|
3
|
+
import * as Avatar from "../../ui/avatar/index.js";
|
|
4
|
+
import { getInitials } from "../../../utils.js";
|
|
5
|
+
import type { NavItem } from "../../../types/nav.js";
|
|
6
6
|
let { nav }: { nav?: NavItem[] } = $props();
|
|
7
|
-
import * as AlertDialog from "
|
|
8
|
-
import Button from "
|
|
9
|
-
import { firekitUser } from "
|
|
10
|
-
import { firekitAuth } from "
|
|
7
|
+
import * as AlertDialog from "../../ui/alert-dialog/index.js";
|
|
8
|
+
import Button from "../../ui/button/button.svelte";
|
|
9
|
+
import { firekitUser } from "../../../firebase/auth/user.svelte.js";
|
|
10
|
+
import { firekitAuth } from "../../../firebase/auth/auth.js";
|
|
11
11
|
import { LogOut } from "lucide-svelte";
|
|
12
|
+
import SettingsDialog from "./settings-dialog.svelte";
|
|
12
13
|
let isOpen = $state(false);
|
|
13
14
|
|
|
14
15
|
async function handleLogout() {
|
|
@@ -53,7 +54,9 @@
|
|
|
53
54
|
</DropdownMenu.GroupHeading>
|
|
54
55
|
<DropdownMenu.Separator />
|
|
55
56
|
<DropdownMenu.Item onclick={() => (isOpen = true)}>
|
|
56
|
-
|
|
57
|
+
{#snippet child({ props })}
|
|
58
|
+
<SettingsDialog child({ props }) />
|
|
59
|
+
{/snippet}
|
|
57
60
|
</DropdownMenu.Item>
|
|
58
61
|
{#if nav}
|
|
59
62
|
{#each nav as { href, label }}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const nav = {
|
|
2
|
-
versions: ["0.0.3"
|
|
2
|
+
versions: ["0.0.3"],
|
|
3
3
|
navMain: [
|
|
4
4
|
{
|
|
5
5
|
title: "Getting Started",
|
|
@@ -20,7 +20,7 @@ export const nav = {
|
|
|
20
20
|
{
|
|
21
21
|
title: "Configuration",
|
|
22
22
|
url: "/docs/configuration",
|
|
23
|
-
}
|
|
23
|
+
},
|
|
24
24
|
],
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -29,12 +29,12 @@ export const nav = {
|
|
|
29
29
|
items: [
|
|
30
30
|
{
|
|
31
31
|
title: "Firebase Config",
|
|
32
|
-
url: "/docs/
|
|
32
|
+
url: "/docs/config",
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
title: "Firebase Service",
|
|
36
|
-
url: "/docs/
|
|
37
|
-
}
|
|
36
|
+
url: "/docs/service",
|
|
37
|
+
},
|
|
38
38
|
],
|
|
39
39
|
},
|
|
40
40
|
{
|
|
@@ -43,44 +43,44 @@ export const nav = {
|
|
|
43
43
|
items: [
|
|
44
44
|
{
|
|
45
45
|
title: "FirekitUser",
|
|
46
|
-
url: "/docs/
|
|
46
|
+
url: "/docs/firekit-user",
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
title: "FirekitAuth",
|
|
50
|
-
url: "/docs/
|
|
50
|
+
url: "/docs/firekit-auth",
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
title: "AuthGuard",
|
|
54
|
-
url: "/docs/auth
|
|
54
|
+
url: "/docs/firekit-auth-guard",
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
title: "Sign In Page",
|
|
58
|
-
url: "/docs/
|
|
58
|
+
url: "/docs/sign-in-page",
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
title: "Sign Up Page",
|
|
62
|
-
url: "/docs/
|
|
62
|
+
url: "/docs/sign-up-page",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
title: "Reset Password Page",
|
|
66
|
-
url: "/docs/
|
|
66
|
+
url: "/docs/reset-password-page",
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
title: "Sign In Form",
|
|
70
|
-
url: "/docs/
|
|
70
|
+
url: "/docs/sign-in-form",
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
title: "Sign Up Form",
|
|
74
|
-
url: "/docs/
|
|
74
|
+
url: "/docs/sign-up-form",
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
77
|
title: "Reset Password Form",
|
|
78
|
-
url: "/docs/
|
|
78
|
+
url: "/docs/reset-password-form",
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
title: "User Button",
|
|
82
|
-
url: "/docs/
|
|
83
|
-
}
|
|
82
|
+
url: "/docs/user-button",
|
|
83
|
+
},
|
|
84
84
|
],
|
|
85
85
|
},
|
|
86
86
|
{
|
|
@@ -89,19 +89,19 @@ export const nav = {
|
|
|
89
89
|
items: [
|
|
90
90
|
{
|
|
91
91
|
title: "FirekitDoc",
|
|
92
|
-
url: "/docs/
|
|
92
|
+
url: "/docs/firekit-doc",
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
title: "FirekitAwaitableDoc",
|
|
96
|
-
url: "/docs/
|
|
96
|
+
url: "/docs/awaitable-doc",
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
title: "FirekitCollection",
|
|
100
|
-
url: "/docs/
|
|
100
|
+
url: "/docs/firekit-collection",
|
|
101
101
|
},
|
|
102
102
|
{
|
|
103
103
|
title: "Document Mutations",
|
|
104
|
-
url: "/docs/
|
|
104
|
+
url: "/docs/document-mutations",
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
title: "Collection Component",
|
|
@@ -110,7 +110,7 @@ export const nav = {
|
|
|
110
110
|
{
|
|
111
111
|
title: "Doc Component",
|
|
112
112
|
url: "/docs/firestore/doc-component",
|
|
113
|
-
}
|
|
113
|
+
},
|
|
114
114
|
],
|
|
115
115
|
},
|
|
116
116
|
{
|
|
@@ -119,20 +119,20 @@ export const nav = {
|
|
|
119
119
|
items: [
|
|
120
120
|
{
|
|
121
121
|
title: "Download URL",
|
|
122
|
-
url: "/docs/
|
|
122
|
+
url: "/docs/download-url",
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
title: "Storage List",
|
|
126
|
-
url: "/docs/storage
|
|
126
|
+
url: "/docs/storage-list",
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
title: "Upload Task",
|
|
130
|
-
url: "/docs/
|
|
130
|
+
url: "/docs/upload-task",
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
133
|
title: "Upload Component",
|
|
134
|
-
url: "/docs/
|
|
135
|
-
}
|
|
134
|
+
url: "/docs/upload-component",
|
|
135
|
+
},
|
|
136
136
|
],
|
|
137
137
|
},
|
|
138
138
|
{
|
|
@@ -150,7 +150,7 @@ export const nav = {
|
|
|
150
150
|
{
|
|
151
151
|
title: "Performance Optimization",
|
|
152
152
|
url: "/docs/advanced/performance-optimization",
|
|
153
|
-
}
|
|
153
|
+
},
|
|
154
154
|
],
|
|
155
155
|
},
|
|
156
156
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import Ellipsis from "lucide-svelte/icons/ellipsis";
|
|
3
3
|
import type { WithElementRef, WithoutChildren } from "bits-ui";
|
|
4
4
|
import type { HTMLAttributes } from "svelte/elements";
|
|
5
5
|
import { cn } from "../../../utils.js";
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
class={cn("flex size-9 items-center justify-center", className)}
|
|
19
19
|
{...restProps}
|
|
20
20
|
>
|
|
21
|
-
<
|
|
21
|
+
<Ellipsis class="size-4" />
|
|
22
22
|
<span class="sr-only">More</span>
|
|
23
23
|
</span>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import ChevronRight from "svelte-
|
|
2
|
+
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
|
3
3
|
import type { WithElementRef } from "bits-ui";
|
|
4
4
|
import type { HTMLLiAttributes } from "svelte/elements";
|
|
5
5
|
import { cn } from "../../../utils.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog as DialogPrimitive, type WithoutChildrenOrChild } from "bits-ui";
|
|
3
|
+
import X from "lucide-svelte/icons/x";
|
|
4
|
+
import type { Snippet } from "svelte";
|
|
5
|
+
import * as Dialog from "./index.js";
|
|
6
|
+
import { cn } from "../../../utils.js";
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
ref = $bindable(null),
|
|
10
|
+
class: className,
|
|
11
|
+
children,
|
|
12
|
+
...restProps
|
|
13
|
+
}: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
|
|
14
|
+
children: Snippet;
|
|
15
|
+
} = $props();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<Dialog.Portal>
|
|
19
|
+
<Dialog.Overlay />
|
|
20
|
+
<DialogPrimitive.Content
|
|
21
|
+
bind:ref
|
|
22
|
+
class={cn(
|
|
23
|
+
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
{...restProps}
|
|
27
|
+
>
|
|
28
|
+
{@render children?.()}
|
|
29
|
+
<DialogPrimitive.Close
|
|
30
|
+
class="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
|
|
31
|
+
>
|
|
32
|
+
<X class="size-4" />
|
|
33
|
+
<span class="sr-only">Close</span>
|
|
34
|
+
</DialogPrimitive.Close>
|
|
35
|
+
</DialogPrimitive.Content>
|
|
36
|
+
</Dialog.Portal>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
declare const DialogContent: import("svelte").Component<Omit<Omit<DialogPrimitive.ContentProps, "child">, "children"> & {
|
|
4
|
+
children: Snippet;
|
|
5
|
+
}, {}, "ref">;
|
|
6
|
+
export default DialogContent;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
3
|
+
import { cn } from "../../../utils.js";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
...restProps
|
|
9
|
+
}: DialogPrimitive.DescriptionProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<DialogPrimitive.Description
|
|
13
|
+
bind:ref
|
|
14
|
+
class={cn("text-muted-foreground text-sm", className)}
|
|
15
|
+
{...restProps}
|
|
16
|
+
/>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { WithElementRef } from "bits-ui";
|
|
3
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import { cn } from "../../../utils.js";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
class: className,
|
|
9
|
+
children,
|
|
10
|
+
...restProps
|
|
11
|
+
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
bind:this={ref}
|
|
16
|
+
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
|
17
|
+
{...restProps}
|
|
18
|
+
>
|
|
19
|
+
{@render children?.()}
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import type { WithElementRef } from "bits-ui";
|
|
4
|
+
import { cn } from "../../../utils.js";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
class: className,
|
|
9
|
+
children,
|
|
10
|
+
...restProps
|
|
11
|
+
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
bind:this={ref}
|
|
16
|
+
class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)}
|
|
17
|
+
{...restProps}
|
|
18
|
+
>
|
|
19
|
+
{@render children?.()}
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
3
|
+
import { cn } from "../../../utils.js";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
...restProps
|
|
9
|
+
}: DialogPrimitive.OverlayProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<DialogPrimitive.Overlay
|
|
13
|
+
bind:ref
|
|
14
|
+
class={cn(
|
|
15
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...restProps}
|
|
19
|
+
/>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
3
|
+
import { cn } from "../../../utils.js";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
ref = $bindable(null),
|
|
7
|
+
class: className,
|
|
8
|
+
...restProps
|
|
9
|
+
}: DialogPrimitive.TitleProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<DialogPrimitive.Title
|
|
13
|
+
bind:ref
|
|
14
|
+
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
|
15
|
+
{...restProps}
|
|
16
|
+
/>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
2
|
+
import Title from "./dialog-title.svelte";
|
|
3
|
+
import Footer from "./dialog-footer.svelte";
|
|
4
|
+
import Header from "./dialog-header.svelte";
|
|
5
|
+
import Overlay from "./dialog-overlay.svelte";
|
|
6
|
+
import Content from "./dialog-content.svelte";
|
|
7
|
+
import Description from "./dialog-description.svelte";
|
|
8
|
+
declare const Root: typeof DialogPrimitive.Root;
|
|
9
|
+
declare const Trigger: typeof DialogPrimitive.Trigger;
|
|
10
|
+
declare const Close: typeof DialogPrimitive.Close;
|
|
11
|
+
declare const Portal: typeof DialogPrimitive.Portal;
|
|
12
|
+
export { Root, Title, Portal, Footer, Header, Trigger, Overlay, Content, Description, Close, Root as Dialog, Title as DialogTitle, Portal as DialogPortal, Footer as DialogFooter, Header as DialogHeader, Trigger as DialogTrigger, Overlay as DialogOverlay, Content as DialogContent, Description as DialogDescription, Close as DialogClose, };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Dialog as DialogPrimitive } from "bits-ui";
|
|
2
|
+
import Title from "./dialog-title.svelte";
|
|
3
|
+
import Footer from "./dialog-footer.svelte";
|
|
4
|
+
import Header from "./dialog-header.svelte";
|
|
5
|
+
import Overlay from "./dialog-overlay.svelte";
|
|
6
|
+
import Content from "./dialog-content.svelte";
|
|
7
|
+
import Description from "./dialog-description.svelte";
|
|
8
|
+
const Root = DialogPrimitive.Root;
|
|
9
|
+
const Trigger = DialogPrimitive.Trigger;
|
|
10
|
+
const Close = DialogPrimitive.Close;
|
|
11
|
+
const Portal = DialogPrimitive.Portal;
|
|
12
|
+
export { Root, Title, Portal, Footer, Header, Trigger, Overlay, Content, Description, Close,
|
|
13
|
+
//
|
|
14
|
+
Root as Dialog, Title as DialogTitle, Portal as DialogPortal, Footer as DialogFooter, Header as DialogHeader, Trigger as DialogTrigger, Overlay as DialogOverlay, Content as DialogContent, Description as DialogDescription, Close as DialogClose, };
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
<script lang="ts">
|
|
23
23
|
import { Dialog as SheetPrimitive, type WithoutChildrenOrChild } from "bits-ui";
|
|
24
|
-
import
|
|
24
|
+
import X from "lucide-svelte/icons/x";
|
|
25
25
|
import type { Snippet } from "svelte";
|
|
26
26
|
import SheetOverlay from "./sheet-overlay.svelte";
|
|
27
27
|
import { cn } from "../../../utils.js";
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<SheetPrimitive.Close
|
|
46
46
|
class="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"
|
|
47
47
|
>
|
|
48
|
-
<
|
|
48
|
+
<X class="size-4" />
|
|
49
49
|
<span class="sr-only">Close</span>
|
|
50
50
|
</SheetPrimitive.Close>
|
|
51
51
|
</SheetPrimitive.Content>
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import type { DocumentData } from "firebase/firestore";
|
|
2
2
|
import { firekitUser } from "./user.svelte.js";
|
|
3
|
-
|
|
3
|
+
interface GuardConfig {
|
|
4
4
|
authRequired?: boolean;
|
|
5
5
|
redirectTo?: string;
|
|
6
6
|
requiredClaims?: string[];
|
|
7
7
|
requiredData?: (data: DocumentData | null) => boolean;
|
|
8
8
|
allowIf?: (user: typeof firekitUser) => boolean;
|
|
9
|
-
|
|
9
|
+
redirectParams?: Record<string, string>;
|
|
10
|
+
}
|
|
10
11
|
export declare class FirekitAuthGuard {
|
|
11
12
|
private static instance;
|
|
12
13
|
private _loading;
|
|
13
14
|
private _error;
|
|
15
|
+
private _lastValidationTime;
|
|
16
|
+
private readonly VALIDATION_THROTTLE;
|
|
14
17
|
private constructor();
|
|
15
18
|
static getInstance(): FirekitAuthGuard;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
private shouldThrottleValidation;
|
|
20
|
+
private handleRedirect;
|
|
21
|
+
private validateClaims;
|
|
22
|
+
validateAuth({ authRequired, redirectTo, requiredClaims, requiredData, allowIf, redirectParams }?: GuardConfig): Promise<boolean>;
|
|
23
|
+
requireAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
|
|
24
|
+
requireNoAuth(redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
|
|
25
|
+
requireClaims(claims: string[], redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
|
|
26
|
+
requireData(validator: (data: DocumentData | null) => boolean, redirectTo?: string, redirectParams?: Record<string, string>): Promise<boolean>;
|
|
21
27
|
get loading(): boolean;
|
|
22
28
|
get error(): Error | null;
|
|
23
29
|
}
|
|
@@ -5,6 +5,8 @@ export class FirekitAuthGuard {
|
|
|
5
5
|
static instance;
|
|
6
6
|
_loading = $state(true);
|
|
7
7
|
_error = $state(null);
|
|
8
|
+
_lastValidationTime = 0;
|
|
9
|
+
VALIDATION_THROTTLE = 1000; // 1 second
|
|
8
10
|
constructor() { }
|
|
9
11
|
static getInstance() {
|
|
10
12
|
if (!FirekitAuthGuard.instance) {
|
|
@@ -12,62 +14,83 @@ export class FirekitAuthGuard {
|
|
|
12
14
|
}
|
|
13
15
|
return FirekitAuthGuard.instance;
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
shouldThrottleValidation() {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
if (now - this._lastValidationTime < this.VALIDATION_THROTTLE) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
this._lastValidationTime = now;
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
async handleRedirect(redirectTo, params) {
|
|
26
|
+
const url = new URL(redirectTo, window.location.origin);
|
|
27
|
+
if (params) {
|
|
28
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
29
|
+
url.searchParams.append(key, value);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
await goto(url.toString());
|
|
33
|
+
}
|
|
34
|
+
async validateClaims(requiredClaims, userClaims) {
|
|
35
|
+
if (!requiredClaims.length)
|
|
36
|
+
return true;
|
|
37
|
+
if (!userClaims)
|
|
38
|
+
return false;
|
|
39
|
+
return requiredClaims.every(claim => userClaims[claim]);
|
|
40
|
+
}
|
|
41
|
+
async validateAuth({ authRequired = true, redirectTo = '/login', requiredClaims = [], requiredData, allowIf, redirectParams } = {}) {
|
|
16
42
|
if (!browser)
|
|
17
|
-
return;
|
|
43
|
+
return true;
|
|
44
|
+
if (this.shouldThrottleValidation())
|
|
45
|
+
return true;
|
|
18
46
|
try {
|
|
19
47
|
this._loading = true;
|
|
20
48
|
this._error = null;
|
|
21
|
-
// Wait for auth state to be determined
|
|
22
|
-
// if (firekitUser.loading) {
|
|
23
|
-
// await new Promise((resolve) => setTimeout(resolve, 100));
|
|
24
|
-
// }
|
|
25
49
|
const isAuthenticated = firekitUser.isLoggedIn;
|
|
26
|
-
// Handle authentication requirement
|
|
27
50
|
if (authRequired && !isAuthenticated) {
|
|
28
|
-
await
|
|
51
|
+
await this.handleRedirect(redirectTo, {
|
|
52
|
+
...redirectParams,
|
|
53
|
+
returnTo: window.location.pathname
|
|
54
|
+
});
|
|
29
55
|
return false;
|
|
30
56
|
}
|
|
31
|
-
// Handle custom conditions if provided
|
|
32
57
|
if (allowIf && !allowIf(firekitUser)) {
|
|
33
|
-
await
|
|
58
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
34
59
|
return false;
|
|
35
60
|
}
|
|
36
|
-
// Handle required claims if any
|
|
37
61
|
if (requiredClaims.length > 0) {
|
|
38
62
|
const userClaims = await firekitUser.user?.getIdTokenResult();
|
|
39
|
-
const hasClaims =
|
|
63
|
+
const hasClaims = await this.validateClaims(requiredClaims, userClaims?.claims);
|
|
40
64
|
if (!hasClaims) {
|
|
41
|
-
await
|
|
65
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
42
66
|
return false;
|
|
43
67
|
}
|
|
44
68
|
}
|
|
45
|
-
// Handle required data validation if provided
|
|
46
69
|
if (requiredData && !requiredData(firekitUser.data)) {
|
|
47
|
-
await
|
|
70
|
+
await this.handleRedirect(redirectTo, redirectParams);
|
|
48
71
|
return false;
|
|
49
72
|
}
|
|
50
73
|
return true;
|
|
51
74
|
}
|
|
52
75
|
catch (error) {
|
|
53
|
-
this._error = error;
|
|
76
|
+
this._error = error instanceof Error ? error : new Error(String(error));
|
|
54
77
|
return false;
|
|
55
78
|
}
|
|
56
79
|
finally {
|
|
57
80
|
this._loading = false;
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
|
-
async requireAuth(redirectTo = '/login') {
|
|
61
|
-
return this.validateAuth({ authRequired: true, redirectTo });
|
|
83
|
+
async requireAuth(redirectTo = '/login', redirectParams) {
|
|
84
|
+
return this.validateAuth({ authRequired: true, redirectTo, redirectParams });
|
|
62
85
|
}
|
|
63
|
-
async requireNoAuth(redirectTo = '/dashboard') {
|
|
64
|
-
return this.validateAuth({ authRequired: false, redirectTo });
|
|
86
|
+
async requireNoAuth(redirectTo = '/dashboard', redirectParams) {
|
|
87
|
+
return this.validateAuth({ authRequired: false, redirectTo, redirectParams });
|
|
65
88
|
}
|
|
66
|
-
async requireClaims(claims, redirectTo = '/login') {
|
|
67
|
-
return this.validateAuth({ requiredClaims: claims, redirectTo });
|
|
89
|
+
async requireClaims(claims, redirectTo = '/login', redirectParams) {
|
|
90
|
+
return this.validateAuth({ requiredClaims: claims, redirectTo, redirectParams });
|
|
68
91
|
}
|
|
69
|
-
async requireData(validator, redirectTo = '/login') {
|
|
70
|
-
return this.validateAuth({ requiredData: validator, redirectTo });
|
|
92
|
+
async requireData(validator, redirectTo = '/login', redirectParams) {
|
|
93
|
+
return this.validateAuth({ requiredData: validator, redirectTo, redirectParams });
|
|
71
94
|
}
|
|
72
95
|
get loading() {
|
|
73
96
|
return this._loading;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { default as ResetPassWordPage } from './auth/reset-password.svelte';
|
|
|
16
16
|
export { default as ResetPassWordForm } from './components/auth/reset-password-form.svelte';
|
|
17
17
|
export { default as SignInForm } from './components/auth/sign-in-form.svelte';
|
|
18
18
|
export { default as SignUpForm } from './components/auth/sign-up-form.svelte';
|
|
19
|
-
export { default as UserButton } from './components/auth/user-button.svelte';
|
|
19
|
+
export { default as UserButton } from './components/auth/user-button/user-button.svelte';
|
|
20
20
|
export { default as Collection } from './components/firestore/collection.svelte';
|
|
21
21
|
export { default as Doc } from './components/firestore/doc.svelte';
|
|
22
22
|
export { default as Upload } from './components/storage/upload.svelte';
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ export { default as ResetPassWordPage } from './auth/reset-password.svelte';
|
|
|
21
21
|
export { default as ResetPassWordForm } from './components/auth/reset-password-form.svelte';
|
|
22
22
|
export { default as SignInForm } from './components/auth/sign-in-form.svelte';
|
|
23
23
|
export { default as SignUpForm } from './components/auth/sign-up-form.svelte';
|
|
24
|
-
export { default as UserButton } from './components/auth/user-button.svelte';
|
|
24
|
+
export { default as UserButton } from './components/auth/user-button/user-button.svelte';
|
|
25
25
|
// firestore components
|
|
26
26
|
export { default as Collection } from './components/firestore/collection.svelte';
|
|
27
27
|
export { default as Doc } from './components/firestore/doc.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-firekit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite dev",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
|
54
54
|
"@tailwindcss/typography": "^0.5.15",
|
|
55
55
|
"autoprefixer": "^10.4.20",
|
|
56
|
-
"bits-ui": "^1.0.0-next.
|
|
56
|
+
"bits-ui": "^1.0.0-next.60",
|
|
57
57
|
"clsx": "^2.1.1",
|
|
58
58
|
"formsnap": "^2.0.0-next.1",
|
|
59
59
|
"lucide-svelte": "^0.456.0",
|