mirror of
https://github.com/lumehq/lume.git
synced 2025-03-18 05:41:53 +01:00
feat: polish
This commit is contained in:
parent
16efd495a0
commit
f65175f11e
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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 <Hashtag key={match + i} tag={hashtag} />;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mentions.length) {
|
||||
for (const mention of mentions) {
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
mention,
|
||||
(match, i) => <MentionUser key={match + i} pubkey={mention} />,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
parsedContent = reactStringReplace(
|
||||
parsedContent,
|
||||
/(https?:\/\/\S+)/g,
|
||||
(match, i) => {
|
||||
const url = new URL(match);
|
||||
return (
|
||||
<Link
|
||||
key={match + i}
|
||||
to={url.toString()}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="break-p font-normal text-blue-500 hover:text-blue-600"
|
||||
>
|
||||
{url.toString()}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return parsedContent;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return parsedContent;
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div
|
||||
@ -31,14 +98,14 @@ export const MentionNote = memo(function MentionNote({
|
||||
contentEditable={false}
|
||||
className="w-full p-3 my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900"
|
||||
>
|
||||
Failed to fetch event
|
||||
Failed to fetch event.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Note.Provider event={data}>
|
||||
<Note.Root className="flex flex-col w-full my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900 border border-neutral-100 dark:border-neutral-900">
|
||||
<div>
|
||||
<div className="flex flex-col w-full my-1 rounded-lg cursor-default bg-neutral-100 dark:bg-neutral-900 border border-neutral-100 dark:border-neutral-900">
|
||||
<User.Provider pubkey={data.pubkey}>
|
||||
<User.Root className="flex h-10 px-3 items-center gap-2">
|
||||
<User.Avatar className="size-6 shrink-0 rounded-md object-cover" />
|
||||
@ -52,7 +119,9 @@ export const MentionNote = memo(function MentionNote({
|
||||
</div>
|
||||
</User.Root>
|
||||
</User.Provider>
|
||||
<Note.Content mini className="px-3" />
|
||||
<div className="px-3 select-text text-balance leading-normal line-clamp-4 whitespace-pre-line">
|
||||
{richContent}
|
||||
</div>
|
||||
{openable ? (
|
||||
<div className="px-3 h-10 flex items-center justify-between">
|
||||
<Link
|
||||
@ -76,9 +145,9 @@ export const MentionNote = memo(function MentionNote({
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-10" />
|
||||
<div className="h-3" />
|
||||
)}
|
||||
</Note.Root>
|
||||
</Note.Provider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -38,6 +38,7 @@ export function Reply({
|
||||
<div />
|
||||
)}
|
||||
<div className="inline-flex items-center gap-4">
|
||||
<Note.Reply />
|
||||
<Note.Repost />
|
||||
<Note.Zap />
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@ export function UserAbout({ className }: { className?: string }) {
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div
|
||||
className={cn(
|
||||
"h-4 w-20 bg-black/20 dark:bg-white/20 rounded animate-pulse",
|
||||
@ -25,7 +25,7 @@ export function UserAbout({ className }: { className?: string }) {
|
||||
className,
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,17 @@ export function UserCover({ className }: { className?: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
if (user && !user.banner) {
|
||||
return (
|
||||
<div
|
||||
className={cn("bg-gradient-to-b from-sky-400 to-sky-200", className)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<img
|
||||
src={user.banner || user.cover}
|
||||
src={user.banner}
|
||||
alt="banner"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
|
@ -169,8 +169,11 @@ export const LumeProvider = ({ children }: PropsWithChildren<object>) => {
|
||||
);
|
||||
|
||||
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(
|
||||
|
@ -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<HTMLDivElement | null>();
|
||||
|
||||
const [editorValue, setEditorValue] = useAtom(editorValueAtom);
|
||||
const [editorValue, setEditorValue] = useState([
|
||||
{
|
||||
type: "paragraph",
|
||||
children: [{ text: "" }],
|
||||
},
|
||||
]);
|
||||
const [contacts, setContacts] = useState<NDKCacheUserProfile[]>([]);
|
||||
const [target, setTarget] = useState<Range | undefined>();
|
||||
const [index, setIndex] = useState(0);
|
||||
|
@ -218,7 +218,6 @@ export function OnboardingFollowScreen() {
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
UU
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
|
@ -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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user