Skip to content

Commit 007f66b

Browse files
committed
wip
1 parent 4c4a460 commit 007f66b

File tree

6 files changed

+63
-60
lines changed

6 files changed

+63
-60
lines changed

apps/web/components/ensure-matching-variants.spec.tsx

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,10 @@
11
import { existsSync } from 'node:fs';
22
import path from 'node:path';
33
import { pretty, render } from '@react-email/components';
4-
import { parse, stringify } from 'html-to-ast';
5-
import type { Attr, IDoc as Doc } from 'html-to-ast/dist/types';
6-
import postcss from 'postcss';
74
import { getComponentElement } from '../src/app/components/get-imported-components-for';
85
import { Layout } from './_components/layout';
96
import { componentsStructure, getComponentPathFromSlug } from './structure';
107

11-
type MaybeDoc = ReturnType<typeof parse>[number];
12-
13-
const walkAst = <T extends MaybeDoc>(ast: T[], callback: (doc: T) => void) => {
14-
for (const doc of ast) {
15-
callback(doc);
16-
if (doc.children) {
17-
walkAst(doc.children as T[], callback);
18-
}
19-
}
20-
};
21-
22-
const getStyleObjectFromString = (style: string): Record<string, string> => {
23-
const obj: Record<string, string> = {};
24-
const root = postcss.parse(style);
25-
root.walkDecls((decl) => {
26-
obj[decl.prop] = decl.value;
27-
});
28-
return obj;
29-
};
30-
31-
const sortStyle = (style: string): string => {
32-
const object = getStyleObjectFromString(style);
33-
const styleProperties = Object.keys(object).sort();
34-
return styleProperties.map((prop) => `${prop}:${object[prop]}`).join(';');
35-
};
36-
37-
const getComparableHtml = (html: string): string => {
38-
const ast = parse(html);
39-
walkAst(ast, (doc) => {
40-
const orderedAttributes: Attr = {};
41-
if (doc.attrs) {
42-
for (const key of Object.keys(doc.attrs).sort()) {
43-
orderedAttributes[key] = doc.attrs[key];
44-
}
45-
doc.attrs = orderedAttributes;
46-
if ('style' in doc.attrs) {
47-
const style = doc.attrs.style as string;
48-
doc.attrs.style = sortStyle(style);
49-
}
50-
}
51-
});
52-
return stringify(ast as Doc[]);
53-
};
54-
558
describe('copy-paste components', () => {
569
const components = componentsStructure.flatMap(
5710
(category) => category.components,
@@ -78,16 +31,14 @@ describe('copy-paste components', () => {
7831
) {
7932
const tailwindElement = await getComponentElement(tailwindVariantPath);
8033
const inlineStylesElement = await getComponentElement(
81-
inlineStylesVariantPath,
34+
inlineStylesVariantPath
8235
);
83-
const tailwindHtml = getComparableHtml(
84-
await pretty(await render(<Layout>{tailwindElement}</Layout>)),
36+
const tailwindHtml = pretty(
37+
await render(<Layout>{tailwindElement}</Layout>),
8538
);
86-
const inlineStylesHtml = getComparableHtml(
87-
await pretty(
88-
await render(
89-
<Layout withTailwind={false}>{inlineStylesElement}</Layout>,
90-
),
39+
const inlineStylesHtml = pretty(
40+
await render(
41+
<Layout withTailwind={false}>{inlineStylesElement}</Layout>,
9142
),
9243
);
9344
expect(tailwindHtml).toBe(inlineStylesHtml);

apps/web/components/four-images-in-a-grid/inline-styles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export const component = (
77
<Row>
88
<Text
99
style={{
10-
margin: '0px',
1110
fontSize: 16,
1211
lineHeight: '24px',
12+
margin: '0px',
1313
fontWeight: 600,
1414
color: 'rgb(79,70,229)',
1515
}}

apps/web/tsconfig.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
22
"extends": "tsconfig/nextjs.json",
33
"compilerOptions": {
4-
"target": "ES2018",
5-
"plugins": [{ "name": "next" }],
4+
"esModuleInterop": true,
65
"paths": { "@/*": ["./src/*"] },
6+
"plugins": [{ "name": "next" }],
7+
"target": "ES2018",
78
"types": ["vitest/globals"]
89
},
910
"include": [

packages/render/src/shared/utils/__snapshots__/pretty.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ exports[`pretty > should prettify base doucment correctly 1`] = `
11351135
"
11361136
`;
11371137

1138-
exports[`pretty > should print style properties per-line once they get too wide 1`] = `
1138+
exports[`pretty > style attribute formatting > should print properties per-line once they get too wide 1`] = `
11391139
"<div
11401140
style="
11411141
width:100%;

packages/render/src/shared/utils/pretty.spec.ts renamed to packages/render/src/shared/utils/pretty.spec.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3+
import { render } from '../../node';
34
import { pretty, wrapText } from './pretty';
5+
import { component } from '../../../../../apps/web/components/four-images-in-a-grid/inline-styles';
6+
import { Layout } from '../../../../../apps/web/components/_components/layout';
47

58
const stripeHtml = fs.readFileSync(
69
path.resolve(__dirname, './tests/stripe-email.html'),
@@ -18,14 +21,25 @@ describe('pretty', () => {
1821
expect(pretty(document, { lineBreak: '\n' })).toMatchSnapshot();
1922
});
2023

24+
test.only('testing', async () => {
25+
const html = await render(<Layout>{component}</Layout>);
26+
await fs.promises.writeFile(
27+
'tailwind copy-paste component.html',
28+
html,
29+
'utf8',
30+
);
31+
32+
console.log(pretty(html));
33+
});
34+
2135
describe('style attribute formatting', () => {
2236
it('should print properties per-line once they get too wide', () => {
2337
const document =
2438
'<div style="width:100%;border:none;border-top:1px solid #eaeaea;border-color:#e6ebf1;margin:20px 0;font-family:&quot;Google Sans&quot;"></div>';
2539
expect(pretty(document, { lineBreak: '\n' })).toMatchSnapshot();
2640
});
2741

28-
it.only('should work with an img element', () => {
42+
it('should work with an img element', () => {
2943
const document =
3044
'<img alt="Stagg Electric Kettle" style="border-radius:12px;border:none;display:block;object-fit:cover;outline:none;text-decoration:none;width:100%;" height="288" src="/static/stagg-eletric-kettle.jpg" />';
3145
expect(pretty(document, { lineBreak: '\n' })).toMatchSnapshot();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html dir="ltr" lang="en"><head><link rel="preload" as="image" href="/static/stagg-eletric-kettle.jpg"/><link rel="preload" as="image" href="/static/ode-grinder.jpg"/><link rel="preload" as="image" href="/static/atmos-vacuum-canister.jpg"/><link rel="preload" as="image" href="/static/clyde-electric-kettle.jpg"/><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--><style>
2+
@font-face {
3+
font-family: 'Inter';
4+
font-style: normal;
5+
font-weight: 400;
6+
mso-font-alt: 'Helvetica';
7+
src: url(https://fonts.gstatic.com/s/inter/v18/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfAZ9hiA.woff2) format('woff2');
8+
}
9+
10+
* {
11+
font-family: 'Inter', Helvetica;
12+
}
13+
</style><style>
14+
@font-face {
15+
font-family: 'Inter';
16+
font-style: normal;
17+
font-weight: 600;
18+
mso-font-alt: 'Helvetica';
19+
src: url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_fjbvMwCp50PDca1ZL7.woff2) format('woff2');
20+
}
21+
22+
* {
23+
font-family: 'Inter', Helvetica;
24+
}
25+
</style><style>
26+
@font-face {
27+
font-family: 'Inter';
28+
font-style: normal;
29+
font-weight: 700;
30+
mso-font-alt: 'Helvetica';
31+
src: url(https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_fjbvMwCp50BTca1ZL7.woff2) format('woff2');
32+
}
33+
34+
* {
35+
font-family: 'Inter', Helvetica;
36+
}
37+
</style></head><body style="margin:0;margin-left:12px;margin-right:12px"><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="max-width:37.5em;margin-left:auto;margin-right:auto;box-sizing:border-box;padding-top:1rem;padding-bottom:1rem;height:100vh"><tbody><tr style="width:100%"><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:16px;margin-bottom:16px"><tbody><tr><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:42px"><tbody><tr><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation"><tbody style="width:100%"><tr style="width:100%"><p style="font-size:16px;line-height:24px;margin:0px;font-weight:600;color:rgb(79,70,229);margin-top:0px;margin-bottom:0px;margin-left:0px;margin-right:0px">Our products</p><p style="font-size:24px;line-height:32px;margin:0px;margin-top:8px;font-weight:600;color:rgb(17,24,39);margin-bottom:0px;margin-left:0px;margin-right:0px">Elegant Style</p><p style="font-size:16px;line-height:24px;margin-top:8px;color:rgb(107,114,128);margin-bottom:16px">We spent two years in development to bring you the next generation of our award-winning home brew grinder. From the finest pour-overs to the coarsest cold brews, your coffee will never be the same again.</p></tr></tbody></table></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:16px"><tbody><tr><td><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:16px"><tbody style="width:100%"><tr style="width:100%"><td data-id="__react-email-column" style="width:50%;padding-right:8px"><a href="#" style="color:#067df7;text-decoration-line:none" target="_blank"><img alt="Stagg Electric Kettle" height="288" src="/static/stagg-eletric-kettle.jpg" style="display:block;outline:none;border:none;text-decoration:none;width:100%;border-radius:12px;object-fit:cover"/></a></td><td data-id="__react-email-column" style="width:50%;padding-left:8px"><a href="#" style="color:#067df7;text-decoration-line:none" target="_blank"><img alt="Ode Grinder" height="288" src="/static/ode-grinder.jpg" style="display:block;outline:none;border:none;text-decoration:none;width:100%;border-radius:12px;object-fit:cover"/></a></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin-top:16px"><tbody style="width:100%"><tr style="width:100%"><td data-id="__react-email-column" style="width:50%;padding-right:8px"><a href="#" style="color:#067df7;text-decoration-line:none" target="_blank"><img alt="Atmos Vacuum Canister" height="288" src="/static/atmos-vacuum-canister.jpg" style="display:block;outline:none;border:none;text-decoration:none;width:100%;border-radius:12px;object-fit:cover"/></a></td><td data-id="__react-email-column" style="width:50%;padding-left:8px"><a href="#" style="color:#067df7;text-decoration-line:none" target="_blank"><img alt="Clyde Electric Kettle" height="288" src="/static/clyde-electric-kettle.jpg" style="display:block;outline:none;border:none;text-decoration:none;width:100%;border-radius:12px;object-fit:cover"/></a></td></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table><!--/$--></body></html>

0 commit comments

Comments
 (0)