Add Tiptap enhancements and webinar date/time fields
- Add text alignment controls to Tiptap editor (left, center, right, justify) - Add horizontal rule/spacer button to Tiptap toolbar - Add event_start and duration_minutes fields to webinar products - Add webinar status badges (Recording Available, Coming Soon, Ended) - Install @tiptap/extension-text-align package 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,12 +3,13 @@ import StarterKit from '@tiptap/starter-kit';
|
||||
import Link from '@tiptap/extension-link';
|
||||
import Image from '@tiptap/extension-image';
|
||||
import Placeholder from '@tiptap/extension-placeholder';
|
||||
import TextAlign from '@tiptap/extension-text-align';
|
||||
import { Node } from '@tiptap/core';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Bold, Italic, List, ListOrdered, Quote, Link as LinkIcon,
|
||||
Image as ImageIcon, Heading1, Heading2, Undo, Redo,
|
||||
Maximize2, Minimize2, MousePointer, Square
|
||||
Maximize2, Minimize2, MousePointer, Square, AlignLeft, AlignCenter, AlignRight, AlignJustify, MoreVertical, Minus
|
||||
} from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
@@ -243,7 +244,15 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
StarterKit.configure({
|
||||
heading: {
|
||||
levels: [1, 2, 3],
|
||||
},
|
||||
horizontalRule: true,
|
||||
}),
|
||||
TextAlign.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
}),
|
||||
Link.configure({
|
||||
openOnClick: false,
|
||||
HTMLAttributes: {
|
||||
@@ -517,6 +526,63 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
<LinkIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
|
||||
{/* Text Align Separator */}
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
|
||||
{/* Text Align Buttons */}
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('left').run()}
|
||||
className={editor.isActive({ textAlign: 'left' }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
title="Align Left"
|
||||
>
|
||||
<AlignLeft className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('center').run()}
|
||||
className={editor.isActive({ textAlign: 'center' }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
title="Align Center"
|
||||
>
|
||||
<AlignCenter className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('right').run()}
|
||||
className={editor.isActive({ textAlign: 'right' }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
title="Align Right"
|
||||
>
|
||||
<AlignRight className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setTextAlign('justify').run()}
|
||||
className={editor.isActive({ textAlign: 'justify' }) ? 'bg-primary text-primary-foreground' : ''}
|
||||
title="Justify"
|
||||
>
|
||||
<AlignJustify className="w-4 h-4" />
|
||||
</Button>
|
||||
|
||||
{/* Spacer/Separator */}
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => editor.chain().focus().setHorizontalRule().run()}
|
||||
title="Insert Spacer"
|
||||
>
|
||||
<Minus className="w-4 h-4" />
|
||||
</Button>
|
||||
|
||||
{/* Email Components Separator */}
|
||||
<div className="w-px h-6 bg-border mx-1" />
|
||||
|
||||
@@ -628,7 +694,7 @@ export function RichTextEditor({ content, onChange, placeholder = 'Tulis konten.
|
||||
<div onPaste={handlePaste}>
|
||||
<EditorContent
|
||||
editor={editor}
|
||||
className="prose prose-sm max-w-none p-4 min-h-[200px] focus:outline-none [&_.ProseMirror]:outline-none [&_.ProseMirror]:min-h-[180px] [&_img]:cursor-pointer [&_img.ProseMirror-selectednode]:ring-2 [&_img.ProseMirror-selectednode]:ring-primary [&_h1]:font-bold [&_h1]:text-2xl [&_h1]:mb-4 [&_h1]:mt-6 [&_h2]:font-bold [&_h2]:text-xl [&_h2]:mb-3 [&_h2]:mt-5 [&_blockquote]:border-l-4 [&_blockquote]:border-primary [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:text-muted-foreground [&_blockquote]:my-4 [&_ul]:list-disc [&_ul]:pl-6 [&_ul]:space-y-1 [&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:space-y-1 [&_li]:marker:text-primary"
|
||||
className="prose prose-sm max-w-none p-4 min-h-[200px] focus:outline-none [&_.ProseMirror]:outline-none [&_.ProseMirror]:min-h-[180px] [&_img]:cursor-pointer [&_img.ProseMirror-selectednode]:ring-2 [&_img.ProseMirror-selectednode]:ring-primary [&_h1]:font-bold [&_h1]:text-2xl [&_h1]:mb-4 [&_h1]:mt-6 [&_h2]:font-bold [&_h2]:text-xl [&_h2]:mb-3 [&_h2]:mt-5 [&_blockquote]:border-l-4 [&_blockquote]:border-primary [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:text-muted-foreground [&_blockquote]:my-4 [&_ul]:list-disc [&_ul]:pl-6 [&_ul]:space-y-1 [&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:space-y-1 [&_li]:marker:text-primary [&_hr]:border-border [&_hr]:my-4 [&_hr]:border-t-2"
|
||||
/>
|
||||
</div>
|
||||
{uploading && (
|
||||
|
||||
Reference in New Issue
Block a user