├── .babelrc ├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── README.md ├── assets └── vue-digital-clock.gif ├── example ├── App.vue ├── index.html └── main.js ├── package.json ├── rollup.config.js ├── src ├── Clock.spec.js ├── Clock.vue └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env"] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | 4 | # Editor files 5 | /.idea 6 | *.suo 7 | *.ntvs* 8 | *.njsproj 9 | *.sln 10 | 11 | # Log files 12 | *.log 13 | reports 14 | coverage 15 | 16 | # Build 17 | dist 18 | .cache 19 | 20 | # Docs 21 | _book 22 | .tmp 23 | tmp* 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2.0.0 / 02-01-2019 2 | 3 | - Add twelveHour prop 4 | - Distribute JS files, rather than a Vue SFC 5 | 6 | # 1.5.0 / 03-30-2017 7 | 8 | - Add displaySeconds prop 9 | 10 | # 1.4.0 / 03-30-2017 11 | 12 | - Add blink prop 13 | 14 | # 1.3.1 / 03-29-2017 15 | 16 | - Remove babel from project 17 | 18 | # 1.3.0 / 03-29-2017 19 | 20 | - Remove ES6 from Clock.vue 21 | 22 | # 1.2.0 / 03-29-2017 23 | 24 | - Remove babel-runtime plugin 25 | 26 | # 1.1.0 / 03-05-2017 27 | 28 | - Add destroyed() method to clear interval when component is destroyed 29 | 30 | # 1.0.2 / 03-02-2017 31 | 32 | - Add keywords to package.json 33 | - Update image URL 34 | - Add installation guide to README 35 | 36 | # 1.0.1 / 03-02-2017 37 | 38 | - Update image URL in README 39 | 40 | # 1.0.0 / 03-01-2017 41 | 42 | - Initial release. 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-digital-clock 2 | 3 | > A digital clock component built with Vue.js 4 | 5 | ## Installation 6 | 7 | With NPM: 8 | 9 | ```shell 10 | npm install --save vue-digital-clock 11 | ``` 12 | 13 | With Yarn 14 | 15 | ```shell 16 | yarn add vue-digital-clock 17 | ``` 18 | 19 | And import it into your project 20 | 21 | ```javascript 22 | import DigitalClock from "vue-digital-clock"; 23 | ``` 24 | 25 | ## Props 26 | 27 | | Prop | Type | Usage | 28 | | ------ | ---- | ------ | 29 | | blink | Boolean | Set as true to have the colon blink with the seconds| 30 | | displaySeconds | Boolean | Set as true to display seconds| 31 | | twelveHour | Boolean | Set as true to display times with AM/PM| 32 | 33 | 34 | ## Example 35 | 36 | ```vue 37 | 40 | 41 | 50 | ``` 51 | 52 | ## Screenshot 53 | 54 | ![vue-digital-clock screenshot](https://raw.githubusercontent.com/eddyerburgh/vue-digital-clock/master/assets/vue-digital-clock.gif) 55 | -------------------------------------------------------------------------------- /assets/vue-digital-clock.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eddyerburgh/vue-digital-clock/5c72db5a9e1243430ae04b9ff7536a39cf9e8cad/assets/vue-digital-clock.gif -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-digital-clock example 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | 4 | /* eslint-disable no-new */ 5 | new Vue({ 6 | el: "#app", 7 | render: h => h(App), 8 | components: { App } 9 | }); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-digital-clock", 3 | "version": "2.0.0", 4 | "description": "A Vue digital clock component, for use out the box", 5 | "author": "Edd Yerburgh ", 6 | "main": "./dist/cjs/Clock.js", 7 | "module": "./dist/es/Clock.js", 8 | "files": [ 9 | "dist/**/*.js" 10 | ], 11 | "scripts": { 12 | "build": "rollup -c", 13 | "dev": "parcel example/index.html", 14 | "format": "prettier --write \"{,!(.cache|dist)/**/}/*.{md,vue,js,json}\"", 15 | "format:check": "prettier --check \"{,!(.cache|dist)/**/}/*.{md,vue,js,json}\"", 16 | "prepare": "npm run build", 17 | "test:unit": "jest", 18 | "test": "npm run format:check && npm run test:unit" 19 | }, 20 | "keywords": [ 21 | "vue clock", 22 | "vue2 clock", 23 | "vuejs clock", 24 | "vue.js clock", 25 | "vue js clock", 26 | "vue clock component", 27 | "vue2 clock component", 28 | "vuejs clock component", 29 | "vue.js clock component", 30 | "vue js clock component", 31 | "vue digital clock", 32 | "vue2 digital clock", 33 | "vuejs digital clock", 34 | "vue.js digital clock", 35 | "vue js digital clock", 36 | "vue digital clock component", 37 | "vue2 digital clock component", 38 | "vuejs digital clock component", 39 | "vue.js digital clock component", 40 | "vue js digital clock component" 41 | ], 42 | "peerDependencies": { 43 | "vue": "^2.x" 44 | }, 45 | "devDependencies": { 46 | "@babel/core": "^7.2.2", 47 | "@babel/preset-env": "^7.3.1", 48 | "avoriaz": "^1.8.2", 49 | "babel-core": "^7.0.0-bridge.0", 50 | "babel-jest": "^24.0.0", 51 | "jest": "^24.0.0", 52 | "parcel": "^1.11.0", 53 | "prettier": "^1.16.3", 54 | "rollup": "^1.1.2", 55 | "rollup-plugin-buble": "^0.19.6", 56 | "rollup-plugin-commonjs": "^9.2.0", 57 | "rollup-plugin-node-resolve": "^4.0.0", 58 | "rollup-plugin-vue": "^4.6.2", 59 | "sinon": "^7.2.3", 60 | "vue": "^2.5.22", 61 | "vue-hot-reload-api": "^2.3.1", 62 | "vue-jest": "^3.0.2", 63 | "vue-template-compiler": "^2.5.22" 64 | }, 65 | "engines": { 66 | "node": ">= 4.0.0", 67 | "npm": ">= 3.0.0" 68 | }, 69 | "repository": { 70 | "type": "git", 71 | "url": "git+ssh://git@github.com/eddyerburgh/vue-digital-clock.git" 72 | }, 73 | "bugs": { 74 | "url": "https://github.com/eddyerburgh/vue-digital-clock/issues" 75 | }, 76 | "homepage": "https://github.com/eddyerburgh/vue-digital-clock#readme", 77 | "jest": { 78 | "transform": { 79 | "^.+\\.js$": "babel-jest", 80 | "^.+\\.vue$": "vue-jest" 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import vue from 'rollup-plugin-vue' 2 | import buble from 'rollup-plugin-buble'; 3 | import resolve from 'rollup-plugin-node-resolve'; 4 | import commonjs from 'rollup-plugin-commonjs'; 5 | 6 | export default { 7 | input: 'src/index.js', 8 | plugins: [ 9 | commonjs(), 10 | resolve(), 11 | vue(), 12 | buble() 13 | ], 14 | output: [ 15 | { 16 | file: 'dist/cjs/Clock.js', 17 | format: 'cjs', 18 | exports: 'default' 19 | }, 20 | { 21 | file: 'dist/es/Clock.js', 22 | format: 'es' 23 | }, 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /src/Clock.spec.js: -------------------------------------------------------------------------------- 1 | import { mount } from "avoriaz"; 2 | import sinon from "sinon"; 3 | import Clock from "./Clock.vue"; 4 | 5 | const seconds = 1000; 6 | const minutes = 60 * seconds; 7 | const hours = 60 * minutes; 8 | 9 | describe("Clock.vue", () => { 10 | let clock; 11 | 12 | beforeEach(() => { 13 | clock = sinon.useFakeTimers(new Date(2016, 2, 15).getTime()); 14 | }); 15 | 16 | it("renders a time element", () => { 17 | expect(mount(Clock).is("time")).toBe(true); 18 | }); 19 | 20 | it("renders current hour in 24 hour format", () => { 21 | clock.tick(21 * hours); 22 | const wrapper = mount(Clock); 23 | expect(wrapper.find(".clock__hour")[0].text()).toContain("21"); 24 | }); 25 | 26 | it("renders current hour with padded 0", () => { 27 | clock.tick(3 * hours); 28 | const wrapper = mount(Clock); 29 | expect(wrapper.find(".clock__hour")[0].text()).toContain("03"); 30 | }); 31 | 32 | it("Updates hours when changed", () => { 33 | clock.tick(13 * hours); 34 | const wrapper = mount(Clock); 35 | expect(wrapper.find(".clock__hour")[0].text()).toContain("13"); 36 | clock.tick(3 * hours); 37 | wrapper.update(); 38 | expect(wrapper.find(".clock__hour")[0].text()).toContain("16"); 39 | }); 40 | 41 | it("renders current minutes", () => { 42 | clock.tick(30 * minutes); 43 | const wrapper = mount(Clock); 44 | expect(wrapper.find(".clock__minutes")[0].text()).toContain("30"); 45 | }); 46 | 47 | it("renders current minutes with padded 0", () => { 48 | clock.tick(3 * minutes); 49 | const wrapper = mount(Clock); 50 | expect(wrapper.find(".clock__minutes")[0].text()).toContain("03"); 51 | }); 52 | 53 | it("updates minutes when changed", () => { 54 | clock.tick(3 * minutes); 55 | const wrapper = mount(Clock); 56 | expect(wrapper.find(".clock__minutes")[0].text()).toContain("03"); 57 | clock.tick(3 * minutes); 58 | wrapper.update(); 59 | expect(wrapper.find(".clock__minutes")[0].text()).toContain("06"); 60 | }); 61 | 62 | it("renders current seconds with padded 0 if props displaySeconds is true", () => { 63 | clock.tick(5 * seconds); 64 | const wrapper = mount(Clock, { propsData: { displaySeconds: true } }); 65 | expect(wrapper.find(".clock__seconds")[0].text()).toContain("05"); 66 | }); 67 | 68 | it("updates seconds when changed if props displaySeconds is true", () => { 69 | clock.tick(3 * seconds); 70 | const wrapper = mount(Clock, { propsData: { displaySeconds: true } }); 71 | expect(wrapper.find(".clock__seconds")[0].text()).toContain("03"); 72 | clock.tick(2 * seconds); 73 | wrapper.update(); 74 | expect(wrapper.find(".clock__seconds")[0].text()).toContain("05"); 75 | }); 76 | 77 | it("does not render seconds with if props displaySeconds is undefined", () => { 78 | clock.tick(5 * seconds); 79 | const wrapper = mount(Clock); 80 | expect(wrapper.find(".clock__seconds").length).toBe(0); 81 | }); 82 | 83 | it("displays colon when not passed blink prop and seconds are even", () => { 84 | clock.tick(seconds * 2); 85 | const wrapper = mount(Clock); 86 | expect(wrapper.text()).toContain(":"); 87 | }); 88 | 89 | it("displays colon when not passed blink prop and seconds are odd", () => { 90 | clock.tick(seconds * 3); 91 | const wrapper = mount(Clock); 92 | expect(wrapper.text()).toContain(":"); 93 | }); 94 | 95 | it("displays colon when passed blink prop and seconds are even", () => { 96 | clock.tick(seconds * 2); 97 | const wrapper = mount(Clock, { propsData: { blink: true } }); 98 | expect(wrapper.text()).toContain(":"); 99 | }); 100 | 101 | it("does not display colon when passed blink prop and seconds are even", () => { 102 | clock.tick(seconds * 3); 103 | const wrapper = mount(Clock, { propsData: { blink: true } }); 104 | expect(wrapper.find(".clock__colon")[0].html()).toContain( 105 | '' 106 | ); 107 | }); 108 | 109 | it("displays second colon when passed blink and displaySeconds props and seconds are even", () => { 110 | clock.tick(seconds * 2); 111 | const wrapper = mount(Clock, { 112 | propsData: { blink: true, displaySeconds: true } 113 | }); 114 | expect(wrapper.find("span")[3].text()).toContain(":"); 115 | }); 116 | 117 | it("does not display second colon when passed blink and displaySeconds props and seconds are odd", () => { 118 | clock.tick(seconds * 3); 119 | const wrapper = mount(Clock, { 120 | propsData: { blink: true, displaySeconds: true } 121 | }); 122 | expect(wrapper.find(".clock__colon")[1].html()).toContain( 123 | '' 124 | ); 125 | }); 126 | 127 | it("does not display colon when passed blink prop and seconds are even", () => { 128 | clock.tick(seconds * 3); 129 | const wrapper = mount(Clock, { propsData: { blink: true } }); 130 | expect(wrapper.find(".clock__colon")[0].html()).toContain( 131 | '' 132 | ); 133 | }); 134 | 135 | it("Calls clear input with vm.ticker when component is destroyed", () => { 136 | const stub = jest.fn(); 137 | window.clearInterval = stub; 138 | const wrapper = mount(Clock); 139 | const ticker = wrapper.vm.ticker; 140 | wrapper.destroy(); 141 | expect(stub).toHaveBeenCalledWith(ticker); 142 | }); 143 | 144 | it("should not display second colon by default", () => { 145 | const wrapper = mount(Clock); 146 | expect((wrapper.text().match(/:/g) || []).length).toBe(1); 147 | }); 148 | 149 | it('renders an ante-meridiem time with "am" when in twelveHour mode', () => { 150 | clock.tick(7 * hours); 151 | const wrapper = mount(Clock, { propsData: { twelveHour: true } }); 152 | expect(wrapper.find(".clock__hour")[0].text()).toContain("07"); 153 | expect(wrapper.find(".clock__ampm")[0].text()).toContain("am"); 154 | }); 155 | 156 | it('renders a post-meridiem time with "pm" when in twelveHour mode', () => { 157 | clock.tick(21 * hours); 158 | const wrapper = mount(Clock, { propsData: { twelveHour: true } }); 159 | expect(wrapper.find(".clock__hour")[0].text()).toContain("09"); 160 | expect(wrapper.find(".clock__ampm")[0].text()).toContain("pm"); 161 | }); 162 | }); 163 | -------------------------------------------------------------------------------- /src/Clock.vue: -------------------------------------------------------------------------------- 1 | 27 | 79 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Clock.vue"; 2 | --------------------------------------------------------------------------------