Skip to content

Commit

Permalink
Adding examples menu (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
cohitre authored Feb 24, 2024
1 parent 87f1e84 commit c15aa90
Show file tree
Hide file tree
Showing 19 changed files with 6,306 additions and 97 deletions.
42 changes: 42 additions & 0 deletions packages/editor-sample/src/App/ExamplesButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';

import { Button, Menu, MenuItem } from '@mui/material';

export default function ExamplesButton() {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleOpen = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};

const select = (val: string) => {
window.location.hash = `#sample/${val}`;
handleClose();
};

return (
<>
<Button onClick={handleOpen}>Samples</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<MenuItem onClick={() => select('one-time-password')}>one-time-password</MenuItem>
<MenuItem onClick={() => select('order-ecomerce')}>order-ecomerce</MenuItem>
<MenuItem onClick={() => select('post-metrics-report')}>post-metrics-report</MenuItem>
<MenuItem onClick={() => select('reservation-reminder')}>reservation-reminder</MenuItem>
<MenuItem onClick={() => select('reset-password')}>reset-password</MenuItem>
<MenuItem onClick={() => select('respond-to-message')}>respond-to-message</MenuItem>
<MenuItem onClick={() => select('subscription-receipt')}>subscription-receipt</MenuItem>
</Menu>
</>
);
}
7 changes: 6 additions & 1 deletion packages/editor-sample/src/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useEditorState } from '../documents/editor/EditorContext';
import ReaderBlock from '../documents/reader/ReaderBlock';
import { ReaderProvider } from '../documents/reader/ReaderContext';

