feat: add darkmode toggle for website

This commit is contained in:
Kingkor Roy Tirtho 2024-02-09 23:02:56 +06:00
parent 1f3f917f7e
commit e529d5e12f
15 changed files with 456 additions and 32 deletions

248
package-lock.json generated Normal file
View File

@ -0,0 +1,248 @@
{
"name": "spotube",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"svelte-media-queries": "^1.6.2",
"svelte-persisted-store": "^0.9.1"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
"integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
"peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"peer": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"peer": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"peer": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"peer": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
"peer": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"peer": true
},
"node_modules/acorn": {
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/aria-query": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
},
"node_modules/axobject-query": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
"peer": true,
"dependencies": {
"dequal": "^2.0.3"
}
},
"node_modules/code-red": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
"acorn": "^8.10.0",
"estree-walker": "^3.0.3",
"periscopic": "^3.1.0"
}
},
"node_modules/css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"peer": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"peer": true,
"engines": {
"node": ">=6"
}
},
"node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"peer": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/is-reference": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
"peer": true,
"dependencies": {
"@types/estree": "*"
}
},
"node_modules/locate-character": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
"peer": true
},
"node_modules/magic-string": {
"version": "0.30.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
"integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
}
},
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"peer": true
},
"node_modules/periscopic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
"peer": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
"is-reference": "^3.0.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/svelte": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.10.tgz",
"integrity": "sha512-Ep06yCaCdgG1Mafb/Rx8sJ1QS3RW2I2BxGp2Ui9LBHSZ2/tO/aGLc5WqPjgiAP6KAnLJGaIr/zzwQlOo1b8MxA==",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18",
"@types/estree": "^1.0.1",
"acorn": "^8.9.0",
"aria-query": "^5.3.0",
"axobject-query": "^4.0.0",
"code-red": "^1.0.3",
"css-tree": "^2.3.1",
"estree-walker": "^3.0.3",
"is-reference": "^3.0.1",
"locate-character": "^3.0.0",
"magic-string": "^0.30.4",
"periscopic": "^3.1.0"
},
"engines": {
"node": ">=16"
}
},
"node_modules/svelte-media-queries": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/svelte-media-queries/-/svelte-media-queries-1.6.2.tgz",
"integrity": "sha512-SMz6od/vIeZEGlc4P0HKJK4G0fZotuwFhCSpBQaPqh75h6sL6sNf+4+IjbegFKXbP7b+SOfyzVOIMXTr8jynkA=="
},
"node_modules/svelte-persisted-store": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/svelte-persisted-store/-/svelte-persisted-store-0.9.1.tgz",
"integrity": "sha512-l00I8Dy5GKjdjnE9ZcMeXLLMhvgV0+Iuru0Mue7eU3tB+pHBwBB2RVVqw2uC2Hbrf7cyZtsV/lnPKhjTHIWphQ==",
"engines": {
"node": ">=0.14"
},
"peerDependencies": {
"svelte": "^3.48.0 || ^4.0.0 || ^5.0.0-next.0"
}
}
}
}

6
package.json Normal file
View File

@ -0,0 +1,6 @@
{
"dependencies": {
"svelte-media-queries": "^1.6.2",
"svelte-persisted-store": "^0.9.1"
}
}

1
website/.gitignore vendored
View File

@ -8,3 +8,4 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.netlify

3
website/netlify.toml Normal file
View File

@ -0,0 +1,3 @@
[build]
command = "npm run build"
publish = "build"

View File

