1
0
Fork 0

Compare commits

..

No commits in common. "4e507a01c6ece7c7019936039cb0f15eb8f1b931" and "c2dafe4ee1c3de0852ae93dda2581e2f37ba9415" have entirely different histories.

16 changed files with 565 additions and 324 deletions

1
.gitignore vendored
View file

@ -10,7 +10,6 @@ lerna-debug.log*
node_modules node_modules
dist dist
dist-ssr dist-ssr
build
*.local *.local
.svelte-kit .svelte-kit

View file

@ -61,8 +61,8 @@ importers:
specifier: ^5.0.5 specifier: ^5.0.5
version: 5.0.5 version: 5.0.5
svelte-check: svelte-check:
specifier: ^4.0.0 specifier: ^3.8.6
version: 4.0.5(picomatch@2.3.1)(svelte@5.0.5)(typescript@5.6.3) version: 3.8.6(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.47))(postcss@8.4.47)(svelte@5.0.5)
svelte-fa: svelte-fa:
specifier: ^4.0.3 specifier: ^4.0.3
version: 4.0.3(svelte@5.0.5) version: 4.0.3(svelte@5.0.5)
@ -486,6 +486,9 @@ packages:
'@types/estree@1.0.6': '@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
'@types/pug@2.0.10':
resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
acorn-typescript@1.4.13: acorn-typescript@1.4.13:
resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==} resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==}
peerDependencies: peerDependencies:
@ -544,6 +547,9 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'} engines: {node: '>=8'}
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
brace-expansion@2.0.1: brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
@ -556,6 +562,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true hasBin: true
buffer-crc32@1.0.0:
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
engines: {node: '>=8.0.0'}
camelcase-css@2.0.1: camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -567,10 +577,6 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
chokidar@4.0.1:
resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==}
engines: {node: '>= 14.16.0'}
color-convert@2.0.1: color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'} engines: {node: '>=7.0.0'}
@ -582,6 +588,9 @@ packages:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
cookie@0.6.0: cookie@0.6.0:
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -608,6 +617,10 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
detect-indent@6.1.0:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
devalue@5.1.1: devalue@5.1.1:
resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
@ -629,6 +642,9 @@ packages:
emoji-regex@9.2.2: emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
esbuild@0.21.5: esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -651,14 +667,6 @@ packages:
fastq@1.17.1: fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
fdir@6.4.2:
resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==}
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
fill-range@7.1.1: fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -670,6 +678,9 @@ packages:
fraction.js@4.3.7: fraction.js@4.3.7:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
fsevents@2.3.3: fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@ -690,12 +701,19 @@ packages:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
hasBin: true hasBin: true
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
globalyzer@0.1.0: globalyzer@0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
globrex@0.1.2: globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
hasown@2.0.2: hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -703,6 +721,13 @@ packages:
import-meta-resolve@4.1.0: import-meta-resolve@4.1.0:
resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
is-binary-path@2.1.0: is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -772,14 +797,28 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
min-indent@1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@9.0.5: minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
minipass@7.1.2: minipass@7.1.2:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
mri@1.2.0: mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -818,9 +857,16 @@ packages:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
package-json-from-dist@1.0.1: package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
path-key@3.1.1: path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -913,10 +959,6 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
readdirp@4.0.2:
resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==}
engines: {node: '>= 14.16.0'}
resolve@1.22.8: resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true hasBin: true
@ -925,6 +967,11 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'} engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rollup@4.24.0: rollup@4.24.0:
resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@ -937,6 +984,9 @@ packages:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'} engines: {node: '>=6'}
sander@0.5.1:
resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
set-cookie-parser@2.7.1: set-cookie-parser@2.7.1:
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
@ -956,6 +1006,10 @@ packages:
resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==}
engines: {node: '>=18'} engines: {node: '>=18'}
sorcery@0.11.1:
resolution: {integrity: sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ==}
hasBin: true
source-map-js@1.2.1: source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -976,6 +1030,10 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
strip-indent@3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
sucrase@3.35.0: sucrase@3.35.0:
resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
@ -985,19 +1043,54 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
svelte-check@4.0.5: svelte-check@3.8.6:
resolution: {integrity: sha512-icBTBZ3ibBaywbXUat3cK6hB5Du+Kq9Z8CRuyLmm64XIe2/r+lQcbuBx/IQgsbrC+kT2jQ0weVpZSSRIPwB6jQ==} resolution: {integrity: sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q==}
engines: {node: '>= 18.0.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0 svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0
typescript: '>=5.0.0'
svelte-fa@4.0.3: svelte-fa@4.0.3:
resolution: {integrity: sha512-saZ8yACM0k9Aexey+2NXU1W0MBosU5lBsRgqFCJKM+Taw7d0HyimPaPAjmvY/Xkyi3UwEYL/Sdu1IZJv/p0Flw==} resolution: {integrity: sha512-saZ8yACM0k9Aexey+2NXU1W0MBosU5lBsRgqFCJKM+Taw7d0HyimPaPAjmvY/Xkyi3UwEYL/Sdu1IZJv/p0Flw==}
peerDependencies: peerDependencies:
svelte: ^4.0.0 || ^5.0.0 svelte: ^4.0.0 || ^5.0.0
svelte-preprocess@5.1.4:
resolution: {integrity: sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA==}
engines: {node: '>= 16.0.0'}
peerDependencies:
'@babel/core': ^7.10.2
coffeescript: ^2.5.1
less: ^3.11.3 || ^4.0.0
postcss: ^7 || ^8
postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
pug: ^3.0.0
sass: ^1.26.8
stylus: ^0.55.0
sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0
svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0
typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0'
peerDependenciesMeta:
'@babel/core':
optional: true
coffeescript:
optional: true
less:
optional: true
postcss:
optional: true
postcss-load-config:
optional: true
pug:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
typescript:
optional: true
svelte@5.0.5: svelte@5.0.5:
resolution: {integrity: sha512-f4WBlP5g8W6pEoDfx741lewMlemy+LIGpEqjGPWqnHVP92wqlQXl87U5O5Bi2tkSUrO95OxOoqwU8qlqiHmFKA==} resolution: {integrity: sha512-f4WBlP5g8W6pEoDfx741lewMlemy+LIGpEqjGPWqnHVP92wqlQXl87U5O5Bi2tkSUrO95OxOoqwU8qlqiHmFKA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1094,6 +1187,9 @@ packages:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
yaml@2.6.0: yaml@2.6.0:
resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
@ -1400,6 +1496,8 @@ snapshots:
'@types/estree@1.0.6': {} '@types/estree@1.0.6': {}
'@types/pug@2.0.10': {}
acorn-typescript@1.4.13(acorn@8.13.0): acorn-typescript@1.4.13(acorn@8.13.0):
dependencies: dependencies:
acorn: 8.13.0 acorn: 8.13.0
@ -1443,6 +1541,11 @@ snapshots:
binary-extensions@2.3.0: {} binary-extensions@2.3.0: {}
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@2.0.1: brace-expansion@2.0.1:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@ -1458,6 +1561,8 @@ snapshots:
node-releases: 2.0.18 node-releases: 2.0.18
update-browserslist-db: 1.1.1(browserslist@4.24.2) update-browserslist-db: 1.1.1(browserslist@4.24.2)
buffer-crc32@1.0.0: {}
camelcase-css@2.0.1: {} camelcase-css@2.0.1: {}
caniuse-lite@1.0.30001669: {} caniuse-lite@1.0.30001669: {}
@ -1474,10 +1579,6 @@ snapshots:
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
chokidar@4.0.1:
dependencies:
readdirp: 4.0.2
color-convert@2.0.1: color-convert@2.0.1:
dependencies: dependencies:
color-name: 1.1.4 color-name: 1.1.4
@ -1486,6 +1587,8 @@ snapshots:
commander@4.1.1: {} commander@4.1.1: {}
concat-map@0.0.1: {}
cookie@0.6.0: {} cookie@0.6.0: {}
cross-spawn@7.0.3: cross-spawn@7.0.3:
@ -1502,6 +1605,8 @@ snapshots:
deepmerge@4.3.1: {} deepmerge@4.3.1: {}
detect-indent@6.1.0: {}
devalue@5.1.1: {} devalue@5.1.1: {}
didyoumean@1.2.2: {} didyoumean@1.2.2: {}
@ -1516,6 +1621,8 @@ snapshots:
emoji-regex@9.2.2: {} emoji-regex@9.2.2: {}
es6-promise@3.3.1: {}
esbuild@0.21.5: esbuild@0.21.5:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5 '@esbuild/aix-ppc64': 0.21.5
@ -1563,10 +1670,6 @@ snapshots:
dependencies: dependencies:
reusify: 1.0.4 reusify: 1.0.4
fdir@6.4.2(picomatch@2.3.1):
optionalDependencies:
picomatch: 2.3.1
fill-range@7.1.1: fill-range@7.1.1:
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
@ -1578,6 +1681,8 @@ snapshots:
fraction.js@4.3.7: {} fraction.js@4.3.7: {}
fs.realpath@1.0.0: {}
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
@ -1600,16 +1705,34 @@ snapshots:
package-json-from-dist: 1.0.1 package-json-from-dist: 1.0.1
path-scurry: 1.11.1 path-scurry: 1.11.1
glob@7.2.3:
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
globalyzer@0.1.0: {} globalyzer@0.1.0: {}
globrex@0.1.2: {} globrex@0.1.2: {}
graceful-fs@4.2.11: {}
hasown@2.0.2: hasown@2.0.2:
dependencies: dependencies:
function-bind: 1.1.2 function-bind: 1.1.2
import-meta-resolve@4.1.0: {} import-meta-resolve@4.1.0: {}
inflight@1.0.6:
dependencies:
once: 1.4.0
wrappy: 1.0.2
inherits@2.0.4: {}
is-binary-path@2.1.0: is-binary-path@2.1.0:
dependencies: dependencies:
binary-extensions: 2.3.0 binary-extensions: 2.3.0
@ -1665,12 +1788,24 @@ snapshots:
braces: 3.0.3 braces: 3.0.3
picomatch: 2.3.1 picomatch: 2.3.1
min-indent@1.0.1: {}
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
minimatch@9.0.5: minimatch@9.0.5:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
minimist@1.2.8: {}
minipass@7.1.2: {} minipass@7.1.2: {}
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
mri@1.2.0: {} mri@1.2.0: {}
mrmime@2.0.0: {} mrmime@2.0.0: {}
@ -1695,8 +1830,14 @@ snapshots:
object-hash@3.0.0: {} object-hash@3.0.0: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
package-json-from-dist@1.0.1: {} package-json-from-dist@1.0.1: {}
path-is-absolute@1.0.1: {}
path-key@3.1.1: {} path-key@3.1.1: {}
path-parse@1.0.7: {} path-parse@1.0.7: {}
@ -1769,8 +1910,6 @@ snapshots:
dependencies: dependencies:
picomatch: 2.3.1 picomatch: 2.3.1
readdirp@4.0.2: {}
resolve@1.22.8: resolve@1.22.8:
dependencies: dependencies:
is-core-module: 2.15.1 is-core-module: 2.15.1
@ -1779,6 +1918,10 @@ snapshots:
reusify@1.0.4: {} reusify@1.0.4: {}
rimraf@2.7.1:
dependencies:
glob: 7.2.3
rollup@4.24.0: rollup@4.24.0:
dependencies: dependencies:
'@types/estree': 1.0.6 '@types/estree': 1.0.6
@ -1809,6 +1952,13 @@ snapshots:
dependencies: dependencies:
mri: 1.2.0 mri: 1.2.0
sander@0.5.1:
dependencies:
es6-promise: 3.3.1
graceful-fs: 4.2.11
mkdirp: 0.5.6
rimraf: 2.7.1
set-cookie-parser@2.7.1: {} set-cookie-parser@2.7.1: {}
shebang-command@2.0.0: shebang-command@2.0.0:
@ -1825,6 +1975,13 @@ snapshots:
mrmime: 2.0.0 mrmime: 2.0.0
totalist: 3.0.1 totalist: 3.0.1
sorcery@0.11.1:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
buffer-crc32: 1.0.0
minimist: 1.2.8
sander: 0.5.1
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
string-width@4.2.3: string-width@4.2.3:
@ -1847,6 +2004,10 @@ snapshots:
dependencies: dependencies:
ansi-regex: 6.1.0 ansi-regex: 6.1.0
strip-indent@3.0.0:
dependencies:
min-indent: 1.0.1
sucrase@3.35.0: sucrase@3.35.0:
dependencies: dependencies:
'@jridgewell/gen-mapping': 0.3.5 '@jridgewell/gen-mapping': 0.3.5
@ -1859,22 +2020,43 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
svelte-check@4.0.5(picomatch@2.3.1)(svelte@5.0.5)(typescript@5.6.3): svelte-check@3.8.6(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.47))(postcss@8.4.47)(svelte@5.0.5):
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
chokidar: 4.0.1 chokidar: 3.6.0
fdir: 6.4.2(picomatch@2.3.1)
picocolors: 1.1.1 picocolors: 1.1.1
sade: 1.8.1 sade: 1.8.1
svelte: 5.0.5 svelte: 5.0.5
svelte-preprocess: 5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.47))(postcss@8.4.47)(svelte@5.0.5)(typescript@5.6.3)
typescript: 5.6.3 typescript: 5.6.3
transitivePeerDependencies: transitivePeerDependencies:
- picomatch - '@babel/core'
- coffeescript
- less
- postcss
- postcss-load-config
- pug
- sass
- stylus
- sugarss
svelte-fa@4.0.3(svelte@5.0.5): svelte-fa@4.0.3(svelte@5.0.5):
dependencies: dependencies:
svelte: 5.0.5 svelte: 5.0.5
svelte-preprocess@5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.47))(postcss@8.4.47)(svelte@5.0.5)(typescript@5.6.3):
dependencies:
'@types/pug': 2.0.10
detect-indent: 6.1.0
magic-string: 0.30.12
sorcery: 0.11.1
strip-indent: 3.0.0
svelte: 5.0.5
optionalDependencies:
postcss: 8.4.47
postcss-load-config: 5.1.0(jiti@1.21.6)(postcss@8.4.47)
typescript: 5.6.3
svelte@5.0.5: svelte@5.0.5:
dependencies: dependencies:
'@ampproject/remapping': 2.3.0 '@ampproject/remapping': 2.3.0
@ -1977,6 +2159,8 @@ snapshots:
string-width: 5.1.2 string-width: 5.1.2
strip-ansi: 7.1.0 strip-ansi: 7.1.0
wrappy@1.0.2: {}
yaml@2.6.0: {} yaml@2.6.0: {}
zimmerframe@1.1.2: {} zimmerframe@1.1.2: {}

