mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 08:25:43 +00:00
149 lines
5.1 KiB
TypeScript
149 lines
5.1 KiB
TypeScript
// @ts-ignore - Tiptap type declarations issue
|
|
import { useEditor, EditorContent } from "@tiptap/react";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import StarterKit from "@tiptap/starter-kit";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import Underline from "@tiptap/extension-underline";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import Link from "@tiptap/extension-link";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import TextAlign from "@tiptap/extension-text-align";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import Image from "@tiptap/extension-image";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import { Color } from "@tiptap/extension-color";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import { TextStyle } from "@tiptap/extension-text-style";
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
import Highlight from "@tiptap/extension-highlight";
|
|
import { useEffect } from "react";
|
|
import { cn } from "@/shared/lib/utils";
|
|
|
|
interface RichTextViewerProps {
|
|
content: string;
|
|
minHeight?: number;
|
|
className?: string;
|
|
variant?: "default" | "minimal" | "bordered";
|
|
}
|
|
|
|
const RichTextViewer = ({
|
|
content,
|
|
minHeight = 200,
|
|
className,
|
|
variant = "default",
|
|
}: RichTextViewerProps) => {
|
|
// @ts-ignore - Tiptap type declarations issue
|
|
const extensions = [
|
|
// @ts-ignore
|
|
StarterKit.configure({
|
|
heading: {
|
|
levels: [1, 2, 3],
|
|
},
|
|
}),
|
|
// @ts-ignore
|
|
Underline.configure(),
|
|
// @ts-ignore
|
|
TextStyle.configure(),
|
|
// @ts-ignore
|
|
Highlight.configure({ multicolor: true }),
|
|
// @ts-ignore
|
|
Color.configure(),
|
|
// @ts-ignore
|
|
Link.configure({
|
|
openOnClick: false,
|
|
HTMLAttributes: {
|
|
rel: "noopener noreferrer",
|
|
target: "_blank",
|
|
class: "text-blue-600 hover:text-blue-800 underline",
|
|
},
|
|
}),
|
|
// @ts-ignore
|
|
TextAlign.configure({
|
|
types: ["heading", "paragraph"],
|
|
alignments: ["left", "center", "right", "justify"],
|
|
}),
|
|
// @ts-ignore
|
|
Image.configure({
|
|
inline: true,
|
|
allowBase64: true,
|
|
HTMLAttributes: {
|
|
class: "rounded-md max-w-full h-auto",
|
|
},
|
|
}),
|
|
];
|
|
|
|
const editor = useEditor({
|
|
extensions,
|
|
content,
|
|
editable: false,
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (editor && content !== editor.getHTML()) {
|
|
editor.commands.setContent(content);
|
|
}
|
|
}, [content, editor]);
|
|
|
|
if (!editor) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"animate-pulse bg-gray-200 rounded-md",
|
|
"dark:bg-gray-700",
|
|
className
|
|
)}
|
|
style={{ minHeight: `${minHeight}px` }}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const variantStyles = {
|
|
default:
|
|
"border border-gray-200 rounded-md bg-white shadow-sm dark:border-gray-700 dark:bg-gray-900",
|
|
minimal: "bg-transparent",
|
|
bordered: "border border-gray-200 rounded-md dark:border-gray-700",
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={cn(variantStyles[variant], className)}
|
|
style={{ minHeight: `${minHeight}px` }}>
|
|
<EditorContent
|
|
editor={editor}
|
|
className={cn(
|
|
"px-6 py-4 min-h-[200px]",
|
|
// Base typography styles
|
|
"[&_.tiptap]:outline-none",
|
|
"[&_.tiptap_h1]:text-2xl [&_.tiptap_h1]:font-bold [&_.tiptap_h1]:my-4",
|
|
"[&_.tiptap_h2]:text-xl [&_.tiptap_h2]:font-bold [&_.tiptap_h2]:my-3",
|
|
"[&_.tiptap_h3]:text-lg [&_.tiptap_h3]:font-bold [&_.tiptap_h3]:my-2",
|
|
"[&_.tiptap_p]:my-2 [&_.tiptap_p]:leading-relaxed",
|
|
"[&_.tiptap_ul]:my-2 [&_.tiptap_ul]:list-disc [&_.tiptap_ul]:pl-6",
|
|
"[&_.tiptap_ol]:my-2 [&_.tiptap_ol]:list-decimal [&_.tiptap_ol]:pl-6",
|
|
"[&_.tiptap_li]:my-1",
|
|
"[&_.tiptap_blockquote]:border-l-4 [&_.tiptap_blockquote]:border-gray-300",
|
|
"[&_.tiptap_blockquote]:pl-4 [&_.tiptap_blockquote]:italic [&_.tiptap_blockquote]:my-2",
|
|
"[&_.tiptap_code]:bg-gray-100 [&_.tiptap_code]:px-1 [&_.tiptap_code]:rounded",
|
|
"[&_.tiptap_code]:text-sm dark:[&_.tiptap_code]:bg-gray-800",
|
|
"[&_.tiptap_pre]:bg-gray-900 [&_.tiptap_pre]:text-white [&_.tiptap_pre]:p-4",
|
|
"[&_.tiptap_pre]:rounded-md [&_.tiptap_pre]:my-2 dark:[&_.tiptap_pre]:bg-gray-800",
|
|
"[&_.tiptap_strong]:font-bold",
|
|
"[&_.tiptap_em]:italic",
|
|
"[&_.tiptap_underline]:underline",
|
|
"[&_.tiptap_highlight]:bg-yellow-200 dark:[&_.tiptap_highlight]:bg-yellow-800",
|
|
"[&_.tiptap_table]:border-collapse [&_.tiptap_table]:border [&_.tiptap_table]:border-gray-300",
|
|
"[&_.tiptap_th]:bg-gray-100 [&_.tiptap_th]:p-2 dark:[&_.tiptap_th]:bg-gray-800",
|
|
"[&_.tiptap_td]:p-2 [&_.tiptap_td]:border [&_.tiptap_td]:border-gray-300",
|
|
"dark:[&_.tiptap_td]:border-gray-700",
|
|
"[&_.tiptap_img]:rounded-md [&_.tiptap_img]:max-w-full [&_.tiptap_img]:h-auto",
|
|
// Dark mode support
|
|
"dark:[&_.tiptap]:text-gray-100",
|
|
"dark:[&_.tiptap_blockquote]:border-gray-600"
|
|
)}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default RichTextViewer;
|