update composer
This commit is contained in:
@@ -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">
|
||||||
|
|||||||
@@ -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 && (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 } });
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -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 };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user