react-email 4.0.0-alpha.4 → 4.0.0-alpha.5

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 (170) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cli/index.js +5 -4
  3. package/dist/cli/index.mjs +9 -5
  4. package/dist/preview/.next/BUILD_ID +1 -1
  5. package/dist/preview/.next/app-build-manifest.json +31 -34
  6. package/dist/preview/.next/app-path-routes-manifest.json +1 -1
  7. package/dist/preview/.next/build-manifest.json +14 -14
  8. package/dist/preview/.next/cache/.rscinfo +1 -1
  9. package/dist/preview/.next/cache/images/TcyzHbFXGFjrOu3wEMvDoSmqCh3qP3iiNqJf0QbED9Y/60.1741728556140.cQ5qicbpvoXZ7leVmWqG2ElLwXB1ynYeSv8MBSA-QeM.Vy8iMWM3MGUtMTk1ODcxYmIyNzMi.webp +0 -0
  10. package/dist/preview/.next/cache/webpack/client-development/0.pack.gz +0 -0
  11. package/dist/preview/.next/cache/webpack/client-development/1.pack.gz +0 -0
  12. package/dist/preview/.next/cache/webpack/client-development/10.pack.gz +0 -0
  13. package/dist/preview/.next/cache/webpack/client-development/11.pack.gz +0 -0
  14. package/dist/preview/.next/cache/webpack/client-development/12.pack.gz +0 -0
  15. package/dist/preview/.next/cache/webpack/client-development/13.pack.gz +0 -0
  16. package/dist/preview/.next/cache/webpack/client-development/2.pack.gz +0 -0
  17. package/dist/preview/.next/cache/webpack/client-development/3.pack.gz +0 -0
  18. package/dist/preview/.next/cache/webpack/client-development/4.pack.gz +0 -0
  19. package/dist/preview/.next/cache/webpack/client-development/5.pack.gz +0 -0
  20. package/dist/preview/.next/cache/webpack/client-development/6.pack.gz +0 -0
  21. package/dist/preview/.next/cache/webpack/client-development/7.pack.gz +0 -0
  22. package/dist/preview/.next/cache/webpack/client-development/8.pack.gz +0 -0
  23. package/dist/preview/.next/cache/webpack/client-development/9.pack.gz +0 -0
  24. package/dist/preview/.next/cache/webpack/client-development/index.pack.gz +0 -0
  25. package/dist/preview/.next/cache/webpack/client-development/index.pack.gz.old +0 -0
  26. package/dist/preview/.next/cache/webpack/client-production/0.pack +0 -0
  27. package/dist/preview/.next/cache/webpack/client-production/index.pack +0 -0
  28. package/dist/preview/.next/cache/webpack/edge-server-production/index.pack +0 -0
  29. package/dist/preview/.next/cache/webpack/server-development/0.pack.gz +0 -0
  30. package/dist/preview/.next/cache/webpack/server-development/1.pack.gz +0 -0
  31. package/dist/preview/.next/cache/webpack/server-development/2.pack.gz +0 -0
  32. package/dist/preview/.next/cache/webpack/server-development/3.pack.gz +0 -0
  33. package/dist/preview/.next/cache/webpack/server-development/4.pack.gz +0 -0
  34. package/dist/preview/.next/cache/webpack/server-development/5.pack.gz +0 -0
  35. package/dist/preview/.next/cache/webpack/server-development/6.pack.gz +0 -0
  36. package/dist/preview/.next/cache/webpack/server-development/7.pack.gz +0 -0
  37. package/dist/preview/.next/cache/webpack/server-development/8.pack.gz +0 -0
  38. package/dist/preview/.next/cache/webpack/server-development/9.pack.gz +0 -0
  39. package/dist/preview/.next/cache/webpack/server-development/index.pack.gz +0 -0
  40. package/dist/preview/.next/cache/webpack/server-development/index.pack.gz.old +0 -0
  41. package/dist/preview/.next/cache/webpack/server-production/0.pack +0 -0
  42. package/dist/preview/.next/cache/webpack/server-production/index.pack +0 -0
  43. package/dist/preview/.next/diagnostics/framework.json +1 -1
  44. package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
  45. package/dist/preview/.next/next-server.js.nft.json +1 -1
  46. package/dist/preview/.next/prerender-manifest.json +1 -1
  47. package/dist/preview/.next/required-server-files.json +1 -1
  48. package/dist/preview/.next/server/app/_not-found/page.js +1 -1
  49. package/dist/preview/.next/server/app/_not-found/page.js.nft.json +1 -1
  50. package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  51. package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
  52. package/dist/preview/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  53. package/dist/preview/.next/server/app/page.js +1 -1
  54. package/dist/preview/.next/server/app/page.js.nft.json +1 -1
  55. package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
  56. package/dist/preview/.next/server/app/preview/[...slug]/page.js +9 -8
  57. package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
  58. package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
  59. package/dist/preview/.next/server/app-paths-manifest.json +1 -1
  60. package/dist/preview/.next/server/chunks/143.js +6 -0
  61. package/dist/preview/.next/server/chunks/409.js +5 -0
  62. package/dist/preview/.next/server/chunks/46.js +1 -0
  63. package/dist/preview/.next/server/chunks/478.js +14 -0
  64. package/dist/preview/.next/server/chunks/707.js +13 -0
  65. package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
  66. package/dist/preview/.next/server/next-font-manifest.js +1 -1
  67. package/dist/preview/.next/server/next-font-manifest.json +1 -1
  68. package/dist/preview/.next/server/pages/500.html +1 -1
  69. package/dist/preview/.next/server/pages/_app.js +1 -1
  70. package/dist/preview/.next/server/pages/_app.js.nft.json +1 -1
  71. package/dist/preview/.next/server/pages/_document.js +1 -1
  72. package/dist/preview/.next/server/pages/_document.js.nft.json +1 -1
  73. package/dist/preview/.next/server/pages/_error.js +1 -1
  74. package/dist/preview/.next/server/pages/_error.js.nft.json +1 -1
  75. package/dist/preview/.next/server/server-reference-manifest.js +1 -1
  76. package/dist/preview/.next/server/server-reference-manifest.json +1 -1
  77. package/dist/preview/.next/static/{Pt6wqIrWnQxbiyqaKNFOx → B4EYZiVzdylEG9lAIl-aO}/_buildManifest.js +1 -1
  78. package/dist/preview/.next/static/chunks/575-bc52750855c25df4.js +2 -0
  79. package/dist/preview/.next/static/chunks/684-0f1ef7361c499798.js +1 -0
  80. package/dist/preview/.next/static/chunks/684c6b30-0c65da32762fc4ee.js +1 -0
  81. package/dist/preview/.next/static/chunks/81-e7539b08d9d3fb4d.js +1 -0
  82. package/dist/preview/.next/static/chunks/883-70c8267c50bc4133.js +1 -0
  83. package/dist/preview/.next/static/chunks/921-d1dc8c63f49e85d6.js +1 -0
  84. package/dist/preview/.next/static/chunks/{afa401a5-9ebf2515b1397993.js → afa401a5-a600c227dacf3ab4.js} +1 -1
  85. package/dist/preview/.next/static/chunks/app/_not-found/{page-96d3eac723be3ee2.js → page-03ce767859c36d4e.js} +1 -1
  86. package/dist/preview/.next/static/chunks/app/layout-7cf14e28880544f1.js +1 -0
  87. package/dist/preview/.next/static/chunks/app/page-065cb49b0a078541.js +1 -0
  88. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-656510fd180c803c.js +1 -0
  89. package/dist/preview/.next/static/chunks/{framework-e7cae9cecd5c9ba2.js → framework-2a724981073c3a29.js} +1 -1
  90. package/dist/preview/.next/static/chunks/main-552b9719bbc3a274.js +1 -0
  91. package/dist/preview/.next/static/chunks/main-app-914a73336fd45af5.js +1 -0
  92. package/dist/preview/.next/static/chunks/pages/_app-77ca34bce25ac75c.js +1 -0
  93. package/dist/preview/.next/static/chunks/pages/_error-73f611c46abbb495.js +1 -0
  94. package/dist/preview/.next/static/chunks/{webpack-9255716c9496e606.js → webpack-2eb145a20ee6cb77.js} +1 -1
  95. package/dist/preview/.next/static/css/2df96d9ee014e8de.css +3 -0
  96. package/dist/preview/.next/static/media/05613964ce6c782e-s.p.otf +0 -0
  97. package/dist/preview/.next/static/media/11c6126b9369e85e-s.p.otf +0 -0
  98. package/dist/preview/.next/static/media/26cb97734d8cb717-s.p.otf +0 -0
  99. package/dist/preview/.next/static/media/bb6462617151f6b7-s.p.otf +0 -0
  100. package/dist/preview/.next/static/media/cf6daef822ab0142-s.p.otf +0 -0
  101. package/dist/preview/.next/static/media/e4051546b3043204-s.p.otf +0 -0
  102. package/dist/preview/.next/trace +22 -22
  103. package/package.json +5 -4
  104. package/src/actions/email-validation/check-images.spec.tsx +23 -14
  105. package/src/actions/email-validation/check-images.ts +89 -87
  106. package/src/actions/email-validation/check-links.spec.tsx +27 -17
  107. package/src/actions/email-validation/check-links.ts +60 -57
  108. package/src/app/fonts/SFMono/SFMonoBold.otf +0 -0
  109. package/src/app/fonts/SFMono/SFMonoBoldItalic.otf +0 -0
  110. package/src/app/fonts/SFMono/SFMonoHeavy.otf +0 -0
  111. package/src/app/fonts/SFMono/SFMonoHeavyItalic.otf +0 -0
  112. package/src/app/fonts/SFMono/SFMonoLight.otf +0 -0
  113. package/src/app/fonts/SFMono/SFMonoLightItalic.otf +0 -0
  114. package/src/app/fonts/SFMono/SFMonoMedium.otf +0 -0
  115. package/src/app/fonts/SFMono/SFMonoMediumItalic.otf +0 -0
  116. package/src/app/fonts/SFMono/SFMonoRegular.otf +0 -0
  117. package/src/app/fonts/SFMono/SFMonoRegularItalic.otf +0 -0
  118. package/src/app/fonts/SFMono/SFMonoSemibold.otf +0 -0
  119. package/src/app/fonts/SFMono/SFMonoSemiboldItalic.otf +0 -0
  120. package/src/app/fonts.ts +39 -0
  121. package/src/app/layout.tsx +5 -2
  122. package/src/app/page.tsx +3 -3
  123. package/src/app/preview/[...slug]/preview.tsx +50 -32
  124. package/src/components/icons/icon-base.tsx +4 -2
  125. package/src/components/icons/icon-reload.tsx +19 -0
  126. package/src/components/icons/icon-scanner.tsx +19 -0
  127. package/src/components/icons/icon-scissors.tsx +19 -0
  128. package/src/components/icons/icon-warning.tsx +31 -0
  129. package/src/components/send.tsx +1 -2
  130. package/src/components/shell.tsx +52 -88
  131. package/src/components/sidebar/file-tree-directory-children.tsx +1 -1
  132. package/src/components/sidebar/file-tree.tsx +1 -1
  133. package/src/components/sidebar/sidebar.tsx +23 -378
  134. package/src/components/toolbar/linter.tsx +167 -0
  135. package/src/components/toolbar/results-table.tsx +0 -0
  136. package/src/components/toolbar/results.tsx +48 -0
  137. package/src/components/toolbar/spam-assassin.tsx +155 -0
  138. package/src/components/toolbar.tsx +189 -0
  139. package/src/components/tooltip-content.tsx +1 -2
  140. package/src/components/topbar.tsx +28 -41
  141. package/tailwind.config.ts +1 -0
  142. package/dist/preview/.next/server/chunks/196.js +0 -5
  143. package/dist/preview/.next/server/chunks/300.js +0 -13
  144. package/dist/preview/.next/server/chunks/631.js +0 -6
  145. package/dist/preview/.next/server/chunks/644.js +0 -1
  146. package/dist/preview/.next/server/chunks/734.js +0 -15
  147. package/dist/preview/.next/static/chunks/285-dbf6306a0d45c33d.js +0 -1
  148. package/dist/preview/.next/static/chunks/447-886131c35ca42b91.js +0 -1
  149. package/dist/preview/.next/static/chunks/490-d5745684930d49e0.js +0 -1
  150. package/dist/preview/.next/static/chunks/5fec7a0a-5179023f3f5a9421.js +0 -1
  151. package/dist/preview/.next/static/chunks/603-36207c8905355e23.js +0 -1
  152. package/dist/preview/.next/static/chunks/797-46f6c20952f0a280.js +0 -2
  153. package/dist/preview/.next/static/chunks/app/layout-d06046b8a368df3b.js +0 -1
  154. package/dist/preview/.next/static/chunks/app/page-ef1c23b954fbd0b5.js +0 -1
  155. package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-ea8e1ae2b5a4a0ec.js +0 -1
  156. package/dist/preview/.next/static/chunks/main-app-9f2fb5ea26e2765b.js +0 -1
  157. package/dist/preview/.next/static/chunks/main-df761fde212f9cda.js +0 -1
  158. package/dist/preview/.next/static/chunks/pages/_app-203a61b355820ccf.js +0 -1
  159. package/dist/preview/.next/static/chunks/pages/_error-1764ca54938748c8.js +0 -1
  160. package/dist/preview/.next/static/css/e4822d5ba3082a95.css +0 -3
  161. package/dist/preview/.next/static/css/ec5d7e66bd3b6cb8.css +0 -1
  162. package/src/app/inter.ts +0 -7
  163. package/src/components/icons/icon-circle-check.tsx +0 -21
  164. package/src/components/icons/icon-circle-close.tsx +0 -17
  165. package/src/components/icons/icon-circle-warning.tsx +0 -17
  166. package/src/components/sidebar/image-checker.tsx +0 -162
  167. package/src/components/sidebar/link-checker.tsx +0 -151
  168. package/src/components/sidebar/spam-assassin.tsx +0 -158
  169. /package/dist/preview/.next/static/{Pt6wqIrWnQxbiyqaKNFOx → B4EYZiVzdylEG9lAIl-aO}/_ssgManifest.js +0 -0
  170. /package/src/components/{sidebar → toolbar}/checking-results.tsx +0 -0
