feat: ui overhaul

This commit is contained in:
Damillora 2025-02-22 13:12:22 +00:00
parent 54ba5835b9
commit 0a79956cca
14 changed files with 711 additions and 158 deletions

View File

@ -20,7 +20,7 @@
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-plugin-svelte": "^2.45.1", "eslint-plugin-svelte": "^2.45.1",
"sass": "^1.64.2", "sass-embedded": "^1.85.0",
"svelte": "^5.0.0", "svelte": "^5.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"svelte-tags-input": "^6.0.2", "svelte-tags-input": "^6.0.2",
@ -43,6 +43,13 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@bufbuild/protobuf": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.3.tgz",
"integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==",
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@ -634,6 +641,7 @@
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"peer": true,
"dependencies": { "dependencies": {
"detect-libc": "^1.0.3", "detect-libc": "^1.0.3",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -676,6 +684,7 @@
"os": [ "os": [
"android" "android"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -697,6 +706,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -718,6 +728,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -739,6 +750,7 @@
"os": [ "os": [
"freebsd" "freebsd"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -760,6 +772,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -781,6 +794,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -802,6 +816,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -823,6 +838,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -844,6 +860,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -865,6 +882,7 @@
"os": [ "os": [
"linux" "linux"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -886,6 +904,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -907,6 +926,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -928,6 +948,7 @@
"os": [ "os": [
"win32" "win32"
], ],
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
@ -1682,6 +1703,13 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/buffer-builder": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz",
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
"dev": true,
"license": "MIT/X11"
},
"node_modules/bulma": { "node_modules/bulma": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.3.tgz", "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.3.tgz",
@ -1761,6 +1789,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
"dev": true,
"license": "MIT"
},
"node_modules/combined-stream": { "node_modules/combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -1878,6 +1913,7 @@
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"optional": true, "optional": true,
"peer": true,
"bin": { "bin": {
"detect-libc": "bin/detect-libc.js" "detect-libc": "bin/detect-libc.js"
}, },
@ -2899,7 +2935,8 @@
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optional": true "optional": true,
"peer": true
}, },
"node_modules/once": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
@ -3330,6 +3367,16 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/sade": { "node_modules/sade": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
@ -3344,11 +3391,13 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.83.4", "version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.0.tgz",
"integrity": "sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==", "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"chokidar": "^4.0.0", "chokidar": "^4.0.0",
"immutable": "^5.0.2", "immutable": "^5.0.2",
@ -3364,6 +3413,407 @@
"@parcel/watcher": "^2.4.1" "@parcel/watcher": "^2.4.1"
} }
}, },
"node_modules/sass-embedded": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.85.0.tgz",
"integrity": "sha512-x3Vv54g0jv1aPSW8OTA/0GzQCs/HMQOjIkLtZJ3Xsn/I4vnyjKbVTQmFTax9bQjldqLEEkdbvy6ES/cOOnYNwA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.0.0",
"buffer-builder": "^0.2.0",
"colorjs.io": "^0.5.0",
"immutable": "^5.0.2",
"rxjs": "^7.4.0",
"supports-color": "^8.1.1",
"sync-child-process": "^1.0.2",
"varint": "^6.0.0"
},
"bin": {
"sass": "dist/bin/sass.js"
},
"engines": {
"node": ">=16.0.0"
},
"optionalDependencies": {
"sass-embedded-android-arm": "1.85.0",
"sass-embedded-android-arm64": "1.85.0",
"sass-embedded-android-ia32": "1.85.0",
"sass-embedded-android-riscv64": "1.85.0",
"sass-embedded-android-x64": "1.85.0",
"sass-embedded-darwin-arm64": "1.85.0",
"sass-embedded-darwin-x64": "1.85.0",
"sass-embedded-linux-arm": "1.85.0",
"sass-embedded-linux-arm64": "1.85.0",
"sass-embedded-linux-ia32": "1.85.0",
"sass-embedded-linux-musl-arm": "1.85.0",
"sass-embedded-linux-musl-arm64": "1.85.0",
"sass-embedded-linux-musl-ia32": "1.85.0",
"sass-embedded-linux-musl-riscv64": "1.85.0",
"sass-embedded-linux-musl-x64": "1.85.0",
"sass-embedded-linux-riscv64": "1.85.0",
"sass-embedded-linux-x64": "1.85.0",
"sass-embedded-win32-arm64": "1.85.0",
"sass-embedded-win32-ia32": "1.85.0",
"sass-embedded-win32-x64": "1.85.0"
}
},
"node_modules/sass-embedded-android-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.85.0.tgz",
"integrity": "sha512-pPBT7Ad6G8Mlao8ypVNXW2ya7I/Bhcny+RYZ/EmrunEXfhzCNp4PWV2VAweitPO9RnPIJwvUTkLc8Fu6K3nVmw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.85.0.tgz",
"integrity": "sha512-4itDzRwezwrW8+YzMLIwHtMeH+qrBNdBsRn9lTVI15K+cNLC8z5JWJi6UCZ8TNNZr9LDBfsh5jUdjSub0yF7jg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.85.0.tgz",
"integrity": "sha512-bwqKq95hzbGbMTeXCMQhH7yEdc2xJVwIXj7rGdD3McvyFWbED6362XRFFPI5YyjfD2wRJd9yWLh/hn+6VyjcYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.85.0.tgz",
"integrity": "sha512-Fgkgay+5EePJXZFHR5Vlkutnsmox2V6nX4U3mfGbSN1xjLRm8F5ST72V2s5Z0mnIFpGvEu/v7hfptgViqMvaxg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.85.0.tgz",
"integrity": "sha512-/bG3JgTn3eoIDHCiJNVkLeJgUesat4ghxqYmKMZUJx++4e6iKCDj8XwQTJAgm+QDrsPKXHBacHEANJ9LEAuTqg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.85.0.tgz",
"integrity": "sha512-plp8TyMz97YFBCB3ndftEvoW29vyfsSBJILM5U84cGzr06SvLh/Npjj8psfUeRw+upEk1zkFtw5u61sRCdgwIw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.85.0.tgz",
"integrity": "sha512-LP8Zv8DG57Gn6PmSwWzC0gEZUsGdg36Ps3m0i1fVTOelql7N3HZIrlPYRjJvidL8ZlB3ISxNANebTREUHn/wkQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.85.0.tgz",
"integrity": "sha512-18xOAEfazJt1MMVS2TRHV94n81VyMnywOoJ7/S7I79qno/zx26OoqqP4XvH107xu8+mZ9Gg54LrUH6ZcgHk08g==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.85.0.tgz",
"integrity": "sha512-JRIRKVOY5Y8M1zlUOv9AQGju4P6lj8i5vLJZsVYVN/uY8Cd2dDJZPC8EOhjntp+IpF8AOGIHqCeCkHBceIyIjA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.85.0.tgz",
"integrity": "sha512-4JH+h+gLt9So22nNPQtsKojEsLzjld9ol3zWcOtMGclv+HojZGbCuhJUrLUcK72F8adXYsULmWhJPKROLIwYMA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.85.0.tgz",
"integrity": "sha512-Z1j4ageDVFihqNUBnm89fxY46pY0zD/Clp1D3ZdI7S+D280+AEpbm5vMoH8LLhBQfQLf2w7H++SZGpQwrisudQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.85.0.tgz",
"integrity": "sha512-aoQjUjK28bvdw9XKTjQeayn8oWQ2QqvoTD11myklGd3IHH7Jj0nwXUstI4NxDueCKt3wghuZoIQkjOheReQxlg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.85.0.tgz",
"integrity": "sha512-/cJCSXOfXmQFH8deE+3U9x+BSz8i0d1Tt9gKV/Gat1Xm43Oumw8pmZgno+cDuGjYQInr9ryW5121pTMlj/PBXQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.85.0.tgz",
"integrity": "sha512-l+FJxMXkmg42RZq5RFKXg4InX0IA7yEiPHe4kVSdrczP7z3NLxk+W9wVkPnoRKYIMe1qZPPQ25y0TgI4HNWouA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.85.0.tgz",
"integrity": "sha512-M9ffjcYfFcRvkFA6V3DpOS955AyvmpvPAhL/xNK45d/ma1n1ehTWpd24tVeKiNK5CZkNjjMEfyw2fHa6MpqmEA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.85.0.tgz",
"integrity": "sha512-yqPXQWfM+qiIPkfn++48GOlbmSvUZIyL9nwFstBk0k4x40UhbhilfknqeTUpxoHfQzylTGVhrm5JE7MjM+LNZA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.85.0.tgz",
"integrity": "sha512-NTDeQFZcuVR7COoaRy8pZD6/+QznwBR8kVFsj7NpmvX9aJ7TX/q+OQZHX7Bfb3tsfKXhf1YZozegPuYxRnMKAQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.85.0.tgz",
"integrity": "sha512-gO0VAuxC4AdV+uZYJESRWVVHQWCGzNs0C3OKCAdH4r1vGRugooMi7J/5wbwUdXDA1MV9ICfhlKsph2n3GiPdqA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.85.0.tgz",
"integrity": "sha512-PCyn6xeFIBUgBceNypuf73/5DWF2VWPlPqPuBprPsTvpZOMUJeBtP+Lf4mnu3dNy1z76mYVnpaCnQmzZ0zHZaA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.85.0.tgz",
"integrity": "sha512-AknE2jLp6OBwrR5hQ8pDsG94KhJCeSheFJ2xgbnk8RUjZX909JiNbgh2sNt9LG+RXf4xZa55dDL537gZoCx/iw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.1", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
@ -3635,6 +4085,29 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/sync-child-process": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
"integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"sync-message-port": "^1.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/sync-message-port": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz",
"integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/text-table": { "node_modules/text-table": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -3752,6 +4225,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
"dev": true,
"license": "MIT"
},
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.14", "version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",

