This commit is contained in:
Ren Amamiya
2023-09-26 09:05:39 +07:00
parent a66770989b
commit 236131087a
21 changed files with 605 additions and 523 deletions

View File

@@ -35,24 +35,28 @@ export function ActiveAccount() {
since: Math.floor(Date.now() / 1000),
};
sub(filter, async (event) => {
addActivity(event);
sub(
filter,
async (event) => {
addActivity(event);
switch (event.kind) {
case NDKKind.Text:
return await sendNativeNotification('Mention');
case NDKKind.Contacts:
return await sendNativeNotification("You've a new follower");
case NDKKind.Repost:
return await sendNativeNotification('Repost');
case NDKKind.Reaction:
return await sendNativeNotification('Reaction');
case NDKKind.Zap:
return await sendNativeNotification('Zap');
default:
break;
}
});
switch (event.kind) {
case NDKKind.Text:
return await sendNativeNotification('Mention');
case NDKKind.Contacts:
return await sendNativeNotification("You've a new follower");
case NDKKind.Repost:
return await sendNativeNotification('Repost');
case NDKKind.Reaction:
return await sendNativeNotification('Reaction');
case NDKKind.Zap:
return await sendNativeNotification('Zap');
default:
break;
}
},
false
);
}, []);
if (status === 'loading') {
@@ -74,7 +78,7 @@ export function ActiveAccount() {
/>
<div className="flex w-full flex-1 flex-col items-start gap-0.5">
<p className="max-w-[10rem] truncate font-semibold leading-none text-white">
{user?.name || user?.display_name}
{user?.name || user?.display_name || user?.displayName}
</p>
<span className="max-w-[7rem] truncate text-sm leading-none text-white/50">
{user?.nip05 || displayNpub(db.account.pubkey, 12)}

View File

@@ -3,4 +3,6 @@ export * from './modal';
export * from './composer';
export * from './mention/item';
export * from './mention/popup';
export * from './mention/suggestion';
export * from './mention/inlineList';
export * from './mediaUploader';

View File

@@ -0,0 +1,83 @@
import { type SuggestionProps } from '@tiptap/suggestion';
import {
ForwardedRef,
forwardRef,
useEffect,
useImperativeHandle,
useState,
} from 'react';
import { twMerge } from 'tailwind-merge';
import { MentionItem } from '@shared/composer';
export const MentionInlineList = forwardRef(
(props: SuggestionProps, ref: ForwardedRef<unknown>) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = (index) => {
const item = props.items[index];
if (item) {
props.command({ id: item });
}
};
const upHandler = () => {
setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length);
};
const downHandler = () => {
setSelectedIndex((selectedIndex + 1) % props.items.length);
};
const enterHandler = () => {
selectItem(selectedIndex);
};
useEffect(() => setSelectedIndex(0), [props.items]);
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }) => {
if (event.key === 'ArrowUp') {
upHandler();
return true;
}
if (event.key === 'ArrowDown') {
downHandler();
return true;
}
if (event.key === 'Enter') {
enterHandler();
return true;
}
return false;
},
}));
return (
<div className="flex w-[250px] flex-col rounded-xl bg-white/10 px-3 py-3 backdrop-blur-xl">
{props.items.length ? (
props.items.map((item: string, index: number) => (
<button
className={twMerge(
'h-11 w-full rounded-lg px-2 text-start text-sm font-medium hover:bg-white/10',
`${index === selectedIndex ? 'is-selected' : ''}`
)}
key={index}
onClick={() => selectItem(index)}
>
<MentionItem embed={item} />
</button>
))
) : (
<div>No result</div>
)}
</div>
);
}
);
MentionInlineList.displayName = 'MentionList';

View File

