|
| 1 | +// Copyright 2025 Google LLC |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +// nolint:lll // WONTFIX - for readability |
| 16 | +package digest |
| 17 | + |
| 18 | +const componentStyles = `{{- define "style_badge_wrapper" -}}align-self: stretch; padding-top: 12px; padding-bottom: 11px; padding-left: 15px; padding-right: 16px; overflow: hidden; border-top-left-radius: 4px; border-top-right-radius: 4px; justify-content: flex-start; align-items: center; display: flex;{{- end -}} |
| 19 | +{{- define "style_badge_inner_wrapper" -}}flex: 1 1 0; flex-direction: column; justify-content: center; align-items: flex-start; display: inline-flex;{{- end -}} |
| 20 | +{{- define "style_change_detail_wrapper" -}}align-self: stretch; justify-content: flex-start; align-items: center; gap: 10px; display: inline-flex; width: 100%;{{- end -}} |
| 21 | +{{- define "style_change_detail_inner" -}}flex: 1 1 0;{{- end -}} |
| 22 | +{{- define "style_banner_wrapper" -}}align-self: stretch; height: 50px; padding-top: 12px; padding-bottom: 11px; padding-left: 15px; padding-right: 16px; overflow: hidden; border-top-left-radius: 4px; border-top-right-radius: 4px; justify-content: flex-start; align-items: center; gap: 8px; display: flex;{{- end -}} |
| 23 | +{{- define "style_banner_icon_wrapper_28" -}}height: 28px; position: relative; overflow: hidden; display: flex; align-items: center;{{- end -}} |
| 24 | +{{- define "style_banner_icon_wrapper_20" -}}height: 20px; position: relative; margin-right: 4px;{{- end -}} |
| 25 | +{{- define "style_img_responsive" -}}display: block; width: auto;{{- end -}} |
| 26 | +{{- define "style_banner_text_wrapper" -}}flex: 1 1 0;{{- end -}} |
| 27 | +{{- define "style_banner_browser_logos_wrapper" -}}justify-content: flex-start; align-items: center; display: flex; margin-right: 8px;{{- end -}} |
| 28 | +{{- define "style_browser_item_row" -}}align-self: stretch; justify-content: flex-start; align-items: center; gap: 10px; display: flex;{{- end -}} |
| 29 | +{{- define "style_browser_item_logo_wrapper" -}}justify-content: flex-start; align-items: center; display: flex;{{- end -}} |
| 30 | +{{- define "style_browser_item_feature_link_wrapper" -}}align-self: stretch; justify-content: flex-start; align-items: center; gap: 10px; display: inline-flex; margin-top: 8px;{{- end -}} |
| 31 | +{{- define "style_button_wrapper" -}}margin: 20px 0; text-align: center;{{- end -}} |
| 32 | +{{- define "style_footer_wrapper" -}}align-self: stretch; padding-top: 16px; flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 12px; display: flex; {{- template "font_family_main" -}};{{- end -}} |
| 33 | +{{- define "style_footer_hr" -}}align-self: stretch; height: 1px; background: #E4E4E7;{{- end -}} |
| 34 | +{{- define "style_footer_text_wrapper" -}}align-self: stretch;{{- end -}} |
| 35 | +{{- define "style_feature_title_row_wrapper" -}}align-self: stretch; justify-content: flex-start; align-items: center; gap: 10px; display: flex;{{- end -}} |
| 36 | +{{- define "style_feature_title_row_inner" -}}flex: 1 1 0;{{- end -}}` |
| 37 | + |
| 38 | +const badgeComponent = `{{- define "badge" -}} |
| 39 | +<div style='{{- template "style_badge_wrapper" -}}; background: {{- badgeBackgroundColor .Title -}};'> |
| 40 | + <div style='{{- template "style_badge_inner_wrapper" -}}'> |
| 41 | + <div style='{{- template "style_text_badge_title" -}}'>{{.Title}}</div> |
| 42 | + {{- if .Description -}} |
| 43 | + <div style='{{- template "style_text_badge_description" -}}'>{{.Description}}</div> |
| 44 | + {{- end -}} |
| 45 | + </div> |
| 46 | +</div> |
| 47 | +{{- end -}}` |
| 48 | + |
| 49 | +const introTextComponent = `{{- define "intro_text" -}} |
| 50 | +<div style='{{- template "style_section_wrapper" -}}'> |
| 51 | + <h2 style='{{- template "style_subject_header" -}}'>{{.Subject}}</h2> |
| 52 | + <div style='{{- template "style_query_text" -}}'> |
| 53 | + Here is your update for the saved search <strong style='font-weight: bold;'>'{{.Query}}'</strong>. |
| 54 | + {{.SummaryText}}. |
| 55 | + </div> |
| 56 | +</div> |
| 57 | +{{- end -}}` |
| 58 | + |
| 59 | +const changeDetailComponent = `{{- define "change_detail" -}} |
| 60 | +<div style='{{- template "style_change_detail_wrapper" -}}'> |
| 61 | + <div style='{{- template "style_change_detail_inner" -}}'> |
| 62 | + <span style='{{- template "style_text_body" -}}'>{{.Label}}</span> |
| 63 | + <span style='{{- template "style_text_body_subtle" -}}'> ({{.From}} → {{.To}})</span> |
| 64 | + </div> |
| 65 | +</div> |
| 66 | +{{- end -}}` |
| 67 | + |
| 68 | +const baselineChangeItemComponent = `{{- define "baseline_change_item" -}} |
| 69 | +<div style='{{- template "style_section_wrapper" -}}'> |
| 70 | + <div style='{{- template "style_banner_wrapper" -}}; {{- template "color_bg_success" -}}'> |
| 71 | + <div style='{{- template "style_banner_icon_wrapper_28" -}}'> |
| 72 | + <img src="{{.ToURL}}" height="28" alt="{{.To}}" style='{{- template "style_img_responsive" -}}' /> |
| 73 | + </div> |
| 74 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 75 | + <span style='{{- template "style_text_banner_bold" -}}'>Baseline</span> |
| 76 | + <span style='{{- template "style_text_banner_normal" -}}'> {{.To}} </span> |
| 77 | + </div> |
| 78 | + </div> |
| 79 | + <div style='{{- template "style_card_body" -}}'> |
| 80 | + <div style='{{- template "style_browser_item_row" -}}'> |
| 81 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 82 | + <span style='{{- template "style_text_feature_link" -}}'>{{.FeatureName}}</span> |
| 83 | + </div> |
| 84 | + <!-- Optional Date logic could go here if passed --> |
| 85 | + </div> |
| 86 | + </div> |
| 87 | +</div> |
| 88 | +{{- end -}}` |
| 89 | + |
| 90 | +const browserItemComponent = `{{- define "browser_item" -}} |
| 91 | +<div style='{{- template "style_card_body" -}}'> |
| 92 | + <div style='{{- template "style_browser_item_row" -}}'> |
| 93 | + <div style='{{- template "style_browser_item_logo_wrapper" -}}'> |
| 94 | + <img src="{{.LogoURL}}" height="20" alt="{{.Name}}" style='{{- template "style_img_responsive" -}}' /> |
| 95 | + </div> |
| 96 | + <div style='{{- template "style_text_browser_item" -}}'> |
| 97 | + {{.Name}}: {{ template "browser_status_detail" .From }} → {{ template "browser_status_detail" .To -}} |
| 98 | + </div> |
| 99 | + </div> |
| 100 | + {{- if .FeatureName -}} |
| 101 | + <div style='{{- template "style_browser_item_feature_link_wrapper" -}}'> |
| 102 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 103 | + <a href="{{.FeatureURL}}" style='{{- template "style_text_feature_link" -}}'>{{.FeatureName}}</a> |
| 104 | + </div> |
| 105 | + </div> |
| 106 | + {{- end -}} |
| 107 | +</div> |
| 108 | +{{- end -}}` |
| 109 | + |
| 110 | +const buttonComponent = `{{- define "button" -}} |
| 111 | +<div style='{{- template "style_button_wrapper" -}}'> |
| 112 | + <a href="{{.URL}}" style='{{- template "style_button_link" -}}'> |
| 113 | + {{.Text}} |
| 114 | + </a> |
| 115 | +</div> |
| 116 | +{{- end -}}` |
| 117 | + |
| 118 | +const footerComponent = `{{- define "footer" -}} |
| 119 | +<div style='{{- template "style_footer_wrapper" -}}'> |
| 120 | + <div style='{{- template "style_footer_hr" -}}'></div> |
| 121 | + <div style='{{- template "style_footer_text_wrapper" -}}'> |
| 122 | + <span style='{{- template "style_text_footer" -}}'>You can </span> |
| 123 | + <a href="{{.UnsubscribeURL}}" style='{{- template "style_text_footer_link" -}}'>unsubscribe</a> |
| 124 | + <span style='{{- template "style_text_footer" -}}'> or change any of your alerts on </span> |
| 125 | + <a href="{{.ManageURL}}" style='{{- template "style_text_footer_link" -}}'>webstatus.dev</a> |
| 126 | + </div> |
| 127 | +</div> |
| 128 | +{{- end -}}` |
| 129 | + |
| 130 | +const bannerComponents = `{{- define "banner_baseline_widely" -}} |
| 131 | +<div style='{{- template "style_banner_wrapper" -}}{{- template "color_bg_success" -}}'> |
| 132 | + <div style='{{- template "style_banner_icon_wrapper_28" -}}'> |
| 133 | + <img src="{{.LogoURL}}" height="28" alt="Widely Available" style='{{- template "style_img_responsive" -}}' /> |
| 134 | + </div> |
| 135 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 136 | + <span style='{{- template "style_text_banner_bold" -}}'>Baseline</span> |
| 137 | + <span style='{{- template "style_text_banner_normal" -}}'> Widely available </span> |
| 138 | + </div> |
| 139 | +</div> |
| 140 | +{{- end -}} |
| 141 | +{{- define "banner_baseline_newly" -}} |
| 142 | +<div style='{{- template "style_banner_wrapper" -}}{{- template "color_bg_info" -}}'> |
| 143 | + <div style='{{- template "style_banner_icon_wrapper_28" -}}'> |
| 144 | + <img src="{{.LogoURL}}" height="28" alt="Newly Available" style='{{- template "style_img_responsive" -}}' /> |
| 145 | + </div> |
| 146 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 147 | + <span style='{{- template "style_text_banner_bold" -}}'>Baseline</span> |
| 148 | + <span style='{{- template "style_text_banner_normal" -}}'> Newly available </span> |
| 149 | + </div> |
| 150 | +</div> |
| 151 | +{{- end -}} |
| 152 | +{{- define "banner_baseline_regression" -}} |
| 153 | +<div style='{{- template "style_banner_wrapper" -}}{{- template "color_bg_neutral" -}}'> |
| 154 | + <div style='{{- template "style_banner_icon_wrapper_28" -}}'> |
| 155 | + <img src="{{.LogoURL}}" height="28" alt="Regressed" style='{{- template "style_img_responsive" -}}' /> |
| 156 | + </div> |
| 157 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 158 | + <span style='{{- template "style_text_banner_bold" -}}'>Regressed</span> |
| 159 | + <span style='{{- template "style_text_banner_normal" -}}'> to limited availability</span> |
| 160 | + </div> |
| 161 | +</div> |
| 162 | +{{- end -}} |
| 163 | +{{- define "banner_browser_implementation" -}} |
| 164 | +<div style='{{- template "style_banner_wrapper" -}}{{- template "color_bg_neutral" -}}'> |
| 165 | + <div style='{{- template "style_banner_browser_logos_wrapper" -}}'> |
| 166 | + {{- /* Always display the 4 main browser logos as requested */ -}} |
| 167 | + <div style='{{- template "style_banner_icon_wrapper_20" -}}'> |
| 168 | + <img src="{{browserLogoURL "chrome"}}" height="20" style='{{- template "style_img_responsive" -}}' /> |
| 169 | + </div> |
| 170 | + <div style='{{- template "style_banner_icon_wrapper_20" -}}'> |
| 171 | + <img src="{{browserLogoURL "edge"}}" height="20" style='{{- template "style_img_responsive" -}}' /> |
| 172 | + </div> |
| 173 | + <div style='{{- template "style_banner_icon_wrapper_20" -}}'> |
| 174 | + <img src="{{browserLogoURL "firefox"}}" height="20" style='{{- template "style_img_responsive" -}}' /> |
| 175 | + </div> |
| 176 | + <div style='{{- template "style_banner_icon_wrapper_20" -}}'> |
| 177 | + <img src="{{browserLogoURL "safari"}}" height="20" style='{{- template "style_img_responsive" -}}' /> |
| 178 | + </div> |
| 179 | + </div> |
| 180 | + <div style='{{- template "style_banner_text_wrapper" -}}; {{- template "style_text_banner_normal" -}}'>Browser support changed</div> |
| 181 | +</div> |
| 182 | +{{- end -}} |
| 183 | +{{- define "banner_generic" -}} |
| 184 | +<div style='{{- template "style_banner_wrapper" -}}{{- template "color_bg_neutral" -}}'> |
| 185 | + <div style='{{- template "style_banner_text_wrapper" -}}'> |
| 186 | + <span style='{{- template "style_text_banner_bold" -}}'>{{.Type}}</span> |
| 187 | + </div> |
| 188 | +</div> |
| 189 | +{{- end -}}` |
| 190 | +const featureTitleRowComponent = `{{- define "feature_title_row" -}} |
| 191 | +<div style='{{- template "style_feature_title_row_wrapper" -}}'> |
| 192 | + <div style='{{- template "style_feature_title_row_inner" -}}'> |
| 193 | + <a href="{{.URL}}" style='{{- template "style_text_feature_link" -}}'>{{.Name}}</a> |
| 194 | + {{- with .Docs -}} |
| 195 | + {{- if .MDNDocs -}} |
| 196 | + <span style='{{- template "style_text_doc_punctuation" -}}'> (</span> |
| 197 | + {{- range $i, $doc := .MDNDocs }} |
| 198 | + {{- if $i }}, {{ end -}} |
| 199 | + <a href="{{$doc.URL}}" style='{{- template "style_text_doc_link" -}}'>MDN</a> |
| 200 | + {{- end -}} |
| 201 | + <span style='{{- template "style_text_doc_punctuation" -}}'>)</span> |
| 202 | + {{- end -}} |
| 203 | + {{- end -}} |
| 204 | + </div> |
| 205 | + {{- if .Date -}} |
| 206 | + <div style='{{- template "style_text_date" -}}'>{{.Date}}</div> |
| 207 | + {{- end -}} |
| 208 | +</div> |
| 209 | +{{- end -}}` |
| 210 | + |
| 211 | +const browserStatusDetailComponent = `{{- define "browser_status_detail" -}} |
| 212 | + {{- formatBrowserStatus .Status -}} |
| 213 | + {{- if .Version -}} |
| 214 | + <span style='{{- template "color_text_medium" -}}'> in {{.Version}}</span> |
| 215 | + {{- end -}} |
| 216 | + {{- if .Date -}} |
| 217 | + <span style='{{- template "color_text_medium" -}}'> (on {{ formatDate .Date -}})</span> |
| 218 | + {{- end -}} |
| 219 | +{{- end -}}` |
| 220 | + |
| 221 | +const EmailComponents = badgeComponent + |
| 222 | + introTextComponent + |
| 223 | + changeDetailComponent + |
| 224 | + baselineChangeItemComponent + |
| 225 | + browserItemComponent + |
| 226 | + buttonComponent + |
| 227 | + footerComponent + |
| 228 | + bannerComponents + |
| 229 | + featureTitleRowComponent + |
| 230 | + browserStatusDetailComponent |
0 commit comments