View File

@ -18,7 +18,7 @@
"@typescript-eslint/parser": "^5.45.0", "@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0", "eslint": "^8.28.0",
"eslint-plugin-svelte": "^2.45.1", "eslint-plugin-svelte": "^2.45.1",
"sass": "^1.64.2", "sass-embedded": "^1.85.0",
"svelte": "^5.0.0", "svelte": "^5.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^4.0.0",
"svelte-tags-input": "^6.0.2", "svelte-tags-input": "^6.0.2",

View File

@ -1,12 +1,12 @@
/* Write your global styles here, in SCSS syntax. Variables and mixins from the src/variables.scss file are available here without importing */ /* Write your global styles here, in SCSS syntax. Variables and mixins from the src/variables.scss file are available here without importing */
// Path to Bulma's sass folder // Path to Bulma's sass folder
@use "bulma/sass" with ( @use "../node_modules/bulma/sass/" as * with (
$family-primary: '"Nunito", sans-serif', $family-primary: '"Nunito", sans-serif',
$primary: #00afcc, $primary: #37b484,
); );
// Import the Google Font // Import the Google Font
@import url("https://fonts.googleapis.com/css?family=Nunito:400,700"); @import "https://fonts.googleapis.com/css?family=Nunito:400,700";
// Others // Others
@ -19,6 +19,9 @@
} }
// Svelte Tags // Svelte Tags
#tags {
position: relative;
}
#tags .svelte-tags-input-layout { #tags .svelte-tags-input-layout {
@extend .input; @extend .input;
padding: 0; padding: 0;
@ -43,5 +46,28 @@
margin-right: var(--bulma-control-padding-horizontal); margin-right: var(--bulma-control-padding-horizontal);
} }
#tags .svelte-tags-input-matchs-parent{ #tags .svelte-tags-input-matchs-parent{
@extend .dropdown-menu;
display: block;
position: relative;
z-index: 2000; z-index: 2000;
} }
#tags .svelte-tags-input-matchs {
@extend .dropdown-content;
position: absolute;
top: 0;
left: 0;
right: 0;
li {
@extend .dropdown-item;
background-color: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), calc(var(--bulma-scheme-main-l) + var(--bulma-dropdown-item-background-l-delta)));
--bulma-dropdown-item-background-l-delta: 0%;
&:hover {
--bulma-dropdown-item-background-l-delta: var(--bulma-hover-background-l-delta);
--bulma-dropdown-item-border-l-delta: var(--bulma-hover-border-l-delta);
}
transition-duration: var(--bulma-duration);
transition-property: background-color, border-color, color;
}
}

