diff --git a/Gruntfile.js b/Gruntfile.js index 05df9e6..20b501d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -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', @@ -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 ------------------------------------------------- */ @@ -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 @@ -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']); }; diff --git a/example_config.json b/example_config.json index 24d5e59..e087ede 100644 --- a/example_config.json +++ b/example_config.json @@ -50,5 +50,10 @@ "bucket": "", "region": "", "overwrite": true + }, + "templates": { + "file": "templates.json", + "cleanOutput": true, + "ephemeralUploadResultsProperty": "postmark-templates-upload-results" } } diff --git a/package.json b/package.json index 7dd21c5..a0e6f18 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "spamcheck": "grunt spamcheck", "litmus": "grunt litmus", "flood": "grunt flood", + "upload": "grunt upload", "build": "grunt" }, "devDependencies": { @@ -28,7 +29,7 @@ "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", @@ -36,6 +37,7 @@ "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" } } diff --git a/previews.html b/previews.html index 5db4f22..ee414c7 100644 --- a/previews.html +++ b/previews.html @@ -3,7 +3,7 @@ Postmark Template Previews - - +
- + - +

MailMason Template Previews

- +
- +
- +
- - diff --git a/tasks/grunt-postmark-templates-generate.js b/tasks/grunt-postmark-templates-generate.js new file mode 100644 index 0000000..9de2ac0 --- /dev/null +++ b/tasks/grunt-postmark-templates-generate.js @@ -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); + }); +}; diff --git a/templates.json b/templates.json new file mode 100644 index 0000000..e392479 --- /dev/null +++ b/templates.json @@ -0,0 +1,52 @@ +{ + "welcome": { + "Name": "Welcome", + "description": "Send a welcome email to users after they sign up.", + "guide": "https://postmarkapp.com/guides/welcome-email-best-practices" + }, + "password_reset": { + "Name": "Password Reset", + "description": "Send users a link to reset their password.", + "guide": "https://postmarkapp.com/guides/password-reset-email-best-practices" + }, + "password_reset_help": { + "Name": "Password Reset Help", + "description": "Help users reset their password if they can’t remember their email.", + "guide": "https://postmarkapp.com/guides/password-reset-email-best-practices" + }, + "invoice": { + "Name": "Invoice", + "description": "Request payment from a user.", + "guide": "https://postmarkapp.com/guides/receipt-and-invoice-email-best-practices" + }, + "receipt": { + "Name": "Receipt", + "description": "Send a receipt to users after they made a purchase.", + "guide": "https://postmarkapp.com/guides/receipt-and-invoice-email-best-practices" + }, + "comment_notification": { + "Name": "Comment Notification", + "description": "Notify users of new comments by other users.", + "guide": "https://postmarkapp.com/guides/comment-notification-email-best-practices" + }, + "trial_expiring": { + "Name": "Trial Expiring", + "description": "Let users know when their trial is about to expire.", + "guide": "https://postmarkapp.com/guides/trial-expiration-email-best-practices" + }, + "trial_expired": { + "Name": "Trial Expired", + "description": "Let users know when their expired trial.", + "guide": "https://postmarkapp.com/guides/trial-expiration-email-best-practices" + }, + "user_invitation": { + "Name": "User Invitation", + "description": "Help users invite others to use your software.", + "guide": "https://postmarkapp.com/guides/user-invitation-email-best-practices" + }, + "example": { + "Name": "Example", + "description": "Examples of built-in elements and styles.", + "guide": "https://postmarkapp.com/guides/transactional-email-best-practices" + } +} \ No newline at end of file