diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2bbbb28..95aefff 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -23,7 +23,7 @@ module.exports = { ecmaVersion: 'latest' }, rules: { - indent: ['error', 2], + indent: ['error', 2, { SwitchCase: 1 }], 'prettier/prettier': [ 'error', { diff --git a/components.json b/components.json new file mode 100644 index 0000000..9c826ef --- /dev/null +++ b/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://shadcn-vue.com/schema.json", + "style": "default", + "typescript": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/assets/main.css", + "baseColor": "slate", + "cssVariables": true + }, + "framework": "vite", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9c98bfc..c2a70b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,15 @@ "name": "vue-project", "version": "0.0.0", "dependencies": { + "@phosphor-icons/vue": "^2.1.6", "@vueuse/core": "^10.9.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "lucide-vue-next": "^0.364.0", "pinia": "^2.1.7", + "radix-vue": "^1.6.1", + "tailwind-merge": "^2.2.2", + "tailwindcss-animate": "^1.0.7", "vue": "^3.4.21", "vue-router": "^4.3.0" }, @@ -29,6 +36,7 @@ "npm-run-all2": "^6.1.2", "postcss": "^8.4.38", "prettier": "^3.0.3", + "sass": "^1.72.0", "start-server-and-test": "^2.0.3", "tailwindcss": "^3.4.3", "typescript": "~5.4.0", @@ -49,7 +57,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "engines": { "node": ">=10" }, @@ -68,6 +75,17 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -572,6 +590,63 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", + "dependencies": { + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@floating-ui/vue": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@floating-ui/vue/-/vue-1.0.6.tgz", + "integrity": "sha512-EdrOljjkpkkqZnrpqUcPoz9NvHxuTjUtSInh6GMv3+Mcy+giY2cE2pHh9rpacRcZ2eMSCxel9jWkWXTjLmY55w==", + "dependencies": { + "@floating-ui/dom": "^1.6.1", + "@floating-ui/utils": "^0.2.1", + "vue-demi": ">=0.13.0" + } + }, + "node_modules/@floating-ui/vue/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -642,11 +717,18 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@internationalized/date": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.5.2.tgz", + "integrity": "sha512-vo1yOMUt2hzp63IutEaTUxROdvQg1qlMRsbCvbay2AK2Gai7wIgCyK5weEX3nHkiLgo4qCXHijFNC/ILhlRpOQ==", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -663,7 +745,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -675,7 +756,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -686,14 +766,12 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -710,7 +788,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -725,7 +802,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -742,7 +818,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -756,7 +831,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -765,7 +839,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -779,7 +852,6 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -789,7 +861,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -802,7 +873,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -811,7 +881,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -820,11 +889,21 @@ "node": ">= 8" } }, + "node_modules/@phosphor-icons/vue": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@phosphor-icons/vue/-/vue-2.1.6.tgz", + "integrity": "sha512-j4iVvNT4JbDR2udIVfakKZHd14i3jCvO4b24OC0W/1rasftU8qVg1Tnb3QDwAT0teNU+UxvaM+kCWxfGHC2dUg==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "vue": ">=3.2.39" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -1064,6 +1143,14 @@ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", "dev": true }, + "node_modules/@swc/helpers": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.8.tgz", + "integrity": "sha512-lruDGw3pnfM3wmZHeW7JuhkGQaJjPyiKjxeGhdmfoOT53Ic9qb5JLDNaK2HUdl1zLDeX28H221UvKjfdvSLVMg==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@tsconfig/node20": { "version": "20.1.4", "resolved": "https://registry.npmjs.org/@tsconfig/node20/-/node20-20.1.4.tgz", @@ -1696,7 +1783,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1705,7 +1791,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1719,14 +1804,12 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1758,8 +1841,7 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/argparse": { "version": "2.0.1", @@ -1767,6 +1849,17 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/aria-hidden": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", + "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -1910,8 +2003,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -1946,7 +2038,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "engines": { "node": ">=8" }, @@ -1976,7 +2067,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -1985,7 +2075,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2099,7 +2188,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "engines": { "node": ">= 6" } @@ -2171,7 +2259,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2195,7 +2282,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -2218,6 +2304,25 @@ "node": ">=8" } }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2270,11 +2375,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2285,8 +2397,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { "version": "2.0.20", @@ -2346,7 +2457,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2360,7 +2470,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "bin": { "cssesc": "bin/cssesc" }, @@ -2494,6 +2603,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==" + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2506,8 +2620,7 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, "node_modules/dir-glob": { "version": "3.0.1", @@ -2524,8 +2637,7 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/doctrine": { "version": "3.0.0", @@ -2548,8 +2660,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ecc-jsbn": { "version": "0.1.2", @@ -2570,8 +2681,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/end-of-stream": { "version": "1.4.4", @@ -3025,8 +3135,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -3038,7 +3147,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -3054,7 +3162,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -3078,7 +3185,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -3132,7 +3238,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3200,7 +3305,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3216,7 +3320,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -3291,7 +3394,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -3305,7 +3407,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3386,7 +3487,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -3539,7 +3639,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -3608,6 +3707,12 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "dev": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -3671,7 +3776,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -3695,7 +3799,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -3707,7 +3810,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3716,7 +3818,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -3725,7 +3826,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -3753,7 +3853,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -3800,8 +3899,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isstream": { "version": "0.1.2", @@ -3813,7 +3911,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -3831,7 +3928,6 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -3968,7 +4064,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "engines": { "node": ">=10" } @@ -3976,8 +4071,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/listr2": { "version": "3.14.0", @@ -4116,6 +4210,14 @@ "node": ">=10" } }, + "node_modules/lucide-vue-next": { + "version": "0.364.0", + "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.364.0.tgz", + "integrity": "sha512-O8MQEEktkd5zL+1S40P3UnEXotR6lrN0oaV/8uyVQCwvBMWlnTKlwIg4Rd8yDBGrALFOAiyCLu69y4gh82fNew==", + "peerDependencies": { + "vue": ">=3.0.1" + } + }, "node_modules/magic-string": { "version": "0.30.8", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", @@ -4152,7 +4254,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -4161,7 +4262,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -4204,7 +4304,6 @@ "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4228,7 +4327,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -4249,7 +4347,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -4289,7 +4386,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4377,7 +4473,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4386,7 +4481,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "engines": { "node": ">= 6" } @@ -4532,7 +4626,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -4540,14 +4633,12 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -4563,7 +4654,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } @@ -4607,7 +4697,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -4631,7 +4720,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4690,7 +4778,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -4726,7 +4813,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -4743,7 +4829,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -4762,7 +4847,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -4797,7 +4881,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -4809,7 +4892,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.11" }, @@ -4828,7 +4910,6 @@ "version": "6.0.16", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", - "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4840,8 +4921,7 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -4971,7 +5051,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -4987,11 +5066,46 @@ } ] }, + "node_modules/radix-vue": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/radix-vue/-/radix-vue-1.6.1.tgz", + "integrity": "sha512-/nnA4u8oYAZK86unEjRuIROrTDDU0HHiwkCgGI0YeCNpyObSnbC1CZJlXUBErdY51yxcqV4cU4WJBKwQC8iRFA==", + "dependencies": { + "@floating-ui/dom": "^1.5.4", + "@floating-ui/vue": "^1.0.4", + "@internationalized/date": "^3.5.2", + "@vueuse/core": "^10.5.0", + "@vueuse/shared": "^10.5.0", + "aria-hidden": "^1.2.3", + "defu": "^6.1.4", + "fast-deep-equal": "^3.1.3", + "nanoid": "^5.0.6" + }, + "peerDependencies": { + "vue": ">= 3.2.0" + } + }, + "node_modules/radix-vue/node_modules/nanoid": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz", + "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -5013,7 +5127,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -5021,6 +5134,11 @@ "node": ">=8.10.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -5040,7 +5158,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -5079,7 +5196,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -5144,7 +5260,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -5198,6 +5313,23 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sass": { + "version": "1.72.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.72.0.tgz", + "integrity": "sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -5234,7 +5366,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5246,7 +5377,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -5433,7 +5563,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5448,7 +5577,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5462,7 +5590,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5475,7 +5602,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5508,7 +5634,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -5530,7 +5655,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } @@ -5539,7 +5663,6 @@ "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -5576,7 +5699,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -5600,11 +5722,22 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tailwind-merge": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.2.tgz", + "integrity": "sha512-tWANXsnmJzgw6mQ07nE3aCDkCK4QdT3ThPMCzawoYA2Pws7vSTCvz3Vrjg61jVUGfFZPJzxEP+NimbcW+EdaDw==", + "dependencies": { + "@babel/runtime": "^7.24.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", - "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -5637,6 +5770,14 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5647,7 +5788,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -5656,7 +5796,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -5692,7 +5831,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -5739,14 +5877,12 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -5879,8 +6015,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/uuid": { "version": "8.3.2", @@ -6068,7 +6203,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -6101,7 +6235,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -6139,7 +6272,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", - "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index be1e4dc..33bb9df 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,14 @@ "format": "prettier --write src/" }, "dependencies": { + "@phosphor-icons/vue": "^2.1.6", "@vueuse/core": "^10.9.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", "pinia": "^2.1.7", + "radix-vue": "^1.6.1", + "tailwind-merge": "^2.2.2", + "tailwindcss-animate": "^1.0.7", "vue": "^3.4.21", "vue-router": "^4.3.0" }, @@ -38,6 +44,7 @@ "npm-run-all2": "^6.1.2", "postcss": "^8.4.38", "prettier": "^3.0.3", + "sass": "^1.72.0", "start-server-and-test": "^2.0.3", "tailwindcss": "^3.4.3", "typescript": "~5.4.0", diff --git a/src/App.vue b/src/App.vue index a78fb6f..15727d4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,12 @@ diff --git a/src/assets/main.css b/src/assets/main.css index b5c61c9..010919c 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,3 +1,78 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --ring: 212.7 26.8% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/assets/theme.css b/src/assets/theme.css deleted file mode 100644 index 8816868..0000000 --- a/src/assets/theme.css +++ /dev/null @@ -1,86 +0,0 @@ -/* color palette from */ -:root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} - -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background: var(--vt-c-black); - --color-background-soft: var(--vt-c-black-soft); - --color-background-mute: var(--vt-c-black-mute); - - --color-border: var(--vt-c-divider-dark-2); - --color-border-hover: var(--vt-c-divider-dark-1); - - --color-heading: var(--vt-c-text-dark-1); - --color-text: var(--vt-c-text-dark-2); - } -} - -*, -*::before, -*::after { - box-sizing: border-box; - margin: 0; - font-weight: normal; -} - -body { - min-height: 100vh; - color: var(--color-text); - background: var(--color-background); - transition: - color 0.5s, - background-color 0.5s; - line-height: 1.6; - font-family: - Inter, - -apple-system, - BlinkMacSystemFont, - 'Segoe UI', - Roboto, - Oxygen, - Ubuntu, - Cantarell, - 'Fira Sans', - 'Droid Sans', - 'Helvetica Neue', - sans-serif; - font-size: 15px; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} diff --git a/src/components/calendar/Calendar.vue b/src/components/calendar/Calendar.vue new file mode 100644 index 0000000..1636137 --- /dev/null +++ b/src/components/calendar/Calendar.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/calendar/CalendarEvent.vue b/src/components/calendar/CalendarEvent.vue new file mode 100644 index 0000000..0feb07e --- /dev/null +++ b/src/components/calendar/CalendarEvent.vue @@ -0,0 +1,38 @@ + + + diff --git a/src/components/calendar/CalendarEventDetails.vue b/src/components/calendar/CalendarEventDetails.vue new file mode 100644 index 0000000..dc4bf49 --- /dev/null +++ b/src/components/calendar/CalendarEventDetails.vue @@ -0,0 +1,53 @@ + + + diff --git a/src/components/calendar/CalendarMenu.vue b/src/components/calendar/CalendarMenu.vue new file mode 100644 index 0000000..ca6d2a1 --- /dev/null +++ b/src/components/calendar/CalendarMenu.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/components/calendar/CalendarMenuNav.vue b/src/components/calendar/CalendarMenuNav.vue new file mode 100644 index 0000000..a3667eb --- /dev/null +++ b/src/components/calendar/CalendarMenuNav.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/components/calendar/CalendarMenuToday.vue b/src/components/calendar/CalendarMenuToday.vue new file mode 100644 index 0000000..f660bf0 --- /dev/null +++ b/src/components/calendar/CalendarMenuToday.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/calendar/CalendarSwitch.vue b/src/components/calendar/CalendarSwitch.vue new file mode 100644 index 0000000..a663bf0 --- /dev/null +++ b/src/components/calendar/CalendarSwitch.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/components/calendar/CalendarTile.vue b/src/components/calendar/CalendarTile.vue new file mode 100644 index 0000000..785b76b --- /dev/null +++ b/src/components/calendar/CalendarTile.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/components/calendar/Search.ts b/src/components/calendar/Search.ts new file mode 100644 index 0000000..b565e1c --- /dev/null +++ b/src/components/calendar/Search.ts @@ -0,0 +1,3 @@ +export const searchUnifier = new RegExp(/[^a-zA-Z0-9\-'']/g) + +export type SearchMode = 'characters' | 'events' | undefined diff --git a/src/components/calendar/search/CalendarSearch.vue b/src/components/calendar/search/CalendarSearch.vue new file mode 100644 index 0000000..91623c7 --- /dev/null +++ b/src/components/calendar/search/CalendarSearch.vue @@ -0,0 +1,435 @@ + + + diff --git a/src/components/calendar/search/lists/SearchList.vue b/src/components/calendar/search/lists/SearchList.vue new file mode 100644 index 0000000..1936fac --- /dev/null +++ b/src/components/calendar/search/lists/SearchList.vue @@ -0,0 +1,196 @@ + + + diff --git a/src/components/calendar/state/Century.vue b/src/components/calendar/state/Century.vue new file mode 100644 index 0000000..63d8978 --- /dev/null +++ b/src/components/calendar/state/Century.vue @@ -0,0 +1,9 @@ + + + diff --git a/src/components/calendar/state/Decade.vue b/src/components/calendar/state/Decade.vue new file mode 100644 index 0000000..1c6de81 --- /dev/null +++ b/src/components/calendar/state/Decade.vue @@ -0,0 +1,3 @@ + diff --git a/src/components/calendar/state/Monthly.vue b/src/components/calendar/state/Monthly.vue new file mode 100644 index 0000000..6d1bcae --- /dev/null +++ b/src/components/calendar/state/Monthly.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/components/calendar/state/Year.vue b/src/components/calendar/state/Year.vue new file mode 100644 index 0000000..b5256a2 --- /dev/null +++ b/src/components/calendar/state/Year.vue @@ -0,0 +1,3 @@ + diff --git a/src/components/ui/badge/Badge.vue b/src/components/ui/badge/Badge.vue new file mode 100644 index 0000000..2e8bdff --- /dev/null +++ b/src/components/ui/badge/Badge.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/components/ui/badge/index.ts b/src/components/ui/badge/index.ts new file mode 100644 index 0000000..db5cb1d --- /dev/null +++ b/src/components/ui/badge/index.ts @@ -0,0 +1,24 @@ +import { type VariantProps, cva } from 'class-variance-authority' + +export { default as Badge } from './Badge.vue' + +export const badgeVariants = cva( + 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', + secondary: + 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', + destructive: + 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', + outline: 'text-foreground' + } + }, + defaultVariants: { + variant: 'default' + } + } +) + +export type BadgeVariants = VariantProps diff --git a/src/components/ui/button/Button.vue b/src/components/ui/button/Button.vue new file mode 100644 index 0000000..6e56542 --- /dev/null +++ b/src/components/ui/button/Button.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ui/button/index.ts b/src/components/ui/button/index.ts new file mode 100644 index 0000000..eba3552 --- /dev/null +++ b/src/components/ui/button/index.ts @@ -0,0 +1,32 @@ +import { type VariantProps, cva } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + 'inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline' + }, + size: { + default: 'h-10 px-4 py-2', + xs: 'h-7 rounded-sm px-2 text-xs', + sm: 'h-9 rounded-md px-3 text-sm', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) + +export type ButtonVariants = VariantProps diff --git a/src/components/ui/command/Command.vue b/src/components/ui/command/Command.vue new file mode 100644 index 0000000..b1c809c --- /dev/null +++ b/src/components/ui/command/Command.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/ui/command/CommandDialog.vue b/src/components/ui/command/CommandDialog.vue new file mode 100644 index 0000000..2b19c30 --- /dev/null +++ b/src/components/ui/command/CommandDialog.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/components/ui/command/CommandEmpty.vue b/src/components/ui/command/CommandEmpty.vue new file mode 100644 index 0000000..1295d2a --- /dev/null +++ b/src/components/ui/command/CommandEmpty.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/command/CommandGroup.vue b/src/components/ui/command/CommandGroup.vue new file mode 100644 index 0000000..3a4422b --- /dev/null +++ b/src/components/ui/command/CommandGroup.vue @@ -0,0 +1,36 @@ + + + diff --git a/src/components/ui/command/CommandInput.vue b/src/components/ui/command/CommandInput.vue new file mode 100644 index 0000000..936f789 --- /dev/null +++ b/src/components/ui/command/CommandInput.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/components/ui/command/CommandItem.vue b/src/components/ui/command/CommandItem.vue new file mode 100644 index 0000000..027fca1 --- /dev/null +++ b/src/components/ui/command/CommandItem.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/components/ui/command/CommandList.vue b/src/components/ui/command/CommandList.vue new file mode 100644 index 0000000..265317b --- /dev/null +++ b/src/components/ui/command/CommandList.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/ui/command/CommandSeparator.vue b/src/components/ui/command/CommandSeparator.vue new file mode 100644 index 0000000..2d83d0f --- /dev/null +++ b/src/components/ui/command/CommandSeparator.vue @@ -0,0 +1,20 @@ + + + diff --git a/src/components/ui/command/CommandShortcut.vue b/src/components/ui/command/CommandShortcut.vue new file mode 100644 index 0000000..0d4da92 --- /dev/null +++ b/src/components/ui/command/CommandShortcut.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/command/index.ts b/src/components/ui/command/index.ts new file mode 100644 index 0000000..0e35f4b --- /dev/null +++ b/src/components/ui/command/index.ts @@ -0,0 +1,9 @@ +export { default as Command } from './Command.vue' +export { default as CommandDialog } from './CommandDialog.vue' +export { default as CommandEmpty } from './CommandEmpty.vue' +export { default as CommandGroup } from './CommandGroup.vue' +export { default as CommandInput } from './CommandInput.vue' +export { default as CommandItem } from './CommandItem.vue' +export { default as CommandList } from './CommandList.vue' +export { default as CommandSeparator } from './CommandSeparator.vue' +export { default as CommandShortcut } from './CommandShortcut.vue' diff --git a/src/components/ui/dialog/Dialog.vue b/src/components/ui/dialog/Dialog.vue new file mode 100644 index 0000000..7f26e47 --- /dev/null +++ b/src/components/ui/dialog/Dialog.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/dialog/DialogClose.vue b/src/components/ui/dialog/DialogClose.vue new file mode 100644 index 0000000..a64703e --- /dev/null +++ b/src/components/ui/dialog/DialogClose.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/dialog/DialogContent.vue b/src/components/ui/dialog/DialogContent.vue new file mode 100644 index 0000000..b835dd3 --- /dev/null +++ b/src/components/ui/dialog/DialogContent.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/components/ui/dialog/DialogDescription.vue b/src/components/ui/dialog/DialogDescription.vue new file mode 100644 index 0000000..3637b7e --- /dev/null +++ b/src/components/ui/dialog/DialogDescription.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/dialog/DialogFooter.vue b/src/components/ui/dialog/DialogFooter.vue new file mode 100644 index 0000000..c6f5d4e --- /dev/null +++ b/src/components/ui/dialog/DialogFooter.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/components/ui/dialog/DialogHeader.vue b/src/components/ui/dialog/DialogHeader.vue new file mode 100644 index 0000000..e22a1fd --- /dev/null +++ b/src/components/ui/dialog/DialogHeader.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/dialog/DialogScrollContent.vue b/src/components/ui/dialog/DialogScrollContent.vue new file mode 100644 index 0000000..424fde4 --- /dev/null +++ b/src/components/ui/dialog/DialogScrollContent.vue @@ -0,0 +1,64 @@ + + + diff --git a/src/components/ui/dialog/DialogTitle.vue b/src/components/ui/dialog/DialogTitle.vue new file mode 100644 index 0000000..0a1c94c --- /dev/null +++ b/src/components/ui/dialog/DialogTitle.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/dialog/DialogTrigger.vue b/src/components/ui/dialog/DialogTrigger.vue new file mode 100644 index 0000000..ee0c12f --- /dev/null +++ b/src/components/ui/dialog/DialogTrigger.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/dialog/index.ts b/src/components/ui/dialog/index.ts new file mode 100644 index 0000000..847e999 --- /dev/null +++ b/src/components/ui/dialog/index.ts @@ -0,0 +1,9 @@ +export { default as Dialog } from './Dialog.vue' +export { default as DialogClose } from './DialogClose.vue' +export { default as DialogTrigger } from './DialogTrigger.vue' +export { default as DialogHeader } from './DialogHeader.vue' +export { default as DialogTitle } from './DialogTitle.vue' +export { default as DialogDescription } from './DialogDescription.vue' +export { default as DialogContent } from './DialogContent.vue' +export { default as DialogScrollContent } from './DialogScrollContent.vue' +export { default as DialogFooter } from './DialogFooter.vue' diff --git a/src/components/ui/dropdown-menu/DropdownMenu.vue b/src/components/ui/dropdown-menu/DropdownMenu.vue new file mode 100644 index 0000000..0f9cd7b --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenu.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue new file mode 100644 index 0000000..bd9cf5f --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuContent.vue b/src/components/ui/dropdown-menu/DropdownMenuContent.vue new file mode 100644 index 0000000..fd88f22 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuContent.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuGroup.vue b/src/components/ui/dropdown-menu/DropdownMenuGroup.vue new file mode 100644 index 0000000..3f20135 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuGroup.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuItem.vue b/src/components/ui/dropdown-menu/DropdownMenuItem.vue new file mode 100644 index 0000000..5774ca5 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuItem.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuLabel.vue b/src/components/ui/dropdown-menu/DropdownMenuLabel.vue new file mode 100644 index 0000000..d95f5eb --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuLabel.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue b/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue new file mode 100644 index 0000000..b6d1fcc --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue b/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue new file mode 100644 index 0000000..a8fc03e --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue b/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue new file mode 100644 index 0000000..e4953df --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue @@ -0,0 +1,24 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue b/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue new file mode 100644 index 0000000..abaeda6 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSub.vue b/src/components/ui/dropdown-menu/DropdownMenuSub.vue new file mode 100644 index 0000000..d01e1ae --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSub.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue b/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue new file mode 100644 index 0000000..5ba1ec6 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue b/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue new file mode 100644 index 0000000..cd15395 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue b/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue new file mode 100644 index 0000000..8efd5a9 --- /dev/null +++ b/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue @@ -0,0 +1,13 @@ + + + diff --git a/src/components/ui/dropdown-menu/index.ts b/src/components/ui/dropdown-menu/index.ts new file mode 100644 index 0000000..6f9446c --- /dev/null +++ b/src/components/ui/dropdown-menu/index.ts @@ -0,0 +1,16 @@ +export { DropdownMenuPortal } from 'radix-vue' + +export { default as DropdownMenu } from './DropdownMenu.vue' +export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue' +export { default as DropdownMenuContent } from './DropdownMenuContent.vue' +export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue' +export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue' +export { default as DropdownMenuItem } from './DropdownMenuItem.vue' +export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue' +export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue' +export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue' +export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue' +export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue' +export { default as DropdownMenuSub } from './DropdownMenuSub.vue' +export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue' +export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue' diff --git a/src/components/ui/input/Input.vue b/src/components/ui/input/Input.vue new file mode 100644 index 0000000..808c921 --- /dev/null +++ b/src/components/ui/input/Input.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/ui/input/index.ts b/src/components/ui/input/index.ts new file mode 100644 index 0000000..a691dd6 --- /dev/null +++ b/src/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from './Input.vue' diff --git a/src/components/ui/pagination/PaginationEllipsis.vue b/src/components/ui/pagination/PaginationEllipsis.vue new file mode 100644 index 0000000..a58de39 --- /dev/null +++ b/src/components/ui/pagination/PaginationEllipsis.vue @@ -0,0 +1,25 @@ + + + diff --git a/src/components/ui/pagination/PaginationFirst.vue b/src/components/ui/pagination/PaginationFirst.vue new file mode 100644 index 0000000..65652b7 --- /dev/null +++ b/src/components/ui/pagination/PaginationFirst.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/pagination/PaginationLast.vue b/src/components/ui/pagination/PaginationLast.vue new file mode 100644 index 0000000..3c254c2 --- /dev/null +++ b/src/components/ui/pagination/PaginationLast.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/pagination/PaginationNext.vue b/src/components/ui/pagination/PaginationNext.vue new file mode 100644 index 0000000..02c156c --- /dev/null +++ b/src/components/ui/pagination/PaginationNext.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/pagination/PaginationPrev.vue b/src/components/ui/pagination/PaginationPrev.vue new file mode 100644 index 0000000..9821666 --- /dev/null +++ b/src/components/ui/pagination/PaginationPrev.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/pagination/index.ts b/src/components/ui/pagination/index.ts new file mode 100644 index 0000000..d42dd72 --- /dev/null +++ b/src/components/ui/pagination/index.ts @@ -0,0 +1,6 @@ +export { PaginationRoot as Pagination, PaginationList, PaginationListItem } from 'radix-vue' +export { default as PaginationEllipsis } from './PaginationEllipsis.vue' +export { default as PaginationFirst } from './PaginationFirst.vue' +export { default as PaginationLast } from './PaginationLast.vue' +export { default as PaginationNext } from './PaginationNext.vue' +export { default as PaginationPrev } from './PaginationPrev.vue' diff --git a/src/components/ui/popover/Popover.vue b/src/components/ui/popover/Popover.vue new file mode 100644 index 0000000..1a5873a --- /dev/null +++ b/src/components/ui/popover/Popover.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/ui/popover/PopoverContent.vue b/src/components/ui/popover/PopoverContent.vue new file mode 100644 index 0000000..5136fd6 --- /dev/null +++ b/src/components/ui/popover/PopoverContent.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/components/ui/popover/PopoverTrigger.vue b/src/components/ui/popover/PopoverTrigger.vue new file mode 100644 index 0000000..22f4772 --- /dev/null +++ b/src/components/ui/popover/PopoverTrigger.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/popover/index.ts b/src/components/ui/popover/index.ts new file mode 100644 index 0000000..495d55a --- /dev/null +++ b/src/components/ui/popover/index.ts @@ -0,0 +1,3 @@ +export { default as Popover } from './Popover.vue' +export { default as PopoverTrigger } from './PopoverTrigger.vue' +export { default as PopoverContent } from './PopoverContent.vue' diff --git a/src/components/ui/select/Select.vue b/src/components/ui/select/Select.vue new file mode 100644 index 0000000..adc42fd --- /dev/null +++ b/src/components/ui/select/Select.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/ui/select/SelectContent.vue b/src/components/ui/select/SelectContent.vue new file mode 100644 index 0000000..5371217 --- /dev/null +++ b/src/components/ui/select/SelectContent.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/components/ui/select/SelectGroup.vue b/src/components/ui/select/SelectGroup.vue new file mode 100644 index 0000000..407d8ad --- /dev/null +++ b/src/components/ui/select/SelectGroup.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/select/SelectItem.vue b/src/components/ui/select/SelectItem.vue new file mode 100644 index 0000000..c180b2c --- /dev/null +++ b/src/components/ui/select/SelectItem.vue @@ -0,0 +1,44 @@ + + + diff --git a/src/components/ui/select/SelectItemText.vue b/src/components/ui/select/SelectItemText.vue new file mode 100644 index 0000000..a0bb5c2 --- /dev/null +++ b/src/components/ui/select/SelectItemText.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/select/SelectLabel.vue b/src/components/ui/select/SelectLabel.vue new file mode 100644 index 0000000..3d45cdb --- /dev/null +++ b/src/components/ui/select/SelectLabel.vue @@ -0,0 +1,13 @@ + + + diff --git a/src/components/ui/select/SelectScrollDownButton.vue b/src/components/ui/select/SelectScrollDownButton.vue new file mode 100644 index 0000000..b4122b6 --- /dev/null +++ b/src/components/ui/select/SelectScrollDownButton.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/components/ui/select/SelectScrollUpButton.vue b/src/components/ui/select/SelectScrollUpButton.vue new file mode 100644 index 0000000..3dffaf7 --- /dev/null +++ b/src/components/ui/select/SelectScrollUpButton.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/ui/select/SelectSeparator.vue b/src/components/ui/select/SelectSeparator.vue new file mode 100644 index 0000000..5ae593d --- /dev/null +++ b/src/components/ui/select/SelectSeparator.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/components/ui/select/SelectTrigger.vue b/src/components/ui/select/SelectTrigger.vue new file mode 100644 index 0000000..22f7b75 --- /dev/null +++ b/src/components/ui/select/SelectTrigger.vue @@ -0,0 +1,33 @@ + + + diff --git a/src/components/ui/select/SelectValue.vue b/src/components/ui/select/SelectValue.vue new file mode 100644 index 0000000..4bc37dd --- /dev/null +++ b/src/components/ui/select/SelectValue.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/select/index.ts b/src/components/ui/select/index.ts new file mode 100644 index 0000000..b1d89ee --- /dev/null +++ b/src/components/ui/select/index.ts @@ -0,0 +1,11 @@ +export { default as Select } from './Select.vue' +export { default as SelectValue } from './SelectValue.vue' +export { default as SelectTrigger } from './SelectTrigger.vue' +export { default as SelectContent } from './SelectContent.vue' +export { default as SelectGroup } from './SelectGroup.vue' +export { default as SelectItem } from './SelectItem.vue' +export { default as SelectItemText } from './SelectItemText.vue' +export { default as SelectLabel } from './SelectLabel.vue' +export { default as SelectSeparator } from './SelectSeparator.vue' +export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue' +export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue' diff --git a/src/components/ui/tabs/Tabs.vue b/src/components/ui/tabs/Tabs.vue new file mode 100644 index 0000000..2fa0971 --- /dev/null +++ b/src/components/ui/tabs/Tabs.vue @@ -0,0 +1,15 @@ + + + diff --git a/src/components/ui/tabs/TabsContent.vue b/src/components/ui/tabs/TabsContent.vue new file mode 100644 index 0000000..475dc94 --- /dev/null +++ b/src/components/ui/tabs/TabsContent.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/ui/tabs/TabsList.vue b/src/components/ui/tabs/TabsList.vue new file mode 100644 index 0000000..4d6c7f7 --- /dev/null +++ b/src/components/ui/tabs/TabsList.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/ui/tabs/TabsTrigger.vue b/src/components/ui/tabs/TabsTrigger.vue new file mode 100644 index 0000000..79c4dc9 --- /dev/null +++ b/src/components/ui/tabs/TabsTrigger.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/components/ui/tabs/index.ts b/src/components/ui/tabs/index.ts new file mode 100644 index 0000000..fbea0c6 --- /dev/null +++ b/src/components/ui/tabs/index.ts @@ -0,0 +1,4 @@ +export { default as Tabs } from './Tabs.vue' +export { default as TabsTrigger } from './TabsTrigger.vue' +export { default as TabsList } from './TabsList.vue' +export { default as TabsContent } from './TabsContent.vue' diff --git a/src/components/ui/tags-input/TagsInput.vue b/src/components/ui/tags-input/TagsInput.vue new file mode 100644 index 0000000..d5ed3ee --- /dev/null +++ b/src/components/ui/tags-input/TagsInput.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/ui/tags-input/TagsInputInput.vue b/src/components/ui/tags-input/TagsInputInput.vue new file mode 100644 index 0000000..399274c --- /dev/null +++ b/src/components/ui/tags-input/TagsInputInput.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/tags-input/TagsInputItem.vue b/src/components/ui/tags-input/TagsInputItem.vue new file mode 100644 index 0000000..0703456 --- /dev/null +++ b/src/components/ui/tags-input/TagsInputItem.vue @@ -0,0 +1,30 @@ + + + diff --git a/src/components/ui/tags-input/TagsInputItemDelete.vue b/src/components/ui/tags-input/TagsInputItemDelete.vue new file mode 100644 index 0000000..4401215 --- /dev/null +++ b/src/components/ui/tags-input/TagsInputItemDelete.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/ui/tags-input/TagsInputItemText.vue b/src/components/ui/tags-input/TagsInputItemText.vue new file mode 100644 index 0000000..f714957 --- /dev/null +++ b/src/components/ui/tags-input/TagsInputItemText.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/ui/tags-input/index.ts b/src/components/ui/tags-input/index.ts new file mode 100644 index 0000000..31305f3 --- /dev/null +++ b/src/components/ui/tags-input/index.ts @@ -0,0 +1,5 @@ +export { default as TagsInput } from './TagsInput.vue' +export { default as TagsInputInput } from './TagsInputInput.vue' +export { default as TagsInputItem } from './TagsInputItem.vue' +export { default as TagsInputItemDelete } from './TagsInputItemDelete.vue' +export { default as TagsInputItemText } from './TagsInputItemText.vue' diff --git a/src/components/ui/toggle-group/ToggleGroup.vue b/src/components/ui/toggle-group/ToggleGroup.vue new file mode 100644 index 0000000..3ff029e --- /dev/null +++ b/src/components/ui/toggle-group/ToggleGroup.vue @@ -0,0 +1,44 @@ + + + diff --git a/src/components/ui/toggle-group/ToggleGroupItem.vue b/src/components/ui/toggle-group/ToggleGroupItem.vue new file mode 100644 index 0000000..af7ca39 --- /dev/null +++ b/src/components/ui/toggle-group/ToggleGroupItem.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/components/ui/toggle-group/index.ts b/src/components/ui/toggle-group/index.ts new file mode 100644 index 0000000..9f89ad7 --- /dev/null +++ b/src/components/ui/toggle-group/index.ts @@ -0,0 +1,2 @@ +export { default as ToggleGroup } from './ToggleGroup.vue' +export { default as ToggleGroupItem } from './ToggleGroupItem.vue' diff --git a/src/components/ui/toggle/Toggle.vue b/src/components/ui/toggle/Toggle.vue new file mode 100644 index 0000000..8092669 --- /dev/null +++ b/src/components/ui/toggle/Toggle.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/components/ui/toggle/index.ts b/src/components/ui/toggle/index.ts new file mode 100644 index 0000000..6eed09f --- /dev/null +++ b/src/components/ui/toggle/index.ts @@ -0,0 +1,26 @@ +import { type VariantProps, cva } from 'class-variance-authority' + +export { default as Toggle } from './Toggle.vue' + +export const toggleVariants = cva( + 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground', + { + variants: { + variant: { + default: 'bg-transparent', + outline: 'border border-input bg-transparent hover:bg-accent hover:text-accent-foreground' + }, + size: { + default: 'h-10 px-3', + sm: 'h-9 px-2.5', + lg: 'h-11 px-5' + } + }, + defaultVariants: { + variant: 'default', + size: 'default' + } + } +) + +export type ToggleVariants = VariantProps diff --git a/src/components/ui/tooltip/Tooltip.vue b/src/components/ui/tooltip/Tooltip.vue new file mode 100644 index 0000000..3581ace --- /dev/null +++ b/src/components/ui/tooltip/Tooltip.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/ui/tooltip/TooltipContent.vue b/src/components/ui/tooltip/TooltipContent.vue new file mode 100644 index 0000000..fdaaf77 --- /dev/null +++ b/src/components/ui/tooltip/TooltipContent.vue @@ -0,0 +1,48 @@ + + + diff --git a/src/components/ui/tooltip/TooltipProvider.vue b/src/components/ui/tooltip/TooltipProvider.vue new file mode 100644 index 0000000..816505d --- /dev/null +++ b/src/components/ui/tooltip/TooltipProvider.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/tooltip/TooltipTrigger.vue b/src/components/ui/tooltip/TooltipTrigger.vue new file mode 100644 index 0000000..f5b0e57 --- /dev/null +++ b/src/components/ui/tooltip/TooltipTrigger.vue @@ -0,0 +1,11 @@ + + + diff --git a/src/components/ui/tooltip/index.ts b/src/components/ui/tooltip/index.ts new file mode 100644 index 0000000..82049b4 --- /dev/null +++ b/src/components/ui/tooltip/index.ts @@ -0,0 +1,4 @@ +export { default as Tooltip } from './Tooltip.vue' +export { default as TooltipContent } from './TooltipContent.vue' +export { default as TooltipTrigger } from './TooltipTrigger.vue' +export { default as TooltipProvider } from './TooltipProvider.vue' diff --git a/src/data/Characters.ts b/src/data/Characters.ts new file mode 100644 index 0000000..4caf5b8 --- /dev/null +++ b/src/data/Characters.ts @@ -0,0 +1,243 @@ +import type { Character } from '@/models/Characters' + +export const charactersList: Character[] = [ + /** + * Player characters + */ + // "Les Milles Cages" + { + name: 'Sulvan Trois-Barbes', + birth: { day: 20, month: 3, year: 3169 }, + wiki: 'https://alexcreates.fr/leim/index.php/Sulvan_Trois-Barbes', + category: 'joueur', + secondaryCategories: ['criminel', 'étincelle'] + }, + { + name: 'Vascylly', + birth: { day: 3, month: 5, year: 3181 }, + wiki: 'https://alexcreates.fr/leim/index.php/Vascylly', + category: 'joueur', + secondaryCategories: ['mage'] + }, + { + name: 'Tara Belyus', + birth: { day: 14, month: 9, year: 3186 }, + category: 'joueur', + secondaryCategories: ['mage'] + }, + // "Les Cloches de Cantane" + { + name: 'Malik', + birth: { day: 22, month: 8, year: 3181 }, + category: 'joueur', + secondaryCategories: ['scientifique'] + }, + { + name: 'Elie', + birth: { day: 5, month: 6, year: 3192 }, + category: 'joueur', + secondaryCategories: ['ecclésiastique'] + }, + { + name: 'Clayron', + birth: { day: 3, month: 5, year: 3178 }, + category: 'joueur', + secondaryCategories: ['sentinelle'] + }, + + /** + * NPC + */ + // Counts of the Alliance + { + name: 'Alfrid de Lagarde', + birth: { day: 29, month: 7, year: 3193 }, + wiki: 'https://alexcreates.fr/leim/index.php/Alfrid_de_Lagarde', + category: 'comte', + secondaryCategories: ['sentinelle'] + }, + { + name: 'Alaric de Lagarde', + birth: { day: 23, month: 8, year: 3192 }, + wiki: 'https://alexcreates.fr/leim/index.php/Alaric_de_Lagarde', + category: 'comte', + secondaryCategories: ['sentinelle'] + }, + { + name: 'Anastael III de Quillon', + birth: { day: 1, month: 5, year: 3184 }, + wiki: 'https://alexcreates.fr/leim/index.php/Anastael_III_de_Quillon', + category: 'comte', + secondaryCategories: ['sentinelle', 'buse blanche'] + }, + { + name: 'Antoine de Mireloin', + birth: { day: 31, month: 5, year: 3190 }, + wiki: 'https://alexcreates.fr/leim/index.php/Antoine_de_Mireloin', + category: 'comte' + }, + { + name: 'Armance Ronchère', + birth: { day: 1, month: 1, year: 3132 }, + wiki: 'https://alexcreates.fr/leim/index.php/Armance_Ronchère', + category: 'comte' + }, + { + name: 'Baranne Rougefer', + birth: { day: 1, month: 0, year: 3175 }, + wiki: 'https://alexcreates.fr/leim/index.php/Baranne_Rougefer', + category: 'comte', + secondaryCategories: ['sentinelle'] + }, + { + name: 'Béatrice II de Grandlac', + birth: { day: 21, month: 4, year: 3158 }, + wiki: 'https://alexcreates.fr/leim/index.php/Béatrice_II_de_Grandlac', + category: 'comte', + secondaryCategories: ['mage'] + }, + { + name: 'Favio Asharos-Losantelle', + birth: { day: 17, month: 3, year: 3091 }, + wiki: 'https://alexcreates.fr/leim/index.php/Favio_Asharos-Losantelle', + category: 'comte', + secondaryCategories: ['mage'] + }, + { + name: 'Firmin de Montardieu', + birth: { day: 9, month: 2, year: 3203 }, + wiki: 'https://alexcreates.fr/leim/index.php/Firmin_de_Montardieu', + category: 'comte' + }, + { + name: 'Laura de Montardieu', + birth: { day: 32, month: 3, year: 3167 }, + death: { day: 1, month: 4, year: 3217 }, + hiddenDeath: true, + wiki: 'https://alexcreates.fr/leim/index.php/Laura_de_Montardieu', + category: 'comte' + }, + { + name: 'Lazarus Tymos', + birth: { day: 29, month: 9, year: 3145 }, + wiki: 'https://alexcreates.fr/leim/index.php/Lazarus_Tymos', + category: 'comte', + secondaryCategories: ['mage', 'buse blanche'] + }, + { + name: 'Marion de Corambre', + birth: { day: 14, month: 7, year: 3190 }, + wiki: 'https://alexcreates.fr/leim/index.php/Marion_de_Corambre', + category: 'comte', + secondaryCategories: ['scientifique', 'ecclésiastique'] + }, + { + name: 'Relforg Pergaré', + birth: { day: 18, month: 9, year: 3182 }, + wiki: 'https://alexcreates.fr/leim/index.php/Relforg_Pergaré', + category: 'comte' + }, + { + name: 'Vilgarde de Ternâcre', + birth: { day: 3, month: 3, year: 2998 }, + wiki: 'https://alexcreates.fr/leim/index.php/Vilgarde_de_Ternâcre', + category: 'comte' + }, + { + name: 'Ysildy Milopée', + birth: { day: 3, month: 1, year: 3187 }, + wiki: 'https://alexcreates.fr/leim/index.php/Ysildy_Milopée', + category: 'comte', + secondaryCategories: ['mage', 'scientifique', 'professeur'] + }, + + // Sparks + { + name: 'Izàc Tymos', + birth: { day: 13, month: 6, year: 3192 }, + wiki: 'https://alexcreates.fr/leim/index.php/Izàc_Tymos', + category: 'mage', + secondaryCategories: ['étincelle', 'criminel', 'professeur', 'scientifique'] + }, + { + name: 'Tvernée', + birth: { day: 19, month: 2, year: 3205 }, + wiki: 'https://alexcreates.fr/leim/index.php/Tvernée', + category: 'étincelle', + secondaryCategories: ['criminel'] + }, + + // Pirates + { + name: 'Räzal', + birth: { day: 13, month: 8, year: 3178 }, + wiki: 'https://alexcreates.fr/leim/index.php/Räzal' + }, + + // "Les Milles Cages" + { + name: 'Ernestin Pomel', + birth: { day: 11, month: 2, year: 3179 }, + wiki: 'https://alexcreates.fr/leim/index.php/Ernestin_Pomel', + category: 'mage' + }, + { + name: 'Quacille Lévios', + birth: { day: 3, month: 6, year: 3162 }, + wiki: 'https://alexcreates.fr/leim/index.php/Quacille_Lévios', + category: 'professeur', + secondaryCategories: ['mage'] + }, + { + name: 'Morel Lévios', + birth: { day: 26, month: 3, year: 3157 }, + wiki: 'https://alexcreates.fr/leim/index.php/Morel_Lévios', + category: 'sentinelle', + secondaryCategories: ['mage', 'buse blanche'] + }, + { + name: 'Anastael Simon', + birth: { day: 32, month: 2, year: 3166 }, + wiki: 'https://alexcreates.fr/leim/index.php/Anastael_Simon', + category: 'étincelle', + secondaryCategories: ['mage'] + }, + { + name: 'Grestain', + birth: { day: 9, month: 2, year: 3162 }, + wiki: 'https://alexcreates.fr/leim/index.php/Grestain', + category: 'criminel', + secondaryCategories: ['mage'] + }, + { + name: 'Lucien Malanth', + birth: { day: 31, month: 4, year: 3167 }, + wiki: 'https://alexcreates.fr/leim/index.php/Lucien_Malanth', + category: 'criminel', + secondaryCategories: ['mage'] + }, + { + name: 'Tivian Rodhus', + birth: { day: 13, month: 3, year: 3157 }, + wiki: 'https://alexcreates.fr/leim/index.php/Tivian_Rodhus', + category: 'professeur', + secondaryCategories: ['mage', 'criminel'] + }, + + // "Les Cloches de Cantane" + { + name: 'Bénédicte Vaht', + description: "Moine d'Ikami ayant entrepris la construction du Pilier Blanc de Cantane", + birth: { day: 28, month: 6, year: 3139 }, + category: 'ecclésiastique' + }, + { + name: 'Taleb Vaht', + description: + "Fils de Bénédicte, il s'est engagé auprès des Étincelles comme alchimiste artificier.", + birth: { day: 9, month: 1, year: 3180 }, + death: { day: 28, month: 7, year: 3209 }, + category: 'étincelle', + secondaryCategories: ['scientifique'] + } +] diff --git a/src/data/Events.ts b/src/data/Events.ts new file mode 100644 index 0000000..bfd1b67 --- /dev/null +++ b/src/data/Events.ts @@ -0,0 +1,120 @@ +import type { CalendarEvent } from '@/models/Events' + +export const regularEvents: CalendarEvent[] = [ + // Histoire Antique + { + title: 'Exécution de Tyhos', + date: { day: 1, month: 0, year: 0 }, + description: + "Le léviathan Tyhos rend l'âme après un combat de plusieurs années contre Lystos, le dieu du Soleil.", + category: 'bénédiction', + secondaryCategories: ['mort'], + wiki: 'https://alexcreates.fr/leim/index.php/Tyhos', + hidden: true + }, + { + title: 'Traité de Kadel', + date: { day: 20, month: 4, year: 100 }, + description: '', + category: 'inauguration', + secondaryCategories: ['législation'], + wiki: 'https://alexcreates.fr/leim/index.php/Alliance_Kald%C3%A9lienne#Trait%C3%A9_de_Kadel' + }, + + // Histoire Récente + { + title: 'Création de la buse kaldélienne', + date: { day: 4, month: 2, year: 3113 }, + description: + 'Sophia de Rougefer invente la buse kaldélienne, une arme à feu souple à deux canons.', + category: 'invention', + secondaryCategories: ['science'], + wiki: 'https://alexcreates.fr/leim/index.php/Buse_(arme)' + }, + + // "Les Milles Cages" + { + title: "Arrivée d'aventuriers à Borélis", + date: { day: 12, month: 7, year: 3209 }, + description: + 'Tara Belyus, Vascylly et Adol Sulvan livrent 3 condamnés à Handany. Ils partent pour la mer durant la journée.', + category: 'joueurs' + }, + { + title: "Naufrage de l'Éclipse", + description: + "L'Éclipse, le navire de la garde contenant des condamnés à destination des Cages Handaniennes, s'échoue au large des côtes montagneuses de la Lance d'Aldys.", + date: { day: 14, month: 7, year: 3209 }, + category: 'catastrophe' + }, + { + title: 'Emprisonnement de Tivian Rodhus', + description: "Celui qu'on surnomme la Bête d'Ambrose arrive à Handany, où il purgera sa peine.", + date: { day: 14, month: 7, year: 3209 }, + category: 'législation' + }, + { + title: 'Sulvan et Anastael atteignent Bamast', + date: { day: 19, month: 2, year: 3210 }, + category: 'joueurs' + }, + { + title: 'Jugement de Bormis Griloup', + description: + "Bromis Griloup est jugé coupable d'escroquerie et sabotage aux Cours d'Acier de Tourgrise. Il purgera une peine de 10 ans au sein des prisons royales.", + date: { day: 4, month: 8, year: 3209 }, + category: 'législation' + }, + + // "Les Cloches de Cantane" + { + title: 'Inauguration de la Cloche du Pilier', + description: "Le Moine Premier inaugure la grande cloche d'argent au sommet du Pilier d'Ikami.", + date: { day: 29, month: 5, year: 3209 }, + category: 'religion', + hidden: true + }, + { + title: '1ère disparation à Cantane', + description: "Taleb Vaht décède dans une grotte à la suite d'une attaque d'ischiels enragées.", + date: { day: 28, month: 7, year: 3209 }, + category: 'mort', + hidden: true + }, + { + title: '2ème disparation à Cantane', + description: 'Seconde victime de la série de disparitions qui affecte Cantane', + date: { day: 32, month: 7, year: 3209 }, + category: 'mort', + hidden: true + }, + { + title: '3ème disparation à Cantane', + description: 'Troisième victime de la série de disparitions qui affecte Cantane', + date: { day: 10, month: 8, year: 3209 }, + category: 'mort', + hidden: true + }, + { + title: '4ème disparation à Cantane', + description: 'Quatrième victime de la série de disparitions qui affecte Cantane', + date: { day: 19, month: 8, year: 3209 }, + category: 'mort', + hidden: true + }, + { + title: '5ème disparation à Cantane', + description: 'Cinquième victime de la série de disparitions qui affecte Cantane', + date: { day: 22, month: 8, year: 3209 }, + category: 'mort', + hidden: true + }, + { + title: 'Grande Banque Minérale de Cantane', + description: + 'Les artisans et mineurs de Rougefer se réunissent à Cantane pour vendre le fruit de leur dur labeur.', + date: { day: 23, month: 8, year: 3209 }, + category: 'inauguration', + hidden: true + } +] diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..d32b0fe --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/main.ts b/src/main.ts index 615f001..5dcad83 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,4 @@ import './assets/main.css' -import './assets/theme.css' import { createApp } from 'vue' import { createPinia } from 'pinia' diff --git a/src/models/Characters.ts b/src/models/Characters.ts new file mode 100644 index 0000000..8be796c --- /dev/null +++ b/src/models/Characters.ts @@ -0,0 +1,31 @@ +import type { LeimDate } from './Date' + +export interface Character { + name: string + description?: string + birth?: LeimDate + death?: LeimDate + hiddenBirth?: boolean + hiddenDeath?: boolean + category?: CharacterCategory + secondaryCategories?: CharacterCategory[] + wiki?: string +} +export const characterCategories = [ + 'joueur', + 'comte', + 'scientifique', + 'mage', + 'professeur', + 'criminel', + 'étincelle', + 'buse blanche', + 'ecclésiastique', + 'sentinelle' +] as const + +export type CharacterCategory = (typeof characterCategories)[number] + +export function isCharacter(object: any): object is Character { + return 'birth' in object +} diff --git a/src/models/Date.ts b/src/models/Date.ts new file mode 100644 index 0000000..feaaec8 --- /dev/null +++ b/src/models/Date.ts @@ -0,0 +1,193 @@ +export interface LeimDate { + day: number + month: number + year: number + period?: LeimPeriod +} + +export type LeimPeriod = 'ante' | 'nante' +export type LeimPeriodShort = 'A.R' | 'N.R' +export type LeimDateOrder = 'asc' | 'desc' + +export const monthsPerYear: number = 10 +export const daysPerYear: number = 320 +export const daysPerMonth: number = 32 +export const daysPerWeek: number = 6 + +/** + * Check whether two dates are identical + * + * @param date1 First date + * @param date2 Second date + * @returns True if the dates are identical + */ +export function areDatesIdentical(date1: LeimDate, date2: LeimDate): boolean { + return convertDateToDays({ ...date1 }) === convertDateToDays({ ...date2 }) +} + +/** + * Compare dates + * + * @param date1 First date + * @param date2 Second date + * @returns 1 means the first date comes before the second, -1 means the second comes before the first, and 0 if they're identical + */ +export function compareDates(a: LeimDate, b: LeimDate, order: LeimDateOrder = 'desc'): number { + // Reverses the order if specified + const orderFactor: number = order === 'desc' ? 1 : -1 + + // Compare eras + if ((a.period === 'ante' && b.period === 'nante') || (a.year < 0 && b.year >= 0)) + return -1 * orderFactor + if ((a.period === 'nante' && b.period === 'ante') || (a.year >= 0 && b.year < 0)) + return 1 * orderFactor + + // Compare years + if (a.year < b.year) return -1 * orderFactor + if (a.year > b.year) return 1 * orderFactor + + // Compare months + if (a.month < b.month) return -1 * orderFactor + if (a.month > b.month) return 1 * orderFactor + + // Compare days + if (a.day < b.day) return -1 * orderFactor + if (a.day > b.day) return 1 * orderFactor + + return 0 +} + +/** + * Converts a LeimDate to its equivalent in days + * + * @todo Handle negative dates + * @param dateToConvert The date object + * @returns How many days does it represent + */ +export function convertDateToDays(dateToConvert: LeimDate): number { + let numberOfDays: number = dateToConvert.day + + numberOfDays = numberOfDays + dateToConvert.month * daysPerMonth + numberOfDays = numberOfDays + dateToConvert.year * daysPerYear + + return numberOfDays +} + +/** + * From two dates, get the difference in days between them + * @param baseDate The base date + * @param relativeDate The year to compare it to + * @returns The number of days separating the two dates (both positive and negative numbers) + */ +export function getDifferenceInDays(baseDate: LeimDate, relativeDate: LeimDate): number { + return convertDateToDays(relativeDate) - convertDateToDays(baseDate) +} + +/** + * From two dates, gives information on how many years, months and days it has been / will be between them + * + * @param baseDate The base date + * @param relativeDate The year to compare it to + * @returns A string with info on how the relative date differs to the base date + */ +export function getRelativeString(baseDate: LeimDate, relativeDate: LeimDate): string { + const differenceInDays: number = getDifferenceInDays(baseDate, relativeDate) + let output: string = '' + let direction: 'past' | 'present' | 'future' = 'present' + let directionPrefix: string = '' + + // Check whether it's a past or future date + if (differenceInDays > 0) { + direction = 'future' + } else if (differenceInDays < 0) { + direction = 'past' + } + + // Handle if it's the same date + if (direction === 'present') { + return "Aujourd'hui" + } + if (differenceInDays === -2) { + return 'Avant-hier' + } + if (differenceInDays === -1) { + return 'Hier' + } + if (differenceInDays === 1) { + return 'Demain' + } + if (differenceInDays === 2) { + return 'Après-demain' + } + + // Get relevant prefix for the string + if (direction === 'future') { + directionPrefix = 'Dans' + } else if (direction === 'past') { + directionPrefix = 'Il y a' + } + + output += directionPrefix + + const yearPackets: number = Math.abs(Math.trunc(differenceInDays / daysPerYear)) + const monthPackets: number = Math.abs(Math.trunc(differenceInDays / daysPerMonth) % monthsPerYear) + + const remainingDays: number = + Math.abs(differenceInDays) - (yearPackets * daysPerYear + monthPackets * daysPerMonth) + + // Assign year part + if (yearPackets) { + if (yearPackets === 1) { + output += ` ${yearPackets} an` + } else { + output += ` ${yearPackets} ans` + } + } + + // Assign month part + if (monthPackets) { + // If there was a year packet(s), separate from them + if (yearPackets) { + output += ',' + } + + output += ` ${monthPackets} mois` + } + + // Assign day part + if (remainingDays) { + // If there was a year OR month packet(s), separate from them + if (yearPackets || monthPackets) { + output += ' et' + } + + if (remainingDays === 1) { + output += ` ${remainingDays} jour` + } else { + output += ` ${remainingDays} jours` + } + } + + return output +} + +// export function getRelativeDate(baseDate: LeimDate, relativeDate: LeimDate) { +// let newDay: number +// let newMonth: number +// let newYear: number +// let newPeriod: LeimPeriod + +// const differenceInDays = getDifferenceInDays(baseDate, relativeDate) + +// // console.log(baseDate, substractionDate) +// console.log(getRelativeString(baseDate, relativeDate)) + +// return differenceInDays + +// // return { +// // day: newDay, +// // month: newMonth, +// // year: newYear, +// // period: newPeriod +// // } +// } diff --git a/src/models/Events.ts b/src/models/Events.ts new file mode 100644 index 0000000..02e5cad --- /dev/null +++ b/src/models/Events.ts @@ -0,0 +1,31 @@ +import type { LeimDate } from './Date' + +export interface CalendarEvent { + title: string + date: LeimDate + description?: string + category?: CalendarEventCategory + secondaryCategories?: CalendarEventCategory[] + hidden?: boolean + wiki?: string +} + +export const calendarEventCategories = [ + 'naissance', + 'mort', + 'catastrophe', + 'législation', + 'catastrophe naturelle', + 'inauguration', + 'religion', + 'invention', + 'science', + 'bénédiction', + 'joueurs' +] + +export type CalendarEventCategory = (typeof calendarEventCategories)[number] + +export function isCalendarEvent(object: any): object is CalendarEvent { + return 'date' in object +} diff --git a/src/stores/CalendarStore.ts b/src/stores/CalendarStore.ts new file mode 100644 index 0000000..cd1aaed --- /dev/null +++ b/src/stores/CalendarStore.ts @@ -0,0 +1,417 @@ +import { + monthsPerYear, + daysPerWeek, + daysPerMonth, + daysPerYear, + type LeimDate, + type LeimPeriod, + type LeimPeriodShort +} from '@/models/Date' +import { isDigit, isInt, isSignedInt } from '@/utils/Regex' +import { useStorage, useUrlSearchParams } from '@vueuse/core' +import { defineStore } from 'pinia' +import { computed, ref, type ComputedRef, type Ref } from 'vue' + +type CalendarViewType = 'month' | 'year' | 'decade' | 'century' + +type CalendarStaticConfig = { + months: string[] + monthsPerYear: number + daysPerYear: number + daysPerMonth: number + daysPerWeek: number +} + +type CalendarCurrentConfig = { + viewType: CalendarViewType +} + +type CalendarCurrentDate = { + currentDay: ComputedRef + currentMonth: ComputedRef + currentMonthName: ComputedRef + currentYear: ComputedRef + currentPeriod: Ref + currentPeriodAbbr: Ref + currentDateTitle: ComputedRef +} + +export const useCalendar = defineStore('calendar', () => { + /** + * Static calendar config + * This shouldn't change + */ + /** + * Month list + */ + const months: string[] = [ + 'Jalen', + 'Malsen', + 'Verlys', + 'Nalys', + 'Verdore', + 'Sidore', + 'Lyllion', + 'Rion', + 'Farene', + 'Dalvene' + ] + + // Assign the static config + const staticConfig: CalendarStaticConfig = { + months, + monthsPerYear, + daysPerYear, + daysPerMonth, + daysPerWeek + } + + const currentConfig: Ref = ref({ + viewType: 'month' + }) + const viewTypeOptions: Set = new Set([ + 'month', + 'year', + 'decade', + 'century' + ]) + + // Get date from URL params + const params = useUrlSearchParams('history', { + write: true + }) + + // Default date settings (current day in the world) + const defaultDay: number = 23 + const defaultMonth: number = 8 + const defaultYear: number = 3209 + const defaultDate: ComputedRef = computed(() => { + return { + day: defaultDay, + month: defaultMonth, + year: defaultYear, + period: 'nante' + } + }) + + // Assign default values if no params exist in URL + if (!params.day || typeof params.day === 'object' || !isInt(params.day)) { + params.day = defaultDay.toString() + } + if (!params.month || typeof params.month === 'object' || !isDigit(params.month)) { + params.month = defaultMonth.toString() + } + if (!params.year || typeof params.year === 'object' || !isSignedInt(params.year)) { + params.year = defaultYear.toString() + } + + const currentDay = computed(() => { + return Number(params.day) + }) + + const currentMonth = computed(() => { + return Number(params.month) + }) + // Gets the label from currentMonth index + const currentMonthName = computed(() => getMonthName(currentMonth.value)) + + const currentYear = computed(() => { + return Number(params.year) + }) + + // Get period from currentYear + const currentPeriod = computed(() => getPeriodOfYear(currentYear.value).long) + const currentPeriodAbbr = computed( + () => getPeriodOfYear(currentYear.value).short + ) + + const currentDateTitle = computed(() => { + switch (currentConfig.value.viewType) { + case 'month': + return getFormattedDateTitle({ + day: currentDate.currentDay.value, + month: currentDate.currentMonth.value, + year: currentDate.currentYear.value, + period: currentDate.currentPeriod.value + }) + + case 'year': + return `Année ${currentYear.value} ${currentPeriodAbbr.value}` + + case 'decade': + return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 10} ${getPeriodOfYear(currentYear.value + 10).short}` + + case 'century': + return `Années ${currentYear.value} ${getPeriodOfYear(currentYear.value).short} - ${currentYear.value + 100} ${getPeriodOfYear(currentYear.value + 100).short}` + + default: + return 'Date inconnue' + } + }) + + // Create base config + const currentDate: CalendarCurrentDate = { + currentDay, + currentMonth, + currentMonthName, + currentYear, + currentPeriod, + currentPeriodAbbr, + currentDateTitle + } + + const currentLeimDate = computed(() => { + return { + day: currentDate.currentDay.value, + month: currentDate.currentMonth.value, + year: currentDate.currentYear.value, + period: currentDate.currentPeriod.value + } + }) + + const selectedDate = useStorage('selected-date', currentLeimDate.value) + + /** + * Check whether the current viewType is active + */ + const isCurrentScreenActive = computed(() => { + switch (currentConfig.value.viewType) { + case 'month': + return ( + defaultDate.value.month === currentDate.currentMonth.value && + defaultDate.value.year === currentDate.currentYear.value + ) + + case 'year': + case 'decade': + case 'century': + return defaultDate.value.year === currentDate.currentYear.value + + default: + return false + } + }) + + /** + * Moves the current date forward one month + */ + function incrementMonth(): void { + let newValue = Number(params.month) + 1 + + // If the new value would exceed the max number of month per year + if (newValue >= staticConfig.monthsPerYear) { + newValue = 0 + // Increment the year + incrementYear() + } + + params.month = newValue.toString() + } + + /** + * Moves the current date backward one month + */ + function decrementMonth(): void { + let newValue = Number(params.month) - 1 + + // If the new value would go below 0 + if (newValue < 0) { + newValue = staticConfig.monthsPerYear - 1 + // Decrement the year + decrementYear() + } + + params.month = newValue.toString() + } + + /** + * Get the previous month number + * + * @param monthNumber Initial month + * @returns The previous month number in the year + */ + function getPreviousMonth(monthNumber: number): number { + const target: number = monthNumber - 1 + + if (target < 0) { + return monthsPerYear - 1 + } + + return target + } + + /** + * Get the following month number + * + * @param monthNumber Initial month + * @returns The next month number in the year + */ + function getNextMonth(monthNumber: number): number { + const target: number = monthNumber + 1 + + if (target + 1 >= monthsPerYear) { + return 0 + } + + return target + } + + /** + * Moves the current date to a particular month + */ + function setMonth(target: number): void { + // If the target is outside the month bounds + if (target < 0 || target >= staticConfig.monthsPerYear) { + return + } + + params.month = target.toString() + } + + /** + * Moves the current date forward one year + */ + function incrementYear(inc: number = 1): void { + const newValue = Number(params.year) + inc + + params.year = newValue.toString() + } + + /** + * Moves the current date backward one year + */ + function decrementYear(inc: number = 1): void { + const newValue = Number(params.year) - inc + + params.year = newValue.toString() + } + + /** + * From a given year, returns a set of LeimPeriod identifier + * + * This is used in range use-cases + * + * @param year The year to display + * @returns An object containing both short and long LeimPeriod + */ + function getPeriodOfYear(year: string | number): { long: LeimPeriod; short: LeimPeriodShort } { + const numYear = year as number + + return { + long: numYear >= 0 ? 'nante' : 'ante', + short: numYear >= 0 ? 'N.R' : 'A.R' + } + } + + /** + * Get the formatted month name given its index + * + * @param monthNumber Index of the month + * @returns Formatted month name + */ + function getMonthName(monthNumber: number): string { + const index = Number(monthNumber) + return staticConfig.months[index] + } + + /** + * Switches the active viewType + * + * @param viewType Target viewType + */ + function setViewType(viewType: CalendarViewType): void { + currentConfig.value.viewType = viewType + } + + /** + * Gets the formatted viewType title + * + * @param viewType Target viewType + * @returns Formatted mode title + */ + function getViewTypeTitle(viewType: CalendarViewType): string { + switch (viewType) { + case 'year': + return 'Année' + + case 'decade': + return 'Décennie' + + case 'century': + return 'Siècle' + + case 'month': + default: + return 'Mois' + } + } + + /** + * From a LeimDate, returns the legible date title + * + * @param date Date target + * @param showNumber Should the date show the day number + * @returns Formatted date name + */ + function getFormattedDateTitle(date: LeimDate, showNumber?: boolean): string { + if (showNumber) { + return `${date.day} ${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}` + } + + return `${getMonthName(date.month)} ${date.year} ${getPeriodOfYear(date.year).short}` + } + + /** + * Jumps the calendar to the given date + * + * @param date Target date + */ + function jumpToDate(date: LeimDate): void { + params.day = date.day.toString() + params.month = date.month.toString() + params.year = date.year.toString() + selectDate(date) + } + + /** + * Jump the calendar to the default date + */ + function jumpToDefaultDate(): void { + jumpToDate(defaultDate.value) + currentConfig.value.viewType = 'month' + } + + /** + * Jump the calendar to the default date + */ + function selectDate(date: LeimDate): void { + selectedDate.value = date + } + + return { + staticConfig, + viewTypeOptions, + currentConfig, + currentDate, + currentLeimDate, + defaultDate, + selectedDate, + selectDate, + params, + getPeriodOfYear, + incrementMonth, + decrementMonth, + setMonth, + getPreviousMonth, + getNextMonth, + incrementYear, + decrementYear, + jumpToDate, + jumpToDefaultDate, + getFormattedDateTitle, + getMonthName, + setViewType, + getViewTypeTitle, + isCurrentScreenActive + } +}) diff --git a/src/stores/CharacterStore.ts b/src/stores/CharacterStore.ts new file mode 100644 index 0000000..1779ea1 --- /dev/null +++ b/src/stores/CharacterStore.ts @@ -0,0 +1,20 @@ +import { charactersList } from '@/data/Characters' +import type { Character } from '@/models/Characters' +import { defineStore } from 'pinia' +import { computed, type ComputedRef } from 'vue' + +export const useCharacters = defineStore('characters', () => { + const characters: Character[] = charactersList + + // Get all birth events + const charactersWithBirthData: ComputedRef = computed(() => + characters.filter((character) => character.birth) + ) + + // Get all death events + const charactersWithDeathData: ComputedRef = computed(() => + characters.filter((character) => character.death) + ) + + return { characters, charactersWithBirthData, charactersWithDeathData } +}) diff --git a/src/stores/EventStore.ts b/src/stores/EventStore.ts new file mode 100644 index 0000000..0f94cd1 --- /dev/null +++ b/src/stores/EventStore.ts @@ -0,0 +1,107 @@ +import type { CalendarEvent } from '@/models/Events' +import { defineStore } from 'pinia' +import { computed, ref, watch, type Ref } from 'vue' +import { useCalendar } from './CalendarStore' +import { useCharacters } from './CharacterStore' +import { regularEvents } from '@/data/Events' +import { convertDateToDays, daysPerMonth } from '@/models/Date' + +export const useCalendarEvents = defineStore('calendar-events', () => { + const { currentDate, currentConfig, currentLeimDate } = useCalendar() + const { charactersWithBirthData, charactersWithDeathData } = useCharacters() + + const baseEvents = ref(regularEvents) + + const characterBirthEvents = computed(() => { + return charactersWithBirthData.map((character) => { + return { + title: `Naissance de ${character.name}`, + date: character.birth, + category: 'naissance' + } as CalendarEvent + }) + }) + + const characterDeathEvents = computed(() => { + return charactersWithDeathData.map((character) => { + return { + title: `Décès de ${character.name}`, + date: character.death, + category: 'mort' + } as CalendarEvent + }) + }) + + const allEvents = computed(() => { + return [...characterBirthEvents.value, ...characterDeathEvents.value, ...baseEvents.value] + }) + + // Gets all current event in its default state + const currentEvents: Ref = ref(computeCurrentEvents()) + + // Watch for currentDate changes + watch(currentDate, () => { + currentEvents.value = computeCurrentEvents() + }) + + /** + * Determines if the event can appear in the front end + * + * This function takes into consideration the viewType of the calendar config + * + * @param event The event to analyze + * @returns Whether the event should appear in the current view + */ + function shouldEventBeDisplayed(event: CalendarEvent): boolean { + const eventDateToDays = convertDateToDays(event.date) + const isEventOnCurrentScreen = + event.date.year === currentDate.currentYear && event.date.month === currentDate.currentMonth + + // Check whether the event is on the last 8 tiles + // This is to allow leap events from appearing on the last 8 tiles + const firstDayOfCurrentMonth = convertDateToDays({ + day: 1, + month: currentDate.currentMonth, + year: currentDate.currentYear + }) + const lastDayOfCurrentMonth = firstDayOfCurrentMonth + daysPerMonth + const last8Tiles = lastDayOfCurrentMonth + 8 + + const isEventOnNext8Tiles = + eventDateToDays <= last8Tiles && eventDateToDays >= lastDayOfCurrentMonth + + switch (currentConfig.viewType) { + case 'month': + return isEventOnCurrentScreen || isEventOnNext8Tiles + + case 'year': + return event.date.year === currentDate.currentYear + + case 'decade': + return ( + event.date.year >= currentDate.currentYear && + event.date.year <= currentDate.currentYear + 10 + ) + + case 'century': + return ( + event.date.year >= currentDate.currentYear && + event.date.year <= currentDate.currentYear + 100 + ) + + default: + return false + } + } + + /** + * Fetches all the current events for the current view + * + * @returns A list of events that can appear in the current view + */ + function computeCurrentEvents(): CalendarEvent[] { + return allEvents.value.filter((event) => shouldEventBeDisplayed(event)) + } + + return { baseEvents, allEvents, currentEvents } +}) diff --git a/src/stores/counter.ts b/src/stores/counter.ts deleted file mode 100644 index b6757ba..0000000 --- a/src/stores/counter.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ref, computed } from 'vue' -import { defineStore } from 'pinia' - -export const useCounterStore = defineStore('counter', () => { - const count = ref(0) - const doubleCount = computed(() => count.value * 2) - function increment() { - count.value++ - } - - return { count, doubleCount, increment } -}) diff --git a/src/utils/Regex.ts b/src/utils/Regex.ts new file mode 100644 index 0000000..c43f0d1 --- /dev/null +++ b/src/utils/Regex.ts @@ -0,0 +1,29 @@ +/** + * Check if the string parses as single digit + * + * @param str String to test + * @returns Result of the test + */ +export function isDigit(str: string) { + return RegExp(/^\d{1}$/g).test(str) +} + +/** + * Check if the string parses as an int + * + * @param str String to test + * @returns Result of the test + */ +export function isInt(str: string) { + return RegExp(/^[0-9]*$/g).test(str) +} + +/** + * Check if the string parses as a signed int (negative or positive) + * + * @param str String to test + * @returns Result of the test + */ +export function isSignedInt(str: string) { + return RegExp(/^[-+]?[0-9]+$/g).test(str) +} diff --git a/src/utils/Strings.ts b/src/utils/Strings.ts new file mode 100644 index 0000000..d210e67 --- /dev/null +++ b/src/utils/Strings.ts @@ -0,0 +1,12 @@ +/** + * Capitalizes first letters of words in string. + * @param {string} str String to be modified + * @param {boolean=false} lower Whether all other letters should be lowercased + * @return {string} + * @usage + * capitalize('fix this string'); // -> 'Fix This String' + * capitalize('javaSCrIPT'); // -> 'JavaSCrIPT' + * capitalize('javaSCrIPT', true); // -> 'Javascript' + */ +export const capitalize = (str: string, lower: boolean = false) => + (lower ? str.toLowerCase() : str).replace(/(?:^|\s|["'([{])+\S/g, (match) => match.toUpperCase()) diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 128941e..d739af9 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -1,5 +1,49 @@ + + diff --git a/tailwind.config.js b/tailwind.config.js index 878a16e..09d66fc 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,13 +1,93 @@ +const animate = require('tailwindcss-animate') + /** @type {import('tailwindcss').Config} */ -export default { - content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], +module.exports = { + darkMode: ['class'], + safelist: ['dark'], + prefix: '', + + content: [ + './pages/**/*.{ts,tsx,vue}', + './components/**/*.{ts,tsx,vue}', + './app/**/*.{ts,tsx,vue}', + './src/**/*.{ts,tsx,vue}' + ], + theme: { + container: { + center: true, + padding: '2rem', + screens: { + '2xl': '1400px' + } + }, extend: { - container: { - padding: '2rem', - center: true + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + } + }, + borderRadius: { + xl: 'calc(var(--radius) + 4px)', + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + keyframes: { + 'accordion-down': { + from: { height: 0 }, + to: { height: 'var(--radix-accordion-content-height)' } + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: 0 } + }, + 'collapsible-down': { + from: { height: 0 }, + to: { height: 'var(--radix-collapsible-content-height)' } + }, + 'collapsible-up': { + from: { height: 'var(--radix-collapsible-content-height)' }, + to: { height: 0 } + } + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + 'collapsible-down': 'collapsible-down 0.2s ease-in-out', + 'collapsible-up': 'collapsible-up 0.2s ease-in-out' } } }, - plugins: [] + plugins: [animate] }