diff --git a/_includes/timings.html b/_includes/timings.html
new file mode 100644
index 000000000..605d6f5df
--- /dev/null
+++ b/_includes/timings.html
@@ -0,0 +1,28 @@
+{% assign thisRecipe = include.recipe %}
+
+ {% if thisRecipe.preptime %}
+
+
+ Prep
+
+
+
+ {% endif %}
+ {% if thisRecipe.cooktime %}
+
+
+ Cook
+
+
+
+ {% endif %}
+ {% if thisRecipe.totaltime %}
+
+
+ Total
+
+
+
+{% endif %}
+
+{% assign thisRecipe = nil %}
diff --git a/_layouts/recipe.html b/_layouts/recipe.html
index 33426a7e0..60a4f19fe 100644
--- a/_layouts/recipe.html
+++ b/_layouts/recipe.html
@@ -22,6 +22,7 @@
@@ -100,6 +101,8 @@
{{recipe.title}}
{% endif %}
{% endfor %}
+ {% include timings.html recipe=recipe %}
+
{{ site.translation[site.language].ingredients }}
{% for item in recipe.ingredients %}
@@ -157,3 +160,4 @@ {{ site.translation[site.language].directions
});
+
diff --git a/css/main.scss b/css/main.scss
index f22d26ed4..198b29c35 100755
--- a/css/main.scss
+++ b/css/main.scss
@@ -51,3 +51,4 @@ a:hover .image{opacity:0.2;}
.border-1 { border-width: 1px; }
.border-1:active { border-width: 1px; }
.capitalize { text-transform: capitalize; }
+.align-middle { vertical-align: middle; } // imported from basscss 8
diff --git a/js/duration.js b/js/duration.js
new file mode 100644
index 000000000..23b0dc108
--- /dev/null
+++ b/js/duration.js
@@ -0,0 +1,52 @@
+let en_GB = {
+ map: {Y: 'yr', B: 'mth', W: 'wk', D: 'day', H: 'hr', M: 'min', S: 'sec'},
+ counted: function(i, c){
+ res = this.map[i];
+ if(c > 1) { res += 's' }
+ return res;
+ }
+ };
+
+function Duration(el) {
+ this.element = document.getElementById(el);
+ this.lang = en_GB;
+ this.result = { Y: 0, B: 0, W: 0, D: 0, H: 0, M: 0, S: 0 };
+ this._rex = /(\d+(?:\.\d+)?)([YBWDHMS])/ig;
+ this.parts = function () {
+ let iso8601 = this.element.dataset.iso8601;
+ let parts = iso8601.substr(1).replace(/M(.*?)T/, 'B$1');
+ parts.match(this._rex).forEach((p) => {
+ let scale = p.substring(0, p.length - 1);
+ let unit = p.substring(p.length - 1).toUpperCase();
+ this.result[unit] = Number(scale);
+ });
+ return this.result;
+ };
+ this.format = function () {
+ const nonZero = (v) => v > 0;
+ let words = [];
+ let parts = this.parts();
+ for (var p in parts) {
+ if (parts.hasOwnProperty(p) && nonZero(parts[p])) {
+ words.push(`${parts[p]} ${this.lang.counted(p, parts[p])}`);
+ }
+ }
+ return words.join(' ');
+ };
+ this.update = function () {
+ this.element.innerHTML = this.format();
+ };
+}
+
+/*
+ Update the page either via object calls passing in the dom ID:
+ new Duration('prepTime').update();
+ new Duration('cookTime').update();
+ or use jquery to find them:
+ $('*[data-iso8601]').each(function (){
+ new Duration(this.id).update();
+ });
+*/
+$('*[data-iso8601]').each(function (){
+ new Duration(this.id).update();
+});