wip: multi-type composer
This commit is contained in:
@@ -59,16 +59,16 @@ export function CreateAccountScreen() {
|
||||
const userNpub = nip19.npubEncode(userPubkey);
|
||||
const userNsec = nip19.nsecEncode(userPrivkey);
|
||||
|
||||
const event = new NDKEvent(ndk);
|
||||
const signer = new NDKPrivateKeySigner(userPrivkey);
|
||||
ndk.signer = signer;
|
||||
|
||||
const event = new NDKEvent(ndk);
|
||||
event.content = JSON.stringify(profile);
|
||||
event.kind = NDKKind.Metadata;
|
||||
event.created_at = Math.floor(Date.now() / 1000);
|
||||
event.pubkey = userPubkey;
|
||||
event.tags = [];
|
||||
|
||||
await event.sign(signer);
|
||||
const publish = await event.publish();
|
||||
|
||||
if (publish) {
|
||||
@@ -217,7 +217,7 @@ export function CreateAccountScreen() {
|
||||
<p className="mb-2 select-text text-sm text-neutral-800 dark:text-neutral-200">
|
||||
Your private key is your password. If you lose this key, you will
|
||||
lose access to your account! Copy it and keep it in a safe place.{' '}
|
||||
<span className="text-red-500">
|
||||
<span className="text-red-600">
|
||||
There is no way to reset your private key.
|
||||
</span>
|
||||
</p>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
@@ -10,10 +12,10 @@ import { User } from '@shared/user';
|
||||
|
||||
import { useOnboarding } from '@stores/onboarding';
|
||||
|
||||
import { useNostr } from '@utils/hooks/useNostr';
|
||||
import { arrayToNIP02 } from '@utils/transform';
|
||||
|
||||
export function OnboardEnrichScreen() {
|
||||
const { ndk } = useNDK();
|
||||
const { db } = useStorage();
|
||||
const { status, data } = useQuery(['trending-profiles-widget'], async () => {
|
||||
const res = await fetch('https://api.nostr.band/v0/trending/profiles');
|
||||
@@ -22,7 +24,6 @@ export function OnboardEnrichScreen() {
|
||||
}
|
||||
return res.json();
|
||||
});
|
||||
const { publish } = useNostr();
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [follows, setFollows] = useState([]);
|
||||
@@ -43,10 +44,17 @@ export function OnboardEnrichScreen() {
|
||||
setLoading(true);
|
||||
|
||||
const tags = arrayToNIP02(follows);
|
||||
const event = await publish({ content: '', kind: 3, tags: tags });
|
||||
|
||||
const event = new NDKEvent(ndk);
|
||||
event.content = '';
|
||||
event.kind = NDKKind.Contacts;
|
||||
event.created_at = Math.floor(Date.now() / 1000);
|
||||
event.tags = tags;
|
||||
|
||||
const publish = await event.publish();
|
||||
|
||||
// redirect to next step
|
||||
if (event) {
|
||||
if (publish) {
|
||||
db.account.follows = follows;
|
||||
|
||||
await db.updateAccount('follows', JSON.stringify(follows));
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
import { useStorage } from '@libs/storage/provider';
|
||||
|
||||
import { ArrowLeftIcon, CheckCircleIcon, LoaderIcon } from '@shared/icons';
|
||||
@@ -19,8 +21,8 @@ export function OnboardRelaysScreen() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [relays, setRelays] = useState(new Set<string>());
|
||||
|
||||
const { publish } = useNostr();
|
||||
const { db } = useStorage();
|
||||
const { ndk } = useNDK();
|
||||
const { getAllRelaysByUsers } = useNostr();
|
||||
const { status, data } = useQuery(
|
||||
['relays'],
|
||||
@@ -52,7 +54,13 @@ export function OnboardRelaysScreen() {
|
||||
}
|
||||
|
||||
const tags = Array.from(relays).map((relay) => ['r', relay.replace(/\/+$/, '')]);
|
||||
await publish({ content: '', kind: 10002, tags: tags });
|
||||
const event = new NDKEvent(ndk);
|
||||
event.content = '';
|
||||
event.kind = 10002;
|
||||
event.created_at = Math.floor(Date.now() / 1000);
|
||||
event.tags = tags;
|
||||
|
||||
await event.publish();
|
||||
|
||||
toggleRelays();
|
||||
navigate(-1);
|
||||
|
||||
40
src/app/notes/components/editor/post.tsx
Normal file
40
src/app/notes/components/editor/post.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import Image from '@tiptap/extension-image';
|
||||
import Placeholder from '@tiptap/extension-placeholder';
|
||||
import { EditorContent, useEditor } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
|
||||
export function PostEditor() {
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit.configure(),
|
||||
Placeholder.configure({ placeholder: 'Type something...' }),
|
||||
Image.configure({
|
||||
HTMLAttributes: {
|
||||
class:
|
||||
'rounded-lg w-full h-auto border border-white/10 outline outline-2 outline-offset-0 outline-white/20 ml-1',
|
||||
},
|
||||
}),
|
||||
],
|
||||
content: JSON.parse(localStorage.getItem('editor-post') || '{}'),
|
||||
editorProps: {
|
||||
attributes: {
|
||||
class:
|
||||
'h-full 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);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<EditorContent
|
||||
editor={editor}
|
||||
spellCheck="false"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
/>
|
||||
);
|
||||
}
|
||||
1
src/app/notes/components/index.ts
Normal file
1
src/app/notes/components/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './editor/post';
|
||||
74
src/app/notes/new.tsx
Normal file
74
src/app/notes/new.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
import { PostEditor } from '@app/notes/components';
|
||||
|
||||
import { ArrowLeftIcon } from '@shared/icons';
|
||||
|
||||
export function NewNoteScreen() {
|
||||
const [type, setType] = useState<'post' | 'article' | 'file' | 'raw'>('post');
|
||||
|
||||
return (
|
||||
<div className="h-full w-full pt-4">
|
||||
<div className="container mx-auto grid grid-cols-8 px-4">
|
||||
<div className="col-span-1">
|
||||
<Link
|
||||
to="/"
|
||||
className="inline-flex h-10 w-10 items-center justify-center rounded-lg bg-neutral-100 hover:bg-neutral-200 dark:bg-neutral-900"
|
||||
>
|
||||
<ArrowLeftIcon className="h-5 w-5" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-span-6">
|
||||
<div className="mb-8 flex items-center gap-3">
|
||||
<div className="flex h-10 items-center gap-2 rounded-lg bg-neutral-100 px-0.5 dark:bg-neutral-800">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setType('post')}
|
||||
className={twMerge(
|
||||
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
|
||||
type === 'post' ? 'bg-white shadow' : 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
Post
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setType('article')}
|
||||
className={twMerge(
|
||||
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
|
||||
type === 'article' ? 'bg-white shadow' : 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
Article
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setType('file')}
|
||||
className={twMerge(
|
||||
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
|
||||
type === 'file' ? 'bg-white shadow' : 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
File
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setType('raw')}
|
||||
className={twMerge(
|
||||
'inline-flex h-9 w-20 items-center justify-center rounded-lg text-sm font-medium',
|
||||
type === 'file' ? 'bg-white shadow' : 'bg-transparent'
|
||||
)}
|
||||
>
|
||||
Raw (advance)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{type === 'post' ? <PostEditor /> : null}
|
||||
</div>
|
||||
<div className="col-span-1" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user