mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Updating shadcn files, moving routes around.
This commit is contained in:
parent
ea9a0f60a8
commit
13162f8270
84 changed files with 1553 additions and 770 deletions
19
package.json
19
package.json
|
|
@ -26,7 +26,7 @@
|
|||
"@playwright/test": "^1.37.0",
|
||||
"@sveltejs/adapter-auto": "^1.0.3",
|
||||
"@sveltejs/adapter-vercel": "^1.0.6",
|
||||
"@sveltejs/kit": "^1.22.6",
|
||||
"@sveltejs/kit": "^1.24.1",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@types/node": "^18.17.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
|
|
@ -37,27 +37,27 @@
|
|||
"eslint-plugin-svelte": "^2.32.4",
|
||||
"just-clone": "^6.2.0",
|
||||
"just-debounce-it": "^3.2.0",
|
||||
"postcss": "^8.4.27",
|
||||
"postcss": "^8.4.29",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"postcss-preset-env": "^8.5.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"prisma": "^5.1.1",
|
||||
"prisma": "^5.2.0",
|
||||
"sass": "^1.65.1",
|
||||
"svelte": "^4.2.0",
|
||||
"svelte-check": "^3.5.0",
|
||||
"svelte-preprocess": "^5.0.4",
|
||||
"svelte-sequential-preprocessor": "^2.0.1",
|
||||
"sveltekit-flash-message": "^2.2.0",
|
||||
"sveltekit-superforms": "^1.6.0",
|
||||
"sveltekit-superforms": "^1.6.1",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "^2.6.1",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.4.9",
|
||||
"vitest": "^0.25.3",
|
||||
"zod": "^3.21.4"
|
||||
"zod": "^3.22.2"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
|
|
@ -67,12 +67,12 @@
|
|||
"dependencies": {
|
||||
"@axiomhq/axiom-node": "^0.12.0",
|
||||
"@fontsource/fira-mono": "^4.5.10",
|
||||
"@iconify-icons/line-md": "^1.2.23",
|
||||
"@iconify-icons/line-md": "^1.2.26",
|
||||
"@iconify-icons/mdi": "^1.2.47",
|
||||
"@lucia-auth/adapter-mysql": "^2.0.0",
|
||||
"@lucia-auth/adapter-prisma": "^3.0.1",
|
||||
"@lukeed/uuid": "^2.0.1",
|
||||
"@melt-ui/svelte": "^0.37.5",
|
||||
"@melt-ui/svelte": "^0.37.6",
|
||||
"@prisma/client": "5.1.1",
|
||||
"@types/feather-icons": "^4.29.1",
|
||||
"bits-ui": "^0.0.27",
|
||||
|
|
@ -80,12 +80,13 @@
|
|||
"clsx": "^1.2.1",
|
||||
"cookie": "^0.5.0",
|
||||
"feather-icons": "^4.29.1",
|
||||
"formsnap": "^0.0.9",
|
||||
"iconify-icon": "^1.0.8",
|
||||
"just-kebab-case": "^4.2.0",
|
||||
"loader": "^2.1.1",
|
||||
"lucia": "^2.4.0",
|
||||
"lucia": "^2.4.2",
|
||||
"lucide-svelte": "^0.256.1",
|
||||
"open-props": "^1.5.11",
|
||||
"open-props": "^1.5.13",
|
||||
"radix-svelte": "^0.9.0",
|
||||
"svelte-french-toast": "^1.2.0",
|
||||
"svelte-lazy": "^1.2.1",
|
||||
|
|
|
|||
597
pnpm-lock.yaml
597
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,5 @@
|
|||
const tailwindcss = require("tailwindcss");
|
||||
const tailwindNesting = require('tailwindcss/nesting');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const postcssPresetEnv = require('postcss-preset-env');
|
||||
const atImport = require('postcss-import');
|
||||
|
|
@ -6,7 +7,7 @@ const atImport = require('postcss-import');
|
|||
const config = {
|
||||
plugins: [
|
||||
atImport(),
|
||||
// 'tailwindcss/nesting'(),
|
||||
tailwindNesting(),
|
||||
tailwindcss(),
|
||||
postcssPresetEnv({
|
||||
stage: 2,
|
||||
|
|
@ -16,8 +17,6 @@ const config = {
|
|||
'media-query-ranges': true
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
] //Some plugins, like tailwindcss/nesting, need to run before Tailwind, tailwindcss(), //But others, like autoprefixer, need to run after, autoprefixer]
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,46 +5,46 @@
|
|||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 224 71.4% 4.1%;
|
||||
--foreground: 20 14.3% 4.1%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 224 71.4% 4.1%;
|
||||
--card-foreground: 20 14.3% 4.1%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 224 71.4% 4.1%;
|
||||
--primary: 262.1 83.3% 57.8%;
|
||||
--primary-foreground: 210 20% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
--muted: 220 14.3% 95.9%;
|
||||
--muted-foreground: 220 8.9% 46.1%;
|
||||
--accent: 220 14.3% 95.9%;
|
||||
--accent-foreground: 220.9 39.3% 11%;
|
||||
--popover-foreground: 20 14.3% 4.1%;
|
||||
--primary: 47.9 95.8% 53.1%;
|
||||
--primary-foreground: 26 83.3% 14.1%;
|
||||
--secondary: 60 4.8% 95.9%;
|
||||
--secondary-foreground: 24 9.8% 10%;
|
||||
--muted: 60 4.8% 95.9%;
|
||||
--muted-foreground: 25 5.3% 44.7%;
|
||||
--accent: 60 4.8% 95.9%;
|
||||
--accent-foreground: 24 9.8% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 20% 98%;
|
||||
--border: 220 13% 91%;
|
||||
--input: 220 13% 91%;
|
||||
--ring: 262.1 83.3% 57.8%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
--border: 20 5.9% 90%;
|
||||
--input: 20 5.9% 90%;
|
||||
--ring: 20 14.3% 4.1%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
.dark {
|
||||
--background: 224 71.4% 4.1%;
|
||||
--foreground: 210 20% 98%;
|
||||
--card: 224 71.4% 4.1%;
|
||||
--card-foreground: 210 20% 98%;
|
||||
--popover: 224 71.4% 4.1%;
|
||||
--popover-foreground: 210 20% 98%;
|
||||
--primary: 263.4 70% 50.4%;
|
||||
--primary-foreground: 210 20% 98%;
|
||||
--secondary: 215 27.9% 16.9%;
|
||||
--secondary-foreground: 210 20% 98%;
|
||||
--muted: 215 27.9% 16.9%;
|
||||
--muted-foreground: 217.9 10.6% 64.9%;
|
||||
--accent: 215 27.9% 16.9%;
|
||||
--accent-foreground: 210 20% 98%;
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 60 9.1% 97.8%;
|
||||
--card: 20 14.3% 4.1%;
|
||||
--card-foreground: 60 9.1% 97.8%;
|
||||
--popover: 20 14.3% 4.1%;
|
||||
--popover-foreground: 60 9.1% 97.8%;
|
||||
--primary: 47.9 95.8% 53.1%;
|
||||
--primary-foreground: 26 83.3% 14.1%;
|
||||
--secondary: 12 6.5% 15.1%;
|
||||
--secondary-foreground: 60 9.1% 97.8%;
|
||||
--muted: 12 6.5% 15.1%;
|
||||
--muted-foreground: 24 5.4% 63.9%;
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 60 9.1% 97.8%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 20% 98%;
|
||||
--border: 215 27.9% 16.9%;
|
||||
--input: 215 27.9% 16.9%;
|
||||
--ring: 263.4 70% 50.4%;
|
||||
--destructive-foreground: 60 9.1% 97.8%;
|
||||
--border: 12 6.5% 15.1%;
|
||||
--input: 12 6.5% 15.1%;
|
||||
--ring: 35.5 91.7% 32.9%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
|||
console.log('user', session?.user);
|
||||
event.locals.user = session?.user;
|
||||
// if (event.route.id?.startsWith('/(protected)')) {
|
||||
// if (!user) throw redirect(302, '/auth/sign-in');
|
||||
// if (!user.verified) throw redirect(302, '/auth/verify/email');
|
||||
// if (!user) throw redirect(302, '/sign-in');
|
||||
// if (!user.verified) throw redirect(302, '/verify/email');
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('Error validating user', error);
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
|
@ -3,7 +3,7 @@
|
|||
import { fly } from "svelte/transition";
|
||||
import { createSelect, melt } from "@melt-ui/svelte";
|
||||
import { Check, ChevronDown, MinusCircle, PlusCircle } from "lucide-svelte";
|
||||
import Button from "./ui/button/Button.svelte";
|
||||
import { Button } from '$components/ui/button';
|
||||
import type { Collection, Wishlist } from "@prisma/client";
|
||||
|
||||
export let game_id: string;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import Button from "./ui/button/Button.svelte";
|
||||
import { Button } from '$components/ui/button';
|
||||
</script>
|
||||
|
||||
<Button type="submit">Add to wishlist</Button>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,21 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import { LogOut } from 'lucide-svelte';
|
||||
import { Button } from '$components/ui/button';
|
||||
import { Separator } from "$components/ui/separator";
|
||||
import logo from './bored-game.png';
|
||||
import { Avatar, AvatarFallback } from '$components/ui/avatar';
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetContent,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger
|
||||
} from "$components/ui/sheet";
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Toggle } from "$lib/components/ui/toggle";
|
||||
import * as Avatar from "$lib/components/ui/avatar";
|
||||
import * as Sheet from "$lib/components/ui/sheet";
|
||||
import Logo from '$components/logo.svelte';
|
||||
|
||||
export let user: any;
|
||||
|
||||
let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
|
||||
</script>
|
||||
|
||||
<header>
|
||||
<div class="corner">
|
||||
<a href="/" title="Home">
|
||||
<img src={logo} alt="Bored Game Home" />
|
||||
<Logo />
|
||||
</a>
|
||||
</div>
|
||||
<!-- <TextSearch /> -->
|
||||
|
|
@ -29,39 +23,42 @@
|
|||
{#if user}
|
||||
<a href="/collection" title="Go to your collection" data-sveltekit-preload-data>Collection</a>
|
||||
<a href="/wishlist" title="Go to your wishlist" data-sveltekit-preload-data>Wishlist</a>
|
||||
<Sheet>
|
||||
<SheetTrigger>
|
||||
<Avatar class="h-16 w-16 bg-neutral-100">
|
||||
<AvatarFallback class="text-3xl font-medium text-magnum-700">
|
||||
{user?.username.slice(0, 1).toUpperCase() || '?'}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
</SheetTrigger>
|
||||
<SheetContent position="right" size="lg">
|
||||
<SheetHeader>
|
||||
<SheetTitle>Menu</SheetTitle>
|
||||
</SheetHeader>
|
||||
<Sheet.Root>
|
||||
<Sheet.Trigger>
|
||||
<Avatar.Root asChild>
|
||||
<Avatar.Fallback class="text-3xl font-medium text-magnum-700 h-16 w-16 bg-neutral-100">
|
||||
{avatar}
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
</Sheet.Trigger>
|
||||
<Sheet.Content side="right">
|
||||
<Sheet.Header>
|
||||
<Sheet.Title>Menu</Sheet.Title>
|
||||
<Toggle aria-label="toggle bold">
|
||||
|
||||
</Toggle>
|
||||
</Sheet.Header>
|
||||
<div class="menu">
|
||||
<div class="item">
|
||||
<SheetClose>
|
||||
<Button variant="link" href="/profile">View Profile</Button>
|
||||
</SheetClose>
|
||||
</div>
|
||||
<div class="item">
|
||||
<SheetClose>
|
||||
<Button variant="link" href="/collection">Your Collection</Button>
|
||||
</SheetClose>
|
||||
</div>
|
||||
<div class="item">
|
||||
<SheetClose>
|
||||
<Button variant="link" href="/wishlist">Your Wishlist</Button>
|
||||
</SheetClose>
|
||||
</div>
|
||||
<Sheet.Close asChild let:builder>
|
||||
<div class="item">
|
||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/profile">View Profile</Button>
|
||||
</div>
|
||||
</Sheet.Close>
|
||||
<Sheet.Close asChild let:builder>
|
||||
<div class="item">
|
||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/collection">Your Collection</Button>
|
||||
</div>
|
||||
</Sheet.Close>
|
||||
<Sheet.Close asChild let:builder>
|
||||
<div class="item">
|
||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/wishlist">Your Wishlist</Button>
|
||||
</div>
|
||||
</Sheet.Close>
|
||||
<div class="separator" />
|
||||
<div class="item">
|
||||
<form
|
||||
use:enhance
|
||||
action="/auth/signout"
|
||||
action="/logout"
|
||||
method="POST"
|
||||
>
|
||||
<Button type="submit">
|
||||
|
|
@ -71,33 +68,22 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<SheetClose>
|
||||
<Button type="button">Close</Button>
|
||||
</SheetClose>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
<!-- <form
|
||||
use:enhance
|
||||
action="/auth/signout"
|
||||
method="POST"
|
||||
>
|
||||
<Button type="submit">
|
||||
<LogOut class="mr-2 h-4 w-4"/>
|
||||
Sign out
|
||||
</Button>
|
||||
</form> -->
|
||||
<Sheet.Footer>
|
||||
<Sheet.Close asChild let:builder>
|
||||
<Button builders={[builder]} type="button">Close</Button>
|
||||
</Sheet.Close>
|
||||
</Sheet.Footer>
|
||||
</Sheet.Content>
|
||||
</Sheet.Root>
|
||||
{/if}
|
||||
{#if !user}
|
||||
<a href="/auth/signin">
|
||||
<span class="flex-auto">Sign In</span></a
|
||||
<a href="/login">
|
||||
<span class="flex-auto">Login</span></a
|
||||
>
|
||||
<a href="/auth/signup">
|
||||
<a href="/sign-up">
|
||||
<span class="flex-auto">Sign Up</span></a
|
||||
>
|
||||
{/if}
|
||||
<!-- <Profile /> -->
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
|
|
@ -119,12 +105,13 @@
|
|||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 0.2rem;
|
||||
/* margin: 0.2rem 0; */
|
||||
}
|
||||
|
||||
.corner {
|
||||
width: 3em;
|
||||
height: 3em;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.corner a {
|
||||
|
|
|
|||
5
src/lib/components/logo.svelte
Normal file
5
src/lib/components/logo.svelte
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<script lang="ts">
|
||||
import logo from '$lib/assets/bored-game.png';
|
||||
</script>
|
||||
|
||||
<img src={logo} alt="Bored Game Home" />
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
import { ToastType } from '$lib/types';
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import { toast } from '../../toast/toast';
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
import { Button } from '$components/ui/button';
|
||||
|
||||
export let data: SuperValidated<SearchSchema>;
|
||||
const { enhance } = superForm(data, {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
];
|
||||
</script>
|
||||
|
||||
<form method="POST" action="/auth/sign-in" use:enhance>
|
||||
<form method="POST" action="/sign-in" use:enhance>
|
||||
<!--<SuperDebug data={$form} />-->
|
||||
{#if $errors._errors}
|
||||
<aside class="alert variant-filled-error mt-6">
|
||||
|
|
@ -77,6 +77,6 @@
|
|||
>
|
||||
</div>
|
||||
<div class="flex flex-row justify-center items-center mt-10">
|
||||
<a href="/auth/password/reset" class="font-semibold">{i("forgotPassword")}</a>
|
||||
<a href="/password/reset" class="font-semibold">{i("forgotPassword")}</a>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
// $: termsValue = $form.terms as Writable<boolean>;
|
||||
</script>
|
||||
|
||||
<form method="POST" action="/auth/signup" use:enhance>
|
||||
<form method="POST" action="/sign-up" use:enhance>
|
||||
<h1>Signup user</h1>
|
||||
<label class="label">
|
||||
<span class="sr-only">First Name</span>
|
||||
|
|
@ -105,7 +105,7 @@
|
|||
<small>{$errors.password}</small>
|
||||
{/if}
|
||||
</label>
|
||||
|
||||
|
||||
<button type="submit">Signup</button>
|
||||
|
||||
<a class="back" href="/"> or Cancel </a>
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
const alertVariants = cva(
|
||||
"relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let variant: VariantProps<typeof alertVariants>["variant"] =
|
||||
"default";
|
||||
</script>
|
||||
|
||||
<div class={cn(alertVariants({ variant }), className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let level: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" = "h5";
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={level}
|
||||
class={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
21
src/lib/components/ui/alert/alert-title.svelte
Normal file
21
src/lib/components/ui/alert/alert-title.svelte
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import type { HeadingLevel } from ".";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
|
||||
level?: HeadingLevel;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let level: $$Props["level"] = "h5";
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={level}
|
||||
class={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
||||
21
src/lib/components/ui/alert/alert.svelte
Normal file
21
src/lib/components/ui/alert/alert.svelte
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { alertVariants, type Variant } from ".";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLDivElement> & {
|
||||
variant?: Variant;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let variant: $$Props["variant"] = "default";
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn(alertVariants({ variant }), className)}
|
||||
{...$$restProps}
|
||||
role="alert"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
|
@ -1,3 +1,33 @@
|
|||
export { default as Alert } from "./Alert.svelte";
|
||||
export { default as AlertDescription } from "./AlertDescription.svelte";
|
||||
export { default as AlertTitle } from "./AlertTitle.svelte";
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
|
||||
import Root from "./alert.svelte";
|
||||
import Description from "./alert-description.svelte";
|
||||
import Title from "./alert-title.svelte";
|
||||
|
||||
export const alertVariants = tv({
|
||||
base: "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11",
|
||||
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type Variant = VariantProps<typeof alertVariants>["variant"];
|
||||
export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Description,
|
||||
Title,
|
||||
//
|
||||
Root as Alert,
|
||||
Description as AlertDescription,
|
||||
Title as AlertTitle
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import type {
|
||||
HTMLAnchorAttributes,
|
||||
HTMLButtonAttributes
|
||||
} from "svelte/elements";
|
||||
import { cn } from "$lib/utils";
|
||||
import { buttonVariants } from ".";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let href: HTMLAnchorAttributes["href"] = undefined;
|
||||
export let type: HTMLButtonAttributes["type"] = undefined;
|
||||
export let variant: VariantProps<typeof buttonVariants>["variant"] =
|
||||
"default";
|
||||
export let size: VariantProps<typeof buttonVariants>["size"] = "default";
|
||||
|
||||
type Props = {
|
||||
class?: string | null;
|
||||
variant?: VariantProps<typeof buttonVariants>["variant"];
|
||||
size?: VariantProps<typeof buttonVariants>["size"];
|
||||
};
|
||||
|
||||
interface AnchorElement extends Props, HTMLAnchorAttributes {
|
||||
href?: HTMLAnchorAttributes["href"];
|
||||
type?: never;
|
||||
}
|
||||
|
||||
interface ButtonElement extends Props, HTMLButtonAttributes {
|
||||
type?: HTMLButtonAttributes["type"];
|
||||
href?: never;
|
||||
}
|
||||
|
||||
type $$Props = AnchorElement | ButtonElement;
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={href ? "a" : "button"}
|
||||
type={href ? undefined : type}
|
||||
{href}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:change
|
||||
on:keydown
|
||||
on:keyup
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
||||
27
src/lib/components/ui/button/button.svelte
Normal file
27
src/lib/components/ui/button/button.svelte
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<script lang="ts">
|
||||
import { Button as ButtonPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
import { buttonVariants, type Size, type Variant } from ".";
|
||||
|
||||
type $$Props = ButtonPrimitive.Props & {
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
};
|
||||
type $$Events = ButtonPrimitive.Events;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let variant: $$Props["variant"] = "default";
|
||||
export let size: $$Props["size"] = "default";
|
||||
export let builders: $$Props["builders"] = [];
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<ButtonPrimitive.Root
|
||||
{builders}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</ButtonPrimitive.Root>
|
||||
|
|
@ -1,32 +1,35 @@
|
|||
import { cva } from "class-variance-authority";
|
||||
import Root from './button.svelte';
|
||||
import { tv, type VariantProps } from 'tailwind-variants';
|
||||
|
||||
export { default as Button } from "./Button.svelte";
|
||||
|
||||
export const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "underline-offset-4 hover:underline text-primary"
|
||||
},
|
||||
size: {
|
||||
default: "h-10 py-2 px-4",
|
||||
sm: "h-9 px-3 rounded-md",
|
||||
lg: "h-11 px-8 rounded-md"
|
||||
}
|
||||
export const buttonVariants = tv({
|
||||
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline'
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default"
|
||||
size: {
|
||||
default: 'h-10 px-4 py-2',
|
||||
sm: 'h-9 rounded-md px-3',
|
||||
lg: 'h-11 rounded-md px-8',
|
||||
icon: 'h-10 w-10'
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default'
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export type Variant = VariantProps<typeof buttonVariants>['variant'];
|
||||
export type Size = VariantProps<typeof buttonVariants>['size'];
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Button
|
||||
};
|
||||
|
|
|
|||
34
src/lib/components/ui/checkbox/checkbox.svelte
Normal file
34
src/lib/components/ui/checkbox/checkbox.svelte
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<script lang="ts">
|
||||
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||
import { Check, Minus } from "lucide-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = CheckboxPrimitive.Props;
|
||||
type $$Events = CheckboxPrimitive.Events;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let checked: $$Props["checked"] = false;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<CheckboxPrimitive.Root
|
||||
bind:checked
|
||||
class={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
>
|
||||
<CheckboxPrimitive.Indicator
|
||||
class={cn("flex items-center justify-center text-current h-4 w-4")}
|
||||
let:isChecked
|
||||
let:isIndeterminate
|
||||
>
|
||||
{#if isChecked}
|
||||
<Check class="h-4 w-4" />
|
||||
{:else if isIndeterminate}
|
||||
<Minus class="h-4 w-4" />
|
||||
{/if}
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
6
src/lib/components/ui/checkbox/index.ts
Normal file
6
src/lib/components/ui/checkbox/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import Root from "./checkbox.svelte";
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Checkbox
|
||||
};
|
||||
15
src/lib/components/ui/collapsible/collapsible-content.svelte
Normal file
15
src/lib/components/ui/collapsible/collapsible-content.svelte
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
||||
import { slide } from "svelte/transition";
|
||||
|
||||
type $$Props = CollapsiblePrimitive.ContentProps;
|
||||
|
||||
export let transition: $$Props["transition"] = slide;
|
||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||
duration: 150
|
||||
};
|
||||
</script>
|
||||
|
||||
<CollapsiblePrimitive.Content {transition} {transitionConfig} {...$$restProps}>
|
||||
<slot />
|
||||
</CollapsiblePrimitive.Content>
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
import { Collapsible as CollapsiblePrimitive } from "radix-svelte";
|
||||
import { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
||||
import Content from "./collapsible-content.svelte";
|
||||
|
||||
export const Collapsible = CollapsiblePrimitive.Root;
|
||||
const Root = CollapsiblePrimitive.Root;
|
||||
const Trigger = CollapsiblePrimitive.Trigger;
|
||||
|
||||
export const CollapsibleTrigger = CollapsiblePrimitive.Trigger;
|
||||
|
||||
export const CollapsibleContent = CollapsiblePrimitive.Content;
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
Trigger,
|
||||
//
|
||||
Root as Collapsible,
|
||||
Content as CollapsibleContent,
|
||||
Trigger as CollapsibleTrigger
|
||||
};
|
||||
|
|
|
|||
9
src/lib/components/ui/form/form-button.svelte
Normal file
9
src/lib/components/ui/form/form-button.svelte
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<script lang="ts">
|
||||
import * as Button from "$lib/components/ui/button";
|
||||
type $$Props = Button.Props;
|
||||
type $$Events = Button.Events;
|
||||
</script>
|
||||
|
||||
<Button.Root type="submit" {...$$restProps} on:click on:keydown>
|
||||
<slot />
|
||||
</Button.Root>
|
||||
25
src/lib/components/ui/form/form-checkbox.svelte
Normal file
25
src/lib/components/ui/form/form-checkbox.svelte
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
import { getFormField } from "formsnap";
|
||||
import type { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||
import { Checkbox } from "$lib/components/ui/checkbox";
|
||||
type $$Props = CheckboxPrimitive.Props;
|
||||
type $$Events = CheckboxPrimitive.Events;
|
||||
|
||||
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
|
||||
|
||||
const { name, setValue, attrStore, value } = getFormField();
|
||||
const { name: nameAttr, value: valueAttr, ...rest } = $attrStore;
|
||||
</script>
|
||||
|
||||
<Checkbox
|
||||
{...rest}
|
||||
checked={typeof $value === "boolean" ? $value : false}
|
||||
onCheckedChange={(v) => {
|
||||
onCheckedChange?.(v);
|
||||
setValue(v);
|
||||
}}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
/>
|
||||
<input hidden {name} value={$value} />
|
||||
16
src/lib/components/ui/form/form-description.svelte
Normal file
16
src/lib/components/ui/form/form-description.svelte
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<script lang="ts">
|
||||
import { Form as FormPrimitive } from "formsnap";
|
||||
import { cn } from "@/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Description
|
||||
class={cn("text-sm text-muted-foreground", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</FormPrimitive.Description>
|
||||
28
src/lib/components/ui/form/form-input.svelte
Normal file
28
src/lib/components/ui/form/form-input.svelte
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<script lang="ts">
|
||||
import { getFormField } from "formsnap";
|
||||
import type { HTMLInputAttributes } from "svelte/elements";
|
||||
import { Input, type InputEvents } from "$lib/components/ui/input";
|
||||
|
||||
type $$Props = HTMLInputAttributes;
|
||||
type $$Events = InputEvents;
|
||||
|
||||
const { attrStore, value } = getFormField();
|
||||
</script>
|
||||
|
||||
<Input
|
||||
{...$attrStore}
|
||||
bind:value={$value}
|
||||
{...$$restProps}
|
||||
on:blur
|
||||
on:change
|
||||
on:click
|
||||
on:focus
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:keyup
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:paste
|
||||
on:input
|
||||
/>
|
||||
12
src/lib/components/ui/form/form-item.svelte
Normal file
12
src/lib/components/ui/form/form-item.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "@/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("space-y-2", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
||||
21
src/lib/components/ui/form/form-label.svelte
Normal file
21
src/lib/components/ui/form/form-label.svelte
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
import type { Label as LabelPrimitive } from "bits-ui";
|
||||
import { getFormField } from "formsnap";
|
||||
import { cn } from "@/utils";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
|
||||
type $$Props = LabelPrimitive.Props;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
|
||||
const { errors, ids } = getFormField();
|
||||
</script>
|
||||
|
||||
<Label
|
||||
for={ids.input}
|
||||
class={cn($errors && "text-destructive", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</Label>
|
||||
24
src/lib/components/ui/form/form-native-select.svelte
Normal file
24
src/lib/components/ui/form/form-native-select.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts">
|
||||
import { Form as FormPrimitive } from "formsnap";
|
||||
import { buttonVariants } from "$lib/components/ui/button";
|
||||
import { cn } from "@/utils";
|
||||
import { ChevronDown } from "lucide-svelte";
|
||||
import type { HTMLSelectAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLSelectAttributes;
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Select
|
||||
class={cn(
|
||||
buttonVariants({ variant: "outline" }),
|
||||
"appearance-none bg-transparent font-normal",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</FormPrimitive.Select>
|
||||
<ChevronDown class="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
|
||||
22
src/lib/components/ui/form/form-radio-group.svelte
Normal file
22
src/lib/components/ui/form/form-radio-group.svelte
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
import { getFormField } from "formsnap";
|
||||
import type { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
||||
import * as RadioGroup from "$lib/components/ui/radio-group";
|
||||
|
||||
type $$Props = RadioGroupPrimitive.Props;
|
||||
const { attrStore, setValue, name, value } = getFormField();
|
||||
|
||||
export let onValueChange: $$Props["onValueChange"] = undefined;
|
||||
</script>
|
||||
|
||||
<RadioGroup.Root
|
||||
{...$attrStore}
|
||||
onValueChange={(v) => {
|
||||
onValueChange?.(v);
|
||||
setValue(v);
|
||||
}}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
<input hidden {name} value={$value} />
|
||||
</RadioGroup.Root>
|
||||
17
src/lib/components/ui/form/form-select-trigger.svelte
Normal file
17
src/lib/components/ui/form/form-select-trigger.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<script lang="ts">
|
||||
import * as Select from "$lib/components/ui/select";
|
||||
import type { Select as SelectPrimitive } from "bits-ui";
|
||||
import { getFormField } from "formsnap";
|
||||
|
||||
type $$Props = SelectPrimitive.TriggerProps & {
|
||||
placeholder?: string;
|
||||
};
|
||||
type $$Events = SelectPrimitive.TriggerEvents;
|
||||
const { attrStore } = getFormField();
|
||||
export let placeholder = "";
|
||||
</script>
|
||||
|
||||
<Select.Trigger {...$$restProps} {...$attrStore} on:click on:keydown>
|
||||
<Select.Value {placeholder} />
|
||||
<slot />
|
||||
</Select.Trigger>
|
||||
20
src/lib/components/ui/form/form-select.svelte
Normal file
20
src/lib/components/ui/form/form-select.svelte
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">
|
||||
import * as Select from "$lib/components/ui/select";
|
||||
import { getFormField } from "formsnap";
|
||||
import type { Select as SelectPrimitive } from "bits-ui";
|
||||
|
||||
type $$Props = SelectPrimitive.Props;
|
||||
const { setValue, name, value } = getFormField();
|
||||
export let onSelectedChange: $$Props["onSelectedChange"];
|
||||
</script>
|
||||
|
||||
<Select.Root
|
||||
onSelectedChange={(v) => {
|
||||
onSelectedChange?.(v);
|
||||
setValue(v ? v.value : undefined);
|
||||
}}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
<input hidden {name} value={$value} />
|
||||
</Select.Root>
|
||||
24
src/lib/components/ui/form/form-switch.svelte
Normal file
24
src/lib/components/ui/form/form-switch.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts">
|
||||
import { getFormField } from "formsnap";
|
||||
import type { Switch as SwitchPrimitive } from "bits-ui";
|
||||
import { Switch } from "$lib/components/ui/switch";
|
||||
type $$Props = SwitchPrimitive.Props;
|
||||
type $$Events = SwitchPrimitive.Events;
|
||||
|
||||
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
|
||||
|
||||
const { name, setValue, attrStore, value } = getFormField();
|
||||
</script>
|
||||
|
||||
<Switch
|
||||
{...$attrStore}
|
||||
checked={typeof $value === "boolean" ? $value : false}
|
||||
onCheckedChange={(v) => {
|
||||
onCheckedChange?.(v);
|
||||
setValue(v);
|
||||
}}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
/>
|
||||
<input hidden {name} value={$value} />
|
||||
32
src/lib/components/ui/form/form-textarea.svelte
Normal file
32
src/lib/components/ui/form/form-textarea.svelte
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<script lang="ts">
|
||||
import { getFormField } from "formsnap";
|
||||
import type { HTMLTextareaAttributes } from "svelte/elements";
|
||||
import type { TextareaGetFormField } from ".";
|
||||
import {
|
||||
Textarea,
|
||||
type TextareaEvents
|
||||
} from "$lib/components/ui/textarea";
|
||||
|
||||
type $$Props = HTMLTextareaAttributes;
|
||||
type $$Events = TextareaEvents;
|
||||
|
||||
const { attrStore, value } = getFormField() as TextareaGetFormField;
|
||||
</script>
|
||||
|
||||
<Textarea
|
||||
{...$attrStore}
|
||||
bind:value={$value}
|
||||
{...$$restProps}
|
||||
on:blur
|
||||
on:change
|
||||
on:click
|
||||
on:focus
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:keyup
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:paste
|
||||
on:input
|
||||
/>
|
||||
14
src/lib/components/ui/form/form-validation.svelte
Normal file
14
src/lib/components/ui/form/form-validation.svelte
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script lang="ts">
|
||||
import { Form as FormPrimitive } from "formsnap";
|
||||
import { cn } from "@/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
type $$Props = HTMLAttributes<HTMLParagraphElement>;
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Validation
|
||||
class={cn("text-sm font-medium text-destructive", className)}
|
||||
{...$$restProps}
|
||||
/>
|
||||
82
src/lib/components/ui/form/index.ts
Normal file
82
src/lib/components/ui/form/index.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { Form as FormPrimitive, getFormField } 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 Label from "./form-label.svelte";
|
||||
import Validation from "./form-validation.svelte";
|
||||
import Checkbox from "./form-checkbox.svelte";
|
||||
import Switch from "./form-switch.svelte";
|
||||
import NativeSelect from "./form-native-select.svelte";
|
||||
import RadioGroup from "./form-radio-group.svelte";
|
||||
import Select from "./form-select.svelte";
|
||||
import SelectTrigger from "./form-select-trigger.svelte";
|
||||
import Button from "./form-button.svelte";
|
||||
|
||||
const Root = FormPrimitive.Root;
|
||||
const Field = FormPrimitive.Field;
|
||||
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 {
|
||||
Root,
|
||||
Field,
|
||||
Item,
|
||||
Input,
|
||||
Label,
|
||||
Button,
|
||||
Switch,
|
||||
Select,
|
||||
Checkbox,
|
||||
Textarea,
|
||||
Validation,
|
||||
RadioGroup,
|
||||
RadioItem,
|
||||
Description,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
NativeSelect,
|
||||
NativeRadio,
|
||||
//
|
||||
Root as Form,
|
||||
Field as FormField,
|
||||
Item as FormItem,
|
||||
Input as FormInput,
|
||||
Textarea as FormTextarea,
|
||||
Description as FormDescription,
|
||||
Label as FormLabel,
|
||||
Validation as FormValidation,
|
||||
NativeSelect as FormNativeSelect,
|
||||
NativeRadio as FormNativeRadio,
|
||||
Checkbox as FormCheckbox,
|
||||
Switch as FormSwitch,
|
||||
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
|
||||
};
|
||||
|
|
@ -1 +1,25 @@
|
|||
export { default as Input } from "./Input.svelte";
|
||||
import Root from "./input.svelte";
|
||||
|
||||
type FormInputEvent<T extends Event = Event> = T & {
|
||||
currentTarget: EventTarget & HTMLInputElement;
|
||||
};
|
||||
export type InputEvents = {
|
||||
blur: FormInputEvent<FocusEvent>;
|
||||
change: FormInputEvent<Event>;
|
||||
click: FormInputEvent<MouseEvent>;
|
||||
focus: FormInputEvent<FocusEvent>;
|
||||
keydown: FormInputEvent<KeyboardEvent>;
|
||||
keypress: FormInputEvent<KeyboardEvent>;
|
||||
keyup: FormInputEvent<KeyboardEvent>;
|
||||
mouseover: FormInputEvent<MouseEvent>;
|
||||
mouseenter: FormInputEvent<MouseEvent>;
|
||||
mouseleave: FormInputEvent<MouseEvent>;
|
||||
paste: FormInputEvent<ClipboardEvent>;
|
||||
input: FormInputEvent<InputEvent>;
|
||||
};
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Input
|
||||
};
|
||||
|
|
|
|||
33
src/lib/components/ui/input/input.svelte
Normal file
33
src/lib/components/ui/input/input.svelte
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLInputAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils";
|
||||
import type { InputEvents } from ".";
|
||||
|
||||
type $$Props = HTMLInputAttributes;
|
||||
type $$Events = InputEvents;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let value: $$Props["value"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<input
|
||||
class={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
bind:value
|
||||
on:blur
|
||||
on:change
|
||||
on:click
|
||||
on:focus
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:keyup
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:paste
|
||||
on:input
|
||||
{...$$restProps}
|
||||
/>
|
||||
33
src/lib/components/ui/select/index.ts
Normal file
33
src/lib/components/ui/select/index.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
|
||||
import Root from "./select.svelte";
|
||||
import Label from "./select-label.svelte";
|
||||
import Item from "./select-item.svelte";
|
||||
import Content from "./select-content.svelte";
|
||||
import Trigger from "./select-trigger.svelte";
|
||||
import Separator from "./select-separator.svelte";
|
||||
|
||||
const Group = SelectPrimitive.Group;
|
||||
const Input = SelectPrimitive.Input;
|
||||
const Value = SelectPrimitive.Value;
|
||||
export {
|
||||
Root,
|
||||
Group,
|
||||
Input,
|
||||
Label,
|
||||
Item,
|
||||
Value,
|
||||
Content,
|
||||
Trigger,
|
||||
Separator,
|
||||
//
|
||||
Root as Select,
|
||||
Group as SelectGroup,
|
||||
Input as SelectInput,
|
||||
Label as SelectLabel,
|
||||
Item as SelectItem,
|
||||
Value as SelectValue,
|
||||
Content as SelectContent,
|
||||
Trigger as SelectTrigger,
|
||||
Separator as SelectSeparator
|
||||
};
|
||||
36
src/lib/components/ui/select/select-content.svelte
Normal file
36
src/lib/components/ui/select/select-content.svelte
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn, flyAndScale } from "$lib/utils";
|
||||
import { scale } from "svelte/transition";
|
||||
|
||||
type $$Props = SelectPrimitive.ContentProps;
|
||||
type $$Events = SelectPrimitive.ContentEvents;
|
||||
export let inTransition: $$Props["inTransition"] = flyAndScale;
|
||||
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
|
||||
export let outTransition: $$Props["outTransition"] = scale;
|
||||
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
|
||||
start: 0.95,
|
||||
opacity: 0,
|
||||
duration: 50
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Content
|
||||
{inTransition}
|
||||
{inTransitionConfig}
|
||||
{outTransition}
|
||||
{outTransitionConfig}
|
||||
class={cn(
|
||||
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md outline-none",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:keydown
|
||||
>
|
||||
<div class="w-full p-1">
|
||||
<slot />
|
||||
</div>
|
||||
</SelectPrimitive.Content>
|
||||
38
src/lib/components/ui/select/select-item.svelte
Normal file
38
src/lib/components/ui/select/select-item.svelte
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { Check } from "lucide-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SelectPrimitive.ItemProps;
|
||||
type $$Events = SelectPrimitive.ItemEvents;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let value: $$Props["value"];
|
||||
export let label: $$Props["label"] = undefined;
|
||||
export let disabled: $$Props["disabled"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Item
|
||||
{value}
|
||||
{disabled}
|
||||
{label}
|
||||
class={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:pointerleave
|
||||
on:pointermove
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check class="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</SelectPrimitive.Item>
|
||||
16
src/lib/components/ui/select/select-label.svelte
Normal file
16
src/lib/components/ui/select/select-label.svelte
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SelectPrimitive.LabelProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Label
|
||||
class={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</SelectPrimitive.Label>
|
||||
14
src/lib/components/ui/select/select-separator.svelte
Normal file
14
src/lib/components/ui/select/select-separator.svelte
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SelectPrimitive.SeparatorProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Separator
|
||||
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...$$restProps}
|
||||
/>
|
||||
27
src/lib/components/ui/select/select-trigger.svelte
Normal file
27
src/lib/components/ui/select/select-trigger.svelte
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { ChevronDown } from "lucide-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SelectPrimitive.TriggerProps;
|
||||
type $$Events = SelectPrimitive.TriggerEvents;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Trigger
|
||||
class={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
let:builder
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot {builder} />
|
||||
<div>
|
||||
<ChevronDown class="h-4 w-4 opacity-50" />
|
||||
</div>
|
||||
</SelectPrimitive.Trigger>
|
||||
12
src/lib/components/ui/select/select.svelte
Normal file
12
src/lib/components/ui/select/select.svelte
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
|
||||
type $$Props = SelectPrimitive.Props;
|
||||
|
||||
export let selected: $$Props["selected"] = undefined;
|
||||
export let open: $$Props["open"] = undefined;
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Root bind:selected bind:open {...$$restProps}>
|
||||
<slot />
|
||||
</SelectPrimitive.Root>
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Overlay
|
||||
class={cn(
|
||||
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
/>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<script lang="ts">
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
const portalVariants = cva("fixed inset-0 z-50 flex", {
|
||||
variants: {
|
||||
position: {
|
||||
top: "items-start",
|
||||
bottom: "items-end",
|
||||
left: "justify-start",
|
||||
right: "justify-end"
|
||||
}
|
||||
},
|
||||
defaultVariants: { position: "right" }
|
||||
});
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let position: VariantProps<typeof portalVariants>["position"] =
|
||||
"right";
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Portal class={cn(className)} {...$$restProps}>
|
||||
<div class={portalVariants({ position })}>
|
||||
<slot />
|
||||
</div>
|
||||
</SheetPrimitive.Portal>
|
||||
|
|
@ -1,102 +1,55 @@
|
|||
import { cva } from "class-variance-authority";
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
|
||||
export { default as SheetContent } from "./SheetContent.svelte";
|
||||
export { default as SheetDescription } from "./SheetDescription.svelte";
|
||||
export { default as SheetFooter } from "./SheetFooter.svelte";
|
||||
export { default as SheetHeader } from "./SheetHeader.svelte";
|
||||
export { default as SheetOverlay } from "./SheetOverlay.svelte";
|
||||
export { default as SheetPortal } from "./SheetPortal.svelte";
|
||||
export { default as SheetTitle } from "./SheetTitle.svelte";
|
||||
import Portal from "./sheet-portal.svelte";
|
||||
import Overlay from "./sheet-overlay.svelte";
|
||||
import Content from "./sheet-content.svelte";
|
||||
import Header from "./sheet-header.svelte";
|
||||
import Footer from "./sheet-footer.svelte";
|
||||
import Title from "./sheet-title.svelte";
|
||||
import Description from "./sheet-description.svelte";
|
||||
|
||||
export const Sheet = SheetPrimitive.Root;
|
||||
export const SheetTrigger = SheetPrimitive.Trigger;
|
||||
export const SheetClose = SheetPrimitive.Close;
|
||||
const Root = SheetPrimitive.Root;
|
||||
const Close = SheetPrimitive.Close;
|
||||
const Trigger = SheetPrimitive.Trigger;
|
||||
|
||||
export const sheetVariants = cva(
|
||||
"fixed z-50 scale-100 gap-4 bg-background p-6 opacity-100 shadow-lg border",
|
||||
{
|
||||
variants: {
|
||||
position: {
|
||||
top: "animate-in slide-in-from-top w-full duration-300",
|
||||
bottom: "animate-in slide-in-from-bottom w-full duration-300",
|
||||
left: "animate-in slide-in-from-left h-full duration-300",
|
||||
right: "animate-in slide-in-from-right h-full duration-300"
|
||||
},
|
||||
size: {
|
||||
content: "",
|
||||
default: "",
|
||||
sm: "",
|
||||
lg: "",
|
||||
xl: "",
|
||||
full: ""
|
||||
}
|
||||
},
|
||||
compoundVariants: [
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "content",
|
||||
class: "max-h-screen"
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "default",
|
||||
class: "h-1/3"
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "sm",
|
||||
class: "h-1/4"
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "lg",
|
||||
class: "h-1/2"
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "xl",
|
||||
class: "h-5/6"
|
||||
},
|
||||
{
|
||||
position: ["top", "bottom"],
|
||||
size: "full",
|
||||
class: "h-screen"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "content",
|
||||
class: "max-w-screen"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "default",
|
||||
class: "w-1/3"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "sm",
|
||||
class: "w-1/4"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "lg",
|
||||
class: "w-1/2"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "xl",
|
||||
class: "w-5/6"
|
||||
},
|
||||
{
|
||||
position: ["right", "left"],
|
||||
size: "full",
|
||||
class: "w-screen"
|
||||
}
|
||||
],
|
||||
defaultVariants: {
|
||||
position: "right",
|
||||
size: "default"
|
||||
export {
|
||||
Root,
|
||||
Close,
|
||||
Trigger,
|
||||
Portal,
|
||||
Overlay,
|
||||
Content,
|
||||
Header,
|
||||
Footer,
|
||||
Title,
|
||||
Description,
|
||||
//
|
||||
Root as Sheet,
|
||||
Close as SheetClose,
|
||||
Trigger as SheetTrigger,
|
||||
Portal as SheetPortal,
|
||||
Overlay as SheetOverlay,
|
||||
Content as SheetContent,
|
||||
Header as SheetHeader,
|
||||
Footer as SheetFooter,
|
||||
Title as SheetTitle,
|
||||
Description as SheetDescription
|
||||
};
|
||||
|
||||
export const sheetVariants = tv({
|
||||
base: "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||
variants: {
|
||||
side: {
|
||||
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
||||
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
||||
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
||||
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
side: "right"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export type Side = VariantProps<typeof sheetVariants>["side"];
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
<script lang="ts">
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { SheetOverlay, SheetPortal, sheetVariants, type Side } from ".";
|
||||
import { X } from "lucide-svelte";
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { cn } from "$lib/utils";
|
||||
import { sheetVariants } from ".";
|
||||
import SheetOverlay from "./SheetOverlay.svelte";
|
||||
import SheetPortal from "./SheetPortal.svelte";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = SheetPrimitive.ContentProps & {
|
||||
side?: Side;
|
||||
};
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let side: $$Props["side"] = "right";
|
||||
export { className as class };
|
||||
export let position: VariantProps<typeof sheetVariants>["position"] =
|
||||
"right";
|
||||
export let size: VariantProps<typeof sheetVariants>["size"] = "default";
|
||||
</script>
|
||||
|
||||
<SheetPortal {position}>
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
class={cn(sheetVariants({ position, size }), className)}
|
||||
class={cn(sheetVariants({ side }), className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = SheetPrimitive.DescriptionProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
17
src/lib/components/ui/sheet/sheet-overlay.svelte
Normal file
17
src/lib/components/ui/sheet/sheet-overlay.svelte
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<script lang="ts">
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SheetPrimitive.OverlayProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Overlay
|
||||
class={cn(
|
||||
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
/>
|
||||
13
src/lib/components/ui/sheet/sheet-portal.svelte
Normal file
13
src/lib/components/ui/sheet/sheet-portal.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SheetPrimitive.PortalProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Portal class={cn(className)} {...$$restProps}>
|
||||
<slot />
|
||||
</SheetPrimitive.Portal>
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
type $$Props = SheetPrimitive.TitleProps;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
7
src/lib/components/ui/switch/index.ts
Normal file
7
src/lib/components/ui/switch/index.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import Root from "./switch.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Switch
|
||||
};
|
||||
25
src/lib/components/ui/switch/switch.svelte
Normal file
25
src/lib/components/ui/switch/switch.svelte
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
import { Switch as SwitchPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = SwitchPrimitive.Props;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let checked: $$Props["checked"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SwitchPrimitive.Root
|
||||
bind:checked
|
||||
class={cn(
|
||||
"peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<SwitchPrimitive.Thumb
|
||||
class={cn(
|
||||
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitive.Root>
|
||||
28
src/lib/components/ui/textarea/index.ts
Normal file
28
src/lib/components/ui/textarea/index.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import Root from "./textarea.svelte";
|
||||
|
||||
type FormTextareaEvent<T extends Event = Event> = T & {
|
||||
currentTarget: EventTarget & HTMLTextAreaElement;
|
||||
};
|
||||
|
||||
type TextareaEvents = {
|
||||
blur: FormTextareaEvent<FocusEvent>;
|
||||
change: FormTextareaEvent<Event>;
|
||||
click: FormTextareaEvent<MouseEvent>;
|
||||
focus: FormTextareaEvent<FocusEvent>;
|
||||
keydown: FormTextareaEvent<KeyboardEvent>;
|
||||
keypress: FormTextareaEvent<KeyboardEvent>;
|
||||
keyup: FormTextareaEvent<KeyboardEvent>;
|
||||
mouseover: FormTextareaEvent<MouseEvent>;
|
||||
mouseenter: FormTextareaEvent<MouseEvent>;
|
||||
mouseleave: FormTextareaEvent<MouseEvent>;
|
||||
paste: FormTextareaEvent<ClipboardEvent>;
|
||||
input: FormTextareaEvent<InputEvent>;
|
||||
};
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Textarea,
|
||||
type TextareaEvents,
|
||||
type FormTextareaEvent
|
||||
};
|
||||
31
src/lib/components/ui/textarea/textarea.svelte
Normal file
31
src/lib/components/ui/textarea/textarea.svelte
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<script lang="ts">
|
||||
import type { HTMLTextareaAttributes } from "svelte/elements";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = HTMLTextareaAttributes;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let value: $$Props["value"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<textarea
|
||||
class={cn(
|
||||
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
bind:value
|
||||
on:blur
|
||||
on:change
|
||||
on:click
|
||||
on:focus
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:keyup
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:paste
|
||||
on:input
|
||||
{...$$restProps}
|
||||
/>
|
||||
31
src/lib/components/ui/toggle/index.ts
Normal file
31
src/lib/components/ui/toggle/index.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import Root from "./toggle.svelte";
|
||||
import { tv, type VariantProps } from "tailwind-variants";
|
||||
|
||||
export const toggleVariants = tv({
|
||||
base: "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors data-[state=on]:bg-accent data-[state=on]:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ring-offset-background hover:bg-muted hover:text-muted-foreground",
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-transparent",
|
||||
outline:
|
||||
"bg-transparent border border-input hover:bg-accent hover:text-accent-foreground"
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-3",
|
||||
sm: "h-9 px-2.5",
|
||||
lg: "h-11 px-5"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default"
|
||||
}
|
||||
});
|
||||
|
||||
export type Variant = VariantProps<typeof toggleVariants>["variant"];
|
||||
export type Size = VariantProps<typeof toggleVariants>["size"];
|
||||
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Toggle
|
||||
};
|
||||
26
src/lib/components/ui/toggle/toggle.svelte
Normal file
26
src/lib/components/ui/toggle/toggle.svelte
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script lang="ts">
|
||||
import { Toggle as TogglePrimitive } from "bits-ui";
|
||||
import { toggleVariants, type Variant, type Size } from ".";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
type $$Props = TogglePrimitive.Props & {
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
};
|
||||
type $$Events = TogglePrimitive.Events;
|
||||
|
||||
let className: $$Props["class"] = undefined;
|
||||
export let variant: $$Props["variant"] = "default";
|
||||
export let size: $$Props["size"] = "default";
|
||||
export let pressed: $$Props["pressed"] = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<TogglePrimitive.Root
|
||||
bind:pressed
|
||||
class={cn(toggleVariants({ variant, size, className }))}
|
||||
{...$$restProps}
|
||||
on:m-click
|
||||
>
|
||||
<slot />
|
||||
</TogglePrimitive.Root>
|
||||
|
|
@ -69,6 +69,11 @@ export const signUpSchema = userSchema
|
|||
}
|
||||
});
|
||||
|
||||
export const signInSchema = userSchema.pick({
|
||||
username: true,
|
||||
password: true
|
||||
});
|
||||
|
||||
export const updateUserPasswordSchema = userSchema
|
||||
.pick({ password: true, confirm_password: true })
|
||||
.superRefine(({ confirm_password, password }, ctx) => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const signInSchema = userSchema.pick({
|
|||
});
|
||||
|
||||
export const load = async (event) => {
|
||||
console.log('sign in load event', event);
|
||||
console.log('login load event', event);
|
||||
const session = await event.locals.auth.validate();
|
||||
if (session) {
|
||||
const message = { type: 'info', message: 'You are already signed in' };
|
||||
|
|
@ -4,11 +4,11 @@
|
|||
import * as flashModule from 'sveltekit-flash-message/client';
|
||||
import toast from 'svelte-french-toast';
|
||||
import { AlertCircle } from "lucide-svelte";
|
||||
import { userSchema } from '$lib/config/zod-schemas.js';
|
||||
import Label from '$components/ui/label/Label.svelte';
|
||||
import Input from '$components/ui/input/Input.svelte';
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
import { Alert, AlertDescription, AlertTitle } from "$components/ui/alert";
|
||||
import { signInSchema } from '$lib/config/zod-schemas.js';
|
||||
import { Label } from '$components/ui/label';
|
||||
import { Input } from '$components/ui/input';
|
||||
import { Button } from '$components/ui/button';
|
||||
import * as Alert from "$components/ui/alert";
|
||||
|
||||
export let data;
|
||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
},
|
||||
syncFlashMessage: false,
|
||||
taintedMessage: null,
|
||||
validators: signInSchema,
|
||||
validationMethod: 'oninput',
|
||||
delayMs: 0,
|
||||
});
|
||||
|
|
@ -39,34 +40,38 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="signin">
|
||||
<svelte:head>
|
||||
<title>Bored Game | Login</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="login">
|
||||
<form method="POST" use:enhance>
|
||||
<div class="grid w-full max-w-sm items-center gap-2">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Sign into your account
|
||||
Log into your account
|
||||
</h2>
|
||||
<Label for="username">Username</Label>
|
||||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} required />
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="password" data-invalid={$errors.password} bind:value={$form.password} required />
|
||||
<Button type="submit">Sign In</Button>
|
||||
</div>
|
||||
</form>
|
||||
{#if $errors._errors}
|
||||
<Alert variant="destructive">
|
||||
<Alert.Root variant="destructive">
|
||||
<AlertCircle class="h-4 w-4" />
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>
|
||||
<Alert.Title>Error</Alert.Title>
|
||||
<Alert.Description>
|
||||
{$errors._errors}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.signin {
|
||||
.login {
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@ export const actions = {
|
|||
console.log('Signing out user');
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
await auth.invalidateSession(session.sessionId); // invalidate session
|
||||
locals.auth.setSession(null); // remove cookie
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
};
|
||||
|
|
@ -40,9 +40,8 @@ export const load = async (event) => {
|
|||
if (session) {
|
||||
throw redirect(302, '/');
|
||||
}
|
||||
const form = await superValidate<typeof signUpSchema, Message>(event, signUpSchema);
|
||||
return {
|
||||
form
|
||||
form: await superValidate<typeof signUpSchema, Message>(event, signUpSchema)
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -4,21 +4,16 @@
|
|||
import * as flashModule from 'sveltekit-flash-message/client';
|
||||
import toast from 'svelte-french-toast';
|
||||
import { ChevronsUpDown } from "lucide-svelte";
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
import Input from '$components/ui/input/Input.svelte';
|
||||
import { Button } from '$components/ui/button';
|
||||
import { Input } from '$components/ui/input';
|
||||
import Label from '$components/ui/label/Label.svelte';
|
||||
import { signUpSchema } from '$lib/config/zod-schemas.js';
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger
|
||||
} from "$components/ui/collapsible";
|
||||
import Alert from '$components/ui/alert/Alert.svelte';
|
||||
import AlertTitle from '$components/ui/alert/AlertTitle.svelte';
|
||||
import AlertDescription from '$components/ui/alert/AlertDescription.svelte';
|
||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { slide } from 'svelte/transition';
|
||||
import { quintIn } from 'svelte/easing';
|
||||
|
||||
export let data;
|
||||
let isOpen = false;
|
||||
|
||||
const { form, errors, constraints, enhance, delayed } = superForm(data.form, {
|
||||
flashMessage: {
|
||||
|
|
@ -44,72 +39,82 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Bored Game | Sign Up</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="page">
|
||||
<form method="POST" action="/auth/signup" use:enhance>
|
||||
<form method="POST" action="/sign-up" use:enhance>
|
||||
<div class="grid w-full max-w-sm items-center gap-2.5">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Signup for an account
|
||||
</h2>
|
||||
<Label for="username">Username <small class="text-destructive">(Required)</small></Label>
|
||||
<Label for="username">Username</Label>
|
||||
<Input type="text" id="username" class={$errors.username && "outline outline-destructive"} name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
{#if $errors.username}
|
||||
<p class="text-sm text-destructive">{$errors.username}</p>
|
||||
{/if}
|
||||
<Label for="password">Password <small class="text-destructive">(Required)</small></Label>
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" class={$errors.password && "outline outline-destructive"} name="password" placeholder="Password" autocomplete="new-password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
{#if $errors.password}
|
||||
<p class="text-sm text-destructive">{$errors.password}</p>
|
||||
{/if}
|
||||
<Label for="confirm_password">Confirm Password <small class="text-destructive">(Required)</small></Label>
|
||||
<Label for="confirm_password">Confirm Password</Label>
|
||||
<Input type="password" id="confirm_password" class={$errors.confirm_password && "outline outline-destructive"} name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" data-invalid={$errors.confirm_password} bind:value={$form.confirm_password} />
|
||||
{#if $errors.confirm_password}
|
||||
<p class="text-sm text-destructive">{$errors.confirm_password}</p>
|
||||
{/if}
|
||||
<Collapsible open={isOpen} class="grid w-full max-w-sm items-center gap-2.5">
|
||||
<Collapsible.Root class="grid w-full max-w-sm items-center gap-2.5">
|
||||
<div>
|
||||
Optional Fields:
|
||||
<CollapsibleTrigger>
|
||||
<Button variant="ghost" size="sm" type="button" class="w-9 p-0">
|
||||
<Collapsible.Trigger asChild let:builder>
|
||||
<Button builders={[builder]} variant="ghost" size="sm" type="button" class="w-9 p-0">
|
||||
<ChevronsUpDown class="h-4 w-4" />
|
||||
<span class="sr-only">Toggle</span>
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
</Collapsible.Trigger>
|
||||
</div>
|
||||
<CollapsibleContent>
|
||||
<Collapsible.Content>
|
||||
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||
<Label for="email">Email</Label>
|
||||
<Input type="email" id="email" class={$errors.email && "outline outline-destructive"} name="email" placeholder="Email" autocomplete="email" data-invalid={$errors.email} bind:value={$form.email} />
|
||||
{#if $errors.email}
|
||||
<p class="text-sm text-destructive">{$errors.email}</p>
|
||||
{/if}
|
||||
</CollapsibleContent>
|
||||
<CollapsibleContent>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
<Collapsible.Content>
|
||||
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||
<Label for="firstName">First Name</Label>
|
||||
<Input type="text" id="firstName" class={$errors.firstName && "outline outline-destructive"} name="firstName" placeholder="First Name" autocomplete="given-name" data-invalid={$errors.firstName} bind:value={$form.firstName} />
|
||||
{#if $errors.firstName}
|
||||
<p class="text-sm text-destructive">{$errors.firstName}</p>
|
||||
{/if}
|
||||
</CollapsibleContent>
|
||||
<CollapsibleContent>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
<Collapsible.Content>
|
||||
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||
<Label for="firstName">Last Name</Label>
|
||||
<Input type="text" id="lastName" class={$errors.firstName && "outline outline-destructive"} name="lastName" placeholder="Last Name" autocomplete="family-name" data-invalid={$errors.lastName} bind:value={$form.lastName} />
|
||||
{#if $errors.lastName}
|
||||
<p class="text-sm text-destructive">{$errors.lastName}</p>
|
||||
{/if}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
<div class="grid grid-cols-2">
|
||||
<Button type="submit">Signup</Button>
|
||||
<Button variant="link" href="/">or Cancel</Button>
|
||||
<Button variant="link" class="text-secondary-foreground" href="/">or Cancel</Button>
|
||||
</div>
|
||||
{#if !$form.email}
|
||||
<Alert>
|
||||
<AlertTitle>Heads up!</AlertTitle>
|
||||
<AlertDescription>
|
||||
<Alert.Root>
|
||||
<Alert.Title level="h3">Heads up!</Alert.Title>
|
||||
<Alert.Description>
|
||||
Without an email address, you won't be able to reset your password. Submit only if you are sure. You can always add this later.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</Alert.Description>
|
||||
</Alert.Root>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -9,7 +9,7 @@ import { search_schema } from '$lib/zodValidation.js';
|
|||
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
// console.log('locals load', locals);
|
||||
|
|
@ -107,7 +107,7 @@ export const actions = {
|
|||
try {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
|
|
@ -159,7 +159,7 @@ export const actions = {
|
|||
create: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
return error(405, 'Method not allowed');
|
||||
},
|
||||
|
|
@ -167,7 +167,7 @@ export const actions = {
|
|||
delete: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
return error(405, 'Method not allowed');
|
||||
},
|
||||
|
|
@ -179,7 +179,7 @@ export const actions = {
|
|||
try {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { redirect } from '@sveltejs/kit';
|
|||
export async function load({ params, locals }) {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { list_game_request_schema } from '$lib/zodValidation';
|
|||
export async function load({ params, locals }) {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -49,7 +49,7 @@ export const actions = {
|
|||
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
|
|
@ -106,21 +106,21 @@ export const actions = {
|
|||
create: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
},
|
||||
// Delete a wishlist
|
||||
delete: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
},
|
||||
// Remove game from a wishlist
|
||||
remove: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const load = async (event) => {
|
|||
const session = await event.locals.auth.validate();
|
||||
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
const { user } = session;
|
||||
|
|
@ -48,7 +48,7 @@ export const actions = {
|
|||
const session = await event.locals.auth.validate();
|
||||
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
const user = session.user;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import { AlertTriangle } from 'lucide-svelte';
|
||||
import Label from '$components/ui/label/Label.svelte';
|
||||
import Input from '$components/ui/input/Input.svelte';
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
import { Button } from '$components/ui/button';
|
||||
export let data;
|
||||
|
||||
const profileSchema = userSchema.pick({
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
{/if}
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<Button variant="link" href="/auth/password/reset">Change Password</Button>
|
||||
<!-- <a href="/auth/password/reset">Change Password</a> -->
|
||||
<Button variant="link" href="/password/reset">Change Password</Button>
|
||||
<!-- <a href="/password/reset">Change Password</a> -->
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
|
|||
export async function load({ params, locals }) {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
console.log('Wishlist load User id', session.user);
|
||||
|
|
@ -56,7 +56,7 @@ export const actions = {
|
|||
try {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
|
|
@ -107,7 +107,7 @@ export const actions = {
|
|||
create: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
return error(405, 'Method not allowed');
|
||||
},
|
||||
|
|
@ -115,7 +115,7 @@ export const actions = {
|
|||
delete: async ({ params, locals, request }) => {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
return error(405, 'Method not allowed');
|
||||
},
|
||||
|
|
@ -127,7 +127,7 @@ export const actions = {
|
|||
try {
|
||||
const session = await locals.auth.validate();
|
||||
if (!session) {
|
||||
throw redirect(302, '/auth/signin');
|
||||
throw redirect(302, '/login');
|
||||
}
|
||||
|
||||
let game = await prisma.game.findUnique({
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
<AddToList {in_collection} {in_wishlist} game_id={game.id} {wishlist} {collection} />
|
||||
{:else}
|
||||
<span>
|
||||
<Button href="/auth/signup">Sign Up</Button> or <Button href="/auth/signin">Sign In</Button> to add to a list.
|
||||
<Button href="/sign-up">Sign Up</Button> or <Button href="/login">Sign In</Button> to add to a list.
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,11 +5,6 @@
|
|||
|
||||
export let data;
|
||||
console.log("search page data", data);
|
||||
|
||||
// $: if (data?.searchData?.games) {
|
||||
// gameStore.removeAll();
|
||||
// gameStore.addAll(data?.searchData?.games);
|
||||
// }
|
||||
</script>
|
||||
|
||||
<div class="game-search">
|
||||
|
|
|
|||
Loading…
Reference in a new issue