bootstrap-email 0.3.1 → 1.0.0.alpha1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/bootstrap-email +2 -0
  4. data/core/bootstrap-email.scss +27 -18
  5. data/core/bootstrap-head.scss +143 -0
  6. data/core/layout.html.erb +11 -0
  7. data/core/scss/_colors.scss +161 -0
  8. data/core/scss/_functions.scss +29 -0
  9. data/core/scss/_helper_groups.scss +21 -0
  10. data/core/{sass → scss}/_reboot_email.scss +7 -22
  11. data/core/scss/_selectors_for_utils.scss +100 -0
  12. data/core/scss/_utilities.scss +125 -0
  13. data/core/scss/_variables.scss +52 -0
  14. data/core/{sass → scss/components}/_alert.scss +0 -1
  15. data/core/{sass → scss/components}/_badge.scss +8 -15
  16. data/core/{sass → scss/components}/_button.scss +21 -17
  17. data/core/{sass → scss/components}/_card.scss +3 -2
  18. data/core/{sass → scss/components}/_container.scss +0 -0
  19. data/core/scss/components/_grid.scss +35 -0
  20. data/core/scss/components/_hr.scss +8 -0
  21. data/core/{sass → scss/components}/_image.scss +2 -1
  22. data/core/{sass → scss/components}/_preview.scss +0 -0
  23. data/core/{sass → scss/components}/_table.scss +0 -0
  24. data/core/scss/utilities/_background.scss +5 -0
  25. data/core/scss/utilities/_border-radius.scss +21 -0
  26. data/core/scss/utilities/_border.scss +13 -0
  27. data/core/scss/utilities/_color.scss +9 -0
  28. data/core/scss/utilities/_display.scss +7 -0
  29. data/core/scss/utilities/_sizing.scss +16 -0
  30. data/core/scss/utilities/_spacing.scss +18 -0
  31. data/core/scss/utilities/_text-decoration.scss +9 -0
  32. data/core/scss/utilities/_typography.scss +54 -0
  33. data/core/templates/col.html.erb +2 -2
  34. data/core/templates/row.html.erb +2 -2
  35. data/lib/bootstrap-email/bootstrap_email_cli.rb +91 -0
  36. data/lib/bootstrap-email/compiler.rb +118 -0
  37. data/lib/bootstrap-email/components/alert.rb +11 -0
  38. data/lib/bootstrap-email/components/align.rb +21 -0
  39. data/lib/bootstrap-email/components/badge.rb +11 -0
  40. data/lib/bootstrap-email/components/base.rb +26 -0
  41. data/lib/bootstrap-email/components/body.rb +22 -0
  42. data/lib/bootstrap-email/components/button.rb +11 -0
  43. data/lib/bootstrap-email/components/card.rb +14 -0
  44. data/lib/bootstrap-email/components/color.rb +13 -0
  45. data/lib/bootstrap-email/components/container.rb +14 -0
  46. data/lib/bootstrap-email/components/grid.rb +14 -0
  47. data/lib/bootstrap-email/components/hr.rb +12 -0
  48. data/lib/bootstrap-email/components/margin.rb +22 -0
  49. data/lib/bootstrap-email/components/padding.rb +16 -0
  50. data/lib/bootstrap-email/components/paragraph.rb +24 -0
  51. data/lib/bootstrap-email/components/spacer.rb +11 -0
  52. data/lib/bootstrap-email/components/spacing.rb +18 -0
  53. data/lib/bootstrap-email/components/table.rb +13 -0
  54. data/lib/bootstrap-email/initialize.rb +1 -0
  55. data/lib/bootstrap-email/rails/action_mailer.rb +10 -0
  56. data/lib/bootstrap-email/{engine.rb → rails/engine.rb} +0 -0
  57. data/lib/bootstrap-email/sass_cache.rb +47 -0
  58. data/lib/bootstrap-email/version.rb +3 -5
  59. data/lib/bootstrap_email.rb +27 -0
  60. metadata +76 -64
  61. data/core/head.scss +0 -269
  62. data/core/sass/_border.scss +0 -73
  63. data/core/sass/_color.scss +0 -33
  64. data/core/sass/_display.scss +0 -7
  65. data/core/sass/_functions.scss +0 -14
  66. data/core/sass/_grid.scss +0 -131
  67. data/core/sass/_hr.scss +0 -14
  68. data/core/sass/_spacing.scss +0 -100
  69. data/core/sass/_typography.scss +0 -50
  70. data/core/sass/_variables.scss +0 -150
  71. data/core/template.html.erb +0 -11
  72. data/core/templates/align-center.html.erb +0 -9
  73. data/core/templates/align-left.html.erb +0 -9
  74. data/core/templates/align-right.html.erb +0 -9
  75. data/core/templates/hr.html.erb +0 -9
  76. data/lib/assets/stylesheets/bootstrap-email.scss +0 -1
  77. data/lib/bootstrap-email.rb +0 -230
  78. data/lib/bootstrap-email/action_mailer.rb +0 -12
  79. data/lib/bootstrap-email/premailer_railtie.rb +0 -5
