From f65175f11e15c03163968805a27510d944c2a7a8 Mon Sep 17 00:00:00 2001 From: reya Date: Fri, 19 Jan 2024 08:24:13 +0700 Subject: [PATCH] feat: polish --- apps/desktop/src/routes/auth/create.tsx | 4 +- packages/ark/src/ark.ts | 6 +- .../ark/src/components/note/mentions/note.tsx | 91 ++++++++++++++++--- .../src/components/note/primitives/reply.tsx | 1 + packages/ark/src/components/user/about.tsx | 4 +- packages/ark/src/components/user/cover.tsx | 10 +- packages/ark/src/provider.tsx | 3 + packages/ui/src/editor/replyForm.tsx | 10 +- packages/ui/src/onboarding/follow.tsx | 1 - .../ui/src/onboarding/profileSettings.tsx | 11 ++- 10 files changed, 114 insertions(+), 27 deletions(-) diff --git a/apps/desktop/src/routes/auth/create.tsx b/apps/desktop/src/routes/auth/create.tsx index f51616a7..599a8531 100644 --- a/apps/desktop/src/routes/auth/create.tsx +++ b/apps/desktop/src/routes/auth/create.tsx @@ -40,8 +40,8 @@ const Item = ({ event }: { event: NDKEvent }) => { export function CreateAccountScreen() { const ark = useArk(); const storage = useStorage(); - const navigate = useNavigate(); const services = useLoaderData() as NDKEvent[]; + const navigate = useNavigate(); const setOnboarding = useSetAtom(onboardingAtom); const [serviceId, setServiceId] = useState(services?.[0]?.id); @@ -162,7 +162,7 @@ export function CreateAccountScreen() { ark.updateNostrSigner({ signer: finalSigner }); // remove default nsecbunker profile and contact list - await ark.createEvent({ kind: NDKKind.Metadata, content: "", tags: [] }); + // await ark.createEvent({ kind: NDKKind.Metadata, content: "", tags: [] }); await ark.createEvent({ kind: NDKKind.Contacts, content: "", tags: [] }); setOnboarding(true); diff --git a/packages/ark/src/ark.ts b/packages/ark/src/ark.ts index b05a9466..7c04d90c 100644 --- a/packages/ark/src/ark.ts +++ b/packages/ark/src/ark.ts @@ -276,7 +276,7 @@ export class Ark { if (content.includes("nostr:note1") || content.includes("nostr:nevent1")) return null; - const events = tags.filter((el) => el[0] === "e"); + const events = tags.filter((el) => el[0] === "e" && el[3] !== "mention"); if (!events.length) return null; @@ -325,7 +325,9 @@ export class Ark { if (events.length > 0) { const replies = new Set(); for (const event of events) { - const tags = event.tags.filter((el) => el[0] === "e" && el[1] !== id); + const tags = event.tags.filter( + (el) => el[0] === "e" && el[1] !== id && el[3] !== "mention", + ); if (tags.length > 0) { for (const tag of tags) { const rootIndex = events.findIndex((el) => el.id === tag[1]); diff --git a/packages/ark/src/components/note/mentions/note.tsx b/packages/ark/src/components/note/mentions/note.tsx index c9256806..536e8974 100644 --- a/packages/ark/src/components/note/mentions/note.tsx +++ b/packages/ark/src/components/note/mentions/note.tsx @@ -1,11 +1,13 @@ -import { PinIcon, RefreshIcon } from "@lume/icons"; -import { COL_TYPES } from "@lume/utils"; -import { memo } from "react"; +import { PinIcon } from "@lume/icons"; +import { COL_TYPES, NOSTR_MENTIONS } from "@lume/utils"; +import { ReactNode, memo, useMemo } from "react"; import { Link } from "react-router-dom"; -import { Note } from "../"; +import reactStringReplace from "react-string-replace"; import { useEvent } from "../../../hooks/useEvent"; import { useColumnContext } from "../../column/provider"; import { User } from "../../user"; +import { Hashtag } from "./hashtag"; +import { MentionUser } from "./user"; export const MentionNote = memo(function MentionNote({ eventId, @@ -14,6 +16,71 @@ export const MentionNote = memo(function MentionNote({ const { addColumn } = useColumnContext(); const { isLoading, isError, data } = useEvent(eventId); + const richContent = useMemo(() => { + if (!data) return ""; + + let parsedContent: string | ReactNode[] = data.content.replace( + /\n+/g, + "\n", + ); + + const text = parsedContent as string; + const words = text.split(/( |\n)/); + + const hashtags = words.filter((word) => word.startsWith("#")); + const mentions = words.filter((word) => + NOSTR_MENTIONS.some((el) => word.startsWith(el)), + ); + + try { + if (hashtags.length) { + for (const hashtag of hashtags) { + parsedContent = reactStringReplace( + parsedContent, + hashtag, + (match, i) => { + return ; + }, + ); + } + } + + if (mentions.length) { + for (const mention of mentions) { + parsedContent = reactStringReplace( + parsedContent, + mention, + (match, i) => , + ); + } + } + + parsedContent = reactStringReplace( + parsedContent, + /(https?:\/\/\S+)/g, + (match, i) => { + const url = new URL(match); + return ( + + {url.toString()} + + ); + }, + ); + + return parsedContent; + } catch (e) { + console.log(e); + return parsedContent; + } + }, [data]); + if (isLoading) { return (
- Failed to fetch event + Failed to fetch event.
); } return ( - - +
+
@@ -52,7 +119,9 @@ export const MentionNote = memo(function MentionNote({
- +
+ {richContent} +
{openable ? (
) : ( -
+
)} - - +
+
); }); diff --git a/packages/ark/src/components/note/primitives/reply.tsx b/packages/ark/src/components/note/primitives/reply.tsx index 0fc5306e..0ff655db 100644 --- a/packages/ark/src/components/note/primitives/reply.tsx +++ b/packages/ark/src/components/note/primitives/reply.tsx @@ -38,6 +38,7 @@ export function Reply({
)}
+
diff --git a/packages/ark/src/components/user/about.tsx b/packages/ark/src/components/user/about.tsx index cdd02cfa..401911bc 100644 --- a/packages/ark/src/components/user/about.tsx +++ b/packages/ark/src/components/user/about.tsx @@ -6,7 +6,7 @@ export function UserAbout({ className }: { className?: string }) { if (!user) { return ( - <> +
- +
); } diff --git a/packages/ark/src/components/user/cover.tsx b/packages/ark/src/components/user/cover.tsx index 68101d52..79870241 100644 --- a/packages/ark/src/components/user/cover.tsx +++ b/packages/ark/src/components/user/cover.tsx @@ -15,9 +15,17 @@ export function UserCover({ className }: { className?: string }) { ); } + if (user && !user.banner) { + return ( +
+ ); + } + return ( banner) => { ); activitySub.addListener("event", async (event: NDKEvent) => { + if (event.pubkey === storage.currentUser.pubkey) return; + setUnreadActivity((state) => state + 1); const profile = await ark.getUserProfile(event.pubkey); + switch (event.kind) { case NDKKind.Text: return await sendNativeNotification( diff --git a/packages/ui/src/editor/replyForm.tsx b/packages/ui/src/editor/replyForm.tsx index 0878d3fc..2340cf22 100644 --- a/packages/ui/src/editor/replyForm.tsx +++ b/packages/ui/src/editor/replyForm.tsx @@ -2,10 +2,9 @@ import { MentionNote, User, useArk } from "@lume/ark"; import { LoaderIcon, TrashIcon } from "@lume/icons"; import { useStorage } from "@lume/storage"; import { NDKCacheUserProfile } from "@lume/types"; -import { cn, editorValueAtom } from "@lume/utils"; +import { cn } from "@lume/utils"; import { NDKEvent, NDKKind } from "@nostr-dev-kit/ndk"; import { Portal } from "@radix-ui/react-dropdown-menu"; -import { useAtom } from "jotai"; import { useEffect, useRef, useState } from "react"; import { Descendant, @@ -193,7 +192,12 @@ export function ReplyForm({ const storage = useStorage(); const ref = useRef(); - const [editorValue, setEditorValue] = useAtom(editorValueAtom); + const [editorValue, setEditorValue] = useState([ + { + type: "paragraph", + children: [{ text: "" }], + }, + ]); const [contacts, setContacts] = useState([]); const [target, setTarget] = useState(); const [index, setIndex] = useState(0); diff --git a/packages/ui/src/onboarding/follow.tsx b/packages/ui/src/onboarding/follow.tsx index 79771967..3bc2df5a 100644 --- a/packages/ui/src/onboarding/follow.tsx +++ b/packages/ui/src/onboarding/follow.tsx @@ -218,7 +218,6 @@ export function OnboardingFollowScreen() { )} - UU
)) diff --git a/packages/ui/src/onboarding/profileSettings.tsx b/packages/ui/src/onboarding/profileSettings.tsx index 263e3bb6..c3467703 100644 --- a/packages/ui/src/onboarding/profileSettings.tsx +++ b/packages/ui/src/onboarding/profileSettings.tsx @@ -23,7 +23,7 @@ export function OnboardingProfileSettingsScreen() { const { register, handleSubmit } = useForm(); const svgURI = `data:image/svg+xml;utf8,${encodeURIComponent( - minidenticon("lume new account", 90, 50), + minidenticon(ark.account.pubkey, 90, 50), )}`; const onSubmit = async (data: { name: string; about: string }) => { @@ -39,7 +39,7 @@ export function OnboardingProfileSettingsScreen() { const profile: NDKUserProfile = { ...data, - lud16: oldProfile?.lud16 || "", + lud16: "", // temporary remove lud16 nip05: oldProfile?.nip05 || "", display_name: data.name, bio: data.about, @@ -56,9 +56,10 @@ export function OnboardingProfileSettingsScreen() { if (publish) { // invalid cache await storage.clearProfileCache(ark.account.pubkey); - await queryClient.setQueryData(["user", ark.account.pubkey], () => { - return profile; - }); + await queryClient.setQueryData( + ["user", ark.account.pubkey], + () => profile, + ); setLoading(false); navigate("/follow");