@@ -6,13 +6,18 @@ import { flushSync } from 'react-dom';
6
6
  import { Toaster } from 'sonner';
7
7
  import { useDebouncedCallback } from 'use-debounce';
8
8
  import type { EmailRenderingResult } from '../../../actions/render-email-by-path';
9
+ import { Topbar } from '../../../components';
9
10
  import { CodeContainer } from '../../../components/code-container';
10
11
  import {
11
12
  ResizableWarpper,
12
13
  makeIframeDocumentBubbleEvents,
13
14
  } from '../../../components/resizable-wrapper';
14
- import { Shell } from '../../../components/shell';
15
+ import { Send } from '../../../components/send';
16
+ import { Shell, ShellContent } from '../../../components/shell';
17
+ import { Toolbar } from '../../../components/toolbar';
15
18
  import { Tooltip } from '../../../components/tooltip';
19
+ import { ActiveViewToggleGroup } from '../../../components/topbar/active-view-toggle-group';
20
+ import { ViewSizeControls } from '../../../components/topbar/view-size-controls';
16
21
  import { useClampedState } from '../../../hooks/use-clamped-state';
17
22
  import { useEmailRenderingResult } from '../../../hooks/use-email-rendering-result';
18
23
  import { useHotreload } from '../../../hooks/use-hot-reload';
@@ -80,7 +85,8 @@ const Preview = ({
80
85
  router.push(`${pathname}?${params.toString()}`);
81
86
  };
82
87
 
83
- const hasNoErrors = typeof renderedEmailMetadata !== 'undefined';
88
+ const hasRenderingMetadata = typeof renderedEmailMetadata !== 'undefined';
89
+ const hasErrors = 'error' in renderingResult;
84
90
 
85
91
  const [maxWidth, setMaxWidth] = useState(Number.POSITIVE_INFINITY);
86
92
  const [maxHeight, setMaxHeight] = useState(Number.POSITIVE_INFINITY);
@@ -107,31 +113,37 @@ const Preview = ({
107
113
  }, 300);
108
114
 
109
115
  return (
110
- <Shell
111
- activeView={activeView}
112
- currentEmailOpenSlug={slug}
113
- markup={renderedEmailMetadata?.markup}
114
- plainText={renderedEmailMetadata?.plainText}
115
- pathSeparator={pathSeparator}
116
- setActiveView={handleViewChange}
117
- setViewHeight={(height) => {
118
- setHeight(height);
119
- flushSync(() => {
120
- handleSaveViewSize();
121
- });
122
- }}
123
- setViewWidth={(width) => {
124
- setWidth(width);
125
- flushSync(() => {
126
- handleSaveViewSize();
127
- });
128
- }}
129
- viewHeight={height}
130
- viewWidth={width}
131
- >
132
- {/* This relative is so that when there is any error the user can still switch between emails */}
133
- <div
134
- className="relative flex h-full bg-gray-200 pb-8"
116
+ <Shell currentEmailOpenSlug={slug}>
117
+ <Topbar pathSeparator={pathSeparator} currentEmailOpenSlug={slug}>
118
+ <ViewSizeControls
119
+ setViewHeight={(height) => {
120
+ setHeight(height);
121
+ flushSync(() => {
122
+ handleSaveViewSize();
123
+ });
124
+ }}
125
+ setViewWidth={(width) => {
126
+ setWidth(width);
127
+ flushSync(() => {
128
+ handleSaveViewSize();
129
+ });
130
+ }}
131
+ viewHeight={height}
132
+ viewWidth={width}
133
+ />
134
+ <ActiveViewToggleGroup
135
+ activeView={activeView}
136
+ setActiveView={handleViewChange}
137
+ />
138
+ {hasRenderingMetadata ? (
139
+ <div className="flex justify-end">
140
+ <Send markup={renderedEmailMetadata.markup} />
141
+ </div>
142
+ ) : null}
143
+ </Topbar>
144
+
145
+ <ShellContent
146
+ className="relative flex bg-gray-200"
135
147
  ref={(element) => {
136
148
  const observer = new ResizeObserver((entry) => {
137
149
  const [elementEntry] = entry;
@@ -150,11 +162,9 @@ const Preview = ({
150
162
  };
151
163
  }}
152
164
  >
153
- {'error' in renderingResult ? (
154
- <RenderingError error={renderingResult.error} />
155
- ) : null}
165
+ {hasErrors ? <RenderingError error={renderingResult.error} /> : null}
156
166
 
157
- {hasNoErrors ? (
167
+ {hasRenderingMetadata ? (
158
168
  <>
159
169
  {activeView === 'preview' && (
160
170
  <ResizableWarpper
@@ -224,7 +234,15 @@ const Preview = ({
224
234
  ) : null}
225
235
 
226
236
  <Toaster />
227
- </div>
237
+ </ShellContent>
238
+
239
+ {!hasErrors && hasRenderingMetadata ? (
240
+ <Toolbar
241
+ emailSlug={slug}
242
+ markup={renderedEmailMetadata.markup}
243
+ plainText={renderedEmailMetadata.plainText}
244
+ />
245
+ ) : undefined}
228
246
  </Shell>
229
247
  );
230
248
  };
@@ -8,7 +8,7 @@ export interface IconProps extends RootProps {
8
8
  }
9
9
 
10
10
  export const IconBase = React.forwardRef<IconElement, Readonly<IconProps>>(
11
- ({ size = 20, ...props }, forwardedRef) => (
11
+ ({ size = 20, children, ...props }, forwardedRef) => (
12
12
  <svg
13
13
  fill="none"
14
14
  height={size}
@@ -17,7 +17,9 @@ export const IconBase = React.forwardRef<IconElement, Readonly<IconProps>>(
17
17
  width={size}
18
18
  xmlns="http://www.w3.org/2000/svg"
19
19
  {...props}
20
- />
20
+ >
21
+ {children}
22
+ </svg>
21
23
  ),
22
24
  );
23
25
 
@@ -0,0 +1,19 @@
1
+ export const IconReload = (props: React.ComponentProps<'svg'>) => {
2
+ return (
3
+ <svg
4
+ width="12"
5
+ height="12"
6
+ viewBox="0 0 12 12"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ {...props}
10
+ >
11
+ <path
12
+ fillRule="evenodd"
13
+ clipRule="evenodd"
14
+ d="M10.52 6C10.52 3.73168 8.75221 1.48 6.00006 1.48C3.77741 1.48 2.67886 3.1251 2.21074 3.99999H3.60005C3.82096 3.99999 4.00005 4.17908 4.00005 4.39999C4.00005 4.6209 3.82096 4.79999 3.60005 4.79999H1.20005C0.979137 4.79999 0.800049 4.6209 0.800049 4.39999V1.99999C0.800049 1.77908 0.979137 1.59999 1.20005 1.59999C1.42096 1.59999 1.60005 1.77908 1.60005 1.99999V3.45056C2.16367 2.45702 3.4673 0.679993 6.00006 0.679993C9.25029 0.679993 11.32 3.34831 11.32 6C11.32 8.65169 9.25029 11.32 6.00006 11.32C4.44499 11.32 3.15027 10.7047 2.22843 9.76673C1.73486 9.26449 1.34939 8.67121 1.08658 8.03257C1.0025 7.8283 1.09995 7.59453 1.30424 7.51046C1.50853 7.42638 1.7423 7.52384 1.82637 7.72812C2.05104 8.27401 2.38001 8.77961 2.79901 9.20593C3.57646 9.99705 4.66802 10.52 6.00006 10.52C8.75221 10.52 10.52 8.26833 10.52 6Z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ );
19
+ };
@@ -0,0 +1,19 @@
1
+ export const IconScanner = (props: React.ComponentProps<'svg'>) => {
2
+ return (
3
+ <svg
4
+ width="13"
5
+ height="12"
6
+ viewBox="0 0 13 12"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ {...props}
10
+ >
11
+ <path
12
+ fillRule="evenodd"
13
+ clipRule="evenodd"
14
+ d="M1.5 1.5C1.22386 1.5 1 1.72386 1 2V8C1 8.27614 1.22386 8.5 1.5 8.5H11.5C11.7761 8.5 12 8.27614 12 8V2C12 1.72386 11.7761 1.5 11.5 1.5H1.5ZM0 8C0 8.6531 0.4174 9.2087 1 9.4146V10C1 10.8284 1.67157 11.5 2.5 11.5H10.5C11.3284 11.5 12 10.8284 12 10V9.4146C12.5826 9.2087 13 8.6531 13 8V2C13 1.17157 12.3284 0.5 11.5 0.5H1.5C0.67157 0.5 0 1.17157 0 2V8ZM11 10V9.5H2V10C2 10.2761 2.22386 10.5 2.5 10.5H10.5C10.7761 10.5 11 10.2761 11 10ZM4.5 4.5C4.22386 4.5 4 4.72386 4 5C4 5.27614 4.22386 5.5 4.5 5.5H8.5C8.77614 5.5 9 5.27614 9 5C9 4.72386 8.77614 4.5 8.5 4.5H4.5Z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ );
19
+ };
@@ -0,0 +1,19 @@
1
+ export const IconScissors = (props: React.ComponentProps<'svg'>) => {
2
+ return (
3
+ <svg
4
+ width="12"
5
+ height="10"
6
+ viewBox="0 0 12 10"
7
+ fill="none"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ {...props}
10
+ >
11
+ <path
12
+ fillRule="evenodd"
13
+ clipRule="evenodd"
14
+ d="M0.760039 2.58762C0.760039 3.27246 1.31521 3.82762 2.00004 3.82762C2.68487 3.82762 3.24004 3.27246 3.24004 2.58762C3.24004 1.90278 2.68487 1.34762 2.00004 1.34762C1.31521 1.34762 0.760039 1.90278 0.760039 2.58762ZM2.00004 4.54762C0.917561 4.54762 0.0400391 3.6701 0.0400391 2.58762C0.0400391 1.50514 0.917561 0.627625 2.00004 0.627625C3.08252 0.627625 3.96004 1.50514 3.96004 2.58762C3.96004 2.84649 3.90986 3.09364 3.81868 3.31986L4.58929 3.83529C4.58359 3.85323 4.5782 3.8713 4.57313 3.88949L4.45035 4.32947L4.16809 4.51817L3.37248 3.98691C3.0189 4.33374 2.53445 4.54762 2.00004 4.54762ZM0.760042 7.39998C0.760042 6.71514 1.31521 6.15997 2.00004 6.15997C2.68487 6.15997 3.24004 6.71514 3.24004 7.39998C3.24004 8.08478 2.68487 8.63999 2.00004 8.63999C1.31521 8.63999 0.760042 8.08478 0.760042 7.39998ZM2.00004 5.43997C0.917561 5.43997 0.0400415 6.31749 0.0400415 7.39998C0.0400415 8.48246 0.917561 9.35998 2.00004 9.35998C3.08252 9.35998 3.96004 8.48246 3.96004 7.39998C3.96004 7.14422 3.91106 6.89996 3.82199 6.67598L12 1.20588L11.2389 1.28588C10.1662 1.39862 9.12733 1.72714 8.18485 2.25167L5.72522 3.6205C5.5385 3.72441 5.40112 3.8987 5.34369 4.10451L5.14127 4.82988L3.37954 6.00764C3.02538 5.65671 2.53802 5.43997 2.00004 5.43997ZM5.71553 6.3719L5.72522 6.37739L8.18485 7.74622C9.12733 8.27071 10.1662 8.59927 11.2389 8.71199L12 8.79198L7.04863 5.48022L5.71553 6.3719Z"
15
+ fill="currentColor"
16
+ />
17
+ </svg>
18
+ );
19
+ };
@@ -0,0 +1,31 @@
1
+ export const IconWarning = (props: React.ComponentProps<'svg'>) => (
2
+ <svg
3
+ width="13"
4
+ height="12"
5
+ viewBox="0 0 13 12"
6
+ fill="none"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ {...props}
9
+ >
10
+ <path
11
+ d="M10.8777 8.99999L6.87766 1.99999C6.79044 1.84609 6.66396 1.71808 6.51112 1.62902C6.35828 1.53997 6.18455 1.49304 6.00766 1.49304C5.83077 1.49304 5.65704 1.53997 5.5042 1.62902C5.35136 1.71808 5.22488 1.84609 5.13766 1.99999L1.13766 8.99999C1.0495 9.15267 1.00327 9.32594 1.00366 9.50224C1.00405 9.67855 1.05105 9.85161 1.13988 10.0039C1.22872 10.1562 1.35623 10.2823 1.50951 10.3694C1.66278 10.4565 1.83636 10.5016 2.01266 10.5H10.0127C10.1881 10.4998 10.3604 10.4535 10.5123 10.3656C10.6642 10.2778 10.7903 10.1515 10.8779 9.99955C10.9656 9.84756 11.0117 9.67518 11.0116 9.49973C11.0116 9.32428 10.9654 9.15193 10.8777 8.99999Z"
12
+ stroke="currentColor"
13
+ strokeLinecap="round"
14
+ strokeLinejoin="round"
15
+ />
16
+ <path
17
+ d="M6.0127 4.5V6.5"
18
+ stroke="currentColor"
19
+ strokeLinecap="round"
20
+ strokeLinejoin="round"
21
+ />
22
+ <path
23
+ d="M6.0127 8.5H6.01853"
24
+ stroke="currentColor"
25
+ strokeLinecap="round"
26
+ strokeLinejoin="round"
27
+ />
28
+ </svg>
29
+ );
30
+
31
+ IconWarning.displayName = 'IconCircleWarning';
@@ -1,7 +1,6 @@
1
1
  import * as Popover from '@radix-ui/react-popover';
2
2
  import * as React from 'react';
3
3
  import { toast } from 'sonner';
4
- import { inter } from '../app/inter';
5
4
  import { Button } from './button';
6
5
  import { Text } from './text';
7
6
 
@@ -64,7 +63,7 @@ export const Send = ({ markup }: { markup: string }) => {
64
63
  <Popover.Portal>
65
64
  <Popover.Content
66
65
  align="end"
67
- className={`-mt-10 w-80 rounded-lg border border-slate-6 bg-black/70 p-3 font-sans text-slate-11 shadow-md backdrop-blur-lg ${inter.variable}`}
66
+ className="-mt-10 w-80 rounded-lg border border-slate-6 bg-black/70 p-3 font-sans text-slate-11 shadow-md backdrop-blur-lg font-sans"
68
67
  sideOffset={48}
69
68
  >
70
69
  <form className="mt-1" onSubmit={(e) => void onFormSubmit(e)}>
@@ -4,44 +4,36 @@ import * as React from 'react';
4
4
  import { cn } from '../utils';
5
5
  import { Logo } from './logo';
6
6
  import { Sidebar } from './sidebar';
7
- import { Topbar } from './topbar';
8
7
 
9
- type RootProps = React.ComponentPropsWithoutRef<'div'>;
10
-
11
- interface ShellProps extends RootProps {
12
- markup?: string;
13
- plainText?: string;
8
+ interface ShellProps {
9
+ children: React.ReactNode;
14
10
  currentEmailOpenSlug?: string;
15
- pathSeparator?: string;
16
-
17
- activeView?: string;
18
- setActiveView?: (view: string) => void;
11
+ }
19
12
 
20
- viewWidth?: number;
21
- setViewWidth?: (width: number) => void;
22
- viewHeight?: number;
23
- setViewHeight?: (height: number) => void;
13
+ interface ShellContextValue {
14
+ sidebarToggled: boolean;
15
+ toggleSidebar: () => void;
24
16
  }
25
17
 
26
- export const Shell = ({
27
- currentEmailOpenSlug,
28
- children,
29
- pathSeparator,
30
- markup,
31
- plainText,
32
- activeView,
33
- setActiveView,
34
- viewHeight,
35
- viewWidth,
36
- setViewHeight,
37
- setViewWidth,
38
- }: ShellProps) => {
39
- const [sidebarToggled, setSidebarToggled] = React.useState(false);
40
- const [triggerTransition, setTriggerTransition] = React.useState(false);
18
+ export const ShellContext = React.createContext<ShellContextValue | undefined>(
19
+ undefined,
20
+ );
21
+
22
+ export const Shell = ({ children, currentEmailOpenSlug }: ShellProps) => {
23
+ const [sidebarToggled, setSidebarToggled] = React.useState(true);
41
24
 
42
25
  return (
43
- <>
44
- <div className="flex h-[4.375rem] items-center justify-between border-slate-6 border-b px-6 lg:hidden">
26
+ <ShellContext.Provider
27
+ value={{
28
+ toggleSidebar: () => setSidebarToggled((v) => !v),
29
+ sidebarToggled,
30
+ }}
31
+ >
32
+ <div
33
+ className={
34
+ 'flex h-[4.375rem] items-center justify-between border-slate-6 border-b px-6 lg:hidden'
35
+ }
36
+ >
45
37
  <div className="flex h-[4.375rem] items-center">
46
38
  <Logo />
47
39
  </div>
@@ -70,64 +62,36 @@ export const Shell = ({
70
62
  </svg>
71
63
  </button>
72
64
  </div>
73
- <React.Suspense>
74
- <Sidebar
75
- className={cn({
76
- 'lg:-translate-x-full translate-x-0': sidebarToggled,
77
- '-translate-x-full lg:translate-x-0': !sidebarToggled,
78
- })}
79
- currentEmailOpenSlug={currentEmailOpenSlug}
80
- markup={markup}
81
- plainText={plainText}
82
- style={{
83
- transition: triggerTransition ? 'transform 0.2s ease-in-out' : '',
84
- }}
85
- />
86
- </React.Suspense>
87
- <main
88
- className={cn(
89
- 'relative h-full max-h-full min-h-screen w-[100vw] overflow-hidden will-change-width sm:mt-[4.375rem] md:absolute md:right-0 lg:mt-0',
90
- {
91
- 'lg:w-[calc(100dvw)] lg:translate-x-0': sidebarToggled,
92
- 'lg:w-[calc(100dvw-20rem)] lg:translate-x-0': !sidebarToggled,
93
- },
94
- )}
95
- style={{
96
- transition: triggerTransition
97
- ? 'width 0.2s ease-in-out, transform 0.2s ease-in-out'
98
- : '',
99
- }}
100
- >
101
- <div className="relative h-full w-full">
102
- {currentEmailOpenSlug && pathSeparator ? (
103
- <Topbar
104
- activeView={activeView}
105
- currentEmailOpenSlug={currentEmailOpenSlug}
106
- markup={markup}
107
- onToggleSidebar={() => {
108
- setTriggerTransition(true);
65
+ <div className="flex w-[100dvw] h-[100dvh] flex-row">
66
+ <React.Suspense>
67
+ <Sidebar
68
+ className={cn('shrink [transition:width_0.2s_ease-in-out]', {
69
+ '-translate-x-full lg:translate-x-0': sidebarToggled,
70
+ 'lg:w-0': !sidebarToggled,
71
+ })}
72
+ currentEmailOpenSlug={currentEmailOpenSlug}
73
+ />
74
+ </React.Suspense>
75
+ <main
76
+ className={cn(
77
+ 'h-full max-h-full min-h-full overflow-hidden will-change-width lg:mt-0',
78
+ 'grow',
79
+ '[transition:width_0.2s_ease-in-out,_transform_0.2s_ease-in-out]',
80
+ )}
81
+ >
82
+ <div className="relative flex h-full w-full flex-col">{children}</div>
83
+ </main>
84
+ </div>
85
+ </ShellContext.Provider>
86
+ );
87
+ };
109
88
 
110
- requestAnimationFrame(() => {
111
- setSidebarToggled((v) => !v);
112
- });
89
+ type ShellContentRootProps = React.ComponentProps<'div'>;
113
90
 
114
- setTimeout(() => {
115
- setTriggerTransition(false);
116
- }, 300);
117
- }}
118
- pathSeparator={pathSeparator}
119
- setActiveView={setActiveView}
120
- setViewHeight={setViewHeight}
121
- setViewWidth={setViewWidth}
122
- viewHeight={viewHeight}
123
- viewWidth={viewWidth}
124
- />
125
- ) : null}
126
- <div className="relative mx-auto h-[calc(100dvh-3.3125rem)] grow md:h-full">
127
- {children}
128
- </div>
129
- </div>
130
- </main>
131
- </>
91
+ export const ShellContent = ({ children, ...rest }: ShellContentRootProps) => {
92
+ return (
93
+ <div {...rest} className={cn('relative grow', rest.className)}>
94
+ {children}
95
+ </div>
132
96
  );
133
97
  };
@@ -99,7 +99,7 @@ export const FileTreeDirectoryChildren = (props: {
99
99
  >
100
100
  {props.isRoot ? null : (
101
101
  <motion.div
102
- className="absolute top-1 left-[.625rem] h-6 w-px rounded-sm bg-cyan-11"
102
+ className="absolute top-1 left-[0.4rem] inset-0 h-6 w-px rounded-sm bg-cyan-11"
103
103
  layoutId="active-file"
104
104
  transition={{
105
105
  type: 'spring',
@@ -13,7 +13,7 @@ export const FileTree = ({
13
13
  emailsDirectoryMetadata,
14
14
  }: FileTreeProps) => {
15
15
  return (
16
- <div className="flex h-full w-full flex-col overflow-hidden lg:w-full lg:min-w-[14.5rem] lg:max-w-[14.5rem]">
16
+ <div className="flex h-full w-full flex-col overflow-hidden lg:w-full lg:min-w-[14.5rem]">
17
17
  <nav className="flex w-full flex-grow flex-col overflow-y-auto p-4 pr-0 pl-0">
18
18
  <Collapsible.Root open>
19
19
  <React.Suspense>