View file

@ -2,7 +2,7 @@
"build": { "build": {
"beforeDevCommand": "pnpm dev", "beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build", "beforeBuildCommand": "pnpm build",
"frontendDist": "../build", "frontendDist": "../dist",
"devUrl": "http://localhost:1420" "devUrl": "http://localhost:1420"
}, },
"bundle": { "bundle": {

View file

@ -1,7 +1,6 @@
<script> <script>
import { RangeSlider, Tab, TabGroup, InputChip, SlideToggle } from '@skeletonlabs/skeleton'; import { RangeSlider, Tab, TabGroup, InputChip, SlideToggle } from '@skeletonlabs/skeleton';
import useSettings from '$lib/useSettings.svelte.js'; import { imageGridColumns, postGridPreviewQuality, blacklist, limitImageHeight } from '$lib/settings';
const settings = useSettings();
let tabPos = $state(0); let tabPos = $state(0);
let showApikey = $state(false); let showApikey = $state(false);
@ -9,31 +8,32 @@
</script> </script>
<div class="flex flex-col"> <div class="flex flex-col">
<h2 class="h2 mb-2 text-dark-token">Settings</h2> <h2 class="h2 mb-2 text-dark-token">Settings</h2>
<!--<TabGroup> <TabGroup>
<Tab class="text-dark-token" bind:group={tabPos} name="tab1" value={0}>Display</Tab> <Tab class="text-dark-token" bind:group={tabPos} name="tab1" value={0}>Display</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab2" value={1}>API</Tab> <Tab class="text-dark-token" bind:group={tabPos} name="tab2" value={1}>API</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab3" value={2}>User</Tab> <Tab class="text-dark-token" bind:group={tabPos} name="tab3" value={2}>User</Tab>
<Tab class="text-dark-token" bind:group={tabPos} name="tab4" value={3}>Chats</Tab> <Tab class="text-dark-token" bind:group={tabPos} name="tab4" value={3}>Chats</Tab>
{#snippet panel()} {#snippet panel()}
{#if tabPos === 0} {#if tabPos === 0}
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<h3 class="h3 text-dark-token font-bold">Image</h3> <h3 class="h3 text-dark-token font-bold">Image</h3>
<SlideToggle name="image-limit-height" bind:checked={settings.limitImageHeight}><span class="text-dark-token">Limit image height</span></SlideToggle> <SlideToggle name="image-limit-height" bind:checked={$limitImageHeight}><span class="text-dark-token">Limit image height</span></SlideToggle>
<h3 class="h3 text-dark-token font-bold">Grid</h3> <h3 class="h3 text-dark-token font-bold">Grid</h3>
<div class="basis-1/2"> <div class="basis-1/2">
<RangeSlider accent="text-dark-token" name="grid-columns" min={1} max={12} bind:value={settings.imageGridColumns} ticked={true}> <RangeSlider accent="text-dark-token" name="grid-columns" min={1} max={12} bind:value={$imageGridColumns} ticked={true}>
<div class="flex flex-grow justify-between items-center dark"> <div class="flex flex-grow justify-between items-center dark">
<div class="text-dark-token font-bold mb-1">Grid Columns</div> <div class="text-dark-token font-bold mb-1">Grid Columns</div>
<div class="text-xs text-dark-token">{settings.imageGridColumns} / {12}</div> <div class="text-xs text-dark-token">{$imageGridColumns} / {12}</div>
</div> </div>
</RangeSlider> </RangeSlider>
</div> </div>
<div class="basis-1/2"> <div class="basis-1/2">
<label class="label"> <label class="label">
<span class="text-dark-token font-bold">Preview type</span> <span class="text-dark-token font-bold">Preview type</span>
<select class="select" bind:value={settings.postGridPreviewQuality}> <select class="select" bind:value={$postGridPreviewQuality}>
<option value="preview">Preview</option> <option value="preview">Preview</option>
<option value="sample">Sample</option> <option value="sample">Sample</option>
</select> </select>
@ -71,7 +71,7 @@
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<div class=""> <div class="">
<p class="text-dark-token font-bold">Blacklist</p> <p class="text-dark-token font-bold">Blacklist</p>
<InputChip name="blacklist" label="Blacklist" bind:value={settings.blacklist} /> <InputChip name="blacklist" label="Blacklist" bind:value={$blacklist} />
</div> </div>
</div> </div>
{/if} {/if}
@ -80,10 +80,11 @@
<div class="flex flex-col gap-3"> <div class="flex flex-col gap-3">
<div class=""> <div class="">
<p class="text-dark-token font-bold">Chats</p> <p class="text-dark-token font-bold">Chats</p>
<InputChip name="blacklist" label="Blacklist" bind:value={settings.blacklist} /> <InputChip name="blacklist" label="Blacklist" bind:value={$blacklist} />
</div> </div>
</div> </div>
{/if} {/if}
{/snippet} {/snippet}
</TabGroup>--> </TabGroup>
</div> </div>

View file

@ -1,20 +1,23 @@
<script> <script>
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons'; import {faArrowLeft} from '@fortawesome/free-solid-svg-icons';
import {Fa} from 'svelte-fa'; import {Fa} from 'svelte-fa';
import {onMount} from "svelte"; import {AppRailAnchor} from '@skeletonlabs/skeleton';
/**
* @typedef {Object} Props
* @property {number} [popCount]
*/
/** @type {Props} */ /** @type {Props} */
let { popCount = 1 } = $props(); let { popCount = 1 } = $props();
let href = $state(); let href = $state();
let pathnameParts = $state(null); let pathnameParts = window.location.pathname.split('/');
onMount(() => { for(let i = 0; i < popCount; i++) {
pathnameParts = window.location.pathname.split('/')
for(let i = 0; i < popCount; i++) {
pathnameParts.pop(); pathnameParts.pop();
} }
switch (pathnameParts.length) { switch (pathnameParts.length) {
case 0: case 0:
href = '/' href = '/'
break; break;
@ -24,14 +27,13 @@
default: default:
href = '/' + pathnameParts.join('/') href = '/' + pathnameParts.join('/')
break; break;
} }
});
</script> </script>
<a {href} class="h-full aspect-square"> <AppRailAnchor {href} title="Back">
<div class="flex flex-col gap-2 place-content-center"> <div class="flex flex-col gap-2 place-content-center">
<Fa size={'2x'} icon={faArrowLeft} /> <Fa size={'2x'} icon={faArrowLeft} />
<p>Back</p> <p>Back</p>
</div> </div>
</a> </AppRailAnchor>

View file

@ -1,22 +1,21 @@
<script> <script>
import useSettings from '$lib/useSettings.svelte.js'; import { preventDefault } from 'svelte/legacy';
import {loading} from "$lib/stores.js";
const settings = useSettings(); import { showSearch, loading } from '$lib/stores';
let searchString = $state(''); import { lastSearch } from '$lib/settings';
const {onsubmit = null} = $props(); import { goto } from '$app/navigation';
$effect(() => {
searchString = settings.lastSearch let searchValue = $state($lastSearch);
});
</script> </script>
<form class="flex flex-row gap-2" {#if $showSearch}
onsubmit={(e) => { <form class="flex flex-row gap-2"
e.preventDefault(); onsubmit={preventDefault(() => {
settings.lastSearch = searchString; $loading = true;
loading.set(true); goto('/')
onsubmit?.(searchString, true); lastSearch.set(searchValue);
}}> })}>
<input class="input py-1 px-2 w-96" type="text" placeholder="Search" bind:value={searchString} /> <input class="input py-1 px-2 w-96" type="text" placeholder="Search" bind:value={searchValue} />
<button class="btn btn-md variant-filled" type="submit">Submit</button> <button class="btn btn-md variant-filled" type="submit">Submit</button>
</form> </form>
{/if}

View file

@ -1,13 +0,0 @@
<script>
import {BackAppRailAnchor, GlobalSearch} from "$lib/components";
let {onsubmit = null, back = null} = $props();
</script>
<header class="top-0 fixed flex">
{#if back}
<BackAppRailAnchor popCount={back} />
{/if}
<GlobalSearch onsubmit={(val = '', explicitRefresh = false) => {
onsubmit?.(val, explicitRefresh);
}} />
</header>

View file

@ -1,25 +1,27 @@
<script> <script>
import useSettings from "$lib/useSettings.svelte.js"; import { showSearch, loading } from '$lib/stores';
import { loading } from "$lib/stores.js"; import { postGridPreviewQuality, imageGridColumns } from '$lib/settings';
let { posts = [] } = $props(); let { posts = [] } = $props();
const settings = useSettings();
</script> </script>
<div class="grid gap-3" style={`grid-template-columns: repeat(${settings.imageGridColumns}, minmax(0, 1fr))`}> <div class="grid gap-3" style={`grid-template-columns: repeat(${$imageGridColumns}, minmax(0, 1fr))`}>
{#each posts as post} {#each posts as post}
<a href={`/posts/${post.id}`} class="card p-3 flex flex-col justify-end items-center" onclick={() => { <a href={`/posts/${post.id}`} class="card p-3 flex flex-col justify-end items-center" onclick={() => {
loading.set(true); $loading = true;
$showSearch = false
}}> }}>
<header class="card-header p-0"></header> <header class="card-header p-0"></header>
<section class="flex flex-col"> <section class="flex flex-col">
<img src={post[settings.postGridPreviewQuality].url} <img src={post[$postGridPreviewQuality].url}
loading="lazy" loading="lazy"
alt={`Post ${post.id}`} /> alt={`Post ${post.id}`} />
<div class="bg-black px-2 py-1"> <div class="bg-black px-2 py-1">
<p class="text-center text-dark-token">{post.id} {post.file.ext} {post.rating}</p> <p class="text-center text-dark-token">{post.id} {post.file.ext} {post.rating}</p>
</div> </div>
</section> </section>
<footer >
</footer>
</a> </a>
{/each} {/each}
</div> </div>

View file

@ -1,6 +1,5 @@
<script> <script>
import useSettings from '$lib/useSettings.svelte.js'; import { limitImageHeight } from '$lib/settings';
const settings = useSettings();
/** /**
* @typedef {Object} Props * @typedef {Object} Props
@ -12,13 +11,13 @@
</script> </script>
{#if post?.preview?.has} {#if post?.preview?.has}
<img class:max-h-dvh={settings.limitImageHeight} src={post.preview.url} alt={`Post ${post.id}`} /> <img class:max-h-dvh={$limitImageHeight} src={post.preview.url} alt={`Post ${post.id}`} />
{:else} {:else}
{#if ['webm', 'mp4'].includes(post.file.ext)} {#if ['webm', 'mp4'].includes(post.file.ext)}
<video class:max-h-dvh={settings.limitImageHeight} controls playsinline> <video class:max-h-dvh={$limitImageHeight} controls playsinline>
<source src={post.file.url} /> <source src={post.file.url} />
</video> </video>
{:else} {:else}
<img class:max-h-dvh={settings.limitImageHeight} src={post.file.url} alt={`Post ${post.id}`} /> <img class:max-h-dvh={$limitImageHeight} src={post.file.url} alt={`Post ${post.id}`} />
{/if} {/if}
{/if} {/if}

View file

@ -0,0 +1,13 @@
<script>
import { Fa } from 'svelte-fa';
import { AppRailAnchor } from '@skeletonlabs/skeleton';
import { showSearch } from '$lib/stores';
import { faSearch } from '@fortawesome/free-solid-svg-icons';
</script>
<AppRailAnchor on:click={() => $showSearch = !$showSearch}>
<div class="flex flex-col gap-2 place-content-center">
<Fa size={'2x'} icon={faSearch} />
<p>Search</p>
</div>
</AppRailAnchor>

View file

@ -3,7 +3,7 @@ import BackAppRailAnchor from './BackAppRailAnchor.svelte';
import GlobalSearch from './GlobalSearch.svelte'; import GlobalSearch from './GlobalSearch.svelte';
import ImageGrid from './ImageGrid.svelte'; import ImageGrid from './ImageGrid.svelte';
import PostMedia from './PostMedia.svelte'; import PostMedia from './PostMedia.svelte';
import Header from './Header.svelte'; import SearchAppRailAnchor from './SearchAppRailAnchor.svelte';
export { export {
AppSettings, AppSettings,
@ -11,5 +11,5 @@ export {
GlobalSearch, GlobalSearch,
ImageGrid, ImageGrid,
PostMedia, PostMedia,
Header, SearchAppRailAnchor
} }

View file

@ -2,3 +2,4 @@ import { writable } from 'svelte/store';
export const postSearchResults = writable(null); export const postSearchResults = writable(null);
export const loading = writable(false); export const loading = writable(false);
export const showSearch = writable(true);

View file

@ -1,56 +0,0 @@
import {onMount} from "svelte";
function initFromLocalStorage(storageKey, initalValue = null) {
return window.localStorage.getItem(storageKey) ?? initalValue;
}
export default function useSettings() {
let lastSearch = $state(null),
imageGridColumns = $state(6),
limitImageHeight = $state(false),
postGridPreviewQuality = $state('preview'),
blacklist = $state([
'gore',
'scat',
'watersports',
'young',
'loli',
'shota',
]);
onMount(() => {
lastSearch = localStorage.getItem('lastSearch') ?? lastSearch;
imageGridColumns = localStorage.getItem('gridColumns') ?? imageGridColumns;
limitImageHeight = localStorage.getItem('limitImageHeight') ?? limitImageHeight;
postGridPreviewQuality = localStorage.getItem('gridPreviewQuality') ?? postGridPreviewQuality;
blacklist = localStorage.getItem('blacklist') ?? blacklist;
})
return {
get lastSearch() {return lastSearch},
get imageGridColumns() {return imageGridColumns},
get postGridPreviewQuality() {return postGridPreviewQuality},
get blacklist() {return blacklist},
get limitImageHeight() {return limitImageHeight},
set lastSearch(val) {
lastSearch = val;
localStorage.setItem('lastSearch', val);
},
set imageGridColumns(val) {
imageGridColumns = val;
localStorage.setItem('gridColumns', val);
},
set postGridPreviewQuality(val) {
postGridPreviewQuality = val
localStorage.setItem('gridPreviewQuality', val);
},
set blacklist(val) {
blacklist = val
localStorage.setItem('blacklist', val);
},
set limitImageHeight(val) {
limitImageHeight = val
localStorage.setItem('limitImageHeight', val);
},
}
}

View file

@ -1,6 +1,8 @@
<script> <script>
import '../app.pcss'; import '../app.pcss';
import { loading } from "$lib/stores.js"; import { Drawer, initializeStores, Modal, ProgressRadial, Toast } from '@skeletonlabs/skeleton';
import { loading } from '$lib/stores';
import { AppSettings } from '$lib/components';
/** /**
* @typedef {Object} Props * @typedef {Object} Props
* @property {import('svelte').Snippet} [children] * @property {import('svelte').Snippet} [children]
@ -8,11 +10,22 @@
/** @type {Props} */ /** @type {Props} */
let { children } = $props(); let { children } = $props();
initializeStores();
</script> </script>
<div class="relative h-dvh"> <div class="relative h-dvh">
<Modal />
<Toast />
<Drawer bgDrawer="bg-surface-500/90" width="w-6/12" height="h-dvh" position="left">
<div class="h-full p-4">
<AppSettings />
</div>
</Drawer>
{#if $loading} {#if $loading}
<p class="absolute top-0 left-0">Loading</p> <div class="fixed bottom-3 right-3 w-8 h-8">
<ProgressRadial width="w-8" height="h-8" stroke={120} strokeLinecap="butt" />
</div>
{/if} {/if}
{@render children?.()} {@render children?.()}
</div> </div>

View file

@ -1,41 +1,84 @@
<script> <script>
import { Header, ImageGrid } from '$lib/components'; import { Fa } from 'svelte-fa';
import { GlobalSearch, ImageGrid, SearchAppRailAnchor} from '$lib/components';
import { faGear } from '@fortawesome/free-solid-svg-icons';
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import { lastSearch, blacklist } from '$lib/settings';
import { postSearchResults, loading, showSearch} from '$lib/stores';
import {
AppBar,
AppRail,
AppRailAnchor,
AppShell,
getDrawerStore, getToastStore
} from '@skeletonlabs/skeleton';
import PostList from '$lib/PostList'; import PostList from '$lib/PostList';
import useSettings from "$lib/useSettings.svelte.js";
import {onMount} from "svelte";
import {loading, postSearchResults} from "$lib/stores.js";
const settings = useSettings(); const drawerStore = getDrawerStore();
let initalSearch = true;
function onSearch(val = '', explicitRefresh = false) { function onSearch() {
loading.set(true); $loading = true;
invoke('get_posts', { query: val }).then((resPosts) => { /*invoke('get_posts', { query: $lastSearch }).then((resPosts) => {
postSearchResults.set(new PostList(resPosts).filterPosts(settings.blacklist).getPosts()) postSearchResults.set(new PostList(resPosts).filterPosts($blacklist).getPosts());
loading.set(false) requestAnimationFrame(() => $loading = false);
}); });*/
} }
onMount(() => {
const urlParams = new URLSearchParams(window.location.search); lastSearch.subscribe(() => {
if (urlParams.has('search')) { if (initalSearch) {
onSearch(urlParams.get('search'), false); initalSearch = false;
return; if ($postSearchResults === null) onSearch();
return
} }
if ($postSearchResults === null) { onSearch();
onSearch(settings.lastSearch, true);
}
}) })
</script> </script>
<div> <AppShell>
<Header onsubmit={(val = '', explicitRefresh = false) => {onSearch(val, explicitRefresh);}}></Header> {#snippet pageHeader()}
<main>
{#if $showSearch}
<AppBar>
<GlobalSearch />
</AppBar>
{/if}
{/snippet}
{#snippet sidebarLeft()}
<div class="h-dvh">
<AppRail>
{#snippet lead()}
<SearchAppRailAnchor />
{/snippet}
{#snippet trail()}
<AppRailAnchor on:click={() => drawerStore.open()}>
<div class="flex flex-col gap-2 place-content-center">
<Fa size={'2x'} icon={faGear} />
<p>Settings</p>
</div>
</AppRailAnchor>
{/snippet}
</AppRail>
</div>
{/snippet}
{#snippet children()}
<div class="overflow-scroll p-2"> <div class="overflow-scroll p-2">
{#if $postSearchResults} {#if $postSearchResults}
<ImageGrid posts={$postSearchResults} /> <ImageGrid posts={$postSearchResults} />
{/if} {/if}
</div> </div>
</main>
</div> {/snippet}
</AppShell>

View file

@ -1,35 +1,100 @@
<script> <script>
import { faStar, faCaretUp, faCaretDown, faHeart } from '@fortawesome/free-solid-svg-icons'; import {
AppBar,
AppRail,
AppRailAnchor,
AppShell,
getDrawerStore,
clipboard,
getToastStore
} from '@skeletonlabs/skeleton';
import {faGear, faCopy, faStar, faCaretUp, faCaretDown, faHeart} from '@fortawesome/free-solid-svg-icons';
import { Fa } from 'svelte-fa'; import { Fa } from 'svelte-fa';
import { PostMedia } from '$lib/components'; import { BackAppRailAnchor, GlobalSearch, PostMedia, SearchAppRailAnchor } from '$lib/components';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { loading, showSearch } from '$lib/stores';
import { TAG_TYPES } from '$lib/Tags'; import { TAG_TYPES } from '$lib/Tags';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import Header from "$lib/components/Header.svelte";
import {goto} from "$app/navigation";
import {loading} from "$lib/stores.js";
let { data } = $props(); let { data } = $props();
const drawerStore = getDrawerStore();
const tagTypes = Object.entries(TAG_TYPES); const tagTypes = Object.entries(TAG_TYPES);
const toastStore = getToastStore();
/** @type any|null */ /** @type any|null */
let post = $state(null); let post = $state(null);
onMount(async () => { onMount(async () => {
loading.set(true); $loading = true;
post = await invoke('get_post', {postId: +data.postId}); const postRequest = await invoke('get_post', {postId: +data.postId});
loading.set(false); $loading = false;
post = postRequest;
}); });
</script> </script>
<div class="grid [grid-template-areas:'main_main_aside''footer_footer_footer']"> <AppShell>
<Header back={2} onsubmit={(val = '') => { {#snippet pageHeader()}
const queryParams = new URLSearchParams();
queryParams.set('search', val); {#if $showSearch}
goto("/?" + queryParams.toString()) <AppBar>
}}></Header> <GlobalSearch />
</AppBar>
{/if}
{/snippet}
{#snippet sidebarRight()}
{#if post}
<div class="p-2 h-dvh">
{#each tagTypes as [name, label]}
<div class="mb-2">
<p class="font-bold">{label}</p>
{#each post.tags[name] as tag}
<p>{tag}</p>
{/each}
</div>
{/each}
</div>
{/if}
{/snippet}
{#snippet sidebarLeft()}
<div class="h-dvh">
<AppRail>
{#snippet lead()}
<BackAppRailAnchor popCount={2} />
<SearchAppRailAnchor />
{/snippet}
{#snippet trail()}
{#if post}
<AppRailAnchor>
<button class="w-full flex flex-col gap-2 place-content-center place-items-center" onclick={() => toastStore.trigger({message: 'Copied link'})} use:clipboard={`https://e621.net/posts/${post.id}`}>
<Fa size={'2x'} icon={faCopy} />
Copy link
</button>
</AppRailAnchor>
{/if}
<AppRailAnchor on:click={() => drawerStore.open()}>
<button class="w-full flex flex-col gap-2 place-content-center place-items-center">
<Fa size={'2x'} icon={faGear} />
Settings
</button>
</AppRailAnchor>
{/snippet}
</AppRail>
</div>
{/snippet}
{#snippet default()}
<main clasS="h-screen [grid-area-main]">
<div class="container mx-auto flex flex-col items-center justify-center"> <div class="container mx-auto flex flex-col items-center justify-center">
{#if post} {#if post}
<div class="card mb-4 flex flex-col"> <div class="card mb-4 flex flex-col">
@ -70,26 +135,15 @@
<footer class="card-footer pt-4"> <footer class="card-footer pt-4">
<h3 class="font-bold mb-2" class:line-through={post.description === ''} >Description</h3> <h3 class="font-bold mb-2" class:line-through={post.description === ''} >Description</h3>
<p>{post.description}</p> <p>{post.description}</p>
<!-- <pre class="break-all">
{JSON.stringify(post, null, 2)}
</pre> -->
</footer> </footer>
</div> </div>
{/if} {/if}
</div> </div>
</main>
<aside class="[grid-area-aside]"> {/snippet}
{#if post} </AppShell>
<div class="p-2 h-dvh">
{#each tagTypes as [name, label]}
<div class="mb-2">
<p class="font-bold">{label}</p>
{#each post.tags[name] as tag}
<p>{tag}</p>
{/each}
</div>
{/each}
</div>
{/if}
</aside>
</div>
<style lang="postcss"></style> <style lang="postcss"></style>