| 1 | import type { schema } from '@ghost/db'; |
| 2 | import { Link, Section |
| 3 | import type { ReactNode |
| 4 | |
| 5 | import { ActionButton, EmailLayout |
| 6 | import { brand, mono |
| 7 | |
| 8 | export type NotificationReason |
| 9 | (typeof schema |
| 10 | |
| 11 | const BECAUSE: Record |
| 12 | assigned: 'you are assigned', |
| 13 | mentioned: 'you were mentioned', |
| 14 | team_mentioned: 'a team you are on was mentioned', |
| 15 | author: 'you opened it', |
| 16 | subscribed: 'you are subscribed', |
| 17 | watching: 'you are watching this repository', |
| 18 | }; |
| 19 | |
| 20 | /** The thread every notification email is about, and why its reader got it. */ |
| 21 | export interface ThreadProps |
| 22 | appUrl: string; |
| 23 | repository: string; |
| 24 | number: number; |
| 25 | title: string; |
| 26 | isPullRequest: boolean; |
| 27 | /** The thread's page, relative to the app. */ |
| 28 | path: string; |
| 29 | reason: NotificationReason |
| 30 | actor: string; |
| 31 | } |
| 32 | |
| 33 | export const previewThread: |
| 34 | appUrl: 'http://localhost:3000', |
| 35 | repository: 'alice/ghost', |
| 36 | number: 42, |
| 37 | title: 'Render notifications in the header', |
| 38 | isPullRequest: false, |
| 39 | path: '/alice/ghost/issues/42', |
| 40 | reason: 'subscribed', |
| 41 | actor: 'bob', |
| 42 | }; |
| 43 | |
| 44 | export function kindOf(thread |
| 45 | return thread.isPullRequest |
| 46 | } |
| 47 | |
| 48 | export function ThreadEmail({ |
| 49 | thread, |
| 50 | preview, |
| 51 | children, |
| 52 | }: { |
| 53 | thread: ThreadProps |
| 54 | preview: string |
| 55 | children: ReactNode |
| 56 | }) { |
| 57 | const url = |
| 58 | return ( |
| 59 | <EmailLayout |
| 60 | appUrl={thread.appUrl |
| 61 | heading={thread.title |
| 62 | preview={preview} |
| 63 | > |
| 64 | <Text style={ |
| 65 | {thread.repository} # |
| 66 | </Text> |
| 67 | {children} |
| 68 | <ActionButton href={ |
| 69 | <Text style={ |
| 70 | You are receiving this because {BECAUSE[thread.reason |
| 71 | <Link href={ |
| 72 | Unsubscribe |
| 73 | </Link>{' ' |
| 74 | from the {kindOf(thread)} |
| 75 | </Text> |
| 76 | </EmailLayout> |
| 77 | ); |
| 78 | } |
| 79 | |
| 80 | /** Markdown quoted as written: rendering it would carry the author's HTML into the email. */ |
| 81 | export function Quote({ |
| 82 | return ( |
| 83 | <Section |
| 84 | style={{ |
| 85 | backgroundColor: brand.secondary |
| 86 | borderLeft: `3px solid ${brand |
| 87 | borderRadius: '6px', |
| 88 | margin: '0 0 16px', |
| 89 | padding: '12px 14px', |
| 90 | }} |
| 91 | > |
| 92 | <Text style={ |
| 93 | {children} |
| 94 | </Text> |
| 95 | </Section> |
| 96 | ); |
| 97 | } |
| 98 | |
| 99 | export function Pill({ |
| 100 | color, |
| 101 | children, |
| 102 | }: { |
| 103 | color: string |
| 104 | children: ReactNode |
| 105 | }) { |
| 106 | return ( |
| 107 | <span |
| 108 | style={{ |
| 109 | backgroundColor: color, |
| 110 | borderRadius: '999px', |
| 111 | color: '#ffffff', |
| 112 | fontSize: '12px', |
| 113 | fontWeight: 600, |
| 114 | padding: '2px 10px', |
| 115 | }} |
| 116 | > |
| 117 | {children} |
| 118 | </span> |
| 119 | ); |
| 120 | } |