Skip to content

Commit

Permalink
ADD image embed functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
dolf321 committed Jul 17, 2023
1 parent e0a1e58 commit 81ca3f7
Show file tree
Hide file tree
Showing 9 changed files with 308 additions and 123 deletions.
4 changes: 4 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"dependencies": {
"@date-io/core": "^1.3.6",
"@date-io/date-fns": "^1.3.13",
"@draft-js-plugins/editor": "^4.1.3",
"@draft-js-plugins/image": "^4.1.3",
"@draft-js-plugins/resizeable": "^5.0.3",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@mui/icons-material": "^5.8.4",
Expand All @@ -31,6 +34,7 @@
"react-device-detect": "^2.2.2",
"react-diff-view": "^2.4.10",
"react-dom": "^18.2.0",
"react-draft-wysiwyg": "^1.15.0",
"react-markdown": "^5.0.2",
"react-router-dom": "^5.1.2",
"react-scripts": "^5.0.1",
Expand Down
35 changes: 19 additions & 16 deletions web/src/components/forums/CreateDialog/CreateDialog.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React, {useState, useRef} from 'react';

import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Box from '@mui/material/Box';
import Input from '@mui/material/Input';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import Switch from '@mui/material/Switch';
import {Dialog, DialogTitle, DialogContent, Box, Input, Typography, Button, Switch, IconButton} from '@mui/material';
import EditorToolbar from './Toolbar/EditorToolbar';
import {Editor, EditorState, RichUtils, convertToRaw} from 'draft-js';
import {EditorState, RichUtils, convertToRaw} from 'draft-js';
import Editor, {composeDecorators} from '@draft-js-plugins/editor';
import createResizablePlugin from '@draft-js-plugins/resizeable';
import createImagePlugin from '@draft-js-plugins/image';
import CloseIcon from '@mui/icons-material/Close';
import IconButton from '@mui/material/IconButton';
import {useStyles} from './CreateDialog.styles';

import 'draft-js/dist/Draft.css';
import './TextEditor.css';
import {useStyles} from './CreateDialog.styles';

const resizeablePlugin = createResizablePlugin();
const decorator = composeDecorators(
resizeablePlugin.decorator,
);
const imagePlugin = createImagePlugin({decorator});

export default function CreateDialog({
mode = 'post',
Expand All @@ -35,10 +35,11 @@ export default function CreateDialog({

const [error, setError] = useState('');
const validatePost = () => {
const content = JSON.stringify(convertToRaw(editorState.getCurrentContent()));
if (title && content) {
handleCreatePost({
title: title,
content: JSON.stringify(convertToRaw(editorState.getCurrentContent())),
content: content,
visible_to_students: isVisibleToStudents,
anonymous: isAnonymous,
});
Expand All @@ -59,6 +60,7 @@ export default function CreateDialog({
isFullScreen
open={open}
classes={{paper: classes.root}}
onClose={() => setOpen(false)}
>
{error}
<DialogTitle className={classes.titleContainer}>
Expand All @@ -72,10 +74,10 @@ export default function CreateDialog({
</Box>
</DialogTitle>
<DialogContent sx={{padding: 0}}>
<Input inputProps={{className: classes.inputTitle}} fullWidth
<Input inputProps={{className: classes.inputTitle}} disableUnderline={true} fullWidth
value={title} onChange={(e) => setTitle(e.target.value)} placeholder={'Put Title Here'} />
<div className={classes.toolbarContainer}>
<EditorToolbar editorState={editorState} setEditorState={setEditorState}/>
<EditorToolbar editorState={editorState} setEditorState={setEditorState} imagePlugin={imagePlugin} />
</div>
<Editor
ref={editor}
Expand All @@ -84,8 +86,9 @@ export default function CreateDialog({
onChange={(editorState) => {
setEditorState(editorState);
}}
plugins={[imagePlugin, resizeablePlugin]}
/>
<Box display="flex" alignItems="center" justifyContent="flex-start" gap="20px" padding="10px">
<Box display="flex" alignItems="center" justifyContent="flex-start" gap="20px" padding="0px 10px">
<div className={classes.switchContainer}>
<p> Visibile to Students?</p>
<Switch checked={isVisibleToStudents} onChange={() => setIsVisisbleToStudents(!isVisibleToStudents)}/>
Expand Down
12 changes: 4 additions & 8 deletions web/src/components/forums/CreateDialog/CreateDialog.styles.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ export const useStyles = makeStyles((theme) => ({
switchContainer: {
display: 'flex',
alignItems: 'center',
},
editorContainer: {
display: 'block',
height: '400px',
margin: theme.spacing(10),
padding: theme.spacing(1),
margin: theme.spacing(0),
padding: theme.spacing(0),
},
buttonIcon: {
color: theme.palette.primary.main,
Expand All @@ -29,11 +25,11 @@ export const useStyles = makeStyles((theme) => ({
titleContainer: {
backgroundColor: `${theme.palette.primary.main}80`,
padding: theme.spacing(1.5),
fontSize: '1rem',
},
inputTitle: {
padding: theme.spacing(1.5, 1, 1.5, 1),
fontSize: '1rem',
borderBottom: '0', // Not working
fontSize: '2.25rem',
},
}));

5 changes: 3 additions & 2 deletions web/src/components/forums/CreateDialog/TextEditor.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
.DraftEditor-editorContainer {
height: 15rem;
padding: 0.8rem;
height: 20rem;
padding: 1rem;
margin-bottom: 10px;
overflow-y: auto;
overflow-x: hidden;
background-color: rgb(0, 0, 0, 0.1);
}

::-webkit-scrollbar {
Expand Down
138 changes: 54 additions & 84 deletions web/src/components/forums/CreateDialog/Toolbar/EditorToolbar.jsx
Original file line number Diff line number Diff line change
@@ -1,132 +1,101 @@
import React, {useState} from 'react';
import Box from '@mui/material/Box';
import {makeStyles} from '@mui/styles';
import {CssBaseline} from '@mui/material';
import FormatBoldIcon from '@mui/icons-material/FormatBold';
import FormatItalicIcon from '@mui/icons-material/FormatItalic';
import FormatUnderlinedIcon from '@mui/icons-material/FormatUnderlined';
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
import CodeIcon from '@mui/icons-material/Code';
import ImageIcon from '@mui/icons-material/Image'; // Need draft-js plugin
import IconButton from '@mui/material/IconButton';


import React from 'react';
import {Box, CssBaseline, IconButton} from '@mui/material';
import {
FormatBold as FormatBoldIcon,
FormatItalic as FormatItalicIcon,
FormatUnderlined as FormatUnderlinedIcon,
FormatListBulleted as FormatListBulletedIcon,
FormatListNumbered as FormatListNumberedIcon,
} from '@mui/icons-material';
import EmbedImage from './Embed/EmbedImage';
import {useStyles} from './EditorToolbar.styles';
import {RichUtils} from 'draft-js';

const useStyles = makeStyles((theme) => ({
root: {
flex: 1,
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
padding: theme.spacing(0),
margin: theme.spacing(0.5, 0.25),
},
p: {
margin: theme.spacing(0),
},
buttonIcon: {
// margin: theme.spacing(1, 0, 0, 0),
},
IconLogo: {
// margin: theme.spacing(0, 0, 0, 0),
translate: 'transform(-50%, -50%)',
padding: theme.spacing(0.1),
},
// inline: {
// display: 'inline',
// },
// datePicker: {
// width: 300,
// marginRight: theme.spacing(2),
// },
// button: {
// marginRight: theme.spacing(1),
// },
}));
const MODES = {
INLINE: 'inline',
BLOCK: 'block',
};

export default function EditorToolbar({editorState, setEditorState}) {
export default function EditorToolbar({editorState, setEditorState, imagePlugin}) {
const classes = useStyles();
// Create JSON array of the icon and their functions FIX THIS

// Create JSON array of the icon and their functions
const tools = [
{label: 'H1', style: 'header-one', method: 'block'},
{label: 'H2', style: 'header-two', method: 'block'},
{label: 'H3', style: 'header-three', method: 'block'},
{
label: 'H1',
style: 'header-one',
method: MODES.BLOCK,
},
{
label: 'H2',
style: 'header-two',
method: MODES.BLOCK,
},
{
label: 'H3',
style: 'header-three',
method: MODES.BLOCK,
},
{
label: 'bold',
style: 'BOLD',
icon: <FormatBoldIcon className={classes.IconLogo} />,
method: 'inline', // Convert to enum?
method: MODES.INLINE,
},
{
label: 'italic',
style: 'ITALIC',
icon: <FormatItalicIcon className={classes.IconLogo} />,
method: 'inline',
method: MODES.INLINE,
},
{
label: 'underline',
style: 'UNDERLINE',
icon: <FormatUnderlinedIcon className={classes.IconLogo} />,
method: 'inline',
method: MODES.INLINE,
},
// {
// label: 'Blockquote',
// style: 'blockQuote',
// icon: <FormatQuoteIcon className={classes.IconLogo} />,
// method: 'block',
// },
{
label: 'Unordered-List',
label: 'unordered-list',
style: 'unordered-list-item',
method: 'block',
method: MODES.BLOCK,
icon: <FormatListBulletedIcon className={classes.IconLogo} />,
},
{
label: 'Ordered-List',
label: 'ordered-list',
style: 'ordered-list-item',
method: 'block',
method: MODES.BLOCK,
icon: <FormatListNumberedIcon className={classes.IconLogo} />,
},
// {
// label: 'Code Block',
// style: 'CODEBLOCK',
// icon: <CodeIcon className={classes.IconLogo} />,
// method: 'inline',
// },
// {
// label: 'Uppercase',
// style: 'UPPERCASE',
// method: 'inline',
// },
// {
// label: 'lowercase',
// style: 'LOWERCASE',
// method: 'inline',
// },
];

const applyStyle = (e, style, method) => {
e.preventDefault();
(method === 'block') ? setEditorState(RichUtils.toggleBlockType(editorState, style)) :
if (method === MODES.BLOCK) {
setEditorState(RichUtils.toggleBlockType(editorState, style));
} else if (method === MODES.INLINE) {
setEditorState(RichUtils.toggleInlineStyle(editorState, style));
}
};

const isActive = (style, method) => {
if (method === 'block') {
if (method === MODES.BLOCK) {
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
return blockType === style;
} else {
} else if (method === MODES.INLINE) {
const currentStyle = editorState.getCurrentInlineStyle();
return currentStyle.has(style);
}
};

const insertImage = (url) => {
console.log('inserting image');
setEditorState(imagePlugin.addImage(editorState, url));
};

return (
<>
<CssBaseline />
Expand All @@ -140,14 +109,15 @@ export default function EditorToolbar({editorState, setEditorState}) {
className={classes.buttonIcon}
key={id}
size="small"
onClick={(e) => applyStyle(e, tool.style, tool.method)}
onClick={(e) => applyStyle(e, tool.style, tool.method)} // Open modal for image
onMouseDown={(e) => e.preventDefault()}
>
{/* If the tool has an icon, render it if not render the label */}
{tool.icon || tool.label}
</IconButton>
</Box>
))}
<EmbedImage className={classes.IconButton} embedImage={insertImage} />
</Box>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles((theme) => ({
root: {
flex: 1,
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
padding: theme.spacing(0),
margin: theme.spacing(0.5, 0.25),
},
p: {
margin: theme.spacing(0),
},
IconLogo: {
translate: 'transform(-50%, -50%)',
padding: theme.spacing(0.1),
},
}));
Loading

0 comments on commit 81ca3f7

Please sign in to comment.