feat: implement SingleDatePicker component with unique ID generation; add utility functions for calendar and color management; update styles and remove unused CSS

This commit is contained in:
Astrian Zheng 2025-02-24 10:53:15 +11:00
parent 9c68b406e0
commit beb8d47ad8
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA
15 changed files with 803 additions and 97 deletions

487
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@vitejs/plugin-vue": "^5.2.1",
"@vue/compiler-sfc": "^3.5.13",
"@vue/tsconfig": "^0.7.0",
"sass-embedded": "^1.85.0",
"typescript": "~5.7.2",
"vite": "^6.1.0",
"vue-tsc": "^2.2.0"
@ -66,6 +67,13 @@
"node": ">=6.9.0"
}
},
"node_modules/@bufbuild/protobuf": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.3.tgz",
"integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==",
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
@ -1002,6 +1010,20 @@
"balanced-match": "^1.0.0"
}
},
"node_modules/buffer-builder": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz",
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
"dev": true,
"license": "MIT/X11"
},
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
"dev": true,
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@ -1089,6 +1111,16 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@ -1099,6 +1131,13 @@
"he": "bin/he"
}
},
"node_modules/immutable": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz",
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
"dev": true,
"license": "MIT"
},
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
@ -1229,6 +1268,401 @@
"fsevents": "~2.3.2"
}
},
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/sass-embedded": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.85.0.tgz",
"integrity": "sha512-x3Vv54g0jv1aPSW8OTA/0GzQCs/HMQOjIkLtZJ3Xsn/I4vnyjKbVTQmFTax9bQjldqLEEkdbvy6ES/cOOnYNwA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bufbuild/protobuf": "^2.0.0",
"buffer-builder": "^0.2.0",
"colorjs.io": "^0.5.0",
"immutable": "^5.0.2",
"rxjs": "^7.4.0",
"supports-color": "^8.1.1",
"sync-child-process": "^1.0.2",
"varint": "^6.0.0"
},
"bin": {
"sass": "dist/bin/sass.js"
},
"engines": {
"node": ">=16.0.0"
},
"optionalDependencies": {
"sass-embedded-android-arm": "1.85.0",
"sass-embedded-android-arm64": "1.85.0",
"sass-embedded-android-ia32": "1.85.0",
"sass-embedded-android-riscv64": "1.85.0",
"sass-embedded-android-x64": "1.85.0",
"sass-embedded-darwin-arm64": "1.85.0",
"sass-embedded-darwin-x64": "1.85.0",
"sass-embedded-linux-arm": "1.85.0",
"sass-embedded-linux-arm64": "1.85.0",
"sass-embedded-linux-ia32": "1.85.0",
"sass-embedded-linux-musl-arm": "1.85.0",
"sass-embedded-linux-musl-arm64": "1.85.0",
"sass-embedded-linux-musl-ia32": "1.85.0",
"sass-embedded-linux-musl-riscv64": "1.85.0",
"sass-embedded-linux-musl-x64": "1.85.0",
"sass-embedded-linux-riscv64": "1.85.0",
"sass-embedded-linux-x64": "1.85.0",
"sass-embedded-win32-arm64": "1.85.0",
"sass-embedded-win32-ia32": "1.85.0",
"sass-embedded-win32-x64": "1.85.0"
}
},
"node_modules/sass-embedded-android-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.85.0.tgz",
"integrity": "sha512-pPBT7Ad6G8Mlao8ypVNXW2ya7I/Bhcny+RYZ/EmrunEXfhzCNp4PWV2VAweitPO9RnPIJwvUTkLc8Fu6K3nVmw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.85.0.tgz",
"integrity": "sha512-4itDzRwezwrW8+YzMLIwHtMeH+qrBNdBsRn9lTVI15K+cNLC8z5JWJi6UCZ8TNNZr9LDBfsh5jUdjSub0yF7jg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.85.0.tgz",
"integrity": "sha512-bwqKq95hzbGbMTeXCMQhH7yEdc2xJVwIXj7rGdD3McvyFWbED6362XRFFPI5YyjfD2wRJd9yWLh/hn+6VyjcYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.85.0.tgz",
"integrity": "sha512-Fgkgay+5EePJXZFHR5Vlkutnsmox2V6nX4U3mfGbSN1xjLRm8F5ST72V2s5Z0mnIFpGvEu/v7hfptgViqMvaxg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-android-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.85.0.tgz",
"integrity": "sha512-/bG3JgTn3eoIDHCiJNVkLeJgUesat4ghxqYmKMZUJx++4e6iKCDj8XwQTJAgm+QDrsPKXHBacHEANJ9LEAuTqg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.85.0.tgz",
"integrity": "sha512-plp8TyMz97YFBCB3ndftEvoW29vyfsSBJILM5U84cGzr06SvLh/Npjj8psfUeRw+upEk1zkFtw5u61sRCdgwIw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-darwin-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.85.0.tgz",
"integrity": "sha512-LP8Zv8DG57Gn6PmSwWzC0gEZUsGdg36Ps3m0i1fVTOelql7N3HZIrlPYRjJvidL8ZlB3ISxNANebTREUHn/wkQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.85.0.tgz",
"integrity": "sha512-18xOAEfazJt1MMVS2TRHV94n81VyMnywOoJ7/S7I79qno/zx26OoqqP4XvH107xu8+mZ9Gg54LrUH6ZcgHk08g==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.85.0.tgz",
"integrity": "sha512-JRIRKVOY5Y8M1zlUOv9AQGju4P6lj8i5vLJZsVYVN/uY8Cd2dDJZPC8EOhjntp+IpF8AOGIHqCeCkHBceIyIjA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.85.0.tgz",
"integrity": "sha512-4JH+h+gLt9So22nNPQtsKojEsLzjld9ol3zWcOtMGclv+HojZGbCuhJUrLUcK72F8adXYsULmWhJPKROLIwYMA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.85.0.tgz",
"integrity": "sha512-Z1j4ageDVFihqNUBnm89fxY46pY0zD/Clp1D3ZdI7S+D280+AEpbm5vMoH8LLhBQfQLf2w7H++SZGpQwrisudQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.85.0.tgz",
"integrity": "sha512-aoQjUjK28bvdw9XKTjQeayn8oWQ2QqvoTD11myklGd3IHH7Jj0nwXUstI4NxDueCKt3wghuZoIQkjOheReQxlg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.85.0.tgz",
"integrity": "sha512-/cJCSXOfXmQFH8deE+3U9x+BSz8i0d1Tt9gKV/Gat1Xm43Oumw8pmZgno+cDuGjYQInr9ryW5121pTMlj/PBXQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.85.0.tgz",
"integrity": "sha512-l+FJxMXkmg42RZq5RFKXg4InX0IA7yEiPHe4kVSdrczP7z3NLxk+W9wVkPnoRKYIMe1qZPPQ25y0TgI4HNWouA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-musl-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.85.0.tgz",
"integrity": "sha512-M9ffjcYfFcRvkFA6V3DpOS955AyvmpvPAhL/xNK45d/ma1n1ehTWpd24tVeKiNK5CZkNjjMEfyw2fHa6MpqmEA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-riscv64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.85.0.tgz",
"integrity": "sha512-yqPXQWfM+qiIPkfn++48GOlbmSvUZIyL9nwFstBk0k4x40UhbhilfknqeTUpxoHfQzylTGVhrm5JE7MjM+LNZA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-linux-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.85.0.tgz",
"integrity": "sha512-NTDeQFZcuVR7COoaRy8pZD6/+QznwBR8kVFsj7NpmvX9aJ7TX/q+OQZHX7Bfb3tsfKXhf1YZozegPuYxRnMKAQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-arm64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.85.0.tgz",
"integrity": "sha512-gO0VAuxC4AdV+uZYJESRWVVHQWCGzNs0C3OKCAdH4r1vGRugooMi7J/5wbwUdXDA1MV9ICfhlKsph2n3GiPdqA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-ia32": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.85.0.tgz",
"integrity": "sha512-PCyn6xeFIBUgBceNypuf73/5DWF2VWPlPqPuBprPsTvpZOMUJeBtP+Lf4mnu3dNy1z76mYVnpaCnQmzZ0zHZaA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-embedded-win32-x64": {
"version": "1.85.0",
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.85.0.tgz",
"integrity": "sha512-AknE2jLp6OBwrR5hQ8pDsG94KhJCeSheFJ2xgbnk8RUjZX909JiNbgh2sNt9LG+RXf4xZa55dDL537gZoCx/iw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@ -1238,6 +1672,52 @@
"node": ">=0.10.0"
}
},
"node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/sync-child-process": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
"integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"sync-message-port": "^1.0.0"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/sync-message-port": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz",
"integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD"
},
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
@ -1259,6 +1739,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
"dev": true,
"license": "MIT"
},
"node_modules/vite": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz",

