update repost

This commit is contained in:
Ren Amamiya
2023-06-18 15:55:07 +07:00
parent 7ec284d4a5
commit d87ca7b75b
9 changed files with 79 additions and 71 deletions

View File

@@ -36,7 +36,7 @@ export function ChatsListItem({ data }: { data: any }) {
<Image
src={user?.image || DEFAULT_AVATAR}
alt={data.sender_pubkey}
className="h-5 w-5 rounded bg-white object-cover"
className="h-5 w-5 rounded object-cover"
/>
</div>
<div className="w-full inline-flex items-center justify-between">

View File

@@ -8,33 +8,31 @@ import {
ComposeIcon,
} from "@shared/icons";
import { useActiveAccount } from "@stores/accounts";
import { Fragment, useState } from "react";
export function ComposerModal() {
const [isOpen, setIsOpen] = useState(false);
const [composer] = useState({ type: "post" });
import { useComposer } from "@stores/composer";
import { Fragment } from "react";
export function Composer() {
const account = useActiveAccount((state: any) => state.account);
const [toggle, open] = useComposer((state: any) => [
state.toggleModal,
state.open,
]);
const closeModal = () => {
setIsOpen(false);
};
const openModal = () => {
setIsOpen(true);
toggle(false);
};
return (
<>
<button
type="button"
onClick={() => openModal()}
onClick={() => toggle(true)}
className="inline-flex h-8 w-max items-center justify-center gap-1 rounded-md bg-fuchsia-500 px-2.5 text-sm font-medium text-zinc-100 shadow-button hover:bg-fuchsia-600 focus:outline-none"
>
<ComposeIcon width={14} height={14} />
Compose
</button>
<Transition appear show={isOpen} as={Fragment}>
<Transition appear show={open} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Transition.Child
as={Fragment}
@@ -68,7 +66,7 @@ export function ComposerModal() {
className="text-zinc-500"
/>
</span>
<div className="inline-flex h-6 w-max items-center justify-center gap-0.5 rounded bg-zinc-800 pl-3 pr-1.5 text-base font-medium text-zinc-400 shadow-mini-button">
<div className="inline-flex h-6 w-max items-center justify-center gap-0.5 rounded bg-zinc-800 pl-3 pr-1.5 text-sm font-medium text-zinc-400">
New Post
<ChevronDownIcon width={14} height={14} />
</div>
@@ -85,9 +83,7 @@ export function ComposerModal() {
/>
</div>
</div>
{composer.type === "post" && account && (
<Post pubkey={account.pubkey} privkey={account.privkey} />
)}
<Post pubkey={account.pubkey} privkey={account.privkey} />
</Dialog.Panel>
</Transition.Child>
</div>

View File

@@ -1,7 +1,9 @@
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
import { ImageUploader } from "@shared/composer/imageUploader";
import { TrashIcon } from "@shared/icons";
import { MentionNote } from "@shared/notes/mentions/note";
import { RelayContext } from "@shared/relayProvider";
import { useComposer } from "@stores/composer";
import { dateToUnix } from "@utils/date";
import { useCallback, useContext, useMemo, useState } from "react";
import { Node, Transforms, createEditor } from "slate";
@@ -59,7 +61,10 @@ const ImagePreview = ({
export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) {
const ndk = useContext(RelayContext);
const [repost, toggle] = useComposer((state: any) => [
state.repost,
state.toggle,
]);
const editor = useMemo(
() => withReact(withImages(withHistory(createEditor()))),
[],
@@ -87,14 +92,25 @@ export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) {
ndk.signer = signer;
const event = new NDKEvent(ndk);
event.kind = 1;
event.content = serializedContent;
event.created_at = dateToUnix();
event.pubkey = pubkey;
event.tags = [];
if (repost.id && repost.pubkey) {
event.kind = 6;
event.tags = [
["e", repost.id],
["p", repost.pubkey],
];
} else {
event.kind = 1;
event.tags = [];
}
// publish event
event.publish();
// close modal
toggle(false);
};
const renderElement = useCallback((props: any) => {
@@ -115,17 +131,20 @@ export function Post({ pubkey, privkey }: { pubkey: string; privkey: string }) {
<div className="flex w-8 shrink-0 items-center justify-center">
<div className="h-full w-[2px] bg-zinc-800" />
</div>
<div className="w-full markdown">
<div className="w-full">
<Editable
autoFocus
placeholder="What's on your mind?"
spellCheck="false"
className="!min-h-[86px]"
className={`${
repost.id ? "!min-h-42" : "!min-h-[86px]"
} markdown`}
renderElement={renderElement}
/>
{repost.id && <MentionNote id={repost.id} />}
</div>
</div>
<div className="flex items-center justify-between">
<div className="mt-4 flex items-center justify-between">
<ImageUploader />
<button
type="button"

View File

@@ -3,21 +3,19 @@ import { ChatsList } from "@app/chat/components/list";
import { Disclosure } from "@headlessui/react";
import { ActiveLink } from "@shared/activeLink";
import { AppHeader } from "@shared/appHeader";
import { ComposerModal } from "@shared/composer/modal";
import {
NavArrowDownIcon,
SpaceIcon,
TrendingIcon,
WorldIcon,
} from "@shared/icons";
import { Composer } from "@shared/composer/modal";
import { NavArrowDownIcon, SpaceIcon, TrendingIcon } from "@shared/icons";
import { useComposer } from "@stores/composer";
export function Navigation() {
const toggle = useComposer((state: any) => state.toggleModal);
return (
<div className="flex w-[232px] flex-col gap-3 border-r border-zinc-900">
<AppHeader />
<div className="flex flex-col gap-3 h-full overflow-y-auto scrollbar-hide">
<div className="inlin-lflex h-8 px-3.5">
<ComposerModal />
<Composer />
</div>
{/* Newsfeed */}
<div className="flex flex-col gap-0.5 px-1.5">

View File

@@ -10,8 +10,12 @@ export function Kind1({
}: { content: any; truncate?: boolean }) {
return (
<>
<div className="select-text whitespace-pre-line break-words text-base text-zinc-100">
{truncate ? truncateContent(content.original, 100) : content.parsed}
<div
className={`select-text whitespace-pre-line break-words text-base text-zinc-100 ${
truncate ? "line-clamp-3" : ""
}`}
>
{content.parsed}
</div>
{Array.isArray(content.images) && content.images.length ? (
<ImagePreview urls={content.images} />

View File

@@ -1,49 +1,18 @@
import { NDKEvent, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
import { RepostIcon } from "@shared/icons";
import { RelayContext } from "@shared/relayProvider";
import { useActiveAccount } from "@stores/accounts";
import { dateToUnix } from "@utils/date";
import { useComposer } from "@stores/composer";
import { compactNumber } from "@utils/number";
import { useContext, useState } from "react";
export function NoteRepost({
id,
pubkey,
reposts,
}: { id: string; pubkey: string; reposts: number }) {
const ndk = useContext(RelayContext);
const account = useActiveAccount((state: any) => state.account);
const [count, setCount] = useState(reposts);
const submitEvent = (e: any) => {
e.stopPropagation();
const signer = new NDKPrivateKeySigner(account.privkey);
ndk.signer = signer;
const event = new NDKEvent(ndk);
// build event
event.content = "";
event.kind = 6;
event.created_at = dateToUnix();
event.pubkey = account.pubkey;
event.tags = [
["e", id],
["p", pubkey],
];
// publish event
event.publish();
// update state
setCount(count + 1);
};
const setRepost = useComposer((state: any) => state.setRepost);
return (
<button
type="button"
onClick={(e) => submitEvent(e)}
onClick={() => setRepost(id, pubkey)}
className="w-20 group inline-flex items-center gap-1.5"
>
<RepostIcon
@@ -52,7 +21,7 @@ export function NoteRepost({
className="text-zinc-400 group-hover:text-blue-400"
/>
<span className="text-base leading-none text-zinc-400 group-hover:text-zinc-100">
{compactNumber.format(count)}
{compactNumber.format(reposts)}
</span>
</button>
);

View File

@@ -27,12 +27,14 @@ export function User({
}`}
>
<Popover.Button
className={`${avatarWidth} ${avatarHeight} shrink-0 overflow-hidden rounded-md bg-zinc-900`}
className={`${avatarWidth} ${avatarHeight} shrink-0 overflow-hidden`}
>
<Image
src={user?.image || DEFAULT_AVATAR}
alt={pubkey}
className={`${avatarWidth} ${avatarHeight} rounded-md object-cover`}
className={`${avatarWidth} ${avatarHeight} ${
size === "small" ? "rounded" : "rounded-md"
} object-cover`}
/>
</Popover.Button>
<div className="flex flex-wrap items-baseline gap-1">

20
src/stores/composer.tsx Normal file
View File

@@ -0,0 +1,20 @@
import { create } from "zustand";
export const useComposer = create((set) => ({
open: false,
repost: { id: null, pubkey: null },
reply: null,
toggleModal: (status: boolean) => {
set({ open: status });
if (!status) {
set({ repost: { id: null, pubkey: null } });
}
},
setRepost: (id: string, pubkey: string) => {
set({ repost: { id: id, pubkey: pubkey } });
set({ open: true });
},
clearRepost: () => {
set({ repost: { id: null, pubkey: null } });
},
}));

View File

@@ -1,6 +1,6 @@
export const APP_VERSION = "1.0.0";
export const DEFAULT_AVATAR = "https://void.cat/d/PZcdCxNc24rCCxV8QXbdFQ";
export const DEFAULT_AVATAR = "https://void.cat/d/5VKmKyuHyxrNMf9bWSVPih";
export const OPENGRAPH_KEY = "9EJG4SY-19Q4M5J-H8R29C9-091XPCC";