Files
RenewCMS/docs/design/source/RenewCMS Emails.dc.html
T

60 lines
4.1 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<meta name="design_doc_mode" content="canvas">
<link rel="icon" href="brand/favicon.svg">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>body{margin:0;background:#ecebe8;font-family:'IBM Plex Sans',sans-serif;font-size:13px;line-height:20px;color:#222}*{box-sizing:border-box}a{color:#111;text-underline-offset:3px}a:hover{color:#444}code{font-family:'IBM Plex Mono',monospace;font-size:12px}</style>
</helmet>
<div data-screen-label="Emails" style="padding:64px;display:flex;flex-direction:column;gap:56px;width:max-content;min-width:100%">
<div style="display:flex;flex-direction:column;gap:10px;max-width:900px">
<h1 style="margin:0;font:600 36px/44px 'IBM Plex Sans',sans-serif;letter-spacing:-0.02em;color:#111">Transactional emails</h1>
<p style="margin:0;font-size:16px;line-height:26px;color:#444;text-wrap:pretty">Two Go <code>html/template</code> files: <a href="emails/verification.html">emails/verification.html</a> and <a href="emails/password-reset.html">emails/password-reset.html</a>. They use a table layout with inline CSS and a 600 px maximum width. The button is bulletproof: a colored table cell plus a padded link, so it survives Outlook. Each has a plain-URL fallback, a hidden preheader, and <code>prefers-color-scheme</code> overrides for clients that support them. The mark is live text in a black cell rather than an image, so it shows even when images are blocked. Previews below use example values.</p>
<p style="margin:0;font-size:14px;line-height:22px;color:#666;text-wrap:pretty">Suggested subjects are "Verify your RenewCMS account" and "Reset your RenewCMS password". <code>html/template</code> escapes the <code>.Email</code> value for the query string in the reset link (the @ becomes %40), and the confirm route reads it back decoded.</p>
</div>
<sc-for list="{{ rows }}" as="r" hint-placeholder-count="2">
<section style="display:flex;flex-direction:column;gap:20px">
<div style="display:flex;flex-direction:column;gap:4px"><h2 style="margin:0;font:600 26px/34px 'IBM Plex Sans',sans-serif;color:#111">{{ r.title }}</h2><span style="font:400 13px 'IBM Plex Mono',monospace;color:#444">{{ r.vars }}</span></div>
<div style="display:flex;gap:32px;align-items:flex-start;flex-wrap:wrap">
<sc-for list="{{ r.frames }}" as="f" hint-placeholder-count="3">
<div style="display:flex;flex-direction:column;gap:8px"><span style="font-weight:600;font-size:14px;color:#111">{{ f.label }}</span><iframe title="{{ f.label }}" srcDoc="{{ f.html }}" style="width:{{ f.w }};height:760px;border:1px solid #cfccc7;background:#fff"></iframe></div>
</sc-for>
</div>
</section>
</sc-for>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script>
class Component extends DCLogic {
state = { v: '', r: '' }
componentDidMount() {
fetch('emails/verification.html').then(x => x.text()).then(v => this.setState({ v }))
fetch('emails/password-reset.html').then(x => x.text()).then(r => this.setState({ r }))
}
fill(t) {
return t.split('{{.Host}}').join('https://cms.renew.example').split('{{.VerificationCode}}').join('7f3c9a2e4b1d').split('{{.Email}}').join('marta%40renew.example').replace('uses marta%40renew.example', 'uses marta@renew.example')
}
frames(t) {
if (!t) return []
const light = this.fill(t)
const dark = light.replace('@media (prefers-color-scheme: dark)', '@media all')
return [{ label: 'Light, 680 px', html: light, w: '680px' }, { label: 'Dark, 680 px', html: dark, w: '680px' }, { label: 'Light, 375 px', html: light, w: '375px' }]
}
renderVals() {
return { rows: [
{ title: 'Verification email', vars: '{{.Host}} · {{.VerificationCode}} → /register/validate?c=', frames: this.frames(this.state.v) },
{ title: 'Password reset email', vars: '{{.Host}} · {{.VerificationCode}} · {{.Email}} → /register/reset/validate?c=&email=', frames: this.frames(this.state.r) }
] }
}
}
</script>
</body>
</html>