Files
hipmi/src/app/zCoba/text_editor2/page.tsx
2025-04-24 17:36:21 +08:00

211 lines
5.6 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import {
Box,
Button,
Group,
Image,
Paper,
ScrollArea,
SimpleGrid,
Stack,
Text,
Tooltip,
Modal,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import dynamic from "next/dynamic";
import { MainColor } from "@/app_modules/_global/color";
import { listStiker } from "@/app_modules/_global/lib/stiker";
// Dynamic import ReactQuill dengan SSR disabled
const ReactQuill = dynamic(
async () => {
const { default: RQ } = await import("react-quill");
// Tidak perlu import CSS dengan import statement
return function comp({ forwardedRef, ...props }: any) {
return <RQ ref={forwardedRef} {...props} />;
};
},
{ ssr: false, loading: () => <p>Loading Editor...</p> }
);
type ChatItem = {
content: string; // HTML content including text and stickers
};
export default function Page() {
const [editorContent, setEditorContent] = useState("");
const [chat, setChat] = useState<ChatItem[]>([]);
const [opened, { open, close }] = useDisclosure(false);
const quillRef = React.useRef<any>(null);
const [quillLoaded, setQuillLoaded] = useState(false);
// Load CSS on client-side only
useEffect(() => {
// Add Quill CSS via <link> tag
const link = document.createElement("link");
link.href = "https://cdn.quilljs.com/1.3.6/quill.snow.css";
link.rel = "stylesheet";
document.head.appendChild(link);
// Add custom style for stickers inside Quill editor
const style = document.createElement("style");
style.textContent = `
.ql-editor img {
max-width: 100px !important;
max-height: 100px !important;
}
.chat-content img {
max-width: 70px !important;
max-height: 70px !important;
}
`;
document.head.appendChild(style);
setQuillLoaded(true);
return () => {
// Clean up when component unmounts
document.head.removeChild(link);
document.head.removeChild(style);
};
}, []);
// Custom toolbar options for ReactQuill
const modules = {
toolbar: [
[{ header: [1, 2, false] }],
["bold", "italic", "underline", "strike", "blockquote"],
[{ list: "ordered" }, { list: "bullet" }],
["link", "image"],
["clean"],
],
};
const formats = [
"header",
"bold",
"italic",
"underline",
"strike",
"blockquote",
"list",
"bullet",
"link",
"image",
];
const insertSticker = (stickerUrl: string) => {
if (!quillRef.current) return;
const quill = quillRef.current.getEditor();
const range = quill.getSelection(true);
// Custom image insertion with size
// Use custom blot or HTML string with size attributes
const stickerHtml = `<img src="${stickerUrl}" alt="sticker" style="width: 40px; height: 40px;">`;
// Insert HTML at cursor position
quill.clipboard.dangerouslyPasteHTML(range.index, stickerHtml);
// Move cursor after inserted sticker
quill.setSelection(range.index + 1, 0);
// Focus back on editor
quill.focus();
// Close sticker modal
close();
};
// Function to send message
const sendMessage = () => {
if (editorContent.trim() !== "") {
setChat((prev) => [...prev, { content: editorContent }]);
setEditorContent(""); // Clear after sending
}
};
return (
<Stack p={"md"} spacing="md">
<SimpleGrid cols={2}>
<Stack bg={"gray.1"} h={560} p="md">
<Stack>
<ScrollArea>
{chat.map((item, index) => (
<Box key={index} mb="md">
<div
className="chat-content"
dangerouslySetInnerHTML={{ __html: item.content }}
/>
</Box>
))}
</ScrollArea>
</Stack>
</Stack>
<Paper withBorder p="md">
<Text size="sm" weight={500} mb="xs">
Chat Preview Data:
</Text>
<ScrollArea h={520}>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(chat, null, 2)}
</pre>
</ScrollArea>
</Paper>
</SimpleGrid>
<Box w="100%" maw={800}>
<Box mb="xs" bg={MainColor.white}>
{quillLoaded && (
<ReactQuill
forwardedRef={quillRef}
theme="snow"
value={editorContent}
onChange={setEditorContent}
modules={modules}
formats={formats}
placeholder="Ketik pesan di sini atau tambahkan stiker..."
style={{
height: 120,
marginBottom: 40,
backgroundColor: MainColor.white,
}}
/>
)}
</Box>
<Group position="apart">
<Button variant="outline" onClick={open} color="blue">
Tambah Stiker
</Button>
<Button onClick={sendMessage}>Kirim Pesan</Button>
</Group>
</Box>
{/* Sticker Modal */}
<Modal opened={opened} onClose={close} title="Pilih Stiker" size="md">
<SimpleGrid cols={3} spacing="md">
{listStiker.map((item) => (
<Box key={item.id}>
<Tooltip label={item.name}>
<Image
src={item.url}
height={100}
width={100}
alt={item.name}
style={{ cursor: "pointer" }}
onClick={() => insertSticker(item.url)}
/>
</Tooltip>
</Box>
))}
</SimpleGrid>
</Modal>
</Stack>
);
}