diff --git a/package.json b/package.json
index 1bfbab73..7d2c74ab 100644
--- a/package.json
+++ b/package.json
@@ -50,9 +50,12 @@
"@tauri-apps/plugin-upload": "2.0.0-alpha.1",
"@tauri-apps/plugin-window": "2.0.0-alpha.1",
"@tiptap/extension-character-count": "^2.1.12",
+ "@tiptap/extension-document": "^2.1.12",
"@tiptap/extension-image": "^2.1.12",
"@tiptap/extension-mention": "^2.1.12",
+ "@tiptap/extension-paragraph": "^2.1.12",
"@tiptap/extension-placeholder": "^2.1.12",
+ "@tiptap/extension-text": "^2.1.12",
"@tiptap/pm": "^2.1.12",
"@tiptap/react": "^2.1.12",
"@tiptap/starter-kit": "^2.1.12",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 052cff96..335964cc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -101,15 +101,24 @@ dependencies:
'@tiptap/extension-character-count':
specifier: ^2.1.12
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
+ '@tiptap/extension-document':
+ specifier: ^2.1.12
+ version: 2.1.12(@tiptap/core@2.1.12)
'@tiptap/extension-image':
specifier: ^2.1.12
version: 2.1.12(@tiptap/core@2.1.12)
'@tiptap/extension-mention':
specifier: ^2.1.12
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)(@tiptap/suggestion@2.1.12)
+ '@tiptap/extension-paragraph':
+ specifier: ^2.1.12
+ version: 2.1.12(@tiptap/core@2.1.12)
'@tiptap/extension-placeholder':
specifier: ^2.1.12
version: 2.1.12(@tiptap/core@2.1.12)(@tiptap/pm@2.1.12)
+ '@tiptap/extension-text':
+ specifier: ^2.1.12
+ version: 2.1.12(@tiptap/core@2.1.12)
'@tiptap/pm':
specifier: ^2.1.12
version: 2.1.12
diff --git a/src/app.css b/src/app.css
index b425d849..a22f5396 100644
--- a/src/app.css
+++ b/src/app.css
@@ -4,6 +4,14 @@
@tailwind components;
@tailwind utilities;
+@layer utilities {
+ .break-p {
+ word-break: break-word;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ }
+}
+
html {
font-size: 14px;
}
diff --git a/src/app.tsx b/src/app.tsx
index 009d7157..1ec6544a 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -6,6 +6,7 @@ import { OnboardingScreen } from '@app/auth/onboarding';
import { ChatsScreen } from '@app/chats';
import { ErrorScreen } from '@app/error';
import { ExploreScreen } from '@app/explore';
+import { NewScreen } from '@app/new';
import { useStorage } from '@libs/storage/provider';
@@ -118,18 +119,39 @@ export default function App() {
},
],
},
+ {
+ path: '/new',
+ element: ,
+ errorElement: ,
+ children: [
+ {
+ path: '',
+ async lazy() {
+ const { NewPostScreen } = await import('@app/new/post');
+ return { Component: NewPostScreen };
+ },
+ },
+ {
+ path: 'article',
+ async lazy() {
+ const { NewArticleScreen } = await import('@app/new/article');
+ return { Component: NewArticleScreen };
+ },
+ },
+ {
+ path: 'file',
+ async lazy() {
+ const { NewFileScreen } = await import('@app/new/file');
+ return { Component: NewFileScreen };
+ },
+ },
+ ],
+ },
{
path: '/notes',
element: ,
errorElement: ,
children: [
- {
- path: 'new',
- async lazy() {
- const { NewNoteScreen } = await import('@app/notes/new');
- return { Component: NewNoteScreen };
- },
- },
{
path: 'text/:id',
async lazy() {
diff --git a/src/app/chats/components/chatForm.tsx b/src/app/chats/components/chatForm.tsx
index 4936b791..ace68a08 100644
--- a/src/app/chats/components/chatForm.tsx
+++ b/src/app/chats/components/chatForm.tsx
@@ -1,11 +1,12 @@
+import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { nip04 } from 'nostr-tools';
import { useCallback, useState } from 'react';
import { MediaUploader } from '@app/chats/components/mediaUploader';
-import { EnterIcon } from '@shared/icons';
+import { useNDK } from '@libs/ndk/provider';
-import { useNostr } from '@utils/hooks/useNostr';
+import { EnterIcon } from '@shared/icons';
export function ChatForm({
receiverPubkey,
@@ -15,7 +16,7 @@ export function ChatForm({
userPubkey: string;
userPrivkey: string;
}) {
- const { publish } = useNostr();
+ const { ndk } = useNDK();
const [value, setValue] = useState('');
const encryptMessage = useCallback(async () => {
@@ -26,8 +27,12 @@ export function ChatForm({
const message = await encryptMessage();
const tags = [['p', receiverPubkey]];
- // publish message
- await publish({ content: message, kind: 4, tags });
+ const event = new NDKEvent(ndk);
+ event.content = message;
+ event.kind = NDKKind.EncryptedDirectMessage;
+ event.tags = tags;
+
+ await event.publish();
// reset state
setValue('');
diff --git a/src/app/new/article.tsx b/src/app/new/article.tsx
new file mode 100644
index 00000000..38998e35
--- /dev/null
+++ b/src/app/new/article.tsx
@@ -0,0 +1,270 @@
+import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
+import CharacterCount from '@tiptap/extension-character-count';
+import Image from '@tiptap/extension-image';
+import Placeholder from '@tiptap/extension-placeholder';
+import { EditorContent, FloatingMenu, useEditor } from '@tiptap/react';
+import StarterKit from '@tiptap/starter-kit';
+import { useMemo, useState } from 'react';
+import { toast } from 'sonner';
+import { twMerge } from 'tailwind-merge';
+import { Markdown } from 'tiptap-markdown';
+
+import { ArticleCoverUploader, MediaUploader, MentionPopup } from '@app/new/components';
+
+import { useNDK } from '@libs/ndk/provider';
+
+import {
+ BoldIcon,
+ Heading1Icon,
+ Heading2Icon,
+ Heading3Icon,
+ ItalicIcon,
+ LoaderIcon,
+ ThreadsIcon,
+} from '@shared/icons';
+
+export function NewArticleScreen() {
+ const { ndk } = useNDK();
+
+ const [loading, setLoading] = useState(false);
+ const [title, setTitle] = useState('');
+ const [summary, setSummary] = useState({ open: false, content: '' });
+ const [cover, setCover] = useState('');
+
+ const ident = useMemo(() => String(Date.now()), []);
+ const editor = useEditor({
+ extensions: [
+ StarterKit.configure(),
+ Placeholder.configure({ placeholder: 'Type something...' }),
+ Image.configure({
+ HTMLAttributes: {
+ class:
+ 'rounded-lg w-full object-cover h-auto max-h-[400px] border border-neutral-200 dark:border-neutral-800 outline outline-1 outline-offset-0 outline-neutral-300 dark:outline-neutral-700',
+ },
+ }),
+ CharacterCount.configure(),
+ Markdown.configure({
+ html: false,
+ tightLists: true,
+ linkify: true,
+ transformPastedText: true,
+ }),
+ ],
+ content: JSON.parse(localStorage.getItem('editor-post') || '{}'),
+ editorProps: {
+ attributes: {
+ class:
+ 'outline-none prose prose-lg prose-neutral max-w-none select-text whitespace-pre-line break-words dark:prose-invert hover:prose-a:text-blue-500',
+ },
+ },
+ onUpdate: ({ editor }) => {
+ const jsonContent = JSON.stringify(editor.getJSON());
+ localStorage.setItem('editor-article', jsonContent);
+ },
+ });
+
+ const submit = async () => {
+ try {
+ setLoading(true);
+
+ // get markdown content
+ const content = editor.storage.markdown.getMarkdown();
+
+ // define tags
+ const tags: string[][] = [
+ ['d', ident],
+ ['title', title],
+ ['image', cover],
+ ['summary', summary.content],
+ ['published_at', String(Math.floor(Date.now() / 1000))],
+ ];
+
+ // add hashtag to tags if present
+ const hashtags = content.split(/\s/gm).filter((s: string) => s.startsWith('#'));
+ hashtags?.forEach((tag: string) => {
+ tags.push(['t', tag.replace('#', '')]);
+ });
+
+ // publish message
+ const event = new NDKEvent(ndk);
+ event.content = content;
+ event.kind = NDKKind.Article;
+ event.tags = tags;
+
+ const publishedRelays = await event.publish();
+ if (publishedRelays) {
+ toast.success(`Broadcasted to ${publishedRelays.size} relays successfully.`);
+ // update state
+ setLoading(false);
+ // reset editor
+ editor.commands.clearContent();
+ localStorage.setItem('editor-article', '{}');
+ }
+ } catch (e) {
+ setLoading(false);
+ toast.error(e);
+ }
+ };
+
+ return (
+
+
+ {cover ? (
+
+ ) : null}
+
+
setTitle(e.target.value)}
+ />
+
0 ? '' : 'hidden'
+ )}
+ >
+
+
+
+
+ {summary.open ? (
+
+ ) : null}
+
+ {editor && (
+
+
+
+
+
+
+
+ )}
+
+
+
+
+
+
+ Article editor is still in beta. If you need a stable and more reliable
+ feature, you can use Habla (habla.news) instead.
+
+
+
+
+
+ {editor?.storage?.characterCount.characters()}
+
+
+ -
+
+
+ Identifier:
+ {ident}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/new/components/articleCoverUploader.tsx b/src/app/new/components/articleCoverUploader.tsx
new file mode 100644
index 00000000..0769a906
--- /dev/null
+++ b/src/app/new/components/articleCoverUploader.tsx
@@ -0,0 +1,84 @@
+import { message, open } from '@tauri-apps/plugin-dialog';
+import { readBinaryFile } from '@tauri-apps/plugin-fs';
+import { useState } from 'react';
+
+import { ImageIcon, LoaderIcon } from '@shared/icons';
+
+export function ArticleCoverUploader({ setCover }) {
+ const [loading, setLoading] = useState(false);
+
+ const uploadToNostrBuild = async () => {
+ try {
+ // start loading
+ setLoading(true);
+
+ const selected = await open({
+ multiple: false,
+ filters: [
+ {
+ name: 'Media',
+ extensions: [
+ 'png',
+ 'jpeg',
+ 'jpg',
+ 'gif',
+ 'mp4',
+ 'mp3',
+ 'webm',
+ 'mkv',
+ 'avi',
+ 'mov',
+ ],
+ },
+ ],
+ });
+
+ if (!selected) {
+ setLoading(false);
+ return;
+ }
+
+ const file = await readBinaryFile(selected.path);
+ const blob = new Blob([file]);
+
+ const data = new FormData();
+ data.append('fileToUpload', blob);
+ data.append('submit', 'Upload Image');
+
+ const res = await fetch('https://nostr.build/api/v2/upload/files', {
+ method: 'POST',
+ body: data,
+ });
+
+ if (res.ok) {
+ const json = await res.json();
+ const content = json.data[0];
+ setCover(content.url);
+
+ // stop loading
+ setLoading(false);
+ }
+ } catch (e) {
+ // stop loading
+ setLoading(false);
+ await message(`Upload failed, error: ${e}`, { title: 'Lume', type: 'error' });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/app/new/components/index.ts b/src/app/new/components/index.ts
new file mode 100644
index 00000000..46777124
--- /dev/null
+++ b/src/app/new/components/index.ts
@@ -0,0 +1,4 @@
+export * from './articleCoverUploader';
+export * from './mediaUploader';
+export * from './mentionPopup';
+export * from './mentionPopupItem';
diff --git a/src/shared/composer/mediaUploader.tsx b/src/app/new/components/mediaUploader.tsx
similarity index 100%
rename from src/shared/composer/mediaUploader.tsx
rename to src/app/new/components/mediaUploader.tsx
diff --git a/src/shared/composer/mention/popup.tsx b/src/app/new/components/mentionPopup.tsx
similarity index 93%
rename from src/shared/composer/mention/popup.tsx
rename to src/app/new/components/mentionPopup.tsx
index 5e5b3236..01be4ae3 100644
--- a/src/shared/composer/mention/popup.tsx
+++ b/src/app/new/components/mentionPopup.tsx
@@ -2,9 +2,10 @@ import * as Popover from '@radix-ui/react-popover';
import { Editor } from '@tiptap/react';
import { nip19 } from 'nostr-tools';
+import { MentionPopupItem } from '@app/new/components';
+
import { useStorage } from '@libs/storage/provider';
-import { MentionItem } from '@shared/composer';
import { MentionIcon } from '@shared/icons';
export function MentionPopup({ editor }: { editor: Editor }) {
@@ -34,7 +35,7 @@ export function MentionPopup({ editor }: { editor: Editor }) {
{db.account.follows.length > 0 ? (
db.account.follows.map((item) => (
))
) : (
diff --git a/src/shared/composer/mention/item.tsx b/src/app/new/components/mentionPopupItem.tsx
similarity index 94%
rename from src/shared/composer/mention/item.tsx
rename to src/app/new/components/mentionPopupItem.tsx
index 30288579..de27f95e 100644
--- a/src/shared/composer/mention/item.tsx
+++ b/src/app/new/components/mentionPopupItem.tsx
@@ -3,7 +3,7 @@ import { Image } from '@shared/image';
import { useProfile } from '@utils/hooks/useProfile';
import { displayNpub } from '@utils/shortenKey';
-export function MentionItem({ pubkey, embed }: { pubkey: string; embed?: string }) {
+export function MentionPopupItem({ pubkey, embed }: { pubkey: string; embed?: string }) {
const { status, user } = useProfile(pubkey, embed);
if (status === 'loading') {
diff --git a/src/app/notes/components/editor/file.tsx b/src/app/new/file.tsx
similarity index 62%
rename from src/app/notes/components/editor/file.tsx
rename to src/app/new/file.tsx
index 817d7d13..8501f960 100644
--- a/src/app/notes/components/editor/file.tsx
+++ b/src/app/new/file.tsx
@@ -8,12 +8,12 @@ import { useNDK } from '@libs/ndk/provider';
import { LoaderIcon } from '@shared/icons';
-export function FileEditor() {
+export function NewFileScreen() {
const { ndk } = useNDK();
const [loading, setLoading] = useState(false);
const [isPublish, setIsPublish] = useState(false);
- const [metadata, setMetadata] = useState(null);
+ const [metadata, setMetadata] = useState(null);
const [caption, setCaption] = useState('');
const uploadFile = async () => {
@@ -105,11 +105,11 @@ export function FileEditor() {
return (
-
+
)}
-
-
-
setCaption(e.target.value)}
- spellCheck={false}
- autoComplete="off"
- autoCorrect="off"
- autoCapitalize="off"
- placeholder="Caption (Optional)..."
- className="h-11 flex-1 rounded-lg bg-neutral-100 px-3 placeholder:text-neutral-500 dark:bg-neutral-900 dark:placeholder:text-neutral-400"
- />
-
+ {metadata ? (
+
+
+ {metadata.map((item, index) => (
+
+
+ {item[0]}
+
+
{item[1]}
+
+ ))}
+
+
+ setCaption(e.target.value)}
+ spellCheck={false}
+ autoComplete="off"
+ autoCorrect="off"
+ autoCapitalize="off"
+ placeholder="Caption (Optional)..."
+ className="h-11 w-full rounded-lg bg-neutral-200 px-3 placeholder:text-neutral-500 dark:bg-neutral-900 dark:placeholder:text-neutral-400"
+ />
+
+
-
+ ) : null}
);
diff --git a/src/app/new/index.tsx b/src/app/new/index.tsx
new file mode 100644
index 00000000..945689f8
--- /dev/null
+++ b/src/app/new/index.tsx
@@ -0,0 +1,77 @@
+import { Link, NavLink, Outlet } from 'react-router-dom';
+import { twMerge } from 'tailwind-merge';
+import { WindowTitlebar } from 'tauri-controls';
+
+import { useStorage } from '@libs/storage/provider';
+
+import { ArrowLeftIcon } from '@shared/icons';
+
+export function NewScreen() {
+ const { db } = useStorage();
+
+ return (
+
+ {db.platform !== 'macos' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+ twMerge(
+ 'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
+ isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
+ )
+ }
+ >
+ Post
+
+
+ twMerge(
+ 'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
+ isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
+ )
+ }
+ >
+ Article
+
+
+ twMerge(
+ 'inline-flex h-9 w-28 items-center justify-center rounded-lg text-sm font-medium',
+ isActive ? 'bg-white shadow dark:bg-black' : 'bg-transparent'
+ )
+ }
+ >
+ File Sharing
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/app/notes/components/editor/post.tsx b/src/app/new/post.tsx
similarity index 66%
rename from src/app/notes/components/editor/post.tsx
rename to src/app/new/post.tsx
index 60a90a88..afb92439 100644
--- a/src/app/notes/components/editor/post.tsx
+++ b/src/app/new/post.tsx
@@ -5,17 +5,22 @@ 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 { useEffect, useState } from 'react';
+import { useSearchParams } from 'react-router-dom';
import { toast } from 'sonner';
+import { MediaUploader, MentionPopup } from '@app/new/components';
+
import { useNDK } from '@libs/ndk/provider';
-import { MediaUploader, MentionPopup } from '@shared/composer';
-import { LoaderIcon } from '@shared/icons';
+import { CancelIcon, LoaderIcon } from '@shared/icons';
+import { MentionNote } from '@shared/notes';
+
+export function NewPostScreen() {
+ const { ndk, relayUrls } = useNDK();
-export function PostEditor() {
- const { ndk } = useNDK();
const [loading, setLoading] = useState(false);
+ const [searchParams, setSearchParams] = useSearchParams();
const editor = useEditor({
extensions: [
@@ -46,6 +51,12 @@ export function PostEditor() {
try {
setLoading(true);
+ const reply = {
+ id: searchParams.get('id'),
+ root: searchParams.get('root'),
+ pubkey: searchParams.get('pubkey'),
+ };
+
// get plaintext content
const html = editor.getHTML();
const serializedContent = convert(html, {
@@ -56,12 +67,29 @@ export function PostEditor() {
});
// define tags
- const tags: string[][] = [];
+ 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, relayUrls[0], 'root'],
+ ['e', reply.id, relayUrls[0], 'reply'],
+ ['p', reply.pubkey],
+ ];
+ } else {
+ tags = [
+ ['e', reply.id, relayUrls[0], '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('#', '')]);
});
@@ -78,6 +106,7 @@ export function PostEditor() {
// update state
setLoading(false);
// reset editor
+ setSearchParams({});
editor.commands.clearContent();
localStorage.setItem('editor-post', '{}');
}
@@ -87,15 +116,33 @@ export function PostEditor() {
}
};
+ useEffect(() => {
+ if (editor) editor.commands.focus('end');
+ }, [editor]);
+
return (
-
+
+
+ {searchParams.get('id') && (
+
+
+
+
+ )}
+
{editor?.storage?.characterCount.characters()}
diff --git a/src/app/notes/components/editor/article.tsx b/src/app/notes/components/editor/article.tsx
deleted file mode 100644
index dc566182..00000000
--- a/src/app/notes/components/editor/article.tsx
+++ /dev/null
@@ -1,124 +0,0 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
-import CharacterCount from '@tiptap/extension-character-count';
-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 { toast } from 'sonner';
-
-import { useNDK } from '@libs/ndk/provider';
-
-import { MediaUploader, MentionPopup } from '@shared/composer';
-import { LoaderIcon } from '@shared/icons';
-
-export function ArticleEditor() {
- const { ndk } = useNDK();
- const [loading, setLoading] = useState(false);
-
- const editor = useEditor({
- extensions: [
- StarterKit.configure(),
- Placeholder.configure({ placeholder: 'Type something...' }),
- Image.configure({
- HTMLAttributes: {
- class:
- 'rounded-lg w-full object-cover h-auto max-h-[400px] border border-neutral-200 dark:border-neutral-800 outline outline-1 outline-offset-0 outline-neutral-300 dark:outline-neutral-700',
- },
- }),
- CharacterCount.configure(),
- ],
- content: JSON.parse(localStorage.getItem('editor-post') || '{}'),
- editorProps: {
- attributes: {
- class:
- 'outline-none prose prose-lg prose-neutral max-w-none select-text whitespace-pre-line break-words dark:prose-invert hover:prose-a:text-blue-500',
- },
- },
- onUpdate: ({ editor }) => {
- const jsonContent = JSON.stringify(editor.getJSON());
- localStorage.setItem('editor-post', 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
- const tags: string[][] = [];
-
- // 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
- const event = new NDKEvent(ndk);
- event.content = serializedContent;
- event.kind = NDKKind.Article;
- event.tags = tags;
-
- const publishedRelays = await event.publish();
- if (publishedRelays) {
- toast.success(`Broadcasted to ${publishedRelays.size} relays successfully.`);
- // update state
- setLoading(false);
- // reset editor
- editor.commands.clearContent();
- localStorage.setItem('editor-post', '{}');
- }
- } catch (e) {
- setLoading(false);
- toast.error(e);
- }
- };
-
- return (
-
-
-
-
- {editor?.storage?.characterCount.characters()}
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/app/notes/components/index.ts b/src/app/notes/components/index.ts
deleted file mode 100644
index 098a1ce3..00000000
--- a/src/app/notes/components/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './editor/post';
-export * from './editor/article';
-export * from './editor/file';
diff --git a/src/app/notes/new.tsx b/src/app/notes/new.tsx
deleted file mode 100644
index ea5034d1..00000000
--- a/src/app/notes/new.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { useState } from 'react';
-import { Link } from 'react-router-dom';
-import { twMerge } from 'tailwind-merge';
-
-import { ArticleEditor, FileEditor, PostEditor } from '@app/notes/components';
-
-import { ArrowLeftIcon } from '@shared/icons';
-
-export function NewNoteScreen() {
- const [type, setType] = useState<'post' | 'article' | 'file' | 'raw'>('post');
-
- const renderEditor = () => {
- switch (type) {
- case 'post':
- return ;
- case 'article':
- return ;
- case 'file':
- return ;
- default:
- return null;
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
{renderEditor()}
-
-
-
- );
-}
diff --git a/src/app/nwc/components/alby.tsx b/src/app/nwc/components/alby.tsx
index c1fa1297..b4e9c500 100644
--- a/src/app/nwc/components/alby.tsx
+++ b/src/app/nwc/components/alby.tsx
@@ -69,7 +69,7 @@ export function NWCAlby() {
diff --git a/src/app/nwc/components/other.tsx b/src/app/nwc/components/other.tsx
index 05ca0d9b..228afbe4 100644
--- a/src/app/nwc/components/other.tsx
+++ b/src/app/nwc/components/other.tsx
@@ -86,7 +86,7 @@ export function NWCOther() {
diff --git a/src/app/relays/components/relayList.tsx b/src/app/relays/components/relayList.tsx
index 1fc1da6f..c9723bf5 100644
--- a/src/app/relays/components/relayList.tsx
+++ b/src/app/relays/components/relayList.tsx
@@ -53,7 +53,7 @@ export function RelayList() {
) : (
-
+
All relays used by your follows
@@ -103,7 +103,6 @@ export function RelayList() {
))}
-
)}
diff --git a/src/libs/storage/instance.ts b/src/libs/storage/instance.ts
index a876b033..a13eecab 100644
--- a/src/libs/storage/instance.ts
+++ b/src/libs/storage/instance.ts
@@ -5,6 +5,7 @@ import Database from '@tauri-apps/plugin-sql';
import { FULL_RELAYS } from '@stores/constants';
+import { rawEvent } from '@utils/transform';
import { Account, DBEvent, Relays, Widget } from '@utils/types';
export class LumeStorage {
@@ -140,6 +141,8 @@ export class LumeStorage {
}
public async createEvent(event: NDKEvent) {
+ const rawNostrEvent = rawEvent(event);
+
let root: string;
let reply: string;
@@ -155,7 +158,7 @@ export class LumeStorage {
[
event.id,
this.account.id,
- JSON.stringify(event),
+ JSON.stringify(rawNostrEvent),
event.pubkey,
event.kind,
root,
diff --git a/src/shared/composer/composer.tsx b/src/shared/composer/composer.tsx
deleted file mode 100644
index 69593887..00000000
--- a/src/shared/composer/composer.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
-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 { useNDK } from '@libs/ndk/provider';
-
-import { MediaUploader, MentionPopup } from '@shared/composer';
-import { CancelIcon, LoaderIcon } from '@shared/icons';
-import { MentionNote } from '@shared/notes';
-
-import { useComposer } from '@stores/composer';
-
-export function Composer() {
- const [loading, setLoading] = useState(false);
- const [reply, clearReply] = useComposer((state) => [state.reply, state.clearReply]);
-
- const { ndk } = useNDK();
-
- 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 prose prose-neutral max-w-none select-text whitespace-pre-line leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-1 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500 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
- const event = new NDKEvent(ndk);
- event.content = serializedContent;
- event.kind = NDKKind.Text;
- event.tags = tags;
-
- const publish = event.publish();
- if (publish) {
- // 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 && (
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/shared/composer/index.ts b/src/shared/composer/index.ts
deleted file mode 100644
index a04ac892..00000000
--- a/src/shared/composer/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export * from './user';
-export * from './modal';
-export * from './composer';
-export * from './mention/item';
-export * from './mention/popup';
-export * from './mention/suggestion';
-export * from './mention/inlineList';
-export * from './mediaUploader';
diff --git a/src/shared/composer/mention/inlineList.tsx b/src/shared/composer/mention/inlineList.tsx
deleted file mode 100644
index 18f34179..00000000
--- a/src/shared/composer/mention/inlineList.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { type SuggestionProps } from '@tiptap/suggestion';
-import {
- ForwardedRef,
- forwardRef,
- useEffect,
- useImperativeHandle,
- useState,
-} from 'react';
-import { twMerge } from 'tailwind-merge';
-
-import { MentionItem } from '@shared/composer';
-
-export const MentionInlineList = forwardRef(
- (props: SuggestionProps, ref: ForwardedRef) => {
- const [selectedIndex, setSelectedIndex] = useState(0);
-
- const selectItem = (index) => {
- const item = props.items[index];
-
- if (item) {
- props.command({ id: item });
- }
- };
-
- const upHandler = () => {
- setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length);
- };
-
- const downHandler = () => {
- setSelectedIndex((selectedIndex + 1) % props.items.length);
- };
-
- const enterHandler = () => {
- selectItem(selectedIndex);
- };
-
- useEffect(() => setSelectedIndex(0), [props.items]);
-
- useImperativeHandle(ref, () => ({
- onKeyDown: ({ event }) => {
- if (event.key === 'ArrowUp') {
- upHandler();
- return true;
- }
-
- if (event.key === 'ArrowDown') {
- downHandler();
- return true;
- }
-
- if (event.key === 'Enter') {
- enterHandler();
- return true;
- }
-
- return false;
- },
- }));
-
- return (
-
- {props.items.length ? (
- props.items.map((item: string, index: number) => (
-
- ))
- ) : (
-
No result
- )}
-
- );
- }
-);
-
-MentionInlineList.displayName = 'MentionList';
diff --git a/src/shared/composer/mention/suggestion.tsx b/src/shared/composer/mention/suggestion.tsx
deleted file mode 100644
index 1d55ccb7..00000000
--- a/src/shared/composer/mention/suggestion.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { ReactRenderer } from '@tiptap/react';
-import tippy from 'tippy.js';
-
-import { MentionInlineList } from '@shared/composer';
-
-export const Suggestion = {
- items: async ({ query }) => {
- const users = [];
- return users
- .filter((item) => item.ident.toLowerCase().startsWith(query.toLowerCase()))
- .slice(0, 5);
- },
-
- render: () => {
- let component;
- let popup;
-
- return {
- onStart: (props) => {
- component = new ReactRenderer(MentionInlineList, {
- props,
- editor: props.editor,
- });
-
- if (!props.clientRect) {
- return;
- }
-
- popup = tippy('body', {
- getReferenceClientRect: props.clientRect,
- appendTo: () => document.body,
- content: component.element,
- showOnCreate: true,
- interactive: true,
- trigger: 'manual',
- placement: 'bottom-start',
- });
- },
-
- onUpdate(props) {
- component.updateProps(props);
-
- if (!props.clientRect) {
- return;
- }
-
- popup[0].setProps({
- getReferenceClientRect: props.clientRect,
- });
- },
-
- onKeyDown(props) {
- if (props.event.key === 'Escape') {
- popup[0].hide();
-
- return true;
- }
-
- return component.ref?.onKeyDown(props);
- },
-
- onExit() {
- popup[0].destroy();
- component.destroy();
- },
- };
- },
-};
diff --git a/src/shared/composer/modal.tsx b/src/shared/composer/modal.tsx
deleted file mode 100644
index 0380a21c..00000000
--- a/src/shared/composer/modal.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as Dialog from '@radix-ui/react-dialog';
-
-import { useStorage } from '@libs/storage/provider';
-
-import { Composer, ComposerUser } from '@shared/composer';
-import {
- CancelIcon,
- ChevronDownIcon,
- ChevronRightIcon,
- ComposeIcon,
-} from '@shared/icons';
-
-import { useComposer } from '@stores/composer';
-
-export function ComposerModal() {
- const { db } = useStorage();
- const [toggleModal, open] = useComposer((state) => [state.toggleModal, state.open]);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/shared/composer/user.tsx b/src/shared/composer/user.tsx
deleted file mode 100644
index 8cfa6a1e..00000000
--- a/src/shared/composer/user.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { useProfile } from '@utils/hooks/useProfile';
-import { displayNpub } from '@utils/shortenKey';
-
-export function ComposerUser({ pubkey }: { pubkey: string }) {
- const { user } = useProfile(pubkey);
-
- return (
-
-
-
- {user?.display_name || user?.name || user?.displayName || displayNpub(pubkey, 16)}
-
-
- );
-}
diff --git a/src/shared/icons/bold.tsx b/src/shared/icons/bold.tsx
new file mode 100644
index 00000000..5b4e62e5
--- /dev/null
+++ b/src/shared/icons/bold.tsx
@@ -0,0 +1,22 @@
+import { SVGProps } from 'react';
+
+export function BoldIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/icons/heading1.tsx b/src/shared/icons/heading1.tsx
new file mode 100644
index 00000000..0d6a0387
--- /dev/null
+++ b/src/shared/icons/heading1.tsx
@@ -0,0 +1,22 @@
+import { SVGProps } from 'react';
+
+export function Heading1Icon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/icons/heading2.tsx b/src/shared/icons/heading2.tsx
new file mode 100644
index 00000000..6bbcbabe
--- /dev/null
+++ b/src/shared/icons/heading2.tsx
@@ -0,0 +1,22 @@
+import { SVGProps } from 'react';
+
+export function Heading2Icon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/icons/heading3.tsx b/src/shared/icons/heading3.tsx
new file mode 100644
index 00000000..5aa4672b
--- /dev/null
+++ b/src/shared/icons/heading3.tsx
@@ -0,0 +1,22 @@
+import { SVGProps } from 'react';
+
+export function Heading3Icon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/icons/index.ts b/src/shared/icons/index.ts
index 3bc53bf2..fc76dda2 100644
--- a/src/shared/icons/index.ts
+++ b/src/shared/icons/index.ts
@@ -73,3 +73,8 @@ export * from './explore2';
export * from './home';
export * from './chats';
export * from './community';
+export * from './heading1';
+export * from './heading2';
+export * from './heading3';
+export * from './bold';
+export * from './italic';
diff --git a/src/shared/icons/italic.tsx b/src/shared/icons/italic.tsx
new file mode 100644
index 00000000..604538fc
--- /dev/null
+++ b/src/shared/icons/italic.tsx
@@ -0,0 +1,22 @@
+import { SVGProps } from 'react';
+
+export function ItalicIcon(props: JSX.IntrinsicAttributes & SVGProps) {
+ return (
+
+ );
+}
diff --git a/src/shared/navigation.tsx b/src/shared/navigation.tsx
index 4b85149e..145f9b97 100644
--- a/src/shared/navigation.tsx
+++ b/src/shared/navigation.tsx
@@ -104,7 +104,7 @@ export function Navigation() {
diff --git a/src/shared/notes/actions/reaction.tsx b/src/shared/notes/actions/reaction.tsx
index ca9a2913..9a126c33 100644
--- a/src/shared/notes/actions/reaction.tsx
+++ b/src/shared/notes/actions/reaction.tsx
@@ -1,10 +1,10 @@
-import { NDKKind } from '@nostr-dev-kit/ndk';
+import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import * as Popover from '@radix-ui/react-popover';
import { useState } from 'react';
-import { ReactionIcon } from '@shared/icons';
+import { useNDK } from '@libs/ndk/provider';
-import { useNostr } from '@utils/hooks/useNostr';
+import { ReactionIcon } from '@shared/icons';
const REACTIONS = [
{
@@ -30,11 +30,11 @@ const REACTIONS = [
];
export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
+ const { ndk } = useNDK();
+
const [open, setOpen] = useState(false);
const [reaction, setReaction] = useState
(null);
- const { publish } = useNostr();
-
const getReactionImage = (content: string) => {
const reaction: { img: string } = REACTIONS.find((el) => el.content === content);
return reaction.img;
@@ -43,16 +43,16 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
const react = async (content: string) => {
setReaction(content);
- const event = await publish({
- content: content,
- kind: NDKKind.Reaction,
- tags: [
- ['e', id],
- ['p', pubkey],
- ],
- });
+ const event = new NDKEvent(ndk);
+ event.content = content;
+ event.kind = NDKKind.Reaction;
+ event.tags = [
+ ['e', id],
+ ['p', pubkey],
+ ];
- if (event) {
+ const publishedRelays = await event.publish();
+ if (publishedRelays) {
setOpen(false);
}
};
diff --git a/src/shared/notes/actions/reply.tsx b/src/shared/notes/actions/reply.tsx
index ef8cf761..29fc1c4e 100644
--- a/src/shared/notes/actions/reply.tsx
+++ b/src/shared/notes/actions/reply.tsx
@@ -1,9 +1,8 @@
import * as Tooltip from '@radix-ui/react-tooltip';
+import { createSearchParams, useNavigate } from 'react-router-dom';
import { ReplyIcon } from '@shared/icons';
-import { useComposer } from '@stores/composer';
-
export function NoteReply({
id,
pubkey,
@@ -13,14 +12,23 @@ export function NoteReply({
pubkey: string;
root?: string;
}) {
- const setReply = useComposer((state) => state.setReply);
+ const navigate = useNavigate();
return (
-
+
-
-
-
+
+
+
Confirm repost this post?
@@ -77,14 +81,14 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
-
submit()}
- className="inline-flex h-9 w-28 items-center justify-center rounded-md bg-white/10 text-sm font-medium leading-none text-white outline-none hover:bg-blue-600"
+ className="inline-flex h-9 w-24 items-center justify-center rounded-md bg-blue-500 text-sm font-medium leading-none text-white outline-none hover:bg-blue-600"
>
{isLoading ? (
diff --git a/src/shared/notes/child.tsx b/src/shared/notes/child.tsx
index 4643989b..e9221cc8 100644
--- a/src/shared/notes/child.tsx
+++ b/src/shared/notes/child.tsx
@@ -1,6 +1,5 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { nip19 } from 'nostr-tools';
-import { Link } from 'react-router-dom';
import {
ArticleNote,
@@ -49,24 +48,17 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
-
-
-
-
- Lume (System)
+
+
+ Lume (System)
-
-
-
- Lume cannot find this post with your current relays, but you can view it
- via njump.me.{' '}
-
- Learn more
-
-
+
+
+ Lume cannot find this post with your current relay set, but you can view
+ it via njump.me
diff --git a/src/shared/notes/kinds/file.tsx b/src/shared/notes/kinds/file.tsx
index 1671c4a9..67e5bf2d 100644
--- a/src/shared/notes/kinds/file.tsx
+++ b/src/shared/notes/kinds/file.tsx
@@ -41,7 +41,7 @@ export function FileNote(props: { event?: NDKEvent }) {
slot="media"
src={url}
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
- preload="auto"
+ preload="none"
muted
crossOrigin=""
/>
diff --git a/src/shared/notes/kinds/repost.tsx b/src/shared/notes/kinds/repost.tsx
index ce9a29f4..cd82b269 100644
--- a/src/shared/notes/kinds/repost.tsx
+++ b/src/shared/notes/kinds/repost.tsx
@@ -2,7 +2,6 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query';
import { nip19 } from 'nostr-tools';
import { memo, useCallback } from 'react';
-import { Link } from 'react-router-dom';
import { twMerge } from 'tailwind-merge';
import { useNDK } from '@libs/ndk/provider';
@@ -113,24 +112,17 @@ export function Repost({
>
-
-
-
-
- Lume (System)
+
+
+ Lume (System)
-
-
-
-
- Lume cannot find this post with your current relays, but you can view
- it via njump.me.{' '}
-
- Learn more
-
-
+
+
+
+ Lume cannot find this post with your current relay set, but you can view
+ it via njump.me
diff --git a/src/shared/notes/kinds/text.tsx b/src/shared/notes/kinds/text.tsx
index 325a5eb6..f061738d 100644
--- a/src/shared/notes/kinds/text.tsx
+++ b/src/shared/notes/kinds/text.tsx
@@ -23,7 +23,7 @@ export function TextNote(props: { content?: string }) {
return (
{
diff --git a/src/shared/notes/preview/link.tsx b/src/shared/notes/preview/link.tsx
index ae8c06b3..8652e917 100644
--- a/src/shared/notes/preview/link.tsx
+++ b/src/shared/notes/preview/link.tsx
@@ -52,7 +52,7 @@ export function LinkPreview({ urls }: { urls: string[] }) {
)}
{data.description && (
-
+
{data.description}
)}
diff --git a/src/shared/notes/preview/video.tsx b/src/shared/notes/preview/video.tsx
index f9808dc2..681da5a1 100644
--- a/src/shared/notes/preview/video.tsx
+++ b/src/shared/notes/preview/video.tsx
@@ -18,7 +18,7 @@ export const VideoPreview = memo(function VideoPreview({ urls }: { urls: string[
slot="media"
src={url}
poster={`https://thumbnail.video/api/get?url=${url}&seconds=1`}
- preload="auto"
+ preload="none"
muted
/>
diff --git a/src/shared/notes/skeleton.tsx b/src/shared/notes/skeleton.tsx
index 08e84289..a0385c2b 100644
--- a/src/shared/notes/skeleton.tsx
+++ b/src/shared/notes/skeleton.tsx
@@ -2,8 +2,10 @@ export function NoteSkeleton() {
return (
diff --git a/src/shared/notes/wrapper.tsx b/src/shared/notes/wrapper.tsx
index 0a2d0f0b..27d6d5b5 100644
--- a/src/shared/notes/wrapper.tsx
+++ b/src/shared/notes/wrapper.tsx
@@ -38,7 +38,7 @@ export function NoteWrapper({
children,
event.kind === 1 ? { content: event.content } : { event: event }
)}
-
+
diff --git a/src/shared/user.tsx b/src/shared/user.tsx
index e74bdc68..98cf7a13 100644
--- a/src/shared/user.tsx
+++ b/src/shared/user.tsx
@@ -80,7 +80,7 @@ export const User = memo(function User({
loading="lazy"
decoding="async"
style={{ contentVisibility: 'auto' }}
- className="h-6 w-6 rounded"
+ className="h-6 w-6 rounded-md"
/>
-
+
{user?.name ||
user?.display_name ||
user?.displayName ||
displayNpub(pubkey, 16)}
- ·
- {createdAt}
+ ·
+ {createdAt}
);
diff --git a/src/shared/widgets/local/network.tsx b/src/shared/widgets/local/network.tsx
index 79339cd7..d5d13457 100644
--- a/src/shared/widgets/local/network.tsx
+++ b/src/shared/widgets/local/network.tsx
@@ -21,7 +21,6 @@ import { EventLoader, WidgetWrapper } from '@shared/widgets';
import { WidgetKinds, useWidgets } from '@stores/widgets';
import { useNostr } from '@utils/hooks/useNostr';
-import { toRawEvent } from '@utils/rawEvent';
import { DBEvent } from '@utils/types';
export function LocalNetworkWidget() {
@@ -103,8 +102,7 @@ export function LocalNetworkWidget() {
};
sub(filter, async (event) => {
- const rawEvent = toRawEvent(event);
- await db.createEvent(rawEvent);
+ await db.createEvent(event);
});
}
}, [data]);
diff --git a/src/stores/composer.ts b/src/stores/composer.ts
deleted file mode 100644
index 736dac60..00000000
--- a/src/stores/composer.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { create } from 'zustand';
-
-interface ComposerState {
- expand: boolean;
- open: boolean;
- reply: { id: string; pubkey: string; root?: string };
- toggleModal: () => void;
- toggleExpand: () => void;
- setReply: (id: string, pubkey: string, root?: string) => void;
- clearReply: () => void;
-}
-
-export const useComposer = create
((set) => ({
- expand: false,
- open: false,
- reply: { id: null, pubkey: null, root: null },
- toggleModal: () => {
- set((state) => ({ open: !state.open }));
- },
- toggleExpand: () => {
- set((state) => ({ expand: !state.expand }));
- },
- setReply: (id: string, pubkey: string, root?: string) => {
- set({ reply: { id: id, pubkey: pubkey, root: root } });
- set({ open: true });
- },
- clearReply: () => {
- set({ reply: { id: null, pubkey: null, root: null } });
- },
-}));
diff --git a/src/stores/constants.ts b/src/stores/constants.ts
index 6508d0ea..5a76cdfc 100644
--- a/src/stores/constants.ts
+++ b/src/stores/constants.ts
@@ -1,6 +1,7 @@
export const FULL_RELAYS = [
'wss://relay.damus.io',
- 'wss://nos.lol',
+ 'wss://relay.primal.net',
+ 'wss://relayable.org',
'wss://relay.nostr.band/all',
'wss://nostr.mutinywallet.com',
];
diff --git a/src/utils/hooks/useEvent.ts b/src/utils/hooks/useEvent.ts
index 77b706e2..04439286 100644
--- a/src/utils/hooks/useEvent.ts
+++ b/src/utils/hooks/useEvent.ts
@@ -1,12 +1,10 @@
import { NDKEvent } from '@nostr-dev-kit/ndk';
import { useQuery } from '@tanstack/react-query';
-import { AddressPointer } from 'nostr-tools/lib/nip19';
+import { AddressPointer } from 'nostr-tools/lib/types/nip19';
import { useNDK } from '@libs/ndk/provider';
import { useStorage } from '@libs/storage/provider';
-import { toRawEvent } from '@utils/rawEvent';
-
export function useEvent(
id: undefined | string,
naddr?: undefined | AddressPointer,
@@ -43,8 +41,7 @@ export function useEvent(
const event = await ndk.fetchEvent(id);
if (!event) return Promise.reject(new Error('event not found'));
- const rawEvent = toRawEvent(event);
- await db.createEvent(rawEvent);
+ await db.createEvent(event);
return event;
},
diff --git a/src/utils/rawEvent.ts b/src/utils/rawEvent.ts
deleted file mode 100644
index acb885d2..00000000
--- a/src/utils/rawEvent.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { NDKEvent } from '@nostr-dev-kit/ndk';
-
-export function toRawEvent(event: NDKEvent) {
- delete event.ndk;
- delete event.decrypt;
- delete event.encrypt;
- delete event.encode;
- delete event.isParamReplaceable;
- delete event.isReplaceable;
- delete event.repost;
- return event;
-}
diff --git a/src/utils/transform.ts b/src/utils/transform.ts
index 704f97c9..0013007a 100644
--- a/src/utils/transform.ts
+++ b/src/utils/transform.ts
@@ -1,4 +1,4 @@
-import { NDKTag } from '@nostr-dev-kit/ndk';
+import { NDKEvent, NDKTag, NostrEvent } from '@nostr-dev-kit/ndk';
// convert array to NIP-02 tag list
export function arrayToNIP02(arr: string[]) {
@@ -30,3 +30,15 @@ export function getMultipleRandom(arr: string[], num: number) {
const shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, num);
}
+
+export function rawEvent(event: NDKEvent) {
+ return {
+ created_at: event.created_at,
+ content: event.content,
+ tags: event.tags,
+ kind: event.kind,
+ pubkey: event.pubkey,
+ id: event.id,
+ sig: event.sig,
+ } as NostrEvent;
+}