View File

@ -62,23 +62,18 @@ export async function getTagAutocomplete({ tag, positive }) {
const response = await axios.get(endpoint); const response = await axios.get(endpoint);
return response.data; return response.data;
} }
export async function getPosts({ page }) { export async function getPosts({ page, q, perPage }: { page: any, q?: any, perPage?: any }) {
const endpoint = url + "/api/post?page=" + page; if (!perPage) {
perPage = 20;
}
let endpoint = url + "/api/post?page=" + page + "&perPage=" + perPage;
if (q) {
endpoint = url + "/api/post?tags=" + q + "&page=" + page + "&perPage=" + perPage;
}
const response = await axios.get(endpoint); const response = await axios.get(endpoint);
return response.data; return response.data;
} }
export async function getPostSearchTag({ page, q }) {
if (q) {
const endpoint = url + "/api/post?tags=" + q + "&page=" + page;
const response = await axios(endpoint);
return response.data;
} else {
const endpoint = url + "/api/post?page=" + page;
const response = await axios(endpoint);
return response.data;
}
}
export async function getPost({ id }) { export async function getPost({ id }) {
const endpoint = url + "/api/post/" + id; const endpoint = url + "/api/post/" + id;
@ -86,6 +81,12 @@ export async function getPost({ id }) {
return response.data; return response.data;
} }
export async function getPostCount() {
const endpoint = url + "/api/post-count";
const response = await axios(endpoint);
return response.data;
}
export async function uploadBlob({ file, onProgress }) { export async function uploadBlob({ file, onProgress }) {
var formData = new FormData(); var formData = new FormData();
formData.append("file", file); formData.append("file", file);

View File

@ -6,6 +6,14 @@
let tagDisplay = tagName.split("_").join(" "); let tagDisplay = tagName.split("_").join(" ");
</script> </script>
<a href="/posts?tags={tagName}" <a href="/posts?tags={tagName}">
>{tagDisplay} <span class="is-pulled-right">{num}</span></a {tagDisplay}
> {#if tagType == "character"}
<span class="tag is-link is-light">character</span>
{:else if tagType == "series"}
<span class="tag is-warning is-light">series</span>
{:else}
<span class="tag">{tagType}</span>
{/if}
<span class="is-pulled-right">{num}</span>
</a>

View File

@ -17,3 +17,11 @@
<Navbar /> <Navbar />
{@render children?.()} {@render children?.()}
<footer class="footer">
<div class="content has-text-centered">
<p>
<strong><a href="https://github.com/Damillora/Shioriko">Shioriko</a></strong>: a booru-style image gallery written in Go and Svelte
</p>
</div>
</footer>

View File

@ -1 +0,0 @@
export const ssr = false;

View File

@ -1,19 +1,22 @@
<script lang="ts"> <script lang="ts">
import Tags from "svelte-tags-input"; import Tags from "svelte-tags-input";
import { getTagAutocomplete } from "$lib/api"; import { getPostCount, getPosts, getTagAutocomplete } from "$lib/api";
import { goto } from '$app/navigation'; import { goto } from "$app/navigation";
import { onMount } from "svelte";
import PostGallery from "$lib/components/ui/PostGallery.svelte";
let searchTerms: string[] = $state([]); let searchTerms: string[] = $state([]);
let postCount: number = $state(0);
const onTagChange = (value) => { const onTagChange = (value) => {
searchTerms = value.detail.tags; searchTerms = value.detail.tags;
}; };
const onAutocomplete = async (tag) => { const onAutocomplete = async (tag) => {
const list = await getTagAutocomplete({ tag }); const list = await getTagAutocomplete({ tag });
return list; return list;
}; };
const onSearch = (e) => { const onSearch = (e) => {
e.preventDefault(); e.preventDefault();
@ -23,35 +26,48 @@
goto(`/posts`); goto(`/posts`);
} }
}; };
const getCounts = async () => {
const response = await getPostCount();
postCount = response.postCount;
};
onMount(() => {
getCounts();
});
</script> </script>
<section class="hero is-small"> <section class="hero is-primary is-fullheight-with-navbar">
<div class="hero-body"> <div class="hero-body">
<div class="container has-text-centered"> <div class="container">
<p class="title">Shioriko</p> <div class="columns is-centered">
<p class="subtitle">Booru-style gallery written in Go and Svelte</p> <div class="column is-12-tablet is-8-desktop is-8-widescreen">
</div> <div class="box has-text-centered">
</div> <p class="title">Shioriko</p>
<div class="hero-foot"> <p class="subtitle">Booru-style gallery written in Go and Svelte</p>
<div class="container has-text-centered"> <div class="block">
<form onsubmit={onSearch}> <form onsubmit={onSearch}>
<div class="field has-addons"> <div class="field">
<div class="control has-text-left is-expanded"> <div class="control has-text-left is-expanded" id="tags">
<div class="control" id="tags"> <Tags
<Tags tags={searchTerms}
tags={searchTerms} addKeys={[9, 32]}
addKeys={[9, 32]} on:tags={onTagChange}
on:tags={onTagChange} autoComplete={onAutocomplete}
autoComplete={onAutocomplete} autoCompleteFilter={false}
autoCompleteFilter={false} />
/> </div>
</div>
<div class="control">
<button type="submit" class="button is-primary">
Search
</button>
</div>
</form>
</div> </div>
<p class="block">Serving <strong>{postCount}</strong> images</p>
</div> </div>
</div> </div>
<div class="control"> </div>
<button type="submit" class="button is-primary"> Search </button>
</div>
</form>
</div> </div>
</div> </div>
</section> </section>

View File

@ -0,0 +1,17 @@
<script lang="ts">
import Navbar from "$lib/components/ui/Navbar.svelte";
interface Props {
children?: import('svelte').Snippet;
}
let { children }: Props = $props();
export const ssr = false;
</script>
<section class="hero is-primary is-fullheight-with-navbar">
<div class="hero-body">
{@render children?.()}
</div>
</section>

View File

@ -19,51 +19,50 @@
}; };
</script> </script>
<section class="hero is-primary"> <div class="container">
<div class="hero-body"> <div class="columns is-centered">
<p class="title">Login</p> <div class="column is-5-tablet is-4-desktop is-3-widescreen">
<div class="box">
<p class="title">Login</p>
<form onsubmit={doLogin}>
<div class="field">
<label for="username" class="label">Username</label>
<div class="control">
<input
id="username"
class="input"
type="text"
placeholder="Username"
bind:value={username}
required
/>
</div>
</div>
<div class="field">
<label for="password" class="label">Password</label>
<div class="control">
<input
id="password"
class="input"
type="password"
placeholder="Password"
bind:value={password}
required
/>
</div>
</div>
{#if error}
<div class="field">
<p class="has-text-danger">{error}</p>
</div>
{/if}
<div class="field">
<div class="control">
<button class="button is-link">Login</button>
</div>
</div>
</form>
</div>
</div>
</div> </div>
</section> </div>
<section class="section">
<div class="container">
<form onsubmit={doLogin}>
<div class="field">
<label for="username" class="label">Username</label>
<div class="control">
<input
id="username"
class="input"
type="text"
placeholder="Username"
bind:value={username}
required
/>
</div>
</div>
<div class="field">
<label for="password" class="label">Password</label>
<div class="control">
<input
id="password"
class="input"
type="password"
placeholder="Password"
bind:value={password}
required
/>
</div>
</div>
{#if error}
<div class="field">
<p class="has-text-danger">{error}</p>
</div>
{/if}
<div class="field">
<div class="control">
<button class="button is-link">Login</button>
</div>
</div>
</form>
</div>
</section>

View File

@ -18,57 +18,58 @@
}; };
</script> </script>
<section class="hero is-primary">
<div class="hero-body">
<p class="title">Register</p>
</div>
</section>
<div class="container"> <div class="container">
<form onsubmit={doRegister}> <div class="columns is-centered">
<div class="field"> <div class="column is-5-tablet is-4-desktop is-3-widescreen">
<label for="email" class="label">Email</label> <div class="box">
<div class="control"> <p class="title">Register</p>
<input <form onsubmit={doRegister}>
id="email" <div class="field">
class="input" <label for="email" class="label">Email</label>
type="text" <div class="control">
placeholder="Email" <input
bind:value={email} id="email"
required class="input"
/> type="text"
placeholder="Email"
bind:value={email}
required
/>
</div>
</div>
<div class="field">
<label for="username" class="label">Username</label>
<div class="control">
<input
id="username"
class="input"
type="text"
placeholder="Username"
bind:value={username}
required
/>
</div>
</div>
<div class="field">
<label for="password" class="label">Password</label>
<div class="control">
<input
id="password"
class="input"
type="password"
placeholder="Password"
bind:value={password}
required
/>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-link">Login</button>
</div>
</div>
</form>
</div> </div>
</div> </div>
<div class="field"> </div>
<label for="username" class="label">Username</label>
<div class="control">
<input
id="username"
class="input"
type="text"
placeholder="Username"
bind:value={username}
required
/>
</div>
</div>
<div class="field">
<label for="password" class="label">Password</label>
<div class="control">
<input
id="password"
class="input"
type="password"
placeholder="Password"
bind:value={password}
required
/>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-link">Login</button>
</div>
</div>
</form>
</div> </div>

