├── .eslintrc.cjs ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc.json ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── deploy.sh ├── index.html ├── package-lock.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ ├── base.css │ └── main.css ├── components │ ├── TheObserver.vue │ └── VueInlineCalendar.vue ├── helpers │ ├── check-is-in-range.js │ ├── check-is-weekend.js │ └── check-same-day.js ├── index.js └── main.js ├── vite.config.js └── vite.lib-config.js /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require("@rushstack/eslint-patch/modern-module-resolution"); 3 | 4 | module.exports = { 5 | root: true, 6 | env: { 7 | node: true 8 | }, 9 | extends: [ 10 | "plugin:vue/vue3-essential", 11 | "eslint:recommended", 12 | "@vue/eslint-config-prettier", 13 | ], 14 | parserOptions: { 15 | ecmaVersion: "latest", 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://www.buymeacoffee.com/sashajarvi"] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "arrowParens": "avoid" 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alexandr Yermakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue3 Inline Calendar 2 | 3 | The simple, functional inline calendar component for Vue3 (you can find the version for Vue2 [here](https://github.com/SashaJarvi/vue2-inline-calendar)) based on Intersection Observer API — just drag and scroll to get future and past dates. 4 | 5 | ## Installation 6 | 7 | `npm i vue-inline-calendar -S` 8 | 9 | or 10 | 11 | `yarn add vue-inline-calendar` 12 | 13 | ## Usage 14 | 15 | ### Options API 16 | ``` 17 | 22 | 23 | 39 | ``` 40 | 41 | ### Composition API 42 | ``` 43 | 48 | 49 | 68 | ``` 69 | 70 | ## Available props 71 | | Prop name | Description | Type | Default value | 72 | |------------------------|------------------------------------------------------------------------------------------|---------|---------------| 73 | | selectedDate | Initial selected date | Date | null | 74 | | selectedRange | Initial selected range of dates | Object | null | 75 | | daysRange | Number of days, which will be loaded on scroll | Number | 7 | 76 | | itemWidth | Width of date element (`.date-item`) | Number | 80 | 77 | | itemsGap | Distance between date elements | Number | 10 | 78 | | locale | A string with a [BCP 47 language tag](https://www.techonthenet.com/js/language_tags.php) | String | "en-US" | 79 | | scrollSpeed | Speed of dates scroll | Number | 4 | 80 | | disableWeekends | Excluding weekends from selection | Boolean | false | 81 | | specMinDate | Minimum allowed date | Date | null | 82 | | specMaxDate | Maximum allowed date | Date | null | 83 | | disablePastDays | Excluding dates before today's date from selection | Boolean | false | 84 | | disableNextDays | Excluding dates after today's date from selection | Boolean | false | 85 | | isRange | Setting up range mode — selection of start and end dates | Boolean | false | 86 | | showYear | Showing of the current year (pass `false`, if you want to hide the year) | Boolean | true | 87 | | showMonth | Showing of the date's month (pass `false`, if you want to hide the month) | Boolean | true | 88 | | showWeekday | Showing of the date's weekend (pass `false`, if you want to hide the weekend) | Boolean | true | 89 | | enableMousewheelScroll | Enabling of the calendar scrolling when using the mousewheel | Boolean | false | 90 | 91 | ## Available events 92 | | Event name | Description | Payload | 93 | |-----------------------|------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------| 94 | | update:selected-date | Fires on date selection | Selected date (instance of `Date` object) | 95 | | update:selected-range | Fires on date range selection (when `endDate` is selected) | Object with startDate and endDate keys and dates as values:
`{startDate: this.startDate, endDate: this.endDate }` | 96 | 97 | ## License 98 | [MIT](https://github.com/SashaJarvi/vue2-inline-calendar/blob/main/LICENSE) License 99 | 100 | ## Support the author 101 | If you would like to support me and my work, you can make a donation via Buy Me a Coffee (link at the section Sponsor this project) or with cryptocurrency: 102 | 103 | | Platform | Address | 104 | |:----------------------------:|:---------------------------------------------:| 105 | | Bitcoin | `bc1q0rygfalnctew4cla3ed9wfw2pv0uh4r0eyfuag` | 106 | | Ethereum/Tether USDT (TRC20) | `0x38b3822213c6BDCc01eF770442F5BF0842AB740f` | 107 | | Litecoin | `ltc1qdgs0jult63k6ggjzaedh3er2z7w70aktl5j2wu` | 108 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run build:gh 8 | 9 | # navigate into the build output directory 10 | cd dist-gh 11 | 12 | # place .nojekyll to bypass Jekyll processing 13 | echo > .nojekyll 14 | 15 | # if you are deploying to a custom domain 16 | # echo 'www.example.com' > CNAME 17 | 18 | git init 19 | git checkout -B main 20 | git add -A 21 | git commit -m 'deploy to github pages' 22 | 23 | # if you are deploying to https://.github.io 24 | # git push -f git@github.com:/.github.io.git main 25 | 26 | # if you are deploying to https://.github.io/ 27 | git push -f git@github.com:SashaJarvi/vue-inline-calendar.git main:gh-pages 28 | 29 | cd - 30 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue Inline Calendar 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-inline-calendar", 3 | "version": "1.0.0", 4 | "main": "./dist/vue-inline-calendar.umd.cjs", 5 | "module": "./dist/vue-inline-calendar.js", 6 | "type": "module", 7 | "files": [ 8 | "dist" 9 | ], 10 | "author": "Sasha Jarvi", 11 | "description": "The simple, functional inline calendar component for Vue3 based on Intersection Observer API — just drag and scroll to get future and past dates.", 12 | "exports": { 13 | ".": { 14 | "import": "./dist/vue-inline-calendar.js", 15 | "require": "./dist/vue-inline-calendar.umd.cjs" 16 | }, 17 | "./dist/style.css": "./dist/style.css" 18 | }, 19 | "private": false, 20 | "scripts": { 21 | "dev": "vite", 22 | "build:gh": "vite build", 23 | "build:lib": "vite build -c vite.lib-config.js", 24 | "preview": "vite preview", 25 | "test:unit": "vitest --environment jsdom --root src/", 26 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore" 27 | }, 28 | "dependencies": { 29 | "vue": "^3.2.45", 30 | "vue-dragscroll": "^4.0.5" 31 | }, 32 | "devDependencies": { 33 | "@rushstack/eslint-patch": "^1.1.4", 34 | "@vitejs/plugin-vue": "^3.2.0", 35 | "@vue/eslint-config-prettier": "^7.0.0", 36 | "@vue/test-utils": "^2.2.4", 37 | "eslint": "^8.22.0", 38 | "eslint-plugin-vue": "^9.3.0", 39 | "jsdom": "^20.0.3", 40 | "prettier": "^2.7.1", 41 | "sass": "^1.56.1", 42 | "vite": "^3.2.4", 43 | "vitest": "^0.25.3" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/SashaJarvi/vue-inline-calendar/issues" 47 | }, 48 | "homepage": "https://sashajarvi.github.io/vue-inline-calendar", 49 | "keywords": [ 50 | "vue", 51 | "vue3", 52 | "vue-component", 53 | "vue component", 54 | "calendar-component", 55 | "calendar component", 56 | "calendar" 57 | ], 58 | "license": "MIT", 59 | "repository": { 60 | "type": "git", 61 | "url": "https://github.com/SashaJarvi/vue-inline-calendar.git" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SashaJarvi/vue-inline-calendar/caa366b29b0a217bbb44e82fecac82f208b9220f/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 131 | 132 | 158 | 159 | 205 | -------------------------------------------------------------------------------- /src/assets/base.css: -------------------------------------------------------------------------------- 1 | /* color palette from */ 2 | :root { 3 | --vt-c-white: #ffffff; 4 | --vt-c-white-soft: #f8f8f8; 5 | --vt-c-white-mute: #f2f2f2; 6 | 7 | --vt-c-black: #181818; 8 | --vt-c-black-soft: #222222; 9 | --vt-c-black-mute: #282828; 10 | 11 | --vt-c-indigo: #2c3e50; 12 | 13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); 14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); 15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); 16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); 17 | 18 | --vt-c-text-light-1: var(--vt-c-indigo); 19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66); 20 | --vt-c-text-dark-1: var(--vt-c-white); 21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); 22 | } 23 | 24 | /* semantic color variables for this project */ 25 | :root { 26 | --color-background: var(--vt-c-white); 27 | --color-background-soft: var(--vt-c-white-soft); 28 | --color-background-mute: var(--vt-c-white-mute); 29 | 30 | --color-border: var(--vt-c-divider-light-2); 31 | --color-border-hover: var(--vt-c-divider-light-1); 32 | 33 | --color-heading: var(--vt-c-text-light-1); 34 | --color-text: var(--vt-c-text-light-1); 35 | 36 | --section-gap: 160px; 37 | } 38 | 39 | @media (prefers-color-scheme: dark) { 40 | :root { 41 | --color-background: var(--vt-c-black); 42 | --color-background-soft: var(--vt-c-black-soft); 43 | --color-background-mute: var(--vt-c-black-mute); 44 | 45 | --color-border: var(--vt-c-divider-dark-2); 46 | --color-border-hover: var(--vt-c-divider-dark-1); 47 | 48 | --color-heading: var(--vt-c-text-dark-1); 49 | --color-text: var(--vt-c-text-dark-2); 50 | } 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | box-sizing: border-box; 57 | margin: 0; 58 | padding: 0; 59 | position: relative; 60 | font-weight: normal; 61 | } 62 | 63 | body { 64 | min-height: 100vh; 65 | color: var(--color-text); 66 | background: var(--color-background); 67 | transition: color 0.5s, background-color 0.5s; 68 | line-height: 1.6; 69 | font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 70 | Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; 71 | font-size: 15px; 72 | text-rendering: optimizeLegibility; 73 | -webkit-font-smoothing: antialiased; 74 | -moz-osx-font-smoothing: grayscale; 75 | overflow-x: hidden; 76 | } 77 | 78 | code, pre { 79 | font-family: "Roboto Mono", Monaco, courier, monospace; 80 | background-color: #f8f8f8; 81 | -webkit-font-smoothing: initial; 82 | } 83 | -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import './base.css'; 2 | 3 | #app { 4 | max-width: 1280px; 5 | margin: 0 auto; 6 | padding: 2rem; 7 | 8 | font-weight: normal; 9 | } 10 | 11 | a, 12 | .green { 13 | text-decoration: none; 14 | color: hsla(160, 100%, 37%, 1); 15 | transition: 0.4s; 16 | } 17 | 18 | @media (hover: hover) { 19 | a:hover { 20 | background-color: hsla(160, 100%, 37%, 0.2); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/TheObserver.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/components/VueInlineCalendar.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 435 | 436 | 526 | -------------------------------------------------------------------------------- /src/helpers/check-is-in-range.js: -------------------------------------------------------------------------------- 1 | export default function (date, startDate, endDate) { 2 | if (!startDate || !endDate) { 3 | return false; 4 | } 5 | 6 | return date > startDate && date < endDate; 7 | } 8 | -------------------------------------------------------------------------------- /src/helpers/check-is-weekend.js: -------------------------------------------------------------------------------- 1 | export default function (date) { 2 | const day = date.getDay(); 3 | return day === 6 || day === 0; 4 | } 5 | -------------------------------------------------------------------------------- /src/helpers/check-same-day.js: -------------------------------------------------------------------------------- 1 | export default function (date1, date2) { 2 | return ( 3 | date1.getFullYear() === date2.getFullYear() && 4 | date1.getMonth() === date2.getMonth() && 5 | date1.getDate() === date2.getDate() 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import VueInlineCalendar from "@/components/VueInlineCalendar.vue"; 2 | export default VueInlineCalendar; 3 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | 4 | import "./assets/main.css"; 5 | 6 | createApp(App).mount("#app"); 7 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from "node:url"; 2 | import { defineConfig } from "vite"; 3 | import vue from "@vitejs/plugin-vue"; 4 | import { resolve } from "path"; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | base: "/vue-inline-calendar/", 9 | plugins: [vue()], 10 | resolve: { 11 | alias: { 12 | "@": fileURLToPath(new URL("./src", import.meta.url)), 13 | }, 14 | }, 15 | build: { 16 | outDir: resolve(__dirname, "dist-gh"), 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /vite.lib-config.js: -------------------------------------------------------------------------------- 1 | import vue from "@vitejs/plugin-vue"; 2 | import { resolve } from "path"; 3 | import { defineConfig } from "vite"; 4 | 5 | export default defineConfig(() => { 6 | const rootPath = resolve(process.cwd()); 7 | const srcPath = `${rootPath}/src`; 8 | 9 | return { 10 | resolve: { 11 | alias: { 12 | "~": rootPath, 13 | "@": srcPath, 14 | }, 15 | }, 16 | plugins: [vue()], // to process SFC 17 | build: { 18 | lib: { 19 | entry: resolve(__dirname, "src/index.js"), 20 | name: "VueInlineCalendar", 21 | }, 22 | rollupOptions: { 23 | // external modules won't be bundled into your library 24 | external: ["vue"], // not every external has a global 25 | output: { 26 | // disable warning on src/index.ts using both default and named export 27 | exports: "named", 28 | // Provide global variables to use in the UMD build 29 | // for externalized deps (not useful if 'umd' is not in lib.formats) 30 | globals: { 31 | vue: "Vue", 32 | }, 33 | }, 34 | }, 35 | }, 36 | }; 37 | }); 38 | --------------------------------------------------------------------------------