View File

@ -16,6 +16,7 @@
"@vitejs/plugin-vue": "^5.2.1",
"@vue/compiler-sfc": "^3.5.13",
"@vue/tsconfig": "^0.7.0",
"sass-embedded": "^1.85.0",
"typescript": "~5.7.2",
"vite": "^6.1.0",
"vue-tsc": "^2.2.0"

View File

@ -3,20 +3,16 @@ import {SingleDatePicker} from '../src'
</script>
<template>
<SingleDatePicker />
<div class="container">
<SingleDatePicker />
</div>
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
<style scoped lang="scss">
.container {
border: 1px solid #d8d8d8;
background: white;
border-radius: 0.5rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
</style>

11
playground/index.scss Normal file
View File

@ -0,0 +1,11 @@
body {
background: #f0f0f0;
margin: 0;
#app {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
}

View File

@ -1,5 +1,5 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import './index.scss'
createApp(App).mount('#app')

View File

@ -1,79 +0,0 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@ -1,7 +1,25 @@
<script setup lang="ts">
import { ref } from 'vue'
import { generateUniqueId } from '../utils'
const selectMonth = ref(false)
const uniqueId = generateUniqueId()
</script>
<template>
singledatepicker
</template>
<div :id="`__datenel_${uniqueId}`">
<div class='datenel-component' role="dialog" aria-label="Date selection panel" v-if="!selectMonth">
<div className='__datenel_header'>
<button className='__datenel_stepper' @click="() => {}" :aria-label="`Go to last month, `"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M10.8284 12.0007L15.7782 16.9504L14.364 18.3646L8 12.0007L14.364 5.63672L15.7782 7.05093L10.8284 12.0007Z"></path></svg></button>
<button className='__datenel_indicator' @click="() => {}" :aria-label="`You are now at . Click here to quick-select month or year.`">
Feb 2025
</button>
<button className='__datenel_stepper' @click="() => {}" :aria-label="`Go to next month, `"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13.1717 12.0007L8.22192 7.05093L9.63614 5.63672L16.0001 12.0007L9.63614 18.3646L8.22192 16.9504L13.1717 12.0007Z"></path></svg></button>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
@use '../style.scss' as *;
</style>

View File

@ -1,3 +1 @@
/// <reference types="vite/client" />
export { default as SingleDatePicker } from './components/SingleDatePicker.vue'

199
src/style.scss Normal file
View File

@ -0,0 +1,199 @@
.datenel-component {
user-select: none;
color: var(--datenel-main-color);
button {
border: none;
background: none;
cursor: pointer;
color: var(--datenel-main-color);
&:hover {
background: var(--datenel-hover-color);
}
}
button.__datenel_sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.__datenel_header {
padding: 0.75rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--datenel-border-color);
button {
img {
width: 1rem;
height: 1rem;
}
&.__datenel_stepper {
width: 1.75rem;
height: 1.75rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
&.__datenel_indicator {
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
}
}
input.__datenel_indicator {
border: none;
background: none;
text-align: center;
outline: none;
border-radius: 0.25rem;
padding: 0.25rem 0;
color: var(--datenel-main-color);
width: 4rem;
font-size: 0.75rem;
&:hover {
background: var(--datenel-hover-color);
}
}
}
.__datenel_body {
display: flex;
.__datenel_calendar-view-body {
padding: 0.75rem;
gap: 0.125rem;
&.__datenel_grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
.__datenel_item.__datenel_date {
border-radius: 50%;
&.__datenel_extra-month, &.__datenel_not-available {
cursor: default;
}
&.__datenel_active {
background: var(--datenel-accent-color);
color: var(--datenel-reversed-color);
}
}
}
&.__datenel_flex {
display: flex;
flex-direction: column;
.__datenel_listitem {
padding: 0;
display: grid;
grid-template-columns: repeat(7, 1fr);
border-radius: 1rem;
.__datenel_item.__datenel_date {
background: none;
}
&.__datenel_active {
background: var(--datenel-accent-color);
color: var(--datenel-reversed-color);
.__datenel_extra-month, .__datenel_not-available {
opacity: 0.5;
}
}
}
}
.__datenel_item {
width: 2rem;
height: 2rem;
display: flex;
justify-content: center;
align-items: center;
font-size: 0.75rem;
position: relative;
&.__datenel_extra-month, &.__datenel_not-available {
opacity: 0.3;
&:hover {
background: none;
};
}
&.__datenel_day-indicator {
opacity: 0.5;
}
.__datenel_today-indicator {
position: absolute;
bottom: 0.25rem;
width: 0.25rem;
height: 0.25rem;
}
}
}
.__datenel_month-selector-body {
display: grid;
grid-template-columns: repeat(3, 1fr);
padding: 0.75rem;
gap: 0.125rem;
.__datenel_item {
border-radius: 0.25rem;
height: 2rem;
padding: 0 0.5rem;
&.__datenel_not-available {
opacity: 0.3;
cursor: default;
&:hover {
background: none;
};
}
}
}
.__datenel_week-indicator {
display: flex;
flex-direction: column;
border-right: 1px solid var(--datenel-border-color);
gap: 0.125rem;
padding: 0.75rem;
.__datenel_item {
font-size: 0.75rem;
width: 2rem;
height: 2rem;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
}
.__datenel_item.__datenel_title {
opacity: 0.5;
}
.__datenel_item.__datenel_active {
background: var(--datenel-accent-color);
color: var(--datenel-reversed-color);
}
}
}
}

