diff --git a/package-lock.json b/package-lock.json
index 647e9d6..1cac732 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,8 +10,10 @@
"dependencies": {
"bits-ui": "^0.21.1",
"clsx": "^2.1.0",
+ "cmdk-sv": "^0.0.16",
"dotenv": "^16.4.5",
"drizzle-orm": "^0.30.4",
+ "lucide-svelte": "^0.363.0",
"pg": "^8.11.3",
"tailwind-merge": "^2.2.2",
"tailwind-variants": "^0.2.1"
@@ -1714,6 +1716,80 @@
"node": ">=6"
}
},
+ "node_modules/cmdk-sv": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/cmdk-sv/-/cmdk-sv-0.0.16.tgz",
+ "integrity": "sha512-erlrIrRPaPgiiCFYZgWxTbqgfaLKjiwAC4tKNJH4eUpMBilGqEe2Ruiip9oYakWcZM14JQhcuiYqOl9ee4KI1Q==",
+ "dependencies": {
+ "bits-ui": "^0.9.0",
+ "nanoid": "^5.0.2"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0"
+ }
+ },
+ "node_modules/cmdk-sv/node_modules/@melt-ui/svelte": {
+ "version": "0.61.2",
+ "resolved": "https://registry.npmjs.org/@melt-ui/svelte/-/svelte-0.61.2.tgz",
+ "integrity": "sha512-BHkD9G31zQBToA4euDRBgTQRvWxT9scufOVCXgDO6HKTvyxFspbWT2bgiSFqAK4BbAGDn9Ao36Q8F9O71KN4OQ==",
+ "dependencies": {
+ "@floating-ui/core": "^1.3.1",
+ "@floating-ui/dom": "^1.4.5",
+ "@internationalized/date": "^3.5.0",
+ "dequal": "^2.0.3",
+ "focus-trap": "^7.5.2",
+ "nanoid": "^4.0.2"
+ },
+ "peerDependencies": {
+ "svelte": ">=3 <5"
+ }
+ },
+ "node_modules/cmdk-sv/node_modules/@melt-ui/svelte/node_modules/nanoid": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz",
+ "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^14 || ^16 || >=18"
+ }
+ },
+ "node_modules/cmdk-sv/node_modules/bits-ui": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-0.9.9.tgz",
+ "integrity": "sha512-LkdkyTtpXdkjBzPZJVJgpcre4fut6DONoprMfadHFo82HNUhph+02CxDjYEcZcThb5z4YjSxMlCYvQPZm+YtfQ==",
+ "dependencies": {
+ "@melt-ui/svelte": "0.61.2",
+ "nanoid": "^5.0.3"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0"
+ }
+ },
+ "node_modules/cmdk-sv/node_modules/nanoid": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz",
+ "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ }
+ },
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
@@ -3123,6 +3199,14 @@
"es5-ext": "~0.10.2"
}
},
+ "node_modules/lucide-svelte": {
+ "version": "0.363.0",
+ "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.363.0.tgz",
+ "integrity": "sha512-zpUBFtMEEOOjILgiDX48ijibUww3JUCLrMo5YDGX/De/m6I+vn+oWIGvdyZtuc8nz/P8xHW9vWLKzIWeMrRYbA==",
+ "peerDependencies": {
+ "svelte": "^3 || ^4 || ^5.0.0-next.42"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.8",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
diff --git a/package.json b/package.json
index 6797d08..a126f55 100644
--- a/package.json
+++ b/package.json
@@ -29,8 +29,10 @@
"dependencies": {
"bits-ui": "^0.21.1",
"clsx": "^2.1.0",
+ "cmdk-sv": "^0.0.16",
"dotenv": "^16.4.5",
"drizzle-orm": "^0.30.4",
+ "lucide-svelte": "^0.363.0",
"pg": "^8.11.3",
"tailwind-merge": "^2.2.2",
"tailwind-variants": "^0.2.1"
diff --git a/src/lib/admin/nav.svelte b/src/lib/admin/nav.svelte
new file mode 100644
index 0000000..8a9e671
--- /dev/null
+++ b/src/lib/admin/nav.svelte
@@ -0,0 +1,130 @@
+
+
+
diff --git a/src/lib/admin/user-role-dropdown.svelte b/src/lib/admin/user-role-dropdown.svelte
new file mode 100644
index 0000000..e27b5bf
--- /dev/null
+++ b/src/lib/admin/user-role-dropdown.svelte
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+ Roles
+ {#each roles as role}
+ {role}
+ {/each}
+
+
+
+
diff --git a/src/lib/components/ui/avatar/avatar-fallback.svelte b/src/lib/components/ui/avatar/avatar-fallback.svelte
new file mode 100644
index 0000000..865fc40
--- /dev/null
+++ b/src/lib/components/ui/avatar/avatar-fallback.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/avatar/avatar-image.svelte b/src/lib/components/ui/avatar/avatar-image.svelte
new file mode 100644
index 0000000..6558dc4
--- /dev/null
+++ b/src/lib/components/ui/avatar/avatar-image.svelte
@@ -0,0 +1,18 @@
+
+
+
diff --git a/src/lib/components/ui/avatar/avatar.svelte b/src/lib/components/ui/avatar/avatar.svelte
new file mode 100644
index 0000000..ba1379b
--- /dev/null
+++ b/src/lib/components/ui/avatar/avatar.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/avatar/index.ts b/src/lib/components/ui/avatar/index.ts
new file mode 100644
index 0000000..d06457b
--- /dev/null
+++ b/src/lib/components/ui/avatar/index.ts
@@ -0,0 +1,13 @@
+import Root from "./avatar.svelte";
+import Image from "./avatar-image.svelte";
+import Fallback from "./avatar-fallback.svelte";
+
+export {
+ Root,
+ Image,
+ Fallback,
+ //
+ Root as Avatar,
+ Image as AvatarImage,
+ Fallback as AvatarFallback,
+};
diff --git a/src/lib/components/ui/badge/badge.svelte b/src/lib/components/ui/badge/badge.svelte
new file mode 100644
index 0000000..97c067f
--- /dev/null
+++ b/src/lib/components/ui/badge/badge.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/badge/index.ts b/src/lib/components/ui/badge/index.ts
new file mode 100644
index 0000000..432886f
--- /dev/null
+++ b/src/lib/components/ui/badge/index.ts
@@ -0,0 +1,21 @@
+import { tv, type VariantProps } from "tailwind-variants";
+export { default as Badge } from "./badge.svelte";
+
+export const badgeVariants = tv({
+ base: "inline-flex items-center border rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none select-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ variants: {
+ variant: {
+ default: "bg-primary hover:bg-primary/80 border-transparent text-primary-foreground",
+ secondary:
+ "bg-secondary hover:bg-secondary/80 border-transparent text-secondary-foreground",
+ destructive:
+ "bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground",
+ outline: "text-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+});
+
+export type Variant = VariantProps["variant"];
diff --git a/src/lib/components/ui/command/command-dialog.svelte b/src/lib/components/ui/command/command-dialog.svelte
new file mode 100644
index 0000000..2293b72
--- /dev/null
+++ b/src/lib/components/ui/command/command-dialog.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-empty.svelte b/src/lib/components/ui/command/command-empty.svelte
new file mode 100644
index 0000000..3a0819d
--- /dev/null
+++ b/src/lib/components/ui/command/command-empty.svelte
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-group.svelte b/src/lib/components/ui/command/command-group.svelte
new file mode 100644
index 0000000..0d78a28
--- /dev/null
+++ b/src/lib/components/ui/command/command-group.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-input.svelte b/src/lib/components/ui/command/command-input.svelte
new file mode 100644
index 0000000..c9d9d38
--- /dev/null
+++ b/src/lib/components/ui/command/command-input.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-item.svelte b/src/lib/components/ui/command/command-item.svelte
new file mode 100644
index 0000000..63bbdac
--- /dev/null
+++ b/src/lib/components/ui/command/command-item.svelte
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-list.svelte b/src/lib/components/ui/command/command-list.svelte
new file mode 100644
index 0000000..8ceda03
--- /dev/null
+++ b/src/lib/components/ui/command/command-list.svelte
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command-separator.svelte b/src/lib/components/ui/command/command-separator.svelte
new file mode 100644
index 0000000..75caf5b
--- /dev/null
+++ b/src/lib/components/ui/command/command-separator.svelte
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/lib/components/ui/command/command-shortcut.svelte b/src/lib/components/ui/command/command-shortcut.svelte
new file mode 100644
index 0000000..f33146b
--- /dev/null
+++ b/src/lib/components/ui/command/command-shortcut.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/command.svelte b/src/lib/components/ui/command/command.svelte
new file mode 100644
index 0000000..0e2ce48
--- /dev/null
+++ b/src/lib/components/ui/command/command.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/command/index.ts b/src/lib/components/ui/command/index.ts
new file mode 100644
index 0000000..d8a2e7c
--- /dev/null
+++ b/src/lib/components/ui/command/index.ts
@@ -0,0 +1,37 @@
+import { Command as CommandPrimitive } from "cmdk-sv";
+
+import Root from "./command.svelte";
+import Dialog from "./command-dialog.svelte";
+import Empty from "./command-empty.svelte";
+import Group from "./command-group.svelte";
+import Item from "./command-item.svelte";
+import Input from "./command-input.svelte";
+import List from "./command-list.svelte";
+import Separator from "./command-separator.svelte";
+import Shortcut from "./command-shortcut.svelte";
+
+const Loading = CommandPrimitive.Loading;
+
+export {
+ Root,
+ Dialog,
+ Empty,
+ Group,
+ Item,
+ Input,
+ List,
+ Separator,
+ Shortcut,
+ Loading,
+ //
+ Root as Command,
+ Dialog as CommandDialog,
+ Empty as CommandEmpty,
+ Group as CommandGroup,
+ Item as CommandItem,
+ Input as CommandInput,
+ List as CommandList,
+ Separator as CommandSeparator,
+ Shortcut as CommandShortcut,
+ Loading as CommandLoading,
+};
diff --git a/src/lib/components/ui/dialog/dialog-content.svelte b/src/lib/components/ui/dialog/dialog-content.svelte
new file mode 100644
index 0000000..9512ba8
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-content.svelte
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+ Close
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-description.svelte b/src/lib/components/ui/dialog/dialog-description.svelte
new file mode 100644
index 0000000..e1d796a
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-description.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-footer.svelte b/src/lib/components/ui/dialog/dialog-footer.svelte
new file mode 100644
index 0000000..6f6e589
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-footer.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-header.svelte b/src/lib/components/ui/dialog/dialog-header.svelte
new file mode 100644
index 0000000..fd6b8f0
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-header.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-overlay.svelte b/src/lib/components/ui/dialog/dialog-overlay.svelte
new file mode 100644
index 0000000..aaf930a
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-overlay.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-portal.svelte b/src/lib/components/ui/dialog/dialog-portal.svelte
new file mode 100644
index 0000000..eb5d0a5
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-portal.svelte
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dialog/dialog-title.svelte b/src/lib/components/ui/dialog/dialog-title.svelte
new file mode 100644
index 0000000..06574f3
--- /dev/null
+++ b/src/lib/components/ui/dialog/dialog-title.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dialog/index.ts b/src/lib/components/ui/dialog/index.ts
new file mode 100644
index 0000000..639b50d
--- /dev/null
+++ b/src/lib/components/ui/dialog/index.ts
@@ -0,0 +1,34 @@
+import { Dialog as DialogPrimitive } from "bits-ui";
+
+const Root = DialogPrimitive.Root;
+const Trigger = DialogPrimitive.Trigger;
+
+import Title from "./dialog-title.svelte";
+import Portal from "./dialog-portal.svelte";
+import Footer from "./dialog-footer.svelte";
+import Header from "./dialog-header.svelte";
+import Overlay from "./dialog-overlay.svelte";
+import Content from "./dialog-content.svelte";
+import Description from "./dialog-description.svelte";
+
+export {
+ Root,
+ Title,
+ Portal,
+ Footer,
+ Header,
+ Trigger,
+ Overlay,
+ Content,
+ Description,
+ //
+ Root as Dialog,
+ Title as DialogTitle,
+ Portal as DialogPortal,
+ Footer as DialogFooter,
+ Header as DialogHeader,
+ Trigger as DialogTrigger,
+ Overlay as DialogOverlay,
+ Content as DialogContent,
+ Description as DialogDescription,
+};
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte
new file mode 100644
index 0000000..cbca3c5
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte
new file mode 100644
index 0000000..a94b527
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte
new file mode 100644
index 0000000..9a05d4b
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte
new file mode 100644
index 0000000..43f1527
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte
new file mode 100644
index 0000000..1c74ae1
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte
new file mode 100644
index 0000000..79a48ee
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte
new file mode 100644
index 0000000..e14d078
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte
@@ -0,0 +1,14 @@
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte
new file mode 100644
index 0000000..880d9b4
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte
new file mode 100644
index 0000000..ff20507
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte
new file mode 100644
index 0000000..9ba3916
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte
@@ -0,0 +1,32 @@
+
+
+
+
+
+
diff --git a/src/lib/components/ui/dropdown-menu/index.ts b/src/lib/components/ui/dropdown-menu/index.ts
new file mode 100644
index 0000000..c1749e9
--- /dev/null
+++ b/src/lib/components/ui/dropdown-menu/index.ts
@@ -0,0 +1,48 @@
+import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
+import Item from "./dropdown-menu-item.svelte";
+import Label from "./dropdown-menu-label.svelte";
+import Content from "./dropdown-menu-content.svelte";
+import Shortcut from "./dropdown-menu-shortcut.svelte";
+import RadioItem from "./dropdown-menu-radio-item.svelte";
+import Separator from "./dropdown-menu-separator.svelte";
+import RadioGroup from "./dropdown-menu-radio-group.svelte";
+import SubContent from "./dropdown-menu-sub-content.svelte";
+import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
+import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
+
+const Sub = DropdownMenuPrimitive.Sub;
+const Root = DropdownMenuPrimitive.Root;
+const Trigger = DropdownMenuPrimitive.Trigger;
+const Group = DropdownMenuPrimitive.Group;
+
+export {
+ Sub,
+ Root,
+ Item,
+ Label,
+ Group,
+ Trigger,
+ Content,
+ Shortcut,
+ Separator,
+ RadioItem,
+ SubContent,
+ SubTrigger,
+ RadioGroup,
+ CheckboxItem,
+ //
+ Root as DropdownMenu,
+ Sub as DropdownMenuSub,
+ Item as DropdownMenuItem,
+ Label as DropdownMenuLabel,
+ Group as DropdownMenuGroup,
+ Content as DropdownMenuContent,
+ Trigger as DropdownMenuTrigger,
+ Shortcut as DropdownMenuShortcut,
+ RadioItem as DropdownMenuRadioItem,
+ Separator as DropdownMenuSeparator,
+ RadioGroup as DropdownMenuRadioGroup,
+ SubContent as DropdownMenuSubContent,
+ SubTrigger as DropdownMenuSubTrigger,
+ CheckboxItem as DropdownMenuCheckboxItem,
+};
diff --git a/src/lib/components/ui/input/index.ts b/src/lib/components/ui/input/index.ts
new file mode 100644
index 0000000..859f3b0
--- /dev/null
+++ b/src/lib/components/ui/input/index.ts
@@ -0,0 +1,27 @@
+import Root from "./input.svelte";
+
+export type FormInputEvent = T & {
+ currentTarget: EventTarget & HTMLInputElement;
+};
+export type InputEvents = {
+ blur: FormInputEvent;
+ change: FormInputEvent;
+ click: FormInputEvent;
+ focus: FormInputEvent;
+ focusin: FormInputEvent;
+ focusout: FormInputEvent;
+ keydown: FormInputEvent;
+ keypress: FormInputEvent;
+ keyup: FormInputEvent;
+ mouseover: FormInputEvent;
+ mouseenter: FormInputEvent;
+ mouseleave: FormInputEvent;
+ paste: FormInputEvent;
+ input: FormInputEvent;
+};
+
+export {
+ Root,
+ //
+ Root as Input,
+};
diff --git a/src/lib/components/ui/input/input.svelte b/src/lib/components/ui/input/input.svelte
new file mode 100644
index 0000000..9a2fe0f
--- /dev/null
+++ b/src/lib/components/ui/input/input.svelte
@@ -0,0 +1,35 @@
+
+
+
diff --git a/src/lib/components/ui/label/index.ts b/src/lib/components/ui/label/index.ts
new file mode 100644
index 0000000..8bfca0b
--- /dev/null
+++ b/src/lib/components/ui/label/index.ts
@@ -0,0 +1,7 @@
+import Root from "./label.svelte";
+
+export {
+ Root,
+ //
+ Root as Label,
+};
diff --git a/src/lib/components/ui/label/label.svelte b/src/lib/components/ui/label/label.svelte
new file mode 100644
index 0000000..2a7d479
--- /dev/null
+++ b/src/lib/components/ui/label/label.svelte
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/popover/index.ts b/src/lib/components/ui/popover/index.ts
new file mode 100644
index 0000000..63aecf9
--- /dev/null
+++ b/src/lib/components/ui/popover/index.ts
@@ -0,0 +1,17 @@
+import { Popover as PopoverPrimitive } from "bits-ui";
+import Content from "./popover-content.svelte";
+const Root = PopoverPrimitive.Root;
+const Trigger = PopoverPrimitive.Trigger;
+const Close = PopoverPrimitive.Close;
+
+export {
+ Root,
+ Content,
+ Trigger,
+ Close,
+ //
+ Root as Popover,
+ Content as PopoverContent,
+ Trigger as PopoverTrigger,
+ Close as PopoverClose,
+};
diff --git a/src/lib/components/ui/popover/popover-content.svelte b/src/lib/components/ui/popover/popover-content.svelte
new file mode 100644
index 0000000..794436c
--- /dev/null
+++ b/src/lib/components/ui/popover/popover-content.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/select/index.ts b/src/lib/components/ui/select/index.ts
new file mode 100644
index 0000000..327541c
--- /dev/null
+++ b/src/lib/components/ui/select/index.ts
@@ -0,0 +1,34 @@
+import { Select as SelectPrimitive } from "bits-ui";
+
+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 Root = SelectPrimitive.Root;
+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,
+};
diff --git a/src/lib/components/ui/select/select-content.svelte b/src/lib/components/ui/select/select-content.svelte
new file mode 100644
index 0000000..edb467d
--- /dev/null
+++ b/src/lib/components/ui/select/select-content.svelte
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
diff --git a/src/lib/components/ui/select/select-item.svelte b/src/lib/components/ui/select/select-item.svelte
new file mode 100644
index 0000000..237ba91
--- /dev/null
+++ b/src/lib/components/ui/select/select-item.svelte
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+ {label ? label : value}
+
+
diff --git a/src/lib/components/ui/select/select-label.svelte b/src/lib/components/ui/select/select-label.svelte
new file mode 100644
index 0000000..d966450
--- /dev/null
+++ b/src/lib/components/ui/select/select-label.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/select/select-separator.svelte b/src/lib/components/ui/select/select-separator.svelte
new file mode 100644
index 0000000..bc518e6
--- /dev/null
+++ b/src/lib/components/ui/select/select-separator.svelte
@@ -0,0 +1,11 @@
+
+
+
diff --git a/src/lib/components/ui/select/select-trigger.svelte b/src/lib/components/ui/select/select-trigger.svelte
new file mode 100644
index 0000000..ed0bc7e
--- /dev/null
+++ b/src/lib/components/ui/select/select-trigger.svelte
@@ -0,0 +1,27 @@
+
+
+span]:line-clamp-1",
+ className
+ )}
+ {...$$restProps}
+ let:builder
+ on:click
+ on:keydown
+>
+
+
+
+
+
diff --git a/src/lib/components/ui/sheet/index.ts b/src/lib/components/ui/sheet/index.ts
new file mode 100644
index 0000000..a2c93e1
--- /dev/null
+++ b/src/lib/components/ui/sheet/index.ts
@@ -0,0 +1,106 @@
+import { Dialog as SheetPrimitive } from "bits-ui";
+import { tv, type VariantProps } from "tailwind-variants";
+
+import Portal from "./sheet-portal.svelte";
+import Overlay from "./sheet-overlay.svelte";
+import Content from "./sheet-content.svelte";
+import Header from "./sheet-header.svelte";
+import Footer from "./sheet-footer.svelte";
+import Title from "./sheet-title.svelte";
+import Description from "./sheet-description.svelte";
+
+const Root = SheetPrimitive.Root;
+const Close = SheetPrimitive.Close;
+const Trigger = SheetPrimitive.Trigger;
+
+export {
+ Root,
+ Close,
+ Trigger,
+ Portal,
+ Overlay,
+ Content,
+ Header,
+ Footer,
+ Title,
+ Description,
+ //
+ Root as Sheet,
+ Close as SheetClose,
+ Trigger as SheetTrigger,
+ Portal as SheetPortal,
+ Overlay as SheetOverlay,
+ Content as SheetContent,
+ Header as SheetHeader,
+ Footer as SheetFooter,
+ Title as SheetTitle,
+ Description as SheetDescription,
+};
+
+export const sheetVariants = tv({
+ base: "fixed z-50 gap-4 bg-background p-6 shadow-lg",
+ variants: {
+ side: {
+ top: "inset-x-0 top-0 border-b",
+ bottom: "inset-x-0 bottom-0 border-t",
+ left: "inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
+ right: "inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
+ },
+ },
+ defaultVariants: {
+ side: "right",
+ },
+});
+
+export const sheetTransitions = {
+ top: {
+ in: {
+ y: "-100%",
+ duration: 500,
+ opacity: 1,
+ },
+ out: {
+ y: "-100%",
+ duration: 300,
+ opacity: 1,
+ },
+ },
+ bottom: {
+ in: {
+ y: "100%",
+ duration: 500,
+ opacity: 1,
+ },
+ out: {
+ y: "100%",
+ duration: 300,
+ opacity: 1,
+ },
+ },
+ left: {
+ in: {
+ x: "-100%",
+ duration: 500,
+ opacity: 1,
+ },
+ out: {
+ x: "-100%",
+ duration: 300,
+ opacity: 1,
+ },
+ },
+ right: {
+ in: {
+ x: "100%",
+ duration: 500,
+ opacity: 1,
+ },
+ out: {
+ x: "100%",
+ duration: 300,
+ opacity: 1,
+ },
+ },
+};
+
+export type Side = VariantProps["side"];
diff --git a/src/lib/components/ui/sheet/sheet-content.svelte b/src/lib/components/ui/sheet/sheet-content.svelte
new file mode 100644
index 0000000..b09a160
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-content.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+ Close
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-description.svelte b/src/lib/components/ui/sheet/sheet-description.svelte
new file mode 100644
index 0000000..e1827e1
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-description.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-footer.svelte b/src/lib/components/ui/sheet/sheet-footer.svelte
new file mode 100644
index 0000000..6f6e589
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-footer.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-header.svelte b/src/lib/components/ui/sheet/sheet-header.svelte
new file mode 100644
index 0000000..d24b41f
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-header.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-overlay.svelte b/src/lib/components/ui/sheet/sheet-overlay.svelte
new file mode 100644
index 0000000..c0b02d4
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-overlay.svelte
@@ -0,0 +1,21 @@
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-portal.svelte b/src/lib/components/ui/sheet/sheet-portal.svelte
new file mode 100644
index 0000000..5543a3b
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-portal.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/lib/components/ui/sheet/sheet-title.svelte b/src/lib/components/ui/sheet/sheet-title.svelte
new file mode 100644
index 0000000..8631410
--- /dev/null
+++ b/src/lib/components/ui/sheet/sheet-title.svelte
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/src/lib/components/user-nav.svelte b/src/lib/components/user-nav.svelte
new file mode 100644
index 0000000..b0185f3
--- /dev/null
+++ b/src/lib/components/user-nav.svelte
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Profile
+ ⇧⌘P
+
+
+
+ {
+ userStore.set(null);
+ }}>
+ Log out
+ ⇧⌘Q
+
+
+
\ No newline at end of file
diff --git a/src/lib/state.js b/src/lib/state.js
new file mode 100644
index 0000000..27d7136
--- /dev/null
+++ b/src/lib/state.js
@@ -0,0 +1,19 @@
+import { browser } from '$app/environment';
+import { writable } from 'svelte/store'
+
+let stored = null;
+
+if(browser && localStorage.auth) {
+ stored = JSON.parse(localStorage.auth);
+}
+
+/**
+ * @type {import('svelte/store').Writable<{id: string, username: string} | null>}
+ */
+export const userStore = writable(stored || null)
+
+userStore.subscribe((value) => {
+ if(browser) {
+ localStorage.auth = JSON.stringify(value)
+ }
+})
\ No newline at end of file
diff --git a/src/routes/(front)/+layout.svelte b/src/routes/(front)/+layout.svelte
new file mode 100644
index 0000000..7ce191d
--- /dev/null
+++ b/src/routes/(front)/+layout.svelte
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+ {#if $userStore !== null}
+
+ {:else}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/if}
+
+
+
+
diff --git a/src/routes/(front)/+page.svelte b/src/routes/(front)/+page.svelte
new file mode 100644
index 0000000..a2d6a14
--- /dev/null
+++ b/src/routes/(front)/+page.svelte
@@ -0,0 +1,36 @@
+
+
+
+
Currently reading
+
+
+ {#each mangas as manga}
+
+
+ {manga.name}
+
+
+ Card Content
+
+
+
+
+
+ {/each}
+
+
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index f67d7ab..c938260 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -1 +1,5 @@
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
deleted file mode 100644
index 79c8c66..0000000
--- a/src/routes/+page.svelte
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- {#each mangas as manga}
-
-
- {manga.name}
-
-
- Card Content
-
-
-
-
-
- {/each}
-
-
diff --git a/src/routes/admin/+page.svelte b/src/routes/admin/+page.svelte
new file mode 100644
index 0000000..d8e70f6
--- /dev/null
+++ b/src/routes/admin/+page.svelte
@@ -0,0 +1,20 @@
+
+
+
diff --git a/src/routes/admin/users/+page.server.ts b/src/routes/admin/users/+page.server.ts
new file mode 100644
index 0000000..e434970
--- /dev/null
+++ b/src/routes/admin/users/+page.server.ts
@@ -0,0 +1,7 @@
+import type { Actions } from "@sveltejs/kit";
+
+export const actions: Actions = {
+ default: async (event) => {
+ console.log(event.request.body);
+ },
+};
\ No newline at end of file
diff --git a/src/routes/admin/users/+page.svelte b/src/routes/admin/users/+page.svelte
new file mode 100644
index 0000000..6cca760
--- /dev/null
+++ b/src/routes/admin/users/+page.svelte
@@ -0,0 +1,69 @@
+
+
+