From 3eafb413a48cde60dea8a7355ee621c6acca952f Mon Sep 17 00:00:00 2001
From: Doog <157747121+doogongithub@users.noreply.github.com>
Date: Wed, 21 Feb 2024 22:07:27 -0500
Subject: first commit
---
fe/.gitignore | 24 +
fe/.vscode/extensions.json | 3 +
fe/README.md | 47 ++
fe/index.html | 13 +
fe/package-lock.json | 1772 ++++++++++++++++++++++++++++++++++++++++++++
fe/package.json | 21 +
fe/public/vite.svg | 1 +
fe/src/App.svelte | 167 +++++
fe/src/app.css | 111 +++
fe/src/assets/svelte.svg | 1 +
fe/src/lib/Card.svelte | 22 +
fe/src/lib/Counter.svelte | 10 +
fe/src/lib/Table.svelte | 41 +
fe/src/lib/errors.ts | 7 +
fe/src/lib/utils.ts | 9 +
fe/src/main.ts | 8 +
fe/src/vite-env.d.ts | 2 +
fe/svelte.config.js | 7 +
fe/tsconfig.json | 20 +
fe/tsconfig.node.json | 10 +
fe/vite.config.ts | 7 +
21 files changed, 2303 insertions(+)
create mode 100644 fe/.gitignore
create mode 100644 fe/.vscode/extensions.json
create mode 100644 fe/README.md
create mode 100644 fe/index.html
create mode 100644 fe/package-lock.json
create mode 100644 fe/package.json
create mode 100644 fe/public/vite.svg
create mode 100644 fe/src/App.svelte
create mode 100644 fe/src/app.css
create mode 100644 fe/src/assets/svelte.svg
create mode 100644 fe/src/lib/Card.svelte
create mode 100644 fe/src/lib/Counter.svelte
create mode 100644 fe/src/lib/Table.svelte
create mode 100644 fe/src/lib/errors.ts
create mode 100644 fe/src/lib/utils.ts
create mode 100644 fe/src/main.ts
create mode 100644 fe/src/vite-env.d.ts
create mode 100644 fe/svelte.config.js
create mode 100644 fe/tsconfig.json
create mode 100644 fe/tsconfig.node.json
create mode 100644 fe/vite.config.ts
(limited to 'fe')
diff --git a/fe/.gitignore b/fe/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/fe/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/fe/.vscode/extensions.json b/fe/.vscode/extensions.json
new file mode 100644
index 0000000..bdef820
--- /dev/null
+++ b/fe/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["svelte.svelte-vscode"]
+}
diff --git a/fe/README.md b/fe/README.md
new file mode 100644
index 0000000..e6cd94f
--- /dev/null
+++ b/fe/README.md
@@ -0,0 +1,47 @@
+# Svelte + TS + Vite
+
+This template should help get you started developing with Svelte and TypeScript in Vite.
+
+## Recommended IDE Setup
+
+[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
+
+## Need an official Svelte framework?
+
+Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
+
+## Technical considerations
+
+**Why use this over SvelteKit?**
+
+- It brings its own routing solution which might not be preferable for some users.
+- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
+
+This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
+
+Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate.
+
+**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
+
+Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information.
+
+**Why include `.vscode/extensions.json`?**
+
+Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project.
+
+**Why enable `allowJs` in the TS template?**
+
+While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant.
+
+**Why is HMR not preserving my local component state?**
+
+HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr).
+
+If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
+
+```ts
+// store.ts
+// An extremely simple external store
+import { writable } from 'svelte/store'
+export default writable(0)
+```
diff --git a/fe/index.html b/fe/index.html
new file mode 100644
index 0000000..b6c5f0a
--- /dev/null
+++ b/fe/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Svelte + TS
+
+
+
+
+
+
diff --git a/fe/package-lock.json b/fe/package-lock.json
new file mode 100644
index 0000000..2c4146a
--- /dev/null
+++ b/fe/package-lock.json
@@ -0,0 +1,1772 @@
+{
+ "name": "fe",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "fe",
+ "version": "0.0.0",
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.2",
+ "@tsconfig/svelte": "^5.0.2",
+ "svelte": "^4.2.10",
+ "svelte-check": "^3.6.3",
+ "tslib": "^2.6.2",
+ "typescript": "^5.2.2",
+ "vite": "^5.1.0"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+ "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.0",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
+ "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
+ "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
+ "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
+ "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
+ "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
+ "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
+ "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
+ "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
+ "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
+ "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
+ "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
+ "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
+ "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
+ "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
+ "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
+ "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
+ "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
+ "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
+ "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
+ "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
+ "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
+ "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
+ "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+ "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.9"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.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/set-array": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.15",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.22",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
+ "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
+ "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz",
+ "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz",
+ "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz",
+ "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz",
+ "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz",
+ "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz",
+ "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz",
+ "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz",
+ "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz",
+ "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz",
+ "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz",
+ "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz",
+ "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz",
+ "integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==",
+ "dev": true,
+ "dependencies": {
+ "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0",
+ "debug": "^4.3.4",
+ "deepmerge": "^4.3.1",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.5",
+ "svelte-hmr": "^0.15.3",
+ "vitefu": "^0.2.5"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20"
+ },
+ "peerDependencies": {
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz",
+ "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
+ "vite": "^5.0.0"
+ }
+ },
+ "node_modules/@tsconfig/svelte": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz",
+ "integrity": "sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==",
+ "dev": true
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+ "dev": true
+ },
+ "node_modules/@types/pug": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz",
+ "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
+ "dev": true
+ },
+ "node_modules/acorn": {
+ "version": "8.11.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
+ "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "dev": true,
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
+ "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
+ "dev": true,
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/code-red": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
+ "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "@types/estree": "^1.0.1",
+ "acorn": "^8.10.0",
+ "estree-walker": "^3.0.3",
+ "periscopic": "^3.1.0"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "dev": true,
+ "dependencies": {
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "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/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/detect-indent": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/es6-promise": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
+ "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==",
+ "dev": true
+ },
+ "node_modules/esbuild": {
+ "version": "0.19.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
+ "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.19.12",
+ "@esbuild/android-arm": "0.19.12",
+ "@esbuild/android-arm64": "0.19.12",
+ "@esbuild/android-x64": "0.19.12",
+ "@esbuild/darwin-arm64": "0.19.12",
+ "@esbuild/darwin-x64": "0.19.12",
+ "@esbuild/freebsd-arm64": "0.19.12",
+ "@esbuild/freebsd-x64": "0.19.12",
+ "@esbuild/linux-arm": "0.19.12",
+ "@esbuild/linux-arm64": "0.19.12",
+ "@esbuild/linux-ia32": "0.19.12",
+ "@esbuild/linux-loong64": "0.19.12",
+ "@esbuild/linux-mips64el": "0.19.12",
+ "@esbuild/linux-ppc64": "0.19.12",
+ "@esbuild/linux-riscv64": "0.19.12",
+ "@esbuild/linux-s390x": "0.19.12",
+ "@esbuild/linux-x64": "0.19.12",
+ "@esbuild/netbsd-x64": "0.19.12",
+ "@esbuild/openbsd-x64": "0.19.12",
+ "@esbuild/sunos-x64": "0.19.12",
+ "@esbuild/win32-arm64": "0.19.12",
+ "@esbuild/win32-ia32": "0.19.12",
+ "@esbuild/win32-x64": "0.19.12"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": 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/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
+ "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "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.7",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
+ "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "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/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/periscopic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
+ "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^3.0.0",
+ "is-reference": "^3.0.0"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
+ "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
+ "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.7",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz",
+ "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "1.0.5"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.12.0",
+ "@rollup/rollup-android-arm64": "4.12.0",
+ "@rollup/rollup-darwin-arm64": "4.12.0",
+ "@rollup/rollup-darwin-x64": "4.12.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.12.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.12.0",
+ "@rollup/rollup-linux-arm64-musl": "4.12.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.12.0",
+ "@rollup/rollup-linux-x64-gnu": "4.12.0",
+ "@rollup/rollup-linux-x64-musl": "4.12.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.12.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.12.0",
+ "@rollup/rollup-win32-x64-msvc": "4.12.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/sade": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
+ "dev": true,
+ "dependencies": {
+ "mri": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/sander": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
+ "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==",
+ "dev": true,
+ "dependencies": {
+ "es6-promise": "^3.1.2",
+ "graceful-fs": "^4.1.3",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.2"
+ }
+ },
+ "node_modules/sorcery": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz",
+ "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.14",
+ "buffer-crc32": "^0.2.5",
+ "minimist": "^1.2.0",
+ "sander": "^0.5.0"
+ },
+ "bin": {
+ "sorcery": "bin/sorcery"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.11.tgz",
+ "integrity": "sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.15",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "@types/estree": "^1.0.1",
+ "acorn": "^8.9.0",
+ "aria-query": "^5.3.0",
+ "axobject-query": "^4.0.0",
+ "code-red": "^1.0.3",
+ "css-tree": "^2.3.1",
+ "estree-walker": "^3.0.3",
+ "is-reference": "^3.0.1",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.4",
+ "periscopic": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/svelte-check": {
+ "version": "3.6.4",
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.4.tgz",
+ "integrity": "sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.17",
+ "chokidar": "^3.4.1",
+ "fast-glob": "^3.2.7",
+ "import-fresh": "^3.2.1",
+ "picocolors": "^1.0.0",
+ "sade": "^1.7.4",
+ "svelte-preprocess": "^5.1.0",
+ "typescript": "^5.0.3"
+ },
+ "bin": {
+ "svelte-check": "bin/svelte-check"
+ },
+ "peerDependencies": {
+ "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0"
+ }
+ },
+ "node_modules/svelte-hmr": {
+ "version": "0.15.3",
+ "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
+ "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20 || ^14.13.1 || >= 16"
+ },
+ "peerDependencies": {
+ "svelte": "^3.19.0 || ^4.0.0"
+ }
+ },
+ "node_modules/svelte-preprocess": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz",
+ "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "@types/pug": "^2.0.6",
+ "detect-indent": "^6.1.0",
+ "magic-string": "^0.30.5",
+ "sorcery": "^0.11.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "pnpm": "^8.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
+ }
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
+ "dev": true
+ },
+ "node_modules/typescript": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
+ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.3.tgz",
+ "integrity": "sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.19.3",
+ "postcss": "^8.4.35",
+ "rollup": "^4.2.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.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",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
+ "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
+ "dev": true,
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/fe/package.json b/fe/package.json
new file mode 100644
index 0000000..6bc8619
--- /dev/null
+++ b/fe/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "fe",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-check --tsconfig ./tsconfig.json"
+ },
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^3.0.2",
+ "@tsconfig/svelte": "^5.0.2",
+ "svelte": "^4.2.10",
+ "svelte-check": "^3.6.3",
+ "tslib": "^2.6.2",
+ "typescript": "^5.2.2",
+ "vite": "^5.1.0"
+ }
+}
diff --git a/fe/public/vite.svg b/fe/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/fe/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fe/src/App.svelte b/fe/src/App.svelte
new file mode 100644
index 0000000..cc4e594
--- /dev/null
+++ b/fe/src/App.svelte
@@ -0,0 +1,167 @@
+
+
+
+ {#if !authenticated}
+
+
+
+ {:else}
+
+ Logout
+
+
+
+
+ Get Data
+
+
+ {#await data}
+ ...fetching
+ {:then data}
+ {#if data}
+ Status
+ {data.status}
+
+
+
+ {:else}
+ No data yet
+ {/if}
+ {:catch errror}
+ {error.message}
+ {/await}
+ {/if}
+
+
+
diff --git a/fe/src/app.css b/fe/src/app.css
new file mode 100644
index 0000000..4768cf6
--- /dev/null
+++ b/fe/src/app.css
@@ -0,0 +1,111 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+
+ --submit: #28a745;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+.card {
+ padding: 2em;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ color: #000;
+ }
+}
+
+.form {
+ display: flex;
+ flex-direction: column;
+}
+
+.form.input.group {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 1em;
+}
+
+.form.input.group label {
+ margin-bottom: .5em;
+}
+
+.form.input.group input {
+ padding: 1em;
+}
+
+.form button[type=submit] {
+ align-self: flex-end;
+ background: var(--submit);
+ color: #fff;
+}
diff --git a/fe/src/assets/svelte.svg b/fe/src/assets/svelte.svg
new file mode 100644
index 0000000..c5e0848
--- /dev/null
+++ b/fe/src/assets/svelte.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fe/src/lib/Card.svelte b/fe/src/lib/Card.svelte
new file mode 100644
index 0000000..feb5bcc
--- /dev/null
+++ b/fe/src/lib/Card.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {#if title}
+
{title}
+ {/if}
+
+
+
+
diff --git a/fe/src/lib/Counter.svelte b/fe/src/lib/Counter.svelte
new file mode 100644
index 0000000..979b4df
--- /dev/null
+++ b/fe/src/lib/Counter.svelte
@@ -0,0 +1,10 @@
+
+
+
+ count is {count}
+
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
new file mode 100644
index 0000000..2df9f8c
--- /dev/null
+++ b/fe/src/lib/Table.svelte
@@ -0,0 +1,41 @@
+
+
+ {#if title}
+ {title}
+ {/if}
+ {#if !noheader}
+
+
+
+ Data Header
+
+
+
+ {/if}
+
+
+ Data
+
+
+ {#if !nofooter}
+
+
+
+ Table Footer
+
+
+
+ {/if}
+
+
diff --git a/fe/src/lib/errors.ts b/fe/src/lib/errors.ts
new file mode 100644
index 0000000..0663d63
--- /dev/null
+++ b/fe/src/lib/errors.ts
@@ -0,0 +1,7 @@
+export class UnauthorizedError extends Error {
+ constructor (message?: string , options?: ErrorOptions) {
+ super(message, options);
+ }
+}
+
+
diff --git a/fe/src/lib/utils.ts b/fe/src/lib/utils.ts
new file mode 100644
index 0000000..c5501ae
--- /dev/null
+++ b/fe/src/lib/utils.ts
@@ -0,0 +1,9 @@
+export function processFormInput(form) {
+ const formData = new FormData(form);
+ const data = {};
+ for (let field of formData) {
+ const [key, value] = field;
+ data[key] = value;
+ }
+ return data;
+}
diff --git a/fe/src/main.ts b/fe/src/main.ts
new file mode 100644
index 0000000..8a909a1
--- /dev/null
+++ b/fe/src/main.ts
@@ -0,0 +1,8 @@
+import './app.css'
+import App from './App.svelte'
+
+const app = new App({
+ target: document.getElementById('app'),
+})
+
+export default app
diff --git a/fe/src/vite-env.d.ts b/fe/src/vite-env.d.ts
new file mode 100644
index 0000000..4078e74
--- /dev/null
+++ b/fe/src/vite-env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/fe/svelte.config.js b/fe/svelte.config.js
new file mode 100644
index 0000000..b0683fd
--- /dev/null
+++ b/fe/svelte.config.js
@@ -0,0 +1,7 @@
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+export default {
+ // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
+ // for more information about preprocessors
+ preprocess: vitePreprocess(),
+}
diff --git a/fe/tsconfig.json b/fe/tsconfig.json
new file mode 100644
index 0000000..5fb548f
--- /dev/null
+++ b/fe/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "@tsconfig/svelte/tsconfig.json",
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "resolveJsonModule": true,
+ /**
+ * Typecheck JS in `.svelte` and `.js` files by default.
+ * Disable checkJs if you'd like to use dynamic types in JS.
+ * Note that setting allowJs false does not prevent the use
+ * of JS in `.svelte` files.
+ */
+ "allowJs": true,
+ "checkJs": true,
+ "isolatedModules": true
+ },
+ "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/fe/tsconfig.node.json b/fe/tsconfig.node.json
new file mode 100644
index 0000000..d02c37d
--- /dev/null
+++ b/fe/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "strict": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/fe/vite.config.ts b/fe/vite.config.ts
new file mode 100644
index 0000000..d701969
--- /dev/null
+++ b/fe/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import { svelte } from '@sveltejs/vite-plugin-svelte'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [svelte()],
+})
--
cgit v1.1
From e37c73e33a4aaf7fb8d25b5af03627f20bcda19f Mon Sep 17 00:00:00 2001
From: Doog <157747121+doogongithub@users.noreply.github.com>
Date: Sat, 24 Feb 2024 20:08:35 -0500
Subject: add gitignore
---
fe/src/App.svelte | 147 +++-----------------------------------------
fe/src/app.css | 2 +-
fe/src/lib/DataView.svelte | 67 ++++++++++++++++++++
fe/src/lib/Layout.svelte | 57 +++++++++++++++++
fe/src/lib/LoginForm.svelte | 64 +++++++++++++++++++
fe/src/lib/Table.svelte | 61 +++++++++++++++---
fe/src/stores/auth.ts | 48 +++++++++++++++
fe/svelte.config.js | 1 +
8 files changed, 301 insertions(+), 146 deletions(-)
create mode 100644 fe/src/lib/DataView.svelte
create mode 100644 fe/src/lib/Layout.svelte
create mode 100644 fe/src/lib/LoginForm.svelte
create mode 100644 fe/src/stores/auth.ts
(limited to 'fe')
diff --git a/fe/src/App.svelte b/fe/src/App.svelte
index cc4e594..8811c52 100644
--- a/fe/src/App.svelte
+++ b/fe/src/App.svelte
@@ -1,146 +1,19 @@
- {#if !authenticated}
-
-
-
+
+ {#if !$authenticated}
+
{:else}
-
- Logout
-
-
-
-
- Get Data
-
-
- {#await data}
- ...fetching
- {:then data}
- {#if data}
- Status
- {data.status}
-
-
-
- {:else}
- No data yet
- {/if}
- {:catch errror}
- {error.message}
- {/await}
+
{/if}
+
diff --git a/fe/src/lib/LoginForm.svelte b/fe/src/lib/LoginForm.svelte
new file mode 100644
index 0000000..22c0faf
--- /dev/null
+++ b/fe/src/lib/LoginForm.svelte
@@ -0,0 +1,64 @@
+
+
+
+
+
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
index 2df9f8c..5572280 100644
--- a/fe/src/lib/Table.svelte
+++ b/fe/src/lib/Table.svelte
@@ -1,8 +1,38 @@
{#if title}
@@ -11,16 +41,27 @@
{#if !noheader}
-
- Data Header
-
+ {#each getDataKeys(data) as header}
+ {header}
+ {/each}
{/if}
+ {#if data}
+ {#each data as row}
- Data
+ {#each getRow(row) as datum}
+
+ {formatDatum(datum)}
+ {/each}
+ {/each}
+ {:else}
+
+ There is not data.
+
+ {/if}
{#if !nofooter}
@@ -38,4 +79,8 @@ table {
margin: 8px;
border: solid 1px black;
}
+
+th {
+ text-transform: capitalize;
+}
diff --git a/fe/src/stores/auth.ts b/fe/src/stores/auth.ts
new file mode 100644
index 0000000..7e70cda
--- /dev/null
+++ b/fe/src/stores/auth.ts
@@ -0,0 +1,48 @@
+import type { Invalidator, Subscriber, Unsubscriber } from 'svelte/store';
+import { writable, derived } from 'svelte/store';
+
+type Nullable = T | null;
+
+interface User {
+ uuid: string;
+ username: string;
+}
+
+interface TokenStore {
+ subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
+ authenticate: (newToken: string) => void,
+ unauthenticate: () => void
+}
+
+function createTokenStore(): TokenStore {
+ const storedToken = localStorage.getItem("token");
+ const { subscribe, set } = writable(storedToken);
+
+ function authenticate(newToken: string): void {
+ try {
+ localStorage.setItem("token", newToken);
+ set(newToken);
+ } catch (e) {
+ console.error('error', e);
+ }
+ }
+
+ function unauthenticate(): void {
+ localStorage.removeItem("token");
+ set(null);
+ }
+
+ return {
+ subscribe,
+ authenticate,
+ unauthenticate
+ };
+}
+
+function onTokenChange ($token: Nullable): boolean {
+ return $token ? true : false;
+}
+
+export const token = createTokenStore();
+export const authenticated = derived(token, onTokenChange);
+export const user = writable(null);
diff --git a/fe/svelte.config.js b/fe/svelte.config.js
index b0683fd..b29bf40 100644
--- a/fe/svelte.config.js
+++ b/fe/svelte.config.js
@@ -4,4 +4,5 @@ export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
+ dev: true
}
--
cgit v1.1
From 9f9a33cbf55d38987a66b709284d2bb4ffea0fe9 Mon Sep 17 00:00:00 2001
From: Doog <157747121+doogongithub@users.noreply.github.com>
Date: Thu, 29 Feb 2024 20:13:48 -0500
Subject: modify api, build additional FE components, add types
---
fe/src/lib/DataView.svelte | 67 ++++++++++++++++++++++++++++++++++++---
fe/src/lib/LoginForm.svelte | 16 ++++++----
fe/src/lib/PreferencesForm.svelte | 45 ++++++++++++++++++++++++++
fe/src/lib/Table.svelte | 19 +++++++++++
fe/src/stores/auth.ts | 57 ++++++++++++++++++++++++++++++++-
fe/src/types.ts | 14 ++++++++
6 files changed, 206 insertions(+), 12 deletions(-)
create mode 100644 fe/src/lib/PreferencesForm.svelte
create mode 100644 fe/src/types.ts
(limited to 'fe')
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index cd7b042..dc8acae 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,11 +1,24 @@
Add Stat Test
+
+ Add Water
@@ -65,3 +112,15 @@ onMount(() => {
{/await}
+
+
diff --git a/fe/src/lib/LoginForm.svelte b/fe/src/lib/LoginForm.svelte
index 22c0faf..499a457 100644
--- a/fe/src/lib/LoginForm.svelte
+++ b/fe/src/lib/LoginForm.svelte
@@ -1,8 +1,8 @@
+
+ User Preferences
+
+
+
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
index 5572280..4b81800 100644
--- a/fe/src/lib/Table.svelte
+++ b/fe/src/lib/Table.svelte
@@ -30,6 +30,11 @@ function formatDatum([key, value]: any[]) {
const parsedDate = new Date(value);
return formatter.format(parsedDate);
}
+
+ if (key === 'user') {
+ return value['name'];
+ }
+
return value;
}
@@ -78,9 +83,23 @@ table {
padding: 16px;
margin: 8px;
border: solid 1px black;
+ border-collapse: collapse;
}
th {
text-transform: capitalize;
}
+
+thead tr {
+ background: rgba(0,0,23, 0.34);
+}
+
+tbody tr:nth-child(odd) {
+ background: rgba(0,0,23,0.14);
+}
+
+th, td {
+ padding: 1em;
+ border: 1px solid rgba(0,0,0, 1);
+}
diff --git a/fe/src/stores/auth.ts b/fe/src/stores/auth.ts
index 7e70cda..10e6bd3 100644
--- a/fe/src/stores/auth.ts
+++ b/fe/src/stores/auth.ts
@@ -1,4 +1,5 @@
import type { Invalidator, Subscriber, Unsubscriber } from 'svelte/store';
+import type { Preference } from '../types';
import { writable, derived } from 'svelte/store';
type Nullable = T | null;
@@ -14,6 +15,18 @@ interface TokenStore {
unauthenticate: () => void
}
+
+interface UserStore {
+ subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
+ setUser: (user: User) => void,
+ reset: () => void
+}
+
+interface PreferenceStore {
+ subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
+ set: (this: void, value: Nullable) => void
+}
+
function createTokenStore(): TokenStore {
const storedToken = localStorage.getItem("token");
const { subscribe, set } = writable(storedToken);
@@ -43,6 +56,48 @@ function onTokenChange ($token: Nullable): boolean {
return $token ? true : false;
}
+function createUserStore(): UserStore {
+ const user = localStorage.getItem('user');
+ const userObj: Nullable = user ? JSON.parse(user) : null;
+ const { subscribe, set } = writable(userObj);
+
+ const setUser = (user: User) => {
+ localStorage.setItem('user', JSON.stringify(user));
+ set(user);
+ }
+
+ const reset = () => {
+ localStorage.removeItem('user');
+ set(null);
+ }
+
+ return {
+ subscribe,
+ setUser,
+ reset
+ }
+}
+
+
+function createPreferenceStore(): PreferenceStore {
+ const preferences = localStorage.getItem('preferences');
+ const preferenceObj: Preference = preferences ? JSON.parse(preferences) : {
+ color: "#FF0000",
+ size: {
+ size: 16,
+ unit: 'oz'
+ }
+ };
+
+ const { subscribe, set } = writable>(preferenceObj);
+
+ return {
+ subscribe,
+ set
+ }
+}
+
export const token = createTokenStore();
export const authenticated = derived(token, onTokenChange);
-export const user = writable(null);
+export const user = createUserStore();
+export const preferences = createPreferenceStore();
diff --git a/fe/src/types.ts b/fe/src/types.ts
new file mode 100644
index 0000000..03d613d
--- /dev/null
+++ b/fe/src/types.ts
@@ -0,0 +1,14 @@
+export interface Size {
+ size: number;
+ unit: string;
+}
+
+export interface Preference {
+ color: string;
+ size: Size;
+}
+
+export interface User {
+ name: string;
+ uuid: string;
+}
--
cgit v1.1
From afeffe31bd7d0f8333627a972e1d32e64a325b5b Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 1 Mar 2024 18:17:42 -0500
Subject: reformat fe
---
fe/.prettierrc | 4 +
fe/src/App.svelte | 42 ++-------
fe/src/lib/Card.svelte | 14 +--
fe/src/lib/Counter.svelte | 10 ---
fe/src/lib/DataView.svelte | 177 +++++++++++++++++++-------------------
fe/src/lib/Layout.svelte | 77 +++++++++--------
fe/src/lib/LoginForm.svelte | 105 +++++++++++++---------
fe/src/lib/PreferencesForm.svelte | 32 ++++---
fe/src/lib/Table.svelte | 138 ++++++++++++++---------------
fe/src/lib/errors.ts | 6 +-
fe/src/lib/utils.ts | 16 ++--
fe/src/main.ts | 2 +-
fe/src/stores/auth.ts | 132 ++++++++++++++--------------
fe/src/types.ts | 18 ++--
14 files changed, 388 insertions(+), 385 deletions(-)
create mode 100644 fe/.prettierrc
delete mode 100644 fe/src/lib/Counter.svelte
(limited to 'fe')
diff --git a/fe/.prettierrc b/fe/.prettierrc
new file mode 100644
index 0000000..222861c
--- /dev/null
+++ b/fe/.prettierrc
@@ -0,0 +1,4 @@
+{
+ "tabWidth": 2,
+ "useTabs": false
+}
diff --git a/fe/src/App.svelte b/fe/src/App.svelte
index 8811c52..25d53dc 100644
--- a/fe/src/App.svelte
+++ b/fe/src/App.svelte
@@ -1,40 +1,16 @@
-
+
{#if !$authenticated}
-
+
{:else}
-
- {/if}
-
+
+ {/if}
+
-
-
diff --git a/fe/src/lib/Card.svelte b/fe/src/lib/Card.svelte
index feb5bcc..0835940 100644
--- a/fe/src/lib/Card.svelte
+++ b/fe/src/lib/Card.svelte
@@ -1,16 +1,16 @@
- {#if title}
-
{title}
- {/if}
-
+ {#if title}
+ {title}
+ {/if}
+
diff --git a/fe/src/lib/Counter.svelte b/fe/src/lib/Counter.svelte
deleted file mode 100644
index 979b4df..0000000
--- a/fe/src/lib/Counter.svelte
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- count is {count}
-
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index dc8acae..1458c9a 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,126 +1,123 @@
-
+
-
Add Stat Test
-
-
- Add Water
-
-
-
Add
- {#await json then data}
-
- {:catch error}
-
{error}
- {/await}
-
+
Add Stat Test
+
+ Add Water
+
+
+
Add
+ {#await json then data}
+
+ {:catch error}
+
{error}
+ {/await}
+
diff --git a/fe/src/lib/Layout.svelte b/fe/src/lib/Layout.svelte
index f349632..94ce84d 100644
--- a/fe/src/lib/Layout.svelte
+++ b/fe/src/lib/Layout.svelte
@@ -1,57 +1,62 @@
- {#if $authenticated}
+ {#if $authenticated}
-
-
Water
-
-
- Settings
- Logout
-
+
+
Water
+
+
+ Settings
+ Logout
+
- {/if}
-
-
-
+
+ {/if}
+
+
+
diff --git a/fe/src/lib/LoginForm.svelte b/fe/src/lib/LoginForm.svelte
index 499a457..bf6d9ad 100644
--- a/fe/src/lib/LoginForm.svelte
+++ b/fe/src/lib/LoginForm.svelte
@@ -1,66 +1,85 @@
-
-
+
diff --git a/fe/src/lib/PreferencesForm.svelte b/fe/src/lib/PreferencesForm.svelte
index 781866c..95e04c1 100644
--- a/fe/src/lib/PreferencesForm.svelte
+++ b/fe/src/lib/PreferencesForm.svelte
@@ -1,7 +1,8 @@
-
+
User Preferences
@@ -42,4 +43,9 @@ dialog {
background: white;
color: black;
}
+
+input[type="color"] {
+ width: 100%;
+ height: 100%;
+}
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
index 4b81800..3a66e0d 100644
--- a/fe/src/lib/Table.svelte
+++ b/fe/src/lib/Table.svelte
@@ -1,105 +1,105 @@
+
- {#if title}
+ {#if title}
{title}
- {/if}
- {#if !noheader}
+ {/if}
+ {#if !noheader && data}
-
- {#each getDataKeys(data) as header}
- {header}
- {/each}
-
+
+ {#each getDataKeys(data) as header}
+ {header}
+ {/each}
+
- {/if}
-
- {#if data}
- {#each data as row}
+ {/if}
+
+ {#if data}
+ {#each data as row}
- {#each getRow(row) as datum}
-
+ {#each getRow(row) as datum}
{formatDatum(datum)}
- {/each}
+ {/each}
- {/each}
- {:else}
-
- There is not data.
-
- {/if}
-
- {#if !nofooter}
+ {/each}
+ {:else}
+ There is not data.
+ {/if}
+
+ {#if !nofooter}
-
+
- Table Footer
+ Table Footer
-
+
- {/if}
+ {/if}
+
diff --git a/fe/src/lib/errors.ts b/fe/src/lib/errors.ts
index 0663d63..d44bec5 100644
--- a/fe/src/lib/errors.ts
+++ b/fe/src/lib/errors.ts
@@ -1,7 +1,7 @@
export class UnauthorizedError extends Error {
- constructor (message?: string , options?: ErrorOptions) {
- super(message, options);
- }
+ constructor(message?: string, options?: ErrorOptions) {
+ super(message, options);
+ }
}
diff --git a/fe/src/lib/utils.ts b/fe/src/lib/utils.ts
index c5501ae..22d4e9a 100644
--- a/fe/src/lib/utils.ts
+++ b/fe/src/lib/utils.ts
@@ -1,9 +1,9 @@
-export function processFormInput(form) {
- const formData = new FormData(form);
- const data = {};
- for (let field of formData) {
- const [key, value] = field;
- data[key] = value;
- }
- return data;
+export function processFormInput(form: HTMLFormElement) {
+ const formData = new FormData(form);
+ const data: Record = {};
+ for (let field of formData) {
+ const [key, value] = field;
+ data[key] = value;
+ }
+ return data;
}
diff --git a/fe/src/main.ts b/fe/src/main.ts
index 8a909a1..ff866d0 100644
--- a/fe/src/main.ts
+++ b/fe/src/main.ts
@@ -2,7 +2,7 @@ import './app.css'
import App from './App.svelte'
const app = new App({
- target: document.getElementById('app'),
+ target: document.getElementById('app') as HTMLElement,
})
export default app
diff --git a/fe/src/stores/auth.ts b/fe/src/stores/auth.ts
index 10e6bd3..0efc80b 100644
--- a/fe/src/stores/auth.ts
+++ b/fe/src/stores/auth.ts
@@ -5,96 +5,96 @@ import { writable, derived } from 'svelte/store';
type Nullable = T | null;
interface User {
- uuid: string;
- username: string;
+ uuid: string;
+ username: string;
}
interface TokenStore {
- subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
- authenticate: (newToken: string) => void,
- unauthenticate: () => void
+ subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
+ authenticate: (newToken: string) => void,
+ unauthenticate: () => void
}
interface UserStore {
- subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
- setUser: (user: User) => void,
- reset: () => void
+ subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
+ setUser: (user: User) => void,
+ reset: () => void
}
interface PreferenceStore {
- subscribe: (run: Subscriber>, invalidate: Invalidator>) => Unsubscriber,
- set: (this: void, value: Nullable) => void
+ subscribe: (run: Subscriber, invalidate?: Invalidator) => Unsubscriber,
+ set: (this: void, value: Preference) => void
}
function createTokenStore(): TokenStore {
- const storedToken = localStorage.getItem("token");
- const { subscribe, set } = writable(storedToken);
-
- function authenticate(newToken: string): void {
- try {
- localStorage.setItem("token", newToken);
- set(newToken);
- } catch (e) {
- console.error('error', e);
- }
+ const storedToken = localStorage.getItem("token");
+ const { subscribe, set } = writable(storedToken);
+
+ function authenticate(newToken: string): void {
+ try {
+ localStorage.setItem("token", newToken);
+ set(newToken);
+ } catch (e) {
+ console.error('error', e);
}
-
- function unauthenticate(): void {
- localStorage.removeItem("token");
- set(null);
- }
-
- return {
- subscribe,
- authenticate,
- unauthenticate
- };
+ }
+
+ function unauthenticate(): void {
+ localStorage.removeItem("token");
+ set(null);
+ }
+
+ return {
+ subscribe,
+ authenticate,
+ unauthenticate
+ };
}
-function onTokenChange ($token: Nullable): boolean {
- return $token ? true : false;
+function onTokenChange($token: Nullable): boolean {
+ return $token ? true : false;
}
function createUserStore(): UserStore {
- const user = localStorage.getItem('user');
- const userObj: Nullable = user ? JSON.parse(user) : null;
- const { subscribe, set } = writable(userObj);
-
- const setUser = (user: User) => {
- localStorage.setItem('user', JSON.stringify(user));
- set(user);
- }
+ const user = localStorage.getItem('user');
+ const userObj: Nullable = user ? JSON.parse(user) : null;
+ const { subscribe, set } = writable(userObj);
+
+ const setUser = (user: User) => {
+ localStorage.setItem('user', JSON.stringify(user));
+ set(user);
+ }
+
+ const reset = () => {
+ localStorage.removeItem('user');
+ set(null);
+ }
+
+ return {
+ subscribe,
+ setUser,
+ reset
+ }
+}
- const reset = () => {
- localStorage.removeItem('user');
- set(null);
- }
- return {
- subscribe,
- setUser,
- reset
+function createPreferenceStore(): PreferenceStore {
+ const preferences = localStorage.getItem('preferences');
+ const preferenceObj: Preference = preferences ? JSON.parse(preferences) : {
+ color: "#FF0000",
+ size: {
+ size: 16,
+ unit: 'oz'
}
-}
+ };
+ const { subscribe, set } = writable(preferenceObj);
-function createPreferenceStore(): PreferenceStore {
- const preferences = localStorage.getItem('preferences');
- const preferenceObj: Preference = preferences ? JSON.parse(preferences) : {
- color: "#FF0000",
- size: {
- size: 16,
- unit: 'oz'
- }
- };
-
- const { subscribe, set } = writable>(preferenceObj);
-
- return {
- subscribe,
- set
- }
+ return {
+ subscribe,
+ set
+ }
}
export const token = createTokenStore();
diff --git a/fe/src/types.ts b/fe/src/types.ts
index 03d613d..526e7eb 100644
--- a/fe/src/types.ts
+++ b/fe/src/types.ts
@@ -1,14 +1,20 @@
export interface Size {
- size: number;
- unit: string;
+ size: number;
+ unit: string;
}
export interface Preference {
- color: string;
- size: Size;
+ color: string;
+ size: Size;
}
export interface User {
- name: string;
- uuid: string;
+ name: string;
+ uuid: string;
}
+
+export interface Statistic {
+ user_id: string;
+ date: string;
+ quantity: number;
+}
\ No newline at end of file
--
cgit v1.1
From 74ec025991f6acde6383e448974738e857758ebb Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 1 Mar 2024 18:50:51 -0500
Subject: Add dependencies, refine dataview
---
fe/package-lock.json | 58 ++++++++++++++++++++++++++--------------------
fe/package.json | 4 ++++
fe/src/lib/DataView.svelte | 27 ++++++++++++++++++++-
3 files changed, 63 insertions(+), 26 deletions(-)
(limited to 'fe')
diff --git a/fe/package-lock.json b/fe/package-lock.json
index 2c4146a..f74bf6c 100644
--- a/fe/package-lock.json
+++ b/fe/package-lock.json
@@ -7,6 +7,10 @@
"": {
"name": "fe",
"version": "0.0.0",
+ "dependencies": {
+ "chart.js": "^4.4.2",
+ "svelte-chartjs": "^3.1.5"
+ },
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@tsconfig/svelte": "^5.0.2",
@@ -21,7 +25,6 @@
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
"integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
- "dev": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
@@ -402,7 +405,6 @@
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
- "dev": true,
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
@@ -416,7 +418,6 @@
"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"
}
@@ -425,7 +426,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
- "dev": true,
"engines": {
"node": ">=6.0.0"
}
@@ -433,19 +433,22 @@
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
- "dev": true
+ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
- "dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
+ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -698,8 +701,7 @@
"node_modules/@types/estree": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
- "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
- "dev": true
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
},
"node_modules/@types/pug": {
"version": "2.0.10",
@@ -711,7 +713,6 @@
"version": "8.11.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
- "dev": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -736,7 +737,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -745,7 +745,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
- "dev": true,
"dependencies": {
"dequal": "^2.0.3"
}
@@ -805,6 +804,17 @@
"node": ">=6"
}
},
+ "node_modules/chart.js": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz",
+ "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -833,7 +843,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
- "dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.1",
@@ -852,7 +861,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
- "dev": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
@@ -891,7 +899,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -953,7 +960,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
- "dev": true,
"dependencies": {
"@types/estree": "^1.0.0"
}
@@ -1131,7 +1137,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
- "dev": true,
"dependencies": {
"@types/estree": "*"
}
@@ -1148,14 +1153,12 @@
"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
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
},
"node_modules/magic-string": {
"version": "0.30.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
"integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
- "dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
@@ -1166,8 +1169,7 @@
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
- "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
- "dev": true
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
},
"node_modules/merge2": {
"version": "1.4.1",
@@ -1309,7 +1311,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
- "dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^3.0.0",
@@ -1523,7 +1524,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1544,7 +1544,6 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.11.tgz",
"integrity": "sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==",
- "dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
@@ -1565,6 +1564,15 @@
"node": ">=16"
}
},
+ "node_modules/svelte-chartjs": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/svelte-chartjs/-/svelte-chartjs-3.1.5.tgz",
+ "integrity": "sha512-ka2zh7v5FiwfAX1oMflZ0HkNkgjHjFqANgRyC+vNYXfxtx2ku68Zo+2KgbKeBH2nS1ThDqkIACPzGxy4T0UaoA==",
+ "peerDependencies": {
+ "chart.js": "^3.5.0 || ^4.0.0",
+ "svelte": "^4.0.0"
+ }
+ },
"node_modules/svelte-check": {
"version": "3.6.4",
"resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.4.tgz",
diff --git a/fe/package.json b/fe/package.json
index 6bc8619..9c75965 100644
--- a/fe/package.json
+++ b/fe/package.json
@@ -17,5 +17,9 @@
"tslib": "^2.6.2",
"typescript": "^5.2.2",
"vite": "^5.1.0"
+ },
+ "dependencies": {
+ "chart.js": "^4.4.2",
+ "svelte-chartjs": "^3.1.5"
}
}
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 1458c9a..00ee21a 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,12 +1,16 @@
@@ -102,6 +126,7 @@
Add
+
{#await json then data}
{:catch error}
--
cgit v1.1
From d8b0f1335078d53d95a4212b1a4d4b0b28016702 Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 1 Mar 2024 20:12:21 -0500
Subject: feat(DataView): Add functionality to add water statistic
This commit adds functionality to add water statistics to the DataView component. It includes the following changes:
- Remove unused imports and variables
- Move the 'handleClick' function logic to a new 'AddForm' component
- Create the 'AddForm' component which displays a dialog with input fields for date and quantity and allows the user to add a new water statistic
- Dispatch events on form submit and dialog close in the 'AddForm' component
- Call the 'fetchData' function on successful submission of a new statistic
- Update chart data to display sample data
New component:
- AddForm.svelte: A form component to add a new water statistic
Note: This commit message exceeds the 50-character limit in the subject line, but adheres to the other specified requirements.
---
fe/src/lib/DataView.svelte | 206 +++++++++++++++-------------------------
fe/src/lib/forms/AddForm.svelte | 74 +++++++++++++++
2 files changed, 148 insertions(+), 132 deletions(-)
create mode 100644 fe/src/lib/forms/AddForm.svelte
(limited to 'fe')
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 00ee21a..7f368c6 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,148 +1,90 @@
-
Add Stat Test
-
- Add Water
-
-
-
Add
-
- {#await json then data}
-
- {:catch error}
-
{error}
- {/await}
-
+
Add
+
+
+ {#await json then data}
+
+ {:catch error}
+
{error}
+ {/await}
+
diff --git a/fe/src/lib/forms/AddForm.svelte b/fe/src/lib/forms/AddForm.svelte
new file mode 100644
index 0000000..f22e5f4
--- /dev/null
+++ b/fe/src/lib/forms/AddForm.svelte
@@ -0,0 +1,74 @@
+
+
+
+ Add Water
+
+
\ No newline at end of file
--
cgit v1.1
From 326f186d67017f87e631a1fbcdf3f184cbc42d7d Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 1 Mar 2024 20:26:42 -0500
Subject: feat: Add last seven days labels to chart
In the `DataView.svelte` component, the last seven days are now included as labels in the chart. This allows users to easily visualize data for the past week. The `getLastSevenDays` function generates an array of string values representing the dates in ISO format. This array is assigned to the `lastSevenDays` variable, which is then used as the labels in the chart's dataset.
---
fe/src/lib/DataView.svelte | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
(limited to 'fe')
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 7f368c6..5182a85 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -12,6 +12,8 @@
let canvasRef: HTMLCanvasElement;
let chart: any;
+ let lastSevenDays: string[];
+
async function fetchData() {
const res = await fetch("http://localhost:8080/api/v1/stats/", {
method: "GET",
@@ -26,6 +28,16 @@
}
}
+ function getLastSevenDays() {
+ const result = [];
+ for (let i = 0; i < 7; i++) {
+ let d = new Date();
+ d.setDate(d.getDate() - i);
+ result.push(d.toISOString().substring(0, 10));
+ }
+ return result;
+ }
+
function handleClick() {
open = true;
}
@@ -41,14 +53,21 @@
onMount(() => {
fetchData();
+ lastSevenDays = getLastSevenDays();
chart = new Chart(canvasRef, {
type: "bar",
data: {
- labels: ["one", "two"],
+ labels: lastSevenDays,
datasets: [
{
- label: "Water",
- data: [1, 2],
+ label: "Zach",
+ data: [1, 2, 8, 2, 5, 5, 1],
+ backgroundColor: "rgba(255, 192, 192, 0.2)",
+ borderColor: "rgba(75, 192, 192, 1)",
+ borderWidth: 1
+ }, {
+ label: "Parker",
+ data: [6, 1, 1, 4, 3, 5, 1],
backgroundColor: "rgba(75, 192, 192, 0.2)",
borderColor: "rgba(75, 192, 192, 1)",
borderWidth: 1
@@ -66,8 +85,8 @@
Add
-
+
{#await json then data}
{:catch error}
--
cgit v1.1
From cf2113e77edabf8e3a632c7b76c769752039ba88 Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Sat, 2 Mar 2024 16:52:55 -0500
Subject: feat: Add API logging
Add logging to the API to keep track of specific requests and headers. Also added CORS middleware to handle OPTIONS requests.
---
The commit adds logging functionality to the API and includes a middleware function to handle CORS OPTIONS requests. This will allow us to track specific requests and headers received by the API.
[API/main.go](/api/main.go):
- Added import for the 'log' package
- Added logging statements to print the request headers and "_I am here_" message
- Removed unnecessary newlines and comments
[fe/src/app.css](/fe/src/app.css):
- Added a new style for button hover effects
[fe/src/lib/Card.svelte](/fe/src/lib/Card.svelte):
- Added a new `height` prop to the Card component
[fe/src/lib/Column.svelte](/fe/src/lib/Column.svelte):
- Added a new CSS class for column layout
- Set the width and gap using CSS variables
[fe/src/lib/DataView.svelte](/fe/src/lib/DataView.svelte):
- Updated the 'fetchData' function to also fetch 'totals' and 'userStats' data
- Added canvas references and chart variables for bar and line charts
- Added a new 'getLastSevenDays' function to calculate the labels for the charts
- Updated the 'onMount' function to initialize the bar and line charts using the canvas references and data
- Updated the 'onDestroy' function to destroy the bar and line charts
- Added a new 'addFormOpen' store and imported it
- Added a new 'onClick' handler for the Add button to open the AddForm modal
- Updated the layout and added Card components to display the bar and line charts and the JSON data
- Added a new 'fetchTotals' function to fetch data for the 'totals' section
- Added a new 'fetchStatsForUser' function to fetch data for the 'userStats' section
[fe/src/lib/Layout.svelte](/fe/src/lib/Layout.svelte):
- Added a new 'preferenceFormOpen' variable and initialized it to 'false'
- Added a new 'showPreferencesDialog' function to set 'preferenceFormOpen' to 'true'
- Added a new 'closePreferenceDialog' function to set 'preferenceFormOpen' to 'false'
- Added a new 'showAddDialog' function to open the AddForm modal
---
fe/src/app.css | 101 +++++++++++++-------------
fe/src/lib/Card.svelte | 30 ++++----
fe/src/lib/Column.svelte | 13 ++++
fe/src/lib/DataView.svelte | 129 +++++++++++++++++++++++++++-------
fe/src/lib/Layout.svelte | 116 ++++++++++++++++--------------
fe/src/lib/Table.svelte | 172 ++++++++++++++++++++++++---------------------
fe/src/stores/forms.ts | 6 ++
7 files changed, 345 insertions(+), 222 deletions(-)
create mode 100644 fe/src/lib/Column.svelte
create mode 100644 fe/src/stores/forms.ts
(limited to 'fe')
diff --git a/fe/src/app.css b/fe/src/app.css
index 0d5fa90..de19b52 100644
--- a/fe/src/app.css
+++ b/fe/src/app.css
@@ -1,82 +1,87 @@
:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
- --submit: #28a745;
+ --submit: #28a745;
}
a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
}
+
a:hover {
- color: #535bf2;
+ color: #535bf2;
}
body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
}
h1 {
- font-size: 3.2em;
- line-height: 1.1;
+ font-size: 3.2em;
+ line-height: 1.1;
}
.card {
- padding: 2em;
+ padding: 2em;
}
#app {
- flex-grow: 2;
- max-width: 1280px;
- margin: 0 auto;
+ flex-grow: 2;
+ max-width: 1280px;
+ margin: 0 auto;
}
button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
}
+
button:hover {
- border-color: #646cff;
+ border-color: #646cff;
}
+
button:focus,
button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
+ outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+
+ a:hover {
+ color: #747bff;
+ }
+
+ button {
+ background-color: #f9f9f9;
+ }
}
@media (prefers-color-scheme: dark) {
@@ -97,7 +102,7 @@ button:focus-visible {
}
.form.input.group label {
- margin-bottom: .5em;
+ margin-bottom: .5em;
}
.form.input.group input {
diff --git a/fe/src/lib/Card.svelte b/fe/src/lib/Card.svelte
index 0835940..d7cd900 100644
--- a/fe/src/lib/Card.svelte
+++ b/fe/src/lib/Card.svelte
@@ -1,22 +1,24 @@
- {#if title}
-
{title}
- {/if}
-
+ {#if title}
+ {title}
+ {/if}
+
diff --git a/fe/src/lib/Column.svelte b/fe/src/lib/Column.svelte
new file mode 100644
index 0000000..f036073
--- /dev/null
+++ b/fe/src/lib/Column.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 5182a85..2b1b8b9 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,16 +1,21 @@
-
-
Add
-
-
- {#await json then data}
-
- {:catch error}
-
{error}
- {/await}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {#await json then data}
+
+ {:catch error}
+ {error}
+ {/await}
+
+
+ fetchTotals()}>Get totals
+ {#await totals then data}
+ {JSON.stringify(data)}
+ {:catch error}
+ {error}
+ {/await}
+
+
+
+
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
index 3a66e0d..d1cd7da 100644
--- a/fe/src/lib/Table.svelte
+++ b/fe/src/lib/Table.svelte
@@ -1,105 +1,113 @@
- {#if title}
- {title}
- {/if}
- {#if !noheader && data}
-
-
- {#each getDataKeys(data) as header}
- {header}
- {/each}
-
-
- {/if}
-
- {#if data}
- {#each data as row}
+ {#if title}
+ {title}
+ {/if}
+ {#if !noheader && data}
+
- {#each getRow(row) as datum}
- {formatDatum(datum)}
- {/each}
+ {#each getDataKeys(data) as header}
+ {header}
+ {/each}
- {/each}
+
+ {/if}
+
+ {#if data}
+ {#each limitedData as row}
+
+ {#each getRow(row) as datum}
+ {formatDatum(datum)}
+ {/each}
+
+ {/each}
{:else}
- There is not data.
+ There is not data.
+ {/if}
+
+ {#if !nofooter}
+
+
+
+ Table Footer
+
+
+
{/if}
-
- {#if !nofooter}
-
-
-
- Table Footer
-
-
-
- {/if}
diff --git a/fe/src/stores/forms.ts b/fe/src/stores/forms.ts
new file mode 100644
index 0000000..daf9181
--- /dev/null
+++ b/fe/src/stores/forms.ts
@@ -0,0 +1,6 @@
+import type { Writable } from "svelte/store";
+import { writable } from "svelte/store";
+
+
+export const preferencesFormOpen: Writable = writable(false);
+export const addFormOpen: Writable = writable(false);
\ No newline at end of file
--
cgit v1.1
From 5fa57845052655883120ba4d19a85d8756fb8d8c Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Wed, 6 Mar 2024 21:53:07 -0500
Subject: [FEAT] Refactor API main file and models
This commit refactors the `main.go` file in the API directory, as well as the related models in the `models.go` file. The changes include:
- Reordering imports and removing unnecessary imports
- Fixing error messages to be more descriptive
- Handling database connections more efficiently with deferred closures
- Handling errors and returning appropriate error responses
- Adding proper JSON bindings for POST requests
- Adding new views in the database scripts for aggregated statistics and daily user statistics
No changes were made to imports and requires.
---
fe/src/lib/DataView.svelte | 130 +++++++++++++++++++++-------------------
fe/src/lib/forms/AddForm.svelte | 13 ++--
2 files changed, 77 insertions(+), 66 deletions(-)
(limited to 'fe')
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 2b1b8b9..7d62a43 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -9,8 +9,6 @@
import AddForm from "./forms/AddForm.svelte";
let json: Promise;
- let totals: Promise;
- let userStats: Promise;
let barCanvasRef: HTMLCanvasElement;
let lineCanvasRef: HTMLCanvasElement;
@@ -18,6 +16,10 @@
let lineChart: any;
let lastSevenDays: string[];
+ let lastSevenDaysData: number[];
+
+ let userTotalsLabels: string[];
+ let userTotalsData: number[];
async function fetchData() {
const res = await fetch("http://localhost:8080/api/v1/stats/", {
@@ -33,24 +35,27 @@
}
}
- async function fetchTotals() {
+ async function fetchDailyUserStatistics() {
const res = await fetch("http://localhost:8080/api/v1/stats/totals/", {
- method: 'GET',
- mode: 'no-cors',
+ method: "GET",
headers: {
Authorization: `Bearer ${$token}`
}
});
if (res.ok) {
- totals = res.json();
+ const json = await res.json();
+ let labels = json.map(d => d.name);
+ let data = json.map(d => d.total);
+ return [labels, data];
} else {
throw new Error("There was a problem with your request");
}
+
}
- async function fetchStatsForUser() {
- const res = await fetch("http://localhost:8080/api/v1/stats/user/1aa668f3-7527-4a67-9c24-fdf307542eeb", {
+ async function fetchWeeklyTotals() {
+ const res = await fetch("http://localhost:8080/api/v1/stats/weekly/", {
method: "GET",
headers: {
Authorization: `Bearer ${$token}`
@@ -58,22 +63,15 @@
});
if (res.ok) {
- userStats = res.json();
+ const json = await res.json();
+ let labels = json.map(d => d.date);
+ let data = json.map(d => d.total);
+ return [labels, data];
} else {
throw new Error("There was a problem with your request");
}
}
- function getLastSevenDays() {
- const result = [];
- for (let i = 0; i < 7; i++) {
- let d = new Date();
- d.setDate(d.getDate() - i);
- result.push(d.toISOString().substring(0, 10));
- }
- return result;
- }
-
function closeDialog() {
addFormOpen.set(false);
}
@@ -81,61 +79,79 @@
function onStatisticAdd() {
closeDialog();
fetchData();
+ fetchWeeklyTotals().then(updateWeeklyTotalsChart).catch(err => console.error(err));
+ fetchDailyUserStatistics().then(updateDailyUserTotalsChart).catch(err => console.error(err));
}
- onMount(() => {
- fetchData();
-// fetchTotals();
- fetchStatsForUser();
- lastSevenDays = getLastSevenDays();
- barChart = new Chart(barCanvasRef, {
- type: "bar",
+ function setupWeeklyTotalsChart(result) {
+ [lastSevenDays, lastSevenDaysData] = result;
+ lineChart = new Chart(lineCanvasRef, {
+ type: "line",
data: {
labels: lastSevenDays,
datasets: [
{
- label: "Zach",
- data: [1, 2, 8, 2, 5, 5, 1],
- backgroundColor: "rgba(255, 192, 192, 0.2)",
- borderColor: "rgba(75, 192, 192, 1)",
- borderWidth: 1
- }, {
- label: "Parker",
- data: [6, 1, 1, 4, 3, 5, 1],
- backgroundColor: "rgba(75, 192, 192, 0.2)",
- borderColor: "rgba(75, 192, 192, 1)",
- borderWidth: 1
+ label: "Totals",
+ data: lastSevenDaysData,
+ backgroundColor: "rgba(255, 192, 192, 0.2)"
}
]
},
options: {
- responsive: true
+ responsive: true,
+ plugins: {
+ legend: {
+ display: false
+ }
+ }
}
});
- lineChart = new Chart(lineCanvasRef, {
- type: "line",
+ }
+
+ function setupDailyUserTotalsChart(result) {
+ [userTotalsLabels, userTotalsData] = result;
+
+ barChart = new Chart(barCanvasRef, {
+ type: "bar",
data: {
- labels: lastSevenDays,
+ labels: userTotalsLabels,
datasets: [
{
- label: "Zach",
- data: [1, 2, 8, 2, 5, 5, 1],
- backgroundColor: "rgba(255, 192, 192, 0.2)",
- borderColor: "rgba(75, 192, 192, 1)",
- borderWidth: 1
- }, {
- label: "Parker",
- data: [6, 1, 1, 4, 3, 5, 1],
- backgroundColor: "rgba(75, 192, 192, 0.2)",
- borderColor: "rgba(75, 192, 192, 1)",
- borderWidth: 1
+ data: userTotalsData,
+ backgroundColor: [
+ "#330000",
+ "rgba(100, 200, 192, 0.2)"
+ ]
}
]
},
options: {
- responsive: true
+ responsive: true,
+ plugins: {
+ legend: {
+ display: false
+ }
+ }
}
});
+ }
+
+ function updateWeeklyTotalsChart(result) {
+ [,lastSevenDaysData] = result;
+ lineChart.data.datasets[0].data = lastSevenDaysData;
+ lineChart.update();
+ }
+
+ function updateDailyUserTotalsChart(result) {
+ [,userTotalsData] = result;
+ barChart.data.datasets[0].data = userTotalsData;
+ barChart.update();
+ }
+
+ onMount(() => {
+ fetchData();
+ fetchWeeklyTotals().then(setupWeeklyTotalsChart);
+ fetchDailyUserStatistics().then(setupDailyUserTotalsChart);
});
onDestroy(() => {
@@ -164,14 +180,6 @@
{error}
{/await}
-
- fetchTotals()}>Get totals
- {#await totals then data}
- {JSON.stringify(data)}
- {:catch error}
- {error}
- {/await}
-
diff --git a/fe/src/lib/forms/AddForm.svelte b/fe/src/lib/forms/AddForm.svelte
index f22e5f4..4520b1b 100644
--- a/fe/src/lib/forms/AddForm.svelte
+++ b/fe/src/lib/forms/AddForm.svelte
@@ -34,20 +34,23 @@
dispatch("close");
}
- async function handleSubmitStat() {
- const response = await fetch("http://localhost:8080/api/v1/stats/", {
+ async function handleSubmitStat()
+ {
+ const { date, quantity } = statistic;
+ await fetch("http://localhost:8080/api/v1/stats/", {
method: "POST",
headers: {
Authorization: `Bearer ${$token}`
},
body: JSON.stringify({
- date: new Date(),
- user_id: 1,
- quantity: 3
+ date: new Date(date),
+ user_id: 2,
+ quantity
})
});
dispatch("submit");
}
+
--
cgit v1.1
From 8fab2d03bce82e4dee798ebffb1e93c557f62a4b Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Thu, 7 Mar 2024 23:16:22 -0500
Subject: feat: Update authentication route and add comments to exported
members
- The authentication route in the API has been updated to use a new router setup function.
- Comments have been added to all exported members of the `auth.go` module in the internal controllers package.
---
fe/src/http.ts | 60 ++++++++++++++++++++++++++++++++++++++++++++++
fe/src/lib/DataView.svelte | 53 +++++++++++++++++++++++++++++++++++-----
fe/src/lib/Table.svelte | 13 +++++-----
3 files changed, 114 insertions(+), 12 deletions(-)
create mode 100644 fe/src/http.ts
(limited to 'fe')
diff --git a/fe/src/http.ts b/fe/src/http.ts
new file mode 100644
index 0000000..cc5a906
--- /dev/null
+++ b/fe/src/http.ts
@@ -0,0 +1,60 @@
+export default class HttpClient {
+ private static instance: HttpClient;
+ baseURL: string;
+
+ private constructor(baseURL: string) {
+ this.baseURL = baseURL;
+ }
+
+ private getURL(endpoint: string): URL {
+ return new URL(endpoint, this.baseURL)
+ }
+
+ public static getInstance(): HttpClient {
+ if (!HttpClient.instance) {
+ const baseUrl = import.meta.env?.VITE_API_BASE_URL ?? 'http://localhost:8080/api/v1';
+ HttpClient.instance = new HttpClient(baseUrl);
+ }
+
+ return HttpClient.instance;
+ }
+
+ async get({ endpoint }: IHttpParameters): Promise {
+ const url = this.getURL(endpoint);
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: headers,
+ });
+ return response.json();
+ }
+
+ async post({ endpoint }: IHttpParameters): Promise {
+ const url = this.getURL(endpoint);
+ const response = await fetch(url, {
+ method: 'POST',
+ body: JSON.stringify(body),
+ headers: headers,
+ });
+ return response.json();
+ }
+
+ async patch({ endpoint, authenticated, headers }: IHttpParameters): Promise {
+ const url = this.getURL(endpoint);
+ if (authenticated) {
+
+ }
+ const response: Response = await fetch(url)
+ }
+
+ async delete({ endpoint, authenticated }: IHttpParameters): Promise {
+ const url = this.getURL(endpoint);
+ if (authenticated) { }
+ const response = await fetch()
+ }
+}
+
+interface IHttpParameters {
+ endpoint: string;
+ authenticated: boolean;
+ headers: Headers
+}
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 7d62a43..0a6b81b 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,5 +1,6 @@
-
-
+
+
-
+
diff --git a/fe/src/lib/Table.svelte b/fe/src/lib/Table.svelte
index d1cd7da..621157e 100644
--- a/fe/src/lib/Table.svelte
+++ b/fe/src/lib/Table.svelte
@@ -5,6 +5,10 @@
export let omit: string[] = ["id"];
export let title: string | undefined = undefined;
+ export let sortBy: string = 'date';
+
+ type SortComparator = (a, b) => number
+
function getDataKeys(data: any[]): string[] {
if (!data || data.length === 0) return [];
return Object.keys(data[0])
@@ -16,11 +20,8 @@
return Object.entries(row).filter((r) => !omit.includes(r[0]));
}
-
- let limitedData: Array = [];
-
- if (data && (data as any[]).length > 0) {
- limitedData = (data as any[]).slice(0, 4);
+ function sort(arr: Array>, fn: SortComparator = (a , b) => new Date(b[sortBy]) - new Date(a[sortBy])) {
+ return arr.sort(fn)
}
const formatter = new Intl.DateTimeFormat("en", {
@@ -62,7 +63,7 @@
{/if}
{#if data}
- {#each limitedData as row}
+ {#each sort(data) as row}
{#each getRow(row) as datum}
{formatDatum(datum)}
--
cgit v1.1
From 9cae9c1d2a0b4f7fa72f3075541b9ffafe1a7275 Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 15 Mar 2024 18:49:43 -0400
Subject: Add routes for preference, clean up and add types
---
fe/src/app.css | 4 +
fe/src/http.ts | 96 ++++++++++++++++--------
fe/src/lib/Card.svelte | 1 -
fe/src/lib/Chart.svelte | 63 ++++++++++++++++
fe/src/lib/DataView.svelte | 40 ++++------
fe/src/lib/Layout.svelte | 8 +-
fe/src/lib/LoginForm.svelte | 2 +-
fe/src/lib/PreferencesForm.svelte | 145 ++++++++++++++++++++++++++----------
fe/src/lib/errors.ts | 6 +-
fe/src/lib/utils.ts | 2 +-
fe/src/stores/auth.ts | 153 +++++++++++++++++---------------------
fe/src/types.ts | 45 +++++++++--
12 files changed, 370 insertions(+), 195 deletions(-)
create mode 100644 fe/src/lib/Chart.svelte
(limited to 'fe')
diff --git a/fe/src/app.css b/fe/src/app.css
index de19b52..c24c713 100644
--- a/fe/src/app.css
+++ b/fe/src/app.css
@@ -109,6 +109,10 @@ button:focus-visible {
padding: 1em;
}
+.form.input.group input[type=color] {
+ padding: 0;
+}
+
.form button[type=submit] {
align-self: flex-end;
background: var(--submit);
diff --git a/fe/src/http.ts b/fe/src/http.ts
index cc5a906..3b2a4f0 100644
--- a/fe/src/http.ts
+++ b/fe/src/http.ts
@@ -1,60 +1,92 @@
-export default class HttpClient {
- private static instance: HttpClient;
+let instance;
+const baseUrl = import.meta.env?.VITE_API_BASE_URL ?? "http://localhost:8080/api/v1";
+
+class HttpClient {
baseURL: string;
-
- private constructor(baseURL: string) {
+ commonHeaders: Headers;
+
+ constructor(baseURL: string) {
this.baseURL = baseURL;
+ this.commonHeaders = new Headers({
+ "Content-Type": "application/json"
+ })
+ if (instance) {
+ throw new Error("New instance cannot be created!");
+ }
+
+ instance = this;
}
-
+
private getURL(endpoint: string): URL {
- return new URL(endpoint, this.baseURL)
+ return new URL(endpoint, this.baseURL);
}
- public static getInstance(): HttpClient {
- if (!HttpClient.instance) {
- const baseUrl = import.meta.env?.VITE_API_BASE_URL ?? 'http://localhost:8080/api/v1';
- HttpClient.instance = new HttpClient(baseUrl);
- }
+ private token(): string | null {
+ return localStorage.getItem('token');
+ }
- return HttpClient.instance;
+ private async makeRequest(request: Request): Promise {
+ return fetch(request)
}
- async get({ endpoint }: IHttpParameters): Promise {
- const url = this.getURL(endpoint);
- const response = await fetch(url, {
- method: 'GET',
- headers: headers,
+ async get({ endpoint, headers }: IHttpParameters): Promise {
+ const url: URL = this.getURL(endpoint);
+ headers = Object.assign(headers, this.commonHeaders);
+ const request: Request = new Request(url, {
+ method: "GET",
+ headers
});
- return response.json();
+
+ return this.makeRequest(request);
}
- async post({ endpoint }: IHttpParameters): Promise {
+ async post({ endpoint, authenticated, body, headers }: IHttpParameters): Promise {
const url = this.getURL(endpoint);
- const response = await fetch(url, {
- method: 'POST',
+
+ if (authenticated) {
+ const token: string | null = this.token();
+ headers.append('Authorization', `Bearer ${token}`);
+ }
+
+ const request: Request = new Request(url, {
+ method: "POST",
body: JSON.stringify(body),
- headers: headers,
- });
- return response.json();
+ headers
+ })
+
+ return this.makeRequest(request);
}
-
+
async patch({ endpoint, authenticated, headers }: IHttpParameters): Promise {
const url = this.getURL(endpoint);
if (authenticated) {
-
+
}
- const response: Response = await fetch(url)
+ const response: Response = await fetch(url, {
+ method: "PATCH",
+ headers
+ });
}
-
- async delete({ endpoint, authenticated }: IHttpParameters): Promise {
+
+ async delete({ endpoint, authenticated, headers }: IHttpParameters): Promise {
const url = this.getURL(endpoint);
- if (authenticated) { }
- const response = await fetch()
+ if (authenticated) {
+
+ }
+ const response: Response = await fetch(url, {
+ method: "DELETE",
+ headers
+ })
}
}
interface IHttpParameters {
endpoint: string;
+ body: Record;
authenticated: boolean;
- headers: Headers
+ headers: Headers;
}
+
+let http: Readonly = Object.freeze(new HttpClient(baseUrl));
+
+export default http;
diff --git a/fe/src/lib/Card.svelte b/fe/src/lib/Card.svelte
index d7cd900..cd1e02c 100644
--- a/fe/src/lib/Card.svelte
+++ b/fe/src/lib/Card.svelte
@@ -1,6 +1,5 @@
diff --git a/fe/src/lib/Chart.svelte b/fe/src/lib/Chart.svelte
new file mode 100644
index 0000000..b19d932
--- /dev/null
+++ b/fe/src/lib/Chart.svelte
@@ -0,0 +1,63 @@
+
+
+
\ No newline at end of file
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 0a6b81b..5e81a5a 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -1,10 +1,11 @@
+
- User Preferences
-
+ User Preferences
+
+
diff --git a/fe/src/lib/errors.ts b/fe/src/lib/errors.ts
index d44bec5..81f7145 100644
--- a/fe/src/lib/errors.ts
+++ b/fe/src/lib/errors.ts
@@ -1,7 +1,5 @@
export class UnauthorizedError extends Error {
- constructor(message?: string, options?: ErrorOptions) {
- super(message, options);
+ constructor(message?: string) {
+ super(message);
}
}
-
-
diff --git a/fe/src/lib/utils.ts b/fe/src/lib/utils.ts
index 22d4e9a..e78556c 100644
--- a/fe/src/lib/utils.ts
+++ b/fe/src/lib/utils.ts
@@ -1,5 +1,5 @@
export function processFormInput(form: HTMLFormElement) {
- const formData = new FormData(form);
+ const formData: FormData = new FormData(form);
const data: Record
= {};
for (let field of formData) {
const [key, value] = field;
diff --git a/fe/src/stores/auth.ts b/fe/src/stores/auth.ts
index 0efc80b..63f027e 100644
--- a/fe/src/stores/auth.ts
+++ b/fe/src/stores/auth.ts
@@ -1,100 +1,87 @@
-import type { Invalidator, Subscriber, Unsubscriber } from 'svelte/store';
-import type { Preference } from '../types';
-import { writable, derived } from 'svelte/store';
+import type { Preference, TokenStore, Nullable, UserStore, User, PreferenceStore } from "../types";
+import { writable, derived } from "svelte/store";
-type Nullable = T | null;
-
-interface User {
- uuid: string;
- username: string;
-}
-
-interface TokenStore {
- subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
- authenticate: (newToken: string) => void,
- unauthenticate: () => void
-}
-
-
-interface UserStore {
- subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
- setUser: (user: User) => void,
- reset: () => void
-}
-
-interface PreferenceStore {
- subscribe: (run: Subscriber, invalidate?: Invalidator) => Unsubscriber,
- set: (this: void, value: Preference) => void
-}
function createTokenStore(): TokenStore {
- const storedToken = localStorage.getItem("token");
- const { subscribe, set } = writable(storedToken);
-
- function authenticate(newToken: string): void {
- try {
- localStorage.setItem("token", newToken);
- set(newToken);
- } catch (e) {
- console.error('error', e);
+ const storedToken = localStorage.getItem("token");
+ const { subscribe, set } = writable(storedToken);
+
+ function authenticate(newToken: string): void {
+ try {
+ localStorage.setItem("token", newToken);
+ set(newToken);
+ } catch (e) {
+ console.error("error", e);
+ }
+ }
+
+ function unauthenticate(): void {
+ localStorage.removeItem("token");
+ set(null);
}
- }
-
- function unauthenticate(): void {
- localStorage.removeItem("token");
- set(null);
- }
-
- return {
- subscribe,
- authenticate,
- unauthenticate
- };
+
+ return {
+ subscribe,
+ authenticate,
+ unauthenticate
+ };
}
function onTokenChange($token: Nullable): boolean {
- return $token ? true : false;
+ return $token ? true : false;
}
function createUserStore(): UserStore {
- const user = localStorage.getItem('user');
- const userObj: Nullable = user ? JSON.parse(user) : null;
- const { subscribe, set } = writable(userObj);
-
- const setUser = (user: User) => {
- localStorage.setItem('user', JSON.stringify(user));
- set(user);
- }
-
- const reset = () => {
- localStorage.removeItem('user');
- set(null);
- }
-
- return {
- subscribe,
- setUser,
- reset
- }
+ const user = localStorage.getItem("user");
+ const userObj: Nullable = user ? JSON.parse(user) : null;
+ const { subscribe, set } = writable(userObj);
+
+ const setUser = (user: User) => {
+ localStorage.setItem("user", JSON.stringify(user));
+ set(user);
+ };
+
+ const reset = () => {
+ localStorage.removeItem("user");
+ set(null);
+ };
+
+ return {
+ subscribe,
+ setUser,
+ reset
+ };
}
function createPreferenceStore(): PreferenceStore {
- const preferences = localStorage.getItem('preferences');
- const preferenceObj: Preference = preferences ? JSON.parse(preferences) : {
- color: "#FF0000",
- size: {
- size: 16,
- unit: 'oz'
- }
- };
-
- const { subscribe, set } = writable(preferenceObj);
-
- return {
- subscribe,
- set
- }
+ const preferences = localStorage.getItem("preferences");
+ const preferenceObj: Preference = preferences ? JSON.parse(preferences) : {
+ id: 0,
+ color: "#FF0000",
+ size_id: 0,
+ user_id: 0
+ };
+
+ const { subscribe, set, update } = writable>(preferenceObj);
+
+ const setPreference = (preference: Preference) => {
+ localStorage.setItem("preference", JSON.stringify(preference));
+ set(preference);
+ };
+
+ const reset = () => {
+ localStorage.removeItem("preference");
+ set(null);
+ };
+
+ return {
+ set,
+ subscribe,
+ reset,
+ update,
+ setPreference,
+ };
}
export const token = createTokenStore();
diff --git a/fe/src/types.ts b/fe/src/types.ts
index 526e7eb..c8f2f00 100644
--- a/fe/src/types.ts
+++ b/fe/src/types.ts
@@ -1,14 +1,19 @@
-export interface Size {
- size: number;
- unit: string;
-}
+import type { Invalidator, Subscriber, Unsubscriber, Updater } from "svelte/store";
export interface Preference {
+ id: number;
color: string;
- size: Size;
+ size_id: number;
+ user_id: number;
+}
+
+export interface Size {
+ size: number;
+ unit: string;
}
export interface User {
+ id: number;
name: string;
uuid: string;
}
@@ -17,4 +22,32 @@ export interface Statistic {
user_id: string;
date: string;
quantity: number;
-}
\ No newline at end of file
+}
+
+export type Nullable = T | null;
+
+export interface User {
+ uuid: string;
+ username: string;
+}
+
+export interface TokenStore {
+ subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
+ authenticate: (newToken: string) => void,
+ unauthenticate: () => void
+}
+
+
+export interface UserStore {
+ subscribe: (run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber,
+ setUser: (user: User) => void,
+ reset: () => void
+}
+
+export interface PreferenceStore {
+ set: (this: void, value: Preference) => void;
+ subscribe: (this: void, run: Subscriber>, invalidate?: Invalidator>) => Unsubscriber;
+ reset: () => void;
+ update: (this: void, updater: Updater>) => void;
+ setPreference: (user: Preference) => void;
+}
--
cgit v1.1
From c4e5776f9e174fe6bf91721649c0541a9fb310ae Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 15 Mar 2024 21:41:12 -0400
Subject: add env samples, move files
---
fe/.env.sample | 1 +
fe/src/errors.ts | 5 +++++
fe/src/lib/errors.ts | 5 -----
fe/src/lib/utils.ts | 9 ---------
fe/src/utils.ts | 9 +++++++++
5 files changed, 15 insertions(+), 14 deletions(-)
create mode 100644 fe/.env.sample
create mode 100644 fe/src/errors.ts
delete mode 100644 fe/src/lib/errors.ts
delete mode 100644 fe/src/lib/utils.ts
create mode 100644 fe/src/utils.ts
(limited to 'fe')
diff --git a/fe/.env.sample b/fe/.env.sample
new file mode 100644
index 0000000..60c383f
--- /dev/null
+++ b/fe/.env.sample
@@ -0,0 +1 @@
+VITE_API_BASE_URL="https://www.example.org"
\ No newline at end of file
diff --git a/fe/src/errors.ts b/fe/src/errors.ts
new file mode 100644
index 0000000..81f7145
--- /dev/null
+++ b/fe/src/errors.ts
@@ -0,0 +1,5 @@
+export class UnauthorizedError extends Error {
+ constructor(message?: string) {
+ super(message);
+ }
+}
diff --git a/fe/src/lib/errors.ts b/fe/src/lib/errors.ts
deleted file mode 100644
index 81f7145..0000000
--- a/fe/src/lib/errors.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export class UnauthorizedError extends Error {
- constructor(message?: string) {
- super(message);
- }
-}
diff --git a/fe/src/lib/utils.ts b/fe/src/lib/utils.ts
deleted file mode 100644
index e78556c..0000000
--- a/fe/src/lib/utils.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export function processFormInput(form: HTMLFormElement) {
- const formData: FormData = new FormData(form);
- const data: Record = {};
- for (let field of formData) {
- const [key, value] = field;
- data[key] = value;
- }
- return data;
-}
diff --git a/fe/src/utils.ts b/fe/src/utils.ts
new file mode 100644
index 0000000..e78556c
--- /dev/null
+++ b/fe/src/utils.ts
@@ -0,0 +1,9 @@
+export function processFormInput(form: HTMLFormElement) {
+ const formData: FormData = new FormData(form);
+ const data: Record = {};
+ for (let field of formData) {
+ const [key, value] = field;
+ data[key] = value;
+ }
+ return data;
+}
--
cgit v1.1
From fd1332a3df191577e91c6d846a8b5db1747099fd Mon Sep 17 00:00:00 2001
From: Zach Berwaldt
Date: Fri, 15 Mar 2024 22:00:10 -0400
Subject: cleanup
---
fe/src/lib/DataView.svelte | 7 ++++---
fe/src/lib/LoginForm.svelte | 3 ++-
fe/src/lib/PreferencesForm.svelte | 15 ++++++++-------
fe/src/lib/forms/AddForm.svelte | 3 ++-
fe/src/utils.ts | 5 +++++
5 files changed, 21 insertions(+), 12 deletions(-)
(limited to 'fe')
diff --git a/fe/src/lib/DataView.svelte b/fe/src/lib/DataView.svelte
index 5e81a5a..ffc2fe8 100644
--- a/fe/src/lib/DataView.svelte
+++ b/fe/src/lib/DataView.svelte
@@ -9,6 +9,7 @@
import Card from "./Card.svelte";
import Column from "./Column.svelte";
import AddForm from "./forms/AddForm.svelte";
+ import { apiURL } from "../utils";
let json: Promise;
@@ -24,7 +25,7 @@
let userTotalsData: number[];
async function fetchData() {
- const res = await fetch("http://localhost:8080/api/v1/stats/", {
+ const res = await fetch(apiURL("stats"), {
method: "GET",
headers: {
Authorization: `Bearer ${$token}`
@@ -38,7 +39,7 @@
}
async function fetchDailyUserStatistics() {
- const res = await fetch("http://localhost:8080/api/v1/stats/daily/", {
+ const res = await fetch(apiURL("stats/daily"), {
method: "GET",
headers: {
Authorization: `Bearer ${$token}`
@@ -57,7 +58,7 @@
}
async function fetchWeeklyTotals() {
- const res = await fetch("http://localhost:8080/api/v1/stats/weekly/", {
+ const res = await fetch(apiURL("stats/weekly"), {
method: "GET",
headers: {
Authorization: `Bearer ${$token}`
diff --git a/fe/src/lib/LoginForm.svelte b/fe/src/lib/LoginForm.svelte
index 8c3c288..cf5febf 100644
--- a/fe/src/lib/LoginForm.svelte
+++ b/fe/src/lib/LoginForm.svelte
@@ -1,6 +1,7 @@