Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability for mailmason to generate and upload/update templates. #34

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ module.exports = function(grunt) {

grunt.loadNpmTasks('grunt-ftp-deploy');

var secret = grunt.file.exists('secrets.json') ? grunt.file.readJSON('secrets.json') : {};
var config = grunt.file.readJSON('config.json');

var path = {
css_src: 'src/stylesheets/global.scss',
css_dest: 'src/stylesheets/global.css',
Expand All @@ -30,8 +33,8 @@ module.exports = function(grunt) {
common changes centralized to key files instead of being littered
throughout the Gruntfile. This also makes it easy to .gitignore secrets
================================================= */
secret: grunt.file.exists('secrets.json') ? grunt.file.readJSON('secrets.json') : {},
config: grunt.file.readJSON('config.json'),
secret: secret,
config: config,

/* SASS
------------------------------------------------- */
Expand Down Expand Up @@ -304,14 +307,37 @@ module.exports = function(grunt) {
to: "<%= config.strings.litmus_email %>",
src: 'dist_test/user_invitation.html'
}
}
},

'postmark-templates-generate': {
options: {
src: [path.email_src],
dist: path.dist,
file: '<%= config.templates && config.templates.file %>'
}
},

'postmark-templates-upload': {
options: {
ephemeralUploadResultsProperty: '<%= config.templates && config.templates.ephemeralUploadResultsProperty %>'
}
},

'postmark-templates-output': {
options: {
outputFile: '<%= config.templates && config.templates.output_file || config.templates && config.templates.file %>',
cleanOutput: '<%= config.templates && config.templates.clean_output %>',
ephemeralUploadResultsProperty: '<%= config.templates && config.templates.ephemeralUploadResultsProperty %>'
}
},
});


/* Tasks
================================================= */

grunt.loadTasks('tasks');

grunt.registerTask('default', ['css', 'html']);

// Assets
Expand All @@ -325,6 +351,9 @@ module.exports = function(grunt) {
grunt.registerTask('litmus', ['testBuild', 'postmark:litmus']);
grunt.registerTask('flood', ['testBuild', 'postmark:flood']);

// Upload
grunt.registerTask('upload', ['default', 'postmark-templates-generate', 'postmark-templates']);

// Before sending tests via Postmark, ensure that test builds with inlined CSS are generated
grunt.registerTask('testBuild', ['default', 'copy:testTemplates', 'premailer:html']);
};
5 changes: 5 additions & 0 deletions example_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,10 @@
"bucket": "",
"region": "",
"overwrite": true
},
"templates": {
"file": "templates.json",
"cleanOutput": true,
"ephemeralUploadResultsProperty": "postmark-templates-upload-results"
}
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"spamcheck": "grunt spamcheck",
"litmus": "grunt litmus",
"flood": "grunt flood",
"upload": "grunt upload",
"build": "grunt"
},
"devDependencies": {
Expand All @@ -28,14 +29,15 @@
"grunt-contrib-watch": "^1.0.0",
"grunt-ftp-deploy": "^0.1.10",
"grunt-inline": "^0.3.4",
"grunt-postmark": "0.0.7",
"grunt-postmark": "0.0.8",
"grunt-premailer": "^1.0.0",
"grunt-prettify": "^0.4.0",
"grunt-sass": "^1.0.0",
"grunt-scss-lint": "^0.3.6",
"grunt-spamcheck": "0.1.1",
"grunt-text-replace": "^0.4.0",
"load-grunt-tasks": "^3.2.0",
"time-grunt": "^1.2.1"
"time-grunt": "^1.2.1",
"yaml-front-matter": "^3.4.0"
}
}
169 changes: 92 additions & 77 deletions previews.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>Postmark Template Previews</title>
<script>
<script type="application/javascript">
var templates = {
"welcome": {
"name": "Welcome",
Expand Down Expand Up @@ -56,6 +56,72 @@
"guide": "https://postmarkapp.com/guides/transactional-email-best-practices"
}
}