import ExamplesButton from './ExamplesButton';
import HtmlPanel from './panels/HtmlPanel';
import ShareButton from './ShareButton';
import ConfigurationPanel from './sidebar/ConfigurationPanel';
Expand Down Expand Up @@ -62,14 +63,18 @@ export default function App() {
sx={{ height: 49, borderBottom: 1, borderColor: 'divider', backgroundColor: 'white' }}
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Tabs value={selectedMainTab} onChange={(_, v) => setEditorState({ selectedMainTab: v })}>
<Tab value="editor" label="Edit" />
<Tab value="preview" label="Preview" />
<Tab value="html" label="HTML" />
<Tab value="data" label="JSON" />
</Tabs>
<ShareButton />
<Box pr={3}>
<ExamplesButton />
<ShareButton />
</Box>
</Stack>
<Box sx={{ height: 'calc(100% - 49px)', overflow: 'auto' }}>{renderMainPanel()}</Box>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function DividerSidebarPanel({ data, setData }: DividerSidebarPan
step={1}
min={1}
max={24}
defaultValue={data.props.lineHeight}
defaultValue={data.props.lineHeight ?? 1}
onChange={(lineHeight) => updateData({ ...data, props: { ...data.props, lineHeight } })}
/>
<MultiStylePropertyPanel
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-sample/src/documents/blocks/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const ButtonPropsSchema = z.object({
backgroundColor: zColor().nullable().default(null),
fontSize: z.number().min(0).default(16),
fontFamily: zFontFamily().nullable().default(null),
fontWeight: zFontWeight().default('bold'),
fontWeight: zFontWeight().nullable().default('bold'),
textAlign: zTextAlign().optional().nullable().default('center'),
padding: zPadding().optional().default({
top: 16,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';

import { TEditorBlock } from '../../editor/core';
import { useCurrentBlockId } from '../../editor/EditorBlock';
import { useEditorState } from '../../editor/EditorContext';
import ReaderBlock from '../../reader/ReaderBlock';
import EditorChildrenIds from '../helpers/EditorChildrenIds';

import { ColumnsContainerProps } from './ColumnsContainerPropsSchema';
import ColumnsContainerPropsSchema, { ColumnsContainerProps } from './ColumnsContainerPropsSchema';

export function ColumnsContainer({ props: { columnsCount, columns } }: ColumnsContainerProps) {
let lastColumn = null;
Expand Down Expand Up @@ -47,47 +48,42 @@ export function ColumnsContainer({ props: { columnsCount, columns } }: ColumnsCo

export function EditorColumnsContainer(data: ColumnsContainerProps) {
const { columnsCount, columns } = data.props;
const [{ document, selectedBlockId }, setEditorState] = useEditorState();
const [{ document }, setEditorState] = useEditorState();
const blockId = useCurrentBlockId();

const insertBlock = (columnIndex: 0 | 1 | 2, blockConfiguration: TEditorBlock, i: number | null) => {
if (!selectedBlockId) {
return;
}
const id = `block-${Date.now()}`;
const columnsCopy: ColumnsContainerProps['props']['columns'] = [...columns];
if (i === null) {
columnsCopy[columnIndex] = {
childrenIds: [...columns[columnIndex].childrenIds, id],
};
} else {

const getColumns = () => {
const columnsCopy: ColumnsContainerProps['props']['columns'] = [...columns];
if (i === null) {
columnsCopy[columnIndex] = {
childrenIds: [...columns[columnIndex].childrenIds, id],
};
return columnsCopy;
}
columnsCopy[columnIndex] = {
childrenIds: [
...columns[columnIndex].childrenIds.slice(0, i),
id,
...columns[columnIndex].childrenIds.slice(i),
],
};
}
return columnsCopy;
};
const data = ColumnsContainerPropsSchema.parse(document[blockId].data);
setEditorState({
selectedBlockId: id,
document: {
...document,
[id]: blockConfiguration,
[selectedBlockId]: {
type: 'ColumnsContainer' as const,
[blockId]: {
type: 'ColumnsContainer',
data: {
style: {
backgroundColor: null,
padding: {
top: 0,
bottom: 0,
left: 0,
right: 0,
},
},
...data,
props: {
columnsCount,
columns: columnsCopy,
...data.props,
columns: getColumns(),
},
},
},
Expand Down
16 changes: 7 additions & 9 deletions packages/editor-sample/src/documents/blocks/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { z } from 'zod';

import { TEditorBlock } from '../editor/core';
import { useCurrentBlockId } from '../editor/EditorBlock';
import { useEditorState } from '../editor/EditorContext';
import ReaderBlock from '../reader/ReaderBlock';

Expand All @@ -12,8 +13,8 @@ export const ContainerPropsSchema = z.object({
style: z
.object({
backgroundColor: zColor().nullable().default(null),
borderColor: zColor().nullable().default(null),
borderRadius: z.number().default(0),
borderColor: zColor().optional().nullable().default(null),
borderRadius: z.number().optional().nullable().default(0),
padding: zPadding().optional().default({
top: 16,
bottom: 16,
Expand All @@ -40,29 +41,26 @@ export function Container({ props: { childrenIds } }: ContainerProps) {
}

export function EditorContainer({ props: { childrenIds } }: ContainerProps) {
const [{ document, selectedBlockId }, setEditorState] = useEditorState();
const [{ document }, setEditorState] = useEditorState();
const blockId = useCurrentBlockId();

const insertBlock = (blockConfiguration: TEditorBlock, i: number | null) => {
if (!selectedBlockId) {
return;
}
const id = `block-${Date.now()}`;
let nChildrenIds: string[];
if (i === null) {
nChildrenIds = [...childrenIds, id];
} else {
nChildrenIds = [...childrenIds.slice(0, i), id, ...childrenIds.slice(i)];
}
const containerBlock = document[selectedBlockId];
setEditorState({
selectedBlockId: id,
document: {
...document,
[id]: blockConfiguration,
[selectedBlockId]: {
[blockId]: {
type: 'Container',
data: {
...containerBlock.data,
...document[blockId].data,
props: { childrenIds: nChildrenIds },
},
} as TEditorBlock,
Expand Down
4 changes: 2 additions & 2 deletions packages/editor-sample/src/documents/blocks/Divider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DividerPropsSchema = z.object({
props: z
.object({
lineColor: zColor().default('#333333'),
lineHeight: z.number().default(1),
lineHeight: z.number().nullable().default(1),
})
.default({}),
});
Expand All @@ -33,7 +33,7 @@ export function Divider({ props: { lineColor, lineHeight } }: DividerProps) {
border: 'none',
borderTop: '1px solid #eaeaea',
borderColor: lineColor,
borderTopWidth: lineHeight,
borderTopWidth: lineHeight ?? 1,
}}
/>
);
Expand Down
27 changes: 13 additions & 14 deletions packages/editor-sample/src/documents/blocks/EmailLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { CSSProperties } from 'react';
import { z } from 'zod';

import { TEditorBlock } from '../editor/core';
import { useCurrentBlockId } from '../editor/EditorBlock';
import { useEditorState } from '../editor/EditorContext';
import ReaderBlock from '../reader/ReaderBlock';

Expand Down Expand Up @@ -44,31 +45,29 @@ export function EmailLayout(props: EmailLayoutProps) {
}

export function EditorEmailLayout(props: EmailLayoutProps) {
const [{ document, selectedBlockId }, setEditorState] = useEditorState();
const [{ document }, setEditorState] = useEditorState();
const blockId = useCurrentBlockId();
const childrenIds = props.childrenIds;

const insertBlock = (blockConfiguration: TEditorBlock, i: number | null) => {
if (!selectedBlockId) {
return;
}
const id = `block-${Date.now()}`;
let nChildrenIds: string[];
if (i === null) {
nChildrenIds = [...childrenIds, id];
} else {
nChildrenIds = [...childrenIds.slice(0, i), id, ...childrenIds.slice(i)];
}
const getChildrenIds = () => {
if (i === null) {
return [...childrenIds, id];
}
return [...childrenIds.slice(0, i), id, ...childrenIds.slice(i)];
};

setEditorState({
selectedBlockId: id,
document: {
...document,
[id]: blockConfiguration,
[selectedBlockId]: {
...document[selectedBlockId],
[blockId]: {
type: 'EmailLayout',
data: {
...document[selectedBlockId].data,
childrenIds: nChildrenIds,
...document[blockId].data,
childrenIds: getChildrenIds(),
},
} as TEditorBlock,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-sample/src/documents/blocks/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const HeadingPropsSchema = z.object({
color: zColor().optional().nullable().default(null),
backgroundColor: zColor().optional().nullable().default(null),
fontFamily: zFontFamily().optional().nullable().default(null),
fontWeight: zFontWeight().optional().default('bold'),
fontWeight: zFontWeight().optional().nullable().default('bold'),
textAlign: zTextAlign().optional().nullable().default(null),
padding: zPadding().optional().default({
top: 16,
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-sample/src/documents/blocks/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const ImagePropsSchema = z.object({
.default({}),
props: z.object({
height: z.number().nullable().default(null),
width: z.number().nullable().default(null),
width: z.number().nullable(),
url: z.string(),
alt: z.string(),
linkHref: z.union([z.string(), z.null()]).default(null),
Expand Down
62 changes: 62 additions & 0 deletions packages/editor-sample/src/getConfiguration/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import ONE_TIME_PASSCODE from './sample/one-time-passcode';
import ORDER_ECOMMERCE from './sample/order-ecommerce';
import POST_METRICS_REPORT from './sample/post-metrics-report';
import RESERVATION_REMINDER from './sample/reservation-reminder';
import RESET_PASSWORD from './sample/reset-password';
import RESPOND_TO_MESSAGE from './sample/respond-to-message';
import SUBSCRIPTION_RECEIPT from './sample/subscription-receipt';

export default function getConfiguration(template: string) {
if (template.startsWith('#sample/')) {
const sampleName = template.replace('#sample/', '');
switch (sampleName) {
case 'one-time-password':
return ONE_TIME_PASSCODE;
case 'order-ecomerce':
return ORDER_ECOMMERCE;
case 'post-metrics-report':
return POST_METRICS_REPORT;
case 'reservation-reminder':
return RESERVATION_REMINDER;
case 'reset-password':
return RESET_PASSWORD;
case 'respond-to-message':
return RESPOND_TO_MESSAGE;
case 'subscription-receipt':
return SUBSCRIPTION_RECEIPT;
}
}

if (template.startsWith('#code/')) {
const encodedString = template.replace('#sample/', '');
const configurationString = atob(encodedString);
try {
return JSON.parse(configurationString);
} catch {
console.error(`Couldn't load configuration from hash.`);
}
}

const configurationString = localStorage.getItem('configuration');
if (typeof configurationString === 'string') {
try {
return JSON.parse(configurationString);
} catch {
console.error(`Couldn't load configuration from localStorage.`);
}
}

return {
root: {
type: 'EmailLayout',
data: {
backdropColor: '#e5e7e5',
canvasColor: '#FFFFFF',
textColor: '#242424',
accentColor: '#0b5499',
fontFamily: 'MODERN_SANS',
childrenIds: [],
},
},
};
}
Loading

0 comments on commit c15aa90

Please sign in to comment.