diff --git a/.prettierignore b/.prettierignore index 6562bcb..4f611ee 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,12 @@ +# IDEs +.vscode/**/ + # Package Managers package-lock.json pnpm-lock.yaml yarn.lock bun.lock bun.lockb + +# Build Artifacts +src/i18n/** \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..116d685 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "inlang.vs-code-extension" + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 552dad7..a519134 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,9 @@ "devDependencies": { "@eslint/compat": "^1.3.0", "@eslint/js": "^9.29.0", - "@lucide/svelte": "^0.518.0", + "@inlang/paraglide-js": "2.2.0", + "@internationalized/date": "^3.8.2", + "@lucide/svelte": "^0.515.0", "@playwright/test": "^1.53.1", "@sveltejs/adapter-auto": "^6.0.1", "@sveltejs/kit": "^2.22.0", @@ -38,6 +40,7 @@ "@types/dotenv": "^6.1.1", "@types/node": "^24", "@types/nodemailer": "^6.4.17", + "bits-ui": "^2.8.13", "clsx": "^2.1.1", "drizzle-kit": "^0.31.1", "eslint": "^9.29.0", @@ -58,9 +61,6 @@ "typescript-eslint": "^8.34.1", "vite": "^6.3.5", "vitest": "^3.2.4" - }, - "engines": { - "node": ">=24.0.0" } }, "node_modules/@adobe/css-tools": { @@ -1295,6 +1295,34 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1361,6 +1389,62 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inlang/paraglide-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.2.0.tgz", + "integrity": "sha512-pkpXu1LanvpcAbvpVPf7PgF11Uq7DliSEBngrcUN36l4ZOOpzn3QBTvVr/tJxvks0O67WseQgiMHet8KH7Oz5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inlang/recommend-sherlock": "0.2.1", + "@inlang/sdk": "2.4.9", + "commander": "11.1.0", + "consola": "3.4.0", + "json5": "2.2.3", + "unplugin": "^2.1.2", + "urlpattern-polyfill": "^10.0.0" + }, + "bin": { + "paraglide-js": "bin/run.js" + } + }, + "node_modules/@inlang/recommend-sherlock": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz", + "integrity": "sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.3" + } + }, + "node_modules/@inlang/sdk": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@inlang/sdk/-/sdk-2.4.9.tgz", + "integrity": "sha512-cvz/C1rF5WBxzHbEoiBoI6Sz6q6M+TdxfWkEGBYTD77opY8i8WN01prUWXEM87GPF4SZcyIySez9U0Ccm12oFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lix-js/sdk": "0.4.7", + "@sinclair/typebox": "^0.31.17", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@internationalized/date": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.8.2.tgz", + "integrity": "sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1422,10 +1506,36 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lix-js/sdk": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.4.7.tgz", + "integrity": "sha512-pRbW+joG12L0ULfMiWYosIW0plmW4AsUdiPCp+Z8rAsElJ+wJ6in58zhD3UwUcd4BNcpldEGjg6PdA7e0RgsDQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@lix-js/server-protocol-schema": "0.1.1", + "dedent": "1.5.1", + "human-id": "^4.1.1", + "js-sha256": "^0.11.0", + "kysely": "^0.27.4", + "sqlite-wasm-kysely": "0.3.0", + "uuid": "^10.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@lix-js/server-protocol-schema": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@lix-js/server-protocol-schema/-/server-protocol-schema-0.1.1.tgz", + "integrity": "sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@lucide/svelte": { - "version": "0.518.0", - "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.518.0.tgz", - "integrity": "sha512-vhSikVKVZnz7eVa70WsWh/ySqdcb7Mn2R/XhG16fCfqgpMKzdu5GCHPRLaHcGaUCaM9cPDMWG8FeBXk0QY1PEg==", + "version": "0.515.0", + "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-0.515.0.tgz", + "integrity": "sha512-CEAyqcZmNBfYzVgaRmK2RFJP5tnbXxekRyDk0XX/eZQRfsJmkDvmQwXNX8C869BgNeryzmrRyjHhUL6g9ZOHNA==", "dev": true, "license": "ISC", "peerDependencies": { @@ -1906,6 +2016,23 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.31.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz", + "integrity": "sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sqlite.org/sqlite-wasm": { + "version": "3.48.0-build4", + "resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.48.0-build4.tgz", + "integrity": "sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "sqlite-wasm": "bin/index.js" + } + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", @@ -2010,6 +2137,16 @@ "vite": "^6.0.0" } }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@tailwindcss/node": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz", @@ -2973,6 +3110,13 @@ "node": ">= 0.4" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3005,6 +3149,69 @@ "dev": true, "license": "MIT" }, + "node_modules/bits-ui": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.8.13.tgz", + "integrity": "sha512-YC3DiatZzREdbTZR8IuxbQeYg+/MNcyQeuS6Hycl+ufoG7eiV66qICx210plFER9B776FEYSHXSYuQdlvWODpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.1", + "@floating-ui/dom": "^1.7.1", + "esm-env": "^1.1.2", + "runed": "^0.29.1", + "svelte-toolbelt": "^0.9.3", + "tabbable": "^6.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/huntabyte" + }, + "peerDependencies": { + "@internationalized/date": "^3.8.1", + "svelte": "^5.33.0" + } + }, + "node_modules/bits-ui/node_modules/runed": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/runed/-/runed-0.29.2.tgz", + "integrity": "sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte", + "https://github.com/sponsors/tglide" + ], + "license": "MIT", + "dependencies": { + "esm-env": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^5.7.0" + } + }, + "node_modules/bits-ui/node_modules/svelte-toolbelt": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.9.3.tgz", + "integrity": "sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/huntabyte" + ], + "dependencies": { + "clsx": "^2.1.1", + "runed": "^0.29.0", + "style-to-object": "^1.0.8" + }, + "engines": { + "node": ">=18", + "pnpm": ">=8.7.0" + }, + "peerDependencies": { + "svelte": "^5.30.2" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -3196,6 +3403,33 @@ "text-hex": "1.0.x" } }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -3209,6 +3443,16 @@ "dev": true, "license": "MIT" }, + "node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", @@ -3218,6 +3462,13 @@ "node": ">= 0.6" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3305,6 +3556,21 @@ "dev": true, "license": "MIT" }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -3834,6 +4100,20 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -4196,6 +4476,16 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -4249,6 +4539,16 @@ "node": ">= 14" } }, + "node_modules/human-id": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.1.1.tgz", + "integrity": "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -4426,6 +4726,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-sha256": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz", + "integrity": "sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg==", + "dev": true, + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4507,6 +4814,19 @@ "dev": true, "license": "MIT" }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4539,6 +4859,16 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, + "node_modules/kysely": { + "version": "0.27.6", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz", + "integrity": "sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5640,6 +5970,16 @@ "node": ">=8" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -5965,6 +6305,18 @@ "source-map": "^0.6.0" } }, + "node_modules/sqlite-wasm-kysely": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/sqlite-wasm-kysely/-/sqlite-wasm-kysely-0.3.0.tgz", + "integrity": "sha512-TzjBNv7KwRw6E3pdKdlRyZiTmUIE0UttT/Sl56MVwVARl/u5gp978KepazCJZewFUnlWHz9i3NQd4kOtP/Afdg==", + "dev": true, + "dependencies": { + "@sqlite.org/sqlite-wasm": "^3.48.0-build2" + }, + "peerDependencies": { + "kysely": "*" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -6211,6 +6563,13 @@ "dev": true, "license": "MIT" }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", @@ -6441,6 +6800,13 @@ "typescript": ">=4.8.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, "node_modules/tw-animate-css": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.4.tgz", @@ -6508,6 +6874,21 @@ "devOptional": true, "license": "MIT" }, + "node_modules/unplugin": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz", + "integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.1", + "picomatch": "^4.0.2", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6518,12 +6899,33 @@ "punycode": "^2.1.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -6749,6 +7151,13 @@ "node": ">=12" } }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", diff --git a/package.json b/package.json index f26c835..fc9511c 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "prepare": "svelte-kit sync && npm run i18n:compile || echo ''", + "check": "npm run prepare && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "npm run prepare && svelte-check --tsconfig ./tsconfig.json --watch", "format": "prettier --write .", "lint": "prettier --check . && eslint .", "test:unit": "vitest", @@ -30,12 +30,15 @@ "docker:prod:up": "docker compose -f docker-compose.prod.yml up -d", "docker:prod:down": "docker compose -f docker-compose.prod.yml down", "docker:prod:logs": "docker compose -f docker-compose.prod.yml logs -f", - "docker:prod:clean": "docker compose -f docker-compose.prod.yml down -v --remove-orphans" + "docker:prod:clean": "docker compose -f docker-compose.prod.yml down -v --remove-orphans", + "i18n:compile": "npx @inlang/paraglide-js compile --project ./project.inlang --outdir ./src/i18n" }, "devDependencies": { "@eslint/compat": "^1.3.0", "@eslint/js": "^9.29.0", - "@lucide/svelte": "^0.518.0", + "@inlang/paraglide-js": "2.2.0", + "@internationalized/date": "^3.8.2", + "@lucide/svelte": "^0.515.0", "@playwright/test": "^1.53.1", "@sveltejs/adapter-auto": "^6.0.1", "@sveltejs/kit": "^2.22.0", @@ -44,9 +47,10 @@ "@tailwindcss/vite": "^4.1.10", "@testing-library/jest-dom": "^6.6.3", "@testing-library/svelte": "^5.2.8", - "@types/nodemailer": "^6.4.17", "@types/dotenv": "^6.1.1", "@types/node": "^24", + "@types/nodemailer": "^6.4.17", + "bits-ui": "^2.8.13", "clsx": "^2.1.1", "drizzle-kit": "^0.31.1", "eslint": "^9.29.0", @@ -83,8 +87,5 @@ "secrets.js-34r7h": "^2.0.2", "winston": "^3.17.0" }, - "engines": { - "node": ">=24.0.0" - }, "license": "AGPL-3.0" } diff --git a/project.inlang/.gitignore b/project.inlang/.gitignore new file mode 100644 index 0000000..5e46596 --- /dev/null +++ b/project.inlang/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/project.inlang/messages/de.json b/project.inlang/messages/de.json new file mode 100644 index 0000000..5fe9afb --- /dev/null +++ b/project.inlang/messages/de.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "welcome": "Willkommen bei OpenReception", + "poweredBy": "Betrieben mit", + "i18n": { + "label": "Sprache wählen", + "search": "Sprache suchen", + "notFound": "Sprache nicht gefunden" + } +} diff --git a/project.inlang/messages/en.json b/project.inlang/messages/en.json new file mode 100644 index 0000000..0f9e789 --- /dev/null +++ b/project.inlang/messages/en.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://inlang.com/schema/inlang-message-format", + "welcome": "Welcome to OpenReception", + "poweredBy": "Powered by", + "i18n": { + "label": "Select Language", + "search": "Search Language", + "notFound": "Language not found" + } +} diff --git a/project.inlang/project_id b/project.inlang/project_id new file mode 100644 index 0000000..4fc8153 --- /dev/null +++ b/project.inlang/project_id @@ -0,0 +1 @@ +AMpl9Oc3gl0QXrTR7u \ No newline at end of file diff --git a/project.inlang/settings.json b/project.inlang/settings.json new file mode 100644 index 0000000..971fb03 --- /dev/null +++ b/project.inlang/settings.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "baseLocale": "en", + "locales": ["en", "de"], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js" + ], + "plugin.inlang.messageFormat": { + "pathPattern": "./project.inlang/messages/{locale}.json" + } +} diff --git a/src/app.html b/src/app.html index e75322c..c6a98cd 100644 --- a/src/app.html +++ b/src/app.html @@ -1,5 +1,5 @@ - +
@@ -10,7 +10,6 @@ - %sveltekit.head% diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 0b44500..5a92a2b 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -4,11 +4,8 @@ import { corsHandle } from "./server-hooks/corsHandle"; import { loggingHandle } from "./server-hooks/loggingHandle"; import { rateLimitHandle } from "./server-hooks/rateLimitHandle"; import { secHeaderHandle } from "./server-hooks/secHeaderHandle"; - -type Error = { - message?: string; - stack?: string; -}; +import { i18nHandle } from "./server-hooks/i18nHandle"; +import { building } from "$app/environment"; export async function handleError({ error, event, status, message }) { const errorLogger = logger.setContext("ERROR_HANDLER"); @@ -21,7 +18,7 @@ export async function handleError({ error, event, status, message }) { url: event.url.pathname, method: event.request.method, userAgent: event.request.headers.get("user-agent"), - ip: event.getClientAddress() + ip: !building ? event.getClientAddress() : "server" }); return { @@ -29,4 +26,10 @@ export async function handleError({ error, event, status, message }) { }; } -export const handle = sequence(loggingHandle, rateLimitHandle, corsHandle, secHeaderHandle); +export const handle = sequence( + loggingHandle, + i18nHandle, + rateLimitHandle, + corsHandle, + secHeaderHandle +); diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte new file mode 100644 index 0000000..4da437d --- /dev/null +++ b/src/lib/components/ui/button/button.svelte @@ -0,0 +1,80 @@ + + + + +{#if href} + + {@render children?.()} + +{:else} + +{/if} diff --git a/src/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts new file mode 100644 index 0000000..068bfa2 --- /dev/null +++ b/src/lib/components/ui/button/index.ts @@ -0,0 +1,17 @@ +import Root, { + type ButtonProps, + type ButtonSize, + type ButtonVariant, + buttonVariants +} from "./button.svelte"; + +export { + Root, + type ButtonProps as Props, + // + Root as Button, + buttonVariants, + type ButtonProps, + type ButtonSize, + type ButtonVariant +}; diff --git a/src/lib/components/ui/combobox/combobox.svelte b/src/lib/components/ui/combobox/combobox.svelte new file mode 100644 index 0000000..57a91a8 --- /dev/null +++ b/src/lib/components/ui/combobox/combobox.svelte @@ -0,0 +1,76 @@ + + +