import { message } from '@tauri-apps/plugin-dialog'; import Image from '@tiptap/extension-image'; import Placeholder from '@tiptap/extension-placeholder'; import { EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import { convert } from 'html-to-text'; import { useState } from 'react'; import { twMerge } from 'tailwind-merge'; import { MediaUploader, MentionPopup } from '@shared/composer'; import { CancelIcon, LoaderIcon } from '@shared/icons'; import { MentionNote } from '@shared/notes'; import { useComposer } from '@stores/composer'; import { useNostr } from '@utils/hooks/useNostr'; import { sendNativeNotification } from '@utils/notification'; export function Composer() { const [loading, setLoading] = useState(false); const [reply, clearReply] = useComposer((state) => [state.reply, state.clearReply]); const { publish } = useNostr(); const expand = useComposer((state) => state.expand); const editor = useEditor({ extensions: [ StarterKit.configure({ dropcursor: { color: '#fff', }, }), Placeholder.configure({ placeholder: 'Type something...' }), Image.configure({ HTMLAttributes: { class: 'rounded-lg w-2/3 h-auto border border-white/10 outline outline-2 outline-offset-0 outline-white/20 ml-1', }, }), ], content: JSON.parse(localStorage.getItem('editor-content') || '{}'), editorProps: { attributes: { class: 'h-full markdown break-all overflow-y-auto outline-none pr-2', }, }, onUpdate: ({ editor }) => { const jsonContent = JSON.stringify(editor.getJSON()); localStorage.setItem('editor-content', jsonContent); }, }); const submit = async () => { try { setLoading(true); // get plaintext content const html = editor.getHTML(); const serializedContent = convert(html, { selectors: [ { selector: 'a', options: { linkBrackets: false } }, { selector: 'img', options: { linkBrackets: false } }, ], }); // define tags let tags: string[][] = []; // add reply to tags if present if (reply.id && reply.pubkey) { if (reply.root && reply.root.length > 1) { tags = [ ['e', reply.root, '', 'root'], ['e', reply.id, '', 'reply'], ['p', reply.pubkey], ]; } else { tags = [ ['e', reply.id, '', 'reply'], ['p', reply.pubkey], ]; } } // add hashtag to tags if present const hashtags = serializedContent .split(/\s/gm) .filter((s: string) => s.startsWith('#')); hashtags?.forEach((tag: string) => { tags.push(['t', tag.replace('#', '')]); }); // publish message await publish({ content: serializedContent, kind: 1, tags }); // send native notifiation await sendNativeNotification('Post has been published successfully.'); // update state setLoading(false); // reset editor editor.commands.clearContent(); // reset reply if (reply.id) { clearReply(); } } catch { setLoading(false); await message('Publishing post failed.', { title: 'Lume', type: 'error' }); } }; return (
{reply.id && (
)}
); }