Unify brand palette across site emails previews and sign defaults

This commit is contained in:
2026-09-10 13:18:56 -04:00
parent a2acd1d08b
commit 9d50aeaeab
11 changed files with 107 additions and 63 deletions
+14
View File
@@ -0,0 +1,14 @@
/** Shared brand colors for web, transactional mail, social previews and signs. */
export const brandPalette = {
background: "#f4f1ea",
surface: "#fffefa",
ink: "#171716",
muted: "#5e5a52",
border: "#d8d2c7",
primary: "#3156c8",
onPrimary: "#ffffff",
accent: "#e4e9f8",
darkBackground: "#0d1018",
darkSurface: "#171b26",
darkPrimary: "#7f9cff",
} as const;
+1
View File
@@ -1,4 +1,5 @@
import { z } from "zod";
export { brandPalette } from "./brand";
export { SIGN_PAPERS, savedSignSchema, type SavedSign } from "./sign";
export const eventStatusSchema = z.enum(["draft", "published", "closed"]);
+13 -12
View File
@@ -4,7 +4,8 @@ import { Resend } from "resend";
import { EMAIL_LOGO_CID, emailLogoAttachment } from "./logo";
export { emailBrowserPreview } from "./logo";
const PRIMARY = "#8b5a4a";
import { brandPalette as palette } from "@album/contracts";
const PRIMARY = palette.primary;
function escapeHtml(value: string) {
return value
@@ -27,22 +28,22 @@ export function chrome(bodyHtml: string) {
<link href="https://fonts.googleapis.com/css2?family=Funnel+Display:wght@500;600;700&amp;family=Geologica:wght@400;600;700&amp;display=swap" rel="stylesheet">
<style>h1,h2 {font-family:'Funnel Display',Arial,Helvetica,sans-serif;line-height:1.15;letter-spacing:-.035em} @media(max-width:480px){body{padding:12px 6px!important}}</style>
</head>
<body style="margin:0;padding:24px 12px;background:#f6f1ea">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width:640px;margin:0 auto;color:#292524;background:#fff;font-family:'Geologica',Arial,Helvetica,sans-serif"><tr><td>
<div style="padding:20px 24px;border:1px solid #e8dfd2;border-top:6px solid ${PRIMARY}">
<body style="margin:0;padding:24px 12px;background:${palette.background}">
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" style="max-width:640px;margin:0 auto;color:${palette.ink};background:${palette.surface};font-family:'Geologica',Arial,Helvetica,sans-serif"><tr><td>
<div style="padding:20px 24px;border:1px solid ${palette.border};border-top:6px solid ${PRIMARY}">
<table role="presentation" cellspacing="0" cellpadding="0"><tr>
<td style="vertical-align:middle;padding-right:8px"><img src="cid:${EMAIL_LOGO_CID}" width="32" height="32" alt="" style="display:block;border:0;width:32px;height:32px"></td>
<td style="vertical-align:middle"><strong style="font-size:26px;line-height:32px;letter-spacing:-.04em;color:${PRIMARY}">Manyangles</strong></td>
<td style="vertical-align:middle"><strong style="font-size:26px;line-height:32px;letter-spacing:-.04em;color:${palette.ink}">Manyangles</strong></td>
</tr></table>
<p style="margin:8px 0 0;font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#78716c">Every angle. One shared album.</p>
<p style="margin:8px 0 0;font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:${palette.muted}">Every angle. One shared album.</p>
</div>
<div style="padding:32px;border:1px solid #e8dfd2;border-top:0;font-size:16px;line-height:1.65">
<div style="padding:32px;border:1px solid ${palette.border};border-top:0;font-size:16px;line-height:1.65">
${bodyHtml}
</div>
<div style="padding:18px 24px;text-align:center;background:#faf7f2;border:1px solid #e8dfd2;border-top:0">
<strong style="font-size:18px;color:${PRIMARY}">Manyangles</strong>
<p style="margin:8px 0;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:#7a6e5e">Keep the moment.</p>
<p style="margin:0;font-size:11px;color:#7a6e5e">Hadlock Technologies LLC</p>
<div style="padding:18px 24px;text-align:center;background:${palette.background};border:1px solid ${palette.border};border-top:0">
<strong style="font-size:18px;color:${palette.ink}">Manyangles</strong>
<p style="margin:8px 0;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:${palette.muted}">Keep the moment.</p>
<p style="margin:0;font-size:11px;color:${palette.muted}">Hadlock Technologies LLC</p>
</div>
</td></tr></table>
</body>
@@ -179,7 +180,7 @@ export async function sendPasswordResetEmail(message: {
Reset password
</a>
</p>
<p style="font-size:12px;color:#7a6e5e">
<p style="font-size:12px;color:${palette.muted}">
If you did not request this, you can ignore this message.
</p>
`),
+3 -3
View File
@@ -1,6 +1,6 @@
// 3x PNG rendering of BrandMark. Keep v1 immutable for queued email retries.
export const EMAIL_LOGO_CID = "manyangles-mark-v1";
export const EMAIL_LOGO_BASE64 = "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";
// 3x PNG rendering of BrandMark in brandPalette.ink. Queued messages retain their embedded image.
export const EMAIL_LOGO_CID = "manyangles-mark-v2";
export const EMAIL_LOGO_BASE64 = "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";
export const emailLogoAttachment = { filename: "manyangles-logo.png", content: EMAIL_LOGO_BASE64, contentId: EMAIL_LOGO_CID };
export function emailBrowserPreview(html: string) {
return html.replaceAll(`cid:${EMAIL_LOGO_CID}`, `data:image/png;base64,${EMAIL_LOGO_BASE64}`);