// This is the block of JavaScript that generates the TOC and previews
function processTemplates (templates) {
// Find the table of contents and previews area
var toc = document.getElementById('toc')
var previews = document.getElementById('previews')

// Iterate over the templates to generate the TOC and previews
for (var key in templates) {
// Build the table of contents for the various templates
var list_item = document.createElement('li')
var anchor = document.createElement('a')
anchor.setAttribute('href', '#' + key)
anchor.appendChild(document.createTextNode(templates[key]['name']))
list_item.appendChild(anchor)
list_item.appendChild(document.createTextNode(' - ' + templates[key]['description']))
toc.appendChild(list_item)

// Build the heading for the template
var heading = document.createElement('h1')
var description = document.createElement('p')
var guide_link = document.createElement('a')
var top_link = document.createElement('a')
top_link.setAttribute('href', '#toc')
top_link.appendChild(document.createTextNode('Back to Top'))
guide_link.setAttribute('href', templates[key]['guide'])
guide_link.setAttribute('target', '_blank')
guide_link.setAttribute('rel', 'noopener noreferrer')
guide_link.appendChild(document.createTextNode('📖 View Best Practices Guide'))
heading.appendChild(document.createTextNode(templates[key]['name']))
heading.setAttribute('id', key)
description.appendChild(document.createTextNode(templates[key]['description']))
description.appendChild(guide_link)
previews.appendChild(heading)
previews.appendChild(top_link)
previews.appendChild(description)

// Build the wide iframe preview for wide view of the template
var wide_preview = document.createElement('iframe')
wide_preview.setAttribute('width', '640')
wide_preview.setAttribute('height', '800')
wide_preview.setAttribute('src', 'dist/' + key + '.html')
previews.appendChild(wide_preview)

// Build the wide iframe preview for narrow view of the template
var narrow_preview = document.createElement('iframe')
narrow_preview.setAttribute('width', '480')
narrow_preview.setAttribute('height', '800')
narrow_preview.setAttribute('src', 'dist/' + key + '.html')
previews.appendChild(narrow_preview)

// Build the wide iframe preview for wide view of the template
var wide_preview = document.createElement('iframe')
wide_preview.setAttribute('width', '640')
wide_preview.setAttribute('height', '400')
wide_preview.setAttribute('src', 'dist/' + key + '.txt')
previews.appendChild(wide_preview)

// Build the wide iframe preview for narrow view of the template
var narrow_preview = document.createElement('iframe')
narrow_preview.setAttribute('width', '480')
narrow_preview.setAttribute('height', '400')
narrow_preview.setAttribute('src', 'dist/' + key + '.txt')
previews.appendChild(narrow_preview)
}
}
</script>
<style>
body {
Expand Down Expand Up @@ -137,7 +203,7 @@
div.container {
width: 1128px;
margin-left: auto;
margin-right: auto;
margin-right: auto;
}
a.mailmason-logo {
float: right;
Expand All @@ -149,7 +215,7 @@
</style>
</head>
<body>
<div class="container">
<nav>
<ul>
Expand All @@ -159,98 +225,47 @@
<li><a href="https://postmarkapp.com/why/templates">Postmark Templates</a></li>
</ul>
</nav>

<a href="https://github.com/wildbit/mailmason" class="mailmason-logo"><img src="http://assets.wildbit.com/wildbit/repos/mailmason/mailmason.png" alt="MailMason"></a>

<div class="table-of-contents">
<h1>MailMason Template Previews</h1>

<ol id="toc">
<!--
The table of contents is generated from the templates hash at the top
of the page using the JavaScript at the bottom of the page
-->
</ol>
</div>

<hr>

<div id="previews">
<!--
The previews are generated from the templates hash at the top
of the page using the JavaScript at the bottom of the page
-->
</div>
</div>

<script>
// This is the block of JavaScript that generates the TOC and previews

// Find the table of contents and previews area
var toc = document.getElementById("toc");
var previews = document.getElementById("previews");

// Iterate over the templates to generate the TOC and previews
for (var key in templates) {
console.log(key);

// Build the table of contents for the various templates
var list_item = document.createElement("li");
var anchor = document.createElement("a");
anchor.setAttribute("href", "#" + key);
anchor.appendChild(document.createTextNode(templates[key]["name"]));
list_item.appendChild(anchor);
list_item.appendChild(document.createTextNode(" - " + templates[key]["description"]));
toc.appendChild(list_item);

// Build the heading for the template
var heading = document.createElement("h1");
var description = document.createElement("p");
var guide_link = document.createElement("a");
var top_link = document.createElement("a");
top_link.setAttribute("href", "#toc");
top_link.appendChild(document.createTextNode("Back to Top"));
guide_link.setAttribute("href", templates[key]["guide"]);
guide_link.setAttribute("target", "_blank");
guide_link.setAttribute("rel", "noopener noreferrer");
guide_link.appendChild(document.createTextNode("📖 View Best Practices Guide"));
heading.appendChild(document.createTextNode(templates[key]["name"]));
heading.setAttribute("id", key);
description.appendChild(document.createTextNode(templates[key]["description"]));
description.appendChild(guide_link)
previews.appendChild(heading);
previews.appendChild(top_link);
previews.appendChild(description);

// Build the wide iframe preview for wide view of the template
var wide_preview = document.createElement("iframe");
wide_preview.setAttribute("width", "640")
wide_preview.setAttribute("height", "800")
wide_preview.setAttribute("src", "dist/" + key + ".html")
previews.appendChild(wide_preview);

// Build the wide iframe preview for narrow view of the template
var narrow_preview = document.createElement("iframe");
narrow_preview.setAttribute("width", "480")
narrow_preview.setAttribute("height", "800")
narrow_preview.setAttribute("src", "dist/" + key + ".html")
previews.appendChild(narrow_preview);

// Build the wide iframe preview for wide view of the template
var wide_preview = document.createElement("iframe");
wide_preview.setAttribute("width", "640")
wide_preview.setAttribute("height", "400")
wide_preview.setAttribute("src", "dist/" + key + ".txt")
previews.appendChild(wide_preview);

// Build the wide iframe preview for narrow view of the template
var narrow_preview = document.createElement("iframe");
narrow_preview.setAttribute("width", "480")
narrow_preview.setAttribute("height", "400")
narrow_preview.setAttribute("src", "dist/" + key + ".txt")
previews.appendChild(narrow_preview);

};

<script type="application/javascript">
(function () {
var xmlhttp = new XMLHttpRequest()

xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE) {
var templatesForProcessing = xmlhttp.status < 300 && xmlhttp.status > 199
? JSON.parse(xmlhttp.responseText)
: templates;
processTemplates(templatesForProcessing);
}
}

xmlhttp.overrideMimeType('application/json');
xmlhttp.open('GET', './templates.json');
xmlhttp.send();
})();
</script>
</body>
</html>
50 changes: 50 additions & 0 deletions tasks/grunt-postmark-templates-generate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* grunt-postmark-templates-generate
* Generate templates to push to a Postmark server for use with grunt-postmark
*
* https://github.com/wildbit/grunt-postmark.git
*/

module.exports = function (grunt) {
grunt.registerTask('postmark-templates-generate', 'Generate templates to push to a Postmark server for use with grunt-postmark', function () {
var path = require('path');
var yaml = require('yaml-front-matter');

var options = this.options();
var templatePaths = grunt.file.expand(options.src);
var templateObjects = grunt.file.readJSON(options.file);

templatePaths.map(function (templatePath) {
try {
var templateFile = yaml.loadFront(grunt.file.read(templatePath));
var templateName = path.basename(templatePath, '.hbs');
var templateContents = {
name: templateObjects[templateName] && templateObjects[templateName].name || templateName,
htmlSrc: path.join(options.dist, templateName + '.html'),
textSrc: path.join(options.dist, templateName + '.txt')
};

if (templateFile.name) {
templateContents.name = templateFile.name;
}

if (templateFile.subject) {
templateContents.subject = templateFile.subject;
}

if (!templateObjects[templateName]) {
templateObjects[templateName] = {};
}

Object.assign(
templateObjects[templateName],
templateContents
);
} catch (e) {
grunt.log.error('templatePath', templatePath, e);
}
});

grunt.config('postmark-templates-upload', templateObjects);
});
};
Loading