update composer

This commit is contained in:
Ren Amamiya
2023-07-08 15:21:06 +07:00
parent 3752a3ab0f
commit 4747299ade
6 changed files with 54 additions and 68 deletions

View File

@@ -7,7 +7,7 @@ import { usePublish } from '@libs/ndk';
import { Button } from '@shared/button'; import { Button } from '@shared/button';
import { ImageUploader } from '@shared/composer/imageUploader'; import { ImageUploader } from '@shared/composer/imageUploader';
import { TrashIcon } from '@shared/icons'; import { CancelIcon, TrashIcon } from '@shared/icons';
import { MentionNote } from '@shared/notes/mentions/note'; import { MentionNote } from '@shared/notes/mentions/note';
import { useComposer } from '@stores/composer'; import { useComposer } from '@stores/composer';
@@ -60,9 +60,9 @@ export function Post() {
const publish = usePublish(); const publish = usePublish();
const editor = useMemo(() => withReact(withImages(withHistory(createEditor()))), []); const editor = useMemo(() => withReact(withImages(withHistory(createEditor()))), []);
const [repost, reply, toggle] = useComposer((state) => [ const [reply, clearReply, toggle] = useComposer((state) => [
state.repost,
state.reply, state.reply,
state.clearReply,
state.toggleModal, state.toggleModal,
]); ]);
const [content, setContent] = useState<Node[]>([ const [content, setContent] = useState<Node[]>([
@@ -79,30 +79,14 @@ export function Post() {
return nodes.map((n) => Node.string(n)).join('\n'); return nodes.map((n) => Node.string(n)).join('\n');
}, []); }, []);
const getRef = () => { const removeReply = () => {
if (repost.id) { clearReply();
return repost.id;
} else if (reply.id) {
return reply.id;
} else {
return null;
}
}; };
const refID = getRef();
const submit = async () => { const submit = async () => {
let tags: string[][] = []; let tags: string[][] = [];
let kind: number;
if (repost.id && repost.pubkey) { if (reply.id && reply.pubkey) {
kind = 6;
tags = [
['e', repost.id, FULL_RELAYS[0], 'root'],
['p', repost.pubkey],
];
} else if (reply.id && reply.pubkey) {
kind = 1;
if (reply.root && reply.root !== reply.id) { if (reply.root && reply.root !== reply.id) {
tags = [ tags = [
['e', reply.id, FULL_RELAYS[0], 'root'], ['e', reply.id, FULL_RELAYS[0], 'root'],
@@ -116,7 +100,6 @@ export function Post() {
]; ];
} }
} else { } else {
kind = 1;
tags = []; tags = [];
} }
@@ -124,7 +107,7 @@ export function Post() {
const serializedContent = serialize(content); const serializedContent = serialize(content);
// publish message // publish message
await publish({ content: serializedContent, kind, tags }); await publish({ content: serializedContent, kind: 1, tags });
// close modal // close modal
toggle(false); toggle(false);
@@ -151,14 +134,28 @@ export function Post() {
</div> </div>
<div className="w-full"> <div className="w-full">
<Editable <Editable
placeholder={refID ? 'Share your thoughts on it' : "What's on your mind?"} placeholder={
reply.id ? 'Share your thoughts on it' : "What's on your mind?"
}
spellCheck="false" spellCheck="false"
className={`${ className={`${
refID ? '!min-h-42' : '!min-h-[86px]' reply.id ? '!min-h-42' : '!min-h-[86px]'
} markdown max-h-[500px] overflow-y-auto`} } markdown max-h-[500px] overflow-y-auto`}
renderElement={renderElement} renderElement={renderElement}
/> />
{refID && <MentionNote id={refID} />} {reply.id && (
<div className="relative">
<MentionNote id={reply.id} />
<button
type="button"
onClick={() => removeReply()}
className="absolute right-3 top-3 inline-flex h-6 w-max items-center justify-center gap-2 rounded bg-zinc-800 px-2 hover:bg-zinc-700"
>
<CancelIcon className="h-4 w-4 text-zinc-100" />
<span className="text-sm">Stop reply</span>
</button>
</div>
)}
</div> </div>
</div> </div>
<div className="mt-4 flex items-center justify-between"> <div className="mt-4 flex items-center justify-between">

View File

@@ -45,7 +45,7 @@ export const MentionNote = memo(function MentionNote({ id }: { id: string }) {
) : status === 'success' ? ( ) : status === 'success' ? (
<> <>
<User pubkey={data.pubkey} time={data.created_at} size="small" /> <User pubkey={data.pubkey} time={data.created_at} size="small" />
<div className="mt-2"> <div>
{data.kind === 1 && <Kind1 content={data.content} truncate={true} />} {data.kind === 1 && <Kind1 content={data.content} truncate={true} />}
{data.kind === 1063 && <Kind1063 metadata={data.tags} />} {data.kind === 1063 && <Kind1063 metadata={data.tags} />}
{data.kind !== 1 && data.kind !== 1063 && ( {data.kind !== 1 && data.kind !== 1063 && (

View File

@@ -1,8 +1,10 @@
import * as Tooltip from '@radix-ui/react-tooltip'; import * as Tooltip from '@radix-ui/react-tooltip';
import { usePublish } from '@libs/ndk';
import { RepostIcon } from '@shared/icons'; import { RepostIcon } from '@shared/icons';
import { useComposer } from '@stores/composer'; import { FULL_RELAYS } from '@stores/constants';
import { compactNumber } from '@utils/number'; import { compactNumber } from '@utils/number';
@@ -15,13 +17,21 @@ export function NoteRepost({
pubkey: string; pubkey: string;
reposts: number; reposts: number;
}) { }) {
const setRepost = useComposer((state) => state.setRepost); const publish = usePublish();
const submit = async () => {
const tags = [
['e', id, FULL_RELAYS[0], 'root'],
['p', pubkey],
];
await publish({ content: '', kind: 6, tags: tags });
};
return ( return (
<Tooltip.Root delayDuration={150}> <Tooltip.Root delayDuration={150}>
<button <button
type="button" type="button"
onClick={() => setRepost(id, pubkey)} onClick={() => submit()}
className="group group inline-flex h-6 w-20 items-center gap-1.5" className="group group inline-flex h-6 w-20 items-center gap-1.5"
> >
<Tooltip.Trigger asChild> <Tooltip.Trigger asChild>

View File

@@ -50,8 +50,8 @@ export function User({
return ( return (
<Popover <Popover
className={`relative flex gap-3 ${ className={`relative flex ${
size === 'small' ? 'items-center' : 'items-start' size === 'small' ? 'items-center gap-2' : 'items-start gap-3'
}`} }`}
> >
<Popover.Button <Popover.Button

View File

@@ -3,35 +3,22 @@ import { create } from 'zustand';
interface ComposerState { interface ComposerState {
open: boolean; open: boolean;
reply: { id: string; root: string; pubkey: string }; reply: { id: string; root: string; pubkey: string };
repost: { id: string; pubkey: string };
toggleModal: (status: boolean) => void; toggleModal: (status: boolean) => void;
setReply: (id: string, root: string, pubkey: string) => void; setReply: (id: string, root: string, pubkey: string) => void;
setRepost: (id: string, pubkey: string) => void;
clearReply: () => void; clearReply: () => void;
clearRepost: () => void;
} }
export const useComposer = create<ComposerState>((set) => ({ export const useComposer = create<ComposerState>((set) => ({
open: false, open: false,
reply: { id: null, root: null, pubkey: null }, reply: { id: null, root: null, pubkey: null },
repost: { id: null, pubkey: null },
toggleModal: (status: boolean) => { toggleModal: (status: boolean) => {
set({ open: status }); set({ open: status });
}, },
setReply: (id: string, root: string, pubkey: string) => { setReply: (id: string, root: string, pubkey: string) => {
set({ reply: { id: id, root: root, pubkey: pubkey } }); set({ reply: { id: id, root: root, pubkey: pubkey } });
set({ repost: { id: null, pubkey: null } });
set({ open: true });
},
setRepost: (id: string, pubkey: string) => {
set({ repost: { id: id, pubkey: pubkey } });
set({ reply: { id: null, root: null, pubkey: null } });
set({ open: true }); set({ open: true });
}, },
clearReply: () => { clearReply: () => {
set({ reply: { id: null, root: null, pubkey: null } }); set({ reply: { id: null, root: null, pubkey: null } });
}, },
clearRepost: () => {
set({ repost: { id: null, pubkey: null } });
},
})); }));

View File

@@ -12,31 +12,23 @@ export function useProfile(pubkey: string, fallback?: string) {
data: user, data: user,
error, error,
isFetching, isFetching,
} = useQuery( } = useQuery(['user', pubkey], async () => {
['user', pubkey], if (!fallback) {
async () => { const current = Math.floor(Date.now() / 1000);
if (!fallback) { const cache = await getUserMetadata(pubkey);
const current = Math.floor(Date.now() / 1000); if (cache && parseInt(cache.created_at) + 86400 >= current) {
const cache = await getUserMetadata(pubkey); return cache;
if (cache && parseInt(cache.created_at) + 86400 >= current) {
console.log('use cache', cache);
return cache;
} else {
const user = ndk.getUser({ hexpubkey: pubkey });
await user.fetchProfile();
await createMetadata(pubkey, pubkey, JSON.stringify(user.profile));
return user.profile;
}
} else { } else {
const profile = JSON.parse(fallback); const user = ndk.getUser({ hexpubkey: pubkey });
return profile; await user.fetchProfile();
await createMetadata(pubkey, pubkey, JSON.stringify(user.profile));
return user.profile;
} }
}, } else {
{ const profile = JSON.parse(fallback);
refetchOnWindowFocus: false, return profile;
refetchOnReconnect: false,
} }
); });
return { status, user, error, isFetching }; return { status, user, error, isFetching };
} }