diff --git a/.github/pages/index.html b/.github/pages/index.html
new file mode 100644
index 0000000..9167de1
--- /dev/null
+++ b/.github/pages/index.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ ThemeKit Configurator
+
+
+
+
+
+
+
+
diff --git a/.github/pages/package-lock.json b/.github/pages/package-lock.json
new file mode 100644
index 0000000..c19606c
--- /dev/null
+++ b/.github/pages/package-lock.json
@@ -0,0 +1,1318 @@
+{
+ "name": "themekit-configurator",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "themekit-configurator",
+ "version": "0.0.0",
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.58.0.tgz",
+ "integrity": "sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.58.0.tgz",
+ "integrity": "sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.58.0.tgz",
+ "integrity": "sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.58.0.tgz",
+ "integrity": "sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.58.0.tgz",
+ "integrity": "sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.58.0.tgz",
+ "integrity": "sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.58.0.tgz",
+ "integrity": "sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.58.0.tgz",
+ "integrity": "sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.58.0.tgz",
+ "integrity": "sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.58.0.tgz",
+ "integrity": "sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.58.0.tgz",
+ "integrity": "sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.58.0.tgz",
+ "integrity": "sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.58.0.tgz",
+ "integrity": "sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.58.0.tgz",
+ "integrity": "sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.58.0.tgz",
+ "integrity": "sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.58.0.tgz",
+ "integrity": "sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.58.0.tgz",
+ "integrity": "sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.58.0.tgz",
+ "integrity": "sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.58.0.tgz",
+ "integrity": "sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.58.0.tgz",
+ "integrity": "sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.58.0.tgz",
+ "integrity": "sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.58.0.tgz",
+ "integrity": "sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.58.0.tgz",
+ "integrity": "sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.58.0.tgz",
+ "integrity": "sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.58.0.tgz",
+ "integrity": "sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sveltejs/acorn-typescript": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
+ "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^8.9.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz",
+ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
+ "dev": true,
+ "dependencies": {
+ "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
+ "debug": "^4.4.1",
+ "deepmerge": "^4.3.1",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.17",
+ "vitefu": "^1.0.6"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
+ "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.7"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "dev": true
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/devalue": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz",
+ "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/esm-env": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
+ "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
+ "dev": true
+ },
+ "node_modules/esrap": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz",
+ "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
+ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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==",
+ "dev": true
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.58.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.58.0.tgz",
+ "integrity": "sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.58.0",
+ "@rollup/rollup-android-arm64": "4.58.0",
+ "@rollup/rollup-darwin-arm64": "4.58.0",
+ "@rollup/rollup-darwin-x64": "4.58.0",
+ "@rollup/rollup-freebsd-arm64": "4.58.0",
+ "@rollup/rollup-freebsd-x64": "4.58.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.58.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.58.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.58.0",
+ "@rollup/rollup-linux-arm64-musl": "4.58.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.58.0",
+ "@rollup/rollup-linux-loong64-musl": "4.58.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.58.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.58.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.58.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.58.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.58.0",
+ "@rollup/rollup-linux-x64-gnu": "4.58.0",
+ "@rollup/rollup-linux-x64-musl": "4.58.0",
+ "@rollup/rollup-openbsd-x64": "4.58.0",
+ "@rollup/rollup-openharmony-arm64": "4.58.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.58.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.58.0",
+ "@rollup/rollup-win32-x64-gnu": "4.58.0",
+ "@rollup/rollup-win32-x64-msvc": "4.58.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "5.53.0",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.0.tgz",
+ "integrity": "sha512-7dhHkSamGS2vtoBmIW2hRab+gl5Z60alEHZB4910ePqqJNxAWnDAxsofVmlZ2tREmWyHNE+A1nCKwICAquoD2A==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@sveltejs/acorn-typescript": "^1.0.5",
+ "@types/estree": "^1.0.5",
+ "@types/trusted-types": "^2.0.7",
+ "acorn": "^8.12.1",
+ "aria-query": "^5.3.1",
+ "axobject-query": "^4.1.0",
+ "clsx": "^2.1.1",
+ "devalue": "^5.6.3",
+ "esm-env": "^1.2.1",
+ "esrap": "^2.2.2",
+ "is-reference": "^3.0.3",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.11",
+ "zimmerframe": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
+ "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==",
+ "dev": true,
+ "workspaces": [
+ "tests/deps/*",
+ "tests/projects/*",
+ "tests/projects/workspace/packages/*"
+ ],
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/zimmerframe": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
+ "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/.github/pages/package.json b/.github/pages/package.json
new file mode 100644
index 0000000..e93329f
--- /dev/null
+++ b/.github/pages/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "themekit-configurator",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+}
diff --git a/.github/pages/src/App.svelte b/.github/pages/src/App.svelte
new file mode 100644
index 0000000..3f71d7b
--- /dev/null
+++ b/.github/pages/src/App.svelte
@@ -0,0 +1,72 @@
+
+
+
+
+
+ {#if loadError}
+
+
Failed to load schema: {loadError}
+
Make sure you have internet access and the schema is available.
+
+ {:else if !schema}
+ Loading schema...
+ {:else}
+
+ {/if}
+
diff --git a/.github/pages/src/components/CategorySection.svelte b/.github/pages/src/components/CategorySection.svelte
new file mode 100644
index 0000000..6a17319
--- /dev/null
+++ b/.github/pages/src/components/CategorySection.svelte
@@ -0,0 +1,27 @@
+
+
+
+
+ {#if enabled}
+
+ {/if}
+
diff --git a/.github/pages/src/components/ConfigSection.svelte b/.github/pages/src/components/ConfigSection.svelte
new file mode 100644
index 0000000..2adf292
--- /dev/null
+++ b/.github/pages/src/components/ConfigSection.svelte
@@ -0,0 +1,45 @@
+
+
+{#if properties.length > 0}
+
+{/if}
diff --git a/.github/pages/src/components/JsonEditor.svelte b/.github/pages/src/components/JsonEditor.svelte
new file mode 100644
index 0000000..8e6a305
--- /dev/null
+++ b/.github/pages/src/components/JsonEditor.svelte
@@ -0,0 +1,77 @@
+
+
+
+
+
+ {#if error}
+ {error}
+ {/if}
+
diff --git a/.github/pages/src/components/StylesSection.svelte b/.github/pages/src/components/StylesSection.svelte
new file mode 100644
index 0000000..ebe31c2
--- /dev/null
+++ b/.github/pages/src/components/StylesSection.svelte
@@ -0,0 +1,12 @@
+
+
+
+ Styles
+ {#each categories as category (category.key)}
+
+ {/each}
+
diff --git a/.github/pages/src/components/TokenField.svelte b/.github/pages/src/components/TokenField.svelte
new file mode 100644
index 0000000..02f0624
--- /dev/null
+++ b/.github/pages/src/components/TokenField.svelte
@@ -0,0 +1,44 @@
+
+
+
diff --git a/.github/pages/src/components/TokenPopover.svelte b/.github/pages/src/components/TokenPopover.svelte
new file mode 100644
index 0000000..c67a0ea
--- /dev/null
+++ b/.github/pages/src/components/TokenPopover.svelte
@@ -0,0 +1,46 @@
+
+
+
+
+
+ {#each tokenProperties as prop}
+
+
+ handleInput(prop.key, e.target.value)}
+ />
+
+ {/each}
+
diff --git a/.github/pages/src/components/TokenTag.svelte b/.github/pages/src/components/TokenTag.svelte
new file mode 100644
index 0000000..e88133a
--- /dev/null
+++ b/.github/pages/src/components/TokenTag.svelte
@@ -0,0 +1,39 @@
+
+
+
+ {token.name}
+
+
+ {#if showPopover}
+ showPopover = false}
+ />
+ {/if}
+
diff --git a/.github/pages/src/lib/schema.js b/.github/pages/src/lib/schema.js
new file mode 100644
index 0000000..9457ad9
--- /dev/null
+++ b/.github/pages/src/lib/schema.js
@@ -0,0 +1,57 @@
+const SCHEMA_URL =
+ 'https://raw.githubusercontent.com/rozd/theme-kit/main/theme.schema.json';
+
+/**
+ * Fetch and parse theme.schema.json into a UI-friendly structure.
+ *
+ * Returns:
+ * configProperties β array of { key, type, description, required }
+ * styleCategories β array of { key, description }
+ * tokenProperties β array of { key, type, description } (from tokenEntry object, excluding "name")
+ */
+export async function loadSchema() {
+ const res = await fetch(SCHEMA_URL);
+ if (!res.ok) throw new Error(`Failed to fetch schema: ${res.status}`);
+ const schema = await res.json();
+
+ const configProperties = parseConfigProperties(schema);
+ const styleCategories = parseStyleCategories(schema);
+ const tokenProperties = parseTokenProperties(schema);
+
+ return { configProperties, styleCategories, tokenProperties };
+}
+
+function parseConfigProperties(schema) {
+ const configSchema = schema.properties?.config;
+ if (!configSchema?.properties) return [];
+ const required = new Set(configSchema.required ?? []);
+ return Object.entries(configSchema.properties).map(([key, def]) => ({
+ key,
+ type: def.type ?? 'string',
+ description: def.description ?? '',
+ required: required.has(key),
+ }));
+}
+
+function parseStyleCategories(schema) {
+ const stylesSchema = schema.properties?.styles;
+ if (!stylesSchema?.properties) return [];
+ return Object.entries(stylesSchema.properties).map(([key, def]) => ({
+ key,
+ description: def.description ?? '',
+ }));
+}
+
+function parseTokenProperties(schema) {
+ const tokenDef = schema.$defs?.tokenEntry;
+ if (!tokenDef?.oneOf) return [];
+ const objectVariant = tokenDef.oneOf.find((v) => v.type === 'object');
+ if (!objectVariant?.properties) return [];
+ return Object.entries(objectVariant.properties)
+ .filter(([key]) => key !== 'name')
+ .map(([key, def]) => ({
+ key,
+ type: def.type ?? 'string',
+ description: def.description ?? '',
+ }));
+}
diff --git a/.github/pages/src/lib/state.svelte.js b/.github/pages/src/lib/state.svelte.js
new file mode 100644
index 0000000..51276d3
--- /dev/null
+++ b/.github/pages/src/lib/state.svelte.js
@@ -0,0 +1,168 @@
+import { serializeToken, normalizeToken } from './utils.js';
+
+/** Internal state for the theme configuration. */
+let styles = $state({});
+let config = $state({ outputPath: '' });
+let enabledCategories = $state(new Set());
+
+/** Whether the JSON editor is currently focused (pauses UIβJSON sync). */
+let jsonEditorFocused = $state(false);
+
+/**
+ * Derived JSON string from the current state.
+ * Only recomputes when styles/config/enabledCategories change.
+ */
+const jsonOutput = $derived.by(() => {
+ const obj = {};
+
+ // Build styles β only include enabled categories
+ const stylesObj = {};
+ for (const cat of enabledCategories) {
+ const tokens = styles[cat] ?? [];
+ stylesObj[cat] = tokens.map(serializeToken);
+ }
+ if (Object.keys(stylesObj).length > 0) {
+ obj.styles = stylesObj;
+ }
+
+ // Build config β only include if it has properties
+ if (Object.keys(config).length > 0) {
+ obj.config = { ...config };
+ }
+
+ return JSON.stringify(obj, null, 2);
+});
+
+/**
+ * Get the current JSON output string.
+ */
+export function getJsonOutput() {
+ return jsonOutput;
+}
+
+/**
+ * Get whether the JSON editor is focused.
+ */
+export function isJsonEditorFocused() {
+ return jsonEditorFocused;
+}
+
+/**
+ * Set whether the JSON editor is focused.
+ */
+export function setJsonEditorFocused(focused) {
+ jsonEditorFocused = focused;
+}
+
+/**
+ * Get the current enabled categories set.
+ */
+export function getEnabledCategories() {
+ return enabledCategories;
+}
+
+/**
+ * Get the tokens for a given category.
+ */
+export function getTokens(category) {
+ return styles[category] ?? [];
+}
+
+/**
+ * Get a config property value.
+ */
+export function getConfig(key) {
+ return config[key];
+}
+
+/**
+ * Toggle a style category on or off.
+ */
+export function toggleCategory(category, enabled) {
+ if (enabled) {
+ enabledCategories.add(category);
+ if (!styles[category]) styles[category] = [];
+ } else {
+ enabledCategories.delete(category);
+ }
+ // Force reactivity on the Set by reassigning
+ enabledCategories = new Set(enabledCategories);
+}
+
+/**
+ * Check if a category is enabled.
+ */
+export function isCategoryEnabled(category) {
+ return enabledCategories.has(category);
+}
+
+/**
+ * Add a token to a category.
+ */
+export function addToken(category, name) {
+ if (!styles[category]) styles[category] = [];
+ styles[category] = [...styles[category], { name, style: name }];
+}
+
+/**
+ * Remove a token from a category by index.
+ */
+export function removeToken(category, index) {
+ styles[category] = styles[category].filter((_, i) => i !== index);
+}
+
+/**
+ * Update a token property in a category.
+ */
+export function updateToken(category, index, key, value) {
+ styles[category] = styles[category].map((t, i) =>
+ i === index ? { ...t, [key]: value } : t
+ );
+}
+
+/**
+ * Set a config property.
+ */
+export function setConfig(key, value) {
+ config = { ...config, [key]: value };
+}
+
+/**
+ * Update state from a JSON string. Returns an error message if invalid.
+ */
+export function updateFromJson(jsonString) {
+ let parsed;
+ try {
+ parsed = JSON.parse(jsonString);
+ } catch {
+ return 'Invalid JSON';
+ }
+
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
+ return 'JSON must be an object';
+ }
+
+ // Update styles
+ const newStyles = {};
+ const newEnabled = new Set();
+
+ if (parsed.styles && typeof parsed.styles === 'object') {
+ for (const [cat, tokens] of Object.entries(parsed.styles)) {
+ if (!Array.isArray(tokens)) continue;
+ newStyles[cat] = tokens.map(normalizeToken);
+ newEnabled.add(cat);
+ }
+ }
+
+ styles = newStyles;
+ enabledCategories = newEnabled;
+
+ // Update config
+ if (parsed.config && typeof parsed.config === 'object') {
+ config = { ...parsed.config };
+ } else {
+ config = {};
+ }
+
+ return null;
+}
diff --git a/.github/pages/src/lib/utils.js b/.github/pages/src/lib/utils.js
new file mode 100644
index 0000000..0054cfa
--- /dev/null
+++ b/.github/pages/src/lib/utils.js
@@ -0,0 +1,25 @@
+/**
+ * Convert a camelCase key to title-cased words.
+ * "meshGradients" β "Mesh Gradients"
+ */
+export function camelToWords(str) {
+ return str
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
+ .replace(/^./, (c) => c.toUpperCase());
+}
+
+/**
+ * Serialize a token for JSON output.
+ * If name === style, use the compact string form; otherwise use the object form.
+ */
+export function serializeToken(token) {
+ return token.name === token.style ? token.name : { name: token.name, style: token.style };
+}
+
+/**
+ * Normalize a raw token value (from JSON) into the internal { name, style } form.
+ */
+export function normalizeToken(raw) {
+ if (typeof raw === 'string') return { name: raw, style: raw };
+ return { name: raw.name, style: raw.style ?? raw.name };
+}
diff --git a/.github/pages/src/main.js b/.github/pages/src/main.js
new file mode 100644
index 0000000..eb88e12
--- /dev/null
+++ b/.github/pages/src/main.js
@@ -0,0 +1,7 @@
+import './styles/app.css';
+import App from './App.svelte';
+import { mount } from 'svelte';
+
+const app = mount(App, { target: document.getElementById('app') });
+
+export default app;
diff --git a/.github/pages/src/styles/app.css b/.github/pages/src/styles/app.css
new file mode 100644
index 0000000..66f1276
--- /dev/null
+++ b/.github/pages/src/styles/app.css
@@ -0,0 +1,584 @@
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+}
+
+:root {
+ color-scheme: light;
+ --color-bg: #fafafa;
+ --color-surface: #ffffff;
+ --color-border: #e2e2e2;
+ --color-border-focus: #888;
+ --color-text: #1a1a1a;
+ --color-text-muted: #666;
+ --color-primary: #2563eb;
+ --color-primary-light: #eff6ff;
+ --color-danger: #dc2626;
+ --color-danger-light: #fef2f2;
+ --color-tag-bg: #f0f0f0;
+ --color-tag-override: #e8f0fe;
+ --radius: 6px;
+ --radius-lg: 10px;
+ --font-mono: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root:not([data-theme='light']) {
+ color-scheme: dark;
+ --color-bg: #161616;
+ --color-surface: #1e1e1e;
+ --color-border: #333;
+ --color-border-focus: #666;
+ --color-text: #e4e4e4;
+ --color-text-muted: #999;
+ --color-primary: #5b9aff;
+ --color-primary-light: #1a2744;
+ --color-danger: #f87171;
+ --color-danger-light: #3b1616;
+ --color-tag-bg: #2a2a2a;
+ --color-tag-override: #1e2d4a;
+ }
+}
+
+[data-theme='dark'] {
+ color-scheme: dark;
+ --color-bg: #161616;
+ --color-surface: #1e1e1e;
+ --color-border: #333;
+ --color-border-focus: #666;
+ --color-text: #e4e4e4;
+ --color-text-muted: #999;
+ --color-primary: #5b9aff;
+ --color-primary-light: #1a2744;
+ --color-danger: #f87171;
+ --color-danger-light: #3b1616;
+ --color-tag-bg: #2a2a2a;
+ --color-tag-override: #1e2d4a;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
+ background: var(--color-bg);
+ color: var(--color-text);
+ line-height: 1.5;
+ -webkit-font-smoothing: antialiased;
+}
+
+/* App layout */
+
+.app {
+ max-width: 1100px;
+ margin: 0 auto;
+ padding: 2rem 1.5rem;
+}
+
+.app-header {
+ margin-bottom: 2rem;
+}
+
+.app-header h1 {
+ font-size: 1.5rem;
+ font-weight: 700;
+ letter-spacing: -0.02em;
+}
+
+.subtitle {
+ color: var(--color-text-muted);
+ font-size: 0.9rem;
+ margin-top: 0.25rem;
+}
+
+.subtitle code {
+ font-family: var(--font-mono);
+ background: var(--color-tag-bg);
+ padding: 0.1em 0.35em;
+ border-radius: 3px;
+ font-size: 0.85em;
+}
+
+.app-layout {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+ align-items: stretch;
+}
+
+@media (max-width: 768px) {
+ .app-layout {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* Panels */
+
+.editor-panel,
+.json-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+}
+
+/* Sections */
+
+section {
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ padding: 1.25rem;
+}
+
+section h2 {
+ font-size: 0.85rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: var(--color-text-muted);
+ margin-bottom: 1rem;
+}
+
+.section-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 1rem;
+}
+
+.section-header h2 {
+ margin-bottom: 0;
+}
+
+.download-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ background: var(--color-surface);
+ color: var(--color-text-muted);
+ font-size: 0.75rem;
+ padding: 0.3rem 0.6rem;
+ cursor: pointer;
+ transition: border-color 0.15s, color 0.15s;
+}
+
+.download-btn:hover {
+ border-color: var(--color-primary);
+ color: var(--color-primary);
+}
+
+/* Config section */
+
+.config-fields {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.config-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.config-field label {
+ font-size: 0.8rem;
+ font-weight: 500;
+ color: var(--color-text-muted);
+}
+
+.config-field .required {
+ color: var(--color-danger);
+}
+
+.config-field input[type='text'],
+.config-field input[type='number'] {
+ padding: 0.5rem 0.65rem;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ font-size: 0.875rem;
+ font-family: var(--font-mono);
+ background: var(--color-bg);
+ transition: border-color 0.15s;
+}
+
+.config-field input:focus {
+ outline: none;
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 2px var(--color-primary-light);
+}
+
+/* Category section */
+
+.category-section {
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ padding: 0.75rem 1rem;
+ margin-bottom: 0.5rem;
+}
+
+.category-section:last-child {
+ margin-bottom: 0;
+}
+
+.category-section.disabled {
+ opacity: 0.6;
+}
+
+.category-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.category-header h3 {
+ font-size: 0.95rem;
+ font-weight: 600;
+}
+
+/* Toggle switch */
+
+.toggle {
+ position: relative;
+ display: inline-block;
+ width: 36px;
+ height: 20px;
+ cursor: pointer;
+}
+
+.toggle input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+.toggle-slider {
+ position: absolute;
+ inset: 0;
+ background: var(--color-border);
+ border-radius: 20px;
+ transition: background 0.2s;
+}
+
+.toggle-slider::before {
+ content: '';
+ position: absolute;
+ width: 16px;
+ height: 16px;
+ left: 2px;
+ bottom: 2px;
+ background: white;
+ border-radius: 50%;
+ transition: transform 0.2s;
+}
+
+.toggle input:checked + .toggle-slider {
+ background: var(--color-primary);
+}
+
+.toggle input:checked + .toggle-slider::before {
+ transform: translateX(16px);
+}
+
+/* Token field */
+
+.token-field {
+ margin-top: 0.75rem;
+}
+
+.token-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.4rem;
+ align-items: center;
+}
+
+/* Token tag (chip) */
+
+.token-tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.15rem;
+ background: var(--color-tag-bg);
+ border-radius: 100px;
+ padding: 0.2rem 0.15rem;
+ font-size: 0.8rem;
+ position: relative;
+}
+
+.token-tag.has-override {
+ background: var(--color-tag-override);
+}
+
+.tag-name {
+ padding: 0 0.25rem 0 0.5rem;
+ font-family: var(--font-mono);
+ font-size: 0.8rem;
+}
+
+.tag-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-radius: 50%;
+ width: 22px;
+ height: 22px;
+ color: var(--color-text-muted);
+ transition: background 0.15s, color 0.15s;
+}
+
+.tag-btn:hover {
+ background: rgba(0, 0, 0, 0.08);
+ color: var(--color-text);
+}
+
+.remove-btn:hover {
+ background: rgba(0, 0, 0, 0.08);
+ color: var(--color-text);
+}
+
+/* Token add input */
+
+.token-add {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+}
+
+.token-input {
+ border: 1px dashed var(--color-border);
+ border-radius: 100px;
+ padding: 0.25rem 0.65rem;
+ font-size: 0.8rem;
+ font-family: var(--font-mono);
+ background: transparent;
+ width: 120px;
+ transition: border-color 0.15s;
+}
+
+.token-input:focus {
+ outline: none;
+ border-color: var(--color-primary);
+ border-style: solid;
+}
+
+.token-input::placeholder {
+ color: var(--color-text-muted);
+ opacity: 0.6;
+}
+
+.token-add-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 24px;
+ height: 24px;
+ border: 1px solid var(--color-border);
+ border-radius: 50%;
+ background: var(--color-surface);
+ font-size: 1rem;
+ cursor: pointer;
+ color: var(--color-text-muted);
+ transition: all 0.15s;
+}
+
+.token-add-btn:hover:not(:disabled) {
+ border-color: var(--color-primary);
+ color: var(--color-primary);
+ background: var(--color-primary-light);
+}
+
+.token-add-btn:disabled {
+ opacity: 0.4;
+ cursor: default;
+}
+
+/* Token popover */
+
+.token-popover {
+ position: absolute;
+ top: calc(100% + 6px);
+ left: 0;
+ z-index: 10;
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ padding: 0.75rem;
+ min-width: 220px;
+}
+
+.popover-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 0.5rem;
+}
+
+.popover-title {
+ font-weight: 600;
+ font-size: 0.85rem;
+ font-family: var(--font-mono);
+}
+
+.popover-close {
+ border: none;
+ background: none;
+ cursor: pointer;
+ font-size: 1.1rem;
+ color: var(--color-text-muted);
+ line-height: 1;
+ padding: 0 0.2rem;
+}
+
+.popover-close:hover {
+ color: var(--color-text);
+}
+
+.popover-field {
+ display: flex;
+ flex-direction: column;
+ gap: 0.2rem;
+}
+
+.popover-field label {
+ font-size: 0.75rem;
+ font-weight: 500;
+ color: var(--color-text-muted);
+}
+
+.popover-field input {
+ padding: 0.35rem 0.5rem;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ font-size: 0.8rem;
+ font-family: var(--font-mono);
+ background: var(--color-bg);
+}
+
+.popover-field input:focus {
+ outline: none;
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 2px var(--color-primary-light);
+}
+
+.popover-field input::placeholder {
+ color: var(--color-text-muted);
+ opacity: 0.5;
+ font-style: italic;
+}
+
+/* JSON editor */
+
+.json-editor {
+ position: sticky;
+ top: 1rem;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+}
+
+.json-textarea {
+ width: 100%;
+ min-height: 200px;
+ flex: 1;
+ padding: 0.75rem;
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius);
+ font-family: var(--font-mono);
+ font-size: 0.8rem;
+ line-height: 1.6;
+ background: var(--color-bg);
+ resize: vertical;
+ transition: border-color 0.15s;
+}
+
+.json-textarea:focus {
+ outline: none;
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 2px var(--color-primary-light);
+}
+
+.json-textarea.json-error {
+ border-color: var(--color-danger);
+ box-shadow: 0 0 0 2px var(--color-danger-light);
+}
+
+.error-text {
+ color: var(--color-danger);
+ font-size: 0.8rem;
+ margin-top: 0.35rem;
+}
+
+/* Loading & error states */
+
+.loading {
+ text-align: center;
+ padding: 3rem;
+ color: var(--color-text-muted);
+}
+
+.error-banner {
+ background: var(--color-danger-light);
+ border: 1px solid var(--color-danger);
+ border-radius: var(--radius);
+ padding: 1rem;
+ color: var(--color-danger);
+}
+
+.error-banner p:first-child {
+ font-weight: 600;
+}
+
+.error-banner p:last-child {
+ font-size: 0.85rem;
+ margin-top: 0.25rem;
+}
+
+/* Theme toggle */
+
+.theme-toggle {
+ display: inline-flex;
+ align-items: center;
+ border: 1px solid var(--color-border);
+ border-radius: 100px;
+ background: var(--color-surface);
+ padding: 2px;
+ gap: 0;
+}
+
+.theme-toggle button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: none;
+ background: none;
+ cursor: pointer;
+ border-radius: 100px;
+ padding: 0.3rem 0.6rem;
+ font-size: 0.75rem;
+ color: var(--color-text-muted);
+ transition: background 0.15s, color 0.15s;
+ line-height: 1;
+ gap: 0.3rem;
+}
+
+.theme-toggle button:hover {
+ color: var(--color-text);
+}
+
+.theme-toggle button.active {
+ background: var(--color-primary-light);
+ color: var(--color-primary);
+}
+
+.theme-toggle svg {
+ width: 14px;
+ height: 14px;
+ fill: currentColor;
+}
diff --git a/.github/pages/svelte.config.js b/.github/pages/svelte.config.js
new file mode 100644
index 0000000..4c6b24b
--- /dev/null
+++ b/.github/pages/svelte.config.js
@@ -0,0 +1,5 @@
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
+
+export default {
+ preprocess: vitePreprocess(),
+};
diff --git a/.github/pages/vite.config.js b/.github/pages/vite.config.js
new file mode 100644
index 0000000..f46d3ff
--- /dev/null
+++ b/.github/pages/vite.config.js
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite';
+import { svelte } from '@sveltejs/vite-plugin-svelte';
+
+export default defineConfig({
+ plugins: [svelte()],
+ base: '/theme-kit/',
+});
diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
new file mode 100644
index 0000000..fd8b4b0
--- /dev/null
+++ b/.github/workflows/deploy-pages.yml
@@ -0,0 +1,51 @@
+name: Deploy Configurator to GitHub Pages
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - '.github/pages/**'
+ - 'theme.schema.json'
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+ cache-dependency-path: .github/pages/package-lock.json
+
+ - name: Install dependencies
+ working-directory: .github/pages
+ run: npm ci
+
+ - name: Build
+ working-directory: .github/pages
+ run: npm run build
+
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: .github/pages/dist
+
+ deploy:
+ needs: build
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index 0d7e0d1..05762b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,7 @@ default.profraw
.claude/settings.local.json
.idea/
-*.log
\ No newline at end of file
+*.log
+.github/pages/node_modules/
+
+.github/pages/dist/
diff --git a/CLAUDE.md b/CLAUDE.md
index 5416ccd..b488acf 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -76,6 +76,10 @@ Only categories present in config are included in generated `Theme` struct.
The config model (`ThemeToken`) is a struct with `name` and `style` properties and custom `Codable` β strings decode to both fields equal, objects require both keys. Encoding round-trips: equal name/style encodes as string.
+### Configurator Web App
+
+A Svelte SPA at `.github/pages/` that lets users build `theme.json` visually instead of editing JSON by hand. Deployed to GitHub Pages (`https://rozd.github.io/theme-kit/`) via `.github/workflows/deploy-pages.yml`. Fetches the JSON Schema at runtime to drive the UI β categories, token fields, and config options are all derived from `theme.schema.json`.
+
## Key Patterns
- All types are `nonisolated`, `Sendable`, and `Codable`
diff --git a/README.md b/README.md
index b36c04f..8c4dd65 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
# ThemeKit
-[](https://github.com/rozd/theme-kit/releases)
+[](https://developer.apple.com/xcode/)
[](https://swift.org)
-[](LICENSE)
+[](https://github.com/rozd/theme-kit/releases)
[](https://codecov.io/gh/rozd/theme-kit)
-[](https://developer.apple.com/xcode/)
+[](LICENSE)
**Native-feeling theming for SwiftUI, powered by the environment.**
@@ -23,6 +23,10 @@ ThemeKit gives your app a design token system that works exactly like SwiftUI's
https://github.com/user-attachments/assets/f4563c6a-57e2-4356-bd87-72276ec9bf96
+## π οΈ Configurator
+
+You don't need to write JSON by hand, use the [**ThemeKit Configurator**](https://rozd.github.io/theme-kit/) β a visual editor that lets you toggle categories, add tokens, configure style overrides, and copy the finished `theme.json` straight into your project.
+
## π Integration
### 1. Add ThemeKit
@@ -35,7 +39,7 @@ https://github.com/rozd/theme-kit
### 2. Create `theme.json`
-Add a `theme.json` to your project root. This file is just a list of token **names** β no colors, no gradients, no design values. You're declaring the shape of your design language; actual values come in step 4.
+Add a `theme.json` to your project root (or use the [Configurator](https://rozd.github.io/theme-kit/) to build it visually). This file is just a list of token **names** β no colors, no gradients, no design values. You're declaring the shape of your design language; actual values come in step 4.
Only include the categories you need β the generated `Theme` struct will match: