├── screenshot.png ├── grunt ├── clean.js ├── open.js ├── autoprefixer.js ├── express.js ├── imagemin.js ├── assemble.js ├── juice.js ├── sass.js ├── watch.js ├── mailgun.js ├── cloudfiles.js ├── cdn.js ├── replace.js ├── aliases.yaml ├── aws_s3.js └── litmus.js ├── preview ├── img │ ├── phone.png │ └── phone-icon.png ├── scss │ ├── _reset-ish.scss │ ├── preview.scss │ ├── _welcome.scss │ └── _ui.scss ├── _blank.html └── index.ejs ├── src ├── img │ └── misty-mountains.jpg ├── partials │ └── components │ │ ├── divider.hbs │ │ ├── button.hbs │ │ └── notice.hbs ├── css │ └── scss │ │ ├── main.scss │ │ ├── _dividers.scss │ │ ├── _custom.scss │ │ ├── _other.scss │ │ ├── _notices.scss │ │ ├── _buttons.scss │ │ ├── _responsive.scss │ │ ├── _layout.scss │ │ ├── _config.scss │ │ ├── _global.scss │ │ └── _type.scss ├── layouts │ └── default.hbs └── emails │ └── kitchen_sink.hbs ├── dist ├── img │ └── misty-mountains.jpg └── kitchen_sink.html ├── .gitignore ├── Gruntfile.js ├── package.json ├── license.txt ├── server.js └── readme.md /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmailThis/typographic-email/HEAD/screenshot.png -------------------------------------------------------------------------------- /grunt/clean.js: -------------------------------------------------------------------------------- 1 | // Clean your /dist folder 2 | module.exports = { 3 | clean: ["dist"] 4 | }; 5 | -------------------------------------------------------------------------------- /preview/img/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmailThis/typographic-email/HEAD/preview/img/phone.png -------------------------------------------------------------------------------- /preview/img/phone-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmailThis/typographic-email/HEAD/preview/img/phone-icon.png -------------------------------------------------------------------------------- /src/img/misty-mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmailThis/typographic-email/HEAD/src/img/misty-mountains.jpg -------------------------------------------------------------------------------- /dist/img/misty-mountains.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmailThis/typographic-email/HEAD/dist/img/misty-mountains.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .sass-cache 4 | .secret 5 | *.css.map 6 | secrets.json 7 | preview/css 8 | src/css/*.css 9 | -------------------------------------------------------------------------------- /grunt/open.js: -------------------------------------------------------------------------------- 1 | // Browser-based preview task 2 | module.exports = { 3 | preview: { 4 | path: 'http://localhost:4001' 5 | } 6 | } -------------------------------------------------------------------------------- /preview/scss/_reset-ish.scss: -------------------------------------------------------------------------------- 1 | *, 2 | *:before, 3 | *:after { 4 | box-sizing: border-box; 5 | } 6 | 7 | html, 8 | body { 9 | background: #fff; 10 | margin: 0; 11 | padding: 0; 12 | } 13 | -------------------------------------------------------------------------------- /grunt/autoprefixer.js: -------------------------------------------------------------------------------- 1 | // Browser-based preview task 2 | module.exports = { 3 | preview: { 4 | options: { 5 | browsers: ['last 6 versions', 'ie 9'] 6 | }, 7 | src: 'preview/css/preview.css' 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /preview/scss/preview.scss: -------------------------------------------------------------------------------- 1 | // Some vars here are fine. 2 | $drawer-animation-duration: 0.3s; 3 | 4 | // Janky, basic needs reset 5 | @import "reset-ish"; 6 | 7 | // Preivew User Interface 8 | @import "ui"; 9 | 10 | // Preview "Welcome (default) Screen" 11 | @import "welcome"; 12 | -------------------------------------------------------------------------------- /src/partials/components/divider.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 |
4 | 5 | 6 | 7 | 8 |
9 |
-------------------------------------------------------------------------------- /src/css/scss/main.scss: -------------------------------------------------------------------------------- 1 | // Main scss styles 2 | @import 'config'; 3 | @import 'global'; 4 | @import 'layout'; 5 | @import 'type'; 6 | @import 'buttons'; 7 | @import 'notices'; 8 | @import 'dividers'; 9 | @import 'other'; 10 | @import 'responsive'; 11 | 12 | 13 | // Specific to this particular template 14 | // @import 'custom'; -------------------------------------------------------------------------------- /grunt/express.js: -------------------------------------------------------------------------------- 1 | // Browser-based preview task 2 | module.exports = { 3 | server: { 4 | options: { 5 | port: 4001, 6 | hostname: '127.0.0.1', 7 | bases: ['<%= paths.dist %>', '<%= paths.preview %>', '<%= paths.src %>'], 8 | server: './server.js', 9 | livereload: true 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/partials/components/button.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 |
4 | 5 | 6 | 9 | 10 |
7 | {{{ title }}} 8 |
11 |
-------------------------------------------------------------------------------- /grunt/imagemin.js: -------------------------------------------------------------------------------- 1 | // Compress images 2 | module.exports = { 3 | dynamic: { 4 | options: { 5 | optimizationLevel: 3, 6 | svgoPlugins: [{ removeViewBox: false }] 7 | }, 8 | 9 | files: [{ 10 | expand: true, 11 | cwd: '<%= paths.src_img %>', 12 | src: ['**/*.{png,jpg,gif}'], 13 | dest: '<%= paths.dist_img %>' 14 | }] 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /src/css/scss/_dividers.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | DIVIDERS 3 | ------------------------------------- */ 4 | 5 | .divider { 6 | border-collapse: separate; 7 | 8 | &-spacer { 9 | padding: $divider-margin; 10 | } 11 | 12 | td { 13 | border-top: 1px solid $divider-color; 14 | line-height: 0; 15 | font-size: 0; 16 | height: 1px; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | } -------------------------------------------------------------------------------- /grunt/assemble.js: -------------------------------------------------------------------------------- 1 | // Assembles your email content with HTML layout 2 | module.exports = { 3 | options: { 4 | layoutdir: '<%= paths.src %>/layouts', 5 | partials: ['<%= paths.src %>/partials/**/*.hbs'], 6 | helpers: ['<%= paths.src %>/helpers/**/*.js'], 7 | data: ['<%= paths.src %>/data/*.{json,yml}'], 8 | flatten: true 9 | }, 10 | pages: { 11 | src: ['<%= paths.src %>/emails/*.hbs'], 12 | dest: '<%= paths.dist %>/' 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /grunt/juice.js: -------------------------------------------------------------------------------- 1 | // Inlines your CSS 2 | module.exports = { 3 | your_target: { 4 | options: { 5 | preserveMediaQueries: true, 6 | applyAttributesTableElements: true, 7 | applyWidthAttributes: true, 8 | preserveImportant: true, 9 | preserveFontFaces: true, 10 | webResources: { 11 | images: false 12 | } 13 | }, 14 | files: [{ 15 | expand: true, 16 | src: ['<%= paths.dist %>/*.html'], 17 | dest: '' 18 | }] 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /grunt/sass.js: -------------------------------------------------------------------------------- 1 | // Takes your SCSS files and compiles them to CSS 2 | module.exports = { 3 | dist: { 4 | options: { 5 | style: 'expanded' 6 | }, 7 | files: { 8 | '<%= paths.src %>/css/main.css': '<%= paths.src %>/css/scss/main.scss' 9 | } 10 | }, 11 | 12 | // This task compiles Sass for the browser-baed preview UI. 13 | // You should not need to edit it. 14 | preview: { 15 | options: { 16 | style: 'compressed' 17 | }, 18 | files: { 19 | '<%= paths.preview %>/css/preview.css': '<%= paths.preview %>/scss/preview.scss' 20 | } 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-config')(grunt, { 4 | 5 | // Pass data to tasks 6 | data: { 7 | 8 | // Re-usable filesystem path variables 9 | paths: { 10 | src: 'src', 11 | src_img: 'src/img', 12 | dist: 'dist', 13 | dist_img: 'dist/img', 14 | preview: 'preview' 15 | }, 16 | 17 | // secrets.json is ignored in git because it contains sensitive data 18 | // See the README for configuration settings 19 | secrets: grunt.file.readJSON('secrets.json') 20 | 21 | } 22 | }); 23 | }; -------------------------------------------------------------------------------- /src/partials/components/notice.hbs: -------------------------------------------------------------------------------- 1 | {{! 2 | Notification Block 3 | Params: 4 | type: (string) accepts 'info', 'success', 'warning', 'danger' 5 | class: (string) opional classes you may want to apply such as 'align-center' 6 | text: (string) unescaped, the text you wish to display in the notice 7 | }} 8 | 9 | 10 | 17 | 18 |
11 | 12 | 13 | 14 | 15 |
{{{ text }}}
16 |
-------------------------------------------------------------------------------- /grunt/watch.js: -------------------------------------------------------------------------------- 1 | // Watches for changes to CSS or email templates then runs grunt tasks 2 | module.exports = { 3 | emails: { 4 | files: ['<%= paths.src %>/css/scss/*','<%= paths.src %>/emails/*','<%= paths.src %>/layouts/*','<%= paths.src %>/partials/**/*','<%= paths.src %>/data/*'], 5 | tasks: ['default'] 6 | }, 7 | preview_dist: { 8 | files: ['./dist/*'], 9 | tasks: [], 10 | options: { 11 | livereload: true 12 | } 13 | }, 14 | preview: { 15 | files: ['<%= paths.preview %>/scss/*'], 16 | tasks: ['sass:preview','autoprefixer:preview'], 17 | options: { 18 | livereload: true 19 | } 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{ subject }} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 |
18 |
{{ body }}
19 |
23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/css/scss/_custom.scss: -------------------------------------------------------------------------------- 1 | // #reader-view { 2 | // table { 3 | // width: 100%; 4 | // max-width: 100%; 5 | // margin: 1em auto; 6 | // border-collapse: collapse; 7 | // th, td { 8 | // padding: 6px; 9 | // text-align: left; 10 | // } 11 | 12 | // border: 1px solid $grey-medium; 13 | // > thead, 14 | // > tbody, 15 | // > tfoot { 16 | // > tr { 17 | // > th, 18 | // > td { 19 | // border: 1px solid $grey-medium; 20 | // } 21 | // } 22 | // } 23 | // > thead > tr { 24 | // > th, 25 | // > td { 26 | // border-bottom-width: 2px; 27 | // } 28 | // } 29 | // } 30 | // } -------------------------------------------------------------------------------- /preview/_blank.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BLANK 6 | 7 | 8 | 9 |
10 |
11 |
12 | 13 | 14 | 15 |
16 |
17 |

Alright. Let's roll...

18 |

Select a template from the upper right.

19 |
20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /grunt/mailgun.js: -------------------------------------------------------------------------------- 1 | // Use Mailgun option if you want to email the design to your inbox or to something like Litmus 2 | module.exports = function(grunt) { 3 | return { 4 | mailer: { 5 | options: { 6 | key: '<%= secrets.mailgun.api_key %>', // See README for secrets.json or replace this with your own key 7 | sender: '<%= secrets.mailgun.sender %>', // See README for secrets.json or replace this with your preferred sender 8 | recipient: '<%= secrets.mailgun.recipient %>', // See README for secrets.json or replace this with your preferred recipient 9 | subject: 'This is a test email' 10 | }, 11 | src: ['<%= paths.dist %>/'+grunt.option('template')] 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /grunt/cloudfiles.js: -------------------------------------------------------------------------------- 1 | // Use Rackspace Cloud Files if you're using images in your email 2 | // grunt cdnify 3 | module.exports = { 4 | prod: { 5 | 'user': '<%= secrets.cloudfiles.user %>', // See README for secrets.json or replace this with your user 6 | 'key': '<%= secrets.cloudfiles.key %>', // See README for secrets.json or replace this with your own key 7 | 'region': '<%= secrets.cloudfiles.region %>', // See README for secrets.json or replace this with your region 8 | 'upload': [{ 9 | 'container': '<%= secrets.cloudfiles.container %>', // See README for secrets.json or replace this with your container name 10 | 'src': '<%= paths.dist_img %>/*', 11 | 'dest': '/', 12 | 'stripcomponents': 0 13 | }] 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /grunt/cdn.js: -------------------------------------------------------------------------------- 1 | // CDN will replace local paths with your CDN path 2 | module.exports = { 3 | cloudfiles: { 4 | options: { 5 | cdn: '<%= secrets.cloudfiles.uri %>', // See README for secrets.json or replace this with your cdn uri 6 | flatten: true, 7 | supportedTypes: 'html' 8 | }, 9 | cwd: './<%= paths.dist %>', 10 | dest: './<%= paths.dist %>', 11 | src: ['*.html'] 12 | }, 13 | 14 | aws_s3: { 15 | options: { 16 | cdn: '<%= secrets.s3.bucketuri %>/<%= secrets.s3.bucketname %>/<%= secrets.s3.bucketdir %>', // See README for secrets.json or replace this with your Amazon S3 bucket uri 17 | flatten: true, 18 | supportedTypes: 'html' 19 | }, 20 | cwd: './<%= paths.dist %>', 21 | dest: './<%= paths.dist %>', 22 | src: ['*.html'] 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /grunt/replace.js: -------------------------------------------------------------------------------- 1 | // Replace compiled template images sources from ../src/html to ../dist/html 2 | module.exports = { 3 | src_images: { 4 | options: { 5 | usePrefix: false, 6 | patterns: [ 7 | { 8 | match: /(]+[\"'])(\.\.\/src\/img\/)/gi, // Matches /' 14 | } 15 | ] 16 | }, 17 | 18 | files: [{ 19 | expand: true, 20 | flatten: true, 21 | src: ['<%= paths.dist %>/*.html'], 22 | dest: '<%= paths.dist %>' 23 | }] 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /grunt/aliases.yaml: -------------------------------------------------------------------------------- 1 | # Where we tell Grunt what to do when we type "grunt" into the terminal 2 | # $ grunt 3 | default: 4 | - 'clean' 5 | - 'sass:dist' 6 | - 'assemble' 7 | - 'juice' 8 | - 'imagemin' 9 | - 'replace:src_images' 10 | 11 | # Use grunt send if you want to actually send the email to your inbox 12 | # $ grunt send --template=transaction.html 13 | send: 14 | - 'mailgun' 15 | 16 | # Upload images to your CDN on Rackspace Cloud Files 17 | # $ grunt rsupload 18 | rsupload: 19 | - 'default' 20 | - 'cloudfiles' 21 | - 'cdn:cloudfiles' 22 | 23 | # Upload image files to Amazon S3 24 | # $ grunt s3upload 25 | s3upload: 26 | - 'default' 27 | - 'aws_s3:prod' 28 | - 'cdn:aws_s3' 29 | 30 | # Launch the express server and start watching 31 | # $ grunt serve 32 | serve: 33 | - 'default' 34 | - 'sass:preview' 35 | - 'autoprefixer:preview' 36 | - 'express' 37 | - 'open' 38 | - 'watch' 39 | -------------------------------------------------------------------------------- /grunt/aws_s3.js: -------------------------------------------------------------------------------- 1 | // Use Amazon S3 for images 2 | // grunt s3upload 3 | module.exports = { 4 | options: { 5 | accessKeyId: '<%= secrets.s3.key %>', // See README for secrets.json 6 | secretAccessKey: '<%= secrets.s3.secret %>', // See README for secrets.json 7 | region: '<%= secrets.s3.region %>', // Enter region or leave blank for US Standard region 8 | uploadConcurrency: 5, // 5 simultaneous uploads 9 | downloadConcurrency: 5 // 5 simultaneous downloads 10 | }, 11 | 12 | prod: { 13 | options: { 14 | bucket: '<%= secrets.s3.bucketname %>', // Define your S3 bucket name in secrets.json 15 | differential: true, // Only uploads the files that have changed 16 | params: { 17 | CacheControl: '2000' 18 | } 19 | }, 20 | files: [ 21 | {expand: true, cwd: '<%= paths.dist_img %>', src: ['**'], dest: '<%= secrets.s3.bucketdir %>/<%= paths.dist_img %>'} 22 | ] 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/css/scss/_other.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | OTHER STYLES THAT MIGHT BE USEFUL 3 | ------------------------------------- */ 4 | 5 | hr { 6 | margin: 2 * $body-font-size 0; 7 | border: none; 8 | border-top: 1px solid $grey-medium; 9 | color: $white; 10 | } 11 | 12 | .last { 13 | margin-bottom: 0; 14 | } 15 | 16 | .first { 17 | margin-top: 0; 18 | } 19 | 20 | .align-center { 21 | text-align: center; 22 | } 23 | 24 | .align-right { 25 | text-align: right; 26 | } 27 | 28 | .align-left { 29 | text-align: left; 30 | } 31 | 32 | .clear { 33 | clear: both; 34 | } 35 | 36 | .mt0 { 37 | margin-top: 0; 38 | } 39 | 40 | .mb0 { 41 | margin-bottom: 0; 42 | } 43 | 44 | // Preheader text is displayed in certain clients as a preview but not shown when the user opens the email 45 | .preheader { 46 | color: transparent; 47 | display: none; 48 | height: 0; 49 | max-height: 0; 50 | max-width: 0; 51 | opacity: 0; 52 | overflow: hidden; 53 | mso-hide: all; 54 | visibility: hidden; 55 | width: 0; 56 | } -------------------------------------------------------------------------------- /grunt/litmus.js: -------------------------------------------------------------------------------- 1 | // Send your email template to Litmus for testing 2 | // grunt litmus --template=transaction.html 3 | module.exports = function(grunt) { 4 | return { 5 | test: { 6 | src: ['<%= paths.dist %>/'+grunt.option('template')], 7 | options: { 8 | username: '<%= secrets.litmus.username %>', // See README for secrets.json or replace this with your username 9 | password: '<%= secrets.litmus.password %>', // See README for secrets.json or replace this with your password 10 | url: 'https://<%= secrets.litmus.company %>.litmus.com', // See README for secrets.json or replace this with your company url 11 | clients: ['android4', 'aolonline', 'androidgmailapp', 'aolonline', 'ffaolonline', 12 | 'chromeaolonline', 'appmail6', 'iphone6', 'ipadmini', 'ipad', 'chromegmailnew', 13 | 'iphone6plus', 'notes85', 'ol2002', 'ol2003', 'ol2007', 'ol2010', 'ol2011', 14 | 'ol2013', 'outlookcom', 'chromeoutlookcom', 'chromeyahoo', 'windowsphone8'] // https://#{company}.litmus.com/emails/clients.xml 15 | } 16 | } 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typographic-email", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/EmailThis/typographic-email" 8 | }, 9 | "devDependencies": { 10 | "assemble": "^0.4.42", 11 | "cheerio": "^0.19.0", 12 | "ejs": "^2.3.1", 13 | "express": "^4.12.3", 14 | "grunt": "^0.4.5", 15 | "grunt-assemble": "^0.3.1", 16 | "grunt-autoprefixer": "^2.2.0", 17 | "grunt-aws-s3": "^0.13.1", 18 | "grunt-cdn": "^0.6.5", 19 | "grunt-cloudfiles": "^0.3.0", 20 | "grunt-contrib-clean": "^0.6.0", 21 | "grunt-contrib-imagemin": "^1.0.0", 22 | "grunt-contrib-watch": "^0.6.1", 23 | "grunt-express": "^1.4.1", 24 | "grunt-juice-email": "^0.1.3", 25 | "grunt-litmus": "^0.1.8", 26 | "grunt-mailgun": "^1.0.1", 27 | "grunt-open": "^0.2.3", 28 | "grunt-parallel": "^0.5.1", 29 | "grunt-replace": "^0.9.3", 30 | "grunt-sass": "^1.0.0", 31 | "imagemin-mozjpeg": "^5.1.0", 32 | "load-grunt-config": "^0.19.0", 33 | "load-grunt-tasks": "^3.2.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2017] [Bharani] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/css/scss/_notices.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | NOTICES 3 | ------------------------------------- */ 4 | 5 | @mixin create-notice($color) { 6 | td { 7 | background: lighten($color, 44%); 8 | border: 1px solid lighten($color, 30%); 9 | border-radius: $notice-border-radius; 10 | color: darken($color, 10%); 11 | padding: $notice-padding; 12 | } 13 | } 14 | 15 | .et-notice { 16 | border-collapse: separate; 17 | &-spacer { 18 | padding: $notice-margin; 19 | } 20 | 21 | td { 22 | line-height: $notice-line-height; 23 | font-size: $notice-font-size; 24 | font-weight: $notice-font-weight; 25 | font-family: $font-family-sans-serif; 26 | 27 | p { 28 | margin: 0; 29 | padding: 0; 30 | } 31 | } 32 | 33 | // Color Variations 34 | &-info { 35 | @include create-notice($notice-color-info); 36 | } 37 | 38 | &-success { 39 | @include create-notice($notice-color-success); 40 | } 41 | 42 | &-warning { 43 | @include create-notice($notice-color-warning); 44 | } 45 | 46 | &-danger { 47 | @include create-notice($notice-color-danger); 48 | } 49 | 50 | // Size Variations 51 | &-lg td { 52 | font-size: ($notice-font-size * 1.2); 53 | line-height: $notice-line-height; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/css/scss/_buttons.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | BUTTONS 3 | ------------------------------------- */ 4 | 5 | .et-btn { 6 | width: 100%; 7 | font-family: $font-family-sans-serif; 8 | margin-bottom: 30px; 9 | 10 | > tr > td { 11 | padding-bottom: 15px; 12 | } 13 | 14 | table { 15 | width: auto; 16 | } 17 | 18 | table td { 19 | background-color: #ffffff; 20 | border-radius: $btn-br; 21 | text-align: center; 22 | } 23 | 24 | a{ 25 | background-color: #ffffff; 26 | border: solid 1px $primary-color; 27 | border-radius: $btn-br; 28 | color: $primary-color; 29 | cursor: pointer; 30 | display: inline-block; 31 | font-size: 14px; 32 | font-weight: bold; 33 | margin: 0; 34 | padding: 12px 25px; 35 | text-decoration: none; 36 | text-transform: capitalize; 37 | font-family: $font-family-sans-serif; 38 | } 39 | } 40 | 41 | // Primary call to action button 42 | .et-btn-primary { 43 | 44 | table td { 45 | background-color: $primary-color; 46 | } 47 | 48 | a{ 49 | background-color: $primary-color; 50 | border-color: $primary-color; 51 | color: #ffffff; 52 | } 53 | } 54 | 55 | // Secondary button 56 | .et-btn-secondary { 57 | 58 | table td { 59 | background-color: transparent; 60 | } 61 | 62 | a{ 63 | background-color: transparent; 64 | border-color: $primary-color; 65 | color: $primary-color; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | cheerio = require('cheerio'), 3 | fs = require('fs'), 4 | app = express(); 5 | 6 | // Use embedded javascript for the view engine (templates) 7 | app.set('view engine', 'ejs'); 8 | 9 | // Allow relative image links from either ./dist/img or ./src/img 10 | app.use("/src/img", express.static(__dirname + "/src/img")); 11 | app.use("/dist/img", express.static(__dirname + "/dist/img")); 12 | 13 | // Set the route handler for the preview page. 14 | app.get('/',function(req,res){ 15 | 16 | res.status(200); 17 | 18 | var data = { 19 | templates: getTemplates() 20 | }; 21 | 22 | res.render(__dirname + '/preview/index', data); 23 | 24 | }); 25 | 26 | module.exports = app; 27 | 28 | 29 | // Helper function to get templates and their "subject" from tag 30 | function getTemplates() { 31 | var templates = [], 32 | templateDir = __dirname + '/dist/', 33 | templateFiles = fs.readdirSync(templateDir); 34 | 35 | templateFiles.forEach( function (file) { 36 | if (file.substr(-5) === '.html') { 37 | var contents = fs.readFileSync(templateDir + file, 'utf8'); 38 | 39 | if (contents) { 40 | $ = cheerio.load(contents); 41 | 42 | templates.push({ 43 | 'filename': file, 44 | 'subject': $("html title").text() || "Subject not available" 45 | }); 46 | } 47 | } 48 | }); 49 | 50 | return templates; 51 | } 52 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Typographic Email 2 | 3 | This is a responsive email template that is optimized for readability. This is used in my project - [EmailThis](https://www.emailthis.me). I created it because I needed a simple, minimal yet beautiful email template that focusses specifically on readability. 4 | 5 | ### [Demo](https://rawgit.com/EmailThis/typographic-email/master/dist/kitchen_sink.html) 6 | 7 | **Side note:** Do check out EmailThis. It is a simpler alternative to Pocket/Readability/Instapaper. EmailThis will remove distractions & ads from an article or web page and send you a nice email with just the text/images. You can then open up the email client on your laptop/mobile and read the article at your leisure. It is completely free, try it out here - [https://www.emailthis.me](https://www.emailthis.me). 8 | 9 | Here is a preview of how it looks - 10 | 11 | ![Email Preview](./screenshot.png) 12 | 13 | 14 | -------- 15 | 16 | Feel free to download it & customize it to suit your needs. 17 | I would welcome your suggestions, comments and bug reports. 18 | 19 | -------- 20 | 21 | ### Installation 22 | ``` 23 | git clone https://github.com/emailthis/typographic-email 24 | cd typographic-email 25 | npm install 26 | grunt serve 27 | ``` 28 | 29 | -------- 30 | 31 | Based on the awesome [Grunt Email Workflow](https://github.com/leemunroe/grunt-email-workflow). 32 | 33 | All the credit goes to Lee Munroe for creating a great email workflow. I simply tweaked the styles a little bit. 34 | 35 | 36 | --------- 37 | Bharani 38 | 39 | Maker @ [EmailThis](https://www.emailthis.me) 40 | -------------------------------------------------------------------------------- /src/css/scss/_responsive.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | RESPONSIVE AND MOBILE FRIENDLY STYLES 3 | ------------------------------------- */ 4 | 5 | table[class=body]{ 6 | @media only screen and (max-width: $width+40) { 7 | font-size: $body-font-size-sm !important; 8 | 9 | p, 10 | ul, 11 | ol { 12 | font-size: $body-font-size-sm !important; 13 | margin-bottom: 15px !important; 14 | } 15 | 16 | .et-btn { 17 | margin-bottom: 15px; 18 | } 19 | 20 | h1 { 21 | font-size: 1.3 * $body-font-size !important; 22 | } 23 | h2 { 24 | font-size: 1.2 * $body-font-size !important; 25 | } 26 | h3 { 27 | font-size: 1.1 * $body-font-size !important; 28 | } 29 | h4 { 30 | font-size: 1.05 * $body-font-size !important; 31 | } 32 | h5 { 33 | font-size: 0.9 * $body-font-size !important; 34 | } 35 | h6 { 36 | font-size: 0.85 * $body-font-size !important; 37 | } 38 | 39 | h1, h2 { 40 | margin-bottom: $body-font-size !important; 41 | margin-top: $body-font-size !important; 42 | } 43 | 44 | // Spacing 45 | .container, .content { 46 | width: 100% !important; 47 | max-width: 100% !important; 48 | } 49 | 50 | .content, 51 | .wrapper { 52 | padding: 10px !important; 53 | } 54 | 55 | .container { 56 | padding: 0 !important; 57 | width: 100% !important; 58 | } 59 | 60 | // Buttons 61 | .btn table, 62 | .btn a { 63 | width: 100% !important; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/css/scss/_layout.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | BODY & CONTAINER 3 | ------------------------------------- */ 4 | 5 | body { 6 | background-color: $body-bg; 7 | } 8 | 9 | .body { 10 | background-color: $body-bg; 11 | width: 100%; 12 | } 13 | 14 | /* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */ 15 | .container { 16 | display: block; 17 | Margin: 0 auto !important; /* makes it centered */ 18 | max-width: $width; 19 | padding: 10px; 20 | width: 100% !important; 21 | } 22 | 23 | /* This should also be a block element, so that it will fill 100% of the .container */ 24 | .content { 25 | display: block; 26 | margin: 0 auto; 27 | max-width: $width; 28 | padding: 10px; 29 | } 30 | 31 | 32 | /* ------------------------------------- 33 | HEADER, FOOTER, MAIN 34 | ------------------------------------- */ 35 | 36 | .main { 37 | background: $body-bg; 38 | border: none; 39 | border-radius: $br; 40 | width: 100%; 41 | } 42 | 43 | .wrapper { 44 | padding: $padding; 45 | } 46 | 47 | // Adds padding to content - use this instead of paragraphs for consistent padding/margin rendering 48 | .content-block { 49 | padding: 0 0 $padding; 50 | } 51 | 52 | .header { 53 | margin-bottom: $padding; 54 | margin-top: ($padding - 10); 55 | width: 100%; 56 | } 57 | 58 | .footer { 59 | clear: both; 60 | width: 100%; 61 | 62 | * { 63 | color: $grey-dark; 64 | font-size: 12px; 65 | } 66 | 67 | td { 68 | padding: 20px 0; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /preview/scss/_welcome.scss: -------------------------------------------------------------------------------- 1 | .welcome-view { 2 | 3 | &, body { 4 | height: 100%; 5 | } 6 | body { 7 | color: #666; 8 | font: normal 16px/1.4 Helvetica,Arial,Sans-serif; 9 | } 10 | h1 { 11 | color: #333; 12 | font-size: 24px; 13 | margin: 20px 0 10px 0; 14 | padding: 0; 15 | } 16 | p { 17 | margin: 0; 18 | padding: 0; 19 | } 20 | .wrapper { 21 | display: table; 22 | height: 100%; 23 | min-height: 100%; 24 | width: 100%; 25 | } 26 | .wrapper--inner { 27 | display: table-cell; 28 | text-align: center; 29 | vertical-align: middle; 30 | } 31 | .animation { 32 | height: 70px; 33 | position: relative; 34 | } 35 | .animation--stem { 36 | position: absolute; 37 | left: 50%; 38 | top: 35px; 39 | width: 2px; 40 | height: 50px; 41 | margin-left: -1px; 42 | background: #348eda; 43 | 44 | &:before { 45 | content: ""; 46 | position: absolute; 47 | left: 50%; 48 | top: 0; 49 | border-radius: 100%; 50 | background: #348eda; 51 | width: 6px; 52 | height: 6px; 53 | margin-left: -3px; 54 | margin-top: -3px; 55 | } 56 | } 57 | .animation--icon { 58 | position: absolute; 59 | left: 50%; 60 | top: 50%; 61 | width: 80px; 62 | height: 80px; 63 | margin-left: -40px; 64 | margin-top: -40px; 65 | 66 | span { 67 | background: #348eda; 68 | background: rgba(52, 142, 218, 0); 69 | border-radius: 100%; 70 | display: block; 71 | width: 80px; 72 | height: 80px; 73 | transform: scale(.2); 74 | animation-name: wilkomen; 75 | animation-duration: 1.8s; 76 | animation-iteration-count: infinite; 77 | animation-timing-function: linear; 78 | } 79 | + .animation--icon span { 80 | animation-delay: .9s; 81 | } 82 | } 83 | } 84 | 85 | @keyframes wilkomen { 86 | 0% { } 87 | 25% { 88 | background: rgba(52, 142, 218, 1); 89 | } 90 | 50% { 91 | background: transparent; 92 | box-shadow: inset 0 0 2px rgba(52, 142, 218, 1); 93 | } 94 | 100% { 95 | transform: scale(1,1); 96 | box-shadow: inset 0 0 2px rgba(52, 142, 218, 0); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/css/scss/_config.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | CONFIGURE YOUR VARIABLES 3 | ------------------------------------- */ 4 | 5 | $padding: 30px; // For consistent padding 6 | $width: 580px; // Width of the content area 7 | $br: 0px; // Border radius 8 | $btn-br: $br; // Border radius 9 | 10 | 11 | // Colors 12 | // ------- 13 | $grey-light: #f6f6f6; 14 | $grey-medium: #cccccc; 15 | $grey-dark: #7F7F7F; 16 | $white: #ffffff; 17 | $black: #111111; 18 | $primary-color: #348eda; 19 | $font-color: $black; 20 | $headings-font-color: #222222; 21 | 22 | 23 | // Typography 24 | // ------- 25 | 26 | // $font-family-sans-serif: "Open Sans", "Fira Sans", "Droid Sans", "HelveticaNeue-Light", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif !default; 27 | // $font-family-serif: Georgia, "Times New Roman", Times, serif !default; 28 | 29 | $font-family-sans-serif: "Roboto", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif !default; 30 | $font-family-serif: Georgia, "Times New Roman", Times, serif !default; 31 | $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default; 32 | 33 | $body-font-family: $font-family-serif !default; 34 | $headings-font-family: $font-family-sans-serif !default; 35 | $body-font-weight: normal !default; 36 | $headings-font-weight: bold !default; 37 | $body-font-size: 20px !default; 38 | $body-font-size-sm: 18px !default; 39 | $body-font-color: #222222 !default; 40 | $body-line-height: 1.5 !default; 41 | $body-bg: $white !default; 42 | 43 | // Notices 44 | // ------- 45 | 46 | $notice-color-info: #3d88ce !default; 47 | $notice-color-success: #81ad22 !default; 48 | $notice-color-warning: #c6a121 !default; 49 | $notice-color-danger: #be2c2c !default; 50 | 51 | $notice-border-radius: $br !default; 52 | $notice-font-size: $body-font-size !default; 53 | $notice-font-weight: $body-font-weight !default; 54 | $notice-line-height: $body-line-height !default; 55 | $notice-padding: 8px 12px !default; 56 | $notice-margin: 12px 0 !default; 57 | 58 | // Dividers 59 | // -------- 60 | 61 | $divider-margin: 20px 0 !default; 62 | $divider-color: #ccc !default; -------------------------------------------------------------------------------- /src/css/scss/_global.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | GLOBAL RESETS 3 | ------------------------------------- */ 4 | /* CLIENT-SPECIFIC STYLES */ 5 | body, table, td, a{-webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;} /* Prevent WebKit and Windows mobile changing default text sizes */ 6 | table, td{mso-table-lspace: 0pt; mso-table-rspace: 0pt;} /* Remove spacing between tables in Outlook 2007 and up */ 7 | img{-ms-interpolation-mode: bicubic;} /* Allow smoother rendering of resized image in Internet Explorer */ 8 | 9 | /* RESET STYLES */ 10 | img{border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none;} 11 | body{height: 100% !important; margin: 0 !important; padding: 0 !important; width: 100% !important;} 12 | figure {margin: 0;padding:0} 13 | article, aside, details, figcaption, figure, 14 | footer, header, hgroup, menu, nav, section { display: block; } 15 | 16 | /* iOS BLUE LINKS */ 17 | a[x-apple-data-detectors] { 18 | color: inherit !important; 19 | text-decoration: none !important; 20 | font-size: inherit !important; 21 | font-family: inherit !important; 22 | font-weight: inherit !important; 23 | line-height: inherit !important; 24 | } 25 | 26 | /* ANDROID CENTER FIX */ 27 | div[style*="margin: 16px 0;"] { margin: 0 !important; } 28 | 29 | table, 30 | td, 31 | div, 32 | a { 33 | box-sizing: border-box; 34 | } 35 | 36 | img { 37 | -ms-interpolation-mode: bicubic; 38 | max-width: 100%; 39 | display: inline-block; 40 | padding: 5px; 41 | border: 1px solid $grey-medium; 42 | } 43 | 44 | body, .body { 45 | font-family: $body-font-family; 46 | font-size: $body-font-size; 47 | line-height: $body-line-height; 48 | height: 100% !important; 49 | width: 100% !important; 50 | margin: 0; 51 | padding: 0; 52 | -webkit-font-smoothing: antialiased; 53 | -ms-text-size-adjust: 100%; 54 | -webkit-text-size-adjust: 100%; 55 | } 56 | 57 | // Let's make sure all tables have defaults 58 | table { 59 | border-collapse: separate !important; 60 | mso-table-lspace: 0pt; 61 | mso-table-rspace: 0pt; 62 | width: 100%; 63 | 64 | td { 65 | font-family: $body-font-family; 66 | font-size: $body-font-size; 67 | vertical-align: top; 68 | } 69 | } 70 | 71 | // External class fix for Outlook.com 72 | .ExternalClass { 73 | width: 100%; 74 | } 75 | 76 | .ExternalClass, 77 | .ExternalClass p, 78 | .ExternalClass span, 79 | .ExternalClass font, 80 | .ExternalClass td, 81 | .ExternalClass div { 82 | line-height: 100%; 83 | } 84 | 85 | 86 | strong, b { 87 | font-weight: $headings-font-weight; 88 | } -------------------------------------------------------------------------------- /src/css/scss/_type.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | TYPOGRAPHY 3 | ------------------------------------- */ 4 | 5 | h1, 6 | h2, 7 | h3, 8 | h4, 9 | h5, 10 | h6 { 11 | color: $headings-font-color !important; 12 | font-family: $headings-font-family; 13 | font-weight: $headings-font-weight; 14 | line-height: 1.2; 15 | margin: 0; 16 | margin-bottom: $body-font-size; 17 | margin-top: 1.5 * $body-font-size; 18 | } 19 | 20 | h1, h2 { 21 | margin-bottom: 1.5 * $body-font-size; 22 | margin-top: 2 * $body-font-size; 23 | } 24 | 25 | h1 { 26 | font-size: 1.6 * $body-font-size; 27 | text-transform: capitalize; 28 | } 29 | h2 { 30 | font-size: 1.4 * $body-font-size; 31 | } 32 | h3 { 33 | font-size: 1.2 * $body-font-size; 34 | } 35 | h4 { 36 | font-size: 1.1 * $body-font-size; 37 | } 38 | h5 { 39 | font-size: 1 * $body-font-size; 40 | } 41 | h6 { 42 | font-size: 0.9 * $body-font-size; 43 | } 44 | 45 | p, 46 | ul, 47 | ol { 48 | font-family: $body-font-family; 49 | font-size: $body-font-size; 50 | font-weight: normal; 51 | margin: 0; 52 | margin-bottom: 30px; 53 | color: $font-color; 54 | } 55 | 56 | ul, ol { 57 | padding: 0; 58 | margin: 0; 59 | margin-bottom: 15px; 60 | padding-left: 25px; 61 | 62 | li { 63 | list-style-position: outside; 64 | margin-left: 5px; 65 | margin-bottom: 2px; 66 | } 67 | } 68 | 69 | li > ul, li > ol { 70 | margin-top: 15px; 71 | } 72 | 73 | a { 74 | color: $primary-color; 75 | text-decoration: none; 76 | font-weight: $headings-font-weight; 77 | } 78 | 79 | // Break long strings to prevent x-scrolling 80 | code, 81 | pre, 82 | .word-wrap { 83 | word-break: break-word; 84 | word-wrap: break-word; 85 | -webkit-hyphens: auto; 86 | -moz-hyphens: auto; 87 | hyphens: auto; 88 | } 89 | 90 | pre, code { 91 | font-family: $font-family-monospace; 92 | } 93 | 94 | pre { 95 | display: block; 96 | width: 96%; 97 | margin: 1em 0; 98 | background: $grey-light; 99 | padding: 2%; 100 | white-space: pre-wrap; 101 | font-size: 0.9 * $body-font-size; 102 | } 103 | 104 | 105 | blockquote { 106 | margin: 0; 107 | padding: 0; 108 | padding-top: $body-font-size; 109 | padding-bottom: $body-font-size; 110 | padding-left: 2 * $body-font-size; 111 | padding-right: 2 * $body-font-size; 112 | border-left: 4px solid $grey-medium; 113 | font-style: italic; 114 | margin: 2em 0; 115 | 116 | p { 117 | margin-bottom: 0; 118 | } 119 | } 120 | 121 | mark { 122 | background: #ff0; 123 | } 124 | 125 | dl { 126 | dt { 127 | font-weight: $headings-font-weight; 128 | } 129 | 130 | dd { 131 | margin-left: 2 * $body-font-size; 132 | } 133 | } -------------------------------------------------------------------------------- /preview/scss/_ui.scss: -------------------------------------------------------------------------------- 1 | .preview-interface-view { 2 | 3 | // Basic elements 4 | body { 5 | background: #fff; 6 | color: #333; 7 | font: normal 14px/1.4 Helvetica, Arial, Sans-serif; 8 | } 9 | a { 10 | color: #000; 11 | text-decoration: none; 12 | 13 | &:hover { 14 | color: #348eda; 15 | } 16 | } 17 | iframe { 18 | border: none; 19 | width: 100%; 20 | } 21 | 22 | // Header 23 | .header { 24 | box-shadow: 0 0 5px rgba(0,0,0,0.4); 25 | display: table; 26 | width: 100%; 27 | position: relative; 28 | z-index: 2; 29 | 30 | > div { 31 | display: table-cell; 32 | padding: 8px 20px; 33 | vertical-align: middle; 34 | } 35 | } 36 | .header--brand { 37 | font-size: 22px; 38 | } 39 | .header--select { 40 | text-align: right; 41 | } 42 | 43 | // Preview Screens 44 | .preview-ui--full, 45 | .preview-ui--mobile, 46 | .preview-ui--mobile__container { 47 | transition: margin all $drawer-animation-duration linear, 48 | padding all $drawer-animation-duration linear, 49 | width all $drawer-animation-duration linear, 50 | opaciy all $drawer-animation-duration linear; 51 | } 52 | 53 | .preview-ui { 54 | overflow: hidden; 55 | position: relative; 56 | z-index: 1; 57 | } 58 | .preview-ui--full { 59 | float: left; 60 | padding-right: 500px; 61 | width: 100%; 62 | } 63 | .preview-ui--mobile { 64 | background: #333; 65 | float: right; 66 | width: 500px; 67 | margin-left: -500px; 68 | position: relative; 69 | text-align: center; 70 | 71 | iframe { 72 | border-top: 1px solid #efefef; 73 | border-bottom: 1px solid #efefef; 74 | width: 320px; 75 | height: 461px; 76 | margin: 129px 0 0 23px; 77 | } 78 | } 79 | .preview-ui--mobile__container { 80 | background: transparent url(../img/phone.png) no-repeat 50% 0; 81 | background-size: 363px 711px; 82 | width: 363px; 83 | height: 711px; 84 | margin: 20px auto 0 auto; 85 | opacity: 1; 86 | text-align: left; 87 | } 88 | 89 | .preview-ui--mobile__toggle { 90 | cursor: pointer; 91 | position: absolute; 92 | left: 10px; 93 | top: 10px; 94 | width: 40px; 95 | height: 40px; 96 | z-index: 10; 97 | } 98 | 99 | // Layout elemnts when mobile drawer is hidden 100 | .mobile-drawer-hidden { 101 | .preview-ui--full { 102 | padding-right: 60px; 103 | } 104 | .preview-ui--mobile { 105 | width: 60px; 106 | margin-left: -60px; 107 | } 108 | .preview-ui--mobile__container { 109 | opacity: 0; 110 | } 111 | } 112 | 113 | // Drawer open toggle (phone) 114 | .toggle-drawer-open { 115 | background: transparent url(../img/phone-icon.png) no-repeat 50% 50%; 116 | background-size: 40px 40px; 117 | opacity: 0; 118 | transition: all $drawer-animation-duration ease-in-out; 119 | z-index: -1; 120 | } 121 | .mobile-drawer-hidden { 122 | .toggle-drawer-open { 123 | opacity: 1; 124 | z-index: 2; 125 | 126 | &:hover { 127 | opacity: 0.8; 128 | } 129 | } 130 | } 131 | 132 | // Drawer close toggle (x) 133 | .toggle-drawer-close { 134 | z-index: 1; 135 | 136 | &:hover { 137 | opacity: 0.8; 138 | } 139 | 140 | &:before, 141 | &:after { 142 | content: ""; 143 | position: absolute; 144 | background: #fff; 145 | display: block; 146 | width: 4px; 147 | height: 40px; 148 | transition: all $drawer-animation-duration ease-in-out; 149 | } 150 | &:before { 151 | left: 18px; 152 | transform: rotate(45deg); 153 | } 154 | &:after { 155 | right: 18px; 156 | transform: rotate(-45deg); 157 | } 158 | } 159 | .mobile-drawer-hidden { 160 | .toggle-drawer-close { 161 | &:before, 162 | &:after { 163 | width: 1px; 164 | opacity: 0; 165 | transform: rotate(0deg); 166 | } 167 | &:before { 168 | left: 0; 169 | } 170 | &:after { 171 | right: 0; 172 | } 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /preview/index.ejs: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en" class="preview-interface-view"> 3 | <head> 4 | <meta charset="UTF-8"> 5 | <title>Typographic Email :: (Preview) 6 | 7 | 8 | 9 | 21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 |
34 |
35 |
36 |
37 | 38 | 166 | 167 | -------------------------------------------------------------------------------- /src/emails/kitchen_sink.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default.hbs 3 | subject: Typographic Email Kitchen Sink 4 | --- 5 | This is preheader text. Some clients will show this text as a preview. 6 | 7 | 8 | 9 | 383 | 384 |
10 | 11 | 12 | 380 | 381 |
13 |

Inside the Eye: Nature’s Most Exquisite Creation

14 | 15 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam soluta eveniet recusandae. Voluptatem ratione repellat vero ullam, dolorem earum reiciendis eaque itaque nemo magni odit id minima, corporis et facere.

16 | 17 | Misty Mountains

18 | 19 |
 20 | Preformated:Testing one row
 21 | and another
22 | 23 |

Duis aute irure dolor in reprehenderit in voluptate velit esse 24 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 25 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

26 | 27 |
    28 |
  • This is a list item
  • 29 |
  • So is this - there could be more
  • 30 |
  • Make sure to style list items to: 31 |
      32 |
    • Not forgetting child list items
    • 33 |
    • Not forgetting child list items
    • 34 |
    • Not forgetting child list items
    • 35 |
    • Not forgetting child list items
    • 36 |
  • 37 |
  • A couple more
  • 38 |
  • top level list items
  • 39 |
40 | 41 | {{> divider }} 42 | 43 | 44 |

Notices

45 | 46 | {{> notice type='info' text='Hello, this is a info notice.' }} 47 | {{> notice type='success' text='Hello, this is a success notice.' }} 48 | {{> notice type='warning' text='Hello, this is a warning notice.' }} 49 | {{> notice type='danger' text='Hello, this is a danger notice.' }} 50 | 51 | {{> divider }} 52 | 53 | 54 |

Buttons

55 | {{> button type='primary' url='https://github.com/leemunroe/grunt-email-workflow' title='Button (primary)' }} 56 | {{> button type='secondary' url='https://github.com/leemunroe/grunt-email-workflow' title='Button (secondary)' }} 57 | 58 | {{> divider }} 59 | 60 |

Don't forget Ordered lists:

61 |
    62 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 63 |
  3. Aliquam tincidunt mauris eu risus. 64 |
      65 |
    1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    2. 66 |
    3. Aliquam tincidunt mauris eu risus.
    4. 67 |
    68 |
  4. 69 |
  5. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  6. 70 |
  7. Aliquam tincidunt mauris eu risus.
  8. 71 |
72 |

A sub heading which is not as important as the first, but is quite imporant overall

73 |

74 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 75 |

76 | 77 | 78 | 79 |

A sub heading which is not as important as the second, but should be used with consideration

80 |

81 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 82 |

83 | 84 |
85 |

This is a properly formatted blockquote, btw. Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

86 | 89 |
90 | 91 |

A sub heading which is not as important as the second, but should be used with consideration

92 |

93 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 94 |

95 |
96 |

97 | “Ooh - a blockquote! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.” 98 |

99 |
100 | 101 | 102 | 103 |
A sub heading which is not as important as the second, but should be used with consideration
104 |

105 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 106 |

107 | 108 |
109 |
Definition list
110 |
111 | Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 112 |
113 |
Lorem ipsum dolor sit amet
114 |
115 | Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 116 |
117 |
118 | 119 |
This heading plays a relatively small bit part role, if you use it at all
120 |

121 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 122 |

123 |

124 | Level 1 heading 125 |

126 |

127 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 128 |

129 |

130 | Level 1 heading class="fancy" 131 |

132 |

133 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 134 |

135 |

136 | Level 1 heading class="thin" 137 |

138 |

139 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 140 |

141 |

142 | Level 1 heading class="caps" 143 |

144 |

145 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 146 |

147 |

148 | Level 02 Heading 149 |

150 |

151 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 152 |

153 |

154 | Level 2 heading class="fancy" 155 |

156 |

157 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 158 |

159 |

160 | Level 2 heading class="thin" 161 |

162 |

163 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 164 |

165 |

166 | Level 2 heading class="caps" 167 |

168 |

169 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 170 |

171 |

172 | Level 03 Heading 173 |

174 |

175 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 176 |

177 |

178 | Level 3 heading class="fancy" 179 |

180 |

181 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 182 |

183 |

184 | Level 3 heading class="thin" 185 |

186 |

187 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 188 |

189 |

190 | Level 3 heading class="caps" 191 |

