mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-11 09:27:30 +00:00
feat: add darkmode toggle for website
This commit is contained in:
parent
1f3f917f7e
commit
e529d5e12f
248
package-lock.json
generated
Normal file
248
package-lock.json
generated
Normal 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
6
package.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"svelte-media-queries": "^1.6.2",
|
||||
"svelte-persisted-store": "^0.9.1"
|
||||
}
|
||||
}
|
||||
1
website/.gitignore
vendored
1
website/.gitignore
vendored
@ -8,3 +8,4 @@ node_modules
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
.netlify
|
||||
|
||||
3
website/netlify.toml
Normal file
3
website/netlify.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[build]
|
||||
command = "npm run build"
|
||||
publish = "build"
|
||||
23
website/package-lock.json
generated
23
website/package-lock.json
generated
@ -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": {
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
32
website/src/components/navbar/darkmode-toggle.svelte
Normal file
32
website/src/components/navbar/darkmode-toggle.svelte
Normal 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>
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
106
website/src/lib/persisted-store.ts
Normal file
106
website/src/lib/persisted-store.ts
Normal 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];
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}')
|
||||
|
||||
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user