diff --git a/src/backend/clients/email/templates.ts b/src/backend/clients/email/templates.ts index f54017461..7e04e3820 100644 --- a/src/backend/clients/email/templates.ts +++ b/src/backend/clients/email/templates.ts @@ -52,24 +52,35 @@ const FONT = /** * Bulletproof-enough CTA: padding lives on the link so the whole button is * clickable, `mso-padding-alt` gives Outlook the same visual size (there only - * the label is clickable, which is the accepted degradation). + * the label is clickable, which is the accepted degradation). Goes full-width + * on small screens via the `.btn` media rule; `#0473c9` is the darker step of + * the GUI's `#088ef0` primary — the brand blue that clears WCAG AA on white. */ const shareCta = (label: string, href: string): string => ` - +
-`; -/** One row per sender: "**alice** shared report.txt". */ +/** + * The event as the card's headline. It repeats the subject on purpose: the + * subject is gone once the mail is open, and the grouped wording ("alice and + * bob shared 2 items with you") is the summary the rows below break down. + */ +const shareHeading = ` +

{{subject_line}}

`; + +/** One row per sender, object first: what arrived, then who it's from. */ const shareList = ` - + {{#each shares}} - {{/each}} @@ -107,8 +118,11 @@ const shareEmailShell = (opts: { img { border: 0; line-height: 100%; outline: none; text-decoration: none; } @media screen and (max-width: 600px) { .container { width: 100% !important; } - .card { padding: 24px 20px !important; } + .card { padding: 28px 20px !important; } .px { padding-left: 12px !important; padding-right: 12px !important; } + .h1 { font-size: 19px !important; line-height: 26px !important; } + .btn { width: 100% !important; } + .btn a { display: block !important; } } @media (prefers-color-scheme: dark) { .email-bg { background-color: #16181d !important; } @@ -116,10 +130,22 @@ const shareEmailShell = (opts: { .text-main { color: #e7eaee !important; } .text-muted { color: #9aa3b0 !important; } .list-panel { background-color: #262a32 !important; } - .share-row { border-color: #333845 !important; color: #e7eaee !important; } + .share-row { border-color: #333845 !important; } .wordmark { color: #e7eaee !important; } .footer-link { color: #9aa3b0 !important; } } + /* Outlook's apps don't read prefers-color-scheme; when they invert they + stamp data-ogsc (text) / data-ogsb (backgrounds) on elements, so the + dark palette is repeated under those attributes. */ + [data-ogsb] .email-bg { background-color: #16181d !important; } + [data-ogsb] .card { background-color: #1f2229 !important; } + [data-ogsb] .list-panel { background-color: #262a32 !important; } + [data-ogsc] .card { border-color: #2e323b !important; } + [data-ogsc] .text-main { color: #e7eaee !important; } + [data-ogsc] .text-muted { color: #9aa3b0 !important; } + [data-ogsc] .share-row { border-color: #333845 !important; } + [data-ogsc] .wordmark { color: #e7eaee !important; } + [data-ogsc] .footer-link { color: #9aa3b0 !important; } @@ -313,13 +339,14 @@ immediately

subject: '{{subject_line}}', html: shareEmailShell({ title: '{{subject_line}}', - preheader: 'It’s waiting for you in your Puter account.', + preheader: + 'Ready in your Puter files, under “Shared with me”.', content: ` -

Hi {{recipient}},

-

Here’s what was shared with you on Puter:

+${shareHeading} +

Hi {{recipient}} — here’s what’s new in your files:

${shareList} -${shareCta('Open Puter', '{{link}}')} -

You’ll find everything under “Shared with me” in your files.

`, +${shareCta('View shared items', '{{link}}')} +

You’ll find these anytime under “Shared with me” in your files.

`, footer: `

You’re receiving this because someone shared items with your Puter account. @@ -331,21 +358,23 @@ You’re receiving this because someone shared items with your Puter account text: ` Hi {{recipient}}, -Here's what was shared with you on Puter: +Here's what's new in your files: {{#each shares}} * {{this.sender}} shared {{this.what}} {{/each}} -Open Puter: {{link}} +View shared items: {{link}} + +You'll find these anytime under "Shared with me" in your files. You're receiving this because someone shared items with your Puter account. {{#if unsubscribe_uuid}}Unsubscribe: {{link}}/unsubscribe?user_uuid={{unsubscribe_uuid}}{{/if}} `, }, // The only way to reach someone with no account. Same digest shape. - // Careful: "Open Puter" must not appear here — it is how the holder - // digest is told apart from this one. + // Careful: "View shared items" must not appear here — it is how the + // holder digest is told apart from this one. file_shared_invite: { subject: '{{subject_line}}', html: shareEmailShell({ @@ -353,10 +382,10 @@ You're receiving this because someone shared items with your Puter account. preheader: 'Create a free Puter account with this email address to view it.', content: ` -

Hi there,

-

Here’s what was shared with you on Puter:

+${shareHeading} +

Hi there — here’s what’s waiting for you:

${shareList} -

There’s no Puter account for {{email}} yet. Create a free account with this exact address, confirm it, and everything shared with you will be waiting in your files.

+

There’s no Puter account for {{email}} yet. Create a free account with this exact address, confirm it, and everything above will be waiting in your files.

${shareCta('Create your account', '{{link}}')}

New to Puter? It’s the open-source Internet OS — your files, apps, and games in one place, from any device.

`, footer: ` @@ -368,7 +397,7 @@ You’re receiving this because a Puter user shared something with this emai text: ` Hi there, -Here's what was shared with you on Puter: +Here's what's waiting for you on Puter: {{#each shares}} * {{this.sender}} shared {{this.what}} @@ -383,34 +412,6 @@ You're receiving this because a Puter user shared something with this email address. If you weren't expecting it, you can safely ignore this email. `, }, - share_by_username: { - subject: 'Puter share from {{susername}}', - html: ` -

Hi there {{rusername}},

-

You've received a share from {{susername}} on Puter.

-

Go to puter.com to check it out.

-{{#if message}} -

The following message was included:

-
{{message}}
-{{/if}} -

Sincerely,

-

Puter

- `, - }, - share_by_email: { - subject: 'share by email', - html: ` -

Hi there,

-

You've received a share from {{sender_name}} on Puter:

-

{{link}}

-{{#if message}} -

The following message was included:

-
{{message}}
-{{/if}} -

Sincerely,

-

Puter

- `, - }, } satisfies Record; export type EmailTemplateName = keyof typeof EMAIL_TEMPLATES; diff --git a/src/backend/services/share/shareEmail.test.ts b/src/backend/services/share/shareEmail.test.ts index ded6de0b8..933f2a6c3 100644 --- a/src/backend/services/share/shareEmail.test.ts +++ b/src/backend/services/share/shareEmail.test.ts @@ -344,7 +344,9 @@ describe('share email', () => { // spent the one message they agreed to receive. await sleep(SETTLE_MS); expect( - mailTo(invitee).filter((mail) => mail.html.includes('Open Puter')), + mailTo(invitee).filter((mail) => + mail.html.includes('View shared items'), + ), ).toHaveLength(0); }); @@ -361,7 +363,7 @@ describe('share email', () => { `${owner.username} shared ${first.name} with you`, ); expect(mail.html).toContain(first.name); - expect(mail.html).toContain('Open Puter'); + expect(mail.html).toContain('View shared items'); expect(mail.html).toContain(`href="${env.origin}"`); expect(mail.html).toContain(recipient.username);