192 |

193 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 194 |

195 |

196 | Level 04 Heading 197 |

198 |

199 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 200 |

201 |

202 | Level 4 heading class="fancy" 203 |

204 |

205 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 206 |

207 |

208 | Level 4 heading class="thin" 209 |

210 |

211 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 212 |

213 |

214 | Level 4 heading class="caps" 215 |

216 |

217 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 218 |

219 |
220 | Level 05 Heading 221 |
222 |

223 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 224 |

225 |
226 | Level 5 heading class="fancy" 227 |
228 |

229 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 230 |

231 |
232 | Level 5 heading class="thin" 233 |
234 |

235 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 236 |

237 |
238 | Level 5 heading class="caps" 239 |
240 |

241 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 242 |

243 |
244 | Level 06 Heading 245 |
246 |

247 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 248 |

249 |
250 | Level 6 heading class="fancy" 251 |
252 |

253 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 254 |

255 |
256 | Level 6 heading class="thin" 257 |
258 |

259 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 260 |

261 |
262 | Level 6 heading class="caps" 263 |
264 |

265 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 266 |

267 |
268 |

269 | Paragraph inside Blockquote: Nam libero leo, elementum in, dapibus a, suscipit vitae, purus. Duis arcu. Integer dignissim fermentum enim. Morbi convallis felis vel nibh. Sed scelerisque sagittis lorem. 270 |

