Skip to content

Commit

Permalink
feat: add upload image capability
Browse files Browse the repository at this point in the history
  • Loading branch information
luciosnd committed Sep 13, 2024
1 parent 173f167 commit 96352c7
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@ import {
VerticalAlignCenterOutlined,
VerticalAlignTopOutlined,
} from '@mui/icons-material';
import { Stack, ToggleButton } from '@mui/material';
import { Box, Button, Stack, ToggleButton } from '@mui/material';
import { ImageProps, ImagePropsSchema } from '@usewaypoint/block-image';

import BaseSidebarPanel from './helpers/BaseSidebarPanel';
import RadioGroupInput from './helpers/inputs/RadioGroupInput';
import TextDimensionInput from './helpers/inputs/TextDimensionInput';
import TextInput from './helpers/inputs/TextInput';
import MultiStylePropertyPanel from './helpers/style-inputs/MultiStylePropertyPanel';
import { addImage, useImages } from '../../../../documents/editor/EditorContext';

type ImageSidebarPanelProps = {
data: ImageProps;
setData: (v: ImageProps) => void;
};
export default function ImageSidebarPanel({ data, setData }: ImageSidebarPanelProps) {
const [, setErrors] = useState<Zod.ZodError | null>(null);
const images = useImages();

const updateData = (d: unknown) => {
const res = ImagePropsSchema.safeParse(d);
Expand All @@ -31,8 +33,39 @@ export default function ImageSidebarPanel({ data, setData }: ImageSidebarPanelPr
}
};

const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) {
return;
}

const reader = new FileReader();
reader.onload = () => {
addImage({ base64: reader.result as string, file });
};
reader.readAsDataURL(file);
};

const handleImageClick = (image: { base64: string; file: File }) => () => {
updateData({ ...data, props: { ...data.props, url: image.file.name } });
};

return (
<BaseSidebarPanel title="Image block">
<Button component="label">
Upload image
<input type="file" accept="image/*" hidden onChange={handleFileUpload} />
</Button>

<Box>
{images.map((image) => (
<Box onClick={handleImageClick(image)}>
<img key={image.file.name} src={image.base64} alt="Uploaded" style={{ width: 50 }} />
{image.file.name}
</Box>
))}
</Box>

<TextInput
label="Source URL"
defaultValue={data.props?.url ?? ''}
Expand Down
17 changes: 17 additions & 0 deletions packages/editor-sample/src/documents/editor/EditorContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import getConfiguration from '../../getConfiguration';

import { TEditorConfiguration } from './core';

export type FileWithBase64 = {
file: File;
base64: string;
};

type TValue = {
document: TEditorConfiguration;

Expand All @@ -14,6 +19,8 @@ type TValue = {

inspectorDrawerOpen: boolean;
samplesDrawerOpen: boolean;

images: Array<FileWithBase64>;
};

const editorStateStore = create<TValue>(() => ({
Expand All @@ -25,6 +32,7 @@ const editorStateStore = create<TValue>(() => ({

inspectorDrawerOpen: true,
samplesDrawerOpen: true,
images: [],
}));

export function useDocument() {
Expand Down Expand Up @@ -59,6 +67,10 @@ export function useSamplesDrawerOpen() {
return editorStateStore((s) => s.samplesDrawerOpen);
}

export function useImages() {
return editorStateStore((s) => s.images);
}

export function setSelectedBlockId(selectedBlockId: TValue['selectedBlockId']) {
const selectedSidebarTab = selectedBlockId === null ? 'styles' : 'block-configuration';
const options: Partial<TValue> = {};
Expand Down Expand Up @@ -107,3 +119,8 @@ export function toggleSamplesDrawerOpen() {
export function setSelectedScreenSize(selectedScreenSize: TValue['selectedScreenSize']) {
return editorStateStore.setState({ selectedScreenSize });
}

export const addImage = (image: FileWithBase64) => {
const images = editorStateStore.getState().images;
return editorStateStore.setState({ images: [...images, image] });
};
27 changes: 26 additions & 1 deletion packages/editor-sample/src/documents/editor/core.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ import ContainerPropsSchema from '../blocks/Container/ContainerPropsSchema';
import EmailLayoutEditor from '../blocks/EmailLayout/EmailLayoutEditor';
import EmailLayoutPropsSchema from '../blocks/EmailLayout/EmailLayoutPropsSchema';
import EditorBlockWrapper from '../blocks/helpers/block-wrappers/EditorBlockWrapper';
import { useImages } from './EditorContext';

const CustomImagePropsSchema = ImagePropsSchema.extend({});

const isUrl = (value: string) => {
try {
new URL(value);
return true;
} catch {
return false;
}
};

const EDITOR_DICTIONARY = buildBlockConfigurationDictionary({
Avatar: {
Expand Down Expand Up @@ -75,13 +87,18 @@ const EDITOR_DICTIONARY = buildBlockConfigurationDictionary({
Image: {
schema: ImagePropsSchema,
Component: (data) => {
const images = useImages()
const props = {
...data,
props: {
...data.props,
url: data.props?.url ?? 'https://placehold.co/600x400@2x/F8F8F8/CCC?text=Your%20image',
url: data.props?.url,
},
};
if (props.props?.url && !isUrl(props.props.url)) {
props.props.url = images.find((i) => i.file.name === props.props.url)?.base64 ?? data.props.url;
}

return (
<EditorBlockWrapper>
<Image {...props} />
Expand Down Expand Up @@ -117,6 +134,14 @@ const EDITOR_DICTIONARY = buildBlockConfigurationDictionary({
</EditorBlockWrapper>
),
},
CustomImage: {
schema: CustomImagePropsSchema,
Component: (props) => (
<EditorBlockWrapper>
<Image {...props} />
</EditorBlockWrapper>
),
},
});

export const EditorBlock = buildBlockComponent(EDITOR_DICTIONARY);
Expand Down

0 comments on commit 96352c7

Please sign in to comment.