21
src/utils/applyColor.ts Normal file
View File

@ -0,0 +1,21 @@
export default (id: string, colorValues: {
mainColor: string
accentColor: string
reversedColor: string
hoverColor: string
borderColor: string
} = {
mainColor: '#000000',
accentColor: '#000000',
reversedColor: '#ffffff',
hoverColor: '#00000017',
borderColor: '#e0e0e0'
}) => {
const element = document.querySelector(`#__datenel-${id}`) as HTMLDivElement
if (!element) return
element.style.setProperty(`--datenel-main-color`, colorValues.mainColor)
element.style.setProperty(`--datenel-accent-color`, colorValues.accentColor)
element.style.setProperty(`--datenel-reversed-color`, colorValues.reversedColor)
element.style.setProperty(`--datenel-hover-color`, colorValues.hoverColor)
element.style.setProperty(`--datenel-border-color`, colorValues.borderColor)
}

View File

@ -0,0 +1,19 @@
export default (date: Date): { weekYear: number, weekNum: number } => {
const tempDate = new Date(date)
tempDate.setHours(0, 0, 0, 0)
tempDate.setDate(tempDate.getDate() + 4 - (tempDate.getDay() || 7))
const forthDay = new Date(tempDate.getFullYear(), 0, 4)
console.log(forthDay)
forthDay.setDate(forthDay.getDate() + 4 - (forthDay.getDay() || 7))
const diffInDays = Math.floor((tempDate.getTime() - forthDay.getTime()) / (24 * 60 * 60 * 1000))
const weekNum = Math.ceil((diffInDays + 1) / 7)
return {
weekYear: tempDate.getFullYear(),
weekNum
}
}