@@ -3,12 +3,12 @@ import { Image } from '@shared/image';
import { useProfile } from '@utils/hooks/useProfile';
import { displayNpub } from '@utils/shortenKey';
export function MentionItem({ pubkey }: { pubkey: string }) {
const { status, user } = useProfile(pubkey);
export function MentionItem({ pubkey, embed }: { pubkey: string; embed?: string }) {
const { status, user } = useProfile(pubkey, embed);
if (status === 'loading') {
return (
<div className="flex items-center gap-2">
<div className="flex items-center gap-2.5 px-2">
<div className="relative h-8 w-8 shrink-0 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
<div className="flex w-full flex-1 flex-col items-start gap-1 text-start">
<span className="h-4 w-1/2 animate-pulse rounded bg-white/10 backdrop-blur-xl" />

View File

@@ -0,0 +1,68 @@
import { ReactRenderer } from '@tiptap/react';
import tippy from 'tippy.js';
import { MentionInlineList } from '@shared/composer';
export const Suggestion = {
items: async ({ query }) => {
const users = [];
return users
.filter((item) => item.ident.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
},
render: () => {
let component;
let popup;
return {
onStart: (props) => {
component = new ReactRenderer(MentionInlineList, {
props,
editor: props.editor,
});
if (!props.clientRect) {
return;
}
popup = tippy('body', {
getReferenceClientRect: props.clientRect,
appendTo: () => document.body,
content: component.element,
showOnCreate: true,
interactive: true,
trigger: 'manual',
placement: 'bottom-start',
});
},
onUpdate(props) {
component.updateProps(props);
if (!props.clientRect) {
return;
}
popup[0].setProps({
getReferenceClientRect: props.clientRect,
});
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
popup[0].hide();
return true;
}
return component.ref?.onKeyDown(props);
},
onExit() {
popup[0].destroy();
component.destroy();
},
};
},
};

View File

@@ -14,7 +14,7 @@ export function ComposerUser({ pubkey }: { pubkey: string }) {
className="h-10 w-10 shrink-0 rounded-lg"
/>
<h5 className="text-base font-semibold leading-none text-white">
{user?.name || user?.display_name || displayNpub(pubkey, 16)}
{user?.name || user?.display_name || user?.displayName || displayNpub(pubkey, 16)}
</h5>
</div>
);

View File

@@ -60,7 +60,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
if (send) {
await sendNativeNotification(
`You've tipped ${compactNumber.format(send.amount)} sats to ${
user?.display_name || user?.name
user?.name || user?.display_name || user?.displayName
}`
);
@@ -106,7 +106,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
<div className="inline-flex w-full shrink-0 items-center justify-between px-5 py-3">
<div className="w-6" />
<Dialog.Title className="text-center text-sm font-semibold leading-none text-white">
Send tip to {user?.display_name || user?.name}
Send tip to {user?.name || user?.display_name || user?.displayName}
</Dialog.Title>
<Dialog.Close className="inline-flex h-6 w-6 items-center justify-center rounded-md backdrop-blur-xl hover:bg-white/10">
<CancelIcon className="h-4 w-4 text-white/50" />

View File

@@ -18,20 +18,24 @@ export function MentionUser({ pubkey }: { pubkey: string }) {
onClick={() =>
setWidget(db, {
kind: WidgetKinds.local.user,
title: user?.name || user?.display_name,
title: user?.name || user?.display_name || user?.displayName,
content: pubkey,
})
}
onKeyDown={() =>
setWidget(db, {
kind: WidgetKinds.local.user,
title: user?.name || user?.display_name,
title: user?.name || user?.display_name || user?.displayName,
content: pubkey,
})
}
className="break-words text-fuchsia-400 hover:text-fuchsia-500"
>
{user?.name || user?.display_name || user?.username || displayNpub(pubkey, 16)}
{user?.name ||
user?.display_name ||
user?.displayName ||
user?.username ||
displayNpub(pubkey, 16)}
</span>
);
}

View File

@@ -1,4 +1,4 @@
import * as Popover from '@radix-ui/react-popover';
import * as HoverCard from '@radix-ui/react-hover-card';
import { memo } from 'react';
import ReactMarkdown from 'react-markdown';
import { Link } from 'react-router-dom';
@@ -70,7 +70,10 @@ export const User = memo(function User({
</button>
<div className="flex flex-1 items-baseline gap-2">
<h5 className="max-w-[10rem] truncate font-semibold leading-none text-white">
{user?.display_name || user?.name || displayNpub(pubkey, 16)}
{user?.name ||
user?.display_name ||
user?.displayName ||
displayNpub(pubkey, 16)}
</h5>
<span className="leading-none text-white/50">·</span>
<span className="leading-none text-white/50">{createdAt}</span>
@@ -90,7 +93,7 @@ export const User = memo(function User({
<div className="flex h-full flex-col items-start justify-between">
<div className="flex flex-col items-start gap-1 text-start">
<p className="max-w-[15rem] truncate text-lg font-semibold leading-none text-white">
{user?.name || user?.display_name}
{user?.name || user?.display_name || user?.displayName}
</p>
<ReactMarkdown
remarkPlugins={[remarkGfm]}
@@ -110,7 +113,7 @@ export const User = memo(function User({
className="inline-flex items-center gap-2 text-sm text-white/70"
>
<WorldIcon className="h-4 w-4" />
<p className="max-w-[10rem] truncate">{user.website}</p>
<p className="max-w-[10rem] truncate">{user?.website}</p>
</Link>
) : null}
</div>
@@ -129,7 +132,7 @@ export const User = memo(function User({
/>
<div className="flex w-full flex-col gap-1">
<h3 className="max-w-[15rem] truncate font-medium leading-none text-white">
{user?.name || user?.display_name}
{user?.name || user?.display_name || user?.displayName}
</h3>
<p className="text-sm leading-none text-white/70">
{user?.nip05 || user?.username || displayNpub(pubkey, 16)}
@@ -163,7 +166,10 @@ export const User = memo(function User({
/>
<div className="inline-flex items-baseline gap-1">
<h5 className="max-w-[10rem] truncate font-medium leading-none text-white/80">
{user?.display_name || user?.name || displayNpub(pubkey, 16)}
{user?.name ||
user?.display_name ||
user?.displayName ||
displayNpub(pubkey, 16)}
</h5>
<span className="text-blue-500">reposted</span>
</div>
@@ -182,7 +188,7 @@ export const User = memo(function User({
/>
<div className="flex flex-1 flex-col gap-2">
<h5 className="max-w-[15rem] truncate font-semibold leading-none text-white">
{user?.display_name || user?.name}
{user?.name || user?.display_name || user?.displayName}
</h5>
<div className="inline-flex items-center gap-2">
<span className="leading-none text-white/50">{createdAt}</span>
@@ -195,9 +201,9 @@ export const User = memo(function User({
}
return (
<Popover.Root>
<HoverCard.Root>
<div className="relative z-10 flex items-start gap-3">
<Popover.Trigger asChild>
<HoverCard.Trigger asChild>
<button
type="button"
className="relative z-40 h-10 w-10 shrink-0 overflow-hidden"
@@ -208,18 +214,21 @@ export const User = memo(function User({
className="h-10 w-10 rounded-lg object-cover"
/>
</button>
</Popover.Trigger>
</HoverCard.Trigger>
<div className="flex flex-1 items-baseline gap-2">
<h5 className="max-w-[15rem] truncate font-semibold leading-none text-white">
{user?.display_name || user?.name || displayNpub(pubkey, 16)}
{user?.name ||
user?.display_name ||
user?.displayName ||
displayNpub(pubkey, 16)}
</h5>
<span className="leading-none text-white/50">·</span>
<span className="leading-none text-white/50">{createdAt}</span>
</div>
</div>
<Popover.Portal>
<Popover.Content
className="w-[300px] overflow-hidden rounded-xl border border-white/10 bg-white/10 backdrop-blur-3xl focus:outline-none"
<HoverCard.Portal>
<HoverCard.Content
className="w-[300px] overflow-hidden rounded-xl border border-white/10 bg-white/10 backdrop-blur-3xl focus:outline-none data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=top]:animate-slideDownAndFade data-[state=open]:transition-all"
sideOffset={5}
>
<div className="flex gap-2.5 border-b border-white/5 px-3 py-3">
@@ -231,12 +240,15 @@ export const User = memo(function User({
<div className="flex flex-1 flex-col gap-2">
<div className="inline-flex flex-col gap-1">
<h5 className="text-sm font-semibold leading-none">
{user?.display_name || user?.name || user?.username}
{user?.name ||
user?.display_name ||
user?.displayName ||
user?.username}
</h5>
{user.nip05 ? (
{user?.nip05 ? (
<NIP05
pubkey={pubkey}
nip05={user.nip05}
nip05={user?.nip05}
className="max-w-[15rem] truncate text-sm leading-none text-white/50"
/>
) : (
@@ -266,8 +278,8 @@ export const User = memo(function User({
Message
</Link>
</div>
</Popover.Content>
</Popover.Portal>
</Popover.Root>
</HoverCard.Content>
</HoverCard.Portal>
</HoverCard.Root>
);
});