Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/Playground.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.playground {
display: flex;
flex-direction: column;
border: 1px solid grey;
border-radius: 10px;
justify-content: center;
padding: 0.25rem;
}

.subheading {
border-bottom: 1px solid grey;
padding: 0.25rem;
margin: auto 10px;
display: flex;
justify-content: space-between;
}

.tabButton {
padding: 0.375rem 0.75rem;
border-radius: 0.375rem;
background-color: transparent;
}

.selectedTabButton {
background-color: rgba(218, 200, 200, 0.3);
color: white;
}
146 changes: 88 additions & 58 deletions docs/Playground.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
'use server';

import { clsx } from 'clsx';
import { CodeXml, Smartphone, Tablet, TvMinimal } from 'lucide-react';
import { useMemo, useState } from 'react';

import { type Component } from '../emails/jsx.js';
import { render } from '../emails/render.js';
import { jsx } from '../emails/runtime.js';
import styles from './Playground.module.css';
import { DisplayRawFile } from './RawFunction.js';

export type PlaygroundProps = {
component: Component<{}>;
label: string;
rawFunction: string;
};

export function Playground(props: PlaygroundProps) {
const { component } = props;
const { component, label, rawFunction } = props;

const [dimension, setDimension] = useState({
height: '480',
width: '320',
height: '100%',
width: '40%',
});
const [selectedTab, setSelectedTab] = useState<
'phone' | 'tablet' | 'desktop' | 'code'
>('phone');

// This needs to be executed server-side due to
// `render` being a server-side function.
Expand All @@ -25,69 +34,90 @@ export function Playground(props: PlaygroundProps) {
}, [component]);

return (
<section
className='Playground'
style={{
display: 'flex',
flexDirection: 'column',
background: '#35352bed',
borderRadius: '10px',
justifyContent: 'center',
padding: '10px',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
padding: '10px',
}}
>
<button
onClick={() => setDimension({ height: '480', width: '320' })}
<section className={clsx(styles.playground)}>
<div className={clsx(styles.subheading)}>
<h2
style={{
backgroundColor: '#7E7CB0',
color: '#1A1A1A',
fontSize: '14px',
padding: '10px 20px',
borderRadius: '4px',
fontSize: '20px',
fontWeight: 'bold',
}}
>
Small Screen
</button>
<button
onClick={() => setDimension({ height: '480', width: '520' })}
{label}
</h2>
<div
className={clsx(styles.tabList)}
role='tablist'
tabIndex={0}
style={{
backgroundColor: '#7E7CB0',
color: '#1A1A1A',
fontSize: '14px',
padding: '10px 20px',
borderRadius: '4px',
outline: 'none',
}}
>
Medium Screen
</button>
<button
onClick={() => setDimension({ height: '480', width: '720' })}
<button
role='tab'
onClick={() => {
setDimension({ height: '100%', width: '30%' });
setSelectedTab('phone');
}}
className={clsx(
styles.tabButton,
selectedTab === 'phone' && styles.selectedTabButton
)}
>
<Smartphone />
</button>
<button
role='tab'
onClick={() => {
setDimension({ height: '100%', width: '70%' });
setSelectedTab('tablet');
}}
className={clsx(
styles.tabButton,
selectedTab === 'tablet' && styles.selectedTabButton
)}
>
<Tablet />
</button>
<button
role='tab'
onClick={() => {
setSelectedTab('desktop');
setDimension({ height: '100%', width: '100%' });
}}
className={clsx(
styles.tabButton,
selectedTab === 'desktop' && styles.selectedTabButton
)}
>
<TvMinimal />
</button>
<button
role='tab'
onClick={() => setSelectedTab('code')}
className={clsx(
styles.tabButton,
selectedTab === 'code' && styles.selectedTabButton
)}
>
<CodeXml />
</button>
</div>
</div>
{selectedTab === 'code' && (
<DisplayRawFile rawFile={rawFunction} functionName='ButtonPlay1' />
)}
{selectedTab !== 'code' && (
<iframe
style={{
backgroundColor: '#7E7CB0',
color: '#1A1A1A',
fontSize: '14px',
padding: '10px 20px',
borderRadius: '4px',
alignSelf: 'center',
padding: '15px',
borderRadius: '2rem',
}}
>
Large Screen
</button>
</div>
<iframe
style={{
alignSelf: 'center',
}}
srcDoc={template}
width={dimension.width}
height={dimension.height}
/>
srcDoc={template}
width={dimension.width}
height={dimension.height}
/>
)}
</section>
);
}
22 changes: 14 additions & 8 deletions docs/RawFunction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ export const CodeBlock: React.FC<{ language: string; children: string }> = ({
</pre>
);

export function DisplayRawFile({
rawFile,
functionName,
}: {
export type DisplayRawFileProps = {
rawFile: string;
functionName: string;
}) {
className?: string;
};

export function DisplayRawFile(props: DisplayRawFileProps) {
const { rawFile, functionName, className } = props;
const codeRef = useRef<HTMLElement>(null);

const code = extractFunction(rawFile, functionName);
Expand All @@ -31,9 +32,14 @@ export function DisplayRawFile({

return (
<pre>
<code ref={codeRef}>{code}</code>
<code
ref={codeRef}
style={{
borderRadius: '5px',
}}
>
{code}
</code>
</pre>
);

// return <CodeBlock language='javascript'>{code}</CodeBlock>;
}
10 changes: 4 additions & 6 deletions docs/pages/kits/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import rawButtonPlay1 from '!!raw-loader!../../../kits/Button.play.js';

import { ButtonPlay1 } from '../../../kits/Button.play.js';
import { Playground } from '../../Playground.js';
import { DisplayRawFile } from '../../RawFunction.js';

<Playground component={ButtonPlay1} />

<DisplayRawFile
rawFile={rawButtonPlay1.toString()}
functionName='ButtonPlay1'
<Playground
component={ButtonPlay1}
label='Single Button'
rawFunction={rawButtonPlay1.toString()}
/>
27 changes: 2 additions & 25 deletions kits/Button.play.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,15 @@ export function ButtonPlay1() {
<Button
href='/hello'
style={{
width: '100%',
backgroundColor: '#1A1A1A',
color: '#FFFFFF',
fontSize: '14px',
padding: '10px 20px',
borderRadius: '4px',
}}
>
Small Screen Button
</Button>
<Button
href='/hello'
style={{
backgroundColor: '#1A1A1A',
color: '#FFFFFF',
fontSize: '16px',
padding: '12px 24px',
borderRadius: '4px',
}}
>
Medium Screen Button
</Button>
<Button
href='/hello'
style={{
backgroundColor: '#1A1A1A',
color: '#FFFFFF',
fontSize: '18px',
padding: '14px 28px',
borderRadius: '4px',
}}
>
Large Screen Button
Get Started
</Button>
</column>
</section>
Expand Down
1 change: 1 addition & 0 deletions kits/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type ButtonProps = {
fontStyle?: string;
fontWeight?: number;
height?: string;
width?: string;
innerPadding?: string;
letterSpacing?: string;
lineHeight?: string;
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@
"license": "ISC",
"dependencies": {
"@types/mjml": "^4.7.4",
"clsx": "^2.1.1",
"decamelize-keys": "^2.0.1",
"highlight.js": "^11.11.1",
"lucide-react": "^0.474.0",
"mjml": "^4.15.3"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/css-modules": "^1.0.5",
"@types/mjml-core": "^4.15.1",
"@types/node": "^22.7.5",
"mjml-browser": "^4.15.3",
Expand Down