View File

@ -1,6 +1,4 @@
<script lang="ts"> <script lang="ts">
import { run } from "svelte/legacy";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getPost, postDelete } from "$lib/api"; import { getPost, postDelete } from "$lib/api";
import { afterNavigate, goto } from "$app/navigation"; import { afterNavigate, goto } from "$app/navigation";
@ -17,7 +15,7 @@
imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%"; imagePercentage = ((1000 * 100) / post.width).toFixed(0) + "%";
}; };
const trimUrl = (str) => { const trimUrl = (str: string) => {
if (str.length > 30) { if (str.length > 30) {
return str.substring(0, 30) + "..."; return str.substring(0, 30) + "...";
} }

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { run } from 'svelte/legacy'; import { run } from 'svelte/legacy';
import { getPostSearchTag, getTag, getTagAutocomplete } from "$lib/api"; import { getPosts, getTag, getTagAutocomplete } from "$lib/api";
import TagLinkNumbered from "$lib/components/ui/TagLinkNumbered.svelte"; import TagLinkNumbered from "$lib/components/ui/TagLinkNumbered.svelte";
import PostGallery from "$lib/components/ui/PostGallery.svelte"; import PostGallery from "$lib/components/ui/PostGallery.svelte";
import queryString from "query-string"; import queryString from "query-string";
@ -25,7 +25,7 @@
let categorizedTags = {}; let categorizedTags = {};
const getData = async () => { const getData = async () => {
const data = await getPostSearchTag({ page, q: searchTerms.join("+") }); const data = await getPosts({ page, q: searchTerms.join("+") });
if (data.posts) { if (data.posts) {
posts = data.posts; posts = data.posts;
tags = data.tags tags = data.tags

View File

@ -1,7 +1,7 @@
<script> <script>
import { onMount } from "svelte"; import { onMount } from "svelte";
import { getTag, getPostSearchTag } from "$lib/api"; import { getTag, getPosts } from "$lib/api";
import EditTagNotesPanel from "$lib/components/panels/EditTagNotesPanel.svelte"; import EditTagNotesPanel from "$lib/components/panels/EditTagNotesPanel.svelte";
import ViewTagNotesPanel from "$lib/components/panels/ViewTagNotesPanel.svelte"; import ViewTagNotesPanel from "$lib/components/panels/ViewTagNotesPanel.svelte";
import ViewTagPanel from "$lib/components/panels/ViewTagPanel.svelte"; import ViewTagPanel from "$lib/components/panels/ViewTagPanel.svelte";
@ -18,7 +18,7 @@
const getData = async () => { const getData = async () => {
if (tag) { if (tag) {
data = await getTag({ tag }); data = await getTag({ tag });
const response = await getPostSearchTag({ const response = await getPosts({
page: 1, page: 1,
q: tag, q: tag,
}); });