yaxa-svelte 1.0.0
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 +163 -0
- package/dist/assets/favicon.svg +15 -0
- package/dist/components/elements/Avatar.svelte +106 -0
- package/dist/components/elements/Avatar.svelte.d.ts +40 -0
- package/dist/components/elements/AvatarGroup.svelte +18 -0
- package/dist/components/elements/AvatarGroup.svelte.d.ts +8 -0
- package/dist/components/elements/Badge.svelte +202 -0
- package/dist/components/elements/Badge.svelte.d.ts +75 -0
- package/dist/components/elements/Button.svelte +300 -0
- package/dist/components/elements/Button.svelte.d.ts +109 -0
- package/dist/components/elements/ButtonGroup.svelte +22 -0
- package/dist/components/elements/ButtonGroup.svelte.d.ts +9 -0
- package/dist/components/elements/Chip.svelte +117 -0
- package/dist/components/elements/Chip.svelte.d.ts +15 -0
- package/dist/components/elements/DataTable.svelte +222 -0
- package/dist/components/elements/DataTable.svelte.d.ts +43 -0
- package/dist/components/elements/Icon.svelte +87 -0
- package/dist/components/elements/Icon.svelte.d.ts +10 -0
- package/dist/components/elements/Kbd.svelte +37 -0
- package/dist/components/elements/Kbd.svelte.d.ts +32 -0
- package/dist/components/elements/Link.svelte +63 -0
- package/dist/components/elements/Link.svelte.d.ts +15 -0
- package/dist/components/elements/Logo.svelte +77 -0
- package/dist/components/elements/Logo.svelte.d.ts +9 -0
- package/dist/components/elements/Meter.svelte +87 -0
- package/dist/components/elements/Meter.svelte.d.ts +14 -0
- package/dist/components/elements/Progress.svelte +63 -0
- package/dist/components/elements/Progress.svelte.d.ts +49 -0
- package/dist/components/elements/Skeleton.svelte +12 -0
- package/dist/components/elements/Skeleton.svelte.d.ts +6 -0
- package/dist/components/elements/Spinner.svelte +39 -0
- package/dist/components/elements/Spinner.svelte.d.ts +7 -0
- package/dist/components/forms/Checkbox.svelte +77 -0
- package/dist/components/forms/Checkbox.svelte.d.ts +17 -0
- package/dist/components/forms/ColorPicker.svelte +142 -0
- package/dist/components/forms/ColorPicker.svelte.d.ts +10 -0
- package/dist/components/forms/Form.svelte +84 -0
- package/dist/components/forms/Form.svelte.d.ts +14 -0
- package/dist/components/forms/FormField.svelte +56 -0
- package/dist/components/forms/FormField.svelte.d.ts +14 -0
- package/dist/components/forms/Input.svelte +138 -0
- package/dist/components/forms/Input.svelte.d.ts +58 -0
- package/dist/components/forms/RadioGroup.svelte +74 -0
- package/dist/components/forms/RadioGroup.svelte.d.ts +17 -0
- package/dist/components/forms/Select.svelte +91 -0
- package/dist/components/forms/Select.svelte.d.ts +50 -0
- package/dist/components/forms/Slider.svelte +37 -0
- package/dist/components/forms/Slider.svelte.d.ts +12 -0
- package/dist/components/forms/Switch.svelte +81 -0
- package/dist/components/forms/Switch.svelte.d.ts +53 -0
- package/dist/components/forms/Textarea.svelte +73 -0
- package/dist/components/forms/Textarea.svelte.d.ts +64 -0
- package/dist/components/layout/Card.svelte +89 -0
- package/dist/components/layout/Card.svelte.d.ts +64 -0
- package/dist/components/layout/Container.svelte +36 -0
- package/dist/components/layout/Container.svelte.d.ts +37 -0
- package/dist/components/layout/Divider.svelte +45 -0
- package/dist/components/layout/Divider.svelte.d.ts +11 -0
- package/dist/components/layout/Footer.svelte +96 -0
- package/dist/components/layout/Footer.svelte.d.ts +10 -0
- package/dist/components/layout/Header.svelte +175 -0
- package/dist/components/layout/Header.svelte.d.ts +12 -0
- package/dist/components/layout/Section.svelte +62 -0
- package/dist/components/layout/Section.svelte.d.ts +14 -0
- package/dist/components/layout/YaxaApp.svelte +48 -0
- package/dist/components/layout/YaxaApp.svelte.d.ts +12 -0
- package/dist/components/navigation/Breadcrumb.svelte +58 -0
- package/dist/components/navigation/Breadcrumb.svelte.d.ts +13 -0
- package/dist/components/navigation/CommandPalette.svelte +201 -0
- package/dist/components/navigation/CommandPalette.svelte.d.ts +19 -0
- package/dist/components/navigation/DropdownMenu.svelte +75 -0
- package/dist/components/navigation/DropdownMenu.svelte.d.ts +20 -0
- package/dist/components/navigation/Pagination.svelte +106 -0
- package/dist/components/navigation/Pagination.svelte.d.ts +10 -0
- package/dist/components/navigation/Tabs.svelte +91 -0
- package/dist/components/navigation/Tabs.svelte.d.ts +18 -0
- package/dist/components/overlays/Accordion.svelte +54 -0
- package/dist/components/overlays/Accordion.svelte.d.ts +16 -0
- package/dist/components/overlays/Alert.svelte +110 -0
- package/dist/components/overlays/Alert.svelte.d.ts +37 -0
- package/dist/components/overlays/ContextMenu.svelte +67 -0
- package/dist/components/overlays/ContextMenu.svelte.d.ts +21 -0
- package/dist/components/overlays/Modal.svelte +99 -0
- package/dist/components/overlays/Modal.svelte.d.ts +40 -0
- package/dist/components/overlays/Popover.svelte +33 -0
- package/dist/components/overlays/Popover.svelte.d.ts +11 -0
- package/dist/components/overlays/Slideover.svelte +102 -0
- package/dist/components/overlays/Slideover.svelte.d.ts +37 -0
- package/dist/components/overlays/Tooltip.svelte +39 -0
- package/dist/components/overlays/Tooltip.svelte.d.ts +12 -0
- package/dist/components/saas/AuthCard.svelte +273 -0
- package/dist/components/saas/AuthCard.svelte.d.ts +16 -0
- package/dist/components/saas/PricingCard.svelte +166 -0
- package/dist/components/saas/PricingCard.svelte.d.ts +19 -0
- package/dist/components/saas/PricingTable.svelte +139 -0
- package/dist/components/saas/PricingTable.svelte.d.ts +11 -0
- package/dist/components/saas/SubscriptionCard.svelte +162 -0
- package/dist/components/saas/SubscriptionCard.svelte.d.ts +16 -0
- package/dist/components/saas/UserMenu.svelte +137 -0
- package/dist/components/saas/UserMenu.svelte.d.ts +19 -0
- package/dist/components/seo/Favicons.svelte +22 -0
- package/dist/components/seo/Favicons.svelte.d.ts +8 -0
- package/dist/components/seo/OgImage.svelte +61 -0
- package/dist/components/seo/OgImage.svelte.d.ts +12 -0
- package/dist/components/seo/Seo.svelte +170 -0
- package/dist/components/seo/Seo.svelte.d.ts +21 -0
- package/dist/composables/useAuth.svelte.d.ts +23 -0
- package/dist/composables/useAuth.svelte.js +157 -0
- package/dist/composables/useClipboard.svelte.d.ts +9 -0
- package/dist/composables/useClipboard.svelte.js +36 -0
- package/dist/composables/useColorMode.svelte.d.ts +8 -0
- package/dist/composables/useColorMode.svelte.js +20 -0
- package/dist/composables/useDebounce.svelte.d.ts +3 -0
- package/dist/composables/useDebounce.svelte.js +17 -0
- package/dist/composables/useMediaQuery.svelte.d.ts +3 -0
- package/dist/composables/useMediaQuery.svelte.js +17 -0
- package/dist/composables/useShortcuts.svelte.d.ts +10 -0
- package/dist/composables/useShortcuts.svelte.js +50 -0
- package/dist/composables/useToast.d.ts +19 -0
- package/dist/composables/useToast.js +34 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +92 -0
- package/dist/server/auth/hook.d.ts +14 -0
- package/dist/server/auth/hook.js +36 -0
- package/dist/server/auth/index.d.ts +39 -0
- package/dist/server/auth/index.js +69 -0
- package/dist/server/db/index.d.ts +18 -0
- package/dist/server/db/index.js +43 -0
- package/dist/server/db/schema-pg.d.ts +977 -0
- package/dist/server/db/schema-pg.js +83 -0
- package/dist/server/db/schema-sqlite.d.ts +1045 -0
- package/dist/server/db/schema-sqlite.js +83 -0
- package/dist/server/db/types.d.ts +44 -0
- package/dist/server/db/types.js +1 -0
- package/dist/server/email/index.d.ts +27 -0
- package/dist/server/email/index.js +79 -0
- package/dist/server/polar/index.d.ts +29 -0
- package/dist/server/polar/index.js +49 -0
- package/dist/server/polar/webhook.d.ts +16 -0
- package/dist/server/polar/webhook.js +118 -0
- package/dist/site/config.d.ts +63 -0
- package/dist/site/config.js +48 -0
- package/dist/site/context.d.ts +11 -0
- package/dist/site/context.js +23 -0
- package/dist/site/hook.d.ts +15 -0
- package/dist/site/hook.js +38 -0
- package/dist/site/manifest.d.ts +6 -0
- package/dist/site/manifest.js +32 -0
- package/dist/site/og.d.ts +14 -0
- package/dist/site/og.js +116 -0
- package/dist/site/robots.d.ts +10 -0
- package/dist/site/robots.js +54 -0
- package/dist/site/schema.d.ts +67 -0
- package/dist/site/schema.js +67 -0
- package/dist/site/seo-helpers.d.ts +36 -0
- package/dist/site/seo-helpers.js +21 -0
- package/dist/site/sitemap-xsl.d.ts +6 -0
- package/dist/site/sitemap-xsl.js +164 -0
- package/dist/site/sitemap.d.ts +20 -0
- package/dist/site/sitemap.js +61 -0
- package/dist/styles/yaxa.css +84 -0
- package/dist/theme/theme.svelte.d.ts +74 -0
- package/dist/theme/theme.svelte.js +421 -0
- package/dist/utils/cn.d.ts +3 -0
- package/dist/utils/cn.js +3 -0
- package/dist/vite/index.d.ts +20 -0
- package/dist/vite/index.js +29 -0
- package/package.json +108 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type VariantProps } from '../../utils/cn';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
export declare const modalVariants: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
size: {
|
|
5
|
+
sm: "max-w-sm";
|
|
6
|
+
md: "max-w-lg";
|
|
7
|
+
lg: "max-w-2xl";
|
|
8
|
+
xl: "max-w-4xl";
|
|
9
|
+
full: "max-w-[calc(100vw-2rem)] h-[calc(100vh-2rem)]";
|
|
10
|
+
};
|
|
11
|
+
}, undefined, "fixed left-1/2 top-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-neutral-200 bg-white p-6 shadow-2xl duration-200 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 dark:border-neutral-800 dark:bg-neutral-900", {
|
|
12
|
+
size: {
|
|
13
|
+
sm: "max-w-sm";
|
|
14
|
+
md: "max-w-lg";
|
|
15
|
+
lg: "max-w-2xl";
|
|
16
|
+
xl: "max-w-4xl";
|
|
17
|
+
full: "max-w-[calc(100vw-2rem)] h-[calc(100vh-2rem)]";
|
|
18
|
+
};
|
|
19
|
+
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
20
|
+
size: {
|
|
21
|
+
sm: "max-w-sm";
|
|
22
|
+
md: "max-w-lg";
|
|
23
|
+
lg: "max-w-2xl";
|
|
24
|
+
xl: "max-w-4xl";
|
|
25
|
+
full: "max-w-[calc(100vw-2rem)] h-[calc(100vh-2rem)]";
|
|
26
|
+
};
|
|
27
|
+
}, undefined>>;
|
|
28
|
+
export type ModalProps = VariantProps<typeof modalVariants> & {
|
|
29
|
+
open?: boolean;
|
|
30
|
+
title?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
trigger?: Snippet;
|
|
33
|
+
header?: Snippet;
|
|
34
|
+
footer?: Snippet;
|
|
35
|
+
children?: Snippet;
|
|
36
|
+
class?: string;
|
|
37
|
+
};
|
|
38
|
+
declare const Modal: import("svelte").Component<ModalProps, {}, "open">;
|
|
39
|
+
type Modal = ReturnType<typeof Modal>;
|
|
40
|
+
export default Modal;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Popover } from 'bits-ui';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
open?: boolean;
|
|
7
|
+
trigger?: Snippet;
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
class?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let { open = $bindable(false), trigger, children, class: className = '' }: Props = $props();
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<Popover.Root bind:open>
|
|
16
|
+
{#if trigger}
|
|
17
|
+
<Popover.Trigger class="inline-flex">
|
|
18
|
+
{@render trigger()}
|
|
19
|
+
</Popover.Trigger>
|
|
20
|
+
{/if}
|
|
21
|
+
|
|
22
|
+
<Popover.Portal>
|
|
23
|
+
<Popover.Content
|
|
24
|
+
class="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 z-50 rounded-xl border border-neutral-200 bg-white p-4 shadow-xl duration-150 outline-none dark:border-neutral-800 dark:bg-neutral-900 {className}"
|
|
25
|
+
sideOffset={8}
|
|
26
|
+
>
|
|
27
|
+
{#if children}
|
|
28
|
+
{@render children()}
|
|
29
|
+
{/if}
|
|
30
|
+
<Popover.Arrow class="fill-neutral-200 dark:fill-neutral-800" />
|
|
31
|
+
</Popover.Content>
|
|
32
|
+
</Popover.Portal>
|
|
33
|
+
</Popover.Root>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Popover } from 'bits-ui';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
open?: boolean;
|
|
5
|
+
trigger?: Snippet;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const Popover: import("svelte").Component<Props, {}, "open">;
|
|
10
|
+
type Popover = ReturnType<typeof Popover>;
|
|
11
|
+
export default Popover;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import { tv, type VariantProps } from '../../utils/cn';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
export const slideoverVariants = tv({
|
|
6
|
+
base: 'fixed z-50 flex flex-col border-neutral-200 bg-white p-6 shadow-2xl transition-transform duration-300 dark:border-neutral-800 dark:bg-neutral-900',
|
|
7
|
+
variants: {
|
|
8
|
+
side: {
|
|
9
|
+
right:
|
|
10
|
+
'inset-y-0 right-0 h-full w-full max-w-md border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0',
|
|
11
|
+
left: 'inset-y-0 left-0 h-full w-full max-w-md border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0',
|
|
12
|
+
top: 'inset-x-0 top-0 w-full max-h-[80vh] border-b data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0',
|
|
13
|
+
bottom:
|
|
14
|
+
'inset-x-0 bottom-0 w-full max-h-[80vh] rounded-t-2xl border-t data-[state=closed]:translate-y-full data-[state=open]:translate-y-0'
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
side: 'right'
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export type SlideoverProps = VariantProps<typeof slideoverVariants> & {
|
|
23
|
+
open?: boolean;
|
|
24
|
+
title?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
trigger?: Snippet;
|
|
27
|
+
header?: Snippet;
|
|
28
|
+
footer?: Snippet;
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
class?: string;
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<script lang="ts">
|
|
35
|
+
import { Dialog } from 'bits-ui';
|
|
36
|
+
import Icon from '../elements/Icon.svelte';
|
|
37
|
+
|
|
38
|
+
let {
|
|
39
|
+
open = $bindable(false),
|
|
40
|
+
side = 'right',
|
|
41
|
+
title,
|
|
42
|
+
description,
|
|
43
|
+
trigger,
|
|
44
|
+
header,
|
|
45
|
+
footer,
|
|
46
|
+
children,
|
|
47
|
+
class: className = ''
|
|
48
|
+
}: SlideoverProps = $props();
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<Dialog.Root bind:open>
|
|
52
|
+
{#if trigger}
|
|
53
|
+
<Dialog.Trigger class="inline-flex">
|
|
54
|
+
{@render trigger()}
|
|
55
|
+
</Dialog.Trigger>
|
|
56
|
+
{/if}
|
|
57
|
+
|
|
58
|
+
<Dialog.Portal>
|
|
59
|
+
<Dialog.Overlay
|
|
60
|
+
class="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-neutral-900/60 backdrop-blur-xs duration-300"
|
|
61
|
+
/>
|
|
62
|
+
<Dialog.Content class={slideoverVariants({ side, class: className })}>
|
|
63
|
+
{#if header}
|
|
64
|
+
{@render header()}
|
|
65
|
+
{:else if title || description}
|
|
66
|
+
<div class="mb-4">
|
|
67
|
+
{#if title}
|
|
68
|
+
<Dialog.Title class="text-lg font-bold text-neutral-900 dark:text-white">
|
|
69
|
+
{title}
|
|
70
|
+
</Dialog.Title>
|
|
71
|
+
{/if}
|
|
72
|
+
{#if description}
|
|
73
|
+
<Dialog.Description class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
|
74
|
+
{description}
|
|
75
|
+
</Dialog.Description>
|
|
76
|
+
{/if}
|
|
77
|
+
</div>
|
|
78
|
+
{/if}
|
|
79
|
+
|
|
80
|
+
{#if children}
|
|
81
|
+
<div class="my-2 flex-1 overflow-y-auto">
|
|
82
|
+
{@render children()}
|
|
83
|
+
</div>
|
|
84
|
+
{/if}
|
|
85
|
+
|
|
86
|
+
{#if footer}
|
|
87
|
+
<div
|
|
88
|
+
class="mt-6 flex justify-end gap-3 border-t border-neutral-100 pt-4 dark:border-neutral-800"
|
|
89
|
+
>
|
|
90
|
+
{@render footer()}
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
93
|
+
|
|
94
|
+
<Dialog.Close
|
|
95
|
+
class="absolute top-4 right-4 rounded-lg p-1 text-neutral-400 hover:bg-neutral-100 hover:text-neutral-600 dark:hover:bg-neutral-800 dark:hover:text-neutral-200"
|
|
96
|
+
aria-label="Close slideover"
|
|
97
|
+
>
|
|
98
|
+
<Icon name="cross" size="sm" />
|
|
99
|
+
</Dialog.Close>
|
|
100
|
+
</Dialog.Content>
|
|
101
|
+
</Dialog.Portal>
|
|
102
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type VariantProps } from '../../utils/cn';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
export declare const slideoverVariants: import("tailwind-variants").TVReturnType<{
|
|
4
|
+
side: {
|
|
5
|
+
right: "inset-y-0 right-0 h-full w-full max-w-md border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0";
|
|
6
|
+
left: "inset-y-0 left-0 h-full w-full max-w-md border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0";
|
|
7
|
+
top: "inset-x-0 top-0 w-full max-h-[80vh] border-b data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0";
|
|
8
|
+
bottom: "inset-x-0 bottom-0 w-full max-h-[80vh] rounded-t-2xl border-t data-[state=closed]:translate-y-full data-[state=open]:translate-y-0";
|
|
9
|
+
};
|
|
10
|
+
}, undefined, "fixed z-50 flex flex-col border-neutral-200 bg-white p-6 shadow-2xl transition-transform duration-300 dark:border-neutral-800 dark:bg-neutral-900", {
|
|
11
|
+
side: {
|
|
12
|
+
right: "inset-y-0 right-0 h-full w-full max-w-md border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0";
|
|
13
|
+
left: "inset-y-0 left-0 h-full w-full max-w-md border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0";
|
|
14
|
+
top: "inset-x-0 top-0 w-full max-h-[80vh] border-b data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0";
|
|
15
|
+
bottom: "inset-x-0 bottom-0 w-full max-h-[80vh] rounded-t-2xl border-t data-[state=closed]:translate-y-full data-[state=open]:translate-y-0";
|
|
16
|
+
};
|
|
17
|
+
}, undefined, import("tailwind-variants").TVReturnTypeLike<{
|
|
18
|
+
side: {
|
|
19
|
+
right: "inset-y-0 right-0 h-full w-full max-w-md border-l data-[state=closed]:translate-x-full data-[state=open]:translate-x-0";
|
|
20
|
+
left: "inset-y-0 left-0 h-full w-full max-w-md border-r data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0";
|
|
21
|
+
top: "inset-x-0 top-0 w-full max-h-[80vh] border-b data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0";
|
|
22
|
+
bottom: "inset-x-0 bottom-0 w-full max-h-[80vh] rounded-t-2xl border-t data-[state=closed]:translate-y-full data-[state=open]:translate-y-0";
|
|
23
|
+
};
|
|
24
|
+
}, undefined>>;
|
|
25
|
+
export type SlideoverProps = VariantProps<typeof slideoverVariants> & {
|
|
26
|
+
open?: boolean;
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
trigger?: Snippet;
|
|
30
|
+
header?: Snippet;
|
|
31
|
+
footer?: Snippet;
|
|
32
|
+
children?: Snippet;
|
|
33
|
+
class?: string;
|
|
34
|
+
};
|
|
35
|
+
declare const Slideover: import("svelte").Component<SlideoverProps, {}, "open">;
|
|
36
|
+
type Slideover = ReturnType<typeof Slideover>;
|
|
37
|
+
export default Slideover;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Tooltip } from 'bits-ui';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
text?: string;
|
|
7
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
8
|
+
trigger?: Snippet;
|
|
9
|
+
content?: Snippet;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { text, side = 'top', trigger, content, children }: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<Tooltip.Root>
|
|
17
|
+
<Tooltip.Trigger class="inline-flex">
|
|
18
|
+
{#if trigger}
|
|
19
|
+
{@render trigger()}
|
|
20
|
+
{:else if children}
|
|
21
|
+
{@render children()}
|
|
22
|
+
{/if}
|
|
23
|
+
</Tooltip.Trigger>
|
|
24
|
+
|
|
25
|
+
<Tooltip.Portal>
|
|
26
|
+
<Tooltip.Content
|
|
27
|
+
{side}
|
|
28
|
+
sideOffset={6}
|
|
29
|
+
class="animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 overflow-hidden rounded-md bg-neutral-900 px-3 py-1.5 text-sm font-medium text-white shadow-md dark:bg-neutral-100 dark:text-neutral-900"
|
|
30
|
+
>
|
|
31
|
+
{#if content}
|
|
32
|
+
{@render content()}
|
|
33
|
+
{:else if text}
|
|
34
|
+
{text}
|
|
35
|
+
{/if}
|
|
36
|
+
<Tooltip.Arrow class="fill-neutral-900 dark:fill-neutral-100" />
|
|
37
|
+
</Tooltip.Content>
|
|
38
|
+
</Tooltip.Portal>
|
|
39
|
+
</Tooltip.Root>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Tooltip } from 'bits-ui';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
text?: string;
|
|
5
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
6
|
+
trigger?: Snippet;
|
|
7
|
+
content?: Snippet;
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
}
|
|
10
|
+
declare const Tooltip: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type Tooltip = ReturnType<typeof Tooltip>;
|
|
12
|
+
export default Tooltip;
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Card from '../layout/Card.svelte';
|
|
3
|
+
import Button from '../elements/Button.svelte';
|
|
4
|
+
import Input from '../forms/Input.svelte';
|
|
5
|
+
import FormField from '../forms/FormField.svelte';
|
|
6
|
+
import Divider from '../layout/Divider.svelte';
|
|
7
|
+
import Alert from '../overlays/Alert.svelte';
|
|
8
|
+
import Icon from '../elements/Icon.svelte';
|
|
9
|
+
import { useAuth, type SocialProvider } from '../../composables/useAuth.svelte';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
title?: string;
|
|
13
|
+
subtitle?: string;
|
|
14
|
+
mode?: 'signin' | 'signup' | 'magic-link';
|
|
15
|
+
providers?: SocialProvider[];
|
|
16
|
+
showSocial?: boolean;
|
|
17
|
+
showMagicLinkToggle?: boolean;
|
|
18
|
+
callbackURL?: string;
|
|
19
|
+
class?: string;
|
|
20
|
+
onsuccess?: () => void;
|
|
21
|
+
onerror?: (err: string) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
title,
|
|
26
|
+
subtitle,
|
|
27
|
+
mode = 'signin',
|
|
28
|
+
providers = ['github', 'google'],
|
|
29
|
+
showSocial = true,
|
|
30
|
+
showMagicLinkToggle = true,
|
|
31
|
+
callbackURL = '/dashboard',
|
|
32
|
+
class: className = '',
|
|
33
|
+
onsuccess,
|
|
34
|
+
onerror
|
|
35
|
+
}: Props = $props();
|
|
36
|
+
|
|
37
|
+
const auth = useAuth();
|
|
38
|
+
|
|
39
|
+
let customMode = $state<'signin' | 'signup' | 'magic-link' | null>(null);
|
|
40
|
+
let currentMode = $derived(customMode ?? mode);
|
|
41
|
+
|
|
42
|
+
let name = $state('');
|
|
43
|
+
let email = $state('');
|
|
44
|
+
let password = $state('');
|
|
45
|
+
let localError = $state<string | null>(null);
|
|
46
|
+
let magicLinkSent = $state(false);
|
|
47
|
+
|
|
48
|
+
async function handleSocial(provider: SocialProvider) {
|
|
49
|
+
localError = null;
|
|
50
|
+
await auth.signInWithSocial(provider);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function handleSubmit(e: SubmitEvent) {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
localError = null;
|
|
56
|
+
|
|
57
|
+
if (currentMode === 'magic-link') {
|
|
58
|
+
const ok = await auth.signInWithMagicLink(email);
|
|
59
|
+
if (ok) {
|
|
60
|
+
magicLinkSent = true;
|
|
61
|
+
if (onsuccess) onsuccess();
|
|
62
|
+
} else {
|
|
63
|
+
localError = auth.error || 'Failed to send magic link';
|
|
64
|
+
if (onerror) onerror(localError);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (currentMode === 'signup') {
|
|
70
|
+
const ok = await auth.signUpWithEmail(email, password, name);
|
|
71
|
+
if (ok) {
|
|
72
|
+
if (onsuccess) onsuccess();
|
|
73
|
+
if (typeof window !== 'undefined') window.location.href = callbackURL;
|
|
74
|
+
} else {
|
|
75
|
+
localError = auth.error || 'Could not create account';
|
|
76
|
+
if (onerror) onerror(localError);
|
|
77
|
+
}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Sign In mode
|
|
82
|
+
const ok = await auth.signInWithEmail(email, password);
|
|
83
|
+
if (ok) {
|
|
84
|
+
if (onsuccess) onsuccess();
|
|
85
|
+
if (typeof window !== 'undefined') window.location.href = callbackURL;
|
|
86
|
+
} else {
|
|
87
|
+
localError = auth.error || 'Invalid email or password';
|
|
88
|
+
if (onerror) onerror(localError);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<Card
|
|
94
|
+
class="mx-auto w-full max-w-md space-y-6 border-zinc-200 p-6 shadow-xl sm:p-8 dark:border-zinc-800 {className}"
|
|
95
|
+
>
|
|
96
|
+
<!-- Header -->
|
|
97
|
+
<div class="space-y-1.5 text-center">
|
|
98
|
+
<h2 class="text-2xl font-bold tracking-tight text-zinc-900 dark:text-zinc-50">
|
|
99
|
+
{#if title}
|
|
100
|
+
{title}
|
|
101
|
+
{:else if currentMode === 'signup'}
|
|
102
|
+
Create an account
|
|
103
|
+
{:else if currentMode === 'magic-link'}
|
|
104
|
+
Sign in with Magic Link
|
|
105
|
+
{:else}
|
|
106
|
+
Welcome back
|
|
107
|
+
{/if}
|
|
108
|
+
</h2>
|
|
109
|
+
<p class="text-sm text-zinc-500 dark:text-zinc-400">
|
|
110
|
+
{#if subtitle}
|
|
111
|
+
{subtitle}
|
|
112
|
+
{:else if currentMode === 'signup'}
|
|
113
|
+
Start your 14-day free trial, no credit card required.
|
|
114
|
+
{:else if currentMode === 'magic-link'}
|
|
115
|
+
We will email you a passwordless sign-in link.
|
|
116
|
+
{:else}
|
|
117
|
+
Sign in to access your dashboard and workspace.
|
|
118
|
+
{/if}
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<!-- Error Alert -->
|
|
123
|
+
{#if localError || auth.error}
|
|
124
|
+
<Alert
|
|
125
|
+
color="error"
|
|
126
|
+
title="Authentication Error"
|
|
127
|
+
description={localError || auth.error || ''}
|
|
128
|
+
/>
|
|
129
|
+
{/if}
|
|
130
|
+
|
|
131
|
+
<!-- Magic Link Success State -->
|
|
132
|
+
{#if magicLinkSent}
|
|
133
|
+
<div
|
|
134
|
+
class="space-y-2 rounded-xl border border-emerald-500/20 bg-emerald-50/50 p-5 text-center dark:bg-emerald-950/20"
|
|
135
|
+
>
|
|
136
|
+
<div class="flex justify-center text-emerald-600 dark:text-emerald-400">
|
|
137
|
+
<Icon name="check" class="h-8 w-8" />
|
|
138
|
+
</div>
|
|
139
|
+
<h3 class="font-semibold text-zinc-900 dark:text-zinc-100">Check your email</h3>
|
|
140
|
+
<p class="text-sm text-zinc-600 dark:text-zinc-400">
|
|
141
|
+
We've sent a magic link to <strong class="text-zinc-900 dark:text-zinc-100">{email}</strong
|
|
142
|
+
>.
|
|
143
|
+
</p>
|
|
144
|
+
<Button
|
|
145
|
+
variant="ghost"
|
|
146
|
+
size="sm"
|
|
147
|
+
class="mt-2 text-xs"
|
|
148
|
+
onclick={() => {
|
|
149
|
+
magicLinkSent = false;
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
Use a different method
|
|
153
|
+
</Button>
|
|
154
|
+
</div>
|
|
155
|
+
{:else}
|
|
156
|
+
<!-- Social Login Buttons -->
|
|
157
|
+
{#if showSocial && providers.length > 0}
|
|
158
|
+
<div class="grid grid-cols-1 gap-2.5 sm:grid-cols-2">
|
|
159
|
+
{#each providers as provider}
|
|
160
|
+
<Button
|
|
161
|
+
variant="outline"
|
|
162
|
+
class="w-full justify-center gap-2 font-medium"
|
|
163
|
+
loading={auth.isLoading}
|
|
164
|
+
onclick={() => handleSocial(provider)}
|
|
165
|
+
>
|
|
166
|
+
{#if provider === 'github'}
|
|
167
|
+
<Icon name="github" class="h-4 w-4" />
|
|
168
|
+
<span>GitHub</span>
|
|
169
|
+
{:else if provider === 'google'}
|
|
170
|
+
<Icon name="external-link" class="h-4 w-4" />
|
|
171
|
+
<span>Google</span>
|
|
172
|
+
{:else}
|
|
173
|
+
<span>{provider}</span>
|
|
174
|
+
{/if}
|
|
175
|
+
</Button>
|
|
176
|
+
{/each}
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
<Divider label="or continue with" />
|
|
180
|
+
{/if}
|
|
181
|
+
|
|
182
|
+
<!-- Email Form -->
|
|
183
|
+
<form onsubmit={handleSubmit} class="space-y-4">
|
|
184
|
+
{#if currentMode === 'signup'}
|
|
185
|
+
<FormField label="Full Name" required>
|
|
186
|
+
<Input type="text" placeholder="Alex Johnson" bind:value={name} required />
|
|
187
|
+
</FormField>
|
|
188
|
+
{/if}
|
|
189
|
+
|
|
190
|
+
<FormField label="Email address" required>
|
|
191
|
+
<Input type="email" placeholder="name@company.com" bind:value={email} required />
|
|
192
|
+
</FormField>
|
|
193
|
+
|
|
194
|
+
{#if currentMode !== 'magic-link'}
|
|
195
|
+
<FormField label="Password" required>
|
|
196
|
+
<Input type="password" placeholder="••••••••" bind:value={password} required />
|
|
197
|
+
</FormField>
|
|
198
|
+
{/if}
|
|
199
|
+
|
|
200
|
+
<Button
|
|
201
|
+
type="submit"
|
|
202
|
+
variant="solid"
|
|
203
|
+
color="primary"
|
|
204
|
+
class="w-full justify-center font-semibold shadow-md"
|
|
205
|
+
loading={auth.isLoading}
|
|
206
|
+
>
|
|
207
|
+
{#if currentMode === 'signup'}
|
|
208
|
+
Create Account
|
|
209
|
+
{:else if currentMode === 'magic-link'}
|
|
210
|
+
Send Magic Link
|
|
211
|
+
{:else}
|
|
212
|
+
Sign In
|
|
213
|
+
{/if}
|
|
214
|
+
</Button>
|
|
215
|
+
</form>
|
|
216
|
+
|
|
217
|
+
<!-- Mode Switchers -->
|
|
218
|
+
<div class="flex flex-col items-center gap-2 pt-2 text-xs text-zinc-500 dark:text-zinc-400">
|
|
219
|
+
{#if currentMode === 'signin'}
|
|
220
|
+
<div>
|
|
221
|
+
Don't have an account?
|
|
222
|
+
<button
|
|
223
|
+
type="button"
|
|
224
|
+
class="font-semibold text-primary-600 hover:underline dark:text-primary-400"
|
|
225
|
+
onclick={() => {
|
|
226
|
+
customMode = 'signup';
|
|
227
|
+
localError = null;
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
Sign up
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
{#if showMagicLinkToggle}
|
|
234
|
+
<button
|
|
235
|
+
type="button"
|
|
236
|
+
class="text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200"
|
|
237
|
+
onclick={() => {
|
|
238
|
+
customMode = 'magic-link';
|
|
239
|
+
localError = null;
|
|
240
|
+
}}
|
|
241
|
+
>
|
|
242
|
+
Sign in with a passwordless magic link
|
|
243
|
+
</button>
|
|
244
|
+
{/if}
|
|
245
|
+
{:else if currentMode === 'signup'}
|
|
246
|
+
<div>
|
|
247
|
+
Already have an account?
|
|
248
|
+
<button
|
|
249
|
+
type="button"
|
|
250
|
+
class="font-semibold text-primary-600 hover:underline dark:text-primary-400"
|
|
251
|
+
onclick={() => {
|
|
252
|
+
customMode = 'signin';
|
|
253
|
+
localError = null;
|
|
254
|
+
}}
|
|
255
|
+
>
|
|
256
|
+
Sign in
|
|
257
|
+
</button>
|
|
258
|
+
</div>
|
|
259
|
+
{:else}
|
|
260
|
+
<button
|
|
261
|
+
type="button"
|
|
262
|
+
class="font-semibold text-primary-600 hover:underline dark:text-primary-400"
|
|
263
|
+
onclick={() => {
|
|
264
|
+
customMode = 'signin';
|
|
265
|
+
localError = null;
|
|
266
|
+
}}
|
|
267
|
+
>
|
|
268
|
+
← Back to email and password sign in
|
|
269
|
+
</button>
|
|
270
|
+
{/if}
|
|
271
|
+
</div>
|
|
272
|
+
{/if}
|
|
273
|
+
</Card>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type SocialProvider } from '../../composables/useAuth.svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
title?: string;
|
|
4
|
+
subtitle?: string;
|
|
5
|
+
mode?: 'signin' | 'signup' | 'magic-link';
|
|
6
|
+
providers?: SocialProvider[];
|
|
7
|
+
showSocial?: boolean;
|
|
8
|
+
showMagicLinkToggle?: boolean;
|
|
9
|
+
callbackURL?: string;
|
|
10
|
+
class?: string;
|
|
11
|
+
onsuccess?: () => void;
|
|
12
|
+
onerror?: (err: string) => void;
|
|
13
|
+
}
|
|
14
|
+
declare const AuthCard: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type AuthCard = ReturnType<typeof AuthCard>;
|
|
16
|
+
export default AuthCard;
|