@@ -1,14 +0,0 @@
1
- div.hr {
2
- width: 100%;
3
- border: 0;
4
- margin: $font-size-base*1.25 0;
5
- & > table {
6
- width: 100%;
7
- & > tbody > tr > td {
8
- width: 100%;
9
- border-top: 1px solid #dddddd;
10
- height: 1px;
11
- width: 100%;
12
- }
13
- }
14
- }
@@ -1,100 +0,0 @@
1
- // Width Helper
2
- @each $size, $percentage in $widths {
3
- .w-#{$size} {
4
- width: $percentage;
5
- & > tbody > tr > td {
6
- width: $percentage;
7
- }
8
- }
9
- }
10
-
11
- @each $size, $percentage in $widths {
12
- .w-lg-#{$size} {
13
- width: $percentage;
14
- & > tbody > tr > td {
15
- width: $percentage;
16
- }
17
- }
18
- }
19
-
20
- // Padding Helper
21
- @each $size, $length in $spacers {
22
- .p-#{$size} {
23
- & > tbody > tr > td {
24
- padding: $length;
25
- }
26
- }
27
- .pt-#{$size},
28
- .py-#{$size} {
29
- & > tbody > tr > td {
30
- padding-top: $length;
31
- }
32
- }
33
- .pr-#{$size},
34
- .px-#{$size} {
35
- & > tbody > tr > td {
36
- padding-right: $length;
37
- }
38
- }
39
- .pb-#{$size},
40
- .py-#{$size} {
41
- & > tbody > tr > td {
42
- padding-bottom: $length;
43
- }
44
- }
45
- .pl-#{$size},
46
- .px-#{$size} {
47
- & > tbody > tr > td {
48
- padding-left: $length;
49
- }
50
- }
51
- }
52
-
53
- @each $size, $length in $spacers {
54
- .p-lg-#{$size} {
55
- & > tbody > tr > td {
56
- padding: $length;
57
- }
58
- }
59
- .pt-lg-#{$size},
60
- .py-lg-#{$size} {
61
- & > tbody > tr > td {
62
- padding-top: $length;
63
- }
64
- }
65
- .pr-lg-#{$size},
66
- .px-lg-#{$size} {
67
- & > tbody > tr > td {
68
- padding-right: $length;
69
- }
70
- }
71
- .pb-lg-#{$size},
72
- .py-lg-#{$size} {
73
- & > tbody > tr > td {
74
- padding-bottom: $length;
75
- }
76
- }
77
- .pl-lg-#{$size},
78
- .px-lg-#{$size} {
79
- & > tbody > tr > td {
80
- padding-left: $length;
81
- }
82
- }
83
- }
84
-
85
- // Spacing Helper
86
- @each $size, $length in $spacers {
87
- .s-#{$size} > tbody > tr > td {
88
- font-size: $length;
89
- line-height: $length;
90
- height: $length;
91
- }
92
- }
93
-
94
- @each $size, $length in $spacers {
95
- .s-lg-#{$size} > tbody > tr > td {
96
- font-size: $length;
97
- line-height: $length;
98
- height: $length;
99
- }
100
- }
@@ -1,50 +0,0 @@
1
- h1, h2, h3, h4, h5, h6,
2
- .h1, .h2, .h3, .h4, .h5, .h6 {
3
- margin-top: $headings-margin-top;
4
- margin-bottom: $headings-margin-bottom;
5
- font-family: $headings-font-family;
6
- font-weight: $headings-font-weight;
7
- color: $headings-color;
8
- text-align: left;
9
- vertical-align: baseline;
10
- }
11
-
12
- @for $n from 1 through 6 {
13
- h#{$n}, .h#{$n} {
14
- font-size: heading-size($n);
15
- line-height: heading-line-height($n);
16
- }
17
- }
18
-
19
- .font-weight-bold {
20
- font-weight: bold !important;
21
- }
22
-
23
- .font-weight-normal {
24
- font-weight: normal !important;
25
- }
26
-
27
- .text-left {
28
- text-align: left !important;
29
- }
30
-
31
- .text-right {
32
- text-align: right !important;
33
- }
34
-
35
- .text-center {
36
- text-align: center !important;
37
- }
38
-
39
- p {
40
- margin-bottom: $paragraph-margin-bottom;
41
- width: 100%;
42
- & > tbody > tr > td {
43
- margin: 0;
44
- padding: 0 0 $font-size-base * 1.25 0;
45
- & > p {
46
- margin: 0;
47
- padding: 0;
48
- }
49
- }
50
- }
@@ -1,150 +0,0 @@
1
- $font-size-base: 16px !default;
2
- $font-weight-base: normal !default;
3
- $font-family-sans-serif: Helvetica, Arial, sans-serif !default;
4
- $font-family-base: $font-family-sans-serif !default;
5
- $border-radius: $font-size-base * 0.25 !default;
6
- $border-radius-lg: $font-size-base * 0.3 !default;
7
- $border-radius-sm: $font-size-base * 0.2 !default;
8
- $border-width: 1px !default;
9
- $line-height-base: 1.5 !default;
10
- $headings-line-height: 1.2 !default;
11
- $headings-ratios: (1: 2.25, 2: 2, 3: 1.75, 4: 1.5, 5: 1.25, 6: 1) !default;
12
- $headings-margin-top: 0 !default;
13
- $headings-margin-bottom: 0 !default;
14
- $headings-font-family: null !default;
15
- $headings-font-weight: 500 !default;
16
- $headings-color: null !default;
17
- $paragraph-margin-bottom: 0 !default;
18
- $rounded-pill: 50 * $font-size-base !default;
19
-
20
- //
21
- // Color system
22
- //
23
-
24
- $white: #ffffff !default;
25
- $gray-100: #f8f9fa !default;
26
- $gray-200: #e9ecef !default;
27
- $gray-300: #dee2e6 !default;
28
- $gray-400: #ced4da !default;
29
- $gray-500: #adb5bd !default;
30
- $gray-600: #868e96 !default;
31
- $gray-700: #495057 !default;
32
- $gray-800: #343a40 !default;
33
- $gray-900: #212529 !default;
34
- $black: #000000 !default;
35
-
36
- $grays: (
37
- 100: $gray-100,
38
- 200: $gray-200,
39
- 300: $gray-300,
40
- 400: $gray-400,
41
- 500: $gray-500,
42
- 600: $gray-600,
43
- 700: $gray-700,
44
- 800: $gray-800,
45
- 900: $gray-900
46
- ) !default;
47
-
48
- $blue: #007bff !default;
49
- $indigo: #6610f2 !default;
50
- $purple: #6f42c1 !default;
51
- $pink: #e83e8c !default;
52
- $red: #dc3545 !default;
53
- $orange: #fd7e14 !default;
54
- $yellow: #ffc107 !default;
55
- $green: #28a745 !default;
56
- $teal: #20c997 !default;
57
- $cyan: #17a2b8 !default;
58
-
59
- $colors: (
60
- blue: $blue,
61
- indigo: $indigo,
62
- purple: $purple,
63
- pink: $pink,
64
- red: $red,
65
- orange: $orange,
66
- yellow: $yellow,
67
- green: $green,
68
- teal: $teal,
69
- cyan: $cyan,
70
- white: $white,
71
- gray: $gray-600,
72
- gray-dark: $gray-800
73
- ) !default;
74
-
75
- $theme-primary: $blue !default;
76
- $theme-secondary: $gray-600 !default;
77
- $theme-success: $green !default;
78
- $theme-danger: $red !default;
79
- $theme-warning: $yellow !default;
80
- $theme-info: $cyan !default;
81
- $theme-light: $gray-100 !default;
82
- $theme-dark: $gray-800 !default;
83
-
84
- $theme-colors: (
85
- primary: $theme-primary,
86
- secondary: $theme-secondary,
87
- success: $theme-success,
88
- danger: $theme-danger,
89
- warning: $theme-warning,
90
- info: $theme-info,
91
- light: $theme-light,
92
- dark: $theme-dark
93
- ) !default;
94
-
95
- $spacer: $font-size-base;
96
- $spacers: (
97
- 0: 0,
98
- 1: ($spacer * .25),
99
- 2: ($spacer * .5),
100
- 3: $spacer,
101
- 4: ($spacer * 1.5),
102
- 5: ($spacer * 3)
103
- ) !default;
104
-
105
- $widths: (
106
- 25: 25%,
107
- 50: 50%,
108
- 75: 75%,
109
- 100: 100%,
110
- auto: auto
111
- ) !default;
112
-
113
- $border-color: $gray-300 !default;
114
-
115
- $table-accent-bg: #f2f2f2 !default;
116
- $table-background-color: null !default;
117
- $table-border-color: $border-color !default;
118
- $table-border-width: $border-width !default;
119
-
120
- $body-color: $black !default;
121
- $body-bg: $white !default;
122
-
123
- $btn-padding-y: 8px !default;
124
- $btn-padding-x: 12px !default;
125
- $btn-font-family: $font-family-base !default;
126
- $btn-font-size: $font-size-base !default;
127
- $btn-line-height: 1.25 * $btn-font-size !default;
128
-
129
- $btn-padding-y-sm: 0.25 * $btn-font-size !default;
130
- $btn-padding-x-sm: 0.5 * $btn-font-size !default;
131
- $btn-font-size-sm: 0.875 * $btn-font-size !default;
132
- $btn-line-height-sm: $btn-line-height * 0.875 !default;
133
-
134
- $btn-padding-y-lg: 0.5 * $btn-font-size !default;
135
- $btn-padding-x-lg: $btn-font-size !default;
136
- $btn-font-size-lg: 1.25 * $btn-font-size !default;
137
- $btn-line-height-lg: $btn-line-height * 1.25 !default;
138
-
139
- $btn-border-width: $border-width !default;
140
-
141
- $btn-font-weight: $font-weight-base !default;
142
-
143
- // Allows for customizing button radius independently from global border radius
144
- $btn-border-radius: $border-radius !default;
145
- $btn-border-radius-lg: $border-radius-lg !default;
146
- $btn-border-radius-sm: $border-radius-sm !default;
147
-
148
- // Utility functions
149
- @function heading-size($n) { @return map-get($headings-ratios, $n) * $font-size-base; }
150
- @function heading-line-height($n) { @return heading-size($n) * $headings-line-height; }
@@ -1,11 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <link rel="stylesheet" href="../../css/email.css">
6
- <!-- inject-style src="./css/head.css" -->
7
- </head>
8
- <body>
9
- <%= contents %>
10
- </body>
11
- </html>
@@ -1,9 +0,0 @@
1
- <table class="mx-auto" align="center">
2
- <tbody>
3
- <tr>
4
- <td>
5
- <%= contents %>
6
- </td>
7
- </tr>
8
- </tbody>
9
- </table>
@@ -1,9 +0,0 @@
1
- <table class="float-left" align="left">
2
- <tbody>
3
- <tr>
4
- <td>
5
- <%= contents %>
6
- </td>
7
- </tr>
8
- </tbody>
9
- </table>
@@ -1,9 +0,0 @@
1
- <table class="float-right" align="right">
2
- <tbody>
3
- <tr>
4
- <td>
5
- <%= contents %>
6
- </td>
7
- </tr>
8
- </tbody>
9
- </table>
@@ -1,9 +0,0 @@
1
- <div class="<%= classes %>">
2
- <table>
3
- <tbody>
4
- <tr>
5
- <td></td>
6
- </tr>
7
- </tbody>
8
- </table>
9
- </div>
@@ -1 +0,0 @@
1
- @import '../../../core/bootstrap-email'
@@ -1,230 +0,0 @@
1
- require 'nokogiri'
2
- require 'erb'
3
- require 'ostruct'
4
- require 'action_mailer'
5
- require 'premailer'
6
- require 'premailer/rails'
7
- require 'rails'
8
-
9
- module BootstrapEmail
10
- class Compiler
11
- def initialize mail
12
- @mail = mail
13
- @source = mail.html_part || mail
14
- update_doc(@source.body.raw_source)
15
- end
16
-
17
- def update_doc source
18
- @doc = Nokogiri::HTML(source)
19
- end
20
-
21
- def perform_full_compile
22
- compile_html!
23
- inline_css!
24
- inject_head!
25
- update_mailer!
26
- end
27
-
28
- def compile_html!
29
- button
30
- badge
31
- alert
32
- card
33
- hr
34
- container
35
- grid
36
- align
37
- padding
38
- margin
39
- spacer
40
- table
41
- body
42
- end
43
-
44
- def inline_css!
45
- @source.body = @doc.to_html
46
- @mail = Premailer::Rails::Hook.perform(@mail)
47
- @mail.header[:skip_premailer] = true
48
- update_doc(@mail.html_part.body.raw_source)
49
- end
50
-
51
- def inject_head!
52
- @doc.at_css('head').add_child(bootstrap_email_head)
53
- end
54
-
55
- def update_mailer!
56
- @mail.html_part.body = @doc.to_html
57
- @mail
58
- end
59
-
60
- private
61
-
62
- def bootstrap_email_head
63
- engine = defined?(SassC::Engine).nil? ? Sass::Engine : SassC::Engine
64
- html_string = <<-HEREDOC
65
- <style type="text/css">
66
- #{engine.new(File.open(File.expand_path('../core/head.scss', __dir__)).read, {syntax: :scss, style: :compressed, cache: false, read_cache: false}).render}
67
- </style>
68
- HEREDOC
69
- html_string
70
- end
71
-
72
- def template file, locals_hash = {}
73
- namespace = OpenStruct.new(locals_hash)
74
- template_html = File.open(File.expand_path("../core/templates/#{file}.html.erb", __dir__)).read
75
- ERB.new(template_html).result(namespace.instance_eval { binding })
76
- end
77
-
78
- def each_node css_lookup, &blk
79
- # sort by youngest child and traverse backwards up the tree
80
- @doc.css(css_lookup).sort_by{ |n| n.ancestors.size }.reverse!.each(&blk)
81
- end
82
-
83
- def button
84
- each_node('.btn') do |node| # move all classes up and remove all classes from the element
85
- node.replace(template('table', classes: node['class'], contents: node.delete('class') && node.to_html))
86
- end
87
- end
88
-
89
- def badge
90
- each_node('.badge') do |node| # move all classes up and remove all classes from the element
91
- node.replace(template('table-left', classes: node['class'], contents: node.delete('class') && node.to_html))
92
- end
93
- end
94
-
95
- def alert
96
- each_node('.alert') do |node| # move all classes up and remove all classes from the element
97
- node.replace(template('table', classes: node['class'], contents: node.delete('class') && node.to_html))
98
- end
99
- end
100
-
101
- def align
102
- each_node('.float-left') do |node|
103
- align_helper(node, /float-left/, 'left')
104
- end
105
- each_node('.mx-auto') do |node|
106
- align_helper(node, /mx-auto/, 'center')
107
- end
108
- each_node('.float-right') do |node|
109
- align_helper(node, /float-right/, 'right')
110
- end
111
- end
112
-
113
- def align_helper node, klass, template
114
- if node.name != 'table' # if it is already on a table, set the proprieties on the current table
115
- node['class'] = node['class'].sub(klass, '')
116
- node.replace(template("align-#{template}", contents: node.to_html))
117
- else
118
- node['align'] = template
119
- end
120
- end
121
-
122
- def card
123
- each_node('.card') do |node| # move all classes up and remove all classes from element
124
- node.replace(template('table', classes: node['class'], contents: node.delete('class') && node.to_html))
125
- end
126
- each_node('.card-body') do |node| # move all classes up and remove all classes from element
127
- node.replace(template('table', classes: node['class'], contents: node.delete('class') && node.to_html))
128
- end
129
- end
130
-
131
- def hr
132
- each_node('hr') do |node| # drop hr in place of current
133
- node.replace(template('hr', classes: "hr #{node['class']}"))
134
- end
135
- end
136
-
137
- def container
138
- each_node('.container') do |node|
139
- node.replace(template('container', classes: node['class'], contents: node.inner_html))
140
- end
141
- each_node('.container-fluid') do |node|
142
- node.replace(template('table', classes: node['class'], contents: node.inner_html))
143
- end
144
- end
145
-
146
- def grid
147
- each_node('.row') do |node|
148
- node.replace(template('row', classes: node['class'], contents: node.inner_html))
149
- end
150
- each_node('*[class*=col]') do |node|
151
- node.replace(template('col', classes: node['class'], contents: node.inner_html))
152
- end
153
- end
154
-
155
- def padding
156
- each_node('*[class*=p-], *[class*=pt-], *[class*=pr-], *[class*=pb-], *[class*=pl-], *[class*=px-], *[class*=py-]') do |node|
157
- if node.name != 'table' # if it is already on a table, set the padding on the table, else wrap the content in a table
158
- padding_regex = /(p[trblxy]?-\d)/
159
- classes = node['class'].scan(padding_regex).join(' ')
160
- node['class'] = node['class'].gsub(padding_regex, '')
161
- node.replace(template('table', classes: classes, contents: node.to_html))
162
- end
163
- end
164
- end
165
-
166
- def margin
167
- each_node('*[class*=my-], *[class*=mt-], *[class*=mb-]') do |node|
168
- top_class = node['class'][/m[ty]{1}-(lg-)?(\d)/]
169
- bottom_class = node['class'][/m[by]{1}-(lg-)?(\d)/]
170
- node['class'] = node['class'].gsub(/(m[tby]{1}-(lg-)?\d)/, '')
171
- html = ''
172
- if top_class
173
- html += template('div', classes: "s-#{top_class.gsub(/m[ty]{1}-/, '')}", contents: nil)
174
- end
175
- html += node.to_html
176
- if bottom_class
177
- html += template('div', classes: "s-#{bottom_class.gsub(/m[by]{1}-/, '')}", contents: nil)
178
- end
179
- node.replace(html)
180
- end
181
- end
182
-
183
- def spacer
184
- spacers = {
185
- '0' => 0,
186
- '1' => (16 * 0.25),
187
- '2' => (16 * 0.5),
188
- '3' => 16,
189
- '4' => (16 * 1.5),
190
- '5' => (16 * 3)
191
- }
192
- each_node('*[class*=s-]') do |node|
193
- temp = Nokogiri::HTML::DocumentFragment.parse(template('table', classes: node['class'] + ' w-100', contents: '&nbsp;'))
194
- temp.at_css('td')['height'] = spacers[node['class'].gsub(/s-/, '')].to_i
195
- node.replace(temp)
196
- end
197
- end
198
-
199
- def table
200
- @doc.css('table').each do |node|
201
- # border="0" cellpadding="0" cellspacing="0"
202
- node['border'] = 0
203
- node['cellpadding'] = 0
204
- node['cellspacing'] = 0
205
- end
206
- end
207
-
208
- def body
209
- @doc.css('body').each do |node|
210
- node.replace('<body>' + preview_text.to_s + template('body', classes: "#{node['class']} body", contents: node.inner_html.to_s) + '</body>')
211
- end
212
- end
213
-
214
- def preview_text
215
- preview_node = @doc.at_css('preview')
216
- if preview_node.present?
217
- # apply spacing after the text max of 100 characters so it doesn't show body text
218
- preview_node.content += '&nbsp;' * (100 - preview_node.content.length.to_i)
219
- node = template('div', classes: 'preview', contents: preview_node.content)
220
- preview_node.remove
221
- return node
222
- end
223
- end
224
- end
225
- end
226
-
227
- require 'bootstrap-email/premailer_railtie'
228
- require 'bootstrap-email/action_mailer'
229
- require 'bootstrap-email/engine'
230
- require 'bootstrap-email/version'