react-email 4.0.0-alpha.8 → 4.0.0
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.
- package/CHANGELOG.md +2 -55
- package/dist/cli/index.js +9 -3
- package/dist/cli/index.mjs +9 -3
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +10 -10
- package/dist/preview/.next/build-manifest.json +3 -3
- package/dist/preview/.next/cache/.rscinfo +1 -1
- package/dist/preview/.next/cache/webpack/client-production/0.pack +0 -0
- package/dist/preview/.next/cache/webpack/client-production/index.pack +0 -0
- package/dist/preview/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/dist/preview/.next/cache/webpack/server-production/0.pack +0 -0
- package/dist/preview/.next/cache/webpack/server-production/index.pack +0 -0
- package/dist/preview/.next/next-minimal-server.js.nft.json +1 -1
- package/dist/preview/.next/next-server.js.nft.json +1 -1
- package/dist/preview/.next/prerender-manifest.json +3 -3
- package/dist/preview/.next/required-server-files.json +3 -3
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/favicon.ico/route.js +1 -1
- package/dist/preview/.next/server/app/page.js +1 -1
- package/dist/preview/.next/server/app/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page.js +9 -9
- package/dist/preview/.next/server/app/preview/[...slug]/page.js.nft.json +1 -1
- package/dist/preview/.next/server/app/preview/[...slug]/page_client-reference-manifest.js +1 -1
- package/dist/preview/.next/server/chunks/203.js +1 -0
- package/dist/preview/.next/server/chunks/600.js +3 -3
- package/dist/preview/.next/server/middleware-build-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.js +1 -1
- package/dist/preview/.next/server/next-font-manifest.json +1 -1
- package/dist/preview/.next/server/pages/500.html +1 -1
- package/dist/preview/.next/server/server-reference-manifest.js +1 -1
- package/dist/preview/.next/server/server-reference-manifest.json +1 -1
- package/dist/preview/.next/static/chunks/683-017aee9270cb8999.js +1 -0
- package/dist/preview/.next/static/chunks/app/layout-311310b665ad8e17.js +1 -0
- package/dist/preview/.next/static/chunks/app/{page-9ea0bd45cd6294b0.js → page-9d038f3c5feb0570.js} +1 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-db4014629693f2b3.js +1 -0
- package/dist/preview/.next/static/chunks/{main-app-256b213b179a95cc.js → main-app-785b93ae096c4901.js} +1 -1
- package/dist/preview/.next/static/css/dda71861895dd2e4.css +3 -0
- package/dist/preview/.next/trace +26 -26
- package/dist/preview/.next/types/app/layout.ts +1 -1
- package/dist/preview/.next/types/app/page.ts +1 -1
- package/dist/preview/.next/types/app/preview/[...slug]/page.ts +1 -1
- package/package.json +1 -1
- package/src/app/layout.tsx +1 -1
- package/src/app/page.tsx +4 -4
- package/src/app/preview/[...slug]/preview.tsx +35 -26
- package/src/components/code-container.tsx +2 -2
- package/src/components/code.tsx +16 -7
- package/src/components/resizable-wrapper.tsx +3 -3
- package/src/components/shell.tsx +13 -18
- package/src/components/sidebar/file-tree-directory-children.tsx +3 -11
- package/src/components/sidebar/file-tree-directory.tsx +9 -17
- package/src/components/sidebar/sidebar.tsx +1 -1
- package/src/components/toolbar/linter.tsx +35 -33
- package/src/components/toolbar/results.tsx +1 -1
- package/src/components/toolbar.tsx +53 -24
- package/src/components/topbar.tsx +17 -5
- package/tailwind.config.ts +8 -0
- package/dist/preview/.next/server/chunks/42.js +0 -1
- package/dist/preview/.next/static/chunks/683-b769e5d91bdf9a82.js +0 -1
- package/dist/preview/.next/static/chunks/app/layout-7dee682873546401.js +0 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-a610d641c64448cc.js +0 -1
- package/dist/preview/.next/static/css/e68ebc9bb8f7b3f4.css +0 -3
- /package/dist/preview/.next/static/{SoPVDfPAp9R983pBBriVn → t4yeIF5ZYqVHaYIHgPxHn}/_buildManifest.js +0 -0
- /package/dist/preview/.next/static/{SoPVDfPAp9R983pBBriVn → t4yeIF5ZYqVHaYIHgPxHn}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// File: /home/gabriel/Projects/Resend/react-email/packages/react-email/src/app/layout.tsx
|
|
1
|
+
// File: /home/gabriel/Projects/Resend/react-email.git/release/packages/react-email/src/app/layout.tsx
|
|
2
2
|
import * as entry from '../../../src/app/layout.js'
|
|
3
3
|
import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// File: /home/gabriel/Projects/Resend/react-email/packages/react-email/src/app/page.tsx
|
|
1
|
+
// File: /home/gabriel/Projects/Resend/react-email.git/release/packages/react-email/src/app/page.tsx
|
|
2
2
|
import * as entry from '../../../src/app/page.js'
|
|
3
3
|
import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// File: /home/gabriel/Projects/Resend/react-email/packages/react-email/src/app/preview/[...slug]/page.tsx
|
|
1
|
+
// File: /home/gabriel/Projects/Resend/react-email.git/release/packages/react-email/src/app/preview/[...slug]/page.tsx
|
|
2
2
|
import * as entry from '../../../../../src/app/preview/[...slug]/page.js'
|
|
3
3
|
import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'
|
|
4
4
|
|
package/package.json
CHANGED
package/src/app/layout.tsx
CHANGED
|
@@ -27,7 +27,7 @@ const RootLayout = async ({ children }: { children: React.ReactNode }) => {
|
|
|
27
27
|
className={`${inter.variable} ${sfMono.variable} font-sans`}
|
|
28
28
|
lang="en"
|
|
29
29
|
>
|
|
30
|
-
<body className="relative flex h-screen flex-col
|
|
30
|
+
<body className="relative flex h-screen flex-col bg-black text-slate-11 leading-loose selection:bg-cyan-5 selection:text-cyan-12">
|
|
31
31
|
<EmailsProvider
|
|
32
32
|
initialEmailsDirectoryMetadata={emailsDirectoryMetadata}
|
|
33
33
|
>
|
package/src/app/page.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import Image from 'next/image';
|
|
|
3
3
|
import Link from 'next/link';
|
|
4
4
|
import { Button, Heading, Text } from '../components';
|
|
5
5
|
import CodeSnippet from '../components/code-snippet';
|
|
6
|
-
import { Shell
|
|
6
|
+
import { Shell } from '../components/shell';
|
|
7
7
|
import { emailsDirectoryAbsolutePath } from './env';
|
|
8
8
|
import logo from './logo.png';
|
|
9
9
|
|
|
@@ -12,8 +12,8 @@ const Home = () => {
|
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<Shell>
|
|
15
|
-
<
|
|
16
|
-
<div className="-mt-10 relative flex flex-col items-center gap-3 text-center">
|
|
15
|
+
<div className="w-full h-full flex items-center justify-center p-8">
|
|
16
|
+
<div className="-mt-10 relative max-w-lg flex flex-col items-center gap-3 text-center">
|
|
17
17
|
<Image
|
|
18
18
|
alt="React Email Icon"
|
|
19
19
|
className="mb-8"
|
|
@@ -38,7 +38,7 @@ const Home = () => {
|
|
|
38
38
|
<Link href="https://react.email/docs">Check the docs</Link>
|
|
39
39
|
</Button>
|
|
40
40
|
</div>
|
|
41
|
-
</
|
|
41
|
+
</div>
|
|
42
42
|
</Shell>
|
|
43
43
|
);
|
|
44
44
|
};
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
4
|
-
import { use,
|
|
4
|
+
import { use, useState } from 'react';
|
|
5
5
|
import { flushSync } from 'react-dom';
|
|
6
6
|
import { Toaster } from 'sonner';
|
|
7
7
|
import { useDebouncedCallback } from 'use-debounce';
|
|
8
8
|
import { Topbar } from '../../../components';
|
|
9
9
|
import { CodeContainer } from '../../../components/code-container';
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
ResizableWrapper,
|
|
12
12
|
makeIframeDocumentBubbleEvents,
|
|
13
13
|
} from '../../../components/resizable-wrapper';
|
|
14
14
|
import { Send } from '../../../components/send';
|
|
15
|
-
import {
|
|
15
|
+
import { useToolbarState } from '../../../components/toolbar';
|
|
16
16
|
import { Tooltip } from '../../../components/tooltip';
|
|
17
17
|
import { ActiveViewToggleGroup } from '../../../components/topbar/active-view-toggle-group';
|
|
18
18
|
import { ViewSizeControls } from '../../../components/topbar/view-size-controls';
|
|
19
19
|
import { PreviewContext } from '../../../contexts/preview';
|
|
20
20
|
import { useClampedState } from '../../../hooks/use-clamped-state';
|
|
21
|
+
import { cn } from '../../../utils';
|
|
21
22
|
import { RenderingError } from './rendering-error';
|
|
22
23
|
|
|
23
|
-
interface PreviewProps {
|
|
24
|
+
interface PreviewProps extends React.ComponentProps<'div'> {
|
|
24
25
|
emailTitle: string;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const Preview = ({ emailTitle }: PreviewProps) => {
|
|
28
|
+
const Preview = ({ emailTitle, className, ...props }: PreviewProps) => {
|
|
28
29
|
const { renderingResult, renderedEmailMetadata } = use(PreviewContext)!;
|
|
29
30
|
|
|
30
31
|
const router = useRouter();
|
|
@@ -53,21 +54,21 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
53
54
|
const hasRenderingMetadata = typeof renderedEmailMetadata !== 'undefined';
|
|
54
55
|
const hasErrors = 'error' in renderingResult;
|
|
55
56
|
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const minWidth =
|
|
59
|
-
const minHeight =
|
|
57
|
+
const [maxWidth, setMaxWidth] = useState(Number.POSITIVE_INFINITY);
|
|
58
|
+
const [maxHeight, setMaxHeight] = useState(Number.POSITIVE_INFINITY);
|
|
59
|
+
const minWidth = 100;
|
|
60
|
+
const minHeight = 100;
|
|
60
61
|
const storedWidth = searchParams.get('width');
|
|
61
62
|
const storedHeight = searchParams.get('height');
|
|
62
63
|
const [width, setWidth] = useClampedState(
|
|
63
64
|
storedWidth ? Number.parseInt(storedWidth) : 600,
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
minWidth,
|
|
66
|
+
maxWidth,
|
|
66
67
|
);
|
|
67
68
|
const [height, setHeight] = useClampedState(
|
|
68
69
|
storedHeight ? Number.parseInt(storedHeight) : 1024,
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
minHeight,
|
|
71
|
+
maxHeight,
|
|
71
72
|
);
|
|
72
73
|
|
|
73
74
|
const handleSaveViewSize = useDebouncedCallback(() => {
|
|
@@ -77,6 +78,8 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
77
78
|
router.push(`${pathname}?${params.toString()}${location.hash}`);
|
|
78
79
|
}, 300);
|
|
79
80
|
|
|
81
|
+
const { toggled: toolbarToggled } = useToolbarState();
|
|
82
|
+
|
|
80
83
|
return (
|
|
81
84
|
<>
|
|
82
85
|
<Topbar emailTitle={emailTitle}>
|
|
@@ -107,14 +110,20 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
107
110
|
) : null}
|
|
108
111
|
</Topbar>
|
|
109
112
|
|
|
110
|
-
<
|
|
111
|
-
|
|
113
|
+
<div
|
|
114
|
+
{...props}
|
|
115
|
+
className={cn(
|
|
116
|
+
'h-[calc(100%-3.5rem-2.375rem)] will-change-height flex p-4 transition-all duration-300',
|
|
117
|
+
activeView === 'preview' && 'bg-gray-200',
|
|
118
|
+
toolbarToggled && 'h-[calc(100%-3.5rem-13rem)]',
|
|
119
|
+
className,
|
|
120
|
+
)}
|
|
112
121
|
ref={(element) => {
|
|
113
122
|
const observer = new ResizeObserver((entry) => {
|
|
114
123
|
const [elementEntry] = entry;
|
|
115
124
|
if (elementEntry) {
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
setMaxWidth(elementEntry.contentRect.width);
|
|
126
|
+
setMaxHeight(elementEntry.contentRect.height);
|
|
118
127
|
}
|
|
119
128
|
});
|
|
120
129
|
|
|
@@ -132,11 +141,11 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
132
141
|
{hasRenderingMetadata ? (
|
|
133
142
|
<>
|
|
134
143
|
{activeView === 'preview' && (
|
|
135
|
-
<
|
|
144
|
+
<ResizableWrapper
|
|
136
145
|
minHeight={minHeight}
|
|
137
146
|
minWidth={minWidth}
|
|
138
|
-
maxHeight={
|
|
139
|
-
maxWidth={
|
|
147
|
+
maxHeight={maxHeight}
|
|
148
|
+
maxWidth={maxWidth}
|
|
140
149
|
height={height}
|
|
141
150
|
onResizeEnd={() => {
|
|
142
151
|
handleSaveViewSize();
|
|
@@ -145,9 +154,9 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
145
154
|
const isHorizontal =
|
|
146
155
|
direction === 'east' || direction === 'west';
|
|
147
156
|
if (isHorizontal) {
|
|
148
|
-
setWidth(value);
|
|
157
|
+
setWidth(Math.round(value));
|
|
149
158
|
} else {
|
|
150
|
-
setHeight(value);
|
|
159
|
+
setHeight(Math.round(value));
|
|
151
160
|
}
|
|
152
161
|
}}
|
|
153
162
|
width={width}
|
|
@@ -166,12 +175,12 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
166
175
|
}}
|
|
167
176
|
title={emailTitle}
|
|
168
177
|
/>
|
|
169
|
-
</
|
|
178
|
+
</ResizableWrapper>
|
|
170
179
|
)}
|
|
171
180
|
|
|
172
181
|
{activeView === 'source' && (
|
|
173
|
-
<div className="h-full w-full
|
|
174
|
-
<div className="m-auto flex max-w-3xl p-6">
|
|
182
|
+
<div className="h-full w-full">
|
|
183
|
+
<div className="m-auto h-full flex max-w-3xl p-6">
|
|
175
184
|
<Tooltip.Provider>
|
|
176
185
|
<CodeContainer
|
|
177
186
|
activeLang={activeLang}
|
|
@@ -199,7 +208,7 @@ const Preview = ({ emailTitle }: PreviewProps) => {
|
|
|
199
208
|
) : null}
|
|
200
209
|
|
|
201
210
|
<Toaster />
|
|
202
|
-
</
|
|
211
|
+
</div>
|
|
203
212
|
</>
|
|
204
213
|
);
|
|
205
214
|
};
|
|
@@ -39,7 +39,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
|
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
41
|
<div
|
|
42
|
-
className="relative w-full
|
|
42
|
+
className="relative max-h-[650px] w-full h-full whitespace-pre rounded-md border border-slate-6 text-sm"
|
|
43
43
|
style={{
|
|
44
44
|
lineHeight: '130%',
|
|
45
45
|
background:
|
|
@@ -84,7 +84,7 @@ export const CodeContainer: React.FC<Readonly<CodeContainerProps>> = ({
|
|
|
84
84
|
filename={`email.${activeMarkup.language}`}
|
|
85
85
|
/>
|
|
86
86
|
</div>
|
|
87
|
-
<div>
|
|
87
|
+
<div className="h-[calc(100%-2.25rem)]">
|
|
88
88
|
<Code language={activeLang}>{activeMarkup.content}</Code>
|
|
89
89
|
</div>
|
|
90
90
|
</div>
|
package/src/components/code.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import Link from 'next/link';
|
|
|
3
3
|
import { useSearchParams } from 'next/navigation';
|
|
4
4
|
import type { Language } from 'prism-react-renderer';
|
|
5
5
|
import { Highlight } from 'prism-react-renderer';
|
|
6
|
-
import { Fragment, useEffect } from 'react';
|
|
6
|
+
import { Fragment, useEffect, useRef } from 'react';
|
|
7
7
|
import { useFragmentIdentifier } from '../hooks/use-fragment-identifier';
|
|
8
8
|
import { cn } from '../utils';
|
|
9
9
|
|
|
@@ -73,12 +73,18 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
73
73
|
return highlight[0] <= line && highlight[1] >= line;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
+
const scrollerRef = useRef<HTMLDivElement>(null);
|
|
77
|
+
|
|
76
78
|
useEffect(() => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
const scroller = scrollerRef.current;
|
|
80
|
+
if (highlight && scroller) {
|
|
81
|
+
const lineElement = scroller.querySelector(`#L${highlight[0]}`);
|
|
82
|
+
if (lineElement instanceof HTMLAnchorElement) {
|
|
83
|
+
scroller.scrollTo({
|
|
84
|
+
top: Math.max(lineElement.offsetTop - 325, 0),
|
|
85
|
+
behavior: 'smooth',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
82
88
|
}
|
|
83
89
|
}, [highlight]);
|
|
84
90
|
|
|
@@ -97,7 +103,10 @@ export const Code: React.FC<Readonly<CodeProps>> = ({
|
|
|
97
103
|
'linear-gradient(90deg, rgba(56, 189, 248, 0) 0%, rgba(56, 189, 248, 0) 0%, rgba(232, 232, 232, 0.2) 33.02%, rgba(143, 143, 143, 0.6719) 64.41%, rgba(236, 72, 153, 0) 98.93%)',
|
|
98
104
|
}}
|
|
99
105
|
/>
|
|
100
|
-
<div
|
|
106
|
+
<div
|
|
107
|
+
ref={scrollerRef}
|
|
108
|
+
className="flex max-h-[650px] h-full p-4 after:w-full after:static after:block after:h-4 after:content-[''] overflow-auto"
|
|
109
|
+
>
|
|
101
110
|
<div className="text-[#49494f] text-[13px] font-light font-[MonoLisa,_Menlo,_monospace]">
|
|
102
111
|
{tokens.map((_, i) => (
|
|
103
112
|
<Link
|
|
@@ -4,7 +4,7 @@ import { cn } from '../utils';
|
|
|
4
4
|
|
|
5
5
|
type Direction = 'north' | 'south' | 'east' | 'west';
|
|
6
6
|
|
|
7
|
-
type
|
|
7
|
+
type ResizableWrapperProps = {
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
10
|
|
|
@@ -41,7 +41,7 @@ export const makeIframeDocumentBubbleEvents = (iframe: HTMLIFrameElement) => {
|
|
|
41
41
|
};
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
export const
|
|
44
|
+
export const ResizableWrapper = ({
|
|
45
45
|
width,
|
|
46
46
|
height,
|
|
47
47
|
onResize,
|
|
@@ -54,7 +54,7 @@ export const ResizableWarpper = ({
|
|
|
54
54
|
minWidth,
|
|
55
55
|
|
|
56
56
|
...rest
|
|
57
|
-
}:
|
|
57
|
+
}: ResizableWrapperProps) => {
|
|
58
58
|
const resizableRef = useRef<HTMLElement>(null);
|
|
59
59
|
|
|
60
60
|
const mouseMoveListener = useRef<(event: MouseEvent) => void>(null);
|
package/src/components/shell.tsx
CHANGED
|
@@ -62,36 +62,31 @@ export const Shell = ({ children, currentEmailOpenSlug }: ShellProps) => {
|
|
|
62
62
|
</svg>
|
|
63
63
|
</button>
|
|
64
64
|
</div>
|
|
65
|
-
<div className="
|
|
65
|
+
<div className="w-[100dvw] flex h-[calc(100dvh-4.375rem)] lg:h-[100dvh]">
|
|
66
66
|
<React.Suspense>
|
|
67
67
|
<Sidebar
|
|
68
|
-
className={cn(
|
|
69
|
-
'-
|
|
70
|
-
'lg:w-
|
|
71
|
-
|
|
68
|
+
className={cn(
|
|
69
|
+
'fixed top-[4.375rem] left-0 z-[9999] h-full max-h-full w-full max-w-full will-change-auto [transition:width_0.2s_ease-in-out]',
|
|
70
|
+
'lg:static lg:inline-block lg:z-auto lg:max-h-full lg:w-[16rem]',
|
|
71
|
+
{
|
|
72
|
+
'-translate-x-full lg:translate-x-0': sidebarToggled,
|
|
73
|
+
'lg:w-0': !sidebarToggled,
|
|
74
|
+
},
|
|
75
|
+
)}
|
|
72
76
|
currentEmailOpenSlug={currentEmailOpenSlug}
|
|
73
77
|
/>
|
|
74
78
|
</React.Suspense>
|
|
75
79
|
<main
|
|
76
80
|
className={cn(
|
|
77
|
-
'
|
|
78
|
-
'
|
|
81
|
+
'inline-block relative overflow-hidden will-change-width',
|
|
82
|
+
'w-full h-full',
|
|
79
83
|
'[transition:width_0.2s_ease-in-out,_transform_0.2s_ease-in-out]',
|
|
84
|
+
sidebarToggled && 'lg:w-[calc(100%-16rem)]',
|
|
80
85
|
)}
|
|
81
86
|
>
|
|
82
|
-
|
|
87
|
+
{children}
|
|
83
88
|
</main>
|
|
84
89
|
</div>
|
|
85
90
|
</ShellContext.Provider>
|
|
86
91
|
);
|
|
87
92
|
};
|
|
88
|
-
|
|
89
|
-
type ShellContentRootProps = React.ComponentProps<'div'>;
|
|
90
|
-
|
|
91
|
-
export const ShellContent = ({ children, ...rest }: ShellContentRootProps) => {
|
|
92
|
-
return (
|
|
93
|
-
<div {...rest} className={cn('relative grow', rest.className)}>
|
|
94
|
-
{children}
|
|
95
|
-
</div>
|
|
96
|
-
);
|
|
97
|
-
};
|
|
@@ -5,7 +5,6 @@ import { useSearchParams } from 'next/navigation';
|
|
|
5
5
|
import { cn } from '../../utils';
|
|
6
6
|
import type { EmailsDirectory } from '../../utils/get-emails-directory-metadata';
|
|
7
7
|
import { IconFile } from '../icons/icon-file';
|
|
8
|
-
import { Tooltip } from '../tooltip';
|
|
9
8
|
import { FileTreeDirectory } from './file-tree-directory';
|
|
10
9
|
|
|
11
10
|
export const FileTreeDirectoryChildren = (props: {
|
|
@@ -117,16 +116,9 @@ export const FileTreeDirectoryChildren = (props: {
|
|
|
117
116
|
height="20"
|
|
118
117
|
width="20"
|
|
119
118
|
/>
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<span className="truncate w-[calc(100%-1.25rem)]">
|
|
124
|
-
{emailFilename}
|
|
125
|
-
</span>
|
|
126
|
-
</Tooltip.Trigger>
|
|
127
|
-
<Tooltip.Content>{emailFilename}</Tooltip.Content>
|
|
128
|
-
</Tooltip>
|
|
129
|
-
</Tooltip.Provider>
|
|
119
|
+
<span className="truncate w-[calc(100%-1.25rem)]">
|
|
120
|
+
{emailFilename}
|
|
121
|
+
</span>
|
|
130
122
|
</motion.span>
|
|
131
123
|
</Link>
|
|
132
124
|
);
|
|
@@ -7,7 +7,6 @@ import { Heading } from '../heading';
|
|
|
7
7
|
import { IconArrowDown } from '../icons/icon-arrow-down';
|
|
8
8
|
import { IconFolder } from '../icons/icon-folder';
|
|
9
9
|
import { IconFolderOpen } from '../icons/icon-folder-open';
|
|
10
|
-
import { Tooltip } from '../tooltip';
|
|
11
10
|
import { FileTreeDirectoryChildren } from './file-tree-directory-children';
|
|
12
11
|
|
|
13
12
|
interface SidebarDirectoryProps {
|
|
@@ -63,22 +62,15 @@ export const FileTreeDirectory = ({
|
|
|
63
62
|
) : (
|
|
64
63
|
<IconFolder height="20" width="20" />
|
|
65
64
|
)}
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
>
|
|
76
|
-
{directoryMetadata.directoryName}
|
|
77
|
-
</Heading>
|
|
78
|
-
</Tooltip.Trigger>
|
|
79
|
-
<Tooltip.Content>{directoryMetadata.directoryName}</Tooltip.Content>
|
|
80
|
-
</Tooltip>
|
|
81
|
-
</Tooltip.Provider>
|
|
65
|
+
<Heading
|
|
66
|
+
as="h3"
|
|
67
|
+
className="transition grow w-[calc(100%-40px)] truncate duration-200 ease-in-out hover:text-slate-12"
|
|
68
|
+
color="gray"
|
|
69
|
+
size="2"
|
|
70
|
+
weight="medium"
|
|
71
|
+
>
|
|
72
|
+
{directoryMetadata.directoryName}
|
|
73
|
+
</Heading>
|
|
82
74
|
{!isEmpty ? (
|
|
83
75
|
<IconArrowDown
|
|
84
76
|
width="20"
|
|
@@ -16,7 +16,7 @@ export const Sidebar = ({ className, currentEmailOpenSlug }: SidebarProps) => {
|
|
|
16
16
|
return (
|
|
17
17
|
<aside
|
|
18
18
|
className={cn(
|
|
19
|
-
'
|
|
19
|
+
'overflow-hidden bg-black',
|
|
20
20
|
'lg:static lg:z-auto lg:max-h-screen lg:w-[16rem]',
|
|
21
21
|
className,
|
|
22
22
|
)}
|
|
@@ -92,6 +92,22 @@ export const Linter = ({ rows }: LinterProps) => {
|
|
|
92
92
|
const failingCheck = row.result.checks.find(
|
|
93
93
|
(check) => check.passed === false,
|
|
94
94
|
)!;
|
|
95
|
+
const metadata: React.ReactNode[] = [];
|
|
96
|
+
for (const check of row.result.checks) {
|
|
97
|
+
if (
|
|
98
|
+
check.type === 'fetch_attempt' &&
|
|
99
|
+
check.metadata.fetchStatusCode
|
|
100
|
+
) {
|
|
101
|
+
metadata.push(<>HTTP {check.metadata.fetchStatusCode}</>);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
metadata.push(
|
|
105
|
+
<CodePreviewLineLink
|
|
106
|
+
line={row.result.codeLocation.line}
|
|
107
|
+
column={row.result.codeLocation.column}
|
|
108
|
+
type="html"
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
95
111
|
return (
|
|
96
112
|
<Result status={row.result.status} key={i}>
|
|
97
113
|
<Result.Name>{sanitize(failingCheck.type)}</Result.Name>
|
|
@@ -102,20 +118,14 @@ export const Linter = ({ rows }: LinterProps) => {
|
|
|
102
118
|
{failingCheck.type === 'fetch_attempt' &&
|
|
103
119
|
failingCheck.metadata.fetchStatusCode &&
|
|
104
120
|
failingCheck.metadata.fetchStatusCode >= 300 &&
|
|
105
|
-
failingCheck.metadata.fetchStatusCode < 400
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
There was a redirect, the content may have been moved
|
|
109
|
-
</>
|
|
110
|
-
) : null}
|
|
121
|
+
failingCheck.metadata.fetchStatusCode < 400
|
|
122
|
+
? 'There was a redirect, the content may have been moved'
|
|
123
|
+
: null}
|
|
111
124
|
{failingCheck.type === 'fetch_attempt' &&
|
|
112
125
|
failingCheck.metadata.fetchStatusCode &&
|
|
113
|
-
failingCheck.metadata.fetchStatusCode >= 400
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
The link is broken
|
|
117
|
-
</>
|
|
118
|
-
) : null}
|
|
126
|
+
failingCheck.metadata.fetchStatusCode >= 400
|
|
127
|
+
? 'The link is broken'
|
|
128
|
+
: null}
|
|
119
129
|
{failingCheck.type === 'syntax'
|
|
120
130
|
? 'The link is broken due to invalid syntax'
|
|
121
131
|
: null}
|
|
@@ -124,15 +134,7 @@ export const Linter = ({ rows }: LinterProps) => {
|
|
|
124
134
|
{row.result.link}
|
|
125
135
|
</span>
|
|
126
136
|
</Result.Description>
|
|
127
|
-
<Result.Metadata>
|
|
128
|
-
{[
|
|
129
|
-
<CodePreviewLineLink
|
|
130
|
-
line={row.result.codeLocation.line}
|
|
131
|
-
column={row.result.codeLocation.column}
|
|
132
|
-
type="html"
|
|
133
|
-
/>,
|
|
134
|
-
]}
|
|
135
|
-
</Result.Metadata>
|
|
137
|
+
<Result.Metadata>{metadata}</Result.Metadata>
|
|
136
138
|
</Result>
|
|
137
139
|
);
|
|
138
140
|
}
|
|
@@ -146,6 +148,12 @@ export const Linter = ({ rows }: LinterProps) => {
|
|
|
146
148
|
if (check.type === 'image_size' && check.metadata.byteCount) {
|
|
147
149
|
metadata.push(prettyBytes(check.metadata.byteCount));
|
|
148
150
|
}
|
|
151
|
+
if (
|
|
152
|
+
check.type === 'fetch_attempt' &&
|
|
153
|
+
check.metadata.fetchStatusCode
|
|
154
|
+
) {
|
|
155
|
+
metadata.push(<>HTTP {check.metadata.fetchStatusCode}</>);
|
|
156
|
+
}
|
|
149
157
|
}
|
|
150
158
|
metadata.push(
|
|
151
159
|
<CodePreviewLineLink
|
|
@@ -164,20 +172,14 @@ export const Linter = ({ rows }: LinterProps) => {
|
|
|
164
172
|
{failingCheck.type === 'fetch_attempt' &&
|
|
165
173
|
failingCheck.metadata.fetchStatusCode &&
|
|
166
174
|
failingCheck.metadata.fetchStatusCode >= 300 &&
|
|
167
|
-
failingCheck.metadata.fetchStatusCode < 400
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
There was a redirect, the image may have been moved
|
|
171
|
-
</>
|
|
172
|
-
) : null}
|
|
175
|
+
failingCheck.metadata.fetchStatusCode < 400
|
|
176
|
+
? 'There was a redirect, the image may have been moved'
|
|
177
|
+
: null}
|
|
173
178
|
{failingCheck.type === 'fetch_attempt' &&
|
|
174
179
|
failingCheck.metadata.fetchStatusCode &&
|
|
175
|
-
failingCheck.metadata.fetchStatusCode >= 400
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
The image is broken
|
|
179
|
-
</>
|
|
180
|
-
) : null}
|
|
180
|
+
failingCheck.metadata.fetchStatusCode >= 400
|
|
181
|
+
? 'The image is broken'
|
|
182
|
+
: null}
|
|
181
183
|
{failingCheck.type === 'syntax'
|
|
182
184
|
? 'The image is broken due to an invalid source'
|
|
183
185
|
: null}
|