271 |
272 |
273 | Address: Example address 224, Sweden 274 |
275 | 276 |

277 | I am the a tag example
278 | I am the abbr tag example
279 | I am the acronym tag example
280 | I am the b tag example
281 | I am the big tag example
282 | I am the cite tag example
283 | I am the code tag example
284 | I am the del tag example
285 | I am the dfn tag example
286 | I am the em tag example
287 | I am the i tag example
288 | I am the ins tag example
289 | I am the kbd tag example
290 | I am the q tag example
291 | I am the samp tag example
292 | I am the small tag example
293 | I am the span tag example
294 | I am the strong tag example
295 | I am the sub tag example
296 | I am the sup tag example
297 | I am the tt tag example
298 | I am the var tag example
299 | I am the small class example
300 | I am the large class example
301 | I am the quiet class example
302 | I am the highlight class example
303 |

304 | 305 |
306 | 307 |
    308 |
  • Unordered list 01
  • 309 |
  • Unordered list 02
  • 310 |
  • Unordered list 03 311 |
      312 |
    • Unordered list inside list level 2
    • 313 |
    • Unordered list inside list level 2 314 |
        315 |
      • Unordered list inside list level 3
      • 316 |
      • Unordered list inside list level 3
      • 317 |
      318 |
    • 319 |
    320 |
  • 321 |
322 |
    323 |
  1. Ordered list 01
  2. 324 |
  3. Ordered list 02
  4. 325 |
  5. Ordered list 03 326 |
      327 |
    1. Ordered list inside list level 2
    2. 328 |
    3. Ordered list inside list level 2 329 |
        330 |
      1. Ordered list inside list level 3
      2. 331 |
      3. Ordered list inside list level 3
      4. 332 |
      333 |
    4. 334 |
    335 |
  6. 336 |
337 | 338 |
339 |
340 | Description list title 01 341 |
342 |
343 | Description list description 01 344 |
345 |
346 | Description list title 02 347 |
348 |
349 | Description list description 02 350 |
351 |
352 | Description list description 03 353 |
354 |
355 | 356 | 357 | I am a word document link, so readers know that I'm not a normal link.
358 | I am a pdf document link, so readers know that I'm not a normal link.
359 | I am an external website link, so readers know that I'm not a normal link.
360 | I am an rss feed link, so readers know that I'm not a normal link.
361 | I am an excel spreadsheet link, so readers know that I'm not a normal link.
362 | I am an AIM screenname link, so readers know that I'm not a normal link.
363 | I am an email address link, so readers know that I'm not a normal link.
364 | I am an internal link. Change the stylesheet's "http://yourwebsite.com" to your domain name so I don't look like an external link.
365 | 366 |
367 | 368 |
369 | 370 |

371 | This is a paragraph with class="success" and a link. 372 |

373 |

374 | This is a paragraph with class="error" and a link. 375 |

376 |

377 | This is a paragraph with class="notice" and a link. 378 |

379 |
382 |
385 | 386 | 397 | -------------------------------------------------------------------------------- /dist/kitchen_sink.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Typographic Email Kitchen Sink 9 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 551 | 552 | 553 |
71 |
72 | 73 | 74 | 75 | 76 | 535 | 536 |
77 | 78 | 79 | 532 | 533 |
80 |

Inside the Eye: Nature’s Most Exquisite Creation

81 | 82 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam soluta eveniet recusandae. Voluptatem ratione repellat vero ullam, dolorem earum reiciendis eaque itaque nemo magni odit id minima, corporis et facere.

83 | 84 | Misty Mountains

85 | 86 |
 87 | Preformated:Testing one row
 88 | and another
89 | 90 |

Duis aute irure dolor in reprehenderit in voluptate velit esse 91 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 92 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

93 | 94 |
    95 |
  • This is a list item
  • 96 |
  • So is this - there could be more
  • 97 |
  • Make sure to style list items to: 98 |
      99 |
    • Not forgetting child list items
    • 100 |
    • Not forgetting child list items
    • 101 |
    • Not forgetting child list items
    • 102 |
    • Not forgetting child list items
    • 103 |
  • 104 |
  • A couple more
  • 105 |
  • top level list items
  • 106 |
107 | 108 | 109 | 110 | 117 | 118 |
111 | 112 | 113 | 114 | 115 |
116 |
119 | 120 |

