This commit is contained in:
2023-10-18 14:49:20 +07:00
parent 489ab6bd0b
commit 939a72f945
47 changed files with 389 additions and 293 deletions

View File

@@ -1,8 +1,7 @@
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import * as Tooltip from '@radix-ui/react-tooltip';
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
import { nip19 } from 'nostr-tools';
import { EventPointer } from 'nostr-tools/lib/nip19';
import { EventPointer } from 'nostr-tools/lib/types/nip19';
import { useState } from 'react';
import { Link } from 'react-router-dom';
@@ -25,19 +24,20 @@ export function MoreActions({ id, pubkey }: { id: string; pubkey: string }) {
return (
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
<DropdownMenu.Trigger>
<HorizontalDotsIcon className="h-5 w-5 text-neutral-800 hover:text-blue-500 dark:text-neutral-200" />
<DropdownMenu.Trigger asChild>
<button type="button" className="inline-flex h-7 w-7 items-center justify-center">
<HorizontalDotsIcon className="h-5 w-5 text-neutral-800 hover:text-blue-500 dark:text-neutral-200" />
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content className="flex w-[200px] flex-col overflow-hidden rounded-xl border border-neutral-300 bg-neutral-200 focus:outline-none dark:border-neutral-700 dark:bg-neutral-800">
<DropdownMenu.Item asChild>
<button
type="button"
onClick={() => copyLink()}
<Link
to={`/notes/text/${id}`}
className="inline-flex h-10 items-center px-4 text-sm text-neutral-900 hover:bg-neutral-300 focus:outline-none dark:text-neutral-100 dark:hover:bg-neutral-700"
>
Focus
</button>
</Link>
</DropdownMenu.Item>
<DropdownMenu.Item asChild>
<button

View File

@@ -62,7 +62,7 @@ export function NoteReaction({ id, pubkey }: { id: string; pubkey: string }) {
<Popover.Trigger asChild>
<button
type="button"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
>
{reaction ? (
<img src={getReactionImage(reaction)} alt={reaction} className="h-5 w-5" />

View File

@@ -21,7 +21,7 @@ export function NoteReply({
<button
type="button"
onClick={() => setReply(id, pubkey, root)}
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
>
<ReplyIcon className="h-5 w-5 group-hover:text-blue-500" />
</button>

View File

@@ -44,7 +44,7 @@ export function NoteRepost({ id, pubkey }: { id: string; pubkey: string }) {
<AlertDialog.Trigger asChild>
<button
type="button"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
>
<RepostIcon
className={twMerge(

View File

@@ -1,6 +1,7 @@
import { webln } from '@getalby/sdk';
import { SendPaymentResponse } from '@getalby/sdk/dist/types';
import * as Dialog from '@radix-ui/react-dialog';
import { invoke } from '@tauri-apps/api';
import { message } from '@tauri-apps/plugin-dialog';
import { QRCodeSVG } from 'qrcode.react';
import { useEffect, useRef, useState } from 'react';
@@ -79,9 +80,10 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
useEffect(() => {
async function getWalletConnectURL() {
// const uri: string = await invoke('secure_load', { key: 'nwc' });
setWalletConnectURL('todo');
const uri: string = await invoke('secure_load', { key: 'nwc' });
if (uri) setWalletConnectURL(uri);
}
getWalletConnectURL();
return () => {
@@ -97,7 +99,7 @@ export function NoteZap({ id, pubkey }: { id: string; pubkey: string }) {
<Dialog.Trigger asChild>
<button
type="button"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-500 dark:text-neutral-300"
className="group inline-flex h-7 w-7 items-center justify-center text-neutral-600 dark:text-neutral-400"
>
<ZapIcon className="h-5 w-5 group-hover:text-blue-500" />
</button>

View File

@@ -80,7 +80,7 @@ export function ChildNote({ id, root }: { id: string; root?: string }) {
<>
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.6rem)] w-0.5 bg-gradient-to-t from-black/20 to-black/10 dark:from-white/20 dark:to-white/10" />
<div className="mb-5 flex flex-col">
<User pubkey={data.pubkey} time={data.created_at} />
<User pubkey={data.pubkey} time={data.created_at} eventId={data.id} />
<div className="-mt-4 flex items-start gap-3">
<div className="w-10 shrink-0" />
<div className="relative z-20 flex-1">

View File

@@ -1,7 +1,10 @@
import { NDKEvent } from '@nostr-dev-kit/ndk';
import ReactMarkdown from 'react-markdown';
import { Link } from 'react-router-dom';
import remarkGfm from 'remark-gfm';
import { Boost, Hashtag, Invoice, MentionUser } from '@shared/notes';
export function ArticleDetailNote({ event }: { event: NDKEvent }) {
/*const metadata = useMemo(() => {
const title = event.tags.find((tag) => tag[0] === 'title')?.[1];
@@ -26,7 +29,38 @@ export function ArticleDetailNote({ event }: { event: NDKEvent }) {
}, [event.id]);*/
return (
<ReactMarkdown className="markdown-article" remarkPlugins={[remarkGfm]}>
<ReactMarkdown
className="prose prose-neutral max-w-none select-text whitespace-pre-line leading-normal dark:prose-invert prose-headings:mb-1 prose-headings:mt-3 prose-p:mb-0 prose-p:mt-0 prose-p:last:mb-1 prose-a:font-normal prose-a:text-blue-500 prose-blockquote:mb-1 prose-blockquote:mt-1 prose-blockquote:border-l-[2px] prose-blockquote:border-blue-500 prose-blockquote:pl-2 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-pre:bg-white/10 prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-ul:mt-1 prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2 hover:prose-a:text-blue-500"
remarkPlugins={[remarkGfm]}
components={{
a: ({ href }) => {
const cleanURL = new URL(href);
cleanURL.search = '';
return (
<Link to={href} target="_blank" className="w-max break-all hover:!underline">
{cleanURL.hostname + cleanURL.pathname}
</Link>
);
},
del: ({ children }) => {
const key = children[0] as string;
if (typeof key !== 'string') return;
if (key.startsWith('pub') && key.length > 50 && key.length < 100) {
return <MentionUser pubkey={key.replace('pub-', '')} />;
}
if (key.startsWith('tag')) {
return <Hashtag tag={key.replace('tag-', '')} />;
}
if (key.startsWith('boost')) {
return <Boost boost={key.replace('boost-', '')} />;
}
if (key.startsWith('lnbc')) {
return <Invoice invoice={key.replace('lnbc-', '')} />;
}
},
}}
linkTarget={'_blank'}
>
{event.content}
</ReactMarkdown>
);

View File

@@ -70,7 +70,11 @@ export function Repost({
>
<User pubkey={event.pubkey} time={event.created_at} variant="repost" />
<div className="relative flex flex-col">
<User pubkey={embedEvent.pubkey} time={embedEvent.created_at} />
<User
pubkey={embedEvent.pubkey}
time={embedEvent.created_at}
eventId={embedEvent.id}
/>
<div className="-mt-4 flex items-start gap-3">
<div className="w-10 shrink-0" />
<div className="relative z-20 flex-1">
@@ -147,7 +151,7 @@ export function Repost({
>
<User pubkey={event.pubkey} time={event.created_at} variant="repost" />
<div className="relative flex flex-col">
<User pubkey={data.pubkey} time={data.created_at} />
<User pubkey={data.pubkey} time={data.created_at} eventId={data.id} />
<div className="-mt-4 flex items-start gap-3">
<div className="w-10 shrink-0" />
<div className="relative z-20 flex-1">

View File

@@ -16,13 +16,13 @@ export function ImagePreview({ urls }: { urls: string[] }) {
<div key={url} className="group relative">
<img
src={url}
alt="image"
className="h-auto w-full rounded-lg border border-neutral-200 object-cover dark:border-neutral-800"
alt={url}
className="h-auto w-full rounded-lg border border-neutral-300 object-cover dark:border-neutral-700"
/>
<button
type="button"
onClick={() => downloadImage(url)}
className="absolute right-2 top-2 hidden h-8 w-8 items-center justify-center rounded-md bg-black/50 backdrop-blur-md group-hover:inline-flex hover:bg-black/40"
className="absolute right-2 top-2 hidden h-10 w-10 items-center justify-center rounded-lg bg-black/50 backdrop-blur-xl group-hover:inline-flex hover:bg-blue-500"
>
<DownloadIcon className="h-5 w-5 text-white" />
</button>

View File

@@ -1,7 +1,6 @@
import { useState } from 'react';
import { Button } from '@shared/button';
import { Image } from '@shared/image';
import { useNostr } from '@utils/hooks/useNostr';
import { useProfile } from '@utils/hooks/useProfile';
@@ -24,34 +23,32 @@ export function NoteReplyForm({ id, pubkey }: { id: string; pubkey: string }) {
};
return (
<div className="mt-3 flex flex-col rounded-xl bg-white/10 backdrop-blur-xl">
<div className="mt-3 flex flex-col rounded-xl bg-neutral-200 dark:bg-neutral-800">
<div className="relative w-full flex-1 overflow-hidden">
<textarea
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Reply to this thread..."
className=" relative h-24 w-full resize-none rounded-md bg-transparent px-3 py-3 text-base text-white !outline-none placeholder:text-white/50"
className=" relative h-24 w-full resize-none rounded-md bg-transparent px-3 py-3 text-base text-neutral-900 !outline-none placeholder:text-neutral-600 dark:text-neutral-100 dark:placeholder:text-neutral-400"
spellCheck={false}
/>
</div>
<div className="w-full border-t border-white/10 px-3 py-3">
<div className="w-full border-t border-neutral-300 px-3 py-3 dark:border-neutral-700">
{status === 'loading' ? (
<div>
<p>Loading...</p>
</div>
<div>Loading</div>
) : (
<div className="flex w-full items-center justify-between">
<div className="inline-flex items-center gap-3">
<div className="inline-flex items-center gap-2">
<div className="relative h-11 w-11 shrink-0 rounded">
<Image
<img
src={user?.picture || user?.image}
alt={pubkey}
className="h-11 w-11 rounded-lg bg-white object-cover"
/>
</div>
<div>
<p className="mb-1 text-sm leading-none text-white/50">Reply as</p>
<p className="text-sm font-medium leading-none text-white">
<p className="text-sm text-neutral-600 dark:text-neutral-400">Reply as</p>
<p className="font-semibold text-neutral-900 dark:text-neutral-100">
{user?.name || displayNpub(pubkey, 16)}
</p>
</div>

View File

@@ -30,7 +30,7 @@ export function NoteWrapper({
<div className="relative">{root && <ChildNote id={root} />}</div>
<div className="relative">{reply && <ChildNote id={reply} root={root} />}</div>
<div className="relative flex flex-col">
<User pubkey={event.pubkey} time={event.created_at} />
<User pubkey={event.pubkey} time={event.created_at} eventId={event.id} />
<div className="-mt-4 flex items-start gap-3">
<div className="w-10 shrink-0" />
<div className="relative z-20 flex-1">