@ -24,7 +24,7 @@
"@playwright/test": "^1.28.1",
"@skeletonlabs/skeleton": "2.8.0",
"@skeletonlabs/tw-plugin": "0.3.1",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/adapter-netlify": "^4.1.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tailwindcss/typography": "0.5.10",
@ -626,6 +626,12 @@
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true
},
"node_modules/@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
"dev": true
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@ -1112,13 +1118,18 @@
"tailwindcss": ">=3.0.0"
}
},
"node_modules/@sveltejs/adapter-static": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.1.tgz",
"integrity": "sha512-6lMvf7xYEJ+oGeR5L8DFJJrowkefTK6ZgA4JiMqoClMkKq0s6yvsd3FZfCFvX1fQ0tpCD7fkuRVHsnUVgsHyNg==",
"node_modules/@sveltejs/adapter-netlify": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-netlify/-/adapter-netlify-4.1.0.tgz",
"integrity": "sha512-TGv14O/9xumJv/q9G57ZCzl+LUWHZ9dDleugT5QQD87zJE3Y98AKyU5Z7c7WlBTjKYKEQEeOxjnSdOpMRuhd6g==",
"dev": true,
"dependencies": {
"@iarna/toml": "^2.2.5",
"esbuild": "^0.19.11",
"set-cookie-parser": "^2.6.0"
},
"peerDependencies": {
"@sveltejs/kit": "^2.0.0"
"@sveltejs/kit": "^2.4.0"
}
},
"node_modules/@sveltejs/kit": {

View File

@ -2,6 +2,7 @@
"name": "website",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
@ -16,7 +17,7 @@
"@playwright/test": "^1.28.1",
"@skeletonlabs/skeleton": "2.8.0",
"@skeletonlabs/tw-plugin": "0.3.1",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/adapter-netlify": "^4.1.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@tailwindcss/typography": "0.5.10",
@ -40,7 +41,6 @@
"vite": "^5.0.3",
"vite-plugin-tailwind-purgecss": "0.2.0"
},
"type": "module",
"dependencies": {
"@floating-ui/dom": "1.6.1",
"@fortawesome/free-brands-svg-icons": "^6.5.1",
@ -54,4 +54,4 @@
"svelte-fa": "^4.0.2",
"svelte-markdown": "^0.4.1"
}
}
}

View File