Notices

121 | 122 | 123 | 124 | 131 | 132 |
125 | 126 | 127 | 128 | 129 |
Hello, this is a info notice.
130 |
133 | 134 | 141 | 142 |
135 | 136 | 137 | 138 | 139 |
Hello, this is a success notice.
140 |
143 | 144 | 151 | 152 |
145 | 146 | 147 | 148 | 149 |
Hello, this is a warning notice.
150 |
153 | 154 | 161 | 162 |
155 | 156 | 157 | 158 | 159 |
Hello, this is a danger notice.
160 |
163 | 164 | 165 | 172 | 173 |
166 | 167 | 168 | 169 | 170 |
171 |
174 | 175 |

Buttons

176 | 177 | 178 | 187 | 188 |
179 | 180 | 181 | 184 | 185 |
182 | Button (primary) 183 |
186 |
189 | 190 | 199 | 200 |
191 | 192 | 193 | 196 | 197 |
194 | Button (secondary) 195 |
198 |
201 | 202 | 203 | 210 | 211 |
204 | 205 | 206 | 207 | 208 |
209 |
212 |

Don't forget Ordered lists:

213 |
    214 |
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. 215 |
  3. Aliquam tincidunt mauris eu risus. 216 |
      217 |
    1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
    2. 218 |
    3. Aliquam tincidunt mauris eu risus.
    4. 219 |
    220 |
  4. 221 |
  5. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  6. 222 |
  7. Aliquam tincidunt mauris eu risus.
  8. 223 |
224 |

A sub heading which is not as important as the first, but is quite imporant overall

225 |

226 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 227 |

228 | 229 | 230 | 231 |

A sub heading which is not as important as the second, but should be used with consideration

232 |

233 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 234 |

235 | 236 |
237 |

This is a properly formatted blockquote, btw. Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

238 | 241 |
242 | 243 |

A sub heading which is not as important as the second, but should be used with consideration

244 |

245 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 246 |

247 |
248 |

249 | “Ooh - a blockquote! Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.” 250 |

251 |
252 | 253 | 254 | 255 |
A sub heading which is not as important as the second, but should be used with consideration
256 |

257 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 258 |

259 | 260 |
261 |
Definition list
262 |
263 | Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 264 |
265 |
Lorem ipsum dolor sit amet
266 |
267 | Consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 268 |
269 |
270 | 271 |
This heading plays a relatively small bit part role, if you use it at all
272 |

273 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. 274 |

275 |

276 | Level 1 heading 277 |

278 |

279 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 280 |

281 |

282 | Level 1 heading class="fancy" 283 |

284 |

285 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 286 |

287 |

288 | Level 1 heading class="thin" 289 |

290 |

291 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 292 |

293 |

294 | Level 1 heading class="caps" 295 |

296 |

297 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 298 |

299 |

300 | Level 02 Heading 301 |

302 |

303 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 304 |

305 |

306 | Level 2 heading class="fancy" 307 |

308 |

309 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 310 |

311 |

312 | Level 2 heading class="thin" 313 |

314 |

315 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 316 |

317 |

318 | Level 2 heading class="caps" 319 |

320 |

321 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 322 |

323 |

324 | Level 03 Heading 325 |

326 |

327 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 328 |

329 |

330 | Level 3 heading class="fancy" 331 |

332 |

333 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 334 |

335 |

336 | Level 3 heading class="thin" 337 |

338 |

339 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 340 |

341 |

342 | Level 3 heading class="caps" 343 |

344 |

345 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 346 |

347 |

348 | Level 04 Heading 349 |

350 |

351 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 352 |

353 |

354 | Level 4 heading class="fancy" 355 |

356 |

357 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 358 |

359 |

360 | Level 4 heading class="thin" 361 |

362 |

363 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 364 |

365 |

366 | Level 4 heading class="caps" 367 |

368 |

369 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 370 |

371 |
372 | Level 05 Heading 373 |
374 |

375 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 376 |

377 |
378 | Level 5 heading class="fancy" 379 |
380 |

381 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 382 |

383 |
384 | Level 5 heading class="thin" 385 |
386 |

387 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 388 |

389 |
390 | Level 5 heading class="caps" 391 |
392 |

393 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 394 |

395 |
396 | Level 06 Heading 397 |
398 |

399 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 400 |

401 |
402 | Level 6 heading class="fancy" 403 |
404 |

405 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 406 |

407 |
408 | Level 6 heading class="thin" 409 |
410 |

411 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 412 |

413 |
414 | Level 6 heading class="caps" 415 |
416 |

417 | Sed scelerisque sagittis lorem. Phasellus sodales. Nulla urna justo, vehicula in, suscipit nec, molestie sed, tellus. 418 |

419 |
420 |

421 | Paragraph inside Blockquote: Nam libero leo, elementum in, dapibus a, suscipit vitae, purus. Duis arcu. Integer dignissim fermentum enim. Morbi convallis felis vel nibh. Sed scelerisque sagittis lorem. 422 |

423 |
424 |
425 | Address: Example address 224, Sweden 426 |
427 | 428 |

429 | I am the a tag example
430 | I am the abbr tag example
431 | I am the acronym tag example
432 | I am the b tag example
433 | I am the big tag example
434 | I am the cite tag example
435 | I am the code tag example
436 | I am the del tag example
437 | I am the dfn tag example
438 | I am the em tag example
439 | I am the i tag example
440 | I am the ins tag example
441 | I am the kbd tag example
442 | I am the q tag example
443 | I am the samp tag example
444 | I am the small tag example
445 | I am the span tag example
446 | I am the strong tag example
447 | I am the sub tag example
448 | I am the sup tag example
449 | I am the tt tag example
450 | I am the var tag example
451 | I am the small class example
452 | I am the large class example
453 | I am the quiet class example
454 | I am the highlight class example
455 |

456 | 457 |
458 | 459 |
    460 |
  • Unordered list 01
  • 461 |
  • Unordered list 02
  • 462 |
  • Unordered list 03 463 |
      464 |
    • Unordered list inside list level 2
    • 465 |
    • Unordered list inside list level 2 466 |
        467 |
      • Unordered list inside list level 3
      • 468 |
      • Unordered list inside list level 3
      • 469 |
      470 |
    • 471 |
    472 |
  • 473 |
474 |
    475 |
  1. Ordered list 01
  2. 476 |
  3. Ordered list 02
  4. 477 |
  5. Ordered list 03 478 |
      479 |
    1. Ordered list inside list level 2
    2. 480 |
    3. Ordered list inside list level 2 481 |
        482 |
      1. Ordered list inside list level 3
      2. 483 |
      3. Ordered list inside list level 3
      4. 484 |
      485 |
    4. 486 |
    487 |
  6. 488 |
489 | 490 |
491 |
492 | Description list title 01 493 |
494 |
495 | Description list description 01 496 |
497 |
498 | Description list title 02 499 |
500 |
501 | Description list description 02 502 |
503 |
504 | Description list description 03 505 |
506 |
507 | 508 | 509 | I am a word document link, so readers know that I'm not a normal link.
510 | I am a pdf document link, so readers know that I'm not a normal link.
511 | I am an external website link, so readers know that I'm not a normal link.
512 | I am an rss feed link, so readers know that I'm not a normal link.
513 | I am an excel spreadsheet link, so readers know that I'm not a normal link.
514 | I am an AIM screenname link, so readers know that I'm not a normal link.
515 | I am an email address link, so readers know that I'm not a normal link.
516 | I am an internal link. Change the stylesheet's "http://yourwebsite.com" to your domain name so I don't look like an external link.
517 | 518 |
519 | 520 |
521 | 522 |

523 | This is a paragraph with class="success" and a link. 524 |

525 |

526 | This is a paragraph with class="error" and a link. 527 |

528 |

529 | This is a paragraph with class="notice" and a link. 530 |

531 |
534 |
537 | 538 | 549 |
550 |
554 | 555 | 556 | 557 | --------------------------------------------------------------------------------