lotsa shit
This commit is contained in:
parent
a8b9dd0510
commit
f42ba94af4
11
.prettierrc
11
.prettierrc
@ -3,6 +3,13 @@
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
14
components.json
Normal file
14
components.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||
"style": "default",
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/app.pcss",
|
||||
"baseColor": "slate"
|
||||
},
|
||||
"aliases": {
|
||||
"components": "$lib/components",
|
||||
"utils": "$lib/utils"
|
||||
},
|
||||
"typescript": false
|
||||
}
|
1904
package-lock.json
generated
1904
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -15,12 +15,29 @@
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss-load-config": "^5.0.2",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-svelte": "^3.1.2",
|
||||
"prettier-plugin-tailwindcss": "^0.5.9",
|
||||
"svelte": "^4.2.7",
|
||||
"svelte-check": "^3.6.0",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3"
|
||||
},
|
||||
"type": "module"
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"bits-ui": "^0.21.4",
|
||||
"clsx": "^2.1.1",
|
||||
"formsnap": "^1.0.0",
|
||||
"lucide-svelte": "^0.373.0",
|
||||
"mode-watcher": "^0.3.0",
|
||||
"svelte-radix": "^1.1.0",
|
||||
"sveltekit-superforms": "^2.12.6",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwind-variants": "^0.2.1",
|
||||
"zod": "^3.23.4"
|
||||
}
|
||||
}
|
||||
|
13
postcss.config.cjs
Normal file
13
postcss.config.cjs
Normal file
@ -0,0 +1,13 @@
|
||||
const tailwindcss = require('tailwindcss');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
autoprefixer
|
||||
]
|
||||
};
|
||||
|
||||
module.exports = config;
|
78
src/app.pcss
Normal file
78
src/app.pcss
Normal file
@ -0,0 +1,78 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 72.2% 50.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: hsl(212.7,26.8%,83.9);
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import { config } from '$lib';
|
||||
import { config } from '$lib/index.js';
|
||||
|
||||
/** @type {import('@sveltejs/kit').HandleFetch} */
|
||||
export async function handleFetch({ event, request, fetch }) {
|
||||
console.log(event.request.headers.get("cookie"))
|
||||
if (request.url.startsWith(config.api_url)) {
|
||||
// @ts-ignore
|
||||
request.headers.set('cookie', event.request.headers.get('cookie'));
|
||||
|
4
src/lib/components/molecules/probadge.svelte
Normal file
4
src/lib/components/molecules/probadge.svelte
Normal file
@ -0,0 +1,4 @@
|
||||
<script>
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
</script>
|
||||
<Badge class="ml-auto bg-purple-500 text-white hover:bg-purple-700">PRO</Badge>
|
17
src/lib/components/molecules/tooltipbutton.svelte
Normal file
17
src/lib/components/molecules/tooltipbutton.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import * as Tooltip from '$lib/components/ui/tooltip'
|
||||
import {Button} from '$lib/components/ui/button'
|
||||
|
||||
export let tip = "";
|
||||
export let variant = "";
|
||||
export let size = "";
|
||||
</script>
|
||||
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger asChild let:builder>
|
||||
<Button builders={[builder]} {variant} {size}><slot /></Button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content>
|
||||
<p>{tip}</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
13
src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
13
src/lib/components/ui/avatar/avatar-fallback.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<AvatarPrimitive.Fallback
|
||||
class={cn("flex h-full w-full items-center justify-center rounded-full bg-muted", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</AvatarPrimitive.Fallback>
|
15
src/lib/components/ui/avatar/avatar-image.svelte
Normal file
15
src/lib/components/ui/avatar/avatar-image.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let src = undefined;
|
||||
export let alt = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<AvatarPrimitive.Image
|
||||
{src}
|
||||
{alt}
|
||||
class={cn("aspect-square h-full w-full", className)}
|
||||
{...$$restProps}
|
||||
/>
|
15
src/lib/components/ui/avatar/avatar.svelte
Normal file
15
src/lib/components/ui/avatar/avatar.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let delayMs = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<AvatarPrimitive.Root
|
||||
{delayMs}
|
||||
class={cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</AvatarPrimitive.Root>
|
12
src/lib/components/ui/avatar/index.js
Normal file
12
src/lib/components/ui/avatar/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
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,
|
||||
};
|
17
src/lib/components/ui/badge/badge.svelte
Normal file
17
src/lib/components/ui/badge/badge.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { badgeVariants } from "./index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let href = undefined;
|
||||
export let variant = "default";
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={href ? "a" : "span"}
|
||||
{href}
|
||||
class={cn(badgeVariants({ variant, className }))}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
18
src/lib/components/ui/badge/index.js
Normal file
18
src/lib/components/ui/badge/index.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { tv } from "tailwind-variants";
|
||||
export { default as Badge } from "./badge.svelte";
|
||||
export const badgeVariants = tv({
|
||||
base: "inline-flex select-none items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
||||
variants: {
|
||||
variant: {
|
||||
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
||||
secondary:
|
||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
});
|
21
src/lib/components/ui/button/button.svelte
Normal file
21
src/lib/components/ui/button/button.svelte
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
import { Button as ButtonPrimitive } from "bits-ui";
|
||||
import { buttonVariants } from "./index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let variant = "default";
|
||||
export let size = "default";
|
||||
export let builders = [];
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<ButtonPrimitive.Root
|
||||
{builders}
|
||||
class={cn(buttonVariants({ variant, size, className }))}
|
||||
type="button"
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</ButtonPrimitive.Root>
|
32
src/lib/components/ui/button/index.js
Normal file
32
src/lib/components/ui/button/index.js
Normal file
@ -0,0 +1,32 @@
|
||||
import { tv } from "tailwind-variants";
|
||||
import Root from "./button.svelte";
|
||||
const buttonVariants = tv({
|
||||
base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
});
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Button,
|
||||
buttonVariants,
|
||||
};
|
9
src/lib/components/ui/card/card-content.svelte
Normal file
9
src/lib/components/ui/card/card-content.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("p-6 pt-0", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
9
src/lib/components/ui/card/card-description.svelte
Normal file
9
src/lib/components/ui/card/card-description.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<p class={cn("text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</p>
|
9
src/lib/components/ui/card/card-footer.svelte
Normal file
9
src/lib/components/ui/card/card-footer.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("flex items-center p-6 pt-0", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
9
src/lib/components/ui/card/card-header.svelte
Normal file
9
src/lib/components/ui/card/card-header.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("flex flex-col space-y-1.5 p-6", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
14
src/lib/components/ui/card/card-title.svelte
Normal file
14
src/lib/components/ui/card/card-title.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let tag = "h3";
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={tag}
|
||||
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
12
src/lib/components/ui/card/card.svelte
Normal file
12
src/lib/components/ui/card/card.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
21
src/lib/components/ui/card/index.js
Normal file
21
src/lib/components/ui/card/index.js
Normal file
@ -0,0 +1,21 @@
|
||||
import Root from "./card.svelte";
|
||||
import Content from "./card-content.svelte";
|
||||
import Description from "./card-description.svelte";
|
||||
import Footer from "./card-footer.svelte";
|
||||
import Header from "./card-header.svelte";
|
||||
import Title from "./card-title.svelte";
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
Description,
|
||||
Footer,
|
||||
Header,
|
||||
Title,
|
||||
//
|
||||
Root as Card,
|
||||
Content as CardContent,
|
||||
Description as CardDescription,
|
||||
Footer as CardFooter,
|
||||
Header as CardHeader,
|
||||
Title as CardTitle,
|
||||
};
|
33
src/lib/components/ui/dialog/dialog-content.svelte
Normal file
33
src/lib/components/ui/dialog/dialog-content.svelte
Normal file
@ -0,0 +1,33 @@
|
||||
<script>
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import X from "lucide-svelte/icons/x";
|
||||
import * as Dialog from "./index.js";
|
||||
import { cn, flyAndScale } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let transition = flyAndScale;
|
||||
export let transitionConfig = {
|
||||
duration: 200,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay />
|
||||
<DialogPrimitive.Content
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
class={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg sm:rounded-lg md:w-full",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
<DialogPrimitive.Close
|
||||
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
|
||||
>
|
||||
<X class="h-4 w-4" />
|
||||
<span class="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</Dialog.Portal>
|
13
src/lib/components/ui/dialog/dialog-description.svelte
Normal file
13
src/lib/components/ui/dialog/dialog-description.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Description
|
||||
class={cn("text-sm text-muted-foreground", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DialogPrimitive.Description>
|
12
src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
12
src/lib/components/ui/dialog/dialog-footer.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
9
src/lib/components/ui/dialog/dialog-header.svelte
Normal file
9
src/lib/components/ui/dialog/dialog-header.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
18
src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
18
src/lib/components/ui/dialog/dialog-overlay.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script>
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { fade } from "svelte/transition";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let transition = fade;
|
||||
export let transitionConfig = {
|
||||
duration: 150,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Overlay
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm", className)}
|
||||
{...$$restProps}
|
||||
/>
|
7
src/lib/components/ui/dialog/dialog-portal.svelte
Normal file
7
src/lib/components/ui/dialog/dialog-portal.svelte
Normal file
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Portal {...$$restProps}>
|
||||
<slot />
|
||||
</DialogPrimitive.Portal>
|
13
src/lib/components/ui/dialog/dialog-title.svelte
Normal file
13
src/lib/components/ui/dialog/dialog-title.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DialogPrimitive.Title
|
||||
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DialogPrimitive.Title>
|
34
src/lib/components/ui/dialog/index.js
Normal file
34
src/lib/components/ui/dialog/index.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { Dialog as DialogPrimitive } from "bits-ui";
|
||||
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";
|
||||
const Root = DialogPrimitive.Root;
|
||||
const Trigger = DialogPrimitive.Trigger;
|
||||
const Close = DialogPrimitive.Close;
|
||||
export {
|
||||
Root,
|
||||
Title,
|
||||
Portal,
|
||||
Footer,
|
||||
Header,
|
||||
Trigger,
|
||||
Overlay,
|
||||
Content,
|
||||
Description,
|
||||
Close,
|
||||
//
|
||||
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,
|
||||
Close as DialogClose,
|
||||
};
|
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import Check from "lucide-svelte/icons/check";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let checked = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
bind:checked
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:pointerdown
|
||||
on:pointerleave
|
||||
on:pointermove
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.CheckboxIndicator>
|
||||
<Check class="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.CheckboxIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn, flyAndScale } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let sideOffset = 4;
|
||||
export let transition = flyAndScale;
|
||||
export let transitionConfig = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Content
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
{sideOffset}
|
||||
class={cn(
|
||||
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.Content>
|
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let inset = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Item
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:pointerdown
|
||||
on:pointerleave
|
||||
on:pointermove
|
||||
>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.Item>
|
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let inset = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Label
|
||||
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.Label>
|
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
export let value = undefined;
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.RadioGroup>
|
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import Circle from "lucide-svelte/icons/circle";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let value;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
class={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{value}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:pointerdown
|
||||
on:pointerleave
|
||||
on:pointermove
|
||||
>
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.RadioIndicator>
|
||||
<Circle class="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.RadioIndicator>
|
||||
</span>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.RadioItem>
|
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.Separator
|
||||
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...$$restProps}
|
||||
/>
|
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<span class={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</span>
|
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import { cn, flyAndScale } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let transition = flyAndScale;
|
||||
export let transitionConfig = {
|
||||
x: -10,
|
||||
y: 0,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
class={cn(
|
||||
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:keydown
|
||||
on:focusout
|
||||
on:pointermove
|
||||
>
|
||||
<slot />
|
||||
</DropdownMenuPrimitive.SubContent>
|
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let inset = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
class={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:pointerleave
|
||||
on:pointermove
|
||||
>
|
||||
<slot />
|
||||
<ChevronRight class="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
46
src/lib/components/ui/dropdown-menu/index.js
Normal file
46
src/lib/components/ui/dropdown-menu/index.js
Normal file
@ -0,0 +1,46 @@
|
||||
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,
|
||||
};
|
7
src/lib/components/ui/form/form-button.svelte
Normal file
7
src/lib/components/ui/form/form-button.svelte
Normal file
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import * as Button from "$lib/components/ui/button/index.js";
|
||||
</script>
|
||||
|
||||
<Button.Root type="submit" on:click on:keydown {...$$restProps}>
|
||||
<slot />
|
||||
</Button.Root>
|
14
src/lib/components/ui/form/form-description.svelte
Normal file
14
src/lib/components/ui/form/form-description.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Description
|
||||
class={cn("text-sm text-muted-foreground", className)}
|
||||
{...$$restProps}
|
||||
let:descriptionAttrs
|
||||
>
|
||||
<slot {descriptionAttrs} />
|
||||
</FormPrimitive.Description>
|
16
src/lib/components/ui/form/form-element-field.svelte
Normal file
16
src/lib/components/ui/form/form-element-field.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts" context="module"></script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
export let form;
|
||||
export let name;
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.ElementField {form} {name} let:constraints let:errors let:tainted let:value>
|
||||
<div class={cn("space-y-2", className)}>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</div>
|
||||
</FormPrimitive.ElementField>
|
21
src/lib/components/ui/form/form-field-errors.svelte
Normal file
21
src/lib/components/ui/form/form-field-errors.svelte
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
export let errorClasses = undefined;
|
||||
</script>
|
||||
|
||||
<FormPrimitive.FieldErrors
|
||||
class={cn("text-sm font-medium text-destructive", className)}
|
||||
{...$$restProps}
|
||||
let:errors
|
||||
let:fieldErrorsAttrs
|
||||
let:errorAttrs
|
||||
>
|
||||
<slot {errors} {fieldErrorsAttrs} {errorAttrs}>
|
||||
{#each errors as error}
|
||||
<div {...errorAttrs} class={cn(errorClasses)}>{error}</div>
|
||||
{/each}
|
||||
</slot>
|
||||
</FormPrimitive.FieldErrors>
|
16
src/lib/components/ui/form/form-field.svelte
Normal file
16
src/lib/components/ui/form/form-field.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<script lang="ts" context="module"></script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
export let form;
|
||||
export let name;
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Field {form} {name} let:constraints let:errors let:tainted let:value>
|
||||
<div class={cn("space-y-2", className)}>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</div>
|
||||
</FormPrimitive.Field>
|
22
src/lib/components/ui/form/form-fieldset.svelte
Normal file
22
src/lib/components/ui/form/form-fieldset.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts" context="module"></script>
|
||||
|
||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
export let form;
|
||||
export let name;
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Fieldset
|
||||
{form}
|
||||
{name}
|
||||
let:constraints
|
||||
let:errors
|
||||
let:tainted
|
||||
let:value
|
||||
class={cn("space-y-2", className)}
|
||||
>
|
||||
<slot {constraints} {errors} {tainted} {value} />
|
||||
</FormPrimitive.Fieldset>
|
12
src/lib/components/ui/form/form-label.svelte
Normal file
12
src/lib/components/ui/form/form-label.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import { getFormControl } from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { Label } from "$lib/components/ui/label/index.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
const { labelAttrs } = getFormControl();
|
||||
</script>
|
||||
|
||||
<Label {...$labelAttrs} class={cn("data-[fs-error]:text-destructive", className)} {...$$restProps}>
|
||||
<slot {labelAttrs} />
|
||||
</Label>
|
14
src/lib/components/ui/form/form-legend.svelte
Normal file
14
src/lib/components/ui/form/form-legend.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<FormPrimitive.Legend
|
||||
{...$$restProps}
|
||||
class={cn("text-sm font-medium leading-none data-[fs-error]:text-destructive", className)}
|
||||
let:legendAttrs
|
||||
>
|
||||
<slot {legendAttrs} />
|
||||
</FormPrimitive.Legend>
|
31
src/lib/components/ui/form/index.js
Normal file
31
src/lib/components/ui/form/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
import * as FormPrimitive from "formsnap";
|
||||
import Description from "./form-description.svelte";
|
||||
import Label from "./form-label.svelte";
|
||||
import FieldErrors from "./form-field-errors.svelte";
|
||||
import Field from "./form-field.svelte";
|
||||
import Fieldset from "./form-fieldset.svelte";
|
||||
import Legend from "./form-legend.svelte";
|
||||
import ElementField from "./form-element-field.svelte";
|
||||
import Button from "./form-button.svelte";
|
||||
const Control = FormPrimitive.Control;
|
||||
export {
|
||||
Field,
|
||||
Control,
|
||||
Label,
|
||||
Button,
|
||||
FieldErrors,
|
||||
Description,
|
||||
Fieldset,
|
||||
Legend,
|
||||
ElementField,
|
||||
//
|
||||
Field as FormField,
|
||||
Control as FormControl,
|
||||
Description as FormDescription,
|
||||
Label as FormLabel,
|
||||
FieldErrors as FormFieldErrors,
|
||||
Fieldset as FormFieldset,
|
||||
Legend as FormLegend,
|
||||
ElementField as FormElementField,
|
||||
Button as FormButton,
|
||||
};
|
6
src/lib/components/ui/input/index.js
Normal file
6
src/lib/components/ui/input/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import Root from "./input.svelte";
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Input,
|
||||
};
|
32
src/lib/components/ui/input/input.svelte
Normal file
32
src/lib/components/ui/input/input.svelte
Normal file
@ -0,0 +1,32 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let value = undefined;
|
||||
export { className as class };
|
||||
export let readonly = undefined;
|
||||
</script>
|
||||
|
||||
<input
|
||||
class={cn(
|
||||
"flex h-10 w-full rounded-md border border-input bg-background 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
|
||||
{readonly}
|
||||
on:blur
|
||||
on:change
|
||||
on:click
|
||||
on:focus
|
||||
on:focusin
|
||||
on:focusout
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:keyup
|
||||
on:mouseover
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:paste
|
||||
on:input
|
||||
on:wheel
|
||||
{...$$restProps}
|
||||
/>
|
6
src/lib/components/ui/label/index.js
Normal file
6
src/lib/components/ui/label/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import Root from "./label.svelte";
|
||||
export {
|
||||
Root,
|
||||
//
|
||||
Root as Label,
|
||||
};
|
17
src/lib/components/ui/label/label.svelte
Normal file
17
src/lib/components/ui/label/label.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { Label as LabelPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<LabelPrimitive.Root
|
||||
class={cn(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:mousedown
|
||||
>
|
||||
<slot />
|
||||
</LabelPrimitive.Root>
|
31
src/lib/components/ui/select/index.js
Normal file
31
src/lib/components/ui/select/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
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,
|
||||
};
|
34
src/lib/components/ui/select/select-content.svelte
Normal file
34
src/lib/components/ui/select/select-content.svelte
Normal file
@ -0,0 +1,34 @@
|
||||
<script>
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { scale } from "svelte/transition";
|
||||
import { cn, flyAndScale } from "$lib/utils.js";
|
||||
export let sideOffset = 4;
|
||||
export let inTransition = flyAndScale;
|
||||
export let inTransitionConfig = undefined;
|
||||
export let outTransition = scale;
|
||||
export let outTransitionConfig = {
|
||||
start: 0.95,
|
||||
opacity: 0,
|
||||
duration: 50,
|
||||
};
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Content
|
||||
{inTransition}
|
||||
{inTransitionConfig}
|
||||
{outTransition}
|
||||
{outTransitionConfig}
|
||||
{sideOffset}
|
||||
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>
|
36
src/lib/components/ui/select/select-item.svelte
Normal file
36
src/lib/components/ui/select/select-item.svelte
Normal file
@ -0,0 +1,36 @@
|
||||
<script>
|
||||
import Check from "lucide-svelte/icons/check";
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let value;
|
||||
export let label = undefined;
|
||||
export let 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 data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground 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>
|
||||
{label || value}
|
||||
</slot>
|
||||
</SelectPrimitive.Item>
|
13
src/lib/components/ui/select/select-label.svelte
Normal file
13
src/lib/components/ui/select/select-label.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = 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>
|
8
src/lib/components/ui/select/select-separator.svelte
Normal file
8
src/lib/components/ui/select/select-separator.svelte
Normal file
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SelectPrimitive.Separator class={cn("-mx-1 my-1 h-px bg-muted", className)} {...$$restProps} />
|
23
src/lib/components/ui/select/select-trigger.svelte
Normal file
23
src/lib/components/ui/select/select-trigger.svelte
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import { Select as SelectPrimitive } from "bits-ui";
|
||||
import ChevronDown from "lucide-svelte/icons/chevron-down";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = 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-background 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 [&>span]:line-clamp-1",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
let:builder
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot {builder} />
|
||||
<div>
|
||||
<ChevronDown class="h-4 w-4 opacity-50" />
|
||||
</div>
|
||||
</SelectPrimitive.Trigger>
|
99
src/lib/components/ui/sheet/index.js
Normal file
99
src/lib/components/ui/sheet/index.js
Normal file
@ -0,0 +1,99 @@
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { tv } 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,
|
||||
},
|
||||
},
|
||||
};
|
34
src/lib/components/ui/sheet/sheet-content.svelte
Normal file
34
src/lib/components/ui/sheet/sheet-content.svelte
Normal file
@ -0,0 +1,34 @@
|
||||
<script>
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import X from "lucide-svelte/icons/x";
|
||||
import { fly } from "svelte/transition";
|
||||
import { SheetOverlay, SheetPortal, sheetTransitions, sheetVariants } from "./index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let side = "right";
|
||||
export { className as class };
|
||||
export let inTransition = fly;
|
||||
export let inTransitionConfig = sheetTransitions[side ?? "right"].in;
|
||||
export let outTransition = fly;
|
||||
export let outTransitionConfig = sheetTransitions[side ?? "right"].out;
|
||||
</script>
|
||||
|
||||
<SheetPortal>
|
||||
<SheetOverlay />
|
||||
<SheetPrimitive.Content
|
||||
{inTransition}
|
||||
{inTransitionConfig}
|
||||
{outTransition}
|
||||
{outTransitionConfig}
|
||||
class={cn(sheetVariants({ side }), className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
<SheetPrimitive.Close
|
||||
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary"
|
||||
>
|
||||
<X class="h-4 w-4" />
|
||||
<span class="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
</SheetPrimitive.Content>
|
||||
</SheetPortal>
|
10
src/lib/components/ui/sheet/sheet-description.svelte
Normal file
10
src/lib/components/ui/sheet/sheet-description.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Description class={cn("text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</SheetPrimitive.Description>
|
12
src/lib/components/ui/sheet/sheet-footer.svelte
Normal file
12
src/lib/components/ui/sheet/sheet-footer.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
9
src/lib/components/ui/sheet/sheet-header.svelte
Normal file
9
src/lib/components/ui/sheet/sheet-header.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
18
src/lib/components/ui/sheet/sheet-overlay.svelte
Normal file
18
src/lib/components/ui/sheet/sheet-overlay.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<script>
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { fade } from "svelte/transition";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let transition = fade;
|
||||
export let transitionConfig = {
|
||||
duration: 150,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Overlay
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm ", className)}
|
||||
{...$$restProps}
|
||||
/>
|
10
src/lib/components/ui/sheet/sheet-portal.svelte
Normal file
10
src/lib/components/ui/sheet/sheet-portal.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Portal class={cn(className)} {...$$restProps}>
|
||||
<slot />
|
||||
</SheetPrimitive.Portal>
|
13
src/lib/components/ui/sheet/sheet-title.svelte
Normal file
13
src/lib/components/ui/sheet/sheet-title.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<script>
|
||||
import { Dialog as SheetPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<SheetPrimitive.Title
|
||||
class={cn("text-lg font-semibold text-foreground", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</SheetPrimitive.Title>
|
27
src/lib/components/ui/table/index.js
Normal file
27
src/lib/components/ui/table/index.js
Normal file
@ -0,0 +1,27 @@
|
||||
import Root from "./table.svelte";
|
||||
import Body from "./table-body.svelte";
|
||||
import Caption from "./table-caption.svelte";
|
||||
import Cell from "./table-cell.svelte";
|
||||
import Footer from "./table-footer.svelte";
|
||||
import Head from "./table-head.svelte";
|
||||
import Header from "./table-header.svelte";
|
||||
import Row from "./table-row.svelte";
|
||||
export {
|
||||
Root,
|
||||
Body,
|
||||
Caption,
|
||||
Cell,
|
||||
Footer,
|
||||
Head,
|
||||
Header,
|
||||
Row,
|
||||
//
|
||||
Root as Table,
|
||||
Body as TableBody,
|
||||
Caption as TableCaption,
|
||||
Cell as TableCell,
|
||||
Footer as TableFooter,
|
||||
Head as TableHead,
|
||||
Header as TableHeader,
|
||||
Row as TableRow,
|
||||
};
|
9
src/lib/components/ui/table/table-body.svelte
Normal file
9
src/lib/components/ui/table/table-body.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tbody class={cn("[&_tr:last-child]:border-0", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</tbody>
|
9
src/lib/components/ui/table/table-caption.svelte
Normal file
9
src/lib/components/ui/table/table-caption.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<caption class={cn("mt-4 text-sm text-muted-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</caption>
|
14
src/lib/components/ui/table/table-cell.svelte
Normal file
14
src/lib/components/ui/table/table-cell.svelte
Normal file
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<td
|
||||
class={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</td>
|
9
src/lib/components/ui/table/table-footer.svelte
Normal file
9
src/lib/components/ui/table/table-footer.svelte
Normal file
@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tfoot class={cn("bg-primary font-medium text-primary-foreground", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</tfoot>
|
15
src/lib/components/ui/table/table-head.svelte
Normal file
15
src/lib/components/ui/table/table-head.svelte
Normal file
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<th
|
||||
class={cn(
|
||||
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</th>
|
10
src/lib/components/ui/table/table-header.svelte
Normal file
10
src/lib/components/ui/table/table-header.svelte
Normal file
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<thead class={cn("[&_tr]:border-b", className)} {...$$restProps} on:click on:keydown>
|
||||
<slot />
|
||||
</thead>
|
17
src/lib/components/ui/table/table-row.svelte
Normal file
17
src/lib/components/ui/table/table-row.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<tr
|
||||
class={cn(
|
||||
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
<slot />
|
||||
</tr>
|
11
src/lib/components/ui/table/table.svelte
Normal file
11
src/lib/components/ui/table/table.svelte
Normal file
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import { cn } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class="relative w-full overflow-auto">
|
||||
<table class={cn("w-full caption-bottom text-sm", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</table>
|
||||
</div>
|
13
src/lib/components/ui/tooltip/index.js
Normal file
13
src/lib/components/ui/tooltip/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
||||
import Content from "./tooltip-content.svelte";
|
||||
const Root = TooltipPrimitive.Root;
|
||||
const Trigger = TooltipPrimitive.Trigger;
|
||||
export {
|
||||
Root,
|
||||
Trigger,
|
||||
Content,
|
||||
//
|
||||
Root as Tooltip,
|
||||
Content as TooltipContent,
|
||||
Trigger as TooltipTrigger,
|
||||
};
|
25
src/lib/components/ui/tooltip/tooltip-content.svelte
Normal file
25
src/lib/components/ui/tooltip/tooltip-content.svelte
Normal file
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
||||
import { cn, flyAndScale } from "$lib/utils.js";
|
||||
let className = undefined;
|
||||
export let sideOffset = 4;
|
||||
export let transition = flyAndScale;
|
||||
export let transitionConfig = {
|
||||
y: 8,
|
||||
duration: 150,
|
||||
};
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<TooltipPrimitive.Content
|
||||
{transition}
|
||||
{transitionConfig}
|
||||
{sideOffset}
|
||||
class={cn(
|
||||
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md",
|
||||
className
|
||||
)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</TooltipPrimitive.Content>
|
48
src/lib/utils.js
Normal file
48
src/lib/utils.js
Normal file
@ -0,0 +1,48 @@
|
||||
import { clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { cubicOut } from "svelte/easing";
|
||||
|
||||
export function cn(...inputs) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export const flyAndScale = (
|
||||
node,
|
||||
params = { y: -8, x: 0, start: 0.95, duration: 150 }
|
||||
) => {
|
||||
const style = getComputedStyle(node);
|
||||
const transform = style.transform === "none" ? "" : style.transform;
|
||||
|
||||
const scaleConversion = (valueA, scaleA, scaleB) => {
|
||||
const [minA, maxA] = scaleA;
|
||||
const [minB, maxB] = scaleB;
|
||||
|
||||
const percentage = (valueA - minA) / (maxA - minA);
|
||||
const valueB = percentage * (maxB - minB) + minB;
|
||||
|
||||
return valueB;
|
||||
};
|
||||
|
||||
const styleToString = (style) => {
|
||||
return Object.keys(style).reduce((str, key) => {
|
||||
if (style[key] === undefined) return str;
|
||||
return str + `${key}:${style[key]};`;
|
||||
}, "");
|
||||
};
|
||||
|
||||
return {
|
||||
duration: params.duration ?? 200,
|
||||
delay: 0,
|
||||
css: (t) => {
|
||||
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
|
||||
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
|
||||
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
|
||||
|
||||
return styleToString({
|
||||
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
|
||||
opacity: t
|
||||
});
|
||||
},
|
||||
easing: cubicOut
|
||||
};
|
||||
};
|
@ -1,10 +1,8 @@
|
||||
import { config } from "$lib"
|
||||
|
||||
/** @type {import("./$types").PageServerLoad} */
|
||||
/** @type {import("./$types").LayoutServerLoad} */
|
||||
export const load = async ({fetch}) => {
|
||||
const res = await fetch(config.api_url+"/me", {
|
||||
credentials: 'include'
|
||||
});
|
||||
const res = await fetch(config.api_url+"/me")
|
||||
|
||||
const data = await res.json();
|
||||
|
124
src/routes/+layout.svelte
Normal file
124
src/routes/+layout.svelte
Normal file
@ -0,0 +1,124 @@
|
||||
<script>
|
||||
import '../app.pcss';
|
||||
|
||||
import Menu from 'lucide-svelte/icons/menu';
|
||||
import Package2 from 'lucide-svelte/icons/package-2';
|
||||
import Search from 'lucide-svelte/icons/search';
|
||||
import CircleUser from 'lucide-svelte/icons/circle-user';
|
||||
import Sun from 'svelte-radix/Sun.svelte';
|
||||
import Moon from 'svelte-radix/Moon.svelte';
|
||||
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import * as Sheet from '$lib/components/ui/sheet/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
|
||||
import { ModeWatcher, toggleMode } from 'mode-watcher';
|
||||
|
||||
/** @type {import('./$types').LayoutServerData} */
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<ModeWatcher />
|
||||
|
||||
<div class="flex min-h-screen w-full flex-col">
|
||||
<header class="sticky top-0 flex h-16 items-center gap-4 border-b bg-background px-4 md:px-6">
|
||||
<nav
|
||||
class="hidden flex-col gap-6 text-lg font-medium md:flex md:flex-row md:items-center md:gap-5 md:text-sm lg:gap-6"
|
||||
>
|
||||
<a href="##" class="flex items-center gap-2 text-lg font-semibold md:text-base">
|
||||
<Package2 class="h-6 w-6" />
|
||||
<span class="sr-only">{data.me.user.name}</span>
|
||||
</a>
|
||||
<a href="/" class="text-foreground transition-colors hover:text-foreground"> Dashboard </a>
|
||||
<a href="/articles" class="text-muted-foreground transition-colors hover:text-foreground">
|
||||
Articles
|
||||
</a>
|
||||
<a href="##" class="text-muted-foreground transition-colors hover:text-foreground">
|
||||
Emails
|
||||
</a>
|
||||
<a href="##" class="text-muted-foreground transition-colors hover:text-foreground">
|
||||
Website
|
||||
</a>
|
||||
<a href="##" class="text-muted-foreground transition-colors hover:text-foreground">
|
||||
Analytics
|
||||
</a>
|
||||
</nav>
|
||||
<Sheet.Root>
|
||||
<Sheet.Trigger asChild let:builder>
|
||||
<Button variant="outline" size="icon" class="shrink-0 md:hidden" builders={[builder]}>
|
||||
<Menu class="h-5 w-5" />
|
||||
<span class="sr-only">Toggle navigation menu</span>
|
||||
</Button>
|
||||
</Sheet.Trigger>
|
||||
<Sheet.Content side="left">
|
||||
<nav class="grid gap-6 text-lg font-medium">
|
||||
<a href="##" class="flex items-center gap-2 text-lg font-semibold">
|
||||
<Package2 class="h-6 w-6" />
|
||||
<span class="sr-only">{data.me.user.name}</span>
|
||||
</a>
|
||||
<a href="/" class="hover:text-foreground"> Dashboard </a>
|
||||
<a href="/articles" class="text-muted-foreground hover:text-foreground"> Articles </a>
|
||||
<a href="##" class="text-muted-foreground hover:text-foreground"> Products </a>
|
||||
<a href="##" class="text-muted-foreground hover:text-foreground"> Customers </a>
|
||||
<a href="##" class="text-muted-foreground hover:text-foreground"> Analytics </a>
|
||||
|
||||
<div class="mt-auto">
|
||||
<Button on:click={toggleMode} variant="outline" size="icon">
|
||||
<Sun
|
||||
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
|
||||
/>
|
||||
<Moon
|
||||
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
|
||||
/>
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
</Sheet.Content>
|
||||
</Sheet.Root>
|
||||
|
||||
<div class="flex w-full items-center gap-4 md:ml-auto md:gap-2 lg:gap-4">
|
||||
<div class="hidden md:block ml-auto">
|
||||
<Button on:click={toggleMode} variant="outline" size="icon">
|
||||
<Sun
|
||||
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0"
|
||||
/>
|
||||
<Moon
|
||||
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100"
|
||||
/>
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</div>
|
||||
<form class="flex-1 sm:flex-initial">
|
||||
<div class="relative">
|
||||
<Search class="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search articles..."
|
||||
class="pl-8 sm:w-[300px] md:w-[200px] lg:w-[300px]"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild let:builder>
|
||||
<Button builders={[builder]} variant="secondary" size="icon" class="rounded-full">
|
||||
<CircleUser class="h-5 w-5" />
|
||||
<span class="sr-only">Toggle user menu</span>
|
||||
</Button>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content align="end">
|
||||
<DropdownMenu.Label>My Account</DropdownMenu.Label>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>Settings</DropdownMenu.Item>
|
||||
<DropdownMenu.Item>Support</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item>Logout</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
</header>
|
||||
<main class="flex flex-1 flex-col gap-4 p-4 md:gap-8 md:p-8">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
@ -1,10 +1,220 @@
|
||||
<script>
|
||||
/** @type {import('./$types').PageServerData} */
|
||||
export let data;
|
||||
<script lang="ts">
|
||||
import Activity from 'lucide-svelte/icons/activity';
|
||||
import ArrowUpRight from 'lucide-svelte/icons/arrow-up-right';
|
||||
import CreditCard from 'lucide-svelte/icons/credit-card';
|
||||
import DollarSign from 'lucide-svelte/icons/dollar-sign';
|
||||
import Users from 'lucide-svelte/icons/users';
|
||||
|
||||
import * as Avatar from '$lib/components/ui/avatar/index.js';
|
||||
import { Badge } from '$lib/components/ui/badge/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import * as Card from '$lib/components/ui/card/index.js';
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
</script>
|
||||
|
||||
<p>{JSON.stringify(data.me)}</p>
|
||||
|
||||
<div class="grid gap-4 md:grid-cols-2 md:gap-8 lg:grid-cols-4">
|
||||
<Card.Root>
|
||||
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<Card.Title class="text-sm font-medium">Total Articles</Card.Title>
|
||||
<DollarSign class="h-4 w-4 text-muted-foreground" />
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="text-2xl font-bold">48</div>
|
||||
<p class="text-xs text-muted-foreground">7 remaining this month</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<Card.Root>
|
||||
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<Card.Title class="text-sm font-medium">Subscriptions</Card.Title>
|
||||
<Users class="h-4 w-4 text-muted-foreground" />
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="text-2xl font-bold">+2350</div>
|
||||
<p class="text-xs text-muted-foreground">+180.1% from last month</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<Card.Root>
|
||||
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<Card.Title class="text-sm font-medium">Emails collected</Card.Title>
|
||||
<CreditCard class="h-4 w-4 text-muted-foreground" />
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="text-2xl font-bold">+12,234</div>
|
||||
<p class="text-xs text-muted-foreground">+19% from last month</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<Card.Root>
|
||||
<Card.Header class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<Card.Title class="text-sm font-medium">Reads</Card.Title>
|
||||
<Activity class="h-4 w-4 text-muted-foreground" />
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="text-2xl font-bold">+573</div>
|
||||
<p class="text-xs text-muted-foreground">+201 since last hour</p>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
<div class="grid gap-4 md:gap-8 lg:grid-cols-2 xl:grid-cols-3">
|
||||
<Card.Root class="xl:col-span-2">
|
||||
<Card.Header class="flex flex-row items-center">
|
||||
<div class="grid gap-2">
|
||||
<Card.Title>Articles</Card.Title>
|
||||
<Card.Description>Recent articles written from your youtube videos.</Card.Description>
|
||||
</div>
|
||||
<Button href="##" size="sm" class="ml-auto gap-1">
|
||||
View All
|
||||
<ArrowUpRight class="h-4 w-4" />
|
||||
</Button>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head>Customer</Table.Head>
|
||||
<Table.Head class="xl:table.-column hidden">Type</Table.Head>
|
||||
<Table.Head class="xl:table.-column hidden">Status</Table.Head>
|
||||
<Table.Head class="xl:table.-column hidden">Date</Table.Head>
|
||||
<Table.Head class="text-right">Amount</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<div class="font-medium">Liam Johnson</div>
|
||||
<div class="hidden text-sm text-muted-foreground md:inline">liam@example.com</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">Sale</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">
|
||||
<Badge class="text-xs" variant="outline">Approved</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="md:table.-cell xl:table.-column hidden lg:hidden">
|
||||
2023-06-23
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">$250.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<div class="font-medium">Olivia Smith</div>
|
||||
<div class="hidden text-sm text-muted-foreground md:inline">olivia@example.com</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">Refund</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">
|
||||
<Badge class="text-xs" variant="outline">Declined</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="md:table.-cell xl:table.-column hidden lg:hidden">
|
||||
2023-06-24
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">$150.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<div class="font-medium">Noah Williams</div>
|
||||
<div class="hidden text-sm text-muted-foreground md:inline">noah@example.com</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">Subscription</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">
|
||||
<Badge class="text-xs" variant="outline">Approved</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="md:table.-cell xl:table.-column hidden lg:hidden">
|
||||
2023-06-25
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">$350.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<div class="font-medium">Emma Brown</div>
|
||||
<div class="hidden text-sm text-muted-foreground md:inline">emma@example.com</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">Sale</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">
|
||||
<Badge class="text-xs" variant="outline">Approved</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="md:table.-cell xl:table.-column hidden lg:hidden">
|
||||
2023-06-26
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">$450.00</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<div class="font-medium">Liam Johnson</div>
|
||||
<div class="hidden text-sm text-muted-foreground md:inline">liam@example.com</div>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">Sale</Table.Cell>
|
||||
<Table.Cell class="xl:table.-column hidden">
|
||||
<Badge class="text-xs" variant="outline">Approved</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell class="md:table.-cell xl:table.-column hidden lg:hidden">
|
||||
2023-06-27
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-right">$550.00</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Recent Signups</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content class="grid gap-8">
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar.Root class="hidden h-9 w-9 sm:flex">
|
||||
<Avatar.Image src="/avatars/01.png" alt="Avatar" />
|
||||
<Avatar.Fallback>OM</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid gap-1">
|
||||
<p class="text-sm font-medium leading-none">Olivia Martin</p>
|
||||
<p class="text-sm text-muted-foreground">olivia.martin@email.com</p>
|
||||
</div>
|
||||
<div class="ml-auto font-medium">56 seconds ago</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar.Root class="hidden h-9 w-9 sm:flex">
|
||||
<Avatar.Image src="/avatars/02.png" alt="Avatar" />
|
||||
<Avatar.Fallback>JL</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid gap-1">
|
||||
<p class="text-sm font-medium leading-none">Jackson Lee</p>
|
||||
<p class="text-sm text-muted-foreground">jackson.lee@email.com</p>
|
||||
</div>
|
||||
<div class="ml-auto font-medium">2 minutes ago</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar.Root class="hidden h-9 w-9 sm:flex">
|
||||
<Avatar.Image src="/avatars/03.png" alt="Avatar" />
|
||||
<Avatar.Fallback>IN</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid gap-1">
|
||||
<p class="text-sm font-medium leading-none">Isabella Nguyen</p>
|
||||
<p class="text-sm text-muted-foreground">isabella.nguyen@email.com</p>
|
||||
</div>
|
||||
<div class="ml-auto font-medium">5 minutes ago</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar.Root class="hidden h-9 w-9 sm:flex">
|
||||
<Avatar.Image src="/avatars/04.png" alt="Avatar" />
|
||||
<Avatar.Fallback>WK</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid gap-1">
|
||||
<p class="text-sm font-medium leading-none">William Kim</p>
|
||||
<p class="text-sm text-muted-foreground">will@email.com</p>
|
||||
</div>
|
||||
<div class="ml-auto font-medium">9 minutes ago</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<Avatar.Root class="hidden h-9 w-9 sm:flex">
|
||||
<Avatar.Image src="/avatars/05.png" alt="Avatar" />
|
||||
<Avatar.Fallback>SD</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
<div class="grid gap-1">
|
||||
<p class="text-sm font-medium leading-none">Sofia Davis</p>
|
||||
<p class="text-sm text-muted-foreground">sofia.davis@email.com</p>
|
||||
</div>
|
||||
<div class="ml-auto font-medium">15 minutes ago</div>
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
<!-- <p>{JSON.stringify(data)}</p>
|
||||
{#await me}
|
||||
<p>loading...</p>
|
||||
|
18
src/routes/articles/+page.server.js
Normal file
18
src/routes/articles/+page.server.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { config } from "$lib"
|
||||
import { superValidate } from "sveltekit-superforms";
|
||||
import { formSchema } from "./schema";
|
||||
import { zod } from "sveltekit-superforms/adapters";
|
||||
|
||||
/** @type {import("./$types").PageServerLoad} */
|
||||
export const load = async ({fetch}) => {
|
||||
const res = await fetch(config.api_url+"/blog?mine=true", {
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
console.log(data);
|
||||
return {
|
||||
articles: data,
|
||||
form: await superValidate(zod(formSchema)),
|
||||
}
|
||||
}
|
180
src/routes/articles/+page.svelte
Normal file
180
src/routes/articles/+page.svelte
Normal file
@ -0,0 +1,180 @@
|
||||
<script>
|
||||
import * as Table from '$lib/components/ui/table/index.js';
|
||||
import { ExternalLink, Pen, Trash } from 'lucide-svelte';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import * as Form from '$lib/components/ui/form';
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
|
||||
import TooltipButton from '$lib/components/molecules/tooltipbutton.svelte';
|
||||
import ProBadge from '$lib/components/molecules/probadge.svelte';
|
||||
|
||||
import { formSchema } from "./schema";
|
||||
import { superForm } from 'sveltekit-superforms';
|
||||
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||
/** @type {import("./$types").PageData} */
|
||||
export let data;
|
||||
|
||||
const form = superForm(data.form, {
|
||||
validators: zodClient(formSchema)
|
||||
});
|
||||
|
||||
const { form: formData, enhance } = form;
|
||||
|
||||
const invoices = [
|
||||
{
|
||||
id: 'AG64NE',
|
||||
title: 'Nullam ornare ornare orci a auctor.',
|
||||
preview:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ornare ornare orci a auctor. Mauris gravida luctus vulputate. Cras porttitor, mi ut pharetra blandit, dolor elit convallis velit, volutpat dictum quam enim ut purus.',
|
||||
source: 'Youtube'
|
||||
},
|
||||
{
|
||||
id: 'AG64NE',
|
||||
title: 'Nullam ornare ornare orci a auctor.',
|
||||
preview:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ornare ornare orci a auctor. Mauris gravida luctus vulputate. Cras porttitor, mi ut pharetra blandit, dolor elit convallis velit, volutpat dictum quam enim ut purus.',
|
||||
source: 'Youtube'
|
||||
},
|
||||
{
|
||||
id: 'AG64NE',
|
||||
title: 'Nullam ornare ornare orci a auctor.',
|
||||
preview:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ornare ornare orci a auctor. Mauris gravida luctus vulputate. Cras porttitor, mi ut pharetra blandit, dolor elit convallis velit, volutpat dictum quam enim ut purus.',
|
||||
source: 'Youtube'
|
||||
},
|
||||
{
|
||||
id: 'AG64NE',
|
||||
title: 'Nullam ornare ornare orci a auctor.',
|
||||
preview:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ornare ornare orci a auctor. Mauris gravida luctus vulputate. Cras porttitor, mi ut pharetra blandit, dolor elit convallis velit, volutpat dictum quam enim ut purus.',
|
||||
source: 'Youtube'
|
||||
},
|
||||
{
|
||||
id: 'AG64NE',
|
||||
title: 'Nullam ornare ornare orci a auctor.',
|
||||
preview:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ornare ornare orci a auctor. Mauris gravida luctus vulputate. Cras porttitor, mi ut pharetra blandit, dolor elit convallis velit, volutpat dictum quam enim ut purus.',
|
||||
source: 'Youtube'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-[1500px]">
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger class={buttonVariants({ variant: 'default' })}>Create Article</Dialog.Trigger>
|
||||
<Dialog.Content class="sm:max-w-[750px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>Create Article</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Configure your article and let our AI do the writing!
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<form method="POST" use:enhance name="blog-converter">
|
||||
<Form.Field {form} name="email">
|
||||
<Form.Control let:attrs>
|
||||
<div class="grid gap-4 py-4">
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Form.Label for="youtube_url" class="text-right">Youtube video URL*</Form.Label>
|
||||
<Input
|
||||
id="youtube_url"
|
||||
placeholder="www.youtube.com/watch?v=..."
|
||||
class="col-span-3"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Form.Label for="length" class="text-right">Article length</Form.Label>
|
||||
<Select.Root portal={null} name="length">
|
||||
<Select.Trigger class="w-[300px]">
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Group>
|
||||
<Select.Item value="short" label="Short (~700 words)"
|
||||
>Short (~700 words)</Select.Item
|
||||
>
|
||||
<Select.Item value="medium" label="Medium (~1500 words)"
|
||||
>Medium (~1500 words)<ProBadge /></Select.Item
|
||||
>
|
||||
<Select.Item value="long" label="Long (~2500 words)"
|
||||
>Long (~2500 words)<ProBadge /></Select.Item
|
||||
>
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
<Select.Input name="blogLength" />
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Form.Label for="length" class="text-right">Format</Form.Label>
|
||||
<Select.Root portal={null} name="length">
|
||||
<Select.Trigger class="w-[200px]">
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Group>
|
||||
<Select.Item value="summary" label="Summary">Summary</Select.Item>
|
||||
<Select.Item value="listicle" label="Listicle">Listicle</Select.Item>
|
||||
<Select.Item value="product review" label="Product Review"
|
||||
>Product Review</Select.Item
|
||||
>
|
||||
<Select.Item value="news report" label="News Report">News Report</Select.Item>
|
||||
<Select.Item value="tutorial" label="Tutorial">Tutorial</Select.Item>
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
<Select.Input name="blogFormat" />
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
</Form.Control>
|
||||
<Form.Description />
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
</form>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button type="submit" form="blog-converter">Create</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
<Table.Root>
|
||||
<Table.Caption>A list of your recent articles.</Table.Caption>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.Head class="w-[100px]">ID</Table.Head>
|
||||
<Table.Head class="w-[300px]">Title</Table.Head>
|
||||
<Table.Head class="w-[500px]">Preview</Table.Head>
|
||||
<Table.Head>Source</Table.Head>
|
||||
<Table.Head>Actions</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each invoices as invoice, i (i)}
|
||||
<Table.Row>
|
||||
<Table.Cell class="font-medium">{invoice.id}</Table.Cell>
|
||||
<Table.Cell class="max-w-16 overflow-hidden overflow-ellipsis text-nowrap"
|
||||
>{invoice.title}</Table.Cell
|
||||
>
|
||||
<Table.Cell class="max-w-10 overflow-hidden overflow-ellipsis text-nowrap"
|
||||
>{invoice.preview}</Table.Cell
|
||||
>
|
||||
<Table.Cell>{invoice.source}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<TooltipButton variant="outline" size="icon" tip="Preview">
|
||||
<ExternalLink size="1rem" />
|
||||
</TooltipButton>
|
||||
<TooltipButton variant="outline" size="icon" tip="Edit">
|
||||
<Pen size="1rem" />
|
||||
</TooltipButton>
|
||||
<TooltipButton variant="outline" size="icon" tip="Delete">
|
||||
<Trash size="1rem" />
|
||||
</TooltipButton>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
<!-- <p>{JSON.stringify(data)}</p> -->
|
9
src/routes/articles/schema.js
Normal file
9
src/routes/articles/schema.js
Normal file
@ -0,0 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const formSchema = z.object({
|
||||
youtube_url: z.string().url(),
|
||||
length: z.enum(["short", "medium", "long"]).optional(),
|
||||
format: z.enum(["summary", "listicle", "product review", "news report", "tutorial"]).optional(),
|
||||
});
|
||||
|
||||
/** @typedef {typeof formSchema} FormSchema */
|
6
src/routes/auth/+page.svelte
Normal file
6
src/routes/auth/+page.svelte
Normal file
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
|
||||
import { config } from "$lib";
|
||||
|
||||
</script>
|
||||
<a href="{config.api_url}/auth/google">Log in here you fat bastard</a>
|
BIN
static/avatars/01.png
Normal file
BIN
static/avatars/01.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
static/avatars/02.png
Normal file
BIN
static/avatars/02.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
static/avatars/03.png
Normal file
BIN
static/avatars/03.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
BIN
static/avatars/04.png
Normal file
BIN
static/avatars/04.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
static/avatars/05.png
Normal file
BIN
static/avatars/05.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
@ -1,3 +1,4 @@
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
@ -7,7 +8,9 @@ const config = {
|
||||
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
},
|
||||
|
||||
preprocess: [vitePreprocess({})]
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
64
tailwind.config.js
Normal file
64
tailwind.config.js
Normal file
@ -0,0 +1,64 @@
|
||||
import { fontFamily } from "tailwindcss/defaultTheme";
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
const config = {
|
||||
darkMode: ["class"],
|
||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
safelist: ["dark"],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px"
|
||||
}
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border) / <alpha-value>)",
|
||||
input: "hsl(var(--input) / <alpha-value>)",
|
||||
ring: "hsl(var(--ring) / <alpha-value>)",
|
||||
background: "hsl(var(--background) / <alpha-value>)",
|
||||
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
|
||||
foreground: "hsl(var(--primary-foreground) / <alpha-value>)"
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
|
||||
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)"
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
||||
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)"
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
|
||||
foreground: "hsl(var(--muted-foreground) / <alpha-value>)"
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
|
||||
foreground: "hsl(var(--accent-foreground) / <alpha-value>)"
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
|
||||
foreground: "hsl(var(--popover-foreground) / <alpha-value>)"
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card) / <alpha-value>)",
|
||||
foreground: "hsl(var(--card-foreground) / <alpha-value>)"
|
||||
}
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)"
|
||||
},
|
||||
fontFamily: {
|
||||
sans: [...fontFamily.sans]
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
Loading…
Reference in New Issue
Block a user