View File

@ -0,0 +1,3 @@
export default (): string => {
return Math.random().toString(36).split('.')[1]
}

View File

@ -0,0 +1,19 @@
export default (currentDate: number, currentYear: number): Date[] => {
const baselineDate = new Date(currentYear, currentDate)
const calendarStart = new Date(baselineDate.getFullYear(), baselineDate.getMonth(), 1)
const dayOfWeek = calendarStart.getDay() === 0 ? 7 : calendarStart.getDay()
if (dayOfWeek !== 1)
calendarStart.setDate(calendarStart.getDate() - dayOfWeek + 1)
const calendarEnd = new Date(baselineDate.getFullYear(), baselineDate.getMonth() + 1, 0)
if (calendarEnd.getDay() !== 0)
calendarEnd.setDate(calendarEnd.getDate() + 7 - calendarEnd.getDay())
const newDates = []
for (let i = calendarStart; i <= calendarEnd; i.setDate(i.getDate() + 1))
newDates.push(new Date(i))
return newDates
}

View File

@ -0,0 +1,8 @@
export default (userLang: string) => {
const newL10nDays = []
for (let i = 0; i < 7; i++) {
const date = new Date(2021, 0, i + 4)
newL10nDays.push(date.toLocaleDateString(userLang, {weekday: "narrow"}))
}
return newL10nDays
}

5
src/utils/index.ts Normal file
View File

@ -0,0 +1,5 @@
export { default as getCalendarDates } from './getCalendarDates'
export { default as getL10Weekday } from './getL10Weekday'
export { default as generateUniqueId } from './generateUniqueId'
export { default as applyColor } from './applyColor'
export { default as calculateWeekNum } from './calculateWeekNum'