Merge pull request #13 from zachd/allow-custom-weekends
Allow custom weekend days to be selected
This commit is contained in:
156
package-lock.json
generated
156
package-lock.json
generated
@@ -8,8 +8,6 @@
|
|||||||
"name": "stretch-my-time-off",
|
"name": "stretch-my-time-off",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/analytics": "^1.3.2",
|
|
||||||
"@vercel/speed-insights": "^1.1.0",
|
|
||||||
"date-holidays": "^3.23.12",
|
"date-holidays": "^3.23.12",
|
||||||
"i18n-iso-countries": "^7.13.0"
|
"i18n-iso-countries": "^7.13.0"
|
||||||
},
|
},
|
||||||
@@ -27,7 +25,7 @@
|
|||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||||
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
@@ -432,7 +430,7 @@
|
|||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.2.1",
|
"@jridgewell/set-array": "^1.2.1",
|
||||||
@@ -447,7 +445,7 @@
|
|||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@@ -457,7 +455,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
@@ -467,14 +465,14 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.25",
|
"version": "0.3.25",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
@@ -485,7 +483,7 @@
|
|||||||
"version": "1.0.0-next.28",
|
"version": "1.0.0-next.28",
|
||||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz",
|
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz",
|
||||||
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==",
|
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
@@ -757,7 +755,7 @@
|
|||||||
"version": "2.8.0",
|
"version": "2.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.8.0.tgz",
|
||||||
"integrity": "sha512-HCiWupCuKJQ3aPaC4Xc6lpPdjOOnoGzEiYjOqMqppdtfGtY2ABrx932Vw66ZwS2RGXc0BmZvFvNq5SzqlmDVLg==",
|
"integrity": "sha512-HCiWupCuKJQ3aPaC4Xc6lpPdjOOnoGzEiYjOqMqppdtfGtY2ABrx932Vw66ZwS2RGXc0BmZvFvNq5SzqlmDVLg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -790,7 +788,7 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-4.0.0.tgz",
|
||||||
"integrity": "sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag==",
|
"integrity": "sha512-kpVJwF+gNiMEsoHaw+FJL76IYiwBikkxYU83+BpqQLdVMff19KeRKLd2wisS8niNBMJ2omv5gG+iGDDwd8jzag==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0",
|
"@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0",
|
||||||
@@ -812,7 +810,7 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-3.0.1.tgz",
|
||||||
"integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==",
|
"integrity": "sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.3.7"
|
"debug": "^4.3.7"
|
||||||
@@ -830,77 +828,21 @@
|
|||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
||||||
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@vercel/analytics": {
|
|
||||||
"version": "1.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.3.2.tgz",
|
|
||||||
"integrity": "sha512-n/Ws7skBbW+fUBMeg+jrT30+GP00jTHvCcL4fuVrShuML0uveEV/4vVUdvqEVnDgXIGfLm0GXW5EID2mCcRXhg==",
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"server-only": "^0.0.1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"next": ">= 13",
|
|
||||||
"react": "^18.0 || ^19.0 || ^19.0.0-rc"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"next": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vercel/speed-insights": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/speed-insights/-/speed-insights-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-rAXxuhhO4mlRGC9noa5F7HLMtGg8YF1zAN6Pjd1Ny4pII4cerhtwSG4vympbCl+pWkH7nBS9kVXRD4FAn54dlg==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"peerDependencies": {
|
|
||||||
"@sveltejs/kit": "^1 || ^2",
|
|
||||||
"next": ">= 13",
|
|
||||||
"react": "^18 || ^19 || ^19.0.0-rc",
|
|
||||||
"svelte": ">= 4",
|
|
||||||
"vue": "^3",
|
|
||||||
"vue-router": "^4"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@sveltejs/kit": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"next": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"svelte": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"vue": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"vue-router": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.0",
|
"version": "8.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
@@ -913,7 +855,7 @@
|
|||||||
"version": "1.4.13",
|
"version": "1.4.13",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
|
||||||
"integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
|
"integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"acorn": ">=8.9.0"
|
"acorn": ">=8.9.0"
|
||||||
@@ -929,7 +871,7 @@
|
|||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
|
||||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -948,7 +890,7 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
|
||||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@@ -986,7 +928,7 @@
|
|||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
@@ -1063,7 +1005,7 @@
|
|||||||
"version": "4.3.7",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "^2.1.3"
|
"ms": "^2.1.3"
|
||||||
@@ -1090,7 +1032,7 @@
|
|||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz",
|
||||||
"integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==",
|
"integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/diacritics": {
|
"node_modules/diacritics": {
|
||||||
@@ -1103,7 +1045,7 @@
|
|||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1142,14 +1084,14 @@
|
|||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.1.4.tgz",
|
||||||
"integrity": "sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==",
|
"integrity": "sha512-oO82nKPHKkzIj/hbtuDYy/JHqBHFlMIW36SDiPCVsj87ntDLcWN+sJ1erdVryd4NxODacFTsdrIE3b7IamqbOg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/esrap": {
|
"node_modules/esrap": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.2.2.tgz",
|
||||||
"integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==",
|
"integrity": "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||||
@@ -1190,14 +1132,14 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
|
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/globrex": {
|
"node_modules/globrex": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
|
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/i18n-iso-countries": {
|
"node_modules/i18n-iso-countries": {
|
||||||
@@ -1216,7 +1158,7 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
|
||||||
"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
|
"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1227,7 +1169,7 @@
|
|||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
||||||
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "*"
|
"@types/estree": "*"
|
||||||
@@ -1255,7 +1197,7 @@
|
|||||||
"version": "4.1.5",
|
"version": "4.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -1265,7 +1207,7 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
@@ -1278,7 +1220,7 @@
|
|||||||
"version": "0.30.12",
|
"version": "0.30.12",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
|
||||||
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==",
|
"integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
@@ -1309,7 +1251,7 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
@@ -1319,7 +1261,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
|
||||||
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
|
"integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
@@ -1329,14 +1271,14 @@
|
|||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.7",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1355,14 +1297,14 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.47",
|
"version": "8.4.47",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -1414,7 +1356,7 @@
|
|||||||
"version": "4.25.0",
|
"version": "4.25.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.25.0.tgz",
|
||||||
"integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==",
|
"integrity": "sha512-uVbClXmR6wvx5R1M3Od4utyLUxrmOcEm3pAtMphn73Apq19PDtHpgZoEvqH2YnnaNUuvKmg2DgRd2Sqv+odyqg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.6"
|
"@types/estree": "1.0.6"
|
||||||
@@ -1452,7 +1394,7 @@
|
|||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||||
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
|
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mri": "^1.1.0"
|
"mri": "^1.1.0"
|
||||||
@@ -1461,24 +1403,18 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/server-only": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/set-cookie-parser": {
|
"node_modules/set-cookie-parser": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
|
||||||
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/sirv": {
|
"node_modules/sirv": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
|
||||||
"integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
|
"integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@polka/url": "^1.0.0-next.24",
|
"@polka/url": "^1.0.0-next.24",
|
||||||
@@ -1493,7 +1429,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
@@ -1503,7 +1439,7 @@
|
|||||||
"version": "5.1.13",
|
"version": "5.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.1.13.tgz",
|
||||||
"integrity": "sha512-xVNk8yLsZNfkyqWzVg8+nfU9ewiSjVW0S4qyTxfKa6Y7P5ZBhA+LDsh2cHWIXJQMltikQAk6W3sqGdQZSH58PA==",
|
"integrity": "sha512-xVNk8yLsZNfkyqWzVg8+nfU9ewiSjVW0S4qyTxfKa6Y7P5ZBhA+LDsh2cHWIXJQMltikQAk6W3sqGdQZSH58PA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.3.0",
|
"@ampproject/remapping": "^2.3.0",
|
||||||
@@ -1552,7 +1488,7 @@
|
|||||||
"version": "0.2.9",
|
"version": "0.2.9",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"globalyzer": "0.1.0",
|
"globalyzer": "0.1.0",
|
||||||
@@ -1563,7 +1499,7 @@
|
|||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
||||||
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
@@ -1587,7 +1523,7 @@
|
|||||||
"version": "5.4.10",
|
"version": "5.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
|
||||||
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
|
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.21.3",
|
"esbuild": "^0.21.3",
|
||||||
@@ -1647,7 +1583,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.3.tgz",
|
||||||
"integrity": "sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==",
|
"integrity": "sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"tests/deps/*",
|
"tests/deps/*",
|
||||||
@@ -1666,7 +1602,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
|
||||||
"integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
|
"integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
"vite": "^5.0.3"
|
"vite": "^5.0.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vercel/analytics": "^1.3.2",
|
|
||||||
"@vercel/speed-insights": "^1.1.0",
|
|
||||||
"date-holidays": "^3.23.12",
|
"date-holidays": "^3.23.12",
|
||||||
"i18n-iso-countries": "^7.13.0"
|
"i18n-iso-countries": "^7.13.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
export let optimizedDaysOff: Date[];
|
export let optimizedDaysOff: Date[];
|
||||||
export let consecutiveDaysOff: Array<{ startDate: Date; endDate: Date; totalDays: number }>;
|
export let consecutiveDaysOff: Array<{ startDate: Date; endDate: Date; totalDays: number }>;
|
||||||
export let selectedCountryCode: string;
|
export let selectedCountryCode: string;
|
||||||
|
export let weekendDays: number[] = [6, 0];
|
||||||
|
|
||||||
// Function to determine the first day of the week based on locale
|
// Function to determine the first day of the week based on locale
|
||||||
function getFirstDayOfWeek(locale: string): number {
|
function getFirstDayOfWeek(locale: string): number {
|
||||||
const normalizedLocale = locale.toLowerCase() === 'us' ? 'en-US' : `en-${locale.toUpperCase()}`;
|
const normalizedLocale = locale.toLowerCase() === 'us' ? 'en-US' : `en-${locale.toUpperCase()}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to get firstDay from Intl.Locale weekInfo
|
|
||||||
// @ts-ignore .weekInfo exists on all browsers except Firefox
|
// @ts-ignore .weekInfo exists on all browsers except Firefox
|
||||||
const weekFirstDay = new Intl.Locale(normalizedLocale)?.weekInfo?.firstDay;
|
const weekFirstDay = new Intl.Locale(normalizedLocale)?.weekInfo?.firstDay;
|
||||||
if (weekFirstDay !== undefined) {
|
if (weekFirstDay !== undefined) {
|
||||||
@@ -80,11 +80,8 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isWeekend(day: number): boolean {
|
function isWeekend(date: Date): boolean {
|
||||||
const dayOfWeek = (adjustedFirstDay + day - 1) % 7;
|
return weekendDays.includes(date.getDay());
|
||||||
const saturdayIndex = (6 - firstDayOfWeek + 7) % 7;
|
|
||||||
const sundayIndex = (7 - firstDayOfWeek + 7) % 7;
|
|
||||||
return dayOfWeek === saturdayIndex || dayOfWeek === sundayIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dayInitials = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
const dayInitials = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
||||||
@@ -103,10 +100,11 @@
|
|||||||
<div class="day"></div>
|
<div class="day"></div>
|
||||||
{/each}
|
{/each}
|
||||||
{#each Array.from({ length: daysInMonth }, (_, i) => i + 1) as day}
|
{#each Array.from({ length: daysInMonth }, (_, i) => i + 1) as day}
|
||||||
<div class="day {isWeekend(day) ? 'weekend' : ''} {getHoliday(day) ? 'holiday' : ''} {isOptimizedDayOff(day) ? 'optimized' : ''} {isConsecutiveDayOff(day) ? 'consecutive-day' : ''}">
|
{@const holiday = getHoliday(day)}
|
||||||
{day}
|
<div class="day {isWeekend(new Date(year, month, day)) ? 'weekend' : ''} {holiday ? 'holiday' : ''} {isOptimizedDayOff(day) ? 'optimized' : ''} {isConsecutiveDayOff(day) ? 'consecutive-day' : ''}">
|
||||||
{#if getHoliday(day)}
|
<span class={holiday?.hidden ? 'strikethrough' : ''}>{day}</span>
|
||||||
<Tooltip text={getHoliday(day)?.name} />
|
{#if holiday}
|
||||||
|
<Tooltip text={holiday.name} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -199,4 +197,9 @@
|
|||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.strikethrough {
|
||||||
|
text-decoration: line-through;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,223 +1,179 @@
|
|||||||
import Holidays from 'date-holidays';
|
import Holidays from 'date-holidays';
|
||||||
|
|
||||||
// Constants
|
|
||||||
const MS_IN_A_DAY = 86400000;
|
const MS_IN_A_DAY = 86400000;
|
||||||
const MAX_GAP_LENGTH = 5;
|
const MAX_GAP_LENGTH = 5;
|
||||||
|
|
||||||
// Helper function to check if a date is a weekend
|
// Core date helper functions
|
||||||
const isWeekend = (date: Date): boolean => date.getDay() === 0 || date.getDay() === 6;
|
|
||||||
|
|
||||||
// Helper function to check if two dates are the same day
|
|
||||||
const isSameDay = (date1: Date, date2: Date): boolean =>
|
|
||||||
date1.getFullYear() === date2.getFullYear() &&
|
|
||||||
date1.getMonth() === date2.getMonth() &&
|
|
||||||
date1.getDate() === date2.getDate();
|
|
||||||
|
|
||||||
// Helper function to generate a unique key for a date
|
|
||||||
const dateKey = (date: Date): string => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
const dateKey = (date: Date): string => `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||||
|
const isWeekend = (date: Date, weekendDays: number[]): boolean => weekendDays.includes(date.getDay());
|
||||||
|
const isHoliday = (date: Date, holidays: { date: Date }[]): boolean => holidays.some(h => dateKey(h.date) === dateKey(date));
|
||||||
|
const daysBetween = (start: Date, end: Date): number => Math.round((end.getTime() - start.getTime()) / MS_IN_A_DAY);
|
||||||
|
|
||||||
// Helper function to check if a date is a holiday
|
// Get holidays for a year, handling multi-day holidays and timezone differences
|
||||||
const isHoliday = (date: Date, holidays: { date: Date }[]): boolean => holidays.some(h => isSameDay(h.date, date));
|
|
||||||
|
|
||||||
// Helper function to check if a date is a day off
|
|
||||||
const isDayOff = (date: Date, allDaysOffSet: Set<string>): boolean => allDaysOffSet.has(dateKey(date));
|
|
||||||
|
|
||||||
// Helper function to calculate the number of days between two dates
|
|
||||||
const daysBetween = (startDate: Date, endDate: Date): number => Math.round((endDate.getTime() - startDate.getTime()) / MS_IN_A_DAY);
|
|
||||||
|
|
||||||
// Helper function to format a date
|
|
||||||
const formatDate = (date: Date): string => date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
||||||
|
|
||||||
// Get holidays for a specific year and country
|
|
||||||
export function getHolidaysForYear(countryCode: string, year: number, stateCode?: string): { date: Date; name: string }[] {
|
export function getHolidaysForYear(countryCode: string, year: number, stateCode?: string): { date: Date; name: string }[] {
|
||||||
// The date-holidays lib has translations for many holidays, but defaults to using the language of the country.
|
// Use browser's languages and timezone to get localized holiday names
|
||||||
// We can pass in the browser's preferred languages (though the lib doesn't fall back, e.g. from `de-AT` to `de`)
|
const opts = {
|
||||||
const languages = navigator.languages.map(lang => lang.split('-')[0]);
|
languages: navigator.languages.map(lang => lang.split('-')[0]),
|
||||||
// Start/end dates are returned in that country/state's time zone, so we need to provide our time zone to localise
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||||
const opts = { languages, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone };
|
};
|
||||||
const hd = stateCode ? new Holidays(countryCode, stateCode, opts) : new Holidays(countryCode, opts);
|
const hd = stateCode ? new Holidays(countryCode, stateCode, opts) : new Holidays(countryCode, opts);
|
||||||
console.log(hd.getHolidays(year));
|
|
||||||
return hd.getHolidays(year)
|
return hd.getHolidays(year)
|
||||||
.filter(holiday => holiday.type === 'public')
|
.filter(holiday => holiday.type === 'public')
|
||||||
.flatMap(holiday =>
|
.flatMap(holiday => Array.from(
|
||||||
// To handle single- and multi-day holidays, we generate a holiday entry for each day in the period
|
{ length: daysBetween(holiday.start, holiday.end) },
|
||||||
Array.from({ length: daysBetween(holiday.start, holiday.end) }, (_, i) => ({
|
(_, i) => ({
|
||||||
date: new Date(holiday.start.getFullYear(), holiday.start.getMonth(), holiday.start.getDate() + i),
|
date: new Date(holiday.start.getFullYear(), holiday.start.getMonth(), holiday.start.getDate() + i),
|
||||||
name: holiday.name,
|
name: holiday.name,
|
||||||
}))
|
})
|
||||||
)
|
))
|
||||||
.sort((holiday1, holiday2) => holiday1.date.getTime() - holiday2.date.getTime() || holiday1.name.localeCompare(holiday2.name));
|
.sort((a, b) => a.date.getTime() - b.date.getTime() || a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize days off to create the longest possible chains
|
// Find optimal placement of PTO days to maximize consecutive time off
|
||||||
export function optimizeDaysOff(holidays: { date: Date }[], year: number, daysOff: number): Date[] {
|
export function optimizeDaysOff(holidays: { date: Date }[], year: number, daysOff: number, weekendDays: number[] = [0, 6]): Date[] {
|
||||||
const currentYearHolidays = holidays.filter(h => h.date.getFullYear() === year);
|
const allDaysOff = new Set([
|
||||||
const weekends = getWeekends(year);
|
...holidays.filter(h => h.date.getFullYear() === year).map(h => dateKey(h.date)),
|
||||||
const allDaysOffSet = new Set([
|
...getWeekends(year, weekendDays).map(d => dateKey(d))
|
||||||
...currentYearHolidays.map(h => dateKey(h.date)),
|
|
||||||
...weekends.map(d => dateKey(d))
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let rankedGaps = rankGapsByEfficiency(findGaps(allDaysOffSet, year), allDaysOffSet);
|
const gaps = findGaps(allDaysOff, year, weekendDays);
|
||||||
|
return selectDaysOff(rankGapsByEfficiency(gaps, allDaysOff, weekendDays), daysOff, allDaysOff, weekendDays);
|
||||||
return selectDaysOff(rankedGaps, daysOff, allDaysOffSet, year);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate consecutive days off
|
// Calculate periods of consecutive days off (weekends + holidays + PTO)
|
||||||
export function calculateConsecutiveDaysOff(holidays: { date: Date }[], optimizedDaysOff: Date[], year: number): { startDate: Date; endDate: Date; usedDaysOff: number; totalDays: number }[] {
|
export function calculateConsecutiveDaysOff(holidays: { date: Date }[], optimizedDaysOff: Date[], year: number, weekendDays: number[] = [0, 6]) {
|
||||||
const allDaysOffSet = new Set([...holidays.map(h => dateKey(h.date)), ...optimizedDaysOff.map(d => dateKey(d))]);
|
const allDaysOff = new Set([
|
||||||
const consecutiveDaysOff: { startDate: Date; endDate: Date; usedDaysOff: number; totalDays: number }[] = [];
|
...holidays.map(h => dateKey(h.date)),
|
||||||
let currentGroup: Date[] = [];
|
...optimizedDaysOff.map(d => dateKey(d)),
|
||||||
|
...getWeekends(year, weekendDays).map(d => dateKey(d))
|
||||||
|
]);
|
||||||
|
|
||||||
for (let month = 0; month < 12; month++) {
|
const consecutiveDaysOff = [];
|
||||||
for (let day = 1; day <= 31; day++) {
|
let currentGroup = [];
|
||||||
const date = new Date(year, month, day);
|
|
||||||
if (date.getMonth() !== month) break;
|
|
||||||
|
|
||||||
if (isWeekend(date) || isHoliday(date, holidays) || isDayOff(date, allDaysOffSet)) {
|
for (let d = new Date(year, 0, 1); d <= new Date(year, 11, 31); d.setDate(d.getDate() + 1)) {
|
||||||
currentGroup.push(date);
|
if (isWeekend(d, weekendDays) || isHoliday(d, holidays) || allDaysOff.has(dateKey(d))) {
|
||||||
} else {
|
currentGroup.push(new Date(d));
|
||||||
if (currentGroup.length > 2) {
|
} else if (currentGroup.length > 0) {
|
||||||
addConsecutiveDaysOff(consecutiveDaysOff, currentGroup, optimizedDaysOff);
|
if (hasWeekendAndNonWeekendHoliday(currentGroup, weekendDays, holidays, optimizedDaysOff)) {
|
||||||
|
consecutiveDaysOff.push(createPeriod(currentGroup, optimizedDaysOff));
|
||||||
}
|
}
|
||||||
currentGroup = [];
|
currentGroup = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (currentGroup.length > 2) {
|
if (currentGroup.length > 0 && hasWeekendAndNonWeekendHoliday(currentGroup, weekendDays, holidays, optimizedDaysOff)) {
|
||||||
addConsecutiveDaysOff(consecutiveDaysOff, currentGroup, optimizedDaysOff);
|
consecutiveDaysOff.push(createPeriod(currentGroup, optimizedDaysOff));
|
||||||
}
|
}
|
||||||
|
|
||||||
return consecutiveDaysOff;
|
return consecutiveDaysOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all weekends for a specific year
|
// Get all weekend days for a year
|
||||||
function getWeekends(year: number): Date[] {
|
function getWeekends(year: number, weekendDays: number[]): Date[] {
|
||||||
const weekends: Date[] = [];
|
const weekends = [];
|
||||||
for (let month = 0; month < 12; month++) {
|
for (let d = new Date(year, 0, 1); d <= new Date(year, 11, 31); d.setDate(d.getDate() + 1)) {
|
||||||
for (let day = 1; day <= 31; day++) {
|
if (d.getMonth() === d.getMonth() && isWeekend(d, weekendDays)) {
|
||||||
const date = new Date(year, month, day);
|
weekends.push(new Date(d));
|
||||||
if (date.getMonth() !== month) break;
|
|
||||||
if (isWeekend(date)) weekends.push(date);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return weekends;
|
return weekends;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find gaps between days off
|
// Find gaps between days off that could be filled with PTO
|
||||||
function findGaps(allDaysOffSet: Set<string>, year: number): { start: Date; end: Date; gapLength: number }[] {
|
function findGaps(allDaysOff: Set<string>, year: number, weekendDays: number[]) {
|
||||||
const gaps: { start: Date; end: Date; gapLength: number }[] = [];
|
const gaps = [];
|
||||||
let currentGapStart: Date | null = null;
|
let gapStart = null;
|
||||||
|
|
||||||
for (let month = 0; month < 12; month++) {
|
for (let d = new Date(year, 0, 1); d <= new Date(year, 11, 31); d.setDate(d.getDate() + 1)) {
|
||||||
for (let day = 1; day <= 31; day++) {
|
if (!allDaysOff.has(dateKey(d)) && !isWeekend(d, weekendDays)) {
|
||||||
const date = new Date(year, month, day);
|
if (!gapStart) gapStart = new Date(d);
|
||||||
if (date.getMonth() !== month) break;
|
} else if (gapStart) {
|
||||||
|
const gapLength = daysBetween(gapStart, d);
|
||||||
const isDayOff = allDaysOffSet.has(dateKey(date));
|
|
||||||
|
|
||||||
if (!isDayOff && !isWeekend(date)) {
|
|
||||||
if (!currentGapStart) currentGapStart = date;
|
|
||||||
} else if (currentGapStart) {
|
|
||||||
const gapLength = daysBetween(currentGapStart, date);
|
|
||||||
if (gapLength > 0 && gapLength <= MAX_GAP_LENGTH) {
|
if (gapLength > 0 && gapLength <= MAX_GAP_LENGTH) {
|
||||||
gaps.push({ start: currentGapStart, end: new Date(date.getTime() - MS_IN_A_DAY), gapLength });
|
gaps.push({ start: gapStart, end: new Date(d.getTime() - MS_IN_A_DAY), gapLength });
|
||||||
}
|
}
|
||||||
currentGapStart = null;
|
gapStart = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (currentGapStart) {
|
|
||||||
const lastDayOfYear = new Date(year, 11, 31);
|
|
||||||
const gapLength = daysBetween(currentGapStart, lastDayOfYear) + 1;
|
|
||||||
if (gapLength > 0 && gapLength <= MAX_GAP_LENGTH) {
|
|
||||||
gaps.push({ start: currentGapStart, end: lastDayOfYear, gapLength });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return gaps;
|
return gaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rank gaps by efficiency
|
// Rank gaps by how efficiently they can be used to create longer periods off
|
||||||
function rankGapsByEfficiency(gaps: { start: Date; end: Date; gapLength: number }[], allDaysOffSet: Set<string>): any[] {
|
function rankGapsByEfficiency(gaps: any[], allDaysOff: Set<string>, weekendDays: number[]) {
|
||||||
return gaps.map(gap => {
|
return gaps
|
||||||
const backward = calculateChain(gap.start, gap.gapLength, allDaysOffSet, 'backward');
|
.map(gap => {
|
||||||
const forward = calculateChain(gap.end, gap.gapLength, allDaysOffSet, 'forward');
|
const [backward, forward] = ['backward', 'forward'].map(direction =>
|
||||||
|
calculateChain(direction === 'backward' ? gap.start : gap.end, gap.gapLength, allDaysOff, direction as 'backward' | 'forward', weekendDays)
|
||||||
return forward.chainLength > backward.chainLength || (forward.chainLength === backward.chainLength && forward.usedDaysOff <= backward.usedDaysOff)
|
);
|
||||||
|
return forward.chainLength > backward.chainLength ||
|
||||||
|
(forward.chainLength === backward.chainLength && forward.usedDaysOff <= backward.usedDaysOff)
|
||||||
? { ...gap, ...forward, fillFrom: 'end' }
|
? { ...gap, ...forward, fillFrom: 'end' }
|
||||||
: { ...gap, ...backward, fillFrom: 'start' };
|
: { ...gap, ...backward, fillFrom: 'start' };
|
||||||
}).sort((a, b) => a.gapLength - b.gapLength || b.chainLength - a.chainLength || a.usedDaysOff - b.usedDaysOff);
|
})
|
||||||
|
.sort((a, b) => a.gapLength - b.gapLength || b.chainLength - a.chainLength || a.usedDaysOff - b.usedDaysOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate potential chain length and days off used
|
// Calculate potential chain length in either direction from a gap
|
||||||
function calculateChain(startDate: Date, gapLength: number, allDaysOffSet: Set<string>, direction: 'backward' | 'forward'): { chainLength: number; usedDaysOff: number } {
|
function calculateChain(date: Date, gapLength: number, allDaysOff: Set<string>, direction: 'backward' | 'forward', weekendDays: number[]) {
|
||||||
let chainLength = gapLength;
|
|
||||||
let usedDaysOff = 0;
|
|
||||||
let currentDate = new Date(startDate);
|
|
||||||
|
|
||||||
const increment = direction === 'backward' ? -1 : 1;
|
const increment = direction === 'backward' ? -1 : 1;
|
||||||
const boundaryCheck = direction === 'backward' ? -MS_IN_A_DAY : MS_IN_A_DAY;
|
let chainLength = gapLength;
|
||||||
|
let currentDate = new Date(date);
|
||||||
|
|
||||||
while (allDaysOffSet.has(dateKey(new Date(currentDate.getTime() + boundaryCheck))) || isWeekend(new Date(currentDate.getTime() + boundaryCheck))) {
|
while (allDaysOff.has(dateKey(new Date(currentDate.getTime() + MS_IN_A_DAY * increment))) ||
|
||||||
|
isWeekend(new Date(currentDate.getTime() + MS_IN_A_DAY * increment), weekendDays)) {
|
||||||
chainLength++;
|
chainLength++;
|
||||||
currentDate.setDate(currentDate.getDate() + increment);
|
currentDate.setDate(currentDate.getDate() + increment);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < gapLength; i++) {
|
return {
|
||||||
const potentialDayOff = new Date(startDate);
|
chainLength,
|
||||||
potentialDayOff.setDate(potentialDayOff.getDate() + (i * increment));
|
usedDaysOff: Array.from({ length: gapLength }, (_, i) => {
|
||||||
if (!allDaysOffSet.has(dateKey(potentialDayOff)) && !isWeekend(potentialDayOff)) {
|
const d = new Date(date);
|
||||||
usedDaysOff++;
|
d.setDate(d.getDate() + i * increment);
|
||||||
}
|
return !allDaysOff.has(dateKey(d)) && !isWeekend(d, weekendDays);
|
||||||
|
}).filter(Boolean).length
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { chainLength, usedDaysOff };
|
// Select optimal days off based on ranked gaps
|
||||||
}
|
function selectDaysOff(rankedGaps: any[], daysOff: number, allDaysOff: Set<string>, weekendDays: number[]): Date[] {
|
||||||
|
const selectedDays = [];
|
||||||
|
let remainingDays = daysOff;
|
||||||
|
|
||||||
// Select days off based on ranked gaps
|
for (const gap of rankedGaps) {
|
||||||
function selectDaysOff(rankedGaps: any[], daysOff: number, allDaysOffSet: Set<string>, year: number): Date[] {
|
if (remainingDays <= 0) break;
|
||||||
const selectedDays: Date[] = [];
|
|
||||||
|
|
||||||
while (daysOff > 0 && rankedGaps.length > 0) {
|
|
||||||
const gap = rankedGaps.shift();
|
|
||||||
|
|
||||||
const increment = gap.fillFrom === 'start' ? 1 : -1;
|
const increment = gap.fillFrom === 'start' ? 1 : -1;
|
||||||
const startDate = gap.fillFrom === 'start' ? gap.start : gap.end;
|
const startDate = gap.fillFrom === 'start' ? gap.start : gap.end;
|
||||||
|
|
||||||
for (let i = 0; i < gap.gapLength && daysOff > 0; i++) {
|
for (let i = 0; i < gap.gapLength && remainingDays > 0; i++) {
|
||||||
const potentialDayOff = new Date(startDate);
|
const day = new Date(startDate);
|
||||||
potentialDayOff.setDate(potentialDayOff.getDate() + (i * increment));
|
day.setDate(day.getDate() + (i * increment));
|
||||||
|
|
||||||
if (!allDaysOffSet.has(dateKey(potentialDayOff)) && !isWeekend(potentialDayOff)) {
|
if (!allDaysOff.has(dateKey(day)) && !isWeekend(day, weekendDays)) {
|
||||||
selectedDays.push(potentialDayOff);
|
selectedDays.push(day);
|
||||||
allDaysOffSet.add(dateKey(potentialDayOff));
|
remainingDays--;
|
||||||
daysOff--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newGaps = findGaps(allDaysOffSet, year);
|
|
||||||
rankedGaps = rankGapsByEfficiency(newGaps, allDaysOffSet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedDays;
|
return selectedDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add consecutive days off to the list
|
// Check if a group contains both a weekend day and a non-weekend holiday/PTO day
|
||||||
function addConsecutiveDaysOff(consecutiveDaysOff: { startDate: Date; endDate: Date; usedDaysOff: number; totalDays: number }[], currentGroup: Date[], optimizedDaysOff: Date[]) {
|
function hasWeekendAndNonWeekendHoliday(group: Date[], weekendDays: number[], holidays: { date: Date }[], optimizedDaysOff: Date[]) {
|
||||||
const startDate = currentGroup[0];
|
return group.some(d => weekendDays.includes(d.getDay())) &&
|
||||||
const endDate = currentGroup[currentGroup.length - 1];
|
group.some(d => !weekendDays.includes(d.getDay()) && (isHoliday(d, holidays) || optimizedDaysOff.some(od => dateKey(od) === dateKey(d))));
|
||||||
const totalDays = daysBetween(startDate, endDate) + 1;
|
}
|
||||||
const usedDaysOff = currentGroup.filter(d => isDayOff(d, new Set(optimizedDaysOff.map(d => dateKey(d))))).length;
|
|
||||||
|
|
||||||
if (totalDays > 2) {
|
// Create a period object from a group of consecutive days
|
||||||
consecutiveDaysOff.push({
|
function createPeriod(group: Date[], optimizedDaysOff: Date[]) {
|
||||||
startDate,
|
return {
|
||||||
endDate,
|
startDate: group[0],
|
||||||
usedDaysOff,
|
endDate: group[group.length - 1],
|
||||||
totalDays
|
totalDays: daysBetween(group[0], group[group.length - 1]) + 1,
|
||||||
});
|
usedDaysOff: group.filter(d => optimizedDaysOff.some(od => dateKey(od) === dateKey(d))).length
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { injectSpeedInsights } from '@vercel/speed-insights';
|
|
||||||
import { inject } from '@vercel/analytics';
|
|
||||||
import countries from 'i18n-iso-countries';
|
import countries from 'i18n-iso-countries';
|
||||||
import enLocale from 'i18n-iso-countries/langs/en.json';
|
import enLocale from 'i18n-iso-countries/langs/en.json';
|
||||||
import CalendarMonth from '../lib/CalendarMonth.svelte';
|
import CalendarMonth from '../lib/CalendarMonth.svelte';
|
||||||
@@ -34,6 +32,9 @@
|
|||||||
|
|
||||||
let showHolidaysList: boolean = false;
|
let showHolidaysList: boolean = false;
|
||||||
|
|
||||||
|
let showWeekendSettings: boolean = false;
|
||||||
|
let weekendDays: number[] = [];
|
||||||
|
|
||||||
$: selectedCountryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
$: selectedCountryCode = Object.keys(countriesList).find(code => countriesList[code] === selectedCountry) || '';
|
||||||
|
|
||||||
$: if (selectedCountryCode || selectedStateCode || daysOff || year) {
|
$: if (selectedCountryCode || selectedStateCode || daysOff || year) {
|
||||||
@@ -63,8 +64,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
inject();
|
|
||||||
injectSpeedInsights();
|
|
||||||
|
|
||||||
fetchCountryCode().then(() => {
|
fetchCountryCode().then(() => {
|
||||||
defaultYear = new Date().getFullYear();
|
defaultYear = new Date().getFullYear();
|
||||||
@@ -89,6 +88,14 @@
|
|||||||
updateStatesList(selectedCountryCode);
|
updateStatesList(selectedCountryCode);
|
||||||
}
|
}
|
||||||
window.addEventListener('keydown', handleKeyDown);
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
|
|
||||||
|
// Load weekend days from localStorage or set defaults
|
||||||
|
const storedWeekendDays = localStorage.getItem('weekendDays');
|
||||||
|
weekendDays = storedWeekendDays
|
||||||
|
? JSON.parse(storedWeekendDays)
|
||||||
|
: [6, 0]; // Default to Saturday (6) and Sunday (0)
|
||||||
|
|
||||||
|
localStorage.setItem('weekendDays', JSON.stringify(weekendDays));
|
||||||
});
|
});
|
||||||
|
|
||||||
async function fetchCountryCode() {
|
async function fetchCountryCode() {
|
||||||
@@ -127,10 +134,9 @@
|
|||||||
date: new Date(holiday.date),
|
date: new Date(holiday.date),
|
||||||
hidden: isHolidayHidden(holiday)
|
hidden: isHolidayHidden(holiday)
|
||||||
}));
|
}));
|
||||||
const visibleHolidays = holidays
|
const visibleHolidays = holidays.filter(h => !h.hidden);
|
||||||
.filter(h => !h.hidden);
|
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, daysOff, weekendDays);
|
||||||
optimizedDaysOff = optimizeDaysOff(visibleHolidays, year, daysOff);
|
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year, weekendDays);
|
||||||
consecutiveDaysOff = calculateConsecutiveDaysOff(visibleHolidays, optimizedDaysOff, year);
|
|
||||||
} else {
|
} else {
|
||||||
holidays = [];
|
holidays = [];
|
||||||
optimizedDaysOff = [];
|
optimizedDaysOff = [];
|
||||||
@@ -245,6 +251,47 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$: visibleHolidaysCount = holidays.filter(h => !h.hidden).length;
|
$: visibleHolidaysCount = holidays.filter(h => !h.hidden).length;
|
||||||
|
|
||||||
|
function toggleWeekendDay(dayNumber: number) {
|
||||||
|
console.log('Toggling weekend day:', dayNumber);
|
||||||
|
if (weekendDays.includes(dayNumber)) {
|
||||||
|
weekendDays = weekendDays.filter(d => d !== dayNumber);
|
||||||
|
} else {
|
||||||
|
weekendDays = [...weekendDays, dayNumber];
|
||||||
|
}
|
||||||
|
weekendDays.sort();
|
||||||
|
localStorage.setItem('weekendDays', JSON.stringify(weekendDays));
|
||||||
|
updateHolidays();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstDayOfWeek(locale: string): number {
|
||||||
|
const normalizedLocale = locale.toLowerCase() === 'us' ? 'en-US' : `en-${locale.toUpperCase()}`;
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
const weekFirstDay = new Intl.Locale(normalizedLocale)?.weekInfo?.firstDay;
|
||||||
|
if (weekFirstDay !== undefined) {
|
||||||
|
return weekFirstDay;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fallback if weekInfo is not supported
|
||||||
|
}
|
||||||
|
return normalizedLocale === 'en-US' ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrderedDays() {
|
||||||
|
const days = [
|
||||||
|
{ name: 'Sunday', index: 0 },
|
||||||
|
{ name: 'Monday', index: 1 },
|
||||||
|
{ name: 'Tuesday', index: 2 },
|
||||||
|
{ name: 'Wednesday', index: 3 },
|
||||||
|
{ name: 'Thursday', index: 4 },
|
||||||
|
{ name: 'Friday', index: 5 },
|
||||||
|
{ name: 'Saturday', index: 6 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const firstDay = getFirstDayOfWeek(selectedCountryCode || 'US');
|
||||||
|
return [...days.slice(firstDay), ...days.slice(0, firstDay)];
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -336,23 +383,27 @@
|
|||||||
.calendar-key {
|
.calendar-key {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
gap: 20px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.key-item {
|
.key-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0 10px;
|
gap: 5px;
|
||||||
font-size: 0.9em;
|
}
|
||||||
|
|
||||||
|
.key-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-box {
|
.color-box {
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
margin-right: 5px;
|
min-width: 15px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +555,6 @@
|
|||||||
.content-box li {
|
.content-box li {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box button {
|
.content-box button {
|
||||||
@@ -537,6 +587,9 @@
|
|||||||
|
|
||||||
.holidays-list {
|
.holidays-list {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #222;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.holidays-list ul {
|
.holidays-list ul {
|
||||||
@@ -547,7 +600,18 @@
|
|||||||
.holidays-list li {
|
.holidays-list li {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 10px;
|
justify-content: space-between;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holidays-list li:hover {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.holidays-list span {
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.holidays-list button {
|
.holidays-list button {
|
||||||
@@ -558,11 +622,26 @@
|
|||||||
padding: 5px 25px;
|
padding: 5px 25px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
min-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.holidays-list button:hover {
|
.holidays-list button:hover {
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
@@ -632,31 +711,47 @@
|
|||||||
<div class="content-box" id="calendar">
|
<div class="content-box" id="calendar">
|
||||||
<div class="calendar-key">
|
<div class="calendar-key">
|
||||||
<div class="key-item">
|
<div class="key-item">
|
||||||
<span class="color-box weekend"></span> Weekend
|
<div class="key-label">
|
||||||
|
<span class="color-box optimized"></span>
|
||||||
|
<span>Day Off</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="key-item">
|
<div class="key-item">
|
||||||
<span class="color-box optimized"></span> Day Off
|
<div class="key-label">
|
||||||
</div>
|
<span class="color-box holiday"></span>
|
||||||
<div class="key-item">
|
<span>Public Holiday</span>
|
||||||
<span class="color-box holiday"></span> Public Holiday
|
|
||||||
</div>
|
</div>
|
||||||
{#if holidays.length > 0}
|
{#if holidays.length > 0}
|
||||||
<a href="#" on:click|preventDefault={() => showHolidaysList = !showHolidaysList} class="edit-link">
|
<a href="#" on:click|preventDefault={() => showHolidaysList = !showHolidaysList} class="edit-link">
|
||||||
(edit list)
|
(edit)
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="key-item">
|
||||||
|
<div class="key-label">
|
||||||
|
<span class="color-box weekend"></span>
|
||||||
|
<span>Weekend</span>
|
||||||
|
</div>
|
||||||
|
<a href="#" on:click|preventDefault={() => showWeekendSettings = !showWeekendSettings} class="edit-link">
|
||||||
|
(edit)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if showHolidaysList}
|
{#if showHolidaysList || showWeekendSettings}
|
||||||
<div class="holidays-list">
|
<div class="holidays-list">
|
||||||
|
{#if showHolidaysList}
|
||||||
|
<div class="settings-section">
|
||||||
<h3>Public Holidays</h3>
|
<h3>Public Holidays</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{#each holidays as holiday}
|
{#each holidays as holiday}
|
||||||
<li>
|
<li>
|
||||||
|
<div class="setting-item-label">
|
||||||
<span class="color-box holiday"></span>
|
<span class="color-box holiday"></span>
|
||||||
<span class={holiday.hidden ? 'strikethrough' : ''}>
|
<span class={holiday.hidden ? 'strikethrough' : ''}>
|
||||||
{formatDate(holiday.date)}: {holiday.name}
|
{formatDate(holiday.date)}: {holiday.name}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
<button on:click={() => toggleHolidayVisibility(holiday)}>
|
<button on:click={() => toggleHolidayVisibility(holiday)}>
|
||||||
{holiday.hidden ? 'Show' : 'Hide'}
|
{holiday.hidden ? 'Show' : 'Hide'}
|
||||||
</button>
|
</button>
|
||||||
@@ -666,6 +761,27 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if showWeekendSettings}
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3>Weekend Days</h3>
|
||||||
|
<ul>
|
||||||
|
{#each getOrderedDays() as {name, index}}
|
||||||
|
<li>
|
||||||
|
<div class="setting-item-label">
|
||||||
|
<span class="color-box weekend"></span>
|
||||||
|
<span>{name}</span>
|
||||||
|
</div>
|
||||||
|
<button on:click={() => toggleWeekendDay(index)}>
|
||||||
|
{weekendDays.includes(index) ? 'Remove' : 'Add'}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="calendar-grid">
|
<div class="calendar-grid">
|
||||||
{#each months as month}
|
{#each months as month}
|
||||||
<div class="calendar-container">
|
<div class="calendar-container">
|
||||||
@@ -676,6 +792,7 @@
|
|||||||
optimizedDaysOff={optimizedDaysOff}
|
optimizedDaysOff={optimizedDaysOff}
|
||||||
consecutiveDaysOff={consecutiveDaysOff}
|
consecutiveDaysOff={consecutiveDaysOff}
|
||||||
selectedCountryCode={selectedCountryCode}
|
selectedCountryCode={selectedCountryCode}
|
||||||
|
weekendDays={weekendDays}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
Reference in New Issue
Block a user