├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── doc └── tw.md ├── index.js ├── jest.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── RecordIt.svg │ ├── baseline-remove_circle-24px.svg │ ├── logo.png │ └── round-warning-24px.svg ├── components │ ├── MonthCalendar.vue │ └── YearCalendar.vue └── main.js ├── tests └── unit │ ├── .eslintrc.js │ ├── __snapshots__ │ └── month.spec.js.snap │ └── month.spec.js └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | English | [繁體中文](./doc/tw.md) 2 | ![](https://i.imgur.com/7rinsub.png) 3 | 4 |

5 | Versions Downloads License 6 |

7 | 8 | > There is no full year (12 months on a page) calendar right now, the Vue-material-year-calendar is designed to solve this problem. 9 | 10 | * 🔥 12 Months on a page 11 | * 🌈 Material style 12 | * 🕒 depend on [dayjs](https://github.com/iamkun/dayjs) 13 | * 🍀 by Vue.js 14 | 15 | 16 | ### [Simple Live Demo](https://nono1526.github.io/vue-material-year-calendar) 17 | 18 | ## Basic usage 19 | 20 | ![Basic_demo](https://media.giphy.com/media/LXQxkdBrhmVzOEMbQf/giphy.gif) 21 | ## Draggable 22 | ![demo](https://media.giphy.com/media/BZkjvL89E4dDvUikAl/giphy.gif) 23 | ## Classification 24 | ![Classification](https://i.imgur.com/3KB3RK7.png)--- 25 | ## Getting Started 26 | 27 | ### 📚 Installation 28 | 29 | ```console 30 | npm install vue-material-year-calendar --save 31 | ``` 32 | 33 | ### 📚 Example 34 | ```vue 35 | 44 | 45 | 69 | 70 | 88 | ``` 89 | 90 | 91 | ## 📚 props 92 | ### v-model 93 | * Type: `String` | `Number` 94 | * Required: `true` 95 | 96 | The year to be display. 97 | 98 | ### activeDates.sync 99 | * Type: `Array of objects` 100 | * Required: `true` 101 | * Default: `[]` 102 | Your selected dates. 103 | 104 | If you set `className` attributes, you can customize it style in CSS. 105 | 106 | ex: 107 | ```javascript 108 | [ 109 | { date: '2019-02-13' }, 110 | { date: '2019-02-14', className: 'red' }, 111 | { date: '2019-02-15', className: 'blue' }, 112 | { date: '2019-02-16', className: 'your_customized_classname' } 113 | ], 114 | ``` 115 | 116 | ### prefixClass 117 | * Type: `String` 118 | * Default: `calendar--active` 119 | * Required: `true` 120 | 121 | A wrapper classname for customized css. Set `prefixClass`'s value, then use it value as a class wrapper in CSS. 122 | 123 | ex: 124 | 125 | ```vue 126 | 132 | 133 | 152 | ``` 153 | 154 | ### activeClass 155 | 156 | * Type: `String` (default class: info or warning ) 157 | * Default: `''`(empty string) 158 | 159 | The classname you want to toggle. For example, set `activeClass` to `my_red` first. Then you click a date on calendar, the date will be add/remove with `my_red` class. 160 | ![](https://i.imgur.com/Lmp3RG1.png) 161 | 162 | 163 | ### lang 164 | * Type: `String` 165 | * Default: `en` 166 | 167 | Choose language to displayed. 168 | 169 | `en`: English, `tw`: 繁體中文, `pt`: Português, `de`: Deutsch, `pl`: Polish, `ru`: Русский 170 | 171 | 172 | 173 | ### showYearSelector 174 | * Type: `Boolean` 175 | * Default: `true` 176 | 177 | Show or hide the years selector on top of the calendar. 178 | 179 | ex: 180 | ```javascript 181 | :showYearSelector="false" 182 | ``` 183 | 184 | 185 | ### hideSunday 186 | * Type: `Boolean` 187 | * Default: `false` 188 | 189 | Hide or show all sundays in the calendar. 190 | 191 | ex: 192 | ```javascript 193 | :hideSunday="true" 194 | ``` 195 | 196 | 197 | 198 | ### hideWeekend 199 | * Type: `Boolean` 200 | * Default: `false` 201 | 202 | Hide or show all weekends (saturdays and sundays) in the calendar. 203 | 204 | ex: 205 | ```javascript 206 | :hideWeekend="true" 207 | ``` 208 | 209 | 210 | 211 | ## 📚 event 212 | ### @toggleDate 213 | * Type: `function` 214 | 215 | Function will be called when you select/unselect a date. 216 | 217 | ex: 218 | 219 | ```vue 220 | 225 | 226 | 234 | ``` 235 | 236 | 237 | ### @monthClick 238 | * $event: `{ year: 2021, month: 1, monthTitle: 'January' }` 239 | 240 | 241 | Trigger when user click month title. 242 | 243 | 244 | 245 | ex: 246 | 247 | ```vue 248 | 253 | 254 | 262 | ``` -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /doc/tw.md: -------------------------------------------------------------------------------- 1 | [English](../README.md) | 繁體中文 2 | # Vue Material Year Calendar 3 |

4 | Versions Downloads License 5 |

6 | 7 | > 目前2019年3月為止,市場上還沒有能一次顯示12個月份的月曆元件。 vue-material-year-calendar 來解決此問題。 8 | 9 | * 🔥 一次顯示12個月份 10 | * 🌈 Material 風格 11 | * 🕒 依賴容量小的 [dayjs](https://github.com/iamkun/dayjs) 12 | * 🍀 在 Vue.js 2 下使用 13 | 14 | 15 | ### [Simple Live Demo](https://nono1526.github.io/vue-material-year-calendar) 16 | 17 | ## 基本用法 18 | 19 | ![Basic_demo](https://media.giphy.com/media/LXQxkdBrhmVzOEMbQf/giphy.gif) 20 | 21 | ## 支援滑鼠拖拉 22 | ![demo](https://media.giphy.com/media/BZkjvL89E4dDvUikAl/giphy.gif) 23 | ## 分類 24 | ![Classification](https://i.imgur.com/3KB3RK7.png)--- 25 | ## Getting Started 26 | --- 27 | ## 快速開始 28 | 29 | ### 📚 安裝 30 | 31 | ```console 32 | npm install vue-material-year-calendar --save 33 | ``` 34 | 35 | ### 📚 範例 36 | ```vue 37 | 46 | 47 | 71 | 72 | 90 | 91 | ``` 92 | 93 | 94 | ## 📚 props 95 | ### v-model 96 | * Type: `String` | `Number` 97 | * Required: `true` 98 | 99 | 要顯示的年份。 100 | 101 | ### activeDates.sync 102 | * Type: `Array of objects` 103 | * Required: `true` 104 | * Default: `[]` 105 | 106 | 使用者選擇的日期。 107 | 108 | 若有設定 `className` 的屬性,則可以在CSS裡控制該日期的樣式。 109 | 110 | ex: 111 | ```javascript 112 | [ 113 | { date: '2019-02-13' }, 114 | { date: '2019-02-14', className: 'red' }, 115 | { date: '2019-02-15', className: 'blue' }, 116 | { date: '2019-02-16', className: 'your_customized_classname' } 117 | ], 118 | ``` 119 | 120 | ### prefixClass 121 | * Type: `String` 122 | * Default: `calendar--active` 123 | * Required: `true` 124 | 125 | 包在外層的CSS calss。 126 | 127 | 例如你設定 `prefixClass` 為`your_customized_wrapper_class`,則你可以在CSS裡面,透過`your_customized_wrapper_class`來做外層的CSS包覆。 128 | 129 | ex: 130 | 131 | ```vue 132 | 138 | 139 | 158 | ``` 159 | 160 | 161 | ### activeClass 162 | 163 | * Type: `String` (default class: info or warning ) 164 | * Default: `''`(empty string) 165 | 166 | 點擊日期時,會切換的 class name. 例如當你指定 `activeClass` 為 `my_red`後,點擊某個日期,該日期就會新增/移除對應的 class name. 167 | 168 | ![](https://i.imgur.com/Lmp3RG1.png) 169 | 170 | 171 | ### lang 172 | * Type: `String` 173 | * Default: `en` 174 | 175 | 選擇語系。預設為英文。 176 | 177 | `en`: English, `tw`: 繁體中文, `pt`: Português, `de`: Deutsch, `pl`: Polish, `ru`: Русский 178 | 179 | ### showYearSelector 180 | * Type: `Boolean` 181 | * Default: true 182 | 183 | 是否顯示選擇年份的 Bar 184 | 185 | ex: 186 | ```javascript 187 | :showYearSelector="false" 188 | ``` 189 | 190 | 191 | ## 📚 事件 192 | ### @toggleDate 193 | * Type: `function` 194 | 195 | 點選/取消日期時,會觸發這個函數。 196 | 197 | ex: 198 | 199 | ```vue 200 | 205 | 206 | 214 | ``` 215 | 216 | 217 | ### @monthClickEvent 218 | * $event: `{ year: 2021, month: 1, monthTitle: 'January' }` 219 | 220 | 點選月份時,觸發這個函數。 221 | 222 | ex: 223 | 224 | ```vue 225 | 230 | 231 | 239 | ``` -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import YearCalendar from './src/components/YearCalendar.vue' 2 | export default YearCalendar 3 | if (typeof window !== 'undefined' && window.Vue) { 4 | window.Vue.component('year-calendar', YearCalendar) 5 | } 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: [ 3 | 'js', 4 | 'jsx', 5 | 'json', 6 | 'vue' 7 | ], 8 | transform: { 9 | '^.+\\.vue$': 'vue-jest', 10 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 11 | '^.+\\.jsx?$': 'babel-jest' 12 | }, 13 | moduleNameMapper: { 14 | '^@/(.*)$': '/src/$1' 15 | }, 16 | snapshotSerializers: [ 17 | 'jest-serializer-vue' 18 | ], 19 | testMatch: [ 20 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 21 | ], 22 | testURL: 'http://localhost/' 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-material-year-calendar", 3 | "main": "index.js", 4 | "version": "1.2.6", 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "test:unit": "jest --clearCache && vue-cli-service test:unit" 10 | }, 11 | "dependencies": { 12 | "dayjs": "^1.8.13", 13 | "gh-pages": "^2.0.1", 14 | "stylus": "^0.54.5", 15 | "stylus-loader": "^3.0.2", 16 | "vue": "^2.5.17" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "^3.0.1", 20 | "@vue/cli-plugin-eslint": "^3.0.1", 21 | "@vue/cli-plugin-unit-jest": "^3.0.1", 22 | "@vue/cli-service": "^3.0.1", 23 | "@vue/eslint-config-standard": "^4.0.0", 24 | "@vue/test-utils": "^1.0.0-beta.20", 25 | "babel-core": "7.0.0-bridge.0", 26 | "babel-eslint": "^10.0.1", 27 | "babel-jest": "^23.6.0", 28 | "eslint": "^5.8.0", 29 | "eslint-plugin-vue": "^5.0.0-0", 30 | "vue-template-compiler": "^2.5.17" 31 | }, 32 | "description": "A full 12-Month view calendar made by vue.js", 33 | "repositories": [ 34 | { 35 | "type": "git", 36 | "url": "https://github.com/nono1526/vue-material-year-calendar" 37 | } 38 | ], 39 | "license": "WTFPL" 40 | } 41 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nono1526/vue-material-year-calendar/988a63020986eaa5dabfa30b301eeeb6af637283/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-material-year-calendar 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 121 | 122 | 147 | -------------------------------------------------------------------------------- /src/assets/RecordIt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/baseline-remove_circle-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nono1526/vue-material-year-calendar/988a63020986eaa5dabfa30b301eeeb6af637283/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/round-warning-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/MonthCalendar.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 197 | 198 | 294 | -------------------------------------------------------------------------------- /src/components/YearCalendar.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 201 | 202 | 252 | 266 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/unit/__snapshots__/month.spec.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`MonthCalendar renders array of objects correctly 1`] = ` 4 |
7 |
10 |
13 | 一月 14 |
15 | 16 |
19 |
23 | 一 24 |
25 |
29 | 二 30 |
31 |
35 | 三 36 |
37 |
41 | 四 42 |
43 |
47 | 五 48 |
49 |
53 | 六 54 |
55 |
59 | 日 60 |
61 | 62 |
65 |
68 | 69 |
70 |
71 |
74 |
77 | 1 78 |
79 |
80 |
83 |
86 | 2 87 |
88 |
89 |
92 |
95 | 3 96 |
97 |
98 |
101 |
104 | 4 105 |
106 |
107 |
110 |
113 | 5 114 |
115 |
116 |
119 |
122 | 6 123 |
124 |
125 |
128 |
131 | 7 132 |
133 |
134 |
137 |
140 | 8 141 |
142 |
143 |
146 |
149 | 9 150 |
151 |
152 |
155 |
158 | 10 159 |
160 |
161 |
164 |
167 | 11 168 |
169 |
170 |
173 |
176 | 12 177 |
178 |
179 |
182 |
185 | 13 186 |
187 |
188 |
191 |
194 | 14 195 |
196 |
197 |
200 |
203 | 15 204 |
205 |
206 |
209 |
212 | 16 213 |
214 |
215 |
218 |
221 | 17 222 |
223 |
224 |
227 |
230 | 18 231 |
232 |
233 |
236 |
239 | 19 240 |
241 |
242 |
245 |
248 | 20 249 |
250 |
251 |
254 |
257 | 21 258 |
259 |
260 |
263 |
266 | 22 267 |
268 |
269 |
272 |
275 | 23 276 |
277 |
278 |
281 |
284 | 24 285 |
286 |
287 |
290 |
293 | 25 294 |
295 |
296 |
299 |
302 | 26 303 |
304 |
305 |
308 |
311 | 27 312 |
313 |
314 |
317 |
320 | 28 321 |
322 |
323 |
326 |
329 | 29 330 |
331 |
332 |
335 |
338 | 30 339 |
340 |
341 |
344 |
347 | 31 348 |
349 |
350 |
353 |
356 | 1 357 |
358 |
359 |
362 |
365 | 2 366 |
367 |
368 |
371 |
374 | 3 375 |
376 |
377 |
378 |
379 |
380 | `; 381 | 382 | exports[`MonthCalendar renders array of strings correctly 1`] = ` 383 |
386 |
389 |
392 | 一月 393 |
394 | 395 |
398 |
402 | 一 403 |
404 |
408 | 二 409 |
410 |
414 | 三 415 |
416 |
420 | 四 421 |
422 |
426 | 五 427 |
428 |
432 | 六 433 |
434 |
438 | 日 439 |
440 | 441 |
444 |
447 | 448 |
449 |
450 |
453 |
456 | 1 457 |
458 |
459 |
462 |
465 | 2 466 |
467 |
468 |
471 |
474 | 3 475 |
476 |
477 |
480 |
483 | 4 484 |
485 |
486 |
489 |
492 | 5 493 |
494 |
495 |
498 |
501 | 6 502 |
503 |
504 |
507 |
510 | 7 511 |
512 |
513 |
516 |
519 | 8 520 |
521 |
522 |
525 |
528 | 9 529 |
530 |
531 |
534 |
537 | 10 538 |
539 |
540 |
543 |
546 | 11 547 |
548 |
549 |
552 |
555 | 12 556 |
557 |
558 |
561 |
564 | 13 565 |
566 |
567 |
570 |
573 | 14 574 |
575 |
576 |
579 |
582 | 15 583 |
584 |
585 |
588 |
591 | 16 592 |
593 |
594 |
597 |
600 | 17 601 |
602 |
603 |
606 |
609 | 18 610 |
611 |
612 |
615 |
618 | 19 619 |
620 |
621 |
624 |
627 | 20 628 |
629 |
630 |
633 |
636 | 21 637 |
638 |
639 |
642 |
645 | 22 646 |
647 |
648 |
651 |
654 | 23 655 |
656 |
657 |
660 |
663 | 24 664 |
665 |
666 |
669 |
672 | 25 673 |
674 |
675 |
678 |
681 | 26 682 |
683 |
684 |
687 |
690 | 27 691 |
692 |
693 |
696 |
699 | 28 700 |
701 |
702 |
705 |
708 | 29 709 |
710 |
711 |
714 |
717 | 30 718 |
719 |
720 |
723 |
726 | 31 727 |
728 |
729 |
732 |
735 | 1 736 |
737 |
738 |
741 |
744 | 2 745 |
746 |
747 |
750 |
753 | 3 754 |
755 |
756 |
757 |
758 |
759 | `; 760 | -------------------------------------------------------------------------------- /tests/unit/month.spec.js: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import MonthCalendar from '@/components/MonthCalendar' 3 | describe('MonthCalendar', () => { 4 | const wrapper = mount(MonthCalendar, { 5 | propsData: { 6 | month: 1, 7 | lang: 'tw', 8 | year: 2019 9 | } 10 | }) 11 | it('renders title', () => { 12 | expect(wrapper.html()).toContain('
一月
') 13 | }) 14 | 15 | it('render custom active class', () => { 16 | wrapper.setProps({ 17 | activeDates: [{ 18 | date: '2019-01-01', className: 'my-custom' 19 | }] 20 | }) 21 | const date = wrapper.find('.day:not(.calendar__day--otherMonth)') 22 | expect(date.classes()).toContain('my-custom') 23 | wrapper.setProps({ 24 | activeDates: [] 25 | }) 26 | const noneDate = wrapper.find('.my-custom') 27 | expect(noneDate.exists()).toBe(false) 28 | }) 29 | 30 | it('renders array of strings correctly', () => { 31 | wrapper.setProps({ 32 | activeDates: ['2019-01-01', '2019-01-20'] 33 | }) 34 | expect(wrapper.element).toMatchSnapshot() 35 | }) 36 | 37 | it('renders array of objects correctly', () => { 38 | wrapper.setProps({ 39 | activeDates: [ 40 | { date: '2019-01-13', className: '' }, 41 | { date: '2019-01-14', className: 'info' }, 42 | { date: '2019-01-15', className: 'warning' }] 43 | }) 44 | expect(wrapper.element).toMatchSnapshot() 45 | }) 46 | 47 | it('should toggle month click event when click month', async () => { 48 | await wrapper.find('.calendar__title').trigger('click') 49 | expect(wrapper.emitted().monthClickEvent).toEqual([[{ 50 | monthTitle: '一月', 51 | month: 1, 52 | year: 2019 53 | }]]) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | baseUrl: './' 3 | } 4 | --------------------------------------------------------------------------------