@tracked/emails 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dist/components/content.d.ts +58 -0
  2. package/dist/components/content.d.ts.map +1 -0
  3. package/dist/components/content.js +166 -0
  4. package/dist/components/content.js.map +1 -0
  5. package/dist/components/index.d.ts +6 -0
  6. package/dist/components/index.d.ts.map +1 -0
  7. package/dist/components/index.js +11 -0
  8. package/dist/components/index.js.map +1 -0
  9. package/dist/components/interactive.d.ts +23 -0
  10. package/dist/components/interactive.d.ts.map +1 -0
  11. package/dist/components/interactive.js +66 -0
  12. package/dist/components/interactive.js.map +1 -0
  13. package/dist/components/layout.d.ts +27 -0
  14. package/dist/components/layout.d.ts.map +1 -0
  15. package/dist/components/layout.js +83 -0
  16. package/dist/components/layout.js.map +1 -0
  17. package/dist/components/tokens.d.ts +58 -0
  18. package/dist/components/tokens.d.ts.map +1 -0
  19. package/dist/components/tokens.js +64 -0
  20. package/dist/components/tokens.js.map +1 -0
  21. package/dist/components/typography.d.ts +31 -0
  22. package/dist/components/typography.d.ts.map +1 -0
  23. package/dist/components/typography.js +72 -0
  24. package/dist/components/typography.js.map +1 -0
  25. package/dist/emails/anniversary.d.ts +12 -0
  26. package/dist/emails/anniversary.d.ts.map +1 -0
  27. package/dist/emails/anniversary.js +41 -0
  28. package/dist/emails/anniversary.js.map +1 -0
  29. package/dist/emails/app-review-request.d.ts +11 -0
  30. package/dist/emails/app-review-request.d.ts.map +1 -0
  31. package/dist/emails/app-review-request.js +24 -0
  32. package/dist/emails/app-review-request.js.map +1 -0
  33. package/dist/emails/bodyweight-goal-reached.d.ts +1 -1
  34. package/dist/emails/bodyweight-goal-reached.d.ts.map +1 -1
  35. package/dist/emails/bodyweight-goal-reached.js +86 -159
  36. package/dist/emails/bodyweight-goal-reached.js.map +1 -1
  37. package/dist/emails/client-inactive-alert.d.ts +14 -0
  38. package/dist/emails/client-inactive-alert.d.ts.map +1 -0
  39. package/dist/emails/client-inactive-alert.js +34 -0
  40. package/dist/emails/client-inactive-alert.js.map +1 -0
  41. package/dist/emails/client-onboarded.d.ts +35 -0
  42. package/dist/emails/client-onboarded.d.ts.map +1 -0
  43. package/dist/emails/client-onboarded.js +66 -0
  44. package/dist/emails/client-onboarded.js.map +1 -0
  45. package/dist/emails/coach-invite.d.ts +1 -1
  46. package/dist/emails/coach-invite.d.ts.map +1 -1
  47. package/dist/emails/coach-invite.js +13 -121
  48. package/dist/emails/coach-invite.js.map +1 -1
  49. package/dist/emails/coach-removed-client.d.ts +1 -1
  50. package/dist/emails/coach-removed-client.d.ts.map +1 -1
  51. package/dist/emails/coach-removed-client.js +3 -76
  52. package/dist/emails/coach-removed-client.js.map +1 -1
  53. package/dist/emails/direct-message.d.ts +1 -1
  54. package/dist/emails/direct-message.d.ts.map +1 -1
  55. package/dist/emails/direct-message.js +22 -96
  56. package/dist/emails/direct-message.js.map +1 -1
  57. package/dist/emails/feature-discovery.d.ts +2 -1
  58. package/dist/emails/feature-discovery.d.ts.map +1 -1
  59. package/dist/emails/feature-discovery.js +20 -117
  60. package/dist/emails/feature-discovery.js.map +1 -1
  61. package/dist/emails/first-workout-assigned.d.ts +1 -1
  62. package/dist/emails/first-workout-assigned.d.ts.map +1 -1
  63. package/dist/emails/first-workout-assigned.js +3 -94
  64. package/dist/emails/first-workout-assigned.js.map +1 -1
  65. package/dist/emails/first-workout-completed.d.ts +1 -1
  66. package/dist/emails/first-workout-completed.d.ts.map +1 -1
  67. package/dist/emails/first-workout-completed.js +14 -125
  68. package/dist/emails/first-workout-completed.js.map +1 -1
  69. package/dist/emails/inactive-reengagement.d.ts +10 -0
  70. package/dist/emails/inactive-reengagement.d.ts.map +1 -0
  71. package/dist/emails/inactive-reengagement.js +31 -0
  72. package/dist/emails/inactive-reengagement.js.map +1 -0
  73. package/dist/emails/index.d.ts +1 -0
  74. package/dist/emails/index.d.ts.map +1 -1
  75. package/dist/emails/index.js +1 -0
  76. package/dist/emails/index.js.map +1 -1
  77. package/dist/emails/monthly-report.d.ts +2 -1
  78. package/dist/emails/monthly-report.d.ts.map +1 -1
  79. package/dist/emails/monthly-report.js +14 -166
  80. package/dist/emails/monthly-report.js.map +1 -1
  81. package/dist/emails/new-follower.d.ts +1 -1
  82. package/dist/emails/new-follower.d.ts.map +1 -1
  83. package/dist/emails/new-follower.js +7 -91
  84. package/dist/emails/new-follower.js.map +1 -1
  85. package/dist/emails/nps-survey.d.ts +9 -0
  86. package/dist/emails/nps-survey.d.ts.map +1 -0
  87. package/dist/emails/nps-survey.js +51 -0
  88. package/dist/emails/nps-survey.js.map +1 -0
  89. package/dist/emails/subscription-canceled.d.ts +1 -1
  90. package/dist/emails/subscription-canceled.d.ts.map +1 -1
  91. package/dist/emails/subscription-canceled.js +20 -127
  92. package/dist/emails/subscription-canceled.js.map +1 -1
  93. package/dist/emails/support-email.d.ts +1 -1
  94. package/dist/emails/support-email.d.ts.map +1 -1
  95. package/dist/emails/support-email.js +3 -38
  96. package/dist/emails/support-email.js.map +1 -1
  97. package/dist/emails/team-invite.d.ts.map +1 -1
  98. package/dist/emails/team-invite.js +7 -96
  99. package/dist/emails/team-invite.js.map +1 -1
  100. package/dist/emails/team-member-removed-email.d.ts +1 -1
  101. package/dist/emails/team-member-removed-email.d.ts.map +1 -1
  102. package/dist/emails/team-member-removed-email.js +3 -93
  103. package/dist/emails/team-member-removed-email.js.map +1 -1
  104. package/dist/emails/tracked-magic-link-activate.d.ts +2 -2
  105. package/dist/emails/tracked-magic-link-activate.d.ts.map +1 -1
  106. package/dist/emails/tracked-magic-link-activate.js +3 -91
  107. package/dist/emails/tracked-magic-link-activate.js.map +1 -1
  108. package/dist/emails/tracked-magic-link.d.ts +3 -3
  109. package/dist/emails/tracked-magic-link.d.ts.map +1 -1
  110. package/dist/emails/tracked-magic-link.js +3 -99
  111. package/dist/emails/tracked-magic-link.js.map +1 -1
  112. package/dist/emails/week-one-checkin.d.ts +3 -2
  113. package/dist/emails/week-one-checkin.d.ts.map +1 -1
  114. package/dist/emails/week-one-checkin.js +22 -136
  115. package/dist/emails/week-one-checkin.js.map +1 -1
  116. package/dist/emails/weekly-progress-digest.d.ts +21 -0
  117. package/dist/emails/weekly-progress-digest.d.ts.map +1 -0
  118. package/dist/emails/weekly-progress-digest.js +78 -0
  119. package/dist/emails/weekly-progress-digest.js.map +1 -0
  120. package/dist/emails/welcome.d.ts +3 -2
  121. package/dist/emails/welcome.d.ts.map +1 -1
  122. package/dist/emails/welcome.js +16 -142
  123. package/dist/emails/welcome.js.map +1 -1
  124. package/dist/index.d.ts +9 -2
  125. package/dist/index.d.ts.map +1 -1
  126. package/dist/index.js +12 -2
  127. package/dist/index.js.map +1 -1
  128. package/package.json +20 -20
  129. package/src/components/content.tsx +351 -0
  130. package/src/components/index.ts +44 -0
  131. package/src/components/interactive.tsx +260 -0
  132. package/src/components/layout.tsx +217 -0
  133. package/src/components/tokens.ts +74 -0
  134. package/src/components/typography.tsx +148 -0
  135. package/src/emails/anniversary.tsx +133 -0
  136. package/src/emails/app-review-request.tsx +100 -0
  137. package/src/emails/bodyweight-goal-reached.tsx +202 -350
  138. package/src/emails/client-inactive-alert.tsx +130 -0
  139. package/src/emails/client-onboarded.tsx +272 -0
  140. package/src/emails/coach-invite.tsx +67 -250
  141. package/src/emails/coach-removed-client.tsx +36 -197
  142. package/src/emails/direct-message.tsx +69 -227
  143. package/src/emails/feature-discovery.tsx +82 -266
  144. package/src/emails/first-workout-assigned.tsx +52 -238
  145. package/src/emails/first-workout-completed.tsx +88 -294
  146. package/src/emails/inactive-reengagement.tsx +81 -0
  147. package/src/emails/index.tsx +1 -0
  148. package/src/emails/monthly-report.tsx +198 -520
  149. package/src/emails/new-follower.tsx +60 -238
  150. package/src/emails/nps-survey.tsx +149 -0
  151. package/src/emails/subscription-canceled.tsx +88 -294
  152. package/src/emails/support-email.tsx +33 -67
  153. package/src/emails/team-invite.tsx +47 -240
  154. package/src/emails/team-member-removed-email.tsx +23 -218
  155. package/src/emails/tracked-magic-link-activate.tsx +29 -237
  156. package/src/emails/tracked-magic-link.tsx +31 -251
  157. package/src/emails/week-one-checkin.tsx +108 -329
  158. package/src/emails/weekly-progress-digest.tsx +248 -0
  159. package/src/emails/welcome.tsx +58 -326
  160. package/src/index.ts +19 -2
  161. package/dist/emails/client-accepted-invitation.d.ts +0 -10
  162. package/dist/emails/client-accepted-invitation.d.ts.map +0 -1
  163. package/dist/emails/client-accepted-invitation.js +0 -99
  164. package/dist/emails/client-accepted-invitation.js.map +0 -1
  165. package/src/emails/client-accepted-invitation.tsx +0 -258
package/dist/index.js CHANGED
@@ -1,25 +1,35 @@
1
+ // Email templates
2
+ import { AnniversaryEmail } from "./emails/anniversary.js";
3
+ import { AppReviewRequestEmail } from "./emails/app-review-request.js";
1
4
  import { BodyweightGoalReachedEmail } from "./emails/bodyweight-goal-reached.js";
2
- import { ClientAcceptedInvitationEmail } from "./emails/client-accepted-invitation.js";
5
+ import { ClientInactiveAlertEmail } from "./emails/client-inactive-alert.js";
6
+ import { ClientOnboardedEmail } from "./emails/client-onboarded.js";
3
7
  import { CoachInviteEmail } from "./emails/coach-invite.js";
4
8
  import { CoachRemovedClientEmail } from "./emails/coach-removed-client.js";
5
9
  import { DirectMessageEmail } from "./emails/direct-message.js";
6
10
  import { FeatureDiscoveryEmail } from "./emails/feature-discovery.js";
7
11
  import { FirstWorkoutAssignedEmail } from "./emails/first-workout-assigned.js";
8
12
  import { FirstWorkoutCompletedEmail } from "./emails/first-workout-completed.js";
13
+ import { InactiveReengagementEmail } from "./emails/inactive-reengagement.js";
9
14
  import { MonthlyReportEmail } from "./emails/monthly-report.js";
10
15
  import { NewFollowerEmail } from "./emails/new-follower.js";
16
+ import { NpsSurveyEmail } from "./emails/nps-survey.js";
11
17
  import { SubscriptionCanceledEmail } from "./emails/subscription-canceled.js";
12
18
  import { SupportEmail } from "./emails/support-email.js";
13
19
  import { TeamInviteEmail } from "./emails/team-invite.js";
14
20
  import { TeamMemberRemovedEmail } from "./emails/team-member-removed-email.js";
15
21
  import { TrackedMagicLink } from "./emails/tracked-magic-link.js";
16
22
  import { TrackedMagicLinkActivate } from "./emails/tracked-magic-link-activate.js";
23
+ import { WeeklyProgressDigestEmail } from "./emails/weekly-progress-digest.js";
17
24
  import { WeekOneCheckinEmail } from "./emails/week-one-checkin.js";
18
25
  import { WelcomeEmail } from "./emails/welcome.js";
19
26
  // Import validation utilities
20
27
  import { isPrivateRelayEmail, isValidEmailFormat, shouldSendEmailTo, } from "./utils/email-validation.js";
21
28
  import { isAnonymousUsername, getSafeDisplayName, } from "./utils/username-validation.js";
22
- export { BodyweightGoalReachedEmail, ClientAcceptedInvitationEmail, CoachInviteEmail, CoachRemovedClientEmail, DirectMessageEmail, FeatureDiscoveryEmail, FirstWorkoutAssignedEmail, FirstWorkoutCompletedEmail, MonthlyReportEmail, NewFollowerEmail, SubscriptionCanceledEmail, SupportEmail, TeamInviteEmail, TeamMemberRemovedEmail, TrackedMagicLink, TrackedMagicLinkActivate, WeekOneCheckinEmail, WelcomeEmail, };
29
+ // Export email templates
30
+ export { AnniversaryEmail, AppReviewRequestEmail, BodyweightGoalReachedEmail, ClientInactiveAlertEmail, ClientOnboardedEmail, CoachInviteEmail, CoachRemovedClientEmail, DirectMessageEmail, FeatureDiscoveryEmail, FirstWorkoutAssignedEmail, FirstWorkoutCompletedEmail, InactiveReengagementEmail, MonthlyReportEmail, NewFollowerEmail, NpsSurveyEmail, SubscriptionCanceledEmail, SupportEmail, TeamInviteEmail, TeamMemberRemovedEmail, TrackedMagicLink, TrackedMagicLinkActivate, WeeklyProgressDigestEmail, WeekOneCheckinEmail, WelcomeEmail, };
23
31
  // Export validation utilities
24
32
  export { isPrivateRelayEmail, isValidEmailFormat, shouldSendEmailTo, isAnonymousUsername, getSafeDisplayName, };
33
+ // Export shared components
34
+ export * from "./components/index.js";
25
35
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,8BAA8B;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC7B,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,YAAY,GACb,CAAC;AAEF,8BAA8B;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACnF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,8BAA8B;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,gCAAgC,CAAC;AAExC,yBAAyB;AACzB,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,0BAA0B,EAC1B,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,0BAA0B,EAC1B,yBAAyB,EACzB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EACzB,YAAY,EACZ,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,mBAAmB,EACnB,YAAY,GACb,CAAC;AAEF,8BAA8B;AAC9B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,CAAC;AAEF,2BAA2B;AAC3B,cAAc,uBAAuB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracked/emails",
3
- "version": "0.1.5",
3
+ "version": "0.2.1",
4
4
  "description": "Email templates for Tracked Training Platform",
5
5
  "author": "Tracked Training Platform Inc.",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "build": "rm -rf ./dist && tsc",
27
- "dev:email": "email dev",
27
+ "dev:email": "email dev --dir src/emails",
28
28
  "export": "email export",
29
29
  "typecheck": "tsc --noEmit",
30
30
  "test": "vitest run",
@@ -37,26 +37,26 @@
37
37
  "clean": "rm -rf dist node_modules .turbo"
38
38
  },
39
39
  "dependencies": {
40
- "@react-email/components": "^0.5.7",
41
- "react": "19.0.0",
42
- "react-dom": "19.0.0",
43
- "react-email": "^4.3.2"
40
+ "@react-email/components": "^1.0.2",
41
+ "react": "^19.2.3",
42
+ "react-dom": "^19.2.3",
43
+ "react-email": "^5.1.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@react-email/preview-server": "latest",
47
- "@types/node": "^22.10.2",
48
- "@types/react": "^18.3.2",
49
- "@types/react-dom": "^18.3.0",
50
- "@typescript-eslint/eslint-plugin": "^8.20.0",
51
- "@typescript-eslint/parser": "^8.20.0",
52
- "@vitest/coverage-v8": "^2.1.8",
53
- "dotenv-cli": "^7.4.2",
54
- "eslint": "^9.17.0",
55
- "eslint-plugin-react": "^7.37.2",
56
- "eslint-plugin-react-hooks": "^5.1.0",
57
- "prettier": "^3.4.2",
58
- "typescript": "^5.8.3",
59
- "vitest": "^2.1.8"
46
+ "@react-email/preview-server": "5.1.0",
47
+ "@types/node": "^25.0.3",
48
+ "@types/react": "^19.2.7",
49
+ "@types/react-dom": "^19.2.3",
50
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
51
+ "@typescript-eslint/parser": "^8.50.0",
52
+ "@vitest/coverage-v8": "^4.0.16",
53
+ "dotenv-cli": "^11.0.0",
54
+ "eslint": "^9.39.2",
55
+ "eslint-plugin-react": "^7.37.5",
56
+ "eslint-plugin-react-hooks": "^7.0.1",
57
+ "prettier": "^3.7.4",
58
+ "typescript": "^5.9.3",
59
+ "vitest": "^4.0.16"
60
60
  },
61
61
  "keywords": [
62
62
  "email",
@@ -0,0 +1,351 @@
1
+ import * as React from "react";
2
+ import { Section, Text, Row, Column } from "@react-email/components";
3
+ import { colors, borderRadius, spacing } from "./tokens";
4
+
5
+ // ============================================
6
+ // FeatureBox - Highlighted feature/info box
7
+ // ============================================
8
+ interface FeatureBoxProps {
9
+ title?: string;
10
+ children: React.ReactNode;
11
+ }
12
+
13
+ export const FeatureBox = ({ title, children }: FeatureBoxProps) => {
14
+ return (
15
+ <Section style={featureBoxStyle}>
16
+ {title && <Text style={featureBoxTitleStyle}>{title}</Text>}
17
+ {children}
18
+ </Section>
19
+ );
20
+ };
21
+
22
+ const featureBoxStyle = {
23
+ backgroundColor: colors.surface,
24
+ padding: `${spacing.md} ${spacing.lg}`,
25
+ borderRadius: borderRadius.md,
26
+ margin: `${spacing.lg} 0`,
27
+ border: `1px solid ${colors.border}`,
28
+ };
29
+
30
+ const featureBoxTitleStyle = {
31
+ color: colors.textPrimary,
32
+ fontSize: "16px",
33
+ fontWeight: "bold" as const,
34
+ marginBottom: spacing.sm,
35
+ marginTop: "0",
36
+ };
37
+
38
+ // ============================================
39
+ // TipBox - Bordered tip/callout box
40
+ // ============================================
41
+ interface TipBoxProps {
42
+ title?: string;
43
+ children: React.ReactNode;
44
+ }
45
+
46
+ export const TipBox = ({ title = "Tip", children }: TipBoxProps) => {
47
+ return (
48
+ <Section style={tipBoxStyle}>
49
+ <Text style={tipBoxTitleStyle}>{title}</Text>
50
+ <Text style={tipBoxTextStyle}>{children}</Text>
51
+ </Section>
52
+ );
53
+ };
54
+
55
+ const tipBoxStyle = {
56
+ backgroundColor: colors.surface,
57
+ padding: `${spacing.md} ${spacing.lg}`,
58
+ borderRadius: borderRadius.md,
59
+ margin: `${spacing.lg} 0`,
60
+ borderLeft: `4px solid ${colors.accent}`,
61
+ };
62
+
63
+ const tipBoxTitleStyle = {
64
+ color: colors.accent,
65
+ fontSize: "14px",
66
+ fontWeight: "bold" as const,
67
+ marginBottom: spacing.xs,
68
+ marginTop: "0",
69
+ };
70
+
71
+ const tipBoxTextStyle = {
72
+ color: colors.textSecondary,
73
+ fontSize: "14px",
74
+ lineHeight: "20px",
75
+ margin: "0",
76
+ };
77
+
78
+ // ============================================
79
+ // MetricCard - Stat display with label/value
80
+ // ============================================
81
+ interface MetricCardProps {
82
+ label: string;
83
+ value: string | number;
84
+ change?: React.ReactNode;
85
+ size?: "normal" | "small";
86
+ }
87
+
88
+ export const MetricCard = ({
89
+ label,
90
+ value,
91
+ change,
92
+ size = "normal",
93
+ }: MetricCardProps) => {
94
+ return (
95
+ <Section style={metricCardStyle}>
96
+ <Text style={metricLabelStyle}>{label}</Text>
97
+ <table>
98
+ <tr>
99
+ <td style={{ verticalAlign: "middle" }}>
100
+ <Text style={size === "small" ? metricValueSmallStyle : metricValueStyle}>
101
+ {value}
102
+ </Text>
103
+ </td>
104
+ {change && (
105
+ <td style={{ verticalAlign: "middle", paddingLeft: spacing.sm }}>
106
+ {change}
107
+ </td>
108
+ )}
109
+ </tr>
110
+ </table>
111
+ </Section>
112
+ );
113
+ };
114
+
115
+ const metricCardStyle = {
116
+ backgroundColor: colors.surface,
117
+ padding: `${spacing.sm} ${spacing.md} ${spacing.md} ${spacing.md}`,
118
+ borderRadius: borderRadius.md,
119
+ border: `1px solid ${colors.border}`,
120
+ };
121
+
122
+ const metricLabelStyle = {
123
+ color: colors.textMuted,
124
+ fontSize: "14px",
125
+ marginBottom: "2px",
126
+ marginTop: "0",
127
+ };
128
+
129
+ const metricValueStyle = {
130
+ color: colors.textPrimary,
131
+ fontSize: "24px",
132
+ fontWeight: "700" as const,
133
+ margin: "0",
134
+ };
135
+
136
+ const metricValueSmallStyle = {
137
+ color: colors.textPrimary,
138
+ fontSize: "20px",
139
+ fontWeight: "700" as const,
140
+ margin: "0",
141
+ };
142
+
143
+ // ============================================
144
+ // ChangeIndicator - Up/down/neutral indicator
145
+ // ============================================
146
+ interface ChangeIndicatorProps {
147
+ value: number | null;
148
+ previousValue: number | null;
149
+ decimals?: number;
150
+ }
151
+
152
+ export const ChangeIndicator = ({
153
+ value,
154
+ previousValue,
155
+ decimals = 1,
156
+ }: ChangeIndicatorProps) => {
157
+ if (value === null || previousValue === null) return null;
158
+
159
+ const diff = value - previousValue;
160
+ const formatted = Math.abs(diff).toFixed(decimals);
161
+
162
+ if (diff > 0) {
163
+ return <Text style={changePositiveStyle}>&#9650; {formatted}</Text>;
164
+ }
165
+ if (diff < 0) {
166
+ return <Text style={changeNegativeStyle}>&#9660; {formatted}</Text>;
167
+ }
168
+ return <Text style={changeNeutralStyle}>—</Text>;
169
+ };
170
+
171
+ const changePositiveStyle = {
172
+ color: colors.success,
173
+ fontSize: "14px",
174
+ margin: "0",
175
+ };
176
+
177
+ const changeNegativeStyle = {
178
+ color: colors.error,
179
+ fontSize: "14px",
180
+ margin: "0",
181
+ };
182
+
183
+ const changeNeutralStyle = {
184
+ color: colors.textMuted,
185
+ fontSize: "14px",
186
+ margin: "0",
187
+ };
188
+
189
+ // ============================================
190
+ // DataRow - Key-value pair row
191
+ // ============================================
192
+ interface DataRowProps {
193
+ label: string;
194
+ value: string | number;
195
+ isLast?: boolean;
196
+ }
197
+
198
+ export const DataRow = ({ label, value, isLast = false }: DataRowProps) => {
199
+ return (
200
+ <Row
201
+ style={{
202
+ padding: spacing.sm,
203
+ borderBottom: isLast ? "none" : `1px solid ${colors.border}`,
204
+ }}
205
+ >
206
+ <Column>
207
+ <Text style={dataRowLabelStyle}>{label}</Text>
208
+ </Column>
209
+ <Column style={{ textAlign: "right" as const }}>
210
+ <Text style={dataRowValueStyle}>{value}</Text>
211
+ </Column>
212
+ </Row>
213
+ );
214
+ };
215
+
216
+ const dataRowLabelStyle = {
217
+ color: colors.textSecondary,
218
+ fontSize: "14px",
219
+ margin: "0",
220
+ };
221
+
222
+ const dataRowValueStyle = {
223
+ color: colors.accent,
224
+ fontSize: "16px",
225
+ fontWeight: "600" as const,
226
+ margin: "0",
227
+ };
228
+
229
+ // ============================================
230
+ // FeatureList - Bulleted feature list
231
+ // ============================================
232
+ interface FeatureListItem {
233
+ title: string;
234
+ description?: string;
235
+ }
236
+
237
+ interface FeatureListProps {
238
+ items: FeatureListItem[];
239
+ }
240
+
241
+ export const FeatureList = ({ items }: FeatureListProps) => {
242
+ return (
243
+ <ul style={featureListStyle}>
244
+ {items.map((item, index) => (
245
+ <li key={index} style={featureListItemStyle}>
246
+ {item.description ? (
247
+ <>
248
+ <strong>{item.title}:</strong> {item.description}
249
+ </>
250
+ ) : (
251
+ item.title
252
+ )}
253
+ </li>
254
+ ))}
255
+ </ul>
256
+ );
257
+ };
258
+
259
+ const featureListStyle = {
260
+ margin: "0",
261
+ paddingLeft: "20px",
262
+ };
263
+
264
+ const featureListItemStyle = {
265
+ color: colors.textSecondary,
266
+ fontSize: "14px",
267
+ lineHeight: "24px",
268
+ marginBottom: spacing.sm,
269
+ };
270
+
271
+ // ============================================
272
+ // ListBox - Container for list items
273
+ // ============================================
274
+ interface ListBoxProps {
275
+ children: React.ReactNode;
276
+ }
277
+
278
+ export const ListBox = ({ children }: ListBoxProps) => {
279
+ return <Section style={listBoxStyle}>{children}</Section>;
280
+ };
281
+
282
+ const listBoxStyle = {
283
+ backgroundColor: colors.surface,
284
+ borderRadius: borderRadius.md,
285
+ overflow: "hidden" as const,
286
+ border: `1px solid ${colors.border}`,
287
+ };
288
+
289
+ // ============================================
290
+ // SectionHeading - Section title
291
+ // ============================================
292
+ interface SectionHeadingProps {
293
+ children: React.ReactNode;
294
+ }
295
+
296
+ export const SectionHeading = ({ children }: SectionHeadingProps) => {
297
+ return <Text style={sectionHeadingStyle}>{children}</Text>;
298
+ };
299
+
300
+ const sectionHeadingStyle = {
301
+ color: colors.textPrimary,
302
+ fontSize: "18px",
303
+ margin: `0 0 ${spacing.sm} 0`,
304
+ fontWeight: "600" as const,
305
+ textTransform: "uppercase" as const,
306
+ letterSpacing: "0.5px",
307
+ };
308
+
309
+ // ============================================
310
+ // HighlightBanner - Accent colored banner
311
+ // ============================================
312
+ interface HighlightBannerProps {
313
+ children: React.ReactNode;
314
+ }
315
+
316
+ export const HighlightBanner = ({ children }: HighlightBannerProps) => {
317
+ return <Section style={highlightBannerStyle}>{children}</Section>;
318
+ };
319
+
320
+ const highlightBannerStyle = {
321
+ backgroundColor: colors.accent,
322
+ padding: `${spacing.sm} ${spacing.lg}`,
323
+ textAlign: "center" as const,
324
+ borderRadius: borderRadius.md,
325
+ margin: `${spacing.lg} 0`,
326
+ };
327
+
328
+ // ============================================
329
+ // Avatar - Circular profile image
330
+ // ============================================
331
+ interface AvatarProps {
332
+ src: string;
333
+ alt: string;
334
+ size?: number;
335
+ }
336
+
337
+ export const Avatar = ({ src, alt, size = 64 }: AvatarProps) => {
338
+ return (
339
+ <img
340
+ src={src}
341
+ alt={alt}
342
+ width={size}
343
+ height={size}
344
+ style={{
345
+ borderRadius: "50%",
346
+ display: "block",
347
+ margin: "0 auto",
348
+ }}
349
+ />
350
+ );
351
+ };
@@ -0,0 +1,44 @@
1
+ // Design Tokens
2
+ export * from "./tokens";
3
+
4
+ // Layout Components
5
+ export {
6
+ EmailLayout,
7
+ EmailHeader,
8
+ EmailFooter,
9
+ ContentSection,
10
+ Divider,
11
+ } from "./layout";
12
+
13
+ // Typography Components
14
+ export {
15
+ Heading,
16
+ Paragraph,
17
+ Label,
18
+ HighlightText,
19
+ SmallText,
20
+ } from "./typography";
21
+
22
+ // Interactive Components
23
+ export {
24
+ PrimaryButton,
25
+ SecondaryButton,
26
+ DiscordButton,
27
+ SocialButtons,
28
+ AppStoreButtons,
29
+ TextLink,
30
+ } from "./interactive";
31
+
32
+ // Content Components
33
+ export {
34
+ FeatureBox,
35
+ TipBox,
36
+ MetricCard,
37
+ ChangeIndicator,
38
+ DataRow,
39
+ FeatureList,
40
+ ListBox,
41
+ SectionHeading,
42
+ HighlightBanner,
43
+ Avatar,
44
+ } from "./content";