Skip to content
Merged
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
11 changes: 11 additions & 0 deletions django_email_learning/templates/emails/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@
border: 1px solid #e0e0e0;
}
}
blockquote {
{% if IS_RTL %}
border-right: 4px solid #e0e0e0;
border-left: none;
{% else %}
border-left: 4px solid #e0e0e0;
border-right: none;
{% endif %}
margin: 0px !important;
padding: 0 16px;
}
{% block extra_styles %}{% endblock %}
</style>
</head>
Expand Down
81 changes: 81 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@
"@mui/material": "^7.3.2",
"@mui/x-charts": "^8.26.0",
"@tiptap/core": "^3.13.0",
"@tiptap/extension-blockquote": "^3.19.0",
"@tiptap/extension-bold": "^3.13.0",
"@tiptap/extension-code-block": "^3.13.0",
"@tiptap/extension-document": "^3.13.0",
"@tiptap/extension-heading": "^3.13.0",
"@tiptap/extension-image": "^3.13.0",
"@tiptap/extension-italic": "^3.19.0",
"@tiptap/extension-link": "^3.19.0",
"@tiptap/extension-list": "^3.19.0",
"@tiptap/extension-paragraph": "^3.13.0",
"@tiptap/extension-text": "^3.13.0",
"@tiptap/extension-text-align": "^3.19.0",
"@tiptap/extensions": "^3.13.0",
"@tiptap/pm": "^3.13.0",
"@tiptap/react": "^3.13.0",
Expand Down
109 changes: 105 additions & 4 deletions frontend/src/components/ContentEditor.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@

import Text from "@tiptap/extension-text";
import Text from '@tiptap/extension-text'
import CodeBlock from '@tiptap/extension-code-block'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Bold from '@tiptap/extension-bold'
import Italic from '@tiptap/extension-italic'
import Link from '@tiptap/extension-link'
import BlockQuote from '@tiptap/extension-blockquote'
import { BulletList, ListItem } from '@tiptap/extension-list'
import InsertLinkIcon from '@mui/icons-material/InsertLink'
import FormatQuoteIcon from '@mui/icons-material/FormatQuote'
import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted'
import AlignHorizontalRightIcon from '@mui/icons-material/AlignHorizontalRight'
import AlignHorizontalLeftIcon from '@mui/icons-material/AlignHorizontalLeft'
import FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter'
import TextAlign from '@tiptap/extension-text-align'
import Image from "@tiptap/extension-image";
import Heading from '@tiptap/extension-heading'
import { Dropcursor } from '@tiptap/extensions'
import { EditorContent, useEditor, EditorContext } from "@tiptap/react";
import { EditorContent, useEditor, EditorContext } from "@tiptap/react"
import {
Paper,
Toolbar,
Expand All @@ -17,6 +28,7 @@ import {
} from '@mui/material';
import { Code as CodeIcon } from '@mui/icons-material';
import FormatBoldIcon from '@mui/icons-material/FormatBold';
import FormatItalicIcon from '@mui/icons-material/FormatItalic';
import ImageIcon from '@mui/icons-material/Image';


Expand All @@ -28,6 +40,14 @@ function ContentEditor({ initialContent, contentUpdateCallback, disabled = false
Text,
CodeBlock,
Bold,
BlockQuote,
BulletList,
ListItem,
Italic,
Link,
TextAlign.configure({
types: ['paragraph', 'heading'],
}),
Image.configure({
allowBase64: false,
resize: {
Expand Down Expand Up @@ -89,6 +109,46 @@ function ContentEditor({ initialContent, contentUpdateCallback, disabled = false
<FormatBoldIcon />
</IconButton>
</Tooltip>
<Tooltip title="Italic" placement="top">
<IconButton
onClick={() => editor.chain().focus().toggleItalic().run()}
size="small"
>
<FormatItalicIcon />
</IconButton>
</Tooltip>
<Tooltip title="Bullet List" placement="top">
<IconButton
onClick={() => editor.chain().focus().toggleBulletList().run()}
size="small"
>
<FormatListBulletedIcon />
</IconButton>
</Tooltip>
<Tooltip title="Align Left" placement="top">
<IconButton
onClick={() => editor.chain().focus().setTextAlign('left').run()}
size="small"
>
<AlignHorizontalLeftIcon />
</IconButton>
</Tooltip>
<Tooltip title="Align Center" placement="top">
<IconButton
onClick={() => editor.chain().focus().setTextAlign('center').run()}
size="small"
>
<FormatAlignCenterIcon />
</IconButton>
</Tooltip>
<Tooltip title="Align Right" placement="top">
<IconButton
onClick={() => editor.chain().focus().setTextAlign('right').run()}
size="small"
>
<AlignHorizontalRightIcon />
</IconButton>
</Tooltip>
<Tooltip title="Insert Image" placement="top">
<IconButton
onClick={() => {
Expand All @@ -103,6 +163,39 @@ function ContentEditor({ initialContent, contentUpdateCallback, disabled = false
<ImageIcon />
</IconButton>
</Tooltip>
<Tooltip title="Insert Link" placement="top">
<IconButton
onClick={() => {
if (editor.isActive('link')) {
const currentHref = editor.getAttributes('link').href || '';
const url = window.prompt('Update URL (leave empty to remove)', currentHref);
if (!url) {
editor.chain().focus().unsetLink().run();
return;
}
editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
return;
}
const url = window.prompt('Enter URL');
if (url) {
editor.chain().focus().toggleLink({ href: url }).run();
}
}}
size="small"
label="Insert Link"
>
<InsertLinkIcon />
</IconButton>
</Tooltip>
<Tooltip title="Block Quote" placement="top">
<IconButton
onClick={() => editor.chain().focus().toggleBlockquote().run()}
size="small"
label="Block Quote"
>
<FormatQuoteIcon />
</IconButton>
</Tooltip>
<Tooltip title="Code Block" placement="top">
<IconButton
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
Expand Down Expand Up @@ -135,17 +228,25 @@ function ContentEditor({ initialContent, contentUpdateCallback, disabled = false
}
},
'& pre': {
backgroundColor: 'grey.100',
backgroundColor: 'grey.50',
borderRadius: 1,
padding: 2,
margin: '16px 0',
fontFamily: 'Monaco, Consolas, monospace',
fontSize: '14px',
border: '1px solid',
borderColor: 'grey.300'
borderColor: 'grey.100'
},
'& strong': {
fontWeight: 'bold'
},
'blockquote': {
borderLeft: direction == 'rtl' ? 'none' : '4px solid',
borderRight: direction == 'rtl' ? '4px solid' : 'none',
margin: '0px !important',
padding: '0 16px',
borderColor: 'grey.100',

}
}
}}
Expand Down