FEATURE: Add email dark mode (#16104)
implement dark mode emails when `SiteSetting.dark_mode_emails_active` is active.
This commit is contained in:
parent
a0ef25f4f0
commit
6c0abe15e0
|
@ -29,11 +29,69 @@ module EmailHelper
|
||||||
EmailStyle.new.html
|
EmailStyle.new.html
|
||||||
.sub('%{email_content}') { capture { yield } }
|
.sub('%{email_content}') { capture { yield } }
|
||||||
.gsub('%{html_lang}', html_lang)
|
.gsub('%{html_lang}', html_lang)
|
||||||
|
.gsub('%{dark_mode_meta_tags}', SiteSetting.dark_mode_emails_active ? dark_mode_meta_tags : "")
|
||||||
|
.gsub('%{dark_mode_styles}', SiteSetting.dark_mode_emails_active ? dark_mode_styles : "")
|
||||||
.html_safe
|
.html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def dark_mode_meta_tags
|
||||||
|
"
|
||||||
|
<meta name='color-scheme' content='light dark' />
|
||||||
|
<meta name='supported-color-schemes' content='light dark' />
|
||||||
|
"
|
||||||
|
end
|
||||||
|
|
||||||
|
def dark_mode_styles
|
||||||
|
"
|
||||||
|
<style>
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
html {
|
||||||
|
background: #151515 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
span {
|
||||||
|
color: #dddddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='light-img'] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='dark-img'] {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='text-color'] {
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='header'] {
|
||||||
|
background: #151515 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='body'] {
|
||||||
|
background: #222222 !important;
|
||||||
|
color: #dddddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[dm='body_primary'] {
|
||||||
|
background: #062e3d !important;
|
||||||
|
color: #dddddd !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
"
|
||||||
|
end
|
||||||
|
|
||||||
def extract_details(topic)
|
def extract_details(topic)
|
||||||
if SiteSetting.private_email?
|
if SiteSetting.private_email?
|
||||||
[topic.slugless_url, private_topic_title(topic)]
|
[topic.slugless_url, private_topic_title(topic)]
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width"
|
content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width"
|
||||||
/>
|
/>
|
||||||
|
%{dark_mode_meta_tags}
|
||||||
<!-- prevent ios zooming + autoscaling -->
|
<!-- prevent ios zooming + autoscaling -->
|
||||||
<meta name="x-apple-disable-message-reformatting" />
|
<meta name="x-apple-disable-message-reformatting" />
|
||||||
<title></title>
|
<title></title>
|
||||||
|
@ -45,5 +46,6 @@
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
%{dark_mode_styles}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table class="with-dir" style="vertical-align:top;width:100%">
|
<table class="digest-topic-title-wrapper with-dir" style="vertical-align:top;width:100%">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="with-dir" style="padding:<%= rtl? ? '0 16px 8px 8px' : '0 8px 8px 16px' %>;width:100%;">
|
<td class="with-dir" style="padding:<%= rtl? ? '0 16px 8px 8px' : '0 8px 8px 16px' %>;width:100%;">
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table class="with-dir" style="padding:0;position:relative;vertical-align:top;width:100%">
|
<table class="digest-topic-title-wrapper with-dir" style="padding:0;position:relative;vertical-align:top;width:100%">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="digest-topic-op" style="color:#0a0a0a;line-height:1.3;margin:0 auto;padding:<%= rtl? ? '0 16px 0 0' : '0 0 0 16px' %>;width:50px;vertical-align:top;">
|
<td class="digest-topic-op" style="color:#0a0a0a;line-height:1.3;margin:0 auto;padding:<%= rtl? ? '0 16px 0 0' : '0 0 0 16px' %>;width:50px;vertical-align:top;">
|
||||||
|
@ -156,15 +156,17 @@
|
||||||
</table>
|
</table>
|
||||||
<%- end %>
|
<%- end %>
|
||||||
|
|
||||||
<table class="digest-topic-stats with-dir" style="padding:0;vertical-align:top;width:100%; margin-top:20px;">
|
<table class="digest-topic-stats with-dir" style="padding:0;vertical-align:top;width:100%; padding-top:20px;">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="digest-topic-stat" style="padding:<%= rtl? ? '0 16px 16px 8px' : '0 8px 16px 16px' %>;white-space:nowrap;vertical-align:top;width:75px">
|
<td class="digest-topic-stat" style="padding:<%= rtl? ? '0 16px 16px 8px' : '0 8px 16px 16px' %>;white-space:nowrap;vertical-align:top;width:75px">
|
||||||
<img class="digest-icon" src="<%= email_image_url 'heart.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="likes">
|
<img class="digest-icon" src="<%= email_image_url 'heart.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="likes" dm="light-img">
|
||||||
|
<img class="digest-icon" src="<%= email_image_url 'heart_dark.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto;display:none;" alt="likes" dm="dark-img">
|
||||||
<span style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"> <%= t.like_count -%></span>
|
<span style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"> <%= t.like_count -%></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="digest-topic-stat" style="padding:0 8px 16px 8px;white-space:nowrap;vertical-align:top;width:75px">
|
<td class="digest-topic-stat" style="padding:0 8px 16px 8px;white-space:nowrap;vertical-align:top;width:75px">
|
||||||
<img class="digest-icon" src="<%= email_image_url 'comment.png' -%>" style="clear:none;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="replies">
|
<img class="digest-icon" src="<%= email_image_url 'comment.png' -%>" style="clear:none;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="replies" dm="light-img">
|
||||||
|
<img class="digest-icon" src="<%= email_image_url 'comment_dark.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto;display:none;" alt="likes" dm="dark-img">
|
||||||
<span style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"> <%= t.posts_count - 1 -%></span>
|
<span style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"> <%= t.posts_count - 1 -%></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="digest-topic-posters" style="padding:0 8px 16px 8px;white-space:nowrap;vertical-align:top;">
|
<td class="digest-topic-posters" style="padding:0 8px 16px 8px;white-space:nowrap;vertical-align:top;">
|
||||||
|
@ -245,7 +247,8 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="border-spacing:0;padding:0;color:#0a0a0a;line-height:1.3;padding:<%= rtl? ? '0 65px 0 0' : '0 0 0 65px' %>;">
|
<td style="border-spacing:0;padding:0;color:#0a0a0a;line-height:1.3;padding:<%= rtl? ? '0 65px 0 0' : '0 0 0 65px' %>;">
|
||||||
<img src="<%= email_image_url 'right_triangle.png' -%>" style="clear:both;display:block;height:20px;width:20px;outline:0;text-decoration:none;" alt="">
|
<img src="<%= email_image_url 'right_triangle.png' -%>" style="clear:both;display:block;height:20px;width:20px;outline:0;text-decoration:none;" alt="" dm="light-img">
|
||||||
|
<img src="<%= email_image_url 'right_triangle_dark.png' -%>" style="clear:both;display:block;height:20px;width:20px;outline:0;text-decoration:none;display:none;" alt="" dm="dark-img">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -330,11 +333,13 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
<td class="digest-new-topic-stat with-dir" style="padding:8px;">
|
<td class="digest-new-topic-stat with-dir" style="padding:8px;">
|
||||||
<img class="digest-icon" src="<%= email_image_url 'heart.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="likes">
|
<img class="digest-icon" src="<%= email_image_url 'heart.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="likes" dm="light-img">
|
||||||
|
<img class="digest-icon" src="<%= email_image_url 'heart_dark.png' -%>" style="clear:both;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto;display:none;" alt="likes" dm="dark-img">
|
||||||
<p style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"><%= t.like_count -%></p>
|
<p style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"><%= t.like_count -%></p>
|
||||||
</td>
|
</td>
|
||||||
<td class="digest-new-topic-stat digest-replies with-dir" style="padding:8px;">
|
<td class="digest-new-topic-stat digest-replies with-dir" style="padding:8px;">
|
||||||
<img class="digest-icon" src="<%= email_image_url 'comment.png' -%>" style="clear:none;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="replies">
|
<img class="digest-icon" src="<%= email_image_url 'comment.png' -%>" style="clear:none;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto" alt="replies" dm="light-img">
|
||||||
|
<img class="digest-icon" src="<%= email_image_url 'comment_dark.png' -%>" style="clear:none;display:inline-block;float:<%= rtl? ? 'right' : 'left' %>;height:20px;margin:0;max-width:100%;opacity:.4;outline:0;text-decoration:none;width:auto;display:none;" alt="replies" dm="dark-img">
|
||||||
<p style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"><%= t.posts_count - 1 -%></p>
|
<p style="color:#8f8f8f;float:<%= rtl? ? 'right' : 'left' %>;line-height:1.3;margin:0 5px 10px 5px;padding:0;font-weight:400;"><%= t.posts_count - 1 -%></p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -283,6 +283,9 @@ basic:
|
||||||
type: enum
|
type: enum
|
||||||
enum: "ColorSchemeSetting"
|
enum: "ColorSchemeSetting"
|
||||||
client: true
|
client: true
|
||||||
|
dark_mode_emails_active:
|
||||||
|
default: false
|
||||||
|
hidden: true
|
||||||
relative_date_duration:
|
relative_date_duration:
|
||||||
client: true
|
client: true
|
||||||
default: 30
|
default: 30
|
||||||
|
|
|
@ -238,6 +238,7 @@ module Email
|
||||||
|
|
||||||
onebox_styles
|
onebox_styles
|
||||||
plugin_styles
|
plugin_styles
|
||||||
|
dark_mode_styles if SiteSetting.dark_mode_emails_active
|
||||||
|
|
||||||
style('.post-excerpt img', "max-width: 50%; max-height: #{MAX_IMAGE_DIMENSION}px;")
|
style('.post-excerpt img', "max-width: 50%; max-height: #{MAX_IMAGE_DIMENSION}px;")
|
||||||
|
|
||||||
|
@ -333,6 +334,16 @@ module Email
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def dark_mode_styles
|
||||||
|
# When we ship the email template and its styles we strip all css classes so to give our
|
||||||
|
# dark mode styles we are including in the template a selector we add a data-attr of 'dm=value' to
|
||||||
|
# the appropriate place
|
||||||
|
style(".digest-header, .digest-topic, .digest-topic-body, .digest-topic-title-wrapper, .digest-topic-stats, .popular-post-excerpt", nil, dm: "header")
|
||||||
|
style(".digest-content, .header-popular-posts, .spacer, .popular-post-spacer, .popular-post-meta, .digest-new-header, .digest-new-topic, .body", nil, dm: "body")
|
||||||
|
style(".with-accent-colors, .digest-content-header", nil, dm: "body_primary")
|
||||||
|
style(".summary-footer", nil, dm: "text-color")
|
||||||
|
end
|
||||||
|
|
||||||
def replace_relative_urls
|
def replace_relative_urls
|
||||||
forum_uri = URI(Discourse.base_url)
|
forum_uri = URI(Discourse.base_url)
|
||||||
host = forum_uri.host
|
host = forum_uri.host
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 492 B |
Binary file not shown.
After Width: | Height: | Size: 606 B |
Binary file not shown.
After Width: | Height: | Size: 197 B |
|
@ -156,6 +156,23 @@ describe Email::Styles do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "dark mode emails" do
|
||||||
|
before do
|
||||||
|
SiteSetting.dark_mode_emails_active = true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds dark_mode_styles when site setting active" do
|
||||||
|
frag = html_fragment('<div class="body">test</div>')
|
||||||
|
styler = Email::Styles.new(frag)
|
||||||
|
styler.format_basic
|
||||||
|
styler.format_html
|
||||||
|
@frag = Nokogiri::HTML5.fragment(styler.to_s)
|
||||||
|
|
||||||
|
# dark mode attribute
|
||||||
|
expect(@frag.css('[dm="body"]')).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "strip_avatars_and_emojis" do
|
context "strip_avatars_and_emojis" do
|
||||||
it "works for lonesome emoji with no title" do
|
it "works for lonesome emoji with no title" do
|
||||||
emoji = "<img src='/images/emoji/twitter/crying_cat_face.png'>"
|
emoji = "<img src='/images/emoji/twitter/crying_cat_face.png'>"
|
||||||
|
|
Loading…
Reference in New Issue