Skip to content

Commit 48d5c64

Browse files
committed
nextjs simple demo
1 parent 2a536ea commit 48d5c64

83 files changed

Lines changed: 17368 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

demo/src/pages/Editor/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ export default function Editor() {
265265

266266
<StandardLayout
267267
categories={defaultCategories}
268-
showSourceCode={false}
268+
showSourceCode={true}
269+
mjmlReadOnly={false}
269270
showBlockLayer={false}
270271
>
271272
<EmailEditor />
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
.header {
1+
.header {}
22

3+
* {
4+
box-sizing: border-box;
35
}

simple-nextjs-demo/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
6+
# next.js
7+
/.next/
8+
/out/
9+
10+
# production
11+
/build
12+
13+
# debug
14+
npm-debug.log*
15+
yarn-debug.log*
16+
yarn-error.log*
17+
.pnpm-debug.log*
18+
19+
# env files
20+
.env*
21+
22+
# vercel
23+
.vercel
24+
25+
# typescript
26+
*.tsbuildinfo
27+
next-env.d.ts

simple-nextjs-demo/components.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "default",
4+
"rsc": true,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.ts",
8+
"css": "app/globals.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
2+
import {
3+
Button,
4+
ConfigProvider,
5+
Dropdown,
6+
Menu,
7+
Message,
8+
PageHeader,
9+
Select,
10+
} from '@arco-design/web-react';
11+
import mjml from 'mjml-browser';
12+
import { saveAs } from 'file-saver';
13+
import {
14+
BlockAvatarWrapper,
15+
EmailEditor,
16+
EmailEditorProvider,
17+
IEmailTemplate,
18+
Stack,
19+
} from 'easy-email-editor';
20+
21+
import { AdvancedType, IBlockData, JsonToMjml } from 'easy-email-core';
22+
import { ExtensionProps, StandardLayout } from 'easy-email-extensions';
23+
24+
import '@arco-themes/react-easy-email-theme/css/arco.css';
25+
import 'easy-email-editor/lib/style.css';
26+
import 'easy-email-extensions/lib/style.css';
27+
28+
import enUS from '@arco-design/web-react/es/locale/en-US';
29+
import { useRouter, useSearchParams } from 'next/navigation';
30+
31+
const defaultCategories: ExtensionProps['categories'] = [
32+
{
33+
label: 'Content',
34+
active: true,
35+
blocks: [
36+
{
37+
type: AdvancedType.TEXT,
38+
},
39+
{
40+
type: AdvancedType.IMAGE,
41+
},
42+
{
43+
type: AdvancedType.BUTTON,
44+
},
45+
{
46+
type: AdvancedType.SOCIAL,
47+
},
48+
{
49+
type: AdvancedType.DIVIDER,
50+
},
51+
{
52+
type: AdvancedType.SPACER,
53+
},
54+
{
55+
type: AdvancedType.HERO,
56+
},
57+
{
58+
type: AdvancedType.WRAPPER,
59+
},
60+
{
61+
type: AdvancedType.TABLE,
62+
},
63+
],
64+
},
65+
{
66+
label: 'Layout',
67+
active: true,
68+
displayType: 'column',
69+
blocks: [
70+
{
71+
title: '2 columns',
72+
payload: [
73+
['50%', '50%'],
74+
['33%', '67%'],
75+
['67%', '33%'],
76+
['25%', '75%'],
77+
['75%', '25%'],
78+
],
79+
},
80+
{
81+
title: '3 columns',
82+
payload: [
83+
['33.33%', '33.33%', '33.33%'],
84+
['25%', '25%', '50%'],
85+
['50%', '25%', '25%'],
86+
],
87+
},
88+
{
89+
title: '4 columns',
90+
payload: [['25%', '25%', '25%', '25%']],
91+
},
92+
],
93+
},
94+
];
95+
96+
export default function Editor() {
97+
const [template, setTemplate] = useState<IEmailTemplate | null>(null);
98+
const [loading, setLoading] = useState(false);
99+
100+
const id = useSearchParams().get('id');
101+
const router = useRouter();
102+
const onUploadImage = async (blob: Blob) => {
103+
return Promise.resolve(URL.createObjectURL(blob));
104+
};
105+
106+
useEffect(() => {
107+
console.log('id', id);
108+
setLoading(true);
109+
import(`../data/template${id}.json`)
110+
.then(data => {
111+
const template = data.content;
112+
113+
setTemplate({
114+
content: template,
115+
subject: 'New Template',
116+
subTitle: 'New Template',
117+
});
118+
})
119+
.finally(() => {
120+
setLoading(false);
121+
});
122+
}, [id]);
123+
124+
const onExportMJML = (values: IEmailTemplate) => {
125+
const mjmlString = JsonToMjml({
126+
data: values.content,
127+
mode: 'production',
128+
context: values.content,
129+
});
130+
131+
navigator.clipboard.writeText(mjmlString);
132+
saveAs(new Blob([mjmlString], { type: 'text/mjml' }), 'easy-email.mjml');
133+
};
134+
135+
const onExportHTML = (values: IEmailTemplate) => {
136+
const mjmlString = JsonToMjml({
137+
data: values.content,
138+
mode: 'production',
139+
context: values.content,
140+
});
141+
142+
const html = mjml(mjmlString, {}).html;
143+
144+
navigator.clipboard.writeText(html);
145+
saveAs(new Blob([html], { type: 'text/html' }), 'easy-email.html');
146+
};
147+
148+
const onExportJSON = (values: IEmailTemplate) => {
149+
navigator.clipboard.writeText(JSON.stringify(values, null, 2));
150+
saveAs(
151+
new Blob([JSON.stringify(values, null, 2)], { type: 'application/json' }),
152+
'easy-email.json',
153+
);
154+
};
155+
156+
const initialValues: IEmailTemplate | null = useMemo(() => {
157+
if (!template) return null;
158+
return template;
159+
}, [template]);
160+
161+
const onSubmit = useCallback(
162+
async (values: IEmailTemplate) => {
163+
console.log(values);
164+
},
165+
[initialValues],
166+
);
167+
168+
if (!initialValues) return null;
169+
170+
return (
171+
<ConfigProvider locale={enUS}>
172+
<div>
173+
<EmailEditorProvider
174+
height={'calc(100vh - 68px)'}
175+
data={initialValues}
176+
onUploadImage={onUploadImage}
177+
onSubmit={onSubmit}
178+
dashed={false}
179+
>
180+
{({ values }, { submit, restart }) => {
181+
return (
182+
<>
183+
<PageHeader
184+
style={{ background: 'var(--color-bg-2)' }}
185+
backIcon
186+
title='Edit'
187+
onBack={() => router.push('/')}
188+
extra={
189+
<Stack alignment='center'>
190+
<Dropdown
191+
droplist={
192+
<Menu>
193+
<Menu.Item
194+
key='Export MJML'
195+
onClick={() => onExportMJML(values)}
196+
>
197+
Export MJML
198+
</Menu.Item>
199+
<Menu.Item
200+
key='Export HTML'
201+
onClick={() => onExportHTML(values)}
202+
>
203+
Export HTML
204+
</Menu.Item>
205+
<Menu.Item
206+
key='Export JSON'
207+
onClick={() => onExportJSON(values)}
208+
>
209+
Export JSON
210+
</Menu.Item>
211+
</Menu>
212+
}
213+
>
214+
<Button>
215+
<strong>Export</strong>
216+
</Button>
217+
</Dropdown>
218+
<Button
219+
type='primary'
220+
target='_blank'
221+
href='https://demo.easyemail.pro?utm_source=easyemail'
222+
>
223+
Try commercial version
224+
</Button>
225+
</Stack>
226+
}
227+
/>
228+
229+
<StandardLayout
230+
categories={defaultCategories}
231+
showSourceCode={true}
232+
mjmlReadOnly={false}
233+
showBlockLayer={false}
234+
>
235+
<EmailEditor />
236+
</StandardLayout>
237+
</>
238+
);
239+
}}
240+
</EmailEditorProvider>
241+
</div>
242+
</ConfigProvider>
243+
);
244+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client'
2+
3+
import * as React from 'react'
4+
import {
5+
ThemeProvider as NextThemesProvider,
6+
type ThemeProviderProps,
7+
} from 'next-themes'
8+
9+
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
10+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
11+
}

0 commit comments

Comments
 (0)