react-email 4.0.0-alpha.4 → 4.0.0-alpha.6
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 +12 -0
- package/dist/cli/index.js +1175 -2658
- package/dist/cli/index.mjs +18 -12
- package/dist/preview/.next/BUILD_ID +1 -1
- package/dist/preview/.next/app-build-manifest.json +31 -34
- package/dist/preview/.next/app-path-routes-manifest.json +6 -1
- package/dist/preview/.next/build-manifest.json +14 -14
- 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/diagnostics/framework.json +1 -1
- package/dist/preview/.next/export-marker.json +6 -1
- package/dist/preview/.next/images-manifest.json +57 -1
- 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 +41 -1
- package/dist/preview/.next/required-server-files.json +310 -1
- package/dist/preview/.next/routes-manifest.json +64 -1
- package/dist/preview/.next/server/app/_not-found/page.js +1 -1
- package/dist/preview/.next/server/app/_not-found/page.js.nft.json +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/favicon.ico/route.js.nft.json +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 +47 -10
- 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/app-paths-manifest.json +1 -1
- package/dist/preview/.next/server/chunks/171.js +14 -0
- package/dist/preview/.next/server/chunks/446.js +6 -0
- package/dist/preview/.next/server/chunks/600.js +8 -0
- package/dist/preview/.next/server/chunks/811.js +13 -0
- package/dist/preview/.next/server/chunks/833.js +1 -0
- package/dist/preview/.next/server/functions-config-manifest.json +4 -1
- 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/pages/_app.js +1 -1
- package/dist/preview/.next/server/pages/_app.js.nft.json +1 -1
- package/dist/preview/.next/server/pages/_document.js +1 -1
- package/dist/preview/.next/server/pages/_document.js.nft.json +1 -1
- package/dist/preview/.next/server/pages/_error.js +1 -1
- package/dist/preview/.next/server/pages/_error.js.nft.json +1 -1
- package/dist/preview/.next/server/pages-manifest.json +5 -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/server/webpack-runtime.js +1 -1
- package/dist/preview/.next/static/chunks/416-56f79fc7e689f06f.js +1 -0
- package/dist/preview/.next/static/chunks/683-8bbfd191e5105f01.js +1 -0
- package/dist/preview/.next/static/chunks/744-79730358b37b2212.js +1 -0
- package/dist/preview/.next/static/chunks/781-5f16c6bc9d9d4cc1.js +1 -0
- package/dist/preview/.next/static/chunks/832ad4be-cb988facfb8f955f.js +1 -0
- package/dist/preview/.next/static/chunks/87-38e35f08507de015.js +1 -0
- package/dist/preview/.next/static/chunks/{afa401a5-9ebf2515b1397993.js → afa401a5-3e949a1cfd317dd3.js} +3 -3
- package/dist/preview/.next/static/chunks/app/_not-found/page-09d694081cc9d4dc.js +1 -0
- package/dist/preview/.next/static/chunks/app/layout-a6640e62690d8fd6.js +1 -0
- package/dist/preview/.next/static/chunks/app/page-ba68f50b287e7478.js +1 -0
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-4a5b026ab543e27f.js +1 -0
- package/dist/preview/.next/static/chunks/framework-c2bd6d936e3077bc.js +1 -0
- package/dist/preview/.next/static/chunks/main-44463a8301435b64.js +1 -0
- package/dist/preview/.next/static/chunks/main-app-c2e686acf8d370d7.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_app-f3011d3f00bb8dba.js +1 -0
- package/dist/preview/.next/static/chunks/pages/_error-39a87dee2e97a2a3.js +1 -0
- package/dist/preview/.next/static/chunks/{webpack-9255716c9496e606.js → webpack-41e2667c9f086a4f.js} +1 -1
- package/dist/preview/.next/static/css/d7df9cfc3e182163.css +3 -0
- package/dist/preview/.next/static/gFk9UfWL8joM4iD7-wlKF/_buildManifest.js +1 -0
- package/dist/preview/.next/static/media/05613964ce6c782e-s.p.otf +0 -0
- package/dist/preview/.next/static/media/11c6126b9369e85e-s.p.otf +0 -0
- package/dist/preview/.next/static/media/26cb97734d8cb717-s.p.otf +0 -0
- package/dist/preview/.next/static/media/bb6462617151f6b7-s.p.otf +0 -0
- package/dist/preview/.next/static/media/cf6daef822ab0142-s.p.otf +0 -0
- package/dist/preview/.next/static/media/e4051546b3043204-s.p.otf +0 -0
- package/dist/preview/.next/trace +26 -22
- package/dist/preview/.next/types/cache-life.d.ts +3 -3
- package/package.json +17 -11
- package/scripts/build-preview-server.mjs +32 -0
- package/scripts/fill-caniemail-data.mjs +36 -0
- package/src/actions/email-validation/caniemail-data.ts +85993 -0
- package/src/actions/email-validation/check-compatibility.ts +322 -0
- package/src/actions/email-validation/check-images.spec.tsx +21 -12
- package/src/actions/email-validation/check-images.ts +88 -86
- package/src/actions/email-validation/check-links.spec.tsx +24 -14
- package/src/actions/email-validation/check-links.ts +59 -56
- package/src/actions/get-email-path-from-slug.ts +1 -1
- package/src/actions/render-email-by-path.tsx +2 -1
- package/src/{utils/emails-directory-absolute-path.ts → app/env.ts} +2 -0
- package/src/app/fonts/SFMono/SFMonoBold.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoBoldItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoHeavy.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoHeavyItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoLight.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoLightItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoMedium.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoMediumItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoRegular.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoRegularItalic.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoSemibold.otf +0 -0
- package/src/app/fonts/SFMono/SFMonoSemiboldItalic.otf +0 -0
- package/src/app/fonts.ts +39 -0
- package/src/app/layout.tsx +6 -3
- package/src/app/page.tsx +4 -4
- package/src/app/preview/[...slug]/page.tsx +73 -16
- package/src/app/preview/[...slug]/preview.tsx +49 -77
- package/src/components/code.tsx +0 -1
- package/src/components/icons/icon-base.tsx +4 -2
- package/src/components/icons/icon-reload.tsx +19 -0
- package/src/components/icons/icon-scanner.tsx +19 -0
- package/src/components/icons/icon-scissors.tsx +19 -0
- package/src/components/icons/icon-warning.tsx +31 -0
- package/src/components/send.tsx +1 -2
- package/src/components/shell.tsx +52 -88
- package/src/components/sidebar/file-tree-directory-children.tsx +1 -1
- package/src/components/sidebar/file-tree.tsx +1 -1
- package/src/components/sidebar/sidebar.tsx +23 -378
- package/src/components/toolbar/linter.tsx +310 -0
- package/src/components/toolbar/results-table.tsx +0 -0
- package/src/components/toolbar/results.tsx +48 -0
- package/src/components/toolbar/spam-assassin.tsx +144 -0
- package/src/components/toolbar/toolbar-button.tsx +50 -0
- package/src/components/toolbar/use-cached-state.ts +33 -0
- package/src/components/toolbar.tsx +197 -0
- package/src/components/tooltip-content.tsx +1 -2
- package/src/components/topbar/view-size-controls.tsx +1 -0
- package/src/components/topbar.tsx +29 -48
- package/src/contexts/emails.tsx +2 -1
- package/src/contexts/preview.tsx +81 -0
- package/src/hooks/use-email-rendering-result.ts +2 -1
- package/src/utils/__snapshots__/get-email-component.spec.ts.snap +1 -1
- package/src/utils/caniemail/all-css-properties.ts +358 -0
- package/src/utils/caniemail/ast/get-object-variables.ts +61 -0
- package/src/utils/caniemail/ast/get-used-style-properties.ts +91 -0
- package/src/utils/caniemail/get-compatibility-stats-for-entry.ts +118 -0
- package/src/utils/caniemail/get-css-functions.ts +25 -0
- package/src/utils/caniemail/get-css-property-names.ts +32 -0
- package/src/utils/caniemail/get-css-property-with-value.ts +14 -0
- package/src/utils/caniemail/get-css-unit.ts +3 -0
- package/src/utils/caniemail/get-element-attributes.ts +7 -0
- package/src/utils/caniemail/get-element-names.ts +20 -0
- package/src/utils/caniemail/tailwind/generate-tailwind-rules.ts +30 -0
- package/src/utils/caniemail/tailwind/get-tailwind-config.ts +205 -0
- package/src/utils/caniemail/tailwind/get-tailwind-metadata.spec.ts +25 -0
- package/src/utils/caniemail/tailwind/get-tailwind-metadata.ts +45 -0
- package/src/utils/caniemail/tailwind/setup-tailwind-context.ts +15 -0
- package/src/utils/get-email-component.ts +34 -67
- package/src/utils/linting.ts +85 -0
- package/src/utils/result.ts +49 -0
- package/src/utils/run-bundled-code.ts +64 -0
- package/tailwind-internals.d.ts +133 -0
- package/tailwind.config.ts +1 -0
- package/tsconfig.json +9 -3
- package/build-preview-server.mjs +0 -25
- package/dist/preview/.next/server/chunks/196.js +0 -5
- package/dist/preview/.next/server/chunks/300.js +0 -13
- package/dist/preview/.next/server/chunks/631.js +0 -6
- package/dist/preview/.next/server/chunks/644.js +0 -1
- package/dist/preview/.next/server/chunks/734.js +0 -15
- package/dist/preview/.next/static/Pt6wqIrWnQxbiyqaKNFOx/_buildManifest.js +0 -1
- package/dist/preview/.next/static/chunks/285-dbf6306a0d45c33d.js +0 -1
- package/dist/preview/.next/static/chunks/447-886131c35ca42b91.js +0 -1
- package/dist/preview/.next/static/chunks/490-d5745684930d49e0.js +0 -1
- package/dist/preview/.next/static/chunks/5fec7a0a-5179023f3f5a9421.js +0 -1
- package/dist/preview/.next/static/chunks/603-36207c8905355e23.js +0 -1
- package/dist/preview/.next/static/chunks/797-46f6c20952f0a280.js +0 -2
- package/dist/preview/.next/static/chunks/app/_not-found/page-96d3eac723be3ee2.js +0 -1
- package/dist/preview/.next/static/chunks/app/layout-d06046b8a368df3b.js +0 -1
- package/dist/preview/.next/static/chunks/app/page-ef1c23b954fbd0b5.js +0 -1
- package/dist/preview/.next/static/chunks/app/preview/[...slug]/page-ea8e1ae2b5a4a0ec.js +0 -1
- package/dist/preview/.next/static/chunks/framework-e7cae9cecd5c9ba2.js +0 -1
- package/dist/preview/.next/static/chunks/main-app-9f2fb5ea26e2765b.js +0 -1
- package/dist/preview/.next/static/chunks/main-df761fde212f9cda.js +0 -1
- package/dist/preview/.next/static/chunks/pages/_app-203a61b355820ccf.js +0 -1
- package/dist/preview/.next/static/chunks/pages/_error-1764ca54938748c8.js +0 -1
- package/dist/preview/.next/static/css/e4822d5ba3082a95.css +0 -3
- package/dist/preview/.next/static/css/ec5d7e66bd3b6cb8.css +0 -1
- package/src/app/inter.ts +0 -7
- package/src/components/icons/icon-circle-check.tsx +0 -21
- package/src/components/icons/icon-circle-close.tsx +0 -17
- package/src/components/icons/icon-circle-warning.tsx +0 -17
- package/src/components/sidebar/image-checker.tsx +0 -162
- package/src/components/sidebar/link-checker.tsx +0 -151
- package/src/components/sidebar/spam-assassin.tsx +0 -158
- /package/dist/preview/.next/static/{Pt6wqIrWnQxbiyqaKNFOx → gFk9UfWL8joM4iD7-wlKF}/_ssgManifest.js +0 -0
- /package/src/components/{sidebar → toolbar}/checking-results.tsx +0 -0
|
@@ -1,401 +1,46 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
|
3
|
-
import * as Tabs from '@radix-ui/react-tabs';
|
|
4
2
|
import { clsx } from 'clsx';
|
|
5
|
-
import { motion } from 'framer-motion';
|
|
6
|
-
import Link from 'next/link';
|
|
7
|
-
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
8
|
-
import type * as React from 'react';
|
|
9
|
-
import animatedHelpIcon from '../../animated-icons-data/help.json';
|
|
10
|
-
import animatedLinkIcon from '../../animated-icons-data/link.json';
|
|
11
|
-
import animatedMailIcon from '../../animated-icons-data/mail.json';
|
|
12
3
|
import { useEmails } from '../../contexts/emails';
|
|
13
|
-
import { useIconAnimation } from '../../hooks/use-icon-animation';
|
|
14
4
|
import { cn } from '../../utils';
|
|
15
|
-
import { Button } from '../button';
|
|
16
5
|
import { Heading } from '../heading';
|
|
17
|
-
import {
|
|
18
|
-
import { IconImage } from '../icons/icon-image';
|
|
19
|
-
import { Tooltip } from '../tooltip';
|
|
6
|
+
import { Logo } from '../logo';
|
|
20
7
|
import { FileTree } from './file-tree';
|
|
21
|
-
import { ImageChecker } from './image-checker';
|
|
22
|
-
import { LinkChecker } from './link-checker';
|
|
23
|
-
import { SpamAssassin } from './spam-assassin';
|
|
24
|
-
|
|
25
|
-
type SidebarPanelValue =
|
|
26
|
-
| 'file-tree'
|
|
27
|
-
| 'link-checker'
|
|
28
|
-
| 'image-checker'
|
|
29
|
-
| 'spam-assassin';
|
|
30
8
|
|
|
31
9
|
interface SidebarProps {
|
|
32
10
|
className?: string;
|
|
33
11
|
currentEmailOpenSlug?: string;
|
|
34
|
-
markup?: string;
|
|
35
|
-
plainText?: string;
|
|
36
|
-
style?: React.CSSProperties;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface NavigationButtonProps {
|
|
40
|
-
children: React.ReactNode;
|
|
41
|
-
className?: string;
|
|
42
|
-
href?: string;
|
|
43
|
-
onMouseEnter?: () => void;
|
|
44
|
-
onMouseLeave?: () => void;
|
|
45
|
-
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
46
|
-
tooltip?: string;
|
|
47
12
|
}
|
|
48
13
|
|
|
49
|
-
|
|
50
|
-
activeTabValue: SidebarPanelValue;
|
|
51
|
-
children?: React.ReactNode;
|
|
52
|
-
className?: string;
|
|
53
|
-
disabled?: boolean;
|
|
54
|
-
onMouseEnter?: () => void;
|
|
55
|
-
onMouseLeave?: () => void;
|
|
56
|
-
tabValue: SidebarPanelValue;
|
|
57
|
-
tooltipText: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
interface PanelProps {
|
|
61
|
-
active: boolean;
|
|
62
|
-
children: React.ReactNode;
|
|
63
|
-
title: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const TAB_ACTION_BASE_CLASSES =
|
|
67
|
-
'group relative aspect-square w-full cursor-pointer text-slate-12 transition-colors duration-150 ease-[cubic-bezier(.36,.66,.6,1)] hover:bg-slate-3 disabled:cursor-not-allowed disabled:bg-slate-2 disabled:text-slate-10';
|
|
68
|
-
|
|
69
|
-
const NavigationButton = ({
|
|
70
|
-
children,
|
|
71
|
-
className,
|
|
72
|
-
href,
|
|
73
|
-
onMouseEnter,
|
|
74
|
-
onMouseLeave,
|
|
75
|
-
side,
|
|
76
|
-
tooltip,
|
|
77
|
-
}: NavigationButtonProps) => (
|
|
78
|
-
<Tooltip.Provider>
|
|
79
|
-
<Tooltip>
|
|
80
|
-
<Tooltip.Trigger asChild>
|
|
81
|
-
<Link
|
|
82
|
-
href={href ?? '#'}
|
|
83
|
-
className={cn(TAB_ACTION_BASE_CLASSES, className)}
|
|
84
|
-
onMouseEnter={onMouseEnter}
|
|
85
|
-
onMouseLeave={onMouseLeave}
|
|
86
|
-
>
|
|
87
|
-
{children}
|
|
88
|
-
</Link>
|
|
89
|
-
</Tooltip.Trigger>
|
|
90
|
-
{tooltip && <Tooltip.Content side={side}>{tooltip}</Tooltip.Content>}
|
|
91
|
-
</Tooltip>
|
|
92
|
-
</Tooltip.Provider>
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const TabTrigger = ({
|
|
96
|
-
activeTabValue,
|
|
97
|
-
children,
|
|
98
|
-
className,
|
|
99
|
-
disabled,
|
|
100
|
-
onMouseEnter,
|
|
101
|
-
onMouseLeave,
|
|
102
|
-
tabValue,
|
|
103
|
-
tooltipText,
|
|
104
|
-
}: TabTriggerProps) => {
|
|
105
|
-
const isActive = tabValue === activeTabValue;
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<Tooltip.Provider>
|
|
109
|
-
<Tooltip>
|
|
110
|
-
<Tooltip.Trigger asChild>
|
|
111
|
-
<Tabs.Trigger
|
|
112
|
-
className={clsx(TAB_ACTION_BASE_CLASSES, className, {
|
|
113
|
-
'bg-slate-6': isActive,
|
|
114
|
-
})}
|
|
115
|
-
data-active={isActive}
|
|
116
|
-
disabled={disabled}
|
|
117
|
-
onMouseEnter={onMouseEnter}
|
|
118
|
-
onMouseLeave={onMouseLeave}
|
|
119
|
-
value={tabValue}
|
|
120
|
-
>
|
|
121
|
-
{isActive && (
|
|
122
|
-
<motion.div
|
|
123
|
-
className="absolute top-0 left-0 h-full w-1 bg-[#0BB9CD] transition-colors duration-300 ease-[bezier(.36,.66,.6,1)]"
|
|
124
|
-
layoutId="sidebar-active-tab"
|
|
125
|
-
transition={{ type: 'spring', bounce: 0.12, duration: 0.6 }}
|
|
126
|
-
/>
|
|
127
|
-
)}
|
|
128
|
-
<div
|
|
129
|
-
aria-hidden
|
|
130
|
-
className="pointer-events-none absolute inset-0 flex items-center justify-center pl-1 transition-opacity duration-150 ease-in"
|
|
131
|
-
>
|
|
132
|
-
{children}
|
|
133
|
-
</div>
|
|
134
|
-
</Tabs.Trigger>
|
|
135
|
-
</Tooltip.Trigger>
|
|
136
|
-
<Tooltip.Content side="right">{tooltipText}</Tooltip.Content>
|
|
137
|
-
</Tooltip>
|
|
138
|
-
</Tooltip.Provider>
|
|
139
|
-
);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const Panel = ({ title, active, children }: PanelProps) => (
|
|
143
|
-
<>
|
|
144
|
-
<div
|
|
145
|
-
className={clsx(
|
|
146
|
-
'hidden min-h-[3.3125rem] flex-shrink items-center p-3 px-4 lg:flex',
|
|
147
|
-
{
|
|
148
|
-
'bg-slate-3': active,
|
|
149
|
-
},
|
|
150
|
-
)}
|
|
151
|
-
>
|
|
152
|
-
<Heading as="h2" className="truncate" size="2" weight="medium">
|
|
153
|
-
{title}
|
|
154
|
-
</Heading>
|
|
155
|
-
</div>
|
|
156
|
-
<div className="-mt-[.5px] relative h-[calc(100dvh-4.375rem)] w-full border-slate-4 border-t px-4 pb-3">
|
|
157
|
-
{children}
|
|
158
|
-
</div>
|
|
159
|
-
</>
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const ReactIcon = () => (
|
|
163
|
-
<svg
|
|
164
|
-
fill="none"
|
|
165
|
-
height="32"
|
|
166
|
-
viewBox="0 0 32 32"
|
|
167
|
-
width="32"
|
|
168
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
169
|
-
className="pointer-events-none duration-300 ease-[cubic-bezier(.42,0,.58,1.8)] group-hover:rotate-90"
|
|
170
|
-
>
|
|
171
|
-
<g clipPath="url(#clip0_27_291)">
|
|
172
|
-
<path
|
|
173
|
-
clipRule="evenodd"
|
|
174
|
-
d="M24.4558 24.4853C25.2339 23.7073 25.3805 22.6549 25.2947 21.746C25.2078 20.8254 24.8697 19.8258 24.3896 18.8287C23.957 17.9302 23.3802 16.9745 22.6821 16C23.3802 15.0255 23.957 14.0698 24.3896 13.1713C24.8697 12.1742 25.2078 11.1746 25.2947 10.254C25.3805 9.34508 25.2339 8.29273 24.4558 7.51472C23.6778 6.73671 22.6255 6.59004 21.7165 6.67584C20.796 6.76273 19.7964 7.10086 18.7993 7.58094C17.9007 8.01357 16.945 8.59036 15.9706 9.28842C14.9961 8.59036 14.0404 8.01357 13.1418 7.58094C12.1447 7.10086 11.1451 6.76273 10.2246 6.67584C9.31564 6.59004 8.26329 6.73671 7.48528 7.51472C6.70727 8.29273 6.5606 9.34508 6.6464 10.254C6.7333 11.1746 7.07142 12.1742 7.5515 13.1713C7.98414 14.0698 8.56092 15.0255 9.25898 16C8.56092 16.9745 7.98414 17.9302 7.5515 18.8287C7.07142 19.8258 6.7333 20.8254 6.6464 21.746C6.5606 22.6549 6.70727 23.7073 7.48528 24.4853C8.26329 25.2633 9.31564 25.41 10.2246 25.3242C11.1451 25.2373 12.1447 24.8991 13.1418 24.4191C14.0404 23.9864 14.9961 23.4096 15.9706 22.7116C16.945 23.4096 17.9007 23.9864 18.7993 24.4191C19.7964 24.8991 20.796 25.2373 21.7165 25.3242C22.6255 25.41 23.6778 25.2633 24.4558 24.4853ZM15.9706 20.948C16.8399 20.2684 17.724 19.4874 18.591 18.6205C19.458 17.7535 20.239 16.8693 20.9186 16C20.239 15.1307 19.458 14.2465 18.591 13.3795C17.724 12.5126 16.8399 11.7316 15.9706 11.052C15.1012 11.7316 14.2171 12.5126 13.3501 13.3795C12.4831 14.2465 11.7021 15.1307 11.0225 16C11.7021 16.8693 12.4831 17.7535 13.3501 18.6205C14.2171 19.4874 15.1012 20.2684 15.9706 20.948ZM17.1498 21.8145C17.968 21.1558 18.7885 20.4195 19.5893 19.6187C20.39 18.818 21.1264 17.9974 21.7851 17.1792C23.7187 19.9919 24.4627 22.4819 23.4576 23.487C22.4524 24.4922 19.9625 23.7482 17.1498 21.8145ZM10.156 17.1792C10.8148 17.9974 11.5511 18.818 12.3518 19.6187C13.1526 20.4195 13.9731 21.1558 14.7914 21.8145C11.9786 23.7482 9.48871 24.4922 8.48355 23.487C7.47839 22.4819 8.22238 19.9919 10.156 17.1792ZM10.156 14.8208C10.8148 14.0026 11.5511 13.182 12.3518 12.3813C13.1526 11.5805 13.9731 10.8442 14.7914 10.1855C11.9786 8.25182 9.48871 7.50783 8.48355 8.51299C7.47839 9.51815 8.22238 12.0081 10.156 14.8208ZM17.1498 10.1855C17.968 10.8442 18.7885 11.5805 19.5893 12.3813C20.39 13.182 21.1264 14.0026 21.7851 14.8208C23.7187 12.0081 24.4627 9.51815 23.4576 8.51299C22.4524 7.50783 19.9625 8.25182 17.1498 10.1855Z"
|
|
175
|
-
fill="white"
|
|
176
|
-
fillRule="evenodd"
|
|
177
|
-
stroke="white"
|
|
178
|
-
strokeWidth="0.5"
|
|
179
|
-
/>
|
|
180
|
-
</g>
|
|
181
|
-
</svg>
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
export const Sidebar = ({
|
|
185
|
-
className,
|
|
186
|
-
currentEmailOpenSlug,
|
|
187
|
-
markup: emailMarkup,
|
|
188
|
-
plainText: emailPlainText,
|
|
189
|
-
style,
|
|
190
|
-
}: SidebarProps) => {
|
|
191
|
-
const pathname = usePathname();
|
|
192
|
-
const searchParams = useSearchParams();
|
|
193
|
-
const router = useRouter();
|
|
194
|
-
const activePanelValue = (searchParams.get('sidebar-panel') ??
|
|
195
|
-
'file-tree') as SidebarPanelValue;
|
|
14
|
+
export const Sidebar = ({ className, currentEmailOpenSlug }: SidebarProps) => {
|
|
196
15
|
const { emailsDirectoryMetadata } = useEmails();
|
|
197
16
|
|
|
198
|
-
const mailAnimation = useIconAnimation();
|
|
199
|
-
const linkAnimation = useIconAnimation();
|
|
200
|
-
const helpAnimation = useIconAnimation();
|
|
201
|
-
|
|
202
|
-
const setActivePanelValue = (newValue: SidebarPanelValue) => {
|
|
203
|
-
const params = new URLSearchParams(searchParams);
|
|
204
|
-
params.set('sidebar-panel', newValue);
|
|
205
|
-
router.push(`${pathname}?${params.toString()}`);
|
|
206
|
-
};
|
|
207
|
-
|
|
208
17
|
return (
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
18
|
+
<aside
|
|
19
|
+
className={cn(
|
|
20
|
+
'fixed top-[4.375rem] left-0 z-[9999] h-full max-h-full w-screen max-w-ful overflow-hidden bg-black will-change-auto',
|
|
21
|
+
'lg:static lg:z-auto lg:max-h-screen lg:w-[16rem]',
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
214
24
|
>
|
|
215
|
-
<
|
|
216
|
-
className=
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
>
|
|
222
|
-
<Tabs.List className="flex h-full flex-col border-slate-6 border-r">
|
|
223
|
-
<TabTrigger
|
|
224
|
-
activeTabValue={activePanelValue}
|
|
225
|
-
onMouseEnter={mailAnimation.onMouseEnter}
|
|
226
|
-
onMouseLeave={mailAnimation.onMouseLeave}
|
|
227
|
-
tabValue="file-tree"
|
|
228
|
-
tooltipText="File Explorer"
|
|
229
|
-
>
|
|
230
|
-
<DotLottieReact
|
|
231
|
-
data={animatedMailIcon}
|
|
232
|
-
autoplay={false}
|
|
233
|
-
className="h-5 w-5"
|
|
234
|
-
loop={false}
|
|
235
|
-
dotLottieRefCallback={(instance) => {
|
|
236
|
-
mailAnimation.ref.current = instance;
|
|
237
|
-
}}
|
|
238
|
-
/>
|
|
239
|
-
</TabTrigger>
|
|
240
|
-
<TabTrigger
|
|
241
|
-
activeTabValue={activePanelValue}
|
|
242
|
-
className="relative"
|
|
243
|
-
onMouseEnter={linkAnimation.onMouseEnter}
|
|
244
|
-
onMouseLeave={linkAnimation.onMouseLeave}
|
|
245
|
-
tabValue="link-checker"
|
|
246
|
-
tooltipText="Link Checker"
|
|
247
|
-
>
|
|
248
|
-
<DotLottieReact
|
|
249
|
-
data={animatedLinkIcon}
|
|
250
|
-
autoplay={false}
|
|
251
|
-
className="h-6 w-6"
|
|
252
|
-
loop={false}
|
|
253
|
-
dotLottieRefCallback={(instance) => {
|
|
254
|
-
linkAnimation.ref.current = instance;
|
|
255
|
-
}}
|
|
256
|
-
/>
|
|
257
|
-
</TabTrigger>
|
|
258
|
-
<TabTrigger
|
|
259
|
-
activeTabValue={activePanelValue}
|
|
260
|
-
className="relative"
|
|
261
|
-
tabValue="image-checker"
|
|
262
|
-
tooltipText="Image Checker"
|
|
263
|
-
>
|
|
264
|
-
<IconImage className="h-6 w-6" />
|
|
265
|
-
</TabTrigger>
|
|
266
|
-
<TabTrigger
|
|
267
|
-
activeTabValue={activePanelValue}
|
|
268
|
-
className="relative"
|
|
269
|
-
tabValue="spam-assassin"
|
|
270
|
-
tooltipText="Spam Assassin"
|
|
25
|
+
<div className="w-full h-full overflow-y-auto overflow-x-hidden">
|
|
26
|
+
<div className="flex w-full h-full flex-col border-slate-6 border-r">
|
|
27
|
+
<div
|
|
28
|
+
className={clsx(
|
|
29
|
+
'hidden min-h-[3.3125rem] flex-shrink items-center p-3 px-4 lg:flex',
|
|
30
|
+
)}
|
|
271
31
|
>
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
<NavigationButton
|
|
276
|
-
className="flex items-center justify-center"
|
|
277
|
-
href="https://react.email/docs"
|
|
278
|
-
onMouseEnter={helpAnimation.onMouseEnter}
|
|
279
|
-
onMouseLeave={helpAnimation.onMouseLeave}
|
|
280
|
-
side="right"
|
|
281
|
-
tooltip="Documentation"
|
|
282
|
-
>
|
|
283
|
-
<DotLottieReact
|
|
284
|
-
data={animatedHelpIcon}
|
|
285
|
-
autoplay={false}
|
|
286
|
-
className="h-5 w-5"
|
|
287
|
-
loop={false}
|
|
288
|
-
dotLottieRefCallback={(instance) => {
|
|
289
|
-
helpAnimation.ref.current = instance;
|
|
290
|
-
}}
|
|
291
|
-
/>
|
|
292
|
-
</NavigationButton>
|
|
293
|
-
<NavigationButton
|
|
294
|
-
className="flex items-center justify-center"
|
|
295
|
-
href="https://react.email"
|
|
296
|
-
side="right"
|
|
297
|
-
tooltip="Website"
|
|
298
|
-
>
|
|
299
|
-
<div className="flex h-7 w-7 items-center justify-center">
|
|
300
|
-
<ReactIcon />
|
|
301
|
-
</div>
|
|
302
|
-
</NavigationButton>
|
|
32
|
+
<Heading as="h2" className="truncate" size="2" weight="medium">
|
|
33
|
+
<Logo />
|
|
34
|
+
</Heading>
|
|
303
35
|
</div>
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
title="Link Checker"
|
|
310
|
-
active={activePanelValue === 'link-checker'}
|
|
311
|
-
>
|
|
312
|
-
{currentEmailOpenSlug && emailMarkup ? (
|
|
313
|
-
<LinkChecker
|
|
314
|
-
emailMarkup={emailMarkup}
|
|
315
|
-
emailSlug={currentEmailOpenSlug}
|
|
316
|
-
/>
|
|
317
|
-
) : (
|
|
318
|
-
<EmptyState
|
|
319
|
-
title="Link Checker"
|
|
320
|
-
onSelectTemplate={() => setActivePanelValue('file-tree')}
|
|
321
|
-
/>
|
|
322
|
-
)}
|
|
323
|
-
</Panel>
|
|
324
|
-
)}
|
|
325
|
-
{activePanelValue === 'image-checker' && (
|
|
326
|
-
<Panel
|
|
327
|
-
title="Image Checker"
|
|
328
|
-
active={activePanelValue === 'image-checker'}
|
|
329
|
-
>
|
|
330
|
-
{currentEmailOpenSlug && emailMarkup ? (
|
|
331
|
-
<ImageChecker
|
|
332
|
-
emailMarkup={emailMarkup}
|
|
333
|
-
emailSlug={currentEmailOpenSlug}
|
|
334
|
-
/>
|
|
335
|
-
) : (
|
|
336
|
-
<EmptyState
|
|
337
|
-
title="Image Checker"
|
|
338
|
-
onSelectTemplate={() => setActivePanelValue('file-tree')}
|
|
339
|
-
/>
|
|
340
|
-
)}
|
|
341
|
-
</Panel>
|
|
342
|
-
)}
|
|
343
|
-
{activePanelValue === 'spam-assassin' && (
|
|
344
|
-
<Panel
|
|
345
|
-
title="Image Checker"
|
|
346
|
-
active={activePanelValue === 'spam-assassin'}
|
|
347
|
-
>
|
|
348
|
-
{currentEmailOpenSlug && emailMarkup && emailPlainText ? (
|
|
349
|
-
<SpamAssassin
|
|
350
|
-
emailMarkup={emailMarkup}
|
|
351
|
-
emailPlainText={emailPlainText}
|
|
352
|
-
emailSlug={currentEmailOpenSlug}
|
|
353
|
-
/>
|
|
354
|
-
) : (
|
|
355
|
-
<EmptyState
|
|
356
|
-
title="Spam Assassin"
|
|
357
|
-
onSelectTemplate={() => setActivePanelValue('file-tree')}
|
|
358
|
-
/>
|
|
359
|
-
)}
|
|
360
|
-
</Panel>
|
|
361
|
-
)}
|
|
362
|
-
{activePanelValue === 'file-tree' && (
|
|
363
|
-
<Panel
|
|
364
|
-
title="File Explorer"
|
|
365
|
-
active={activePanelValue === 'file-tree'}
|
|
366
|
-
>
|
|
367
|
-
<FileTree
|
|
368
|
-
currentEmailOpenSlug={currentEmailOpenSlug}
|
|
369
|
-
emailsDirectoryMetadata={emailsDirectoryMetadata}
|
|
370
|
-
/>
|
|
371
|
-
</Panel>
|
|
372
|
-
)}
|
|
36
|
+
<div className="relative h-full w-full border-slate-4 border-t px-4 pb-3">
|
|
37
|
+
<FileTree
|
|
38
|
+
currentEmailOpenSlug={currentEmailOpenSlug}
|
|
39
|
+
emailsDirectoryMetadata={emailsDirectoryMetadata}
|
|
40
|
+
/>
|
|
373
41
|
</div>
|
|
374
42
|
</div>
|
|
375
|
-
</aside>
|
|
376
|
-
</Tabs.Root>
|
|
377
|
-
);
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
interface EmptyStateProps {
|
|
381
|
-
onSelectTemplate: () => void;
|
|
382
|
-
title: string;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const EmptyState = ({ onSelectTemplate, title }: EmptyStateProps) => {
|
|
386
|
-
return (
|
|
387
|
-
<div className="mt-4 flex w-full flex-col gap-2 text-pretty text-xs leading-relaxed">
|
|
388
|
-
<div className="flex flex-col gap-1 rounded-lg border border-[#0BB9CD]/50 bg-[#0BB9CD]/20 text-white">
|
|
389
|
-
<span className="mx-2.5 mt-2">
|
|
390
|
-
To use the {title}, you need to select a template.
|
|
391
|
-
</span>
|
|
392
|
-
<Button
|
|
393
|
-
className="mx-2 my-2.5 transition-all disabled:border-transparent disabled:bg-slate-11"
|
|
394
|
-
onClick={() => onSelectTemplate()}
|
|
395
|
-
>
|
|
396
|
-
Select a template
|
|
397
|
-
</Button>
|
|
398
43
|
</div>
|
|
399
|
-
</
|
|
44
|
+
</aside>
|
|
400
45
|
);
|
|
401
46
|
};
|