feat: Major Email Builder Improvements! 🚀
## 🎯 All User Feedback Implemented: ### 1. ✅ Header & Button Outside Cards **Problem:** - Header and Button were wrapped in [card] tags - Not honest rendering - Doesn't make sense to wrap single elements **Solution:** - Removed Header and Text as separate block types - Only Card contains rich content now - Button, Divider, Spacer render outside cards - Honest, semantic HTML structure **Before:** ``` [card]<h1>Header</h1>[/card] [card]<button>Click</button>[/card] ``` **After:** ``` [card]<h1>Header</h1><p>Content...</p>[/card] <button>Click</button> ``` ### 2. ✅ Rich Content in Cards **Problem:** - Cards had plain textarea - No formatting options - Hard to create mixed content **Solution:** - Cards now use RichTextEditor - Full WYSIWYG editing - Headers, text, lists, links, images, alignment - All in one card! **Card Dialog:** ``` Edit Card ───────────────────── Card Type: [Default ▼] Content: ┌──────────────────────────────┐ │ [B][I][List][Link][←][↔][→][📷]│ │ │ │ <h2>Customer Details</h2> │ │ <p>Name: {customer_name}</p> │ │ │ └──────────────────────────────┘ ``` ### 3. ✅ Text Alignment & Image Support **Added to RichTextEditor:** - ← Align Left - ↔ Align Center - → Align Right - 📷 Insert Image **Extensions:** - `@tiptap/extension-text-align` - `@tiptap/extension-image` ### 4. ✅ CodeMirror for Code Mode **Problem:** - Plain textarea for code - No syntax highlighting - Hard to read/edit **Solution:** - CodeMirror editor - HTML syntax highlighting - One Dark theme - Auto-completion - Professional code editing **Features:** - Syntax highlighting - Line numbers - Bracket matching - Auto-indent - Search & replace ## 📦 Block Structure: **Simplified to 4 types:** 1. **Card** - Rich content container (headers, text, images, etc.) 2. **Button** - Standalone CTA (outside card) 3. **Divider** - Horizontal line (outside card) 4. **Spacer** - Vertical spacing (outside card) ## 🔄 Converter Updates: **blocksToHTML():** - Cards → `[card]...[/card]` - Buttons → `<a class="button">...</a>` (no card wrapper) - Dividers → `<hr />` (no card wrapper) - Spacers → `<div style="height:...">` (no card wrapper) **htmlToBlocks():** - Parses cards AND standalone elements - Correctly identifies buttons outside cards - Maintains structure integrity ## 📋 Required Dependencies: **TipTap Extensions:** ```bash npm install @tiptap/extension-text-align @tiptap/extension-image ``` **CodeMirror:** ```bash npm install codemirror @codemirror/lang-html @codemirror/theme-one-dark ``` **Radix UI:** ```bash npm install @radix-ui/react-radio-group ``` ## 🎨 User Experience: **For Non-Technical Users:** - Visual builder with rich text editing - No HTML knowledge needed - Click, type, format, done! **For Tech-Savvy Users:** - Code mode with CodeMirror - Full HTML control - Syntax highlighting - Professional editing **Best of Both Worlds!** 🎉 ## Summary: ✅ Honest rendering (no unnecessary card wrappers) ✅ Rich content in cards (WYSIWYG editing) ✅ Text alignment & images ✅ Professional code editor ✅ Perfect for all skill levels This is PRODUCTION-READY! 🚀
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEditor, EditorContent } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
import Placeholder from '@tiptap/extension-placeholder';
|
||||
import Link from '@tiptap/extension-link';
|
||||
import TextAlign from '@tiptap/extension-text-align';
|
||||
import Image from '@tiptap/extension-image';
|
||||
import {
|
||||
Bold,
|
||||
Italic,
|
||||
List,
|
||||
ListOrdered,
|
||||
Link as LinkIcon,
|
||||
AlignLeft,
|
||||
AlignCenter,
|
||||
AlignRight,
|
||||
ImageIcon,
|
||||
Undo,
|
||||
Redo,
|
||||
} from 'lucide-react';
|
||||
@@ -42,6 +48,15 @@ export function RichTextEditor({
|
||||
class: 'text-primary underline',
|
||||
},
|
||||
}),
|
||||
TextAlign.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
}),
|
||||
Image.configure({
|
||||
inline: true,
|
||||
HTMLAttributes: {
|
||||
class: 'max-w-full h-auto rounded',
|
||||
},
|
||||
}),
|
||||
],
|
||||
content,
|
||||
onUpdate: ({ editor }) => {
|
||||
@@ -85,6 +100,13 @@ export function RichTextEditor({
|
||||
}
|
||||
};
|
||||
|
||||
const addImage = () => {
|
||||
const url = window.prompt(__('Enter image URL:'));
|
||||
if (url) {
|
||||
editor.chain().focus().setImage({ src: url }).run();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg overflow-hidden">
|
||||
{/* Toolbar */}
|
||||
@@ -137,6 +159,43 @@ export function RichTextEditor({
|
||||
<LinkIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('left').run()}
|
||||
className={editor.isActive({ textAlign: 'left' }) ? 'bg-accent' : ''}
|
||||
>
|
||||
<AlignLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('center').run()}
|
||||
className={editor.isActive({ textAlign: 'center' }) ? 'bg-accent' : ''}
|
||||
>
|
||||
<AlignCenter className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('right').run()}
|
||||
className={editor.isActive({ textAlign: 'right' }) ? 'bg-accent' : ''}
|
||||
>
|
||||
<AlignRight className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={addImage}
|
||||
>
|
||||
<ImageIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
@@ -174,7 +233,7 @@ export function RichTextEditor({
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => insertVariable(variable)}
|
||||
className="text-xs h-7"
|
||||
className="!font-normal !text-xs !px-2"
|
||||
>
|
||||
{`{${variable}}`}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user