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",
|
"@playwright/test": "^1.37.0",
|
||||||
"@sveltejs/adapter-auto": "^1.0.3",
|
"@sveltejs/adapter-auto": "^1.0.3",
|
||||||
"@sveltejs/adapter-vercel": "^1.0.6",
|
"@sveltejs/adapter-vercel": "^1.0.6",
|
||||||
"@sveltejs/kit": "^1.22.6",
|
"@sveltejs/kit": "^1.24.1",
|
||||||
"@types/cookie": "^0.5.1",
|
"@types/cookie": "^0.5.1",
|
||||||
"@types/node": "^18.17.5",
|
"@types/node": "^18.17.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
|
|
@ -37,27 +37,27 @@
|
||||||
"eslint-plugin-svelte": "^2.32.4",
|
"eslint-plugin-svelte": "^2.32.4",
|
||||||
"just-clone": "^6.2.0",
|
"just-clone": "^6.2.0",
|
||||||
"just-debounce-it": "^3.2.0",
|
"just-debounce-it": "^3.2.0",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.29",
|
||||||
"postcss-import": "^15.1.0",
|
"postcss-import": "^15.1.0",
|
||||||
"postcss-load-config": "^4.0.1",
|
"postcss-load-config": "^4.0.1",
|
||||||
"postcss-preset-env": "^8.5.1",
|
"postcss-preset-env": "^8.5.1",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"prisma": "^5.1.1",
|
"prisma": "^5.2.0",
|
||||||
"sass": "^1.65.1",
|
"sass": "^1.65.1",
|
||||||
"svelte": "^4.2.0",
|
"svelte": "^4.2.0",
|
||||||
"svelte-check": "^3.5.0",
|
"svelte-check": "^3.5.0",
|
||||||
"svelte-preprocess": "^5.0.4",
|
"svelte-preprocess": "^5.0.4",
|
||||||
"svelte-sequential-preprocessor": "^2.0.1",
|
"svelte-sequential-preprocessor": "^2.0.1",
|
||||||
"sveltekit-flash-message": "^2.2.0",
|
"sveltekit-flash-message": "^2.2.0",
|
||||||
"sveltekit-superforms": "^1.6.0",
|
"sveltekit-superforms": "^1.6.1",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.6.1",
|
"tslib": "^2.6.1",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"vite": "^4.4.9",
|
"vite": "^4.4.9",
|
||||||
"vitest": "^0.25.3",
|
"vitest": "^0.25.3",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.22.2"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -67,12 +67,12 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@axiomhq/axiom-node": "^0.12.0",
|
"@axiomhq/axiom-node": "^0.12.0",
|
||||||
"@fontsource/fira-mono": "^4.5.10",
|
"@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",
|
"@iconify-icons/mdi": "^1.2.47",
|
||||||
"@lucia-auth/adapter-mysql": "^2.0.0",
|
"@lucia-auth/adapter-mysql": "^2.0.0",
|
||||||
"@lucia-auth/adapter-prisma": "^3.0.1",
|
"@lucia-auth/adapter-prisma": "^3.0.1",
|
||||||
"@lukeed/uuid": "^2.0.1",
|
"@lukeed/uuid": "^2.0.1",
|
||||||
"@melt-ui/svelte": "^0.37.5",
|
"@melt-ui/svelte": "^0.37.6",
|
||||||
"@prisma/client": "5.1.1",
|
"@prisma/client": "5.1.1",
|
||||||
"@types/feather-icons": "^4.29.1",
|
"@types/feather-icons": "^4.29.1",
|
||||||
"bits-ui": "^0.0.27",
|
"bits-ui": "^0.0.27",
|
||||||
|
|
@ -80,12 +80,13 @@
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"cookie": "^0.5.0",
|
"cookie": "^0.5.0",
|
||||||
"feather-icons": "^4.29.1",
|
"feather-icons": "^4.29.1",
|
||||||
|
"formsnap": "^0.0.9",
|
||||||
"iconify-icon": "^1.0.8",
|
"iconify-icon": "^1.0.8",
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "^2.4.0",
|
"lucia": "^2.4.2",
|
||||||
"lucide-svelte": "^0.256.1",
|
"lucide-svelte": "^0.256.1",
|
||||||
"open-props": "^1.5.11",
|
"open-props": "^1.5.13",
|
||||||
"radix-svelte": "^0.9.0",
|
"radix-svelte": "^0.9.0",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svelte-lazy": "^1.2.1",
|
"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 tailwindcss = require("tailwindcss");
|
||||||
|
const tailwindNesting = require('tailwindcss/nesting');
|
||||||
const autoprefixer = require('autoprefixer');
|
const autoprefixer = require('autoprefixer');
|
||||||
const postcssPresetEnv = require('postcss-preset-env');
|
const postcssPresetEnv = require('postcss-preset-env');
|
||||||
const atImport = require('postcss-import');
|
const atImport = require('postcss-import');
|
||||||
|
|
@ -6,7 +7,7 @@ const atImport = require('postcss-import');
|
||||||
const config = {
|
const config = {
|
||||||
plugins: [
|
plugins: [
|
||||||
atImport(),
|
atImport(),
|
||||||
// 'tailwindcss/nesting'(),
|
tailwindNesting(),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
postcssPresetEnv({
|
postcssPresetEnv({
|
||||||
stage: 2,
|
stage: 2,
|
||||||
|
|
@ -16,8 +17,6 @@ const config = {
|
||||||
'media-query-ranges': true
|
'media-query-ranges': true
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
] //Some plugins, like tailwindcss/nesting, need to run before Tailwind, tailwindcss(), //But others, like autoprefixer, need to run after, autoprefixer]
|
] //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 {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 224 71.4% 4.1%;
|
--foreground: 20 14.3% 4.1%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 224 71.4% 4.1%;
|
--card-foreground: 20 14.3% 4.1%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 224 71.4% 4.1%;
|
--popover-foreground: 20 14.3% 4.1%;
|
||||||
--primary: 262.1 83.3% 57.8%;
|
--primary: 47.9 95.8% 53.1%;
|
||||||
--primary-foreground: 210 20% 98%;
|
--primary-foreground: 26 83.3% 14.1%;
|
||||||
--secondary: 220 14.3% 95.9%;
|
--secondary: 60 4.8% 95.9%;
|
||||||
--secondary-foreground: 220.9 39.3% 11%;
|
--secondary-foreground: 24 9.8% 10%;
|
||||||
--muted: 220 14.3% 95.9%;
|
--muted: 60 4.8% 95.9%;
|
||||||
--muted-foreground: 220 8.9% 46.1%;
|
--muted-foreground: 25 5.3% 44.7%;
|
||||||
--accent: 220 14.3% 95.9%;
|
--accent: 60 4.8% 95.9%;
|
||||||
--accent-foreground: 220.9 39.3% 11%;
|
--accent-foreground: 24 9.8% 10%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 210 20% 98%;
|
--destructive-foreground: 60 9.1% 97.8%;
|
||||||
--border: 220 13% 91%;
|
--border: 20 5.9% 90%;
|
||||||
--input: 220 13% 91%;
|
--input: 20 5.9% 90%;
|
||||||
--ring: 262.1 83.3% 57.8%;
|
--ring: 20 14.3% 4.1%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
.dark {
|
.dark {
|
||||||
--background: 224 71.4% 4.1%;
|
--background: 20 14.3% 4.1%;
|
||||||
--foreground: 210 20% 98%;
|
--foreground: 60 9.1% 97.8%;
|
||||||
--card: 224 71.4% 4.1%;
|
--card: 20 14.3% 4.1%;
|
||||||
--card-foreground: 210 20% 98%;
|
--card-foreground: 60 9.1% 97.8%;
|
||||||
--popover: 224 71.4% 4.1%;
|
--popover: 20 14.3% 4.1%;
|
||||||
--popover-foreground: 210 20% 98%;
|
--popover-foreground: 60 9.1% 97.8%;
|
||||||
--primary: 263.4 70% 50.4%;
|
--primary: 47.9 95.8% 53.1%;
|
||||||
--primary-foreground: 210 20% 98%;
|
--primary-foreground: 26 83.3% 14.1%;
|
||||||
--secondary: 215 27.9% 16.9%;
|
--secondary: 12 6.5% 15.1%;
|
||||||
--secondary-foreground: 210 20% 98%;
|
--secondary-foreground: 60 9.1% 97.8%;
|
||||||
--muted: 215 27.9% 16.9%;
|
--muted: 12 6.5% 15.1%;
|
||||||
--muted-foreground: 217.9 10.6% 64.9%;
|
--muted-foreground: 24 5.4% 63.9%;
|
||||||
--accent: 215 27.9% 16.9%;
|
--accent: 12 6.5% 15.1%;
|
||||||
--accent-foreground: 210 20% 98%;
|
--accent-foreground: 60 9.1% 97.8%;
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 62.8% 30.6%;
|
||||||
--destructive-foreground: 210 20% 98%;
|
--destructive-foreground: 60 9.1% 97.8%;
|
||||||
--border: 215 27.9% 16.9%;
|
--border: 12 6.5% 15.1%;
|
||||||
--input: 215 27.9% 16.9%;
|
--input: 12 6.5% 15.1%;
|
||||||
--ring: 263.4 70% 50.4%;
|
--ring: 35.5 91.7% 32.9%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
||||||
console.log('user', session?.user);
|
console.log('user', session?.user);
|
||||||
event.locals.user = session?.user;
|
event.locals.user = session?.user;
|
||||||
// if (event.route.id?.startsWith('/(protected)')) {
|
// if (event.route.id?.startsWith('/(protected)')) {
|
||||||
// if (!user) throw redirect(302, '/auth/sign-in');
|
// if (!user) throw redirect(302, '/sign-in');
|
||||||
// if (!user.verified) throw redirect(302, '/auth/verify/email');
|
// if (!user.verified) throw redirect(302, '/verify/email');
|
||||||
// }
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error validating user', 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 { fly } from "svelte/transition";
|
||||||
import { createSelect, melt } from "@melt-ui/svelte";
|
import { createSelect, melt } from "@melt-ui/svelte";
|
||||||
import { Check, ChevronDown, MinusCircle, PlusCircle } from "lucide-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";
|
import type { Collection, Wishlist } from "@prisma/client";
|
||||||
|
|
||||||
export let game_id: string;
|
export let game_id: string;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from "./ui/button/Button.svelte";
|
import { Button } from '$components/ui/button';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button type="submit">Add to wishlist</Button>
|
<Button type="submit">Add to wishlist</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,21 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { LogOut } from 'lucide-svelte';
|
import { LogOut } from 'lucide-svelte';
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Separator } from "$components/ui/separator";
|
import { Toggle } from "$lib/components/ui/toggle";
|
||||||
import logo from './bored-game.png';
|
import * as Avatar from "$lib/components/ui/avatar";
|
||||||
import { Avatar, AvatarFallback } from '$components/ui/avatar';
|
import * as Sheet from "$lib/components/ui/sheet";
|
||||||
import {
|
import Logo from '$components/logo.svelte';
|
||||||
Sheet,
|
|
||||||
SheetClose,
|
|
||||||
SheetContent,
|
|
||||||
SheetFooter,
|
|
||||||
SheetHeader,
|
|
||||||
SheetTitle,
|
|
||||||
SheetTrigger
|
|
||||||
} from "$components/ui/sheet";
|
|
||||||
|
|
||||||
export let user: any;
|
export let user: any;
|
||||||
|
|
||||||
|
let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<div class="corner">
|
<div class="corner">
|
||||||
<a href="/" title="Home">
|
<a href="/" title="Home">
|
||||||
<img src={logo} alt="Bored Game Home" />
|
<Logo />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- <TextSearch /> -->
|
<!-- <TextSearch /> -->
|
||||||
|
|
@ -29,39 +23,42 @@
|
||||||
{#if user}
|
{#if user}
|
||||||
<a href="/collection" title="Go to your collection" data-sveltekit-preload-data>Collection</a>
|
<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>
|
<a href="/wishlist" title="Go to your wishlist" data-sveltekit-preload-data>Wishlist</a>
|
||||||
<Sheet>
|
<Sheet.Root>
|
||||||
<SheetTrigger>
|
<Sheet.Trigger>
|
||||||
<Avatar class="h-16 w-16 bg-neutral-100">
|
<Avatar.Root asChild>
|
||||||
<AvatarFallback class="text-3xl font-medium text-magnum-700">
|
<Avatar.Fallback class="text-3xl font-medium text-magnum-700 h-16 w-16 bg-neutral-100">
|
||||||
{user?.username.slice(0, 1).toUpperCase() || '?'}
|
{avatar}
|
||||||
</AvatarFallback>
|
</Avatar.Fallback>
|
||||||
</Avatar>
|
</Avatar.Root>
|
||||||
</SheetTrigger>
|
</Sheet.Trigger>
|
||||||
<SheetContent position="right" size="lg">
|
<Sheet.Content side="right">
|
||||||
<SheetHeader>
|
<Sheet.Header>
|
||||||
<SheetTitle>Menu</SheetTitle>
|
<Sheet.Title>Menu</Sheet.Title>
|
||||||
</SheetHeader>
|
<Toggle aria-label="toggle bold">
|
||||||
|
|
||||||
|
</Toggle>
|
||||||
|
</Sheet.Header>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="item">
|
<Sheet.Close asChild let:builder>
|
||||||
<SheetClose>
|
<div class="item">
|
||||||
<Button variant="link" href="/profile">View Profile</Button>
|
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/profile">View Profile</Button>
|
||||||
</SheetClose>
|
</div>
|
||||||
</div>
|
</Sheet.Close>
|
||||||
<div class="item">
|
<Sheet.Close asChild let:builder>
|
||||||
<SheetClose>
|
<div class="item">
|
||||||
<Button variant="link" href="/collection">Your Collection</Button>
|
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/collection">Your Collection</Button>
|
||||||
</SheetClose>
|
</div>
|
||||||
</div>
|
</Sheet.Close>
|
||||||
<div class="item">
|
<Sheet.Close asChild let:builder>
|
||||||
<SheetClose>
|
<div class="item">
|
||||||
<Button variant="link" href="/wishlist">Your Wishlist</Button>
|
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/wishlist">Your Wishlist</Button>
|
||||||
</SheetClose>
|
</div>
|
||||||
</div>
|
</Sheet.Close>
|
||||||
<div class="separator" />
|
<div class="separator" />
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<form
|
<form
|
||||||
use:enhance
|
use:enhance
|
||||||
action="/auth/signout"
|
action="/logout"
|
||||||
method="POST"
|
method="POST"
|
||||||
>
|
>
|
||||||
<Button type="submit">
|
<Button type="submit">
|
||||||
|
|
@ -71,33 +68,22 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<SheetFooter>
|
<Sheet.Footer>
|
||||||
<SheetClose>
|
<Sheet.Close asChild let:builder>
|
||||||
<Button type="button">Close</Button>
|
<Button builders={[builder]} type="button">Close</Button>
|
||||||
</SheetClose>
|
</Sheet.Close>
|
||||||
</SheetFooter>
|
</Sheet.Footer>
|
||||||
</SheetContent>
|
</Sheet.Content>
|
||||||
</Sheet>
|
</Sheet.Root>
|
||||||
<!-- <form
|
|
||||||
use:enhance
|
|
||||||
action="/auth/signout"
|
|
||||||
method="POST"
|
|
||||||
>
|
|
||||||
<Button type="submit">
|
|
||||||
<LogOut class="mr-2 h-4 w-4"/>
|
|
||||||
Sign out
|
|
||||||
</Button>
|
|
||||||
</form> -->
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if !user}
|
{#if !user}
|
||||||
<a href="/auth/signin">
|
<a href="/login">
|
||||||
<span class="flex-auto">Sign In</span></a
|
<span class="flex-auto">Login</span></a
|
||||||
>
|
>
|
||||||
<a href="/auth/signup">
|
<a href="/sign-up">
|
||||||
<span class="flex-auto">Sign Up</span></a
|
<span class="flex-auto">Sign Up</span></a
|
||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <Profile /> -->
|
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -119,12 +105,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
margin-bottom: 0.2rem;
|
/* margin: 0.2rem 0; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.corner {
|
.corner {
|
||||||
width: 3em;
|
width: 3em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.corner a {
|
.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 { ToastType } from '$lib/types';
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import { toast } from '../../toast/toast';
|
import { toast } from '../../toast/toast';
|
||||||
import Button from '$components/ui/button/Button.svelte';
|
import { Button } from '$components/ui/button';
|
||||||
|
|
||||||
export let data: SuperValidated<SearchSchema>;
|
export let data: SuperValidated<SearchSchema>;
|
||||||
const { enhance } = superForm(data, {
|
const { enhance } = superForm(data, {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form method="POST" action="/auth/sign-in" use:enhance>
|
<form method="POST" action="/sign-in" use:enhance>
|
||||||
<!--<SuperDebug data={$form} />-->
|
<!--<SuperDebug data={$form} />-->
|
||||||
{#if $errors._errors}
|
{#if $errors._errors}
|
||||||
<aside class="alert variant-filled-error mt-6">
|
<aside class="alert variant-filled-error mt-6">
|
||||||
|
|
@ -77,6 +77,6 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row justify-center items-center mt-10">
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
// $: termsValue = $form.terms as Writable<boolean>;
|
// $: termsValue = $form.terms as Writable<boolean>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form method="POST" action="/auth/signup" use:enhance>
|
<form method="POST" action="/sign-up" use:enhance>
|
||||||
<h1>Signup user</h1>
|
<h1>Signup user</h1>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="sr-only">First Name</span>
|
<span class="sr-only">First Name</span>
|
||||||
|
|
@ -105,7 +105,7 @@
|
||||||
<small>{$errors.password}</small>
|
<small>{$errors.password}</small>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button type="submit">Signup</button>
|
<button type="submit">Signup</button>
|
||||||
|
|
||||||
<a class="back" href="/"> or Cancel </a>
|
<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">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
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 };
|
export { className as class };
|
||||||
</script>
|
</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";
|
import { tv, type VariantProps } from "tailwind-variants";
|
||||||
export { default as AlertDescription } from "./AlertDescription.svelte";
|
|
||||||
export { default as AlertTitle } from "./AlertTitle.svelte";
|
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 = 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',
|
||||||
export const buttonVariants = cva(
|
variants: {
|
||||||
"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",
|
variant: {
|
||||||
{
|
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||||
variants: {
|
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||||
variant: {
|
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||||
default:
|
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||||
"bg-primary text-primary-foreground hover:bg-primary/90",
|
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||||
destructive:
|
link: 'text-primary underline-offset-4 hover:underline'
|
||||||
"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"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
size: {
|
||||||
variant: "default",
|
default: 'h-10 px-4 py-2',
|
||||||
size: "default"
|
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 {
|
||||||
|
Root,
|
||||||
export const CollapsibleContent = CollapsiblePrimitive.Content;
|
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 "bits-ui";
|
||||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
import { tv, type VariantProps } from "tailwind-variants";
|
||||||
|
|
||||||
export { default as SheetContent } from "./SheetContent.svelte";
|
import Portal from "./sheet-portal.svelte";
|
||||||
export { default as SheetDescription } from "./SheetDescription.svelte";
|
import Overlay from "./sheet-overlay.svelte";
|
||||||
export { default as SheetFooter } from "./SheetFooter.svelte";
|
import Content from "./sheet-content.svelte";
|
||||||
export { default as SheetHeader } from "./SheetHeader.svelte";
|
import Header from "./sheet-header.svelte";
|
||||||
export { default as SheetOverlay } from "./SheetOverlay.svelte";
|
import Footer from "./sheet-footer.svelte";
|
||||||
export { default as SheetPortal } from "./SheetPortal.svelte";
|
import Title from "./sheet-title.svelte";
|
||||||
export { default as SheetTitle } from "./SheetTitle.svelte";
|
import Description from "./sheet-description.svelte";
|
||||||
|
|
||||||
export const Sheet = SheetPrimitive.Root;
|
const Root = SheetPrimitive.Root;
|
||||||
export const SheetTrigger = SheetPrimitive.Trigger;
|
const Close = SheetPrimitive.Close;
|
||||||
export const SheetClose = SheetPrimitive.Close;
|
const Trigger = SheetPrimitive.Trigger;
|
||||||
|
|
||||||
export const sheetVariants = cva(
|
export {
|
||||||
"fixed z-50 scale-100 gap-4 bg-background p-6 opacity-100 shadow-lg border",
|
Root,
|
||||||
{
|
Close,
|
||||||
variants: {
|
Trigger,
|
||||||
position: {
|
Portal,
|
||||||
top: "animate-in slide-in-from-top w-full duration-300",
|
Overlay,
|
||||||
bottom: "animate-in slide-in-from-bottom w-full duration-300",
|
Content,
|
||||||
left: "animate-in slide-in-from-left h-full duration-300",
|
Header,
|
||||||
right: "animate-in slide-in-from-right h-full duration-300"
|
Footer,
|
||||||
},
|
Title,
|
||||||
size: {
|
Description,
|
||||||
content: "",
|
//
|
||||||
default: "",
|
Root as Sheet,
|
||||||
sm: "",
|
Close as SheetClose,
|
||||||
lg: "",
|
Trigger as SheetTrigger,
|
||||||
xl: "",
|
Portal as SheetPortal,
|
||||||
full: ""
|
Overlay as SheetOverlay,
|
||||||
}
|
Content as SheetContent,
|
||||||
},
|
Header as SheetHeader,
|
||||||
compoundVariants: [
|
Footer as SheetFooter,
|
||||||
{
|
Title as SheetTitle,
|
||||||
position: ["top", "bottom"],
|
Description as SheetDescription
|
||||||
size: "content",
|
};
|
||||||
class: "max-h-screen"
|
|
||||||
},
|
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",
|
||||||
position: ["top", "bottom"],
|
variants: {
|
||||||
size: "default",
|
side: {
|
||||||
class: "h-1/3"
|
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",
|
||||||
position: ["top", "bottom"],
|
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"
|
||||||
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"
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
side: "right"
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
|
export type Side = VariantProps<typeof sheetVariants>["side"];
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
<script lang="ts">
|
<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 { X } from "lucide-svelte";
|
||||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
|
||||||
import { cn } from "$lib/utils";
|
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 { className as class };
|
||||||
export let position: VariantProps<typeof sheetVariants>["position"] =
|
|
||||||
"right";
|
|
||||||
export let size: VariantProps<typeof sheetVariants>["size"] = "default";
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SheetPortal {position}>
|
<SheetPortal>
|
||||||
<SheetOverlay />
|
<SheetOverlay />
|
||||||
<SheetPrimitive.Content
|
<SheetPrimitive.Content
|
||||||
class={cn(sheetVariants({ position, size }), className)}
|
class={cn(sheetVariants({ side }), className)}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
type $$Props = SheetPrimitive.DescriptionProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
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 };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
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 };
|
export { className as class };
|
||||||
</script>
|
</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">
|
<script lang="ts">
|
||||||
import { Dialog as SheetPrimitive } from "radix-svelte";
|
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
let className: string | undefined | null = undefined;
|
type $$Props = SheetPrimitive.TitleProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</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
|
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) => {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const signInSchema = userSchema.pick({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const load = async (event) => {
|
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();
|
const session = await event.locals.auth.validate();
|
||||||
if (session) {
|
if (session) {
|
||||||
const message = { type: 'info', message: 'You are already signed in' };
|
const message = { type: 'info', message: 'You are already signed in' };
|
||||||
|
|
@ -4,11 +4,11 @@
|
||||||
import * as flashModule from 'sveltekit-flash-message/client';
|
import * as flashModule from 'sveltekit-flash-message/client';
|
||||||
import toast from 'svelte-french-toast';
|
import toast from 'svelte-french-toast';
|
||||||
import { AlertCircle } from "lucide-svelte";
|
import { AlertCircle } from "lucide-svelte";
|
||||||
import { userSchema } from '$lib/config/zod-schemas.js';
|
import { signInSchema } from '$lib/config/zod-schemas.js';
|
||||||
import Label from '$components/ui/label/Label.svelte';
|
import { Label } from '$components/ui/label';
|
||||||
import Input from '$components/ui/input/Input.svelte';
|
import { Input } from '$components/ui/input';
|
||||||
import Button from '$components/ui/button/Button.svelte';
|
import { Button } from '$components/ui/button';
|
||||||
import { Alert, AlertDescription, AlertTitle } from "$components/ui/alert";
|
import * as Alert from "$components/ui/alert";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
},
|
},
|
||||||
syncFlashMessage: false,
|
syncFlashMessage: false,
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
|
validators: signInSchema,
|
||||||
validationMethod: 'oninput',
|
validationMethod: 'oninput',
|
||||||
delayMs: 0,
|
delayMs: 0,
|
||||||
});
|
});
|
||||||
|
|
@ -39,34 +40,38 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="signin">
|
<svelte:head>
|
||||||
|
<title>Bored Game | Login</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="login">
|
||||||
<form method="POST" use:enhance>
|
<form method="POST" use:enhance>
|
||||||
<div class="grid w-full max-w-sm items-center gap-2">
|
<div class="grid w-full max-w-sm items-center gap-2">
|
||||||
<h2
|
<h2
|
||||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
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>
|
</h2>
|
||||||
<Label for="username">Username</Label>
|
<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>
|
<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>
|
<Button type="submit">Sign In</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{#if $errors._errors}
|
{#if $errors._errors}
|
||||||
<Alert variant="destructive">
|
<Alert.Root variant="destructive">
|
||||||
<AlertCircle class="h-4 w-4" />
|
<AlertCircle class="h-4 w-4" />
|
||||||
<AlertTitle>Error</AlertTitle>
|
<Alert.Title>Error</Alert.Title>
|
||||||
<AlertDescription>
|
<Alert.Description>
|
||||||
{$errors._errors}
|
{$errors._errors}
|
||||||
</AlertDescription>
|
</Alert.Description>
|
||||||
</Alert>
|
</Alert.Root>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.signin {
|
.login {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
@ -6,10 +6,10 @@ export const actions = {
|
||||||
console.log('Signing out user');
|
console.log('Signing out user');
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
await auth.invalidateSession(session.sessionId); // invalidate session
|
await auth.invalidateSession(session.sessionId); // invalidate session
|
||||||
locals.auth.setSession(null); // remove cookie
|
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) {
|
if (session) {
|
||||||
throw redirect(302, '/');
|
throw redirect(302, '/');
|
||||||
}
|
}
|
||||||
const form = await superValidate<typeof signUpSchema, Message>(event, signUpSchema);
|
|
||||||
return {
|
return {
|
||||||
form
|
form: await superValidate<typeof signUpSchema, Message>(event, signUpSchema)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -4,21 +4,16 @@
|
||||||
import * as flashModule from 'sveltekit-flash-message/client';
|
import * as flashModule from 'sveltekit-flash-message/client';
|
||||||
import toast from 'svelte-french-toast';
|
import toast from 'svelte-french-toast';
|
||||||
import { ChevronsUpDown } from "lucide-svelte";
|
import { ChevronsUpDown } from "lucide-svelte";
|
||||||
import Button from '$components/ui/button/Button.svelte';
|
import { Button } from '$components/ui/button';
|
||||||
import Input from '$components/ui/input/Input.svelte';
|
import { Input } from '$components/ui/input';
|
||||||
import Label from '$components/ui/label/Label.svelte';
|
import Label from '$components/ui/label/Label.svelte';
|
||||||
import { signUpSchema } from '$lib/config/zod-schemas.js';
|
import { signUpSchema } from '$lib/config/zod-schemas.js';
|
||||||
import {
|
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||||
Collapsible,
|
import * as Alert from '$lib/components/ui/alert';
|
||||||
CollapsibleContent,
|
import { slide } from 'svelte/transition';
|
||||||
CollapsibleTrigger
|
import { quintIn } from 'svelte/easing';
|
||||||
} 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';
|
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
let isOpen = false;
|
|
||||||
|
|
||||||
const { form, errors, constraints, enhance, delayed } = superForm(data.form, {
|
const { form, errors, constraints, enhance, delayed } = superForm(data.form, {
|
||||||
flashMessage: {
|
flashMessage: {
|
||||||
|
|
@ -44,72 +39,82 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Bored Game | Sign Up</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
<div class="page">
|
<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">
|
<div class="grid w-full max-w-sm items-center gap-2.5">
|
||||||
<h2
|
<h2
|
||||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||||
>
|
>
|
||||||
Signup for an account
|
Signup for an account
|
||||||
</h2>
|
</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} />
|
<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}
|
{#if $errors.username}
|
||||||
<p class="text-sm text-destructive">{$errors.username}</p>
|
<p class="text-sm text-destructive">{$errors.username}</p>
|
||||||
{/if}
|
{/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} />
|
<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}
|
{#if $errors.password}
|
||||||
<p class="text-sm text-destructive">{$errors.password}</p>
|
<p class="text-sm text-destructive">{$errors.password}</p>
|
||||||
{/if}
|
{/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} />
|
<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}
|
{#if $errors.confirm_password}
|
||||||
<p class="text-sm text-destructive">{$errors.confirm_password}</p>
|
<p class="text-sm text-destructive">{$errors.confirm_password}</p>
|
||||||
{/if}
|
{/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>
|
<div>
|
||||||
Optional Fields:
|
Optional Fields:
|
||||||
<CollapsibleTrigger>
|
<Collapsible.Trigger asChild let:builder>
|
||||||
<Button variant="ghost" size="sm" type="button" class="w-9 p-0">
|
<Button builders={[builder]} variant="ghost" size="sm" type="button" class="w-9 p-0">
|
||||||
<ChevronsUpDown class="h-4 w-4" />
|
<ChevronsUpDown class="h-4 w-4" />
|
||||||
<span class="sr-only">Toggle</span>
|
<span class="sr-only">Toggle</span>
|
||||||
</Button>
|
</Button>
|
||||||
</CollapsibleTrigger>
|
</Collapsible.Trigger>
|
||||||
</div>
|
</div>
|
||||||
<CollapsibleContent>
|
<Collapsible.Content>
|
||||||
|
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||||
<Label for="email">Email</Label>
|
<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} />
|
<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}
|
{#if $errors.email}
|
||||||
<p class="text-sm text-destructive">{$errors.email}</p>
|
<p class="text-sm text-destructive">{$errors.email}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</CollapsibleContent>
|
</div>
|
||||||
<CollapsibleContent>
|
</Collapsible.Content>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||||
<Label for="firstName">First Name</Label>
|
<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} />
|
<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}
|
{#if $errors.firstName}
|
||||||
<p class="text-sm text-destructive">{$errors.firstName}</p>
|
<p class="text-sm text-destructive">{$errors.firstName}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</CollapsibleContent>
|
</div>
|
||||||
<CollapsibleContent>
|
</Collapsible.Content>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<div transition:slide|global={{ delay: 10, duration: 150, easing: quintIn }}>
|
||||||
<Label for="firstName">Last Name</Label>
|
<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} />
|
<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}
|
{#if $errors.lastName}
|
||||||
<p class="text-sm text-destructive">{$errors.lastName}</p>
|
<p class="text-sm text-destructive">{$errors.lastName}</p>
|
||||||
{/if}
|
{/if}
|
||||||
</CollapsibleContent>
|
</div>
|
||||||
</Collapsible>
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
<div class="grid grid-cols-2">
|
<div class="grid grid-cols-2">
|
||||||
<Button type="submit">Signup</Button>
|
<Button type="submit">Signup</Button>
|
||||||
<Button variant="link" href="/">or Cancel</Button>
|
<Button variant="link" class="text-secondary-foreground" href="/">or Cancel</Button>
|
||||||
</div>
|
</div>
|
||||||
{#if !$form.email}
|
{#if !$form.email}
|
||||||
<Alert>
|
<Alert.Root>
|
||||||
<AlertTitle>Heads up!</AlertTitle>
|
<Alert.Title level="h3">Heads up!</Alert.Title>
|
||||||
<AlertDescription>
|
<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.
|
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.Description>
|
||||||
</Alert>
|
</Alert.Root>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -9,7 +9,7 @@ import { search_schema } from '$lib/zodValidation.js';
|
||||||
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
export const load: PageServerLoad = async ({ fetch, url, locals }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('locals load', locals);
|
// console.log('locals load', locals);
|
||||||
|
|
@ -107,7 +107,7 @@ export const actions = {
|
||||||
try {
|
try {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
let game = await prisma.game.findUnique({
|
||||||
|
|
@ -159,7 +159,7 @@ export const actions = {
|
||||||
create: async ({ params, locals, request }) => {
|
create: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
return error(405, 'Method not allowed');
|
return error(405, 'Method not allowed');
|
||||||
},
|
},
|
||||||
|
|
@ -167,7 +167,7 @@ export const actions = {
|
||||||
delete: async ({ params, locals, request }) => {
|
delete: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
return error(405, 'Method not allowed');
|
return error(405, 'Method not allowed');
|
||||||
},
|
},
|
||||||
|
|
@ -179,7 +179,7 @@ export const actions = {
|
||||||
try {
|
try {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
let game = await prisma.game.findUnique({
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { redirect } from '@sveltejs/kit';
|
||||||
export async function load({ params, locals }) {
|
export async function load({ params, locals }) {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { list_game_request_schema } from '$lib/zodValidation';
|
||||||
export async function load({ params, locals }) {
|
export async function load({ params, locals }) {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -49,7 +49,7 @@ export const actions = {
|
||||||
|
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
let game = await prisma.game.findUnique({
|
||||||
|
|
@ -106,21 +106,21 @@ export const actions = {
|
||||||
create: async ({ params, locals, request }) => {
|
create: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Delete a wishlist
|
// Delete a wishlist
|
||||||
delete: async ({ params, locals, request }) => {
|
delete: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Remove game from a wishlist
|
// Remove game from a wishlist
|
||||||
remove: async ({ params, locals, request }) => {
|
remove: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
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();
|
const session = await event.locals.auth.validate();
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = session;
|
const { user } = session;
|
||||||
|
|
@ -48,7 +48,7 @@ export const actions = {
|
||||||
const session = await event.locals.auth.validate();
|
const session = await event.locals.auth.validate();
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = session.user;
|
const user = session.user;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
import { AlertTriangle } from 'lucide-svelte';
|
import { AlertTriangle } from 'lucide-svelte';
|
||||||
import Label from '$components/ui/label/Label.svelte';
|
import Label from '$components/ui/label/Label.svelte';
|
||||||
import Input from '$components/ui/input/Input.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;
|
export let data;
|
||||||
|
|
||||||
const profileSchema = userSchema.pick({
|
const profileSchema = userSchema.pick({
|
||||||
|
|
@ -63,8 +63,8 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<Button variant="link" href="/auth/password/reset">Change Password</Button>
|
<Button variant="link" href="/password/reset">Change Password</Button>
|
||||||
<!-- <a href="/auth/password/reset">Change Password</a> -->
|
<!-- <a href="/password/reset">Change Password</a> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
|
||||||
export async function load({ params, locals }) {
|
export async function load({ params, locals }) {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Wishlist load User id', session.user);
|
console.log('Wishlist load User id', session.user);
|
||||||
|
|
@ -56,7 +56,7 @@ export const actions = {
|
||||||
try {
|
try {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
let game = await prisma.game.findUnique({
|
||||||
|
|
@ -107,7 +107,7 @@ export const actions = {
|
||||||
create: async ({ params, locals, request }) => {
|
create: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
return error(405, 'Method not allowed');
|
return error(405, 'Method not allowed');
|
||||||
},
|
},
|
||||||
|
|
@ -115,7 +115,7 @@ export const actions = {
|
||||||
delete: async ({ params, locals, request }) => {
|
delete: async ({ params, locals, request }) => {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
return error(405, 'Method not allowed');
|
return error(405, 'Method not allowed');
|
||||||
},
|
},
|
||||||
|
|
@ -127,7 +127,7 @@ export const actions = {
|
||||||
try {
|
try {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
let game = await prisma.game.findUnique({
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
<AddToList {in_collection} {in_wishlist} game_id={game.id} {wishlist} {collection} />
|
<AddToList {in_collection} {in_wishlist} game_id={game.id} {wishlist} {collection} />
|
||||||
{:else}
|
{:else}
|
||||||
<span>
|
<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>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,6 @@
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
console.log("search page data", data);
|
console.log("search page data", data);
|
||||||
|
|
||||||
// $: if (data?.searchData?.games) {
|
|
||||||
// gameStore.removeAll();
|
|
||||||
// gameStore.addAll(data?.searchData?.games);
|
|
||||||
// }
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="game-search">
|
<div class="game-search">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue