diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..cac3b78 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,14 @@ +{ + "language_servers": ["!vtsls", "!deno", "!tailwindcss-language-server", "!biome", "..."], + "languages": { + "Vue.js": { + "code_actions_on_format": { + "source.fixAll.eslint": true, + "source.organizeImports": true + }, + "formatter": "language_server", + "prettier": null, + "format_on_save": "on" + } + } +} diff --git a/bun.lock b/bun.lock index 71c723d..13e6955 100644 --- a/bun.lock +++ b/bun.lock @@ -4,43 +4,50 @@ "": { "name": "journal-media", "dependencies": { - "@effect/platform": "^0.77.2", - "@effect/sql-drizzle": "^0.29.2", - "a11y-dialog": "^8.1.1", - "drizzle-orm": "^0.39.3", - "effect": "^3.13.2", - "pinia": "^3.0.1", - "sqlocal": "^0.14.0", - "vue": "^3.5.13", - "vue-router": "^4.5.0", + "@effect/platform": "latest", + "@effect/sql-drizzle": "latest", + "@unhead/vue": "latest", + "@vueuse/core": "latest", + "@vueuse/router": "latest", + "a11y-dialog": "latest", + "drizzle-orm": "latest", + "effect": "latest", + "pinia": "latest", + "sqlocal": "latest", + "unhead": "latest", + "vue": "latest", + "vue-router": "latest", }, "devDependencies": { - "@types/bun": "^1.2.2", - "@types/node": "^22.13.4", - "@vitejs/plugin-vue": "^5.2.1", - "@vue/eslint-config-prettier": "^10.2.0", - "@vue/eslint-config-typescript": "^14.4.0", - "browserlist": "^1.0.1", - "browserslist": "^4.24.4", - "drizzle-kit": "^0.30.4", - "eslint": "^9.20.1", - "eslint-plugin-perfectionist": "^4.9.0", - "eslint-plugin-vue": "^9.32.0", - "globals": "^15.15.0", - "jiti": "^2.4.2", - "lightningcss": "^1.29.1", - "prettier": "^3.5.1", - "typescript": "^5.7.3", - "vite": "^6.1.1", - "vite-plugin-vue-devtools": "^7.7.2", - "vue-tsc": "^2.2.2", + "@types/bun": "latest", + "@unhead/addons": "latest", + "@vitejs/plugin-vue": "latest", + "@vue/eslint-config-typescript": "latest", + "@vue/typescript-plugin": "latest", + "browserslist": "latest", + "drizzle-kit": "latest", + "eslint": "latest", + "eslint-plugin-perfectionist": "latest", + "eslint-plugin-vue": "latest", + "globals": "latest", + "jiti": "latest", + "knip": "latest", + "lightningcss": "latest", + "prettier": "latest", + "prettier-plugin-pkg": "latest", + "prettier-plugin-sh": "latest", + "tsr": "latest", + "typescript": "latest", + "vite": "latest", + "vite-plugin-vue-devtools": "latest", + "vue-tsc": "latest", }, }, }, "packages": { "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - "@antfu/utils": ["@antfu/utils@0.7.10", "", {}, "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww=="], + "@antfu/utils": ["@antfu/utils@8.1.1", "", {}, "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ=="], "@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], @@ -170,15 +177,15 @@ "@eslint/config-array": ["@eslint/config-array@0.19.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w=="], - "@eslint/core": ["@eslint/core@0.11.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA=="], + "@eslint/core": ["@eslint/core@0.12.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg=="], - "@eslint/eslintrc": ["@eslint/eslintrc@3.2.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w=="], + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.0", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ=="], - "@eslint/js": ["@eslint/js@9.20.0", "", {}, "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ=="], + "@eslint/js": ["@eslint/js@9.21.0", "", {}, "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw=="], "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.6", "", { "dependencies": { "@eslint/core": "^0.11.0", "levn": "^0.4.1" } }, "sha512-+0TjwR1eAUdZtvv/ir1mGX+v0tUoR3VEPB8Up0LLJC+whRW0GgBBtpbOkg/a/U4Dxa6l5a3l9AJ1aWIQVyoWJA=="], + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.7", "", { "dependencies": { "@eslint/core": "^0.12.0", "levn": "^0.4.1" } }, "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -186,7 +193,7 @@ "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.1", "", {}, "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA=="], + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], @@ -210,16 +217,14 @@ "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3", "", { "os": "win32", "cpu": "x64" }, "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@4.0.1", "", { "dependencies": { "@nodelib/fs.stat": "4.0.0", "run-parallel": "^1.2.0" } }, "sha512-vAkI715yhnmiPupY+dq+xenu5Tdf2TBQ66jLvBIcCddtz+5Q8LbMKaf9CIJJreez8fQ8fgaY+RaywQx8RJIWpw=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@nodelib/fs.walk": ["@nodelib/fs.walk@3.0.1", "", { "dependencies": { "@nodelib/fs.scandir": "4.0.1", "fastq": "^1.15.0" } }, "sha512-nIh/M6Kh3ZtOmlY00DaUYB4xeeV6F3/ts1l29iwl3/cfyY/OuCfUx+v08zgx8TKPTifXRcjjqVQ4KB2zOYSbyw=="], "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.30.0", "", {}, "sha512-4VlGgo32k2EQ2wcCY3vEU28A0O13aOtHz3Xt2/2U5FAh9EfhD6t6DqL5Z6yAnRCntbTFDU4YfbpyzSlHNWycPw=="], - "@pkgr/core": ["@pkgr/core@0.1.1", "", {}, "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA=="], - "@polka/url": ["@polka/url@1.0.0-next.28", "", {}, "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw=="], "@rollup/pluginutils": ["@rollup/pluginutils@5.1.4", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ=="], @@ -266,6 +271,8 @@ "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], + "@snyk/github-codeowners": ["@snyk/github-codeowners@1.1.0", "", { "dependencies": { "commander": "^4.1.1", "ignore": "^5.1.8", "p-map": "^4.0.0" }, "bin": { "github-codeowners": "dist/cli.js" } }, "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw=="], + "@sqlite.org/sqlite-wasm": ["@sqlite.org/sqlite-wasm@3.48.0-build4", "", { "bin": { "sqlite-wasm": "bin/index.js" } }, "sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ=="], "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], @@ -278,6 +285,8 @@ "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="], + "@types/web-bluetooth": ["@types/web-bluetooth@0.0.20", "", {}, "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="], + "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.24.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.24.1", "@typescript-eslint/type-utils": "8.24.1", "@typescript-eslint/utils": "8.24.1", "@typescript-eslint/visitor-keys": "8.24.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA=="], @@ -300,6 +309,10 @@ "@ungap/with-resolvers": ["@ungap/with-resolvers@0.1.0", "", {}, "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw=="], + "@unhead/addons": ["@unhead/addons@2.0.0-alpha.19", "", { "dependencies": { "@rollup/pluginutils": "^5.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17", "mlly": "^1.7.4", "ufo": "^1.5.4", "unplugin": "^2.2.0", "unplugin-ast": "^0.14.0" }, "peerDependencies": { "unhead": "2.0.0-alpha.19" } }, "sha512-nzTC9/J6SJ425YSFZoC2Hf1w3JbmGO3zvT4CsY9/RF0ByihxsIH63v84nVN/K0hAm1CeOVho53yWH1lTgcNksQ=="], + + "@unhead/vue": ["@unhead/vue@2.0.0-alpha.19", "", { "dependencies": { "hookable": "^5.5.3", "unhead": "2.0.0-alpha.19" }, "peerDependencies": { "vue": ">=3.5.13" } }, "sha512-PEjFg2oYXKZOGnR75ANReudH+/OdRlQkE8jwf9KBFLXiuu94tdqyph3gcgUs0pHsZmgVYpwxvdkOg+lldBUpjA=="], + "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.1", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ=="], "@volar/language-core": ["@volar/language-core@2.4.11", "", { "dependencies": { "@volar/source-map": "2.4.11" } }, "sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg=="], @@ -332,8 +345,6 @@ "@vue/devtools-shared": ["@vue/devtools-shared@7.7.2", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA=="], - "@vue/eslint-config-prettier": ["@vue/eslint-config-prettier@10.2.0", "", { "dependencies": { "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2" }, "peerDependencies": { "eslint": ">= 8.21.0", "prettier": ">= 3.0.0" } }, "sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw=="], - "@vue/eslint-config-typescript": ["@vue/eslint-config-typescript@14.4.0", "", { "dependencies": { "@typescript-eslint/utils": "^8.23.0", "fast-glob": "^3.3.3", "typescript-eslint": "^8.23.0", "vue-eslint-parser": "^9.4.3" }, "peerDependencies": { "eslint": "^9.10.0", "eslint-plugin-vue": "^9.28.0", "typescript": ">=4.8.4" }, "optionalPeers": ["typescript"] }, "sha512-daU+eAekEeVz3CReE4PRW25fe+OJDKwE28jHN6LimDEnuFMbJ6H4WGogEpNof276wVP6UvzOeJQfLFjB5mW29A=="], "@vue/language-core": ["@vue/language-core@2.2.2", "", { "dependencies": { "@volar/language-core": "~2.4.11", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^1.0.3", "minimatch": "^9.0.3", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-QotO41kurE5PLf3vrNgGTk3QswO2PdUFjBwNiOi7zMmGhwb25PSTh9hD1MCgKC06AVv+8sZQvlL3Do4TTVHSiQ=="], @@ -348,20 +359,36 @@ "@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], + "@vue/typescript-plugin": ["@vue/typescript-plugin@2.2.2", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.2", "@vue/shared": "^3.5.0" } }, "sha512-M/fNR/M4Rt+jm7Vmv21sPoHNM7MLYC7QjW5gqmP9y6HGmIlxOubqXYIqddeEnikmEsOc3linykEAxAIVxfIvbA=="], + + "@vueuse/core": ["@vueuse/core@12.7.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "12.7.0", "@vueuse/shared": "12.7.0", "vue": "^3.5.13" } }, "sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA=="], + + "@vueuse/metadata": ["@vueuse/metadata@12.7.0", "", {}, "sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g=="], + + "@vueuse/router": ["@vueuse/router@12.7.0", "", { "dependencies": { "@vueuse/shared": "12.7.0", "vue": "^3.5.13" }, "peerDependencies": { "vue-router": ">=4.0.0-rc.1" } }, "sha512-Jp6dIel54oc2nh++zqjY06ipCcTT6YWDCNQ8dSSnqRwx90wIl7w7MQP7Wpp1wrDwXEoqhelfeZf2gjfrkAhq3g=="], + + "@vueuse/shared": ["@vueuse/shared@12.7.0", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw=="], + "a11y-dialog": ["a11y-dialog@8.1.1", "", { "dependencies": { "focusable-selectors": "^0.8.0" } }, "sha512-7SBLXFwhQBnEHOaIiKUUQZ5VKJa/b1jBDvPJvlejlqX2w9cpi+iHBrdjcmd4Xd6vIdsuMHGo9Is2SWu0Hzu0zg=="], "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "alien-signals": ["alien-signals@1.0.3", "", {}, "sha512-zQOh3wAYK5ujENxvBBR3CFGF/b6afaSzZ/c9yNhJ1ENrGHETvpUuKQsa93Qrclp0+PzTF93MaZ7scVp1uUozhA=="], - "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "ast-kit": ["ast-kit@1.4.0", "", { "dependencies": { "@babel/parser": "^7.26.5", "pathe": "^2.0.2" } }, "sha512-BlGeOw73FDsX7z0eZE/wuuafxYoek2yzNJ6l6A1nsb4+z/p87TOPbHaWuN53kFKNuUXiCQa2M+xLF71IqQmRSw=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "birpc": ["birpc@0.2.19", "", {}, "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ=="], @@ -372,8 +399,6 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browserlist": ["browserlist@1.0.1", "", { "dependencies": { "chalk": "^2.4.1" }, "bin": { "browserlist": "./cli.js" } }, "sha512-nYq9jiWv+qXcgrJxQzivfEc7Wo2GvAKkeRViE5L3cUJpq4SZO6NZR710I/8T+OjE5BPECbzpm8rpUkwslE3nTg=="], - "browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="], "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], @@ -386,16 +411,24 @@ "caniuse-lite": ["caniuse-lite@1.0.30001700", "", {}, "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ=="], - "chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + + "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], "coincident": ["coincident@1.2.3", "", { "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", "gc-hook": "^0.3.1", "proxy-target": "^3.0.2" }, "optionalDependencies": { "ws": "^8.16.0" } }, "sha512-Uxz3BMTWIslzeWjuQnizGWVg0j6khbvHUQ8+5BdM7WuJEm4ALXwq3wluYoB+uF68uPBz/oUOeJnYURKyfjexlA=="], - "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="], @@ -416,6 +449,8 @@ "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], @@ -424,10 +459,14 @@ "drizzle-orm": ["drizzle-orm@0.39.3", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-EZ8ZpYvDIvKU9C56JYLOmUskazhad+uXZCTCRN4OnRMsL+xAJ05dv1eCpAG5xzhsm1hqiuC5kAZUCS924u2DTw=="], + "easy-table": ["easy-table@1.2.0", "", { "dependencies": { "ansi-regex": "^5.0.1" }, "optionalDependencies": { "wcwidth": "^1.0.1" } }, "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww=="], + "effect": ["effect@3.13.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-/w+CPqHDJ33Wq7xC4YKAchrEEPtjvxh563xH9kDTZp99seNYBoBs87vl8DJwartEjj+KLQLP8PzoDne+XmGT2A=="], "electron-to-chromium": ["electron-to-chromium@1.5.102", "", {}, "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q=="], + "enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="], + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "error-stack-parser-es": ["error-stack-parser-es@0.1.5", "", {}, "sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg=="], @@ -440,14 +479,10 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@9.20.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.11.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.20.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g=="], - - "eslint-config-prettier": ["eslint-config-prettier@10.0.1", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "build/bin/cli.js" } }, "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw=="], + "eslint": ["eslint@9.21.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.0", "@eslint/js": "9.21.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg=="], "eslint-plugin-perfectionist": ["eslint-plugin-perfectionist@4.9.0", "", { "dependencies": { "@typescript-eslint/types": "^8.24.0", "@typescript-eslint/utils": "^8.24.0", "natural-orderby": "^5.0.0" }, "peerDependencies": { "eslint": ">=8.0.0" } }, "sha512-76lDfJnonOcXGW3bEXuqhEGId0LrOlvIE1yLHvK/eKMMPOc0b43KchAIR2Bdbqlg+LPXU5/Q+UzuzkO+cWHT6w=="], - "eslint-plugin-prettier": ["eslint-plugin-prettier@5.2.3", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": "*", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw=="], - "eslint-plugin-vue": ["eslint-plugin-vue@9.32.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", "postcss-selector-parser": "^6.0.15", "semver": "^7.6.3", "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, "peerDependencies": { "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, "sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug=="], "eslint-scope": ["eslint-scope@8.2.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A=="], @@ -462,7 +497,7 @@ "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], @@ -472,8 +507,6 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], - "fast-glob": ["fast-glob@3.3.3", "", { "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.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], @@ -512,13 +545,13 @@ "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], + "globals": ["globals@16.0.0", "", {}, "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - "has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], @@ -534,6 +567,8 @@ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -576,6 +611,8 @@ "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + "knip": ["knip@5.44.4", "", { "dependencies": { "@nodelib/fs.walk": "3.0.1", "@snyk/github-codeowners": "1.1.0", "easy-table": "1.2.0", "enhanced-resolve": "^5.18.0", "fast-glob": "^3.3.3", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "minimist": "^1.2.8", "picocolors": "^1.1.0", "picomatch": "^4.0.1", "pretty-ms": "^9.0.0", "smol-toml": "^1.3.1", "strip-json-comments": "5.0.1", "summary": "2.1.0", "zod": "^3.22.4", "zod-validation-error": "^3.0.3" }, "peerDependencies": { "@types/node": ">=18", "typescript": ">=5.0.4" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-Ryn8LwWHLId8jSK1DgtT0hmg5DbzkqAtH+Gg3vZJpmSMgGHMspej9Ag+qKTm8wsPLDjVetuEz/lIsobo0XCMvQ=="], + "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], @@ -612,14 +649,22 @@ "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + "magic-string-ast": ["magic-string-ast@0.7.0", "", { "dependencies": { "magic-string": "^0.30.17" } }, "sha512-686fgAHaJY7wLTFEq7nnKqeQrhqmXB19d1HnqT35Ci7BN6hbAYLZUezTQ062uUHM7ggZEQlqJ94Ftls+KDXU8Q=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], + "mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -632,6 +677,8 @@ "multipasta": ["multipasta@0.2.5", "", {}, "sha512-c8eMDb1WwZcE02WVjHoOmUVk7fnKU/RmUcosHACglrWAuPQsEJv+E8430sXj6jNc1jHw0zrS16aCjQh4BcEb4A=="], + "mvdan-sh": ["mvdan-sh@0.10.1", "", {}, "sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg=="], + "nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -654,6 +701,8 @@ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], @@ -670,10 +719,12 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], "pinia": ["pinia@3.0.1", "", { "dependencies": { "@vue/devtools-api": "^7.7.2" }, "peerDependencies": { "typescript": ">=4.4.4", "vue": "^2.7.0 || ^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg=="], + "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "postcss": ["postcss@8.5.2", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA=="], "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], @@ -682,7 +733,9 @@ "prettier": ["prettier@3.5.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw=="], - "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="], + "prettier-plugin-pkg": ["prettier-plugin-pkg@0.18.1", "", { "peerDependencies": { "prettier": "^3.0.3" } }, "sha512-FuUxvsYZR/8rsLH8s/jbPQmgYvv0yxW8LoIHCy6+Q7p4FBjjdP3DNKx8fMTOsc0SlEB1skB4o1LcahRceIh87A=="], + + "prettier-plugin-sh": ["prettier-plugin-sh@0.15.0", "", { "dependencies": { "mvdan-sh": "^0.10.1", "sh-syntax": "^0.4.2" }, "peerDependencies": { "prettier": "^3.0.3" } }, "sha512-U0PikJr/yr2bzzARl43qI0mApBj0C1xdAfA04AZa6LnvIKawXHhuy2fFo6LNA7weRzGlAiNbaEFfKMFo0nZr/A=="], "pretty-ms": ["pretty-ms@9.2.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg=="], @@ -710,6 +763,8 @@ "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + "sh-syntax": ["sh-syntax@0.4.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-/l2UZ5fhGZLVZa16XQM9/Vq/hezGGbdHeVEA01uWjOL1+7Ek/gt6FquW0iKKws4a9AYPYvlz6RyVvjh3JxOteg=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], @@ -718,6 +773,8 @@ "sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="], + "smol-toml": ["smol-toml@1.3.1", "", {}, "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -730,15 +787,17 @@ "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "strip-json-comments": ["strip-json-comments@5.0.1", "", {}, "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw=="], + + "summary": ["summary@2.1.0", "", {}, "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw=="], "superjson": ["superjson@2.2.2", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q=="], - "supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "svg-tags": ["svg-tags@1.0.0", "", {}, "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA=="], - "synckit": ["synckit@0.9.2", "", { "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" } }, "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw=="], + "tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -748,6 +807,8 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tsr": ["tsr@1.3.4", "", { "dependencies": { "mri": "^1.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "typescript": ">=4.0.0" }, "bin": { "tsr": "dist/cli.js" } }, "sha512-VHGK2GNokLaQ2OXdL4kE8+U9Dn6EWmDEZ/HdoFCnOoyR6ZFxi0QdzshPs7ZJ1xY9lfi+pQ0hZI5fLZAHZIJ+GA=="], + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], @@ -756,12 +817,22 @@ "typescript-eslint": ["typescript-eslint@8.24.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.24.1", "@typescript-eslint/parser": "8.24.1", "@typescript-eslint/utils": "8.24.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA=="], + "ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], + "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "unhead": ["unhead@2.0.0-alpha.19", "", { "dependencies": { "hookable": "^5.5.3" } }, "sha512-MbjBinF3G61+Ecy/eQt013SCdnIdUhu14JKyDf7fAzpV0d6snC6BdPY/O+NOk4MNWpxrD05Dc8/AJ/8Vpo66IQ=="], + "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "unplugin": ["unplugin@2.2.0", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-m1ekpSwuOT5hxkJeZGRxO7gXbXT3gF26NjQ7GdVHoLoF8/nopLcd/QfPigpCy7i51oFHiRJg/CyHhj4vs2+KGw=="], + + "unplugin-ast": ["unplugin-ast@0.14.0", "", { "dependencies": { "@antfu/utils": "^8.1.0", "@babel/generator": "^7.26.5", "ast-kit": "^1.4.0", "magic-string-ast": "^0.7.0", "unplugin": "^2.1.2", "unplugin-utils": "^0.2.0" } }, "sha512-a9MPyEyrecxmaMGS7xmwYVXcdZIAPaAr+ePmPR1duTh3Bk6/QxR70udb4dkvggZzy9AuzD/7b0RVCcA/N9HmzQ=="], + + "unplugin-utils": ["unplugin-utils@0.2.4", "", { "dependencies": { "pathe": "^2.0.2", "picomatch": "^4.0.2" } }, "sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA=="], + "update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -790,6 +861,10 @@ "vue-tsc": ["vue-tsc@2.2.2", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.2" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-1icPKkxAA5KTAaSwg0wVWdE48EdsH8fgvcbAiqojP4jXKl6LEM3soiW1aG/zrWrFt8Mw1ncG2vG1PvpZpVfehA=="], + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], @@ -800,10 +875,16 @@ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="], + "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], + + "zod-validation-error": ["zod-validation-error@3.4.0", "", { "peerDependencies": { "zod": "^3.18.0" } }, "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -818,30 +899,40 @@ "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + "@eslint/eslintrc/strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], - "@rollup/pluginutils/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "@nodelib/fs.scandir/@nodelib/fs.stat": ["@nodelib/fs.stat@4.0.0", "", {}, "sha512-ctr6bByzksKRCV0bavi8WoQevU6plSp2IkllIsEqaiKe2mwNNnaluhnRhcsgGZHrrHk57B3lf95MkLMO3STYcg=="], + + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@vue/compiler-core/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "@vue/devtools-core/nanoid": ["nanoid@5.1.0", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw=="], "@vue/language-core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], - - "eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "eslint-plugin-vue/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="], + "fast-glob/@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "node-gyp-build-optional-packages/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="], "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "vite/esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="], + "vite-plugin-inspect/@antfu/utils": ["@antfu/utils@0.7.10", "", {}, "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww=="], + "vue-eslint-parser/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], "vue-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], @@ -898,9 +989,7 @@ "@vue/language-core/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - "eslint/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "eslint/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "fast-glob/@nodelib/fs.walk/@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="], @@ -947,11 +1036,5 @@ "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="], "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="], - - "eslint/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "eslint/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "eslint/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], } } diff --git a/cfg/.prettierignore b/cfg/.prettierignore new file mode 100755 index 0000000..52d6d45 --- /dev/null +++ b/cfg/.prettierignore @@ -0,0 +1,26 @@ +# Tout ce qui est traité par dprint +*.css +*.html +*.js +*.json +*.jsonc +*.md +*.mjs +*.mts +*.ts +*.vue +*.yaml +*.yml +!package.json + +# Cache +.cache + +# Compilation +dist + +# Jujutsu +.jj + +# Zed +.zed diff --git a/dprint.json b/cfg/dprint.json similarity index 99% rename from dprint.json rename to cfg/dprint.json index 48f3ac1..4df9a71 100644 --- a/dprint.json +++ b/cfg/dprint.json @@ -16,7 +16,7 @@ "jsonTrailingCommaFiles": [".swcrc", "biome.jsonc", "settings.json", "tsconfig.json"], "lineWidth": 120, "newLineKind": "lf", - "preferSingleLine": true, + "preferSingleLine": false, "trailingCommas": "never", "useTabs": false }, diff --git a/eslint.config.mts b/cfg/eslint.config.mts similarity index 88% rename from eslint.config.mts rename to cfg/eslint.config.mts index 510aae7..bc08986 100644 --- a/eslint.config.mts +++ b/cfg/eslint.config.mts @@ -6,19 +6,10 @@ import globals from "globals"; export default defineConfigWithVueTs( { files: ["**/*.{js,mjs,ts,mts,vue}"], - languageOptions: { - ecmaVersion: "latest", - globals: { - ...globals.browser, - ...globals.es2025, - }, - }, + languageOptions: { ecmaVersion: "latest", globals: { ...globals.browser, ...globals.es2025 } }, name: "app/files-to-lint", }, - { - ignores: [".cache/", "dist/", "node_modules/"], - name: "app/files-to-ignore", - }, + { ignores: [".cache/", "dist/", "node_modules/"], name: "app/files-to-ignore" }, vueTsConfigs.strictTypeChecked, vueTsConfigs.stylisticTypeChecked, vue.configs["flat/recommended"], @@ -29,9 +20,7 @@ export default defineConfigWithVueTs( "vue/array-bracket-spacing": "off", "vue/array-element-newline": "off", "vue/arrow-spacing": "off", - "vue/attributes-order": ["error", { - alphabetical: true, - }], + "vue/attributes-order": ["error", { alphabetical: true }], "vue/block-spacing": "off", "vue/block-tag-newline": "off", "vue/brace-style": "off", diff --git a/cfg/knip.config.ts b/cfg/knip.config.ts new file mode 100644 index 0000000..6c1a4e7 --- /dev/null +++ b/cfg/knip.config.ts @@ -0,0 +1,13 @@ +import type { KnipConfig } from "knip"; + +const config: KnipConfig = { + entry: [ + "vite.config.mts", + "src/main.ts", + "src/App.vue", + "pages/**/*.vue", + ], + project: ["src/**/*.{ts,vue}"], +}; + +export default config; diff --git a/prettier.config.mjs b/cfg/prettier.config.mjs similarity index 82% rename from prettier.config.mjs rename to cfg/prettier.config.mjs index 302f420..c7ca140 100644 --- a/prettier.config.mjs +++ b/cfg/prettier.config.mjs @@ -10,14 +10,7 @@ const config = { htmlWhitespaceSensitivity: "ignore", jsxSingleQuote: false, objectWrap: "collapse", - overrides: [ - { - files: ["package.json"], - options: { - plugins: ["prettier-plugin-pkg"], - }, - }, - ], + overrides: [{ files: ["package.json"], options: { plugins: ["prettier-plugin-pkg"] } }], plugins: ["prettier-plugin-sh"], printWidth: 120, proseWrap: "never", diff --git a/cspell.json b/cspell.json index 2fcb74e..0c66d33 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1,17 @@ -{ "words": ["oxlint", "lightningcss", "sqlocal", "Tmdb", "AUTOINCREMENT"] } +{ + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "version": "0.2", + "dictionaries": [ + "fr-fr" + ], + "words": [ + "oxlint", + "lightningcss", + "sqlocal", + "Tmdb", + "AUTOINCREMENT", + "vtsls", + "quartary", + "fieldset" + ] +} diff --git a/env.d.ts b/env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/index.html b/index.html index 63b098a..2e26614 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,22 @@ - - - Vite App + + + Journal Média + + + + + -
+
+
+