@ -0,0 +1,32 @@
<script lang="ts">
import { SlideToggle } from '@skeletonlabs/skeleton';
import { persisted } from '$lib/persisted-store';
import { browser } from '$app/environment';
export const isDark = persisted('dark-mode', false);
$: {
if (browser) {
$isDark
? document.documentElement.classList.add('dark')
: document.documentElement.classList.remove('dark');
}
}
export let label: string | undefined;
</script>
<div class="inline-flex gap-2">
{#if label}
<label class="ps-4">{label}</label>
{/if}
<SlideToggle
active="bg-primary-backdrop-token"
size="sm"
name="dark-mode"
checked={$isDark}
on:change={() => {
isDark.update((prev) => !prev);
}}
/>
</div>

View File

@ -2,9 +2,10 @@
import { page } from '$app/stores';
import { routes } from '$lib';
import { faGithub } from '@fortawesome/free-brands-svg-icons';
import { getDrawerStore } from '@skeletonlabs/skeleton';
import { SlideToggle, getDrawerStore } from '@skeletonlabs/skeleton';
import { Menu } from 'lucide-svelte';
import Fa from 'svelte-fa';
import DarkmodeToggle from './darkmode-toggle.svelte';
const drawerStore = getDrawerStore();
</script>
@ -35,7 +36,7 @@
</button>
</a>
</div>
<nav class="hidden md:flex gap-3">
<nav class="hidden md:flex gap-3 items-center">
{#each Object.entries(routes) as route}
<a href={route[0]}>
<button
@ -48,5 +49,6 @@
</button>
</a>
{/each}
<DarkmodeToggle />
</nav>
</header>

View File

@ -4,6 +4,7 @@
import { routes } from '$lib';
import { ListBox, ListBoxItem, getDrawerStore } from '@skeletonlabs/skeleton';
import { X } from 'lucide-svelte';
import DarkmodeToggle from '../navbar/darkmode-toggle.svelte';
let currentRoute: string = $page.url.pathname;
const drawerStore = getDrawerStore();
@ -31,5 +32,6 @@
</div>
</ListBoxItem>
{/each}
<DarkmodeToggle label="Theme" />
</ListBox>
</nav>

View File

@ -0,0 +1,106 @@
import { writable as internal, type Writable } from 'svelte/store';
declare type Updater<T> = (value: T) => T;
declare type StoreDict<T> = { [key: string]: Writable<T> };
/* eslint-disable @typescript-eslint/no-explicit-any */
interface Stores {
local: StoreDict<any>;
session: StoreDict<any>;
}
const stores: Stores = {
local: {},
session: {}
};
export interface Serializer<T> {
parse(text: string): T;
stringify(object: T): string;
}
export type StorageType = 'local' | 'session';
export interface Options<T> {
serializer?: Serializer<T>;
storage?: StorageType;
syncTabs?: boolean;
onError?: (e: unknown) => void;
}
function getStorage(type: StorageType) {
return type === 'local' ? localStorage : sessionStorage;
}
/** @deprecated `writable()` has been renamed to `persisted()` */
export function writable<T>(key: string, initialValue: T, options?: Options<T>): Writable<T> {
console.warn(
"writable() has been deprecated. Please use persisted() instead.\n\nchange:\n\nimport { writable } from 'svelte-persisted-store'\n\nto:\n\nimport { persisted } from 'svelte-persisted-store'"
);
return persisted<T>(key, initialValue, options);
}
export function persisted<T>(key: string, initialValue: T, options?: Options<T>): Writable<T> {
const serializer = options?.serializer ?? JSON;
const storageType = options?.storage ?? 'local';
const syncTabs = options?.syncTabs ?? true;
const onError =
options?.onError ??
((e) =>
console.error(`Error when writing value from persisted store "${key}" to ${storageType}`, e));
const browser = typeof window !== 'undefined' && typeof document !== 'undefined';
const storage = browser ? getStorage(storageType) : null;
function updateStorage(key: string, value: T) {
try {
storage?.setItem(key, serializer.stringify(value));
} catch (e) {
onError(e);
}
}
function maybeLoadInitial(): T {
const json = storage?.getItem(key);
if (json) {
return <T>serializer.parse(json);
}
return initialValue;
}
if (!stores[storageType][key]) {
const initial = maybeLoadInitial();
const store = internal(initial, (set) => {
if (browser && storageType == 'local' && syncTabs) {
const handleStorage = (event: StorageEvent) => {
if (event.key === key) set(event.newValue ? serializer.parse(event.newValue) : null);
};
window.addEventListener('storage', handleStorage);
return () => window.removeEventListener('storage', handleStorage);
}
});
const { subscribe, set } = store;
stores[storageType][key] = {
set(value: T) {
set(value);
updateStorage(key, value);
},
update(callback: Updater<T>) {
return store.update((last) => {
const value = callback(last);
updateStorage(key, value);
return value;
});
},
subscribe
};
}
return stores[storageType][key];
}

View File

@ -41,7 +41,7 @@
<slot />
<br /><br />
</main>
<footer class="w-full bg-surface-200/40 p-4 flex justify-between">
<footer class="w-full bg-tertiary-backdrop-token p-4 flex justify-between">
<div>
<h3 class="h3">Spotube</h3>
<p>

View File

@ -14,6 +14,16 @@
export let data: PageData;
</script>
<svelte:head>
<title>Spotube</title>
<meta name="description" content="An Open Source Spotify Client for every platform" />
<meta name="keywords" content="spotify, client, open source, music, streaming" />
<meta name="author" content="KRTirtho" />
<meta name="robots" content="index, follow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#1DB954" />
</svelte:head>
<section class="flex flex-col gap-4 ps-4 pt-16 md:ps-24 md:pt-24">
<div>
<h1 class="h1">Spotube</h1>

View File

@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-static';
import adapter from '@sveltejs/adapter-netlify';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
import { mdsvex } from 'mdsvex';
@ -22,7 +22,10 @@ const config = {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
adapter: adapter({
edge: false,
split: false
})
}
};
export default config;

View File

@ -4,7 +4,7 @@ import typography from '@tailwindcss/typography';
import { skeleton } from '@skeletonlabs/tw-plugin';
export default {
darkMode: 'media',
darkMode: 'class',
content: [
'./src/**/*.{html,js,svelte,ts}',
join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')

View File

@ -1,18 +1,18 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}