Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/art-deco. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
179 lines
7.6 KiB
Plaintext
179 lines
7.6 KiB
Plaintext
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
|
|
"git.dev.alexdunmow.com/block/core/templates"
|
|
)
|
|
|
|
// ArtDecoEmailWrapper wraps body content in the Art Deco email layout:
|
|
// ivory background, 600px column, jet-black masthead with flat-gold PNG sunburst,
|
|
// Cormorant body, gold hairline above footer, reservation phone postscript.
|
|
func ArtDecoEmailWrapper(body string, emailCtx templates.EmailContext) string {
|
|
var buf bytes.Buffer
|
|
_ = artDecoEmailTemplate(emailCtx, body).Render(context.Background(), &buf)
|
|
return buf.String()
|
|
}
|
|
|
|
// edColor returns a color from the email context or a hex fallback for the named token.
|
|
func edColor(value, fallback string) string {
|
|
if value != "" {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
// edBg ivory background.
|
|
func edBg(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.Background, "#f6efe2")
|
|
}
|
|
|
|
// edCard jet-black masthead surface (uses Foreground as the dark masthead colour).
|
|
func edCardDark(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
|
}
|
|
|
|
// edFg foreground text on the ivory body.
|
|
func edFg(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.Foreground, "#191510")
|
|
}
|
|
|
|
// edPrimary champagne-gold accent (used for the hairline and links).
|
|
func edPrimary(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.Primary, "#c9a14a")
|
|
}
|
|
|
|
// edMutedFg muted footer text.
|
|
func edMutedFg(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.MutedForeground, "#6c5b35")
|
|
}
|
|
|
|
// edBorder hairline gold border colour.
|
|
func edBorder(emailCtx templates.EmailContext) string {
|
|
return edColor(emailCtx.Colors.Border, "#c9a14a")
|
|
}
|
|
|
|
// flatGoldSunburstSVG is the inlined data: URI for the flat-gold sunburst image
|
|
// used as a fallback for the Outlook masthead (CSS conic-gradient is flattened by Outlook).
|
|
// We render via string concatenation so the URL-encoded %xx tokens are not misread as fmt verbs.
|
|
func flatGoldSunburstSVG(gold string) string {
|
|
g := stripHash(gold)
|
|
prefix := "data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%2080%22%3E%3Crect%20width%3D%22600%22%20height%3D%2280%22%20fill%3D%22%23191510%22%2F%3E%3Cg%20stroke%3D%22%23"
|
|
rays := "%22%20stroke-width%3D%221%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M300%2080%20L%20100%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20180%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20260%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20340%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20420%2010%22%2F%3E%3Cpath%20d%3D%22M300%2080%20L%20500%2010%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"
|
|
return prefix + g + rays
|
|
}
|
|
|
|
// stripHash removes a leading '#' if present (defensive for the data URI).
|
|
func stripHash(s string) string {
|
|
if len(s) > 0 && s[0] == '#' {
|
|
return s[1:]
|
|
}
|
|
return s
|
|
}
|
|
|
|
// artDecoEmailTemplate renders the Art Deco email wrapper.
|
|
templ artDecoEmailTemplate(emailCtx templates.EmailContext, body string) {
|
|
<!DOCTYPE html>
|
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
<head>
|
|
<meta charset="utf-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<meta name="x-apple-disable-message-reformatting"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
|
<!--[if mso]>
|
|
<noscript>
|
|
<xml>
|
|
<o:OfficeDocumentSettings>
|
|
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
</o:OfficeDocumentSettings>
|
|
</xml>
|
|
</noscript>
|
|
<![endif]-->
|
|
<title>{ emailCtx.SiteSettings.SiteName }</title>
|
|
<style type="text/css">
|
|
body, table, td, p, a, li, blockquote {
|
|
-webkit-text-size-adjust: 100%;
|
|
-ms-text-size-adjust: 100%;
|
|
}
|
|
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
|
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
|
|
body { margin: 0 !important; padding: 0 !important; width: 100% !important; }
|
|
a[x-apple-data-detectors] { color: inherit !important; text-decoration: none !important; }
|
|
@media only screen and (max-width: 620px) {
|
|
.email-container { width: 100% !important; max-width: 100% !important; }
|
|
.content-padding { padding-left: 24px !important; padding-right: 24px !important; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body style={ fmt.Sprintf("background-color: %s; margin: 0; padding: 0; font-family: 'Cormorant Garamond', 'Cormorant', Georgia, serif;", edBg(emailCtx)) }>
|
|
if emailCtx.PreviewText != "" {
|
|
<div style="display: none; max-height: 0; overflow: hidden; mso-hide: all;">
|
|
{ emailCtx.PreviewText }
|
|
</div>
|
|
}
|
|
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
|
|
<tr>
|
|
<td align="center" style={ fmt.Sprintf("padding: 32px 10px; background-color: %s;", edBg(emailCtx)) }>
|
|
<table role="presentation" class="email-container" width="600" cellspacing="0" cellpadding="0" border="0" style={ fmt.Sprintf("max-width: 600px; background-color: %s; border: 1px solid %s;", edBg(emailCtx), edBorder(emailCtx)) }>
|
|
<tr>
|
|
<td align="center" style={ fmt.Sprintf("padding: 0; background-color: %s;", edCardDark(emailCtx)) }>
|
|
<img
|
|
src={ flatGoldSunburstSVG(edPrimary(emailCtx)) }
|
|
alt=""
|
|
width="600"
|
|
height="80"
|
|
style={ fmt.Sprintf("display: block; width: 100%%; max-width: 600px; height: 80px; background-color: %s;", edCardDark(emailCtx)) }
|
|
/>
|
|
if emailCtx.SiteSettings.SiteName != "" {
|
|
<h1 style={ fmt.Sprintf("margin: 0; padding: 24px 16px; font-family: 'Italiana', 'Cinzel', Georgia, serif; font-size: 28px; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edPrimary(emailCtx)) }>
|
|
{ emailCtx.SiteSettings.SiteName }
|
|
</h1>
|
|
}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="content-padding" style={ fmt.Sprintf("padding: 40px 48px; color: %s; font-size: 16px; line-height: 1.7;", edFg(emailCtx)) }>
|
|
@templ.Raw(body)
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style={ fmt.Sprintf("padding: 0 48px;") }>
|
|
<hr style={ fmt.Sprintf("border: none; border-top: 1px solid %s; margin: 0;", edPrimary(emailCtx)) }/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td align="center" style={ fmt.Sprintf("padding: 24px 48px; color: %s; font-size: 13px;", edMutedFg(emailCtx)) }>
|
|
<p style={ fmt.Sprintf("margin: 0 0 8px; font-family: 'Italiana', 'Cinzel', Georgia, serif; text-transform: uppercase; letter-spacing: 0.18em; color: %s;", edFg(emailCtx)) }>
|
|
{ emailCtx.SiteSettings.SiteName }
|
|
</p>
|
|
if emailCtx.SiteSettings.SiteURL != "" {
|
|
<p style="margin: 0 0 8px;">
|
|
<a href={ templ.SafeURL(emailCtx.SiteSettings.SiteURL) } style={ fmt.Sprintf("color: %s; text-decoration: none; border-bottom: 1px solid %s;", edPrimary(emailCtx), edPrimary(emailCtx)) }>
|
|
{ emailCtx.SiteSettings.SiteURL }
|
|
</a>
|
|
</p>
|
|
}
|
|
if emailCtx.SiteSettings.SupportEmail != "" {
|
|
<p style={ fmt.Sprintf("margin: 12px 0 0; font-style: italic; color: %s;", edMutedFg(emailCtx)) }>
|
|
P.S. Reservations & enquiries: { emailCtx.SiteSettings.SupportEmail }
|
|
</p>
|
|
}
|
|
if emailCtx.UnsubscribeURL != "" {
|
|
<p style="margin: 16px 0 0; font-size: 11px;">
|
|
<a href={ templ.SafeURL(emailCtx.UnsubscribeURL) } style={ fmt.Sprintf("color: %s; text-decoration: none;", edMutedFg(emailCtx)) }>
|
|
Unsubscribe
|
|
</a>
|
|
</p>
|
|
}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>
|
|
}
|