loading

+
+
diff --git a/justfile b/justfile new file mode 100755 index 0000000..8500f0a --- /dev/null +++ b/justfile @@ -0,0 +1,89 @@ +set shell := ["fish", "-c"] + +# Variables de chemins de configuration. + +drizzleConfigFile := "src/db/drizzle.config.ts" +prettierConfigFile := "cfg/prettier.config.mjs" +prettierIgnoreFile := "cfg/.prettierignore" +esLintConfigFile := "cfg/eslint.config.mts" +knipConfigFile := "cfg/knip.config.ts" + +# Variables de cache. + +cacheFolder := ".cache" +prettierCacheFile := "prettiercache" +stylelintCacheFile := "stylelintcache" + +# Variables de dossiers. + +stylesFolder := "src/styles/" + +### + +# Liste toutes les recettes. +list: + @just --list --list-heading 'Recettes disponibles :'\n'' --unsorted + +# Lance le mode de développement. +dev: + bun --bun vite dev + +# Compile le projet. +build: + -bun --bun vue-tsc --build . + bun --bun vite build + +# Lance la prévisualisation du mode de production. +preview: + just build + bun --bun vite preview + +# Met à jour les dépendances avec bun. +update: + bun update --latest + +# Affiche les dépendances obsolètes avec bun. +outdated: + bun outdated --latest + +# Génère un nouveau schéma de BDD. +db-generate-schema: + bun drizzle-kit --config {{ drizzleConfigFile }} generate + +# Formate avec prettier puis dprint. +format: + bun --bun prettier \ + --cache --cache-location "{{ cacheFolder }}/{{ prettierCacheFile }}" \ + --config "{{ prettierConfigFile }}" \ + --ignore-path ".gitignore" --ignore-path "{{ prettierIgnoreFile }}" \ + --ignore-unknown \ + --write \ + . + dprint --config "cfg/dprint.json" fmt + +watch-format: + watchexec dprint --config "cfg/dprint.json" fmt + +# Vérifie le code CSS avec stylelint. +lint-css: + bun --bun stylelint \ + --cache --cache-location "{{ cacheFolder }}/{{ stylelintCacheFile }}" \ + --fix \ + {{ stylesFolder }} + +# Analyse le code TypeScript et Astro. +lint-js fix="": + bun --bun eslint --config "{{ esLintConfigFile }}" {{ fix }} + +# Analyse l'orthographe et la grammaire. +lint-spelling: + bun --bun cspell lint * + +# Vérifie la présence de « code mort ». +lint-dead-code: + bun knip-bun --config "{{ knipConfigFile }}" + +# Vérifie tous les fichiers. +lint-all: + just lint-css + just lint-js diff --git a/package.json b/package.json index 1046d14..689ec3b 100644 --- a/package.json +++ b/package.json @@ -1,40 +1,49 @@ { "name": "journal-media", "version": "0.0.0", - "private": true, "type": "module", + "private": true, "scripts": { - "dev": "vite", - "preview": "vite preview", "build-only": "vite build", - "type-check": "vue-tsc --build", - "lint:eslint": "eslint . --fix" + "dev": "vite", + "lint:eslint": "eslint . --fix", + "preview": "vite preview", + "type-check": "vue-tsc --build" }, "dependencies": { "@effect/platform": "^0.77.2", "@effect/sql-drizzle": "^0.29.2", + "@unhead/vue": "^2.0.0-alpha.19", + "@vueuse/core": "^12.7.0", + "@vueuse/router": "^12.7.0", "a11y-dialog": "^8.1.1", "drizzle-orm": "^0.39.3", "effect": "^3.13.2", "pinia": "^3.0.1", "sqlocal": "^0.14.0", + "unhead": "^2.0.0-alpha.19", "vue": "^3.5.13", "vue-router": "^4.5.0" }, "devDependencies": { "@types/bun": "^1.2.2", - "@types/node": "^22.13.4", + "@unhead/addons": "^2.0.0-alpha.19", "@vitejs/plugin-vue": "^5.2.1", "@vue/eslint-config-typescript": "^14.4.0", + "@vue/typescript-plugin": "^2.2.2", "browserslist": "^4.24.4", "drizzle-kit": "^0.30.4", - "eslint": "^9.20.1", + "eslint": "^9.21.0", "eslint-plugin-perfectionist": "^4.9.0", "eslint-plugin-vue": "^9.32.0", - "globals": "^15.15.0", + "globals": "^16.0.0", "jiti": "^2.4.2", + "knip": "^5.44.4", "lightningcss": "^1.29.1", "prettier": "^3.5.1", + "prettier-plugin-pkg": "^0.18.1", + "prettier-plugin-sh": "^0.15.0", + "tsr": "^1.3.4", "typescript": "^5.7.3", "vite": "^6.1.1", "vite-plugin-vue-devtools": "^7.7.2", diff --git a/public/app-loading.css b/public/app-loading.css new file mode 100644 index 0000000..b46e74c --- /dev/null +++ b/public/app-loading.css @@ -0,0 +1,40 @@ +@import url("fonts.css"); + +#app-loading { + position: fixed; + inset: 0; + text-align: center; + align-content: center; + z-index: 100; + background: salmon; + font-family: Banquise; + font-size: 2rem; + + p { + width: 10ch; + margin: auto; + } + + p::after { + content: ""; + animation: 2s forwards infinite loading; + } +} + +@keyframes loading { + from { + content: ""; + } + 25% { + content: "."; + } + 50% { + content: ".."; + } + 75% { + content: "..."; + } + to { + content: ""; + } +} diff --git a/public/favicon/favicon.svg b/public/favicon/favicon.svg new file mode 100755 index 0000000..f157bd1 --- /dev/null +++ b/public/favicon/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/public/fonts.css b/public/fonts.css new file mode 100644 index 0000000..9bc07b5 --- /dev/null +++ b/public/fonts.css @@ -0,0 +1,25 @@ +@font-face { + font-family: BRKLY; + font-weight: 100 150; + font-style: normal; + font-display: swap; + src: url("/fonts/BerkeleyMonoVariable-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: BRKLY; + font-weight: 100 150; + font-style: italic; + font-display: swap; + src: url("/fonts/BerkeleyMonoVariable-Italic.ttf") format("truetype"); +} + +@font-face { + font-family: Banquise; + font-weight: 400; + font-style: normal; + font-display: swap; + src: + url("/fonts/Banquise-Regular.woff") format("woff"), + url("/fonts/Banquise-Regular.otf") format("opentype"); +} diff --git a/public/fonts/Banquise-Regular.otf b/public/fonts/Banquise-Regular.otf new file mode 100644 index 0000000..6d0a58f Binary files /dev/null and b/public/fonts/Banquise-Regular.otf differ diff --git a/public/fonts/Banquise-Regular.woff b/public/fonts/Banquise-Regular.woff new file mode 100644 index 0000000..9454177 Binary files /dev/null and b/public/fonts/Banquise-Regular.woff differ diff --git a/public/fonts/BerkeleyMonoVariable-Italic.ttf b/public/fonts/BerkeleyMonoVariable-Italic.ttf new file mode 100644 index 0000000..07993aa Binary files /dev/null and b/public/fonts/BerkeleyMonoVariable-Italic.ttf differ diff --git a/public/fonts/BerkeleyMonoVariable-Regular.ttf b/public/fonts/BerkeleyMonoVariable-Regular.ttf new file mode 100644 index 0000000..842e17c Binary files /dev/null and b/public/fonts/BerkeleyMonoVariable-Regular.ttf differ diff --git a/src/App.vue b/src/App.vue index 2edf06e..a836508 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,33 @@ + + diff --git a/src/components/ErrorComponent.vue b/src/components/ErrorComponent.vue deleted file mode 100644 index 2c73a10..0000000 --- a/src/components/ErrorComponent.vue +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/src/components/ImposterBox.vue b/src/components/ImposterBox.vue new file mode 100644 index 0000000..6cb33b4 --- /dev/null +++ b/src/components/ImposterBox.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/components/LastAddedEntry.vue b/src/components/LastAddedEntry.vue index 5059355..6e83669 100644 --- a/src/components/LastAddedEntry.vue +++ b/src/components/LastAddedEntry.vue @@ -1,19 +1,25 @@ diff --git a/src/components/LoadingComponent.vue b/src/components/LoadingComponent.vue deleted file mode 100644 index bf9f285..0000000 --- a/src/components/LoadingComponent.vue +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/src/components/MainHeader.vue b/src/components/MainHeader.vue new file mode 100644 index 0000000..655e4ec --- /dev/null +++ b/src/components/MainHeader.vue @@ -0,0 +1,8 @@ + + + diff --git a/src/components/NavigationMenu.vue b/src/components/NavigationMenu.vue new file mode 100644 index 0000000..19a99af --- /dev/null +++ b/src/components/NavigationMenu.vue @@ -0,0 +1,16 @@ + + + + + diff --git a/src/db/drizzle.config.ts b/src/db/drizzle.config.ts index e613323..a1afdee 100644 --- a/src/db/drizzle.config.ts +++ b/src/db/drizzle.config.ts @@ -1,20 +1,5 @@ import type { Config } from "drizzle-kit"; -import { loadEnv } from "vite"; - -const env = loadEnv("development", process.cwd(), ""); -const DATABASE_URL = env["DATABASE_URL"]; - -// L'URL de la BDD doit être valide. -if (!DATABASE_URL || DATABASE_URL === "") { - throw new Error("L'URL de la base de données doit être renseignée dans le fichier de variables d'environnement."); -} - -const DrizzleKitConfig: Config = { - dbCredentials: { url: DATABASE_URL }, - dialect: "sqlite", - out: "./src/db/drizzle", - schema: "./src/db/schema.ts", -}; +const DrizzleKitConfig: Config = { dialect: "sqlite", out: "./src/db/drizzle", schema: "./src/db/schemas.ts" }; export default DrizzleKitConfig; diff --git a/src/db/drizzle/0000_perfect_justice.sql b/src/db/drizzle/0000_perfect_justice.sql index a4b3b03..62bb55a 100644 --- a/src/db/drizzle/0000_perfect_justice.sql +++ b/src/db/drizzle/0000_perfect_justice.sql @@ -3,7 +3,7 @@ CREATE TABLE `art_works` ( `medium_type_id` integer, `name` text NOT NULL, `release_date` text(10) NOT NULL, - FOREIGN KEY (`medium_type_id`) REFERENCES `medium_types`(`id`) ON UPDATE no action ON DELETE no action + FOREIGN KEY (`medium_type_id`) REFERENCES `media_types`(`id`) ON UPDATE no action ON DELETE no action ); --> statement-breakpoint CREATE TABLE `diary_entries` ( @@ -40,14 +40,14 @@ CREATE TABLE `genres` ( --> statement-breakpoint CREATE UNIQUE INDEX `genres_name_unique` ON `genres` (`name`);--> statement-breakpoint CREATE UNIQUE INDEX `genres_slug_unique` ON `genres` (`slug`);--> statement-breakpoint -CREATE TABLE `medium_types` ( +CREATE TABLE `media_types` ( `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `name` text NOT NULL, `slug` text NOT NULL ); --> statement-breakpoint -CREATE UNIQUE INDEX `medium_types_name_unique` ON `medium_types` (`name`);--> statement-breakpoint -CREATE UNIQUE INDEX `medium_types_slug_unique` ON `medium_types` (`slug`);--> statement-breakpoint +CREATE UNIQUE INDEX `media_types_name_unique` ON `media_types` (`name`);--> statement-breakpoint +CREATE UNIQUE INDEX `media_types_slug_unique` ON `media_types` (`slug`);--> statement-breakpoint CREATE TABLE `users` ( `email` text NOT NULL, `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, diff --git a/src/db/drizzle/meta/0000_snapshot.json b/src/db/drizzle/meta/0000_snapshot.json index e66a8a2..9ae39c9 100644 --- a/src/db/drizzle/meta/0000_snapshot.json +++ b/src/db/drizzle/meta/0000_snapshot.json @@ -26,10 +26,10 @@ }, "indexes": {}, "foreignKeys": { - "art_works_medium_type_id_medium_types_id_fk": { - "name": "art_works_medium_type_id_medium_types_id_fk", + "art_works_medium_type_id_media_types_id_fk": { + "name": "art_works_medium_type_id_media_types_id_fk", "tableFrom": "art_works", - "tableTo": "medium_types", + "tableTo": "media_types", "columnsFrom": ["medium_type_id"], "columnsTo": ["id"], "onDelete": "no action", @@ -192,16 +192,16 @@ "uniqueConstraints": {}, "checkConstraints": {} }, - "medium_types": { - "name": "medium_types", + "media_types": { + "name": "media_types", "columns": { "id": { "name": "id", "type": "integer", "primaryKey": true, "notNull": true, "autoincrement": true }, "name": { "name": "name", "type": "text", "primaryKey": false, "notNull": true, "autoincrement": false }, "slug": { "name": "slug", "type": "text", "primaryKey": false, "notNull": true, "autoincrement": false } }, "indexes": { - "medium_types_name_unique": { "name": "medium_types_name_unique", "columns": ["name"], "isUnique": true }, - "medium_types_slug_unique": { "name": "medium_types_slug_unique", "columns": ["slug"], "isUnique": true } + "media_types_name_unique": { "name": "media_types_name_unique", "columns": ["name"], "isUnique": true }, + "media_types_slug_unique": { "name": "media_types_slug_unique", "columns": ["slug"], "isUnique": true } }, "foreignKeys": {}, "compositePrimaryKeys": {}, diff --git a/src/db/schemas.ts b/src/db/schemas.ts deleted file mode 100644 index c8f41b7..0000000 --- a/src/db/schemas.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { Values } from "@/libs/utils/types"; -import type { InferSelectModel } from "drizzle-orm"; -import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core"; - -import * as t from "drizzle-orm/sqlite-core"; -import { sqliteTable as table } from "drizzle-orm/sqlite-core"; - -import type { DIARY_ENTRY_STATES, MEDIUM_TYPES } from "./constants"; - -/** - * Configuration de la BDD SQLite de l'application. - * - * Assumer ici que toute colonne : - * - non explicitement définie comme optionnelle est obligatoire ; - * - non explicitement définie comme unique peut contenir plusieurs fois la même valeur ; - */ - -export const Users = table("users", { - email: t.text("email").notNull().unique(), - id: t.integer("id").primaryKey({ autoIncrement: true }), - name: t.text("name").notNull().unique(), -}); -export type User = InferSelectModel; - -export const MediumTypes = table("medium_types", { - id: t.integer("id").primaryKey({ autoIncrement: true }), - name: t.text("name").notNull().unique(), - slug: t.text("slug").$type>().notNull().unique(), -}); -export type MediumType = InferSelectModel; - -export const ArtWorks = table("art_works", { - id: t.integer("id").primaryKey({ autoIncrement: true }), - mediumTypeId: t.integer("medium_type_id").references((): AnySQLiteColumn => MediumTypes.id), - name: t.text("name").notNull(), - releaseDate: t.text("release_date", { length: 10 }).notNull(), -}); -export type ArtWork = InferSelectModel; - -export const Genres = table("genres", { - id: t.integer("id").primaryKey({ autoIncrement: true }), - name: t.text("name").notNull().unique(), - slug: t.text("slug").notNull().unique(), -}); -export type Genre = InferSelectModel; - -export const DiaryEntries = table("diary_entries", { - artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id), - dateCreated: t.text("date_created", { length: 10 }).notNull(), - dateModified: t.text("date_modified", { length: 10 }).notNull(), - id: t.integer("id").primaryKey({ autoIncrement: true }), - stateId: t.integer("state_id").references((): AnySQLiteColumn => DiaryEntriesStates.id), - userId: t.integer("user_id").references((): AnySQLiteColumn => Users.id), -}); -export type DiaryEntry = InferSelectModel; - -export const Viewings = table("viewings", { - artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id), - date: t.text("date", { length: 10 }).notNull(), - id: t.integer("id").primaryKey({ autoIncrement: true }), - userId: t.integer("user_id").references((): AnySQLiteColumn => Users.id), -}); -export type Viewing = InferSelectModel; - -export const DiaryEntriesGenres = table("diary_entries_genres", { - artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id), - genreId: t.integer("genre_id").references((): AnySQLiteColumn => Genres.id), - id: t.integer("id").primaryKey({ autoIncrement: true }), -}); -export type DiaryEntryGenre = InferSelectModel; - -export const DiaryEntriesStates = table("diary_entries_states", { - id: t.integer("id").primaryKey({ autoIncrement: true }), - state: t.text("state").$type>().notNull().unique(), -}); -export type DiaryEntryState = InferSelectModel; diff --git a/src/db/constants.ts b/src/db/schemas/constants.ts similarity index 95% rename from src/db/constants.ts rename to src/db/schemas/constants.ts index 90af842..a616ed8 100644 --- a/src/db/constants.ts +++ b/src/db/schemas/constants.ts @@ -1,4 +1,4 @@ -export const MEDIUM_TYPES = { +export const MEDIA_TYPES = { DOCUMENTARY: "documentary", FILM: "film", SERIES: "series", diff --git a/src/db/schemas/entries.ts b/src/db/schemas/entries.ts new file mode 100644 index 0000000..f20acd5 --- /dev/null +++ b/src/db/schemas/entries.ts @@ -0,0 +1,40 @@ +import type { Values } from "@/libs/utils/types"; +import type { InferSelectModel } from "drizzle-orm"; +import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core"; + +import * as t from "drizzle-orm/sqlite-core"; +import { sqliteTable as table } from "drizzle-orm/sqlite-core"; + +import type { DIARY_ENTRY_STATES } from "./constants"; + +import { ArtWorks, Genres } from "./works"; + +export const DiaryEntries = table("diary_entries", { + artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id), + dateCreated: t.text("date_created", { length: 10 }).notNull(), + dateModified: t.text("date_modified", { length: 10 }).notNull(), + id: t.integer("id").primaryKey({ autoIncrement: true }), + stateId: t.integer("state_id").references((): AnySQLiteColumn => DiaryEntriesStates.id).notNull(), +}); + +export const DiaryEntriesGenres = table("diary_entries_genres", { + artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id).notNull(), + genreId: t.integer("genre_id").references((): AnySQLiteColumn => Genres.id), + id: t.integer("id").primaryKey({ autoIncrement: true }), +}); + +export const DiaryEntriesStates = table("diary_entries_states", { + id: t.integer("id").primaryKey({ autoIncrement: true }), + state: t.text("state").$type>().notNull().unique(), +}); + +export const Viewings = table("viewings", { + artWorkId: t.integer("art_work_id").references((): AnySQLiteColumn => ArtWorks.id).notNull(), + date: t.text("date", { length: 10 }).notNull(), + id: t.integer("id").primaryKey({ autoIncrement: true }), +}); + +export type DiaryEntry = InferSelectModel; +export type DiaryEntryGenre = InferSelectModel; +export type DiaryEntryState = InferSelectModel; +export type Viewing = InferSelectModel; diff --git a/src/db/schemas/works.ts b/src/db/schemas/works.ts new file mode 100644 index 0000000..7daf6df --- /dev/null +++ b/src/db/schemas/works.ts @@ -0,0 +1,31 @@ +import type { Values } from "@/libs/utils/types"; +import type { InferSelectModel } from "drizzle-orm"; +import type { AnySQLiteColumn } from "drizzle-orm/sqlite-core"; + +import * as t from "drizzle-orm/sqlite-core"; +import { sqliteTable as table } from "drizzle-orm/sqlite-core"; + +import type { MEDIA_TYPES } from "./constants"; + +export const MediaTypes = table("media_types", { + id: t.integer("id").primaryKey({ autoIncrement: true }), + name: t.text("name").notNull().unique(), + slug: t.text("slug").$type>().notNull().unique(), +}); + +export const ArtWorks = table("art_works", { + id: t.integer("id").primaryKey({ autoIncrement: true }), + mediumTypeId: t.integer("medium_type_id").references((): AnySQLiteColumn => MediaTypes.id).notNull(), + name: t.text("name").notNull(), + releaseDate: t.text("release_date", { length: 10 }).notNull(), +}); + +export const Genres = table("genres", { + id: t.integer("id").primaryKey({ autoIncrement: true }), + name: t.text("name").notNull().unique(), + slug: t.text("slug").notNull().unique(), +}); + +export type ArtWork = InferSelectModel; +export type Genre = InferSelectModel; +export type MediaType = InferSelectModel; diff --git a/src/libs/apis/tmdb/schemas.ts b/src/libs/apis/tmdb/schemas.ts index 1f2411a..204acec 100644 --- a/src/libs/apis/tmdb/schemas.ts +++ b/src/libs/apis/tmdb/schemas.ts @@ -15,28 +15,33 @@ export class TmdbMovieSearchQueryParams extends Schema.Class "fr")), + region: Schema.NonEmptyString.pipe( + Schema.propertySignature, + Schema.withConstructorDefault(() => "fr"), + ), year: Schema.NonEmptyString.pipe(Schema.length(4), Schema.optional), }) {} export class TmdbMovieSearchResponse extends Schema.Class("TmdbMovieSearchResponse")({ page: Schema.NonNegativeInt, - results: Schema.Array(Schema.Struct({ - adult: Schema.Boolean, - backdrop_path: Schema.Union(Schema.String, Schema.Null), - genre_ids: Schema.Array(Schema.NonNegativeInt), - id: Schema.NonNegativeInt, - original_language: Schema.String, - original_title: Schema.String, - overview: Schema.String, - popularity: Schema.Number, - poster_path: Schema.Union(Schema.String, Schema.Null), - release_date: Schema.NonEmptyString.pipe(Schema.length(10)), - title: Schema.String, - video: Schema.Boolean, - vote_average: Schema.Number, - vote_count: Schema.NonNegativeInt, - })), + results: Schema.Array( + Schema.Struct({ + adult: Schema.Boolean, + backdrop_path: Schema.Union(Schema.String, Schema.Null), + genre_ids: Schema.Array(Schema.NonNegativeInt), + id: Schema.NonNegativeInt, + original_language: Schema.String, + original_title: Schema.String, + overview: Schema.String, + popularity: Schema.Number, + poster_path: Schema.Union(Schema.String, Schema.Null), + release_date: Schema.NonEmptyString.pipe(Schema.length(10)), + title: Schema.String, + video: Schema.Boolean, + vote_average: Schema.Number, + vote_count: Schema.NonNegativeInt, + }), + ), total_pages: Schema.NonNegativeInt, total_results: Schema.NonNegativeInt, }) {} diff --git a/src/libs/types/events.ts b/src/libs/types/events.ts new file mode 100644 index 0000000..c0c9b67 --- /dev/null +++ b/src/libs/types/events.ts @@ -0,0 +1,16 @@ +/** Événement émis au clic d'un Élément demandant l'ouverture d'une modale particulière. */ +export class DialogWantedEvent extends Event { + /** L'ID de la modale demandée. */ + dialogId: string; + + constructor(dialogId: string) { + super("dialog-wanted", { bubbles: true, composed: true }); + this.dialogId = dialogId; + } +} + +declare global { + interface GlobalEventHandlersEventMap { + "dialog-wanted": DialogWantedEvent; + } +} diff --git a/src/libs/utils/dates.ts b/src/libs/utils/dates.ts new file mode 100644 index 0000000..d819cdf --- /dev/null +++ b/src/libs/utils/dates.ts @@ -0,0 +1,7 @@ +export const getTodayDate = (): string => + new Date(Date.now()).toLocaleDateString("fr-FR", { + day: "numeric", + month: "long", + weekday: "long", + year: "numeric", + }); diff --git a/src/pages/HomePage.vue b/src/pages/HomePage.vue new file mode 100644 index 0000000..87792cb --- /dev/null +++ b/src/pages/HomePage.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/pages/NotFoundPage.vue b/src/pages/NotFoundPage.vue new file mode 100644 index 0000000..07bc10b --- /dev/null +++ b/src/pages/NotFoundPage.vue @@ -0,0 +1,13 @@ + + + diff --git a/src/router/index.ts b/src/router/index.ts index 1d93256..b723695 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,15 +1,40 @@ -import HomeView from "@/views/HomeView.vue"; -import { createRouter, createWebHistory } from "vue-router"; +import HomePage from "@/pages/HomePage.vue"; +import { Option, pipe, Predicate } from "effect"; +import { createRouter, createWebHistory, type Router } from "vue-router"; -const router = createRouter({ +const siteName = "Journal Média"; +const separator = "|"; + +const generatePageTitle = (siteName: string, separator: string, pageTitle: string): string => + [siteName, separator, pageTitle].join(" "); + +const router: Router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { - component: HomeView, - name: "home", + component: HomePage, + meta: { title: "Accueil" }, + name: "Home", path: "/", }, + { + component: () => import("@/pages/NotFoundPage.vue"), + meta: { title: "404" }, + name: "NotFound", + path: "/:pathMatch(.*)*", + }, ], }); +router.beforeEach((to, _): void => { + console.debug("router - to", to); + pipe( + Option.liftPredicate(Predicate.isString)(to.meta["title"]), + Option.getOrElse((): string => "???"), + (pageName: string): void => { + document.title = generatePageTitle(siteName, separator, pageName); + }, + ); +}); + export default router; diff --git a/src/router/typed-routes.d.ts b/src/router/typed-routes.d.ts new file mode 100644 index 0000000..db1d92f --- /dev/null +++ b/src/router/typed-routes.d.ts @@ -0,0 +1,25 @@ +import type { RouteRecordInfo } from "vue-router"; + +export interface RouteNamedMap { + Home: RouteRecordInfo< + "Home", + "/", + Record, + Record, + { title: string } + >; + NotFound: RouteRecordInfo< + "NotFound", + "/:pathMatch(.*)*", + { path: string }, + { path: string }, + { title: string } + >; +} + +// Last, you will need to augment the Vue Router types with this map of routes +declare module "vue-router" { + interface TypesConfig { + RouteNamedMap: RouteNamedMap; + } +} diff --git a/src/services/db.ts b/src/services/db.ts index 9984e57..6bf0ad0 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -1,9 +1,8 @@ -import { drizzle } from "drizzle-orm/sqlite-proxy"; +import { drizzle, type SqliteRemoteDatabase } from "drizzle-orm/sqlite-proxy"; import { Data, Effect } from "effect"; import { SQLocalDrizzle } from "sqlocal/drizzle"; -class LocalSqliteError extends Data.TaggedError("LocalSqliteError")<{ cause: unknown }> { -} +class LocalSqliteError extends Data.TaggedError("LocalSqliteError")<{ cause: unknown }> {} export class LocalSqlite extends Effect.Service()("LocalSqlite", { effect: Effect.gen(function*() { @@ -30,13 +29,13 @@ export class LocalSqlite extends Effect.Service()("LocalSqlite", { }), }); - const orm = drizzle(client.driver, client.batchDriver); + const orm: SqliteRemoteDatabase = drizzle(client.driver, client.batchDriver); const query = (execute: (_: typeof orm) => Promise) => - Effect.tryPromise({ - catch: (error: unknown) => new LocalSqliteError({ cause: error }), - try: () => execute(orm), - }); + Effect.tryPromise({ catch: (error: unknown) => new LocalSqliteError({ cause: error }), try: () => execute(orm) }); + + yield* Effect.logDebug("--- DB ---"); + yield* Effect.tryPromise(() => client.deleteDatabaseFile()); return { client, orm, query }; }), diff --git a/src/services/logger.ts b/src/services/logger.ts new file mode 100644 index 0000000..75a42eb --- /dev/null +++ b/src/services/logger.ts @@ -0,0 +1,14 @@ +import type { LogLevel } from "effect/LogLevel"; + +import { Config, ConfigProvider, Effect, Layer, Logger, pipe } from "effect"; + +const EnvConfigProvider = Layer.setConfigProvider(ConfigProvider.fromMap(new Map([["LOG_LEVEL", "DEBUG"]]))); + +const LogLevelLive = pipe( + Config.logLevel("LOG_LEVEL"), + Effect.andThen((level: LogLevel) => Logger.minimumLogLevel(level)), + Layer.unwrapEffect, // Convertis l'Effect en Layer + Layer.provide(EnvConfigProvider), +); + +export const PrettyLogger = Layer.mergeAll(Logger.pretty, LogLevelLive); diff --git a/src/services/migrations.ts b/src/services/migrations.ts new file mode 100644 index 0000000..cd535c3 --- /dev/null +++ b/src/services/migrations.ts @@ -0,0 +1,20 @@ +import type { SQLocalDrizzle } from "sqlocal/drizzle"; + +import v0000 from "@/db/drizzle/0000_perfect_justice.sql?raw"; +import { Data, Effect } from "effect"; + +import { LocalSqlite } from "./db"; + +class MigrationsError extends Data.TaggedError("MigrationsError")<{ cause: unknown }> {} + +const executeRawSql = (client: SQLocalDrizzle) => (sql: string) => + Effect.tryPromise({ catch: (error: unknown) => new MigrationsError({ cause: error }), try: () => client.sql(sql) }); + +export class Migrations extends Effect.Service()("Migrations", { + dependencies: [LocalSqlite.Default], + effect: Effect.gen(function*() { + const db = yield* LocalSqlite; + yield* Effect.logDebug("--- MIGRATIONS ---"); + return [yield* executeRawSql(db.client)(v0000)] as const; + }), +}) {} diff --git a/src/services/read-api.ts b/src/services/read-api.ts index 00ccb8d..aef8d0b 100644 --- a/src/services/read-api.ts +++ b/src/services/read-api.ts @@ -1,4 +1,4 @@ -import { DiaryEntries } from "@/db/schemas"; +import { DiaryEntries, Users } from "@/db/schemas"; import { singleResultOrFail } from "@/libs/utils/effects"; import { desc } from "drizzle-orm"; import { Data, Effect } from "effect"; @@ -12,11 +12,15 @@ export class ReadApi extends Effect.Service()("ReadApi", { effect: Effect.gen(function*() { const { query } = yield* LocalSqlite; + yield* Effect.logDebug("--- READ-API ---"); + return { + getAllEntries: () => query(_ => _.select().from(DiaryEntries)), getLastAddedEntry: () => query(_ => _.select().from(DiaryEntries).limit(1).orderBy(desc(DiaryEntries.dateCreated))).pipe( singleResultOrFail(() => new ReadApiError({ cause: "Aucune entrée n'a encore été ajoutée." })), ), + getUsers: () => query(_ => _.select().from(Users)), }; }), }) {} diff --git a/src/services/runtime-client.ts b/src/services/runtime-client.ts new file mode 100644 index 0000000..1e0a792 --- /dev/null +++ b/src/services/runtime-client.ts @@ -0,0 +1,15 @@ +import { Layer, ManagedRuntime } from "effect"; + +import { LocalSqlite } from "./db"; +import { PrettyLogger } from "./logger"; +import { Migrations } from "./migrations"; +import { ReadApi } from "./read-api"; + +const MainLayer = Layer.mergeAll( + // WriteApi.Default, + LocalSqlite.Default, + Migrations.Default, + ReadApi.Default, +).pipe(Layer.provide(PrettyLogger)); + +export const RuntimeClient = ManagedRuntime.make(MainLayer); diff --git a/src/styles/base/base.css b/src/styles/base/base.css new file mode 100755 index 0000000..0757d69 --- /dev/null +++ b/src/styles/base/base.css @@ -0,0 +1,119 @@ +/* + * 1. Utilise un meilleur modèle de boîte. + * 2. Fait que seul font-size puisse influencer la taille du texte. + * 3. Applique les schémas de couleurs. + * 4. Utilise une indentation plus étroite. + * 5. Permet l'usage de propriétés intrinsèques comme auto ou fit-content dans les animations. + */ +html { + box-sizing: border-box; /* 1 */ + tab-size: 2; /* 4 */ + color-scheme: dark light; /* 3 */ + interpolate-size: allow-keywords; /* 6 */ + /* stylelint-disable */ + -moz-text-size-adjust: none; /* 2 */ + -webkit-text-size-adjust: none; /* 2 */ + text-size-adjust: none; /* 2 */ + block-size: 100%; + /* stylelint-enable */ + + /* scrollbar-gutter: stable; */ +} + +body { + accent-color: var(--color-tertiary); + background: var(--color-secondary); + --webkit-font-smoothing: antialiased; + font-family: monospace, system-ui, sans-serif; + font-optical-sizing: auto; + font-kerning: normal; + font-variant-ligatures: common-ligatures no-discretionary-ligatures no-historical-ligatures + contextual; + line-height: var(--line-height-comfortable); + text-decoration-skip-ink: auto; + text-rendering: geometricprecision; +} + +/* + * 1. Hérite le modèle de boîte de l'élément racine. + * 2. Désactive toute marge pour partir de bases saines. + * 3. Hérite toute propriété typographique et de couleur pour éviter des redéfinitions. + */ +*, *::before, *::after { + box-sizing: inherit; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 2 */ + font: inherit; /* 3 */ + font-feature-settings: inherit; /* 3 */ + font-variation-settings: inherit; /* 3 */ + color: inherit; /* 3 */ + letter-spacing: inherit; /* 3 */ + word-spacing: inherit; /* 3 */ +} + +/* Utilise une couleur particulière pour l'arrière-plan des éléments sélectionnés avec le curseur. */ +*::selection { + color: var(--color-secondary); + background: var(--color-primary); +} + +/* TODO: Prendre en compte a11y-dialog */ +/* Empêche le défilement de la page quand une modale est ouverte. */ +:where(html:has(dialog:modal[open])) { + overflow: clip; +} + +/* Retire les bordures et applique un modèle d'arrière-plan plus sain. */ +*:where(:not(progress, meter)) { + background-repeat: no-repeat; + background-origin: border-box; + border: 0 solid transparent; +} + +/* Classe pour cacher visuellement tout en restant accessible par les lecteurs d'écran. */ +:where(.visually-hidden:not(:focus, :active, :focus-within)) { + position: absolute; + overflow: hidden; + inline-size: 1px; + block-size: 1px; + white-space: nowrap; + clip-path: inset(50%); +} + +/* Cache les éléments cachés. */ +:where([hidden]) { + display: none; +} + +/* Affiche un curseur « Désactivé » pour les éléments désactivés. */ +:where([disabled]) { + cursor: not-allowed; +} + +/* Applique des contours de focus visibles. */ +:where(:focus-visible) { + outline: currentcolor solid 0.2rem; + outline-offset: 0.2rem; +} + +:where(:focus-visible, :target) { + scroll-margin-block: 8vh; +} + +/* Active une transition de page simple. */ +@view-transition { + navigation: auto; +} + +/* Désactive animations et transitions pour les Utilisateurs le demandant explicitement. */ +@media (prefers-reduced-motion) { + *, *::before, *::after { + scroll-behavior: auto !important; + transition: none !important; + animation-duration: 0s !important; + } + + @view-transition { + navigation: none !important; + } +} diff --git a/src/styles/base/elements.css b/src/styles/base/elements.css new file mode 100644 index 0000000..d6ed7a8 --- /dev/null +++ b/src/styles/base/elements.css @@ -0,0 +1,56 @@ +/* Réinitialise l'apparence d'éléments interactifs. */ +:where(button, fieldset, input, select, textarea) { + appearance: none; +} + +/* Hauteur de ligne plus étroite pour les éléments interactifs. */ +:where(button, fieldset, input, label, select, textarea) { + line-height: var(--line-height-compact); +} + +:where(textarea) { + resize: vertical; +} + +@supports (resize: block) { + :where(textarea) { + resize: block; + } +} + +/* Curseur de main pour les éléments interactifs cliquables. */ +:where(button, label, select) { + cursor: pointer; +} + +:where(button) { + inline-size: fit-content; +} + +/* Évite le dépassement des textes. */ +:where(p, h1, h2, h3, h4, h5, h6) { + overflow-wrap: break-word; +} + +/* Les médias doivent occuper toute la longueur disponible au sein de leur propre bloc. */ +:where(img, picture, video, canvas, svg) { + display: block; + max-inline-size: 100%; + block-size: auto; +} + +:where(ol, ul) { + list-style: none; +} + +:where(a) { + text-decoration: none; +} + +/* + * Empêche les marqueurs de listes de modifier la hauteur de ligne sur Firefox. + * https://danburzo.ro/notes/moz-bullet-font + */ +::marker { + line-height: 0; +} diff --git a/src/styles/base/variables.css b/src/styles/base/variables.css new file mode 100755 index 0000000..bf9ca5a --- /dev/null +++ b/src/styles/base/variables.css @@ -0,0 +1,39 @@ +:root { + /* Couleurs */ + + /* Réelles */ + --color-white: #fff; + --color-black: #000; + + /* Logiques */ + --color-primary: black; + --color-secondary: salmon; + --color-tertiary: dimgrey; + --color-quartary: #be2727; + + /* Typographie */ + + /* Hauteurs de ligne */ + --line-height-comfortable: 1.4; + --line-height-compact: 1.1; + + /* Échelles */ + --ratio: 1.4; + --s-5: calc(var(--s-4) / var(--ratio)); + --s-4: calc(var(--s-3) / var(--ratio)); + --s-3: calc(var(--s-2) / var(--ratio)); + --s-2: calc(var(--s-1) / var(--ratio)); + --s-1: calc(var(--s0) / var(--ratio)); + --s0: 1rem; + --s1: calc(var(--s0) * var(--ratio)); + --s2: calc(var(--s1) * var(--ratio)); + --s3: calc(var(--s2) * var(--ratio)); + --s4: calc(var(--s3) * var(--ratio)); + --s5: calc(var(--s4) * var(--ratio)); + + /* Arrière-plans à motifs */ + --bg25-secondary: repeating-conic-gradient(var(--color-tertiary) 0% 25%, transparent 0% 100%) 1px + 0.5px / 2px 2px; + --bg75-secondary: repeating-conic-gradient(var(--color-secondary) 0% 75%, transparent 0% 100%) 1px + 0.5px / 2px 2px; +} diff --git a/src/styles/components/imposter-box.css b/src/styles/components/imposter-box.css new file mode 100644 index 0000000..5de0e46 --- /dev/null +++ b/src/styles/components/imposter-box.css @@ -0,0 +1,55 @@ +.dialog { + position: fixed; /* 1 */ + z-index: 2; /* 1 */ + inset: 0; /* 1 */ + display: flex; /* 2 */ + background: var(--bg25-secondary); + margin: 0; + + &[aria-hidden="true"] { + display: none; /* 1 */ + } +} + +.dialog-content { + position: relative; /* 2 */ + max-inline-size: 80ch; + margin: auto; /* 1 */ + padding: initial; + border: 1px solid var(--color-primary); + background-color: var(--color-secondary); + box-shadow: 0.5rem 0.5rem 0 0 var(--color-primary); + animation: fade-in 100ms 10ms both; + + header { + overflow: hidden; + display: flex; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; + border-block-end: 1px solid var(--color-primary); + + h2 { + padding-inline: var(--s-1); + font-size: var(--s1); + } + + button { + padding: var(--s-1); + font-family: Banquise, monospace; + font-weight: 500; + } + } +} + +@keyframes fade-in { + from { + opacity: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .dialog-overlay, .dialog-content { + animation: none; + } +} diff --git a/src/styles/components/navigation-menu.css b/src/styles/components/navigation-menu.css new file mode 100644 index 0000000..3705dfa --- /dev/null +++ b/src/styles/components/navigation-menu.css @@ -0,0 +1,3 @@ +[aria-current] { + font-weight: 125; +} diff --git a/src/styles/layouts/_layouts.css b/src/styles/layouts/_layouts.css new file mode 100644 index 0000000..3845601 --- /dev/null +++ b/src/styles/layouts/_layouts.css @@ -0,0 +1,7 @@ +@import url("./box.css"); +@import url("./center.css"); +@import url("./cover.css"); +@import url("./cluster.css"); +@import url("./sidebar.css"); +@import url("./stack.css"); +@import url("./switcher.css"); diff --git a/src/styles/layouts/box.css b/src/styles/layouts/box.css new file mode 100755 index 0000000..53ac50f --- /dev/null +++ b/src/styles/layouts/box.css @@ -0,0 +1,17 @@ +/* + * 1. Affiche une bordure pour les thèmes à haut contraste sans augmenter la taille de la boîte. + */ +.box { + padding: var(--s0, 1rem); + background-color: var(--color-secondary, #fff); + outline: 0.125rem solid transparent; /* 1 */ + outline-offset: -0.125rem; /* 1 */ + + /* border: 1px solid var(--color-primary); */ +} + +/* Inverse les couleurs de la boîte. */ +.box.invert { + color: var(--color-secondary, #fff); + background-color: var(--color-primary, #000); +} diff --git a/src/styles/layouts/center.css b/src/styles/layouts/center.css new file mode 100755 index 0000000..1fb860d --- /dev/null +++ b/src/styles/layouts/center.css @@ -0,0 +1,14 @@ +/* + * 1. Utilise un modèle de boîte excluant les marges internes du calcul de la longueur. + * 2. Centre l'Élément avec des marges externes automatiques en ligne et une longueur maximale. + * 3. Assure que des espaces latéraux sont présents. + */ +.center { + display: flex; + flex-flow: column nowrap; + align-items: center; + box-sizing: content-box; /* 1 */ + max-inline-size: var(--longueur-max-texte, 80ch); /* 2 */ + margin-inline: auto; /* 2 */ + padding-inline: var(--s0, 1rem) var(--s0, 1rem); /* 3 */ +} diff --git a/src/styles/layouts/cluster.css b/src/styles/layouts/cluster.css new file mode 100644 index 0000000..6ea3b7f --- /dev/null +++ b/src/styles/layouts/cluster.css @@ -0,0 +1,8 @@ +.cluster { + display: flex; + flex-flow: row wrap; + gap: var(--s0, 1rem); + align-items: center; + + /* justify-content: center; */ +} diff --git a/src/styles/layouts/cover.css b/src/styles/layouts/cover.css new file mode 100755 index 0000000..07cb098 --- /dev/null +++ b/src/styles/layouts/cover.css @@ -0,0 +1,40 @@ +/* + * Cover est une disposition permettant de centrer verticalement en son sein un Élément, avec + * potentiellement une en-tête et/ou potentiellement un pied de page à chaque extrémité. + * + * Un usage typique de Cover est l'affichage d'une partie introductive au sein d'une page. + * + * 1. Arrange les Éléments en colonne. + * 2. Fait que la disposition ait une taille minimale fixe tout en permettant son expansion si le contenu la dépasse. + * 3. Empêche l'Élément centrale de la disposition de toucher les bords. + */ +.cover { + --cover-minimal-height: 100vb; + --cover-container-padding: var(--s0, 1rem); + --cover-inter-element-spacing: var(--s0, 1rem); + + display: flex; /* 1 */ + flex-flow: column nowrap; /* 1 */ + min-block-size: var(--cover-minimal-height); /* 2 */ + padding: var(--cover-container-padding); /* 3 */ + + /* Applique un espacement inter-élément pour tout Élément supplémentaire. */ + > * { + margin-block: var(--cover-inter-element-spacing); + } + + /* Pas de marge pour les Éléments aux extrémités de la disposition. */ + > :first-child:not(.cover-center) { + margin-block-start: 0; + } + + /* Pas de marge pour les Éléments aux extrémités de la disposition. */ + > :last-child:not(.cover-center) { + margin-block-end: 0; + } + + /* Centre verticalement l'Élément central. */ + > .cover-center { + margin-block: auto; + } +} diff --git a/src/styles/layouts/sidebar.css b/src/styles/layouts/sidebar.css new file mode 100644 index 0000000..0dbc249 --- /dev/null +++ b/src/styles/layouts/sidebar.css @@ -0,0 +1,19 @@ +.with-sidebar { + --gutter: var(--s0); + + display: flex; + flex-flow: row wrap; + gap: var(--gutter, var(--s0)); + align-content: start; +} + +.with-sidebar > :first-child { + flex-basis: 0; + flex-grow: 999; + min-inline-size: 65%; +} + +.with-sidebar > :last-child { + flex-basis: 15ch; + flex-grow: 1; +} diff --git a/src/styles/layouts/stack.css b/src/styles/layouts/stack.css new file mode 100755 index 0000000..85e4c0c --- /dev/null +++ b/src/styles/layouts/stack.css @@ -0,0 +1,19 @@ +.stack { + --space: var(--s0, 1rem); + + display: flex; + flex-flow: column nowrap; + justify-content: flex-start; +} + +.stack > * { + margin-block: 0; +} + +.stack > * + * { + margin-block-start: var(--space); +} + +.stack:only-child { + block-size: 100%; +} diff --git a/src/styles/layouts/switcher.css b/src/styles/layouts/switcher.css new file mode 100644 index 0000000..d7430de --- /dev/null +++ b/src/styles/layouts/switcher.css @@ -0,0 +1,16 @@ +.switcher { + --threshold: 30rem; + + display: flex; + flex-flow: row wrap; + gap: var(--s0, 1rem); +} + +.switcher > *:not(.column-separator) { + flex-basis: calc((var(--threshold) - 100%) * 999); + flex-grow: 1; +} + +.switcher > :nth-last-child(n+5), .switcher > :nth-last-child(n+5) ~ * { + flex-basis: 100%; +} diff --git a/src/styles/main.css b/src/styles/main.css new file mode 100755 index 0000000..eeba308 --- /dev/null +++ b/src/styles/main.css @@ -0,0 +1,9 @@ +@layer base, elements, layouts, components, themes; + +@import url("./base/variables.css"); +@import url("./base/base.css") layer(base); +@import url("./base/elements.css") layer(base); + +@import url("./layouts/_layouts.css") layer(layouts); + +@import url("./themes/default.css") layer(themes); diff --git a/src/styles/pages/main-layout.css b/src/styles/pages/main-layout.css new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/src/styles/pages/main-layout.css @@ -0,0 +1 @@ + diff --git a/src/styles/themes/default.css b/src/styles/themes/default.css new file mode 100644 index 0000000..13b0a42 --- /dev/null +++ b/src/styles/themes/default.css @@ -0,0 +1,60 @@ +@import url("./default/buttons.css"); +@import url("./default/headings.css"); + +body { + font-family: BRKLY, sans-serif; + font-weight: 100; + background: var(--color-secondary); +} + +*:focus-visible { + animation: flicker 50ms 2; +} + +.invert { + font-weight: 120; + color: var(--color-secondary); + background-color: var(--color-primary); +} + +h1 { + font-family: Banquise, monospace; +} + +.container { + --longueur-max-texte: 100ch; + + place-content: start; + place-items: start; + + /* opacity: 0; + animation: flicker 50ms 4 forwards 100ms ease-in; */ +} + +.container > :is(main, aside) { + margin-block-start: var(--s2); +} + +main > header { + margin-block-end: var(--s2); +} + +#last-watched-media { + --space: var(--s2); +} + +@keyframes fade-in { + to { + opacity: 1; + } +} + +@keyframes flicker { + from, 49% { + opacity: 0; + } + + 50%, to { + opacity: 1; + } +} diff --git a/src/styles/themes/default/buttons.css b/src/styles/themes/default/buttons.css new file mode 100755 index 0000000..81118de --- /dev/null +++ b/src/styles/themes/default/buttons.css @@ -0,0 +1,54 @@ +button { + --button-background-color: var(--color-secondary); + --button-border-color: var(--color-primary); + --button-font-weight: 100; + --button-padding: var(--s-1); + --button-text-color: var(--color-primary); + + padding: var(--button-padding); + border: 1px solid var(--button-border-color); + font-weight: var(--button-font-weight); + color: var(--button-text-color); + background-color: var(--button-background-color); + box-shadow: 4px 4px 0 0 var(--color-primary); + + &:hover { + --button-background-color: var(--color-primary); + --button-border-color: var(--color-secondary); + --button-font-weight: 120; + --button-text-color: var(--color-secondary); + } + + &:active { + transform: translateX(2px) translateY(2px); + box-shadow: 1px 1px 0 0 var(--color-primary); + } + + &:focus-visible { + outline-offset: -0.3rem; + } + + /* Inversion des couleurs. */ + &.invert { + --button-background-color: var(--color-primary); + --button-border-color: var(--color-secondary); + --button-text-color: var(--color-secondary); + + outline-color: var(--color-secondary); + } + + /* TODO: Déplacer dans un Composant. */ + /* Bouton intégré dans un ensemble. */ + &.integrated { + border: initial; + + &:hover { + color: var(--color-primary); + background: var(--bg75-secondary); + } + + &:active { + transform: translateX(2px) translateY(2px); + } + } +} diff --git a/src/styles/themes/default/headings.css b/src/styles/themes/default/headings.css new file mode 100755 index 0000000..466dff7 --- /dev/null +++ b/src/styles/themes/default/headings.css @@ -0,0 +1,12 @@ +h1 { + font-family: Banquise, monospace; + font-size: var(--s3); + font-weight: 600; + letter-spacing: 1.5px; +} + +h2 { + font-family: Banquise, monospace; + font-size: var(--s2); + letter-spacing: 1px; +} diff --git a/src/views/BaseView.vue b/src/views/BaseView.vue new file mode 100644 index 0000000..05d0939 --- /dev/null +++ b/src/views/BaseView.vue @@ -0,0 +1,4 @@ + + + diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue deleted file mode 100644 index ec98f0a..0000000 --- a/src/views/HomeView.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/src/views/SidebarView.vue b/src/views/SidebarView.vue new file mode 100644 index 0000000..6e397ec --- /dev/null +++ b/src/views/SidebarView.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..149fcbd --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,22 @@ +/// + +interface ImportMetaEnv { + /** Le nom du fichier contenant la base de données SQLite. */ + readonly VITE_DATABASE_NAME: string; + /** La clé API de l'application liée à un compte TMDB. */ + readonly VITE_TMDB_API_KEY: string; +} + +declare module "bun" { + interface Env { + /** Le nom du fichier contenant la base de données SQLite. */ + readonly VITE_DATABASE_NAME: string; + /** La clé API de l'application liée à un compte TMDB. */ + readonly VITE_TMDB_API_KEY: string; + } +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} +export {}; diff --git a/tsconfig.json b/tsconfig.json index 6692751..65acbc7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,7 @@ "isolatedModules": true, "jsx": "preserve", "jsxImportSource": "vue", - "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], + "lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable", "WebWorker"], "module": "ESNext", "moduleDetection": "force", "moduleResolution": "bundler", @@ -32,11 +32,12 @@ "noUncheckedSideEffectImports": false, "noUnusedLocals": true, "noUnusedParameters": true, - "resolveJsonModule": true, "paths": { "@/*": ["./src/*"] }, + "plugins": [{ "name": "@vue/typescript-plugin" }], + "resolveJsonModule": true, + "skipDefaultLibCheck": true, "skipLibCheck": true, "strict": true, - "skipDefaultLibCheck": true, "strictBindCallApply": true, "strictFunctionTypes": true, "strictNullChecks": true, @@ -46,6 +47,6 @@ "useUnknownInCatchVariables": true, "verbatimModuleSyntax": true }, - "exclude": ["dist/", ".cache"], - "include": ["env.d.ts", "**/*", "**/*.vue"] + "exclude": ["node_modules", "dist/", ".cache"], + "include": ["src/router/typed-routes.d.ts", "src/env.d.ts", "**/*", "**/*.vue"] } diff --git a/vite.config.mts b/vite.config.mts index c9b1a3a..59eafea 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,3 +1,4 @@ +import unheadVite from "@unhead/addons/vite"; import vue from "@vitejs/plugin-vue"; import { defineConfig } from "vite"; import vueDevTools from "vite-plugin-vue-devtools"; @@ -8,33 +9,37 @@ export default defineConfig({ emptyOutDir: true, outDir: "dist", reportCompressedSize: true, - rollupOptions: { - output: { - compact: true, - format: "esm", - validate: true, - }, - }, + rollupOptions: { output: { compact: true, format: "esm", validate: true } }, sourcemap: false, }, cacheDir: ".cache/vite", clearScreen: false, - css: { - transformer: "lightningcss", - }, - optimizeDeps: { - exclude: ["sqlocal"], - }, + css: { transformer: "lightningcss" }, + optimizeDeps: { exclude: ["sqlocal"] }, plugins: [ vue(), - vueDevTools(), + // vueDevTools(), + { + configureServer: server => { + server.middlewares.use((_req, res, next) => { + res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + res.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT"); + res.setHeader("Access-Control-Allow-Origin", "http://localhost:4321"); + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Cross-Origin-Embedder-Policy", "require-corp"); + res.setHeader("Cross-Origin-Opener-Policy", "same-origin"); + res.setHeader("Cross-Origin-Resource-Policy", "cross-origin"); + next(); + }); + }, + name: "configure-response-headers", + }, + unheadVite(), ], resolve: { alias: { "@": Bun.fileURLToPath(new URL("./src", import.meta.url)), }, }, - worker: { - format: "es", - }, + worker: { format: "es" }, });