mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Moving validations to separate folder, upgrading superforms v2, and shadcn components.
This commit is contained in:
parent
becf1d8349
commit
8f9db3fea5
53 changed files with 997 additions and 583 deletions
24
package.json
24
package.json
|
|
@ -26,7 +26,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@melt-ui/pp": "^0.3.0",
|
"@melt-ui/pp": "^0.3.0",
|
||||||
"@melt-ui/svelte": "^0.74.1",
|
"@melt-ui/svelte": "^0.74.2",
|
||||||
"@playwright/test": "^1.41.2",
|
"@playwright/test": "^1.41.2",
|
||||||
"@resvg/resvg-js": "^2.6.0",
|
"@resvg/resvg-js": "^2.6.0",
|
||||||
"@sveltejs/adapter-auto": "^3.1.1",
|
"@sveltejs/adapter-auto": "^3.1.1",
|
||||||
|
|
@ -34,14 +34,14 @@
|
||||||
"@sveltejs/kit": "^2.5.1",
|
"@sveltejs/kit": "^2.5.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/node": "^20.11.19",
|
"@types/node": "^20.11.20",
|
||||||
"@types/pg": "^8.11.0",
|
"@types/pg": "^8.11.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"drizzle-kit": "^0.20.14",
|
"drizzle-kit": "^0.20.14",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-svelte": "^2.35.1",
|
"eslint-plugin-svelte": "^2.35.1",
|
||||||
"just-clone": "^6.2.0",
|
"just-clone": "^6.2.0",
|
||||||
|
|
@ -53,17 +53,17 @@
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-svelte": "^3.2.1",
|
"prettier-plugin-svelte": "^3.2.1",
|
||||||
"prisma": "^5.9.1",
|
"prisma": "^5.9.1",
|
||||||
"sass": "^1.71.0",
|
"sass": "^1.71.1",
|
||||||
"satori": "^0.10.13",
|
"satori": "^0.10.13",
|
||||||
"satori-html": "^0.3.2",
|
"satori-html": "^0.3.2",
|
||||||
"svelte": "^4.2.11",
|
"svelte": "^4.2.12",
|
||||||
"svelte-check": "^3.6.4",
|
"svelte-check": "^3.6.4",
|
||||||
"svelte-meta-tags": "^3.1.0",
|
"svelte-meta-tags": "^3.1.0",
|
||||||
"svelte-preprocess": "^5.1.3",
|
"svelte-preprocess": "^5.1.3",
|
||||||
"svelte-sequential-preprocessor": "^2.0.1",
|
"svelte-sequential-preprocessor": "^2.0.1",
|
||||||
"sveltekit-flash-message": "^2.4.2",
|
"sveltekit-flash-message": "^2.4.2",
|
||||||
"sveltekit-rate-limiter": "^0.4.3",
|
"sveltekit-rate-limiter": "^0.4.3",
|
||||||
"sveltekit-superforms": "^1.13.4",
|
"sveltekit-superforms": "^2.6.2",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tslib": "^2.6.1",
|
"tslib": "^2.6.1",
|
||||||
|
|
@ -93,31 +93,31 @@
|
||||||
"@sveltejs/adapter-vercel": "^5.1.0",
|
"@sveltejs/adapter-vercel": "^5.1.0",
|
||||||
"@types/feather-icons": "^4.29.4",
|
"@types/feather-icons": "^4.29.4",
|
||||||
"@vercel/og": "^0.5.20",
|
"@vercel/og": "^0.5.20",
|
||||||
"bits-ui": "^0.18.1",
|
"bits-ui": "^0.18.2",
|
||||||
"boardgamegeekclient": "^1.9.1",
|
"boardgamegeekclient": "^1.9.1",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
"drizzle-orm": "^0.29.4",
|
"drizzle-orm": "^0.29.4",
|
||||||
"feather-icons": "^4.29.1",
|
"feather-icons": "^4.29.1",
|
||||||
"formsnap": "^0.4.4",
|
"formsnap": "^0.5.1",
|
||||||
"html-entities": "^2.4.0",
|
"html-entities": "^2.4.0",
|
||||||
"iconify-icon": "^2.0.0",
|
"iconify-icon": "^2.0.0",
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "3.0.1",
|
"lucia": "3.0.1",
|
||||||
"lucide-svelte": "^0.335.0",
|
"lucide-svelte": "^0.340.0",
|
||||||
"mysql2": "^3.9.1",
|
"mysql2": "^3.9.1",
|
||||||
"nanoid": "^5.0.6",
|
"nanoid": "^5.0.6",
|
||||||
"open-props": "^1.6.19",
|
"open-props": "^1.6.19",
|
||||||
"oslo": "^1.1.2",
|
"oslo": "^1.1.3",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"postgres": "^3.4.3",
|
"postgres": "^3.4.3",
|
||||||
"radix-svelte": "^0.9.0",
|
"radix-svelte": "^0.9.0",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svelte-lazy-loader": "^1.0.0",
|
"svelte-lazy-loader": "^1.0.0",
|
||||||
"tailwind-merge": "^2.2.1",
|
"tailwind-merge": "^2.2.1",
|
||||||
"tailwind-variants": "^0.1.20",
|
"tailwind-variants": "^0.2.0",
|
||||||
"tailwindcss-animate": "^1.0.6",
|
"tailwindcss-animate": "^1.0.6",
|
||||||
"zod-to-json-schema": "^3.22.4"
|
"zod-to-json-schema": "^3.22.4"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
981
pnpm-lock.yaml
981
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,16 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { ConicGradient } from '@skeletonlabs/skeleton';
|
import { ConicGradient } from '@skeletonlabs/skeleton';
|
||||||
import type { ConicStop } from '@skeletonlabs/skeleton';
|
import type { ConicStop } from '@skeletonlabs/skeleton';
|
||||||
|
import { i } from "@inlang/sdk-js";
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
//import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
|
//import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
|
||||||
import { userSchema } from '$lib/config/zod-schemas';
|
import { userSchema } from '$lib/validations/zod-schemas';
|
||||||
import { AlertTriangle } from 'lucide-svelte';
|
import { AlertTriangle } from 'lucide-svelte';
|
||||||
import { i } from "@inlang/sdk-js";
|
import { signInSchema } from '$lib/validations/auth';
|
||||||
export let data;
|
export let data;
|
||||||
const signInSchema = userSchema.pick({ email: true, password: true });
|
|
||||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: signInSchema,
|
validators: zodClient(signInSchema),
|
||||||
delayMs: 0
|
delayMs: 0
|
||||||
});
|
});
|
||||||
const conicStops: ConicStop[] = [
|
const conicStops: ConicStop[] = [
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import { signUpSchema } from '$lib/config/zod-schemas';
|
import { signUpSchema } from '$lib/validations/auth';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
const { form, errors, enhance } = superForm(data.form, {
|
const { form, errors, enhance } = superForm(data.form, {
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: signUpSchema,
|
validators: zodClient(signUpSchema),
|
||||||
delayMs: 0
|
delayMs: 0
|
||||||
});
|
});
|
||||||
// $: termsValue = $form.terms as Writable<boolean>;
|
// $: termsValue = $form.terms as Writable<boolean>;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AvatarPrimitive.Fallback
|
<AvatarPrimitive.Fallback
|
||||||
class={cn(
|
class={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
|
||||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,7 @@
|
||||||
|
|
||||||
<AvatarPrimitive.Root
|
<AvatarPrimitive.Root
|
||||||
{delayMs}
|
{delayMs}
|
||||||
class={cn(
|
class={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
|
||||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ export {
|
||||||
//
|
//
|
||||||
Root as Avatar,
|
Root as Avatar,
|
||||||
Image as AvatarImage,
|
Image as AvatarImage,
|
||||||
Fallback as AvatarFallback
|
Fallback as AvatarFallback,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,19 @@ const buttonVariants = tv({
|
||||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
link: "text-primary underline-offset-4 hover:underline"
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-4 py-2",
|
default: "h-10 px-4 py-2",
|
||||||
sm: "h-9 rounded-md px-3",
|
sm: "h-9 rounded-md px-3",
|
||||||
lg: "h-11 rounded-md px-8",
|
lg: "h-11 rounded-md px-8",
|
||||||
icon: "h-10 w-10"
|
icon: "h-10 w-10",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
size: "default"
|
size: "default",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type Variant = VariantProps<typeof buttonVariants>["variant"];
|
type Variant = VariantProps<typeof buttonVariants>["variant"];
|
||||||
|
|
@ -45,5 +45,5 @@ export {
|
||||||
Root as Button,
|
Root as Button,
|
||||||
type Props as ButtonProps,
|
type Props as ButtonProps,
|
||||||
type Events as ButtonEvents,
|
type Events as ButtonEvents,
|
||||||
buttonVariants
|
buttonVariants,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={cn(
|
class={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
||||||
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export {
|
||||||
Description as CardDescription,
|
Description as CardDescription,
|
||||||
Footer as CardFooter,
|
Footer as CardFooter,
|
||||||
Header as CardHeader,
|
Header as CardHeader,
|
||||||
Title as CardTitle
|
Title as CardTitle,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
export let transition: $$Props["transition"] = slide;
|
export let transition: $$Props["transition"] = slide;
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
duration: 150
|
duration: 150,
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,5 @@ export {
|
||||||
//
|
//
|
||||||
Root as Collapsible,
|
Root as Collapsible,
|
||||||
Content as CollapsibleContent,
|
Content as CollapsibleContent,
|
||||||
Trigger as CollapsibleTrigger
|
Trigger as CollapsibleTrigger,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import Check from "lucide-svelte/icons/check";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { Check } from "lucide-svelte";
|
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
||||||
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<DropdownMenuPrimitive.CheckboxItem
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
bind:checked
|
bind:checked
|
||||||
class={cn(
|
class={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
||||||
|
|
||||||
let className: $$Props["class"] = undefined;
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
export let transition: $$Props["transition"] = flyAndScale;
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
<DropdownMenuPrimitive.Content
|
<DropdownMenuPrimitive.Content
|
||||||
{transition}
|
{transition}
|
||||||
{transitionConfig}
|
{transitionConfig}
|
||||||
|
{sideOffset}
|
||||||
class={cn(
|
class={cn(
|
||||||
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||||
className
|
className
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
class={cn(
|
class={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import Circle from "lucide-svelte/icons/circle";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { Circle } from "lucide-svelte";
|
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
||||||
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
<DropdownMenuPrimitive.RadioItem
|
<DropdownMenuPrimitive.RadioItem
|
||||||
class={cn(
|
class={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{value}
|
{value}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,6 @@
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span
|
<span class={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...$$restProps}>
|
||||||
class={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
|
||||||
{...$$restProps}
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
export let transition: $$Props["transition"] = flyAndScale;
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
x: -10,
|
x: -10,
|
||||||
y: 0
|
y: 0,
|
||||||
};
|
};
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { ChevronRight } from "lucide-svelte";
|
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent",
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -44,5 +44,5 @@ export {
|
||||||
RadioGroup as DropdownMenuRadioGroup,
|
RadioGroup as DropdownMenuRadioGroup,
|
||||||
SubContent as DropdownMenuSubContent,
|
SubContent as DropdownMenuSubContent,
|
||||||
SubTrigger as DropdownMenuSubTrigger,
|
SubTrigger as DropdownMenuSubTrigger,
|
||||||
CheckboxItem as DropdownMenuCheckboxItem
|
CheckboxItem as DropdownMenuCheckboxItem,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as Button from "$lib/components/ui/button";
|
import * as Button from "$lib/components/ui/button";
|
||||||
|
|
||||||
type $$Props = Button.Props;
|
type $$Props = Button.Props;
|
||||||
type $$Events = Button.Events;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
|
<Button.Root type="submit" {...$$restProps}>
|
||||||
<slot />
|
<slot />
|
||||||
</Button.Root>
|
</Button.Root>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Form as FormPrimitive } from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
|
@ -8,6 +8,10 @@
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormPrimitive.Description class={cn("text-sm text-muted-foreground", className)} {...$$restProps}>
|
<FormPrimitive.Description
|
||||||
<slot />
|
class={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
let:descriptionAttrs
|
||||||
|
>
|
||||||
|
<slot {descriptionAttrs} />
|
||||||
</FormPrimitive.Description>
|
</FormPrimitive.Description>
|
||||||
|
|
|
||||||
26
src/lib/components/ui/form/form-element-field.svelte
Normal file
26
src/lib/components/ui/form/form-element-field.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import type { FormPathLeaves, SuperForm } from "sveltekit-superforms";
|
||||||
|
type T = Record<string, unknown>;
|
||||||
|
type U = unknown;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import * as FormPrimitive from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||||
|
|
||||||
|
export let form: SuperForm<T>;
|
||||||
|
export let name: U;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.ElementField {form} {name} let:constraints let:errors let:tainted let:value>
|
||||||
|
<div class={cn("space-y-2", className)}>
|
||||||
|
<slot {constraints} {errors} {tainted} {value} />
|
||||||
|
</div>
|
||||||
|
</FormPrimitive.ElementField>
|
||||||
26
src/lib/components/ui/form/form-field-errors.svelte
Normal file
26
src/lib/components/ui/form/form-field-errors.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as FormPrimitive from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = FormPrimitive.FieldErrorsProps & {
|
||||||
|
errorClasses?: string | undefined | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
export let errorClasses: $$Props["class"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.FieldErrors
|
||||||
|
class={cn("text-sm font-medium text-destructive", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
let:errors
|
||||||
|
let:fieldErrorsAttrs
|
||||||
|
let:errorAttrs
|
||||||
|
>
|
||||||
|
<slot {errors} {fieldErrorsAttrs} {errorAttrs}>
|
||||||
|
{#each errors as error}
|
||||||
|
<div {...errorAttrs} class={cn(errorClasses)}>{error}</div>
|
||||||
|
{/each}
|
||||||
|
</slot>
|
||||||
|
</FormPrimitive.FieldErrors>
|
||||||
26
src/lib/components/ui/form/form-field.svelte
Normal file
26
src/lib/components/ui/form/form-field.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||||
|
type T = Record<string, unknown>;
|
||||||
|
type U = unknown;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import * as FormPrimitive from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||||
|
|
||||||
|
export let form: SuperForm<T>;
|
||||||
|
export let name: U;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.Field {form} {name} let:constraints let:errors let:tainted let:value>
|
||||||
|
<div class={cn("space-y-2", className)}>
|
||||||
|
<slot {constraints} {errors} {tainted} {value} />
|
||||||
|
</div>
|
||||||
|
</FormPrimitive.Field>
|
||||||
31
src/lib/components/ui/form/form-fieldset.svelte
Normal file
31
src/lib/components/ui/form/form-fieldset.svelte
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts" context="module">
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||||
|
type T = Record<string, unknown>;
|
||||||
|
type U = unknown;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||||
|
import * as FormPrimitive from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = FormPrimitive.FieldsetProps<T, U>;
|
||||||
|
|
||||||
|
export let form: SuperForm<T>;
|
||||||
|
export let name: U;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.Fieldset
|
||||||
|
{form}
|
||||||
|
{name}
|
||||||
|
let:constraints
|
||||||
|
let:errors
|
||||||
|
let:tainted
|
||||||
|
let:value
|
||||||
|
class={cn("space-y-2", className)}
|
||||||
|
>
|
||||||
|
<slot {constraints} {errors} {tainted} {value} />
|
||||||
|
</FormPrimitive.Fieldset>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Label as LabelPrimitive } from "bits-ui";
|
import type { Label as LabelPrimitive } from "bits-ui";
|
||||||
import { getFormField } from "formsnap";
|
import { getFormControl } from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { Label } from "$lib/components/ui/label";
|
import { Label } from "$lib/components/ui/label";
|
||||||
|
|
||||||
|
|
@ -9,9 +9,9 @@
|
||||||
let className: $$Props["class"] = undefined;
|
let className: $$Props["class"] = undefined;
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
const { errors, ids } = getFormField();
|
const { labelAttrs } = getFormControl();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Label for={$ids.input} class={cn($errors && "text-destructive", className)} {...$$restProps}>
|
<Label {...$labelAttrs} class={cn("data-[fs-error]:text-destructive", className)} {...$$restProps}>
|
||||||
<slot />
|
<slot {labelAttrs} />
|
||||||
</Label>
|
</Label>
|
||||||
|
|
|
||||||
17
src/lib/components/ui/form/form-legend.svelte
Normal file
17
src/lib/components/ui/form/form-legend.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import * as FormPrimitive from "formsnap";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = FormPrimitive.LegendProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormPrimitive.Legend
|
||||||
|
{...$$restProps}
|
||||||
|
class={cn("text-sm font-medium leading-none data-[fs-error]:text-destructive", className)}
|
||||||
|
let:legendAttrs
|
||||||
|
>
|
||||||
|
<slot {legendAttrs} />
|
||||||
|
</FormPrimitive.Legend>
|
||||||
|
|
@ -1,82 +1,33 @@
|
||||||
import { Form as FormPrimitive, getFormField } from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import * as RadioGroupComp from "$lib/components/ui/radio-group";
|
|
||||||
import * as SelectComp from "$lib/components/ui/select";
|
|
||||||
import type { Writable } from "svelte/store";
|
|
||||||
import Item from "./form-item.svelte";
|
|
||||||
import Input from "./form-input.svelte";
|
|
||||||
import Textarea from "./form-textarea.svelte";
|
|
||||||
import Description from "./form-description.svelte";
|
import Description from "./form-description.svelte";
|
||||||
import Label from "./form-label.svelte";
|
import Label from "./form-label.svelte";
|
||||||
import Validation from "./form-validation.svelte";
|
import FieldErrors from "./form-field-errors.svelte";
|
||||||
import Checkbox from "./form-checkbox.svelte";
|
import Field from "./form-field.svelte";
|
||||||
import Switch from "./form-switch.svelte";
|
import Fieldset from "./form-fieldset.svelte";
|
||||||
import NativeSelect from "./form-native-select.svelte";
|
import Legend from "./form-legend.svelte";
|
||||||
import RadioGroup from "./form-radio-group.svelte";
|
import ElementField from "./form-element-field.svelte";
|
||||||
import Select from "./form-select.svelte";
|
|
||||||
import SelectTrigger from "./form-select-trigger.svelte";
|
|
||||||
import Button from "./form-button.svelte";
|
import Button from "./form-button.svelte";
|
||||||
|
|
||||||
const Root = FormPrimitive.Root;
|
|
||||||
const Field = FormPrimitive.Field;
|
|
||||||
const Control = FormPrimitive.Control;
|
const Control = FormPrimitive.Control;
|
||||||
const RadioItem = RadioGroupComp.Item;
|
|
||||||
const NativeRadio = FormPrimitive.Radio;
|
|
||||||
const SelectContent = SelectComp.Content;
|
|
||||||
const SelectLabel = SelectComp.Label;
|
|
||||||
const SelectGroup = SelectComp.Group;
|
|
||||||
const SelectItem = SelectComp.Item;
|
|
||||||
const SelectSeparator = SelectComp.Separator;
|
|
||||||
|
|
||||||
export type TextareaGetFormField = Omit<ReturnType<typeof getFormField>, "value"> & {
|
|
||||||
value: Writable<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
|
||||||
Field,
|
Field,
|
||||||
Control,
|
Control,
|
||||||
Item,
|
|
||||||
Input,
|
|
||||||
Label,
|
Label,
|
||||||
Button,
|
Button,
|
||||||
Switch,
|
FieldErrors,
|
||||||
Select,
|
|
||||||
Checkbox,
|
|
||||||
Textarea,
|
|
||||||
Validation,
|
|
||||||
RadioGroup,
|
|
||||||
RadioItem,
|
|
||||||
Description,
|
Description,
|
||||||
SelectContent,
|
Fieldset,
|
||||||
SelectLabel,
|
Legend,
|
||||||
SelectGroup,
|
ElementField,
|
||||||
SelectItem,
|
|
||||||
SelectSeparator,
|
|
||||||
SelectTrigger,
|
|
||||||
NativeSelect,
|
|
||||||
NativeRadio,
|
|
||||||
//
|
//
|
||||||
Root as Form,
|
|
||||||
Field as FormField,
|
Field as FormField,
|
||||||
Control as FormControl,
|
Control as FormControl,
|
||||||
Item as FormItem,
|
|
||||||
Input as FormInput,
|
|
||||||
Textarea as FormTextarea,
|
|
||||||
Description as FormDescription,
|
Description as FormDescription,
|
||||||
Label as FormLabel,
|
Label as FormLabel,
|
||||||
Validation as FormValidation,
|
FieldErrors as FormFieldErrors,
|
||||||
NativeSelect as FormNativeSelect,
|
Fieldset as FormFieldset,
|
||||||
NativeRadio as FormNativeRadio,
|
Legend as FormLegend,
|
||||||
Checkbox as FormCheckbox,
|
ElementField as FormElementField,
|
||||||
Switch as FormSwitch,
|
Button as FormButton,
|
||||||
RadioGroup as FormRadioGroup,
|
|
||||||
RadioItem as FormRadioItem,
|
|
||||||
Select as FormSelect,
|
|
||||||
SelectContent as FormSelectContent,
|
|
||||||
SelectLabel as FormSelectLabel,
|
|
||||||
SelectGroup as FormSelectGroup,
|
|
||||||
SelectItem as FormSelectItem,
|
|
||||||
SelectSeparator as FormSelectSeparator,
|
|
||||||
SelectTrigger as FormSelectTrigger,
|
|
||||||
Button as FormButton
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ import Root from "./label.svelte";
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Label
|
Root as Label,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,5 +20,5 @@ export {
|
||||||
Link as PaginationLink,
|
Link as PaginationLink,
|
||||||
PrevButton as PaginationPrevButton,
|
PrevButton as PaginationPrevButton,
|
||||||
NextButton as PaginationNextButton,
|
NextButton as PaginationNextButton,
|
||||||
Ellipsis as PaginationEllipsis
|
Ellipsis as PaginationEllipsis,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import MoreHorizontal from "lucide-svelte/icons/more-horizontal";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { MoreHorizontal } from "lucide-svelte";
|
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
class={cn(
|
class={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: isActive ? "outline" : "ghost",
|
variant: isActive ? "outline" : "ghost",
|
||||||
size
|
size,
|
||||||
}),
|
}),
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||||
|
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||||
import { Button } from "$lib/components/ui/button";
|
import { Button } from "$lib/components/ui/button";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { ChevronRight } from "lucide-svelte";
|
|
||||||
|
|
||||||
type $$Props = PaginationPrimitive.NextButtonProps;
|
type $$Props = PaginationPrimitive.NextButtonProps;
|
||||||
type $$Events = PaginationPrimitive.NextButtonEvents;
|
type $$Events = PaginationPrimitive.NextButtonEvents;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||||
|
import ChevronLeft from "lucide-svelte/icons/chevron-left";
|
||||||
import { Button } from "$lib/components/ui/button";
|
import { Button } from "$lib/components/ui/button";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
import { ChevronLeft } from "lucide-svelte";
|
|
||||||
|
|
||||||
type $$Props = PaginationPrimitive.PrevButtonProps;
|
type $$Props = PaginationPrimitive.PrevButtonProps;
|
||||||
type $$Events = PaginationPrimitive.PrevButtonEvents;
|
type $$Events = PaginationPrimitive.PrevButtonEvents;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
asChild
|
asChild
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
>
|
>
|
||||||
<nav {...builder} class={cn("mx-auto flex flex-col w-full items-center", className)}>
|
<nav {...builder} class={cn("mx-auto flex w-full flex-col items-center", className)}>
|
||||||
<slot {pages} {range} {currentPage} />
|
<slot {pages} {range} {currentPage} />
|
||||||
</nav>
|
</nav>
|
||||||
</PaginationPrimitive.Root>
|
</PaginationPrimitive.Root>
|
||||||
|
|
|
||||||
|
|
@ -1,90 +1,43 @@
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { userSchema } from './zod-schemas';
|
||||||
|
|
||||||
export type ListGame = {
|
export const profileSchema = userSchema.pick({
|
||||||
id: string;
|
firstName: true,
|
||||||
game_name: string;
|
lastName: true,
|
||||||
game_id: string;
|
email: true,
|
||||||
collection_id: string;
|
username: true
|
||||||
wishlist_id: string;
|
|
||||||
times_played: number;
|
|
||||||
thumb_url: string | null;
|
|
||||||
in_collection: boolean;
|
|
||||||
in_wishlist: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const modifyListGameSchema = z.object({
|
|
||||||
id: z.string()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ModifyListGame = typeof modifyListGameSchema;
|
export const changeUserPasswordSchema = z
|
||||||
|
.object({
|
||||||
export const userSchema = z.object({
|
current_password: z.string({ required_error: 'Current Password is required' }),
|
||||||
firstName: z.string().trim().optional(),
|
password: z.string({ required_error: 'Password is required' }).trim(),
|
||||||
lastName: z.string().trim().optional(),
|
confirm_password: z.string({ required_error: 'Confirm Password is required' }).trim()
|
||||||
email: z.string().email({ message: 'Please enter a valid email address' }).optional(),
|
|
||||||
username: z
|
|
||||||
.string()
|
|
||||||
.trim()
|
|
||||||
.min(3, { message: 'Username must be at least 3 characters' })
|
|
||||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
|
||||||
password: z
|
|
||||||
.string({ required_error: 'Password is required' })
|
|
||||||
.trim(),
|
|
||||||
confirm_password: z
|
|
||||||
.string({ required_error: 'Confirm Password is required' })
|
|
||||||
.trim(),
|
|
||||||
verified: z.boolean().default(false),
|
|
||||||
token: z.string().optional(),
|
|
||||||
receiveEmail: z.boolean().default(false),
|
|
||||||
createdAt: z.date().optional(),
|
|
||||||
updatedAt: z.date().optional()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const signUpSchema = userSchema
|
|
||||||
.pick({
|
|
||||||
firstName: true,
|
|
||||||
lastName: true,
|
|
||||||
email: true,
|
|
||||||
username: true,
|
|
||||||
password: true,
|
|
||||||
confirm_password: true,
|
|
||||||
terms: true
|
|
||||||
})
|
})
|
||||||
.superRefine(({ confirm_password, password }, ctx) => {
|
.superRefine(({ confirm_password, password }, ctx) => {
|
||||||
refinePasswords(confirm_password, password, ctx);
|
refinePasswords(confirm_password, password, ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const signInSchema = userSchema.pick({
|
|
||||||
username: true,
|
|
||||||
password: true
|
|
||||||
});
|
|
||||||
|
|
||||||
export const updateUserPasswordSchema = userSchema
|
export const updateUserPasswordSchema = userSchema
|
||||||
.pick({ password: true, confirm_password: true })
|
.pick({ password: true, confirm_password: true })
|
||||||
.superRefine(({ confirm_password, password }, ctx) => {
|
.superRefine(({ confirm_password, password }, ctx) => {
|
||||||
refinePasswords(confirm_password, password, ctx);
|
refinePasswords(confirm_password, password, ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const changeUserPasswordSchema = z
|
export const refinePasswords = async function (
|
||||||
.object({
|
confirm_password: string,
|
||||||
current_password: z.string({ required_error: 'Current Password is required' }),
|
password: string,
|
||||||
password: z
|
ctx: z.RefinementCtx
|
||||||
.string({ required_error: 'Password is required' })
|
) {
|
||||||
.trim(),
|
|
||||||
confirm_password: z
|
|
||||||
.string({ required_error: 'Confirm Password is required' })
|
|
||||||
.trim()
|
|
||||||
})
|
|
||||||
.superRefine(({ confirm_password, password }, ctx) => {
|
|
||||||
refinePasswords(confirm_password, password, ctx);
|
|
||||||
});
|
|
||||||
|
|
||||||
const refinePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
|
|
||||||
comparePasswords(confirm_password, password, ctx);
|
comparePasswords(confirm_password, password, ctx);
|
||||||
checkPasswordStrength(password, ctx);
|
checkPasswordStrength(password, ctx);
|
||||||
}
|
};
|
||||||
|
|
||||||
const comparePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
|
const comparePasswords = async function (
|
||||||
|
confirm_password: string,
|
||||||
|
password: string,
|
||||||
|
ctx: z.RefinementCtx
|
||||||
|
) {
|
||||||
if (confirm_password !== password) {
|
if (confirm_password !== password) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
|
|
@ -92,15 +45,14 @@ const comparePasswords = async function(confirm_password: string, password: stri
|
||||||
path: ['confirm_password']
|
path: ['confirm_password']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
|
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
|
||||||
const minimumLength = password.length < 8;
|
const minimumLength = password.length < 8;
|
||||||
const maximumLength = password.length > 128;
|
const maximumLength = password.length > 128;
|
||||||
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
|
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
|
||||||
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
|
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
|
||||||
const containsSpecialChar = (ch: string) =>
|
const containsSpecialChar = (ch: string) => /[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
|
||||||
/[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
|
|
||||||
let countOfUpperCase = 0,
|
let countOfUpperCase = 0,
|
||||||
countOfLowerCase = 0,
|
countOfLowerCase = 0,
|
||||||
countOfNumbers = 0,
|
countOfNumbers = 0,
|
||||||
|
|
@ -139,7 +91,6 @@ const checkPasswordStrength = async function (password: string, ctx: z.Refinemen
|
||||||
errorMessage += ' Be less than 128 characters long.';
|
errorMessage += ' Be less than 128 characters long.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (errorMessage.length > 'Your password:'.length) {
|
if (errorMessage.length > 'Your password:'.length) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
|
|
@ -147,4 +98,4 @@ const checkPasswordStrength = async function (password: string, ctx: z.Refinemen
|
||||||
path: ['password']
|
path: ['password']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
21
src/lib/validations/auth.ts
Normal file
21
src/lib/validations/auth.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { refinePasswords } from "./account";
|
||||||
|
import { userSchema } from "./zod-schemas";
|
||||||
|
|
||||||
|
export const signUpSchema = userSchema
|
||||||
|
.pick({
|
||||||
|
firstName: true,
|
||||||
|
lastName: true,
|
||||||
|
email: true,
|
||||||
|
username: true,
|
||||||
|
password: true,
|
||||||
|
confirm_password: true,
|
||||||
|
terms: true
|
||||||
|
})
|
||||||
|
.superRefine(({ confirm_password, password }, ctx) => {
|
||||||
|
refinePasswords(confirm_password, password, ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const signInSchema = userSchema.pick({
|
||||||
|
username: true,
|
||||||
|
password: true
|
||||||
|
});
|
||||||
45
src/lib/validations/zod-schemas.ts
Normal file
45
src/lib/validations/zod-schemas.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export type ListGame = {
|
||||||
|
id: string;
|
||||||
|
game_name: string;
|
||||||
|
game_id: string;
|
||||||
|
collection_id: string;
|
||||||
|
wishlist_id: string;
|
||||||
|
times_played: number;
|
||||||
|
thumb_url: string | null;
|
||||||
|
in_collection: boolean;
|
||||||
|
in_wishlist: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modifyListGameSchema = z.object({
|
||||||
|
id: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ModifyListGame = typeof modifyListGameSchema;
|
||||||
|
|
||||||
|
export const userSchema = z.object({
|
||||||
|
firstName: z.string().trim().optional(),
|
||||||
|
lastName: z.string().trim().optional(),
|
||||||
|
email: z.string()
|
||||||
|
.trim()
|
||||||
|
.max(64, { message: 'Email must be less than 64 characters' })
|
||||||
|
.email({ message: 'Please enter a valid email address' })
|
||||||
|
.optional(),
|
||||||
|
username: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(3, { message: 'Username must be at least 3 characters' })
|
||||||
|
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||||
|
password: z
|
||||||
|
.string({ required_error: 'Password is required' })
|
||||||
|
.trim(),
|
||||||
|
confirm_password: z
|
||||||
|
.string({ required_error: 'Confirm Password is required' })
|
||||||
|
.trim(),
|
||||||
|
verified: z.boolean().default(false),
|
||||||
|
token: z.string().optional(),
|
||||||
|
receiveEmail: z.boolean().default(false),
|
||||||
|
createdAt: z.date().optional(),
|
||||||
|
updatedAt: z.date().optional()
|
||||||
|
});
|
||||||
|
|
@ -4,11 +4,11 @@ import { drizzle } from 'drizzle-orm/postgres-js';
|
||||||
import { migrate } from 'drizzle-orm/postgres-js/migrator';
|
import { migrate } from 'drizzle-orm/postgres-js/migrator';
|
||||||
|
|
||||||
const connection = postgres({
|
const connection = postgres({
|
||||||
host: process.env.DATABASE_HOST,
|
host: process.env.DATABASE_HOST || 'localhost',
|
||||||
port: 3306,
|
port: 3306,
|
||||||
user: process.env.DATABASE_USER,
|
user: process.env.DATABASE_USER || 'root',
|
||||||
password: process.env.DATABASE_PASSWORD,
|
password: process.env.DATABASE_PASSWORD || '',
|
||||||
database: process.env.DATABASE_DB,
|
database: process.env.DATABASE_DB || 'boredgame',
|
||||||
ssl: 'require',
|
ssl: 'require',
|
||||||
max: 1
|
max: 1
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||||
|
import { and, eq } from 'drizzle-orm';
|
||||||
import { superValidate } from 'sveltekit-superforms/server';
|
import { superValidate } from 'sveltekit-superforms/server';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
|
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
|
||||||
import { search_schema } from '$lib/zodValidation.js';
|
import { search_schema } from '$lib/zodValidation.js';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import db from '$lib/drizzle';
|
import db from '$lib/drizzle';
|
||||||
import { and, eq } from 'drizzle-orm';
|
|
||||||
import { collection_items, collections, games } from '../../../../schema';
|
import { collection_items, collections, games } from '../../../../schema';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||||
|
|
@ -26,8 +27,8 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||||
skip
|
skip
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchForm = await superValidate(searchData, search_schema);
|
const searchForm = await superValidate(searchData, zod(search_schema));
|
||||||
const listManageForm = await superValidate(modifyListGameSchema);
|
const listManageForm = await superValidate(zod(modifyListGameSchema));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const collection = await db.query.collections.findFirst({
|
const collection = await db.query.collections.findFirst({
|
||||||
|
|
@ -98,7 +99,7 @@ export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
// Add game to a wishlist
|
// Add game to a wishlist
|
||||||
add: async (event) => {
|
add: async (event) => {
|
||||||
const form = await superValidate(event, modifyListGameSchema);
|
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||||
|
|
||||||
if (!event.locals.user) {
|
if (!event.locals.user) {
|
||||||
throw fail(401);
|
throw fail(401);
|
||||||
|
|
@ -160,7 +161,7 @@ export const actions: Actions = {
|
||||||
// Remove game from a wishlist
|
// Remove game from a wishlist
|
||||||
remove: async (event) => {
|
remove: async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event;
|
||||||
const form = await superValidate(event, modifyListGameSchema);
|
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||||
|
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
throw fail(401);
|
throw fail(401);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { redirect } from "@sveltejs/kit";
|
import { redirect } from "@sveltejs/kit";
|
||||||
|
import { superValidate } from "sveltekit-superforms/server";
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import type { PageServerLoad } from "../$types";
|
import type { PageServerLoad } from "../$types";
|
||||||
import { BggForm } from "$lib/zodValidation";
|
import { BggForm } from "$lib/zodValidation";
|
||||||
import { superValidate } from "sveltekit-superforms/server";
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ locals, fetch }) => {
|
export const load: PageServerLoad = async ({ locals, fetch }) => {
|
||||||
const user = locals.user;
|
const user = locals.user;
|
||||||
|
|
@ -9,7 +10,7 @@ export const load: PageServerLoad = async ({ locals, fetch }) => {
|
||||||
redirect(302, '/login');
|
redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
const form = await superValidate({}, BggForm);
|
const form = await superValidate({}, zod(BggForm));
|
||||||
|
|
||||||
return { form };
|
return { form };
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ export const actions: Actions = {
|
||||||
// Add game to a wishlist
|
// Add game to a wishlist
|
||||||
add: async (event) => {
|
add: async (event) => {
|
||||||
const { params, locals, request } = event;
|
const { params, locals, request } = event;
|
||||||
const form = await superValidate(event, modifyListGameSchema);
|
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||||
|
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
throw fail(401);
|
throw fail(401);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { fail, redirect, type Actions } from "@sveltejs/kit";
|
import { fail, redirect, type Actions } from "@sveltejs/kit";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
import { Argon2id } from "oslo/password";
|
import { Argon2id } from "oslo/password";
|
||||||
import db from "$lib/drizzle";
|
import db from "$lib/drizzle";
|
||||||
|
|
@ -9,7 +10,7 @@ import type { PageServerLoad } from "./$types";
|
||||||
import { users } from "../../../../../schema";
|
import { users } from "../../../../../schema";
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const form = await superValidate(event, changeUserPasswordSchema);
|
const form = await superValidate(event, zod(changeUserPasswordSchema));
|
||||||
const user = event.locals.user;
|
const user = event.locals.user;
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
@ -28,7 +29,7 @@ export const load: PageServerLoad = async (event) => {
|
||||||
|
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
default: async (event) => {
|
default: async (event) => {
|
||||||
const form = await superValidate(event, changeUserPasswordSchema);
|
const form = await superValidate(event, zod(changeUserPasswordSchema));
|
||||||
|
|
||||||
if (!form.valid) {
|
if (!form.valid) {
|
||||||
return fail(400, {
|
return fail(400, {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import { changeUserPasswordSchema, userSchema } from '$lib/config/zod-schemas';
|
import { changeUserPasswordSchema, userSchema } from '$lib/validations/zod-schemas.js';
|
||||||
import { Label } from '$components/ui/label';
|
import { Label } from '$components/ui/label';
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
|
|
@ -9,7 +10,7 @@
|
||||||
|
|
||||||
const { form, errors, enhance, delayed, message } = superForm(data.form, {
|
const { form, errors, enhance, delayed, message } = superForm(data.form, {
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: changeUserPasswordSchema,
|
validators: zodClient(changeUserPasswordSchema),
|
||||||
delayMs: 0
|
delayMs: 0
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { fail, type Actions } from '@sveltejs/kit';
|
import { fail, type Actions } from '@sveltejs/kit';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { message, setError, superValidate } from 'sveltekit-superforms/server';
|
import { message, setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
import { redirect } from 'sveltekit-flash-message/server';
|
import { redirect } from 'sveltekit-flash-message/server';
|
||||||
import { userSchema } from '$lib/config/zod-schemas';
|
import { userSchema } from '$lib/validations/zod-schemas';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { users } from '../../../../schema';
|
import { users } from '../../../../schema';
|
||||||
import db from '$lib/drizzle';
|
import db from '$lib/drizzle';
|
||||||
|
|
@ -15,7 +16,7 @@ const profileSchema = userSchema.pick({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const form = await superValidate(event, profileSchema);
|
const form = await superValidate(event, zod(profileSchema));
|
||||||
|
|
||||||
if (!event.locals.user) {
|
if (!event.locals.user) {
|
||||||
const message = { type: 'error', message: 'You are not signed in' } as const;
|
const message = { type: 'error', message: 'You are not signed in' } as const;
|
||||||
|
|
@ -37,7 +38,7 @@ export const load: PageServerLoad = async (event) => {
|
||||||
|
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
default: async (event) => {
|
default: async (event) => {
|
||||||
const form = await superValidate(event, profileSchema);
|
const form = await superValidate(event, zod(profileSchema));
|
||||||
|
|
||||||
if (!form.valid) {
|
if (!form.valid) {
|
||||||
return fail(400, {
|
return fail(400, {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import { AlertTriangle, KeyRound } from 'lucide-svelte';
|
import { AlertTriangle, KeyRound } from 'lucide-svelte';
|
||||||
import { userSchema } from '$lib/config/zod-schemas';
|
import { profileSchema } from '$lib/validations/account';
|
||||||
import * as Alert from "$lib/components/ui/alert";
|
import * as Alert from "$lib/components/ui/alert";
|
||||||
import { Label } from '$lib/components/ui/label';
|
import { Label } from '$lib/components/ui/label';
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
|
|
@ -9,16 +10,9 @@
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
const profileSchema = userSchema.pick({
|
|
||||||
firstName: true,
|
|
||||||
lastName: true,
|
|
||||||
email: true,
|
|
||||||
username: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const { form, errors, enhance, message } = superForm(data.form, {
|
const { form, errors, enhance, message } = superForm(data.form, {
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: profileSchema,
|
validators: zodClient(profileSchema),
|
||||||
delayMs: 0
|
delayMs: 0
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { error, redirect, type Actions } from '@sveltejs/kit';
|
import { error, redirect, type Actions } from '@sveltejs/kit';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { superValidate } from 'sveltekit-superforms/server';
|
import { superValidate } from 'sveltekit-superforms/server';
|
||||||
import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
|
import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
|
||||||
import db from '$lib/drizzle.js';
|
import db from '$lib/drizzle.js';
|
||||||
|
|
@ -49,7 +50,7 @@ export const actions: Actions = {
|
||||||
// Add game to a wishlist
|
// Add game to a wishlist
|
||||||
add: async (event) => {
|
add: async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event;
|
||||||
const form = await superValidate(event, modifyListGameSchema);
|
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
|
|
@ -111,7 +112,7 @@ export const actions: Actions = {
|
||||||
// Remove game from a wishlist
|
// Remove game from a wishlist
|
||||||
remove: async (event) => {
|
remove: async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event;
|
||||||
const form = await superValidate(event, modifyListGameSchema);
|
const form = await superValidate(event, zod(modifyListGameSchema));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!locals.user) {
|
if (!locals.user) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade, fly } from 'svelte/transition';
|
|
||||||
import { Image } from 'svelte-lazy-loader';
|
import { Image } from 'svelte-lazy-loader';
|
||||||
import { Dices, ExternalLinkIcon, MinusIcon, PlusIcon } from 'lucide-svelte';
|
import { Dices, ExternalLinkIcon, MinusIcon, PlusIcon } from 'lucide-svelte';
|
||||||
import type { SavedGameType } from '$lib/types';
|
import type { SavedGameType } from '$lib/types';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { superValidate } from 'sveltekit-superforms/server';
|
import { superValidate } from 'sveltekit-superforms/server';
|
||||||
import kebabCase from 'just-kebab-case';
|
import kebabCase from 'just-kebab-case';
|
||||||
import type { GameType, SearchQuery } from '$lib/types';
|
import type { GameType, SearchQuery } from '$lib/types';
|
||||||
|
|
@ -16,7 +17,7 @@ async function searchForGames(
|
||||||
try {
|
try {
|
||||||
console.log('urlQueryParams search games', urlQueryParams);
|
console.log('urlQueryParams search games', urlQueryParams);
|
||||||
|
|
||||||
const headers: HeadersInit = new Headers();
|
const headers = new Headers();
|
||||||
headers.set('Content-Type', 'application/json');
|
headers.set('Content-Type', 'application/json');
|
||||||
const requestInit: RequestInit = {
|
const requestInit: RequestInit = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|
@ -112,7 +113,7 @@ export const load: PageServerLoad = async ({ locals, fetch, url }) => {
|
||||||
skip: Number(searchParams.skip || defaults.skip),
|
skip: Number(searchParams.skip || defaults.skip),
|
||||||
limit: Number(searchParams.limit || defaults.limit),
|
limit: Number(searchParams.limit || defaults.limit),
|
||||||
exact: searchParams.exact ? searchParams.exact === 'true' : defaults.exact
|
exact: searchParams.exact ? searchParams.exact === 'true' : defaults.exact
|
||||||
}, search_schema);
|
}, zod(search_schema));
|
||||||
|
|
||||||
const queryParams: SearchQuery = {
|
const queryParams: SearchQuery = {
|
||||||
limit: form.data?.limit,
|
limit: form.data?.limit,
|
||||||
|
|
@ -189,7 +190,7 @@ export const load: PageServerLoad = async ({ locals, fetch, url }) => {
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
random: async ({ request, locals, fetch }): Promise<any> => {
|
random: async ({ request, locals, fetch }): Promise<any> => {
|
||||||
const form = await superValidate(request, search_schema);
|
const form = await superValidate(request, zod(search_schema));
|
||||||
const queryParams: SearchQuery = {
|
const queryParams: SearchQuery = {
|
||||||
order_by: 'rank',
|
order_by: 'rank',
|
||||||
ascending: false,
|
ascending: false,
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,17 @@
|
||||||
import { fail, type Actions } from '@sveltejs/kit';
|
import { fail, type Actions } from '@sveltejs/kit';
|
||||||
import { eq, sql } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
import { redirect } from 'sveltekit-flash-message/server';
|
import { redirect } from 'sveltekit-flash-message/server';
|
||||||
import { lucia } from '$lib/server/auth';
|
import { lucia } from '$lib/server/auth';
|
||||||
import { Argon2id } from 'oslo/password';
|
import { Argon2id } from 'oslo/password';
|
||||||
import { userSchema } from '$lib/config/zod-schemas';
|
|
||||||
import db from '$lib/drizzle';
|
import db from '$lib/drizzle';
|
||||||
|
import { signInSchema } from '$lib/validations/auth'
|
||||||
import { collections, users, wishlists } from '../../../schema';
|
import { collections, users, wishlists } from '../../../schema';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
const signInSchema = userSchema.pick({
|
|
||||||
username: true,
|
|
||||||
password: true
|
|
||||||
});
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const form = await superValidate(event, signInSchema);
|
const form = await superValidate(event, zod(signInSchema));
|
||||||
|
|
||||||
console.log('login load event', event);
|
console.log('login load event', event);
|
||||||
if (event.locals.user) {
|
if (event.locals.user) {
|
||||||
|
|
@ -31,7 +27,7 @@ export const load: PageServerLoad = async (event) => {
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
default: async (event) => {
|
default: async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event;
|
||||||
const form = await superValidate(event, signInSchema);
|
const form = await superValidate(event, zod(signInSchema));
|
||||||
|
|
||||||
if (!form.valid) {
|
if (!form.valid) {
|
||||||
form.data.password = '';
|
form.data.password = '';
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import * as flashModule from 'sveltekit-flash-message/client';
|
import * as flashModule from 'sveltekit-flash-message/client';
|
||||||
import { AlertCircle } from "lucide-svelte";
|
import { AlertCircle } from "lucide-svelte";
|
||||||
import { signInSchema } from '$lib/config/zod-schemas.js';
|
import { signInSchema } from '$lib/validations/zod-schemas.js';
|
||||||
import { Label } from '$components/ui/label';
|
import { Label } from '$components/ui/label';
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
},
|
},
|
||||||
syncFlashMessage: false,
|
syncFlashMessage: false,
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: signInSchema,
|
validators: zodClient(signInSchema),
|
||||||
validationMethod: 'oninput',
|
validationMethod: 'oninput',
|
||||||
delayMs: 0,
|
delayMs: 0,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import { quintIn } from 'svelte/easing';
|
import { quintIn } from 'svelte/easing';
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import * as flashModule from 'sveltekit-flash-message/client';
|
import * as flashModule from 'sveltekit-flash-message/client';
|
||||||
import { ChevronsUpDown } from "lucide-svelte";
|
import { ChevronsUpDown } from "lucide-svelte";
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
import { Label } from '$components/ui/label';
|
import { Label } from '$components/ui/label';
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
import { signUpSchema } from '$lib/config/zod-schemas.js';
|
import { signUpSchema } from '$lib/validations/zod-schemas.js';
|
||||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||||
import * as Alert from '$lib/components/ui/alert';
|
import * as Alert from '$lib/components/ui/alert';
|
||||||
import { boredState } from '$lib/stores/boredState.js';
|
import { boredState } from '$lib/stores/boredState.js';
|
||||||
|
|
@ -25,7 +26,7 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: signUpSchema,
|
validators: zodClient(signUpSchema),
|
||||||
delayMs: 0,
|
delayMs: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue