├── .examples └── example.png ├── custom.css ├── package.json ├── CHANGELOG.md ├── MMM-Advent.css ├── README.md └── MMM-Advent.js /.examples/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jopyth/MMM-Advent/HEAD/.examples/example.png -------------------------------------------------------------------------------- /custom.css: -------------------------------------------------------------------------------- 1 | .candle-body { 2 | /* example for a different background color */ 3 | /*background-color: #AB0D30;*/ 4 | 5 | /* example for a background image */ 6 | /*background-image: url("http://images.all-free-download.com/images/graphiclarge/variety_christmas_gift_cartoon_vector_elements_and_153536.jpg"); */ 7 | /*background-position: -104px 66px;*/ 8 | } 9 | 10 | .mark { 11 | /* example for a different mark color */ 12 | /*color: #170069;*/ 13 | 14 | /* example for a different font */ 15 | /*font-family: 'Arial';*/ 16 | /*font-weight: bolder;*/ 17 | /*font-style: italic;*/ 18 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Magic-Mirror-Module-Advent", 3 | "version": "1.0.2", 4 | "description": "A module for displaying timed candles.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/jopyth/MMM-Advent" 8 | }, 9 | "keywords": [ 10 | "magic mirror", 11 | "smart mirror", 12 | "buttons", 13 | "module" 14 | ], 15 | "author": "Joseph Bethge", 16 | "contributors": "git+https://github.com/jopyth/MMM-Advent/graphs/contributors", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "git+https://github.com/jopyth/MMM-Advent/issues" 20 | }, 21 | "homepage": "git+https://github.com/jopyth/MMM-Advent#readme" 22 | } 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # MMM Advent Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [1.0.2] - 2016-12-04 8 | ### Changed 9 | - Configuration options: 10 | - `start` and `end` can be an array of timestamps now 11 | - if they are, multiple candles are created side by side, one for each element in both arrays (length of both arrays should match) 12 | - Example for four red candles, lightning up at each advent sunday (disable animation with `enableAnimation: false,` if the flicker does not look nice): 13 | ```javascript 14 | { 15 | module: "MMM-Advent", 16 | position: "bottom_center", 17 | config: { 18 | marks: 0, 19 | candleColor: "#EE1111", 20 | start: ["2016-11-27 14:00:00", "2016-12-04 14:00:00", "2016-12-11 14:00:00", "2016-12-18 14:00:00"], 21 | end: ["2016-12-24 22:00:00", "2016-12-24 22:00:00", "2016-12-24 22:00:00", "2016-12-24 22:00:00"] 22 | } 23 | }, 24 | ``` 25 | 26 | ## [1.0.1] - 2016-11-22 27 | ### Added 28 | - Configuration options: 29 | - `enableAnimation` - set to `false` to disable flame animation, default is `true` 30 | - `fontCSS` - link to a custom font stylesheet, default is `https://fonts.googleapis.com/css?family=Dosis` 31 | - `fontColor` - the color of the marks on the candle, default is `#000000` (black) 32 | - `candleColor` - the color of the candle, default is `#FFFFFF` (white) 33 | - `font` - the font used (probably depends on the `fontCSS` option, default is `'Dosis', sans-serif` 34 | 35 | ### Changed 36 | - Value are applied through a `css` stylesheet 37 | - Default font is a **bold** version of `Dosis` 38 | - Default candle height is 425 39 | 40 | ### Fixed 41 | - If flame is shown before the start time, it does no longer hover way above the candle 42 | 43 | ### Removed 44 | - Loading of pumpkin font 45 | 46 | ## [1.0.0] - 2016-11-20 47 | ### Initial release of the Advent module. 48 | -------------------------------------------------------------------------------- /MMM-Advent.css: -------------------------------------------------------------------------------- 1 | .candle-container { 2 | height: 400px; 3 | position: relative; 4 | width: 120px; 5 | margin-top: 60px; 6 | } 7 | 8 | .candle-top-shape { 9 | border-radius: 0px 0px 50px 50px; 10 | height: 60px; 11 | width: 100%; 12 | left: 0px; 13 | position: absolute; 14 | background: black; 15 | } 16 | 17 | .candle-body { 18 | height: 340px; 19 | width: 80px; 20 | position: absolute; 21 | background-color: white; 22 | bottom: 0px; 23 | border-radius: 15px; 24 | left: 20px; 25 | } 26 | 27 | .mark { 28 | position: absolute; 29 | font-size: 12px; 30 | line-height: 1em; 31 | color: black; 32 | width: 40px; 33 | text-align: center; 34 | left: 40px; 35 | font-weight: normal; 36 | font-style: normal; 37 | } 38 | 39 | /* source for the flame animation: https://codepen.io/dazulu/pen/fGFyj */ 40 | .flame-container{ 41 | width: 60px; 42 | position: absolute; 43 | left: 30px; 44 | top: 35px; 45 | transform-origin: center bottom; 46 | animation-name: flicker; 47 | animation-duration: 3ms; 48 | animation-delay: 200ms; 49 | animation-timing-function: ease-in; 50 | animation-iteration-count: infinite; 51 | animation-direction: alternate; 52 | } 53 | 54 | .flame{ 55 | bottom:0; 56 | position:absolute; 57 | border-bottom-right-radius: 50%; 58 | border-bottom-left-radius: 50%; 59 | border-top-left-radius: 50%; 60 | transform:rotate(-45deg) scale(1.5,1.5); 61 | } 62 | 63 | .yellow{ 64 | left:15px; 65 | width: 30px; 66 | height: 30px; 67 | background:gold; 68 | box-shadow: 0px 0px 9px 4px gold; 69 | } 70 | 71 | .orange{ 72 | left:10px; 73 | width: 40px; 74 | height: 40px; 75 | background:orange; 76 | box-shadow: 0px 0px 9px 4px orange; 77 | } 78 | 79 | .red{ 80 | left:5px; 81 | width: 50px; 82 | height: 50px; 83 | background:OrangeRed; 84 | box-shadow: 0px 0px 5px 4px OrangeRed; 85 | } 86 | 87 | .white{ 88 | left:15px; 89 | bottom:-4px; 90 | width: 30px; 91 | height: 30px; 92 | background:white; 93 | box-shadow: 0px 0px 9px 4px white; 94 | } 95 | 96 | .circle{ 97 | border-radius: 50%; 98 | position:absolute; 99 | } 100 | 101 | @keyframes flicker{ 102 | 0% {transform: rotate(-1deg);} 103 | 20% {transform: rotate(1deg);} 104 | 40% {transform: rotate(-1deg);} 105 | 60% {transform: rotate(1deg) scaleY(1.02);} 106 | 80% {transform: rotate(-2deg) scaleY(0.96);} 107 | 100% {transform: rotate(1deg);} 108 | } 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magic Mirror Module Advent 2 | 3 | This module for the [MagicMirror](https://github.com/MichMich/MagicMirror) shows a candle, which burns turn towards a specified date (e.g. as an advent candle). 4 | 5 | ![Three example candles](/.examples/example.png?raw=true) 6 | 7 | ## Installation 8 | 9 | 1\. Execute the following commands to install the module: 10 | 11 | ```bash 12 | cd ~/MagicMirror/modules # navigate to module folder 13 | git clone https://github.com/Jopyth/MMM-Advent.git # clone this repository 14 | ``` 15 | 16 | 2\. Then, add the following into the `modules` section of your `config/config.js` file: 17 | 18 | ````javascript 19 | { 20 | module: 'MMM-Advent', 21 | position: 'bottom_center', // This can be any of the regions, best results in center regions 22 | config: { 23 | // See 'Configuration options' for more information. 24 | } 25 | }, 26 | ```` 27 | 28 | 3\. *(Optional)* Customize your candle with configuration options or the `custom.css` stylesheet. 29 | 30 | ## Candle customization 31 | 32 | The rules in the `custom.css` stylesheet will be applied before any configuration options are applied (e.g. `candleColor`), therefore if you want to set e.g. a candle color, you will need to set the corresponding config option to an empty string `""`. 33 | 34 | ## Configuration options 35 | 36 | The following properties can be configured: 37 | 38 | | option | description | 39 | | ------------- | ------------- | 40 | | `updateInterval` | time between updates in ms, default is `10 * 60 * 1000` (10 minutes) | 41 | | `marks` | number of marks on the candle, default is `24` | 42 | | `height` | height of the (whole) candle in pixel, default is `425` | 43 | | `showFlameBeforeStart` | whether to show the flame before the start time, default is `false` | 44 | | `start` | date and time as a string, when the candle should start burning (down), format is `YYYY-MM-DD HH-MM-SS`, default is `"2016-12-01 08:00:00"`, can be an array of timestamps, should match the length of `end`, one candle will be created for each entry | 45 | | `end` | date and time as a string, when the candle should stop burning (down), format is `YYYY-MM-DD HH-MM-SS`, default is `"2016-12-24 22:00:00"`, can be an array of timestamps, should match the length of `start`, one candle will be created for each entry | 46 | | `enableAnimation` | set to `false` to disable flame animation, default is `true` | 47 | | `fontCSS` | link to a custom font stylesheet, default is `https://fonts.googleapis.com/css?family=Dosis` | 48 | | `fontColor` | the color of the marks on the candle, default is `#000000` (black) | 49 | | `candleColor` | the color of the candle, default is `#FFFFFF` (white) | 50 | | `font` | the font used (probably depends on the `fontCSS` option, default is `'Dosis', sans-serif` | 51 | -------------------------------------------------------------------------------- /MMM-Advent.js: -------------------------------------------------------------------------------- 1 | /* global Module */ 2 | 3 | /* Magic Mirror 4 | * Module: Advent 5 | * 6 | * By Joseph Bethge 7 | * MIT Licensed. 8 | */ 9 | 10 | // flame animation based on: https://codepen.io/dazulu/pen/fGFyj 11 | 12 | Module.register("MMM-Advent", { 13 | 14 | // Default module config. 15 | defaults: { 16 | updateInterval: 10 * 60 * 1000, // 10 minutes 17 | marks: 24, 18 | height: 425, // in pixel 19 | showFlameBeforeStart: false, 20 | start: "2016-12-01 08:00:00", // YYYY-MM-DD HH-MM-SS 21 | end: "2016-12-24 22:00:00", // YYYY-MM-DD HH-MM-SS 22 | enableAnimation: true, 23 | fontCSS: "https://fonts.googleapis.com/css?family=Dosis:700", // css of font 24 | fontColor: "#000000", // black 25 | candleColor: "#FFFFFF", // white 26 | font: "'Dosis', sans-serif" 27 | }, 28 | 29 | // Define start sequence. 30 | start: function() { 31 | var self = this; 32 | 33 | Log.info("Starting module: " + this.name); 34 | 35 | this.offset = -0.01; 36 | 37 | var head = document.getElementsByTagName('head')[0]; 38 | 39 | if (this.config.fontCSS) { 40 | var font = document.createElement("link"); 41 | font.rel = "stylesheet"; 42 | font.href = this.config.fontCSS; 43 | head.appendChild(font); 44 | } 45 | 46 | if (this.config.candleColor || this.config.font || this.config.fontColor) { 47 | var configValues = document.createElement("style"); 48 | configValues.type = "text/css"; 49 | configValues.innerHTML = ""; 50 | if (this.config.candleColor) { 51 | configValues.innerHTML += ".candle-body { background-color: " + this.config.candleColor + "; }\n"; 52 | } 53 | if (this.config.font) { 54 | configValues.innerHTML += ".mark { font-family: " + this.config.font + "; }\n"; 55 | } 56 | if (this.config.fontColor) { 57 | configValues.innerHTML += ".mark { color: " + this.config.fontColor + "; }\n"; 58 | } 59 | head.appendChild(configValues); 60 | } 61 | 62 | if (this.config.updateInterval < 10 * 1000) { 63 | // 10 seconds minimum update interval 64 | this.config.updateInterval = 10 * 1000; 65 | } 66 | setInterval(function() { 67 | self.updateDom(); 68 | }, this.config.updateInterval); 69 | }, 70 | 71 | // Define required styles 72 | getStyles: function () { 73 | return ["MMM-Advent.css", "custom.css"]; 74 | }, 75 | 76 | getCandleDom(start, end) { 77 | var now = new Date(); 78 | 79 | this.offset = (now - start) / (end - start); 80 | 81 | if (this.offset >= 1.0) { 82 | this.offset = 1.0; 83 | } 84 | if (this.offset <= -0.01) { 85 | this.offset = -0.01; 86 | } 87 | 88 | // define magic numbers 89 | var flameSpace = 35; 90 | var candleStart = 62; 91 | var candleEnd = 12; // padding of numbers towards bottom end 92 | var candleTopSpace = 60; 93 | 94 | var wrapper = document.createElement("div"); 95 | wrapper.className = "candle-container"; 96 | wrapper.style.height = (this.config.height + 1) + "px"; 97 | 98 | var candleBody = document.createElement("div"); 99 | candleBody.className = "candle-body"; 100 | candleBody.style.height = (this.config.height - candleTopSpace + 1) + "px"; 101 | wrapper.appendChild(candleBody); 102 | 103 | for (var i = 0; i < this.config.marks; i++) { 104 | var mark = document.createElement("span"); 105 | mark.className = "mark"; 106 | mark.innerHTML = i + 1; 107 | mark.style.top = candleStart + (i / (this.config.marks - 1)) * (this.config.height - (candleStart + candleEnd)) + "px"; 108 | wrapper.appendChild(mark); 109 | } 110 | 111 | var candleTop = document.createElement("div"); 112 | candleTop.className = "candle-top-shape"; 113 | wrapper.appendChild(candleTop); 114 | candleTop.style.height = (candleTopSpace + Math.round(this.offset * (this.config.height - candleTopSpace))) + "px"; 115 | 116 | if (this.config.showFlameBeforeStart || this.offset >= 0.0) { 117 | // flame on 118 | var flameContainer = document.createElement("div"); 119 | flameContainer.className = "flame-container"; 120 | wrapper.appendChild(flameContainer); 121 | 122 | if (!this.config.enableAnimation) { 123 | flameContainer.style.animationName = "none"; 124 | } 125 | 126 | var components = [ 127 | "red flame", 128 | "orange flame", 129 | "yellow flame", 130 | "white flame" 131 | ]; 132 | 133 | for (var i = 0; i < components.length; i++) { 134 | var element = document.createElement("div"); 135 | element.className = components[i]; 136 | flameContainer.appendChild(element); 137 | } 138 | 139 | flameContainer.style.top = (flameSpace + Math.round(this.offset * (this.config.height - candleTopSpace))) + "px"; 140 | } 141 | 142 | return wrapper; 143 | }, 144 | 145 | // Override dom generator. 146 | getDom: function() { 147 | var startConfig = this.config.start; 148 | var endConfig = this.config.end; 149 | 150 | if (Array.isArray(startConfig) && Array.isArray(endConfig)) 151 | { 152 | var table = document.createElement("table"); 153 | var tr = document.createElement("tr"); 154 | 155 | for (var i = 0; i < startConfig.length && i < endConfig.length; i++) 156 | { 157 | var td = document.createElement("td"); 158 | 159 | var start = new Date(startConfig[i]); 160 | var end = new Date(endConfig[i]); 161 | 162 | td.appendChild(this.getCandleDom(start, end)); 163 | tr.appendChild(td); 164 | } 165 | 166 | table.appendChild(tr); 167 | return table; 168 | } 169 | else 170 | { 171 | var start = new Date(startConfig); 172 | var end = new Date(endConfig); 173 | 174 | return this.getCandleDom(start, end); 175 | } 176 | } 177 | }); 178 | --------------------------------------------------------------------------------