Spaces:
Running
Running
Commit
•
b14d567
1
Parent(s):
6bce3a4
setup webllm with smol 360m demo
Browse files- bun.lockb +0 -0
- components.json +14 -0
- package.json +10 -1
- postcss.config.js +6 -0
- src/app.css +78 -0
- src/lib/components/ui/badge/badge.svelte +18 -0
- src/lib/components/ui/badge/index.ts +21 -0
- src/lib/components/ui/textarea/index.ts +28 -0
- src/lib/components/ui/textarea/textarea.svelte +38 -0
- src/lib/utils.ts +62 -0
- src/routes/+layout.svelte +1 -0
- src/routes/+page.svelte +98 -2
- svelte.config.js +4 -1
- tailwind.config.ts +64 -0
bun.lockb
CHANGED
Binary files a/bun.lockb and b/bun.lockb differ
|
|
components.json
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"$schema": "https://shadcn-svelte.com/schema.json",
|
3 |
+
"style": "default",
|
4 |
+
"tailwind": {
|
5 |
+
"config": "tailwind.config.ts",
|
6 |
+
"css": "src/app.css",
|
7 |
+
"baseColor": "slate"
|
8 |
+
},
|
9 |
+
"aliases": {
|
10 |
+
"components": "$lib/components",
|
11 |
+
"utils": "$lib/utils"
|
12 |
+
},
|
13 |
+
"typescript": true
|
14 |
+
}
|
package.json
CHANGED
@@ -13,10 +13,19 @@
|
|
13 |
"@sveltejs/adapter-auto": "^3.0.0",
|
14 |
"@sveltejs/kit": "^2.0.0",
|
15 |
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
|
|
|
|
16 |
"svelte": "^4.2.7",
|
17 |
"svelte-check": "^3.6.0",
|
|
|
18 |
"typescript": "^5.0.0",
|
19 |
"vite": "^5.0.3"
|
20 |
},
|
21 |
-
"type": "module"
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
|
|
13 |
"@sveltejs/adapter-auto": "^3.0.0",
|
14 |
"@sveltejs/kit": "^2.0.0",
|
15 |
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
16 |
+
"@tailwindcss/typography": "^0.5.14",
|
17 |
+
"autoprefixer": "^10.4.20",
|
18 |
"svelte": "^4.2.7",
|
19 |
"svelte-check": "^3.6.0",
|
20 |
+
"tailwindcss": "^3.4.9",
|
21 |
"typescript": "^5.0.0",
|
22 |
"vite": "^5.0.3"
|
23 |
},
|
24 |
+
"type": "module",
|
25 |
+
"dependencies": {
|
26 |
+
"@mlc-ai/web-llm": "^0.2.60",
|
27 |
+
"clsx": "^2.1.1",
|
28 |
+
"tailwind-merge": "^2.5.2",
|
29 |
+
"tailwind-variants": "^0.2.1"
|
30 |
+
}
|
31 |
}
|
postcss.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export default {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {}
|
5 |
+
}
|
6 |
+
};
|
src/app.css
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
@layer base {
|
6 |
+
:root {
|
7 |
+
--background: 0 0% 100%;
|
8 |
+
--foreground: 222.2 84% 4.9%;
|
9 |
+
|
10 |
+
--muted: 210 40% 96.1%;
|
11 |
+
--muted-foreground: 215.4 16.3% 46.9%;
|
12 |
+
|
13 |
+
--popover: 0 0% 100%;
|
14 |
+
--popover-foreground: 222.2 84% 4.9%;
|
15 |
+
|
16 |
+
--card: 0 0% 100%;
|
17 |
+
--card-foreground: 222.2 84% 4.9%;
|
18 |
+
|
19 |
+
--border: 214.3 31.8% 91.4%;
|
20 |
+
--input: 214.3 31.8% 91.4%;
|
21 |
+
|
22 |
+
--primary: 222.2 47.4% 11.2%;
|
23 |
+
--primary-foreground: 210 40% 98%;
|
24 |
+
|
25 |
+
--secondary: 210 40% 96.1%;
|
26 |
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
27 |
+
|
28 |
+
--accent: 210 40% 96.1%;
|
29 |
+
--accent-foreground: 222.2 47.4% 11.2%;
|
30 |
+
|
31 |
+
--destructive: 0 72.2% 50.6%;
|
32 |
+
--destructive-foreground: 210 40% 98%;
|
33 |
+
|
34 |
+
--ring: 222.2 84% 4.9%;
|
35 |
+
|
36 |
+
--radius: 0.5rem;
|
37 |
+
}
|
38 |
+
|
39 |
+
.dark {
|
40 |
+
--background: 222.2 84% 4.9%;
|
41 |
+
--foreground: 210 40% 98%;
|
42 |
+
|
43 |
+
--muted: 217.2 32.6% 17.5%;
|
44 |
+
--muted-foreground: 215 20.2% 65.1%;
|
45 |
+
|
46 |
+
--popover: 222.2 84% 4.9%;
|
47 |
+
--popover-foreground: 210 40% 98%;
|
48 |
+
|
49 |
+
--card: 222.2 84% 4.9%;
|
50 |
+
--card-foreground: 210 40% 98%;
|
51 |
+
|
52 |
+
--border: 217.2 32.6% 17.5%;
|
53 |
+
--input: 217.2 32.6% 17.5%;
|
54 |
+
|
55 |
+
--primary: 210 40% 98%;
|
56 |
+
--primary-foreground: 222.2 47.4% 11.2%;
|
57 |
+
|
58 |
+
--secondary: 217.2 32.6% 17.5%;
|
59 |
+
--secondary-foreground: 210 40% 98%;
|
60 |
+
|
61 |
+
--accent: 217.2 32.6% 17.5%;
|
62 |
+
--accent-foreground: 210 40% 98%;
|
63 |
+
|
64 |
+
--destructive: 0 62.8% 30.6%;
|
65 |
+
--destructive-foreground: 210 40% 98%;
|
66 |
+
|
67 |
+
--ring: hsl(212.7,26.8%,83.9);
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
@layer base {
|
72 |
+
* {
|
73 |
+
@apply border-border;
|
74 |
+
}
|
75 |
+
body {
|
76 |
+
@apply bg-background text-foreground;
|
77 |
+
}
|
78 |
+
}
|
src/lib/components/ui/badge/badge.svelte
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { type Variant, badgeVariants } from "./index.js";
|
3 |
+
import { cn } from "$lib/utils.js";
|
4 |
+
|
5 |
+
let className: string | undefined | null = undefined;
|
6 |
+
export let href: string | undefined = undefined;
|
7 |
+
export let variant: Variant = "default";
|
8 |
+
export { className as class };
|
9 |
+
</script>
|
10 |
+
|
11 |
+
<svelte:element
|
12 |
+
this={href ? "a" : "span"}
|
13 |
+
{href}
|
14 |
+
class={cn(badgeVariants({ variant, className }))}
|
15 |
+
{...$$restProps}
|
16 |
+
>
|
17 |
+
<slot />
|
18 |
+
</svelte:element>
|
src/lib/components/ui/badge/index.ts
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { type VariantProps, tv } from "tailwind-variants";
|
2 |
+
export { default as Badge } from "./badge.svelte";
|
3 |
+
|
4 |
+
export const badgeVariants = tv({
|
5 |
+
base: "focus:ring-ring 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-offset-2",
|
6 |
+
variants: {
|
7 |
+
variant: {
|
8 |
+
default: "bg-primary text-primary-foreground hover:bg-primary/80 border-transparent",
|
9 |
+
secondary:
|
10 |
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent",
|
11 |
+
destructive:
|
12 |
+
"bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent",
|
13 |
+
outline: "text-foreground",
|
14 |
+
},
|
15 |
+
},
|
16 |
+
defaultVariants: {
|
17 |
+
variant: "default",
|
18 |
+
},
|
19 |
+
});
|
20 |
+
|
21 |
+
export type Variant = VariantProps<typeof badgeVariants>["variant"];
|
src/lib/components/ui/textarea/index.ts
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import Root from "./textarea.svelte";
|
2 |
+
|
3 |
+
type FormTextareaEvent<T extends Event = Event> = T & {
|
4 |
+
currentTarget: EventTarget & HTMLTextAreaElement;
|
5 |
+
};
|
6 |
+
|
7 |
+
type TextareaEvents = {
|
8 |
+
blur: FormTextareaEvent<FocusEvent>;
|
9 |
+
change: FormTextareaEvent<Event>;
|
10 |
+
click: FormTextareaEvent<MouseEvent>;
|
11 |
+
focus: FormTextareaEvent<FocusEvent>;
|
12 |
+
keydown: FormTextareaEvent<KeyboardEvent>;
|
13 |
+
keypress: FormTextareaEvent<KeyboardEvent>;
|
14 |
+
keyup: FormTextareaEvent<KeyboardEvent>;
|
15 |
+
mouseover: FormTextareaEvent<MouseEvent>;
|
16 |
+
mouseenter: FormTextareaEvent<MouseEvent>;
|
17 |
+
mouseleave: FormTextareaEvent<MouseEvent>;
|
18 |
+
paste: FormTextareaEvent<ClipboardEvent>;
|
19 |
+
input: FormTextareaEvent<InputEvent>;
|
20 |
+
};
|
21 |
+
|
22 |
+
export {
|
23 |
+
Root,
|
24 |
+
//
|
25 |
+
Root as Textarea,
|
26 |
+
type TextareaEvents,
|
27 |
+
type FormTextareaEvent,
|
28 |
+
};
|
src/lib/components/ui/textarea/textarea.svelte
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import type { HTMLTextareaAttributes } from "svelte/elements";
|
3 |
+
import type { TextareaEvents } from "./index.js";
|
4 |
+
import { cn } from "$lib/utils.js";
|
5 |
+
|
6 |
+
type $$Props = HTMLTextareaAttributes;
|
7 |
+
type $$Events = TextareaEvents;
|
8 |
+
|
9 |
+
let className: $$Props["class"] = undefined;
|
10 |
+
export let value: $$Props["value"] = undefined;
|
11 |
+
export { className as class };
|
12 |
+
|
13 |
+
// Workaround for https://github.com/sveltejs/svelte/issues/9305
|
14 |
+
// Fixed in Svelte 5, but not backported to 4.x.
|
15 |
+
export let readonly: $$Props["readonly"] = undefined;
|
16 |
+
</script>
|
17 |
+
|
18 |
+
<textarea
|
19 |
+
class={cn(
|
20 |
+
"border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
21 |
+
className
|
22 |
+
)}
|
23 |
+
bind:value
|
24 |
+
{readonly}
|
25 |
+
on:blur
|
26 |
+
on:change
|
27 |
+
on:click
|
28 |
+
on:focus
|
29 |
+
on:keydown
|
30 |
+
on:keypress
|
31 |
+
on:keyup
|
32 |
+
on:mouseover
|
33 |
+
on:mouseenter
|
34 |
+
on:mouseleave
|
35 |
+
on:paste
|
36 |
+
on:input
|
37 |
+
{...$$restProps}
|
38 |
+
></textarea>
|
src/lib/utils.ts
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { type ClassValue, clsx } from "clsx";
|
2 |
+
import { twMerge } from "tailwind-merge";
|
3 |
+
import { cubicOut } from "svelte/easing";
|
4 |
+
import type { TransitionConfig } from "svelte/transition";
|
5 |
+
|
6 |
+
export function cn(...inputs: ClassValue[]) {
|
7 |
+
return twMerge(clsx(inputs));
|
8 |
+
}
|
9 |
+
|
10 |
+
type FlyAndScaleParams = {
|
11 |
+
y?: number;
|
12 |
+
x?: number;
|
13 |
+
start?: number;
|
14 |
+
duration?: number;
|
15 |
+
};
|
16 |
+
|
17 |
+
export const flyAndScale = (
|
18 |
+
node: Element,
|
19 |
+
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
|
20 |
+
): TransitionConfig => {
|
21 |
+
const style = getComputedStyle(node);
|
22 |
+
const transform = style.transform === "none" ? "" : style.transform;
|
23 |
+
|
24 |
+
const scaleConversion = (
|
25 |
+
valueA: number,
|
26 |
+
scaleA: [number, number],
|
27 |
+
scaleB: [number, number]
|
28 |
+
) => {
|
29 |
+
const [minA, maxA] = scaleA;
|
30 |
+
const [minB, maxB] = scaleB;
|
31 |
+
|
32 |
+
const percentage = (valueA - minA) / (maxA - minA);
|
33 |
+
const valueB = percentage * (maxB - minB) + minB;
|
34 |
+
|
35 |
+
return valueB;
|
36 |
+
};
|
37 |
+
|
38 |
+
const styleToString = (
|
39 |
+
style: Record<string, number | string | undefined>
|
40 |
+
): string => {
|
41 |
+
return Object.keys(style).reduce((str, key) => {
|
42 |
+
if (style[key] === undefined) return str;
|
43 |
+
return str + `${key}:${style[key]};`;
|
44 |
+
}, "");
|
45 |
+
};
|
46 |
+
|
47 |
+
return {
|
48 |
+
duration: params.duration ?? 200,
|
49 |
+
delay: 0,
|
50 |
+
css: (t) => {
|
51 |
+
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
|
52 |
+
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
|
53 |
+
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
|
54 |
+
|
55 |
+
return styleToString({
|
56 |
+
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
|
57 |
+
opacity: t
|
58 |
+
});
|
59 |
+
},
|
60 |
+
easing: cubicOut
|
61 |
+
};
|
62 |
+
};
|
src/routes/+layout.svelte
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
<script>import "../app.css";</script><slot></slot>
|
src/routes/+page.svelte
CHANGED
@@ -1,2 +1,98 @@
|
|
1 |
-
<
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import Textarea from "@/lib/components/ui/textarea/textarea.svelte";
|
3 |
+
import Badge from "@/lib/components/ui/badge/badge.svelte";
|
4 |
+
import * as webllm from "@mlc-ai/web-llm";
|
5 |
+
import { onMount } from 'svelte';
|
6 |
+
|
7 |
+
let engine: webllm.MLCEngineInterface;
|
8 |
+
let isLoading = false;
|
9 |
+
let loadingStatus = '';
|
10 |
+
let inputText = '';
|
11 |
+
let outputText = '';
|
12 |
+
let error = '';
|
13 |
+
let completionSpeed: number | null = null;
|
14 |
+
let selectedModel = "SmolLM-360M-Instruct-q4f16_1-MLC";
|
15 |
+
let isGenerating = false;
|
16 |
+
|
17 |
+
async function loadWebLLM() {
|
18 |
+
isLoading = true;
|
19 |
+
error = '';
|
20 |
+
const initProgressCallback = (report: webllm.InitProgressReport) => {
|
21 |
+
loadingStatus = report.text;
|
22 |
+
};
|
23 |
+
|
24 |
+
const appConfig: webllm.AppConfig = {
|
25 |
+
model_list: [{
|
26 |
+
model: `https://huggingface.co/mlc-ai/${selectedModel}`,
|
27 |
+
model_id: selectedModel,
|
28 |
+
model_lib: `${webllm.modelLibURLPrefix}${webllm.modelVersion}/SmolLM-360M-Instruct-q4f16_1-ctx2k_cs1k-webgpu.wasm`,
|
29 |
+
overrides: { context_window_size: 2048 },
|
30 |
+
}],
|
31 |
+
};
|
32 |
+
|
33 |
+
try {
|
34 |
+
engine = await webllm.CreateMLCEngine(selectedModel, {
|
35 |
+
appConfig,
|
36 |
+
initProgressCallback,
|
37 |
+
logLevel: "INFO",
|
38 |
+
});
|
39 |
+
} catch (err) {
|
40 |
+
error = `Failed to load the model: ${(err as Error).message}`;
|
41 |
+
} finally {
|
42 |
+
isLoading = false;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
async function generateCompletion() {
|
47 |
+
if (!engine || !inputText.trim() || isGenerating) return;
|
48 |
+
|
49 |
+
isGenerating = true;
|
50 |
+
const startTime = performance.now();
|
51 |
+
try {
|
52 |
+
const reply = await engine.completions.create({
|
53 |
+
prompt: inputText,
|
54 |
+
echo: false,
|
55 |
+
max_tokens: 10,
|
56 |
+
});
|
57 |
+
|
58 |
+
outputText = reply.choices[0].text;
|
59 |
+
completionSpeed = Math.round(performance.now() - startTime);
|
60 |
+
error = '';
|
61 |
+
} catch (err) {
|
62 |
+
error = `Error: ${(err as Error).message}`;
|
63 |
+
} finally {
|
64 |
+
isGenerating = false;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
onMount(loadWebLLM);
|
69 |
+
</script>
|
70 |
+
|
71 |
+
<div class="flex my-20 flex-col items-center gap-4 max-w-lg mx-auto">
|
72 |
+
<h1 class="text-center font-mono font-bold text-4xl">Mini Playground</h1>
|
73 |
+
<p class="text-center font-mono text-sm mb-4">Powered by `{selectedModel}`</p>
|
74 |
+
<Textarea
|
75 |
+
bind:value={inputText}
|
76 |
+
on:input={() => {
|
77 |
+
if (!isGenerating) {
|
78 |
+
generateCompletion();
|
79 |
+
}
|
80 |
+
}}
|
81 |
+
disabled={isLoading}
|
82 |
+
class="w-full"
|
83 |
+
placeholder="Enter your prompt here"
|
84 |
+
/>
|
85 |
+
<pre class="text-lg whitespace-pre-wrap">{outputText}</pre>
|
86 |
+
{#if isLoading}
|
87 |
+
<p class="text-sm text-slate-600 text-center">{loadingStatus}</p>
|
88 |
+
{:else if error}
|
89 |
+
<p class="text-sm text-red-600">{error}</p>
|
90 |
+
{:else}
|
91 |
+
<div class="flex gap-2">
|
92 |
+
{#if completionSpeed !== null}
|
93 |
+
<Badge>{completionSpeed}ms</Badge>
|
94 |
+
{/if}
|
95 |
+
<Badge class="bg-green-700">{selectedModel}</Badge>
|
96 |
+
</div>
|
97 |
+
{/if}
|
98 |
+
</div>
|
svelte.config.js
CHANGED
@@ -11,7 +11,10 @@ const config = {
|
|
11 |
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
12 |
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
14 |
-
adapter: adapter()
|
|
|
|
|
|
|
15 |
}
|
16 |
};
|
17 |
|
|
|
11 |
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
12 |
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
13 |
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
14 |
+
adapter: adapter(),
|
15 |
+
alias: {
|
16 |
+
"@/*": "./src/*",
|
17 |
+
},
|
18 |
}
|
19 |
};
|
20 |
|
tailwind.config.ts
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { fontFamily } from "tailwindcss/defaultTheme";
|
2 |
+
import type { Config } from "tailwindcss";
|
3 |
+
|
4 |
+
const config: Config = {
|
5 |
+
darkMode: ["class"],
|
6 |
+
content: ["./src/**/*.{html,js,svelte,ts}"],
|
7 |
+
safelist: ["dark"],
|
8 |
+
theme: {
|
9 |
+
container: {
|
10 |
+
center: true,
|
11 |
+
padding: "2rem",
|
12 |
+
screens: {
|
13 |
+
"2xl": "1400px"
|
14 |
+
}
|
15 |
+
},
|
16 |
+
extend: {
|
17 |
+
colors: {
|
18 |
+
border: "hsl(var(--border) / <alpha-value>)",
|
19 |
+
input: "hsl(var(--input) / <alpha-value>)",
|
20 |
+
ring: "hsl(var(--ring) / <alpha-value>)",
|
21 |
+
background: "hsl(var(--background) / <alpha-value>)",
|
22 |
+
foreground: "hsl(var(--foreground) / <alpha-value>)",
|
23 |
+
primary: {
|
24 |
+
DEFAULT: "hsl(var(--primary) / <alpha-value>)",
|
25 |
+
foreground: "hsl(var(--primary-foreground) / <alpha-value>)"
|
26 |
+
},
|
27 |
+
secondary: {
|
28 |
+
DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
|
29 |
+
foreground: "hsl(var(--secondary-foreground) / <alpha-value>)"
|
30 |
+
},
|
31 |
+
destructive: {
|
32 |
+
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
33 |
+
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)"
|
34 |
+
},
|
35 |
+
muted: {
|
36 |
+
DEFAULT: "hsl(var(--muted) / <alpha-value>)",
|
37 |
+
foreground: "hsl(var(--muted-foreground) / <alpha-value>)"
|
38 |
+
},
|
39 |
+
accent: {
|
40 |
+
DEFAULT: "hsl(var(--accent) / <alpha-value>)",
|
41 |
+
foreground: "hsl(var(--accent-foreground) / <alpha-value>)"
|
42 |
+
},
|
43 |
+
popover: {
|
44 |
+
DEFAULT: "hsl(var(--popover) / <alpha-value>)",
|
45 |
+
foreground: "hsl(var(--popover-foreground) / <alpha-value>)"
|
46 |
+
},
|
47 |
+
card: {
|
48 |
+
DEFAULT: "hsl(var(--card) / <alpha-value>)",
|
49 |
+
foreground: "hsl(var(--card-foreground) / <alpha-value>)"
|
50 |
+
}
|
51 |
+
},
|
52 |
+
borderRadius: {
|
53 |
+
lg: "var(--radius)",
|
54 |
+
md: "calc(var(--radius) - 2px)",
|
55 |
+
sm: "calc(var(--radius) - 4px)"
|
56 |
+
},
|
57 |
+
fontFamily: {
|
58 |
+
sans: [...fontFamily.sans]
|
59 |
+
}
|
60 |
+
}
|
61 |
+
},
|
62 |
+
};
|
63 |
+
|
64 |
+
export default config;
|