lotsa shit
This commit is contained in:
parent
a8b9dd0510
commit
f42ba94af4
11
.prettierrc
11
.prettierrc
@ -3,6 +3,13 @@
|
|||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 100,
|
"printWidth": 100,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
"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/adapter-auto": "^3.0.0",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.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": "^3.1.1",
|
||||||
"prettier-plugin-svelte": "^3.1.2",
|
"prettier-plugin-svelte": "^3.1.2",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.5.9",
|
||||||
"svelte": "^4.2.7",
|
"svelte": "^4.2.7",
|
||||||
"svelte-check": "^3.6.0",
|
"svelte-check": "^3.6.0",
|
||||||
|
"tailwindcss": "^3.3.6",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3"
|
"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} */
|
/** @type {import('@sveltejs/kit').HandleFetch} */
|
||||||
export async function handleFetch({ event, request, fetch }) {
|
export async function handleFetch({ event, request, fetch }) {
|
||||||
|
console.log(event.request.headers.get("cookie"))
|
||||||
if (request.url.startsWith(config.api_url)) {
|
if (request.url.startsWith(config.api_url)) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
request.headers.set('cookie', event.request.headers.get('cookie'));
|
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"
|
import { config } from "$lib"
|
||||||
|
|
||||||
/** @type {import("./$types").PageServerLoad} */
|
/** @type {import("./$types").LayoutServerLoad} */
|
||||||
export const load = async ({fetch}) => {
|
export const load = async ({fetch}) => {
|
||||||
const res = await fetch(config.api_url+"/me", {
|
const res = await fetch(config.api_url+"/me")
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await res.json();
|
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>
|
<script lang="ts">
|
||||||
/** @type {import('./$types').PageServerData} */
|
import Activity from 'lucide-svelte/icons/activity';
|
||||||
export let data;
|
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>
|
</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>
|
<!-- <p>{JSON.stringify(data)}</p>
|
||||||
{#await me}
|
{#await me}
|
||||||
<p>loading...</p>
|
<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';
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @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.
|
// 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.
|
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
adapter: adapter()
|
adapter: adapter()
|
||||||
}
|
},
|
||||||
|
|
||||||
|
preprocess: [vitePreprocess({})]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
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