mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-03-26 17:52:18 +01:00
remove broken torrent preview view
remove test DM windows
This commit is contained in:
parent
6d0fd9e960
commit
3a3851aa91
@ -62,7 +62,6 @@
|
||||
"three": "^0.157.0",
|
||||
"three-spritetext": "^1.8.1",
|
||||
"webln": "^0.3.2",
|
||||
"webtorrent": "^2.1.29",
|
||||
"yet-another-react-lightbox": "^3.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -79,7 +78,6 @@
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/three": "^0.157.2",
|
||||
"@types/webscopeio__react-textarea-autocomplete": "^4.7.2",
|
||||
"@types/webtorrent": "^0.109.7",
|
||||
"@vitejs/plugin-react": "^4.0.4",
|
||||
"camelcase": "^8.0.0",
|
||||
"prettier": "^3.0.2",
|
||||
|
@ -95,7 +95,6 @@ const ChannelView = lazy(() => import("./views/channels/channel"));
|
||||
|
||||
const TorrentsView = lazy(() => import("./views/torrents"));
|
||||
const TorrentDetailsView = lazy(() => import("./views/torrents/torrent"));
|
||||
const TorrentPreviewView = lazy(() => import("./views/torrents/preview"));
|
||||
const NewTorrentView = lazy(() => import("./views/torrents/new"));
|
||||
|
||||
const overrideReactTextareaAutocompleteStyles = css`
|
||||
@ -289,10 +288,6 @@ const router = createHashRouter([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "torrents/:id/preview",
|
||||
element: <TorrentPreviewView />,
|
||||
},
|
||||
{
|
||||
path: "torrents",
|
||||
children: [
|
||||
|
@ -1,121 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { Button, Card, CardBody, CardHeader, CloseButton, Flex, Heading, IconButton, useToast } from "@chakra-ui/react";
|
||||
import { Kind } from "nostr-tools";
|
||||
import dayjs from "dayjs";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { ChevronDownIcon, ChevronUpIcon } from "../icons";
|
||||
import UserName from "../user-name";
|
||||
import MagicTextArea from "../magic-textarea";
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { useReadRelayUrls, useWriteRelayUrls } from "../../hooks/use-client-relays";
|
||||
import { useUserRelays } from "../../hooks/use-user-relays";
|
||||
import { RelayMode } from "../../classes/relay";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import IntersectionObserverProvider from "../../providers/intersection-observer";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import MessageBlock from "../../views/dms/message-block";
|
||||
import { LightboxProvider } from "../lightbox-provider";
|
||||
import { useSigningContext } from "../../providers/signing-provider";
|
||||
import { DraftNostrEvent } from "../../types/nostr-event";
|
||||
import NostrPublishAction from "../../classes/nostr-publish-action";
|
||||
import { correctContentMentions, createEmojiTags } from "../../helpers/nostr/post";
|
||||
import { useContextEmojis } from "../../providers/emoji-provider";
|
||||
|
||||
export default function ChatWindow({ pubkey, onClose }: { pubkey: string; onClose: () => void }) {
|
||||
const toast = useToast();
|
||||
const account = useCurrentAccount()!;
|
||||
const emojis = useContextEmojis();
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
|
||||
const usersRelays = useUserRelays(pubkey);
|
||||
const readRelays = useReadRelayUrls(usersRelays.filter((c) => c.mode & RelayMode.WRITE).map((c) => c.url));
|
||||
const writeRelays = useWriteRelayUrls(usersRelays.filter((c) => c.mode & RelayMode.WRITE).map((c) => c.url));
|
||||
|
||||
const timeline = useTimelineLoader(`${pubkey}-${account.pubkey}-messages`, readRelays, [
|
||||
{ authors: [account.pubkey], kinds: [Kind.EncryptedDirectMessage], "#p": [pubkey] },
|
||||
{ authors: [pubkey], kinds: [Kind.EncryptedDirectMessage], "#p": [account.pubkey] },
|
||||
]);
|
||||
|
||||
const { handleSubmit, getValues, setValue, formState, watch, reset } = useForm({ defaultValues: { content: "" } });
|
||||
watch("content");
|
||||
const { requestSignature, requestEncrypt } = useSigningContext();
|
||||
const submit = handleSubmit(async (values) => {
|
||||
try {
|
||||
if (!values.content) return;
|
||||
let draft: DraftNostrEvent = {
|
||||
kind: Kind.EncryptedDirectMessage,
|
||||
content: values.content,
|
||||
tags: [["p", pubkey]],
|
||||
created_at: dayjs().unix(),
|
||||
};
|
||||
|
||||
draft = createEmojiTags(draft, emojis);
|
||||
draft.content = correctContentMentions(draft.content);
|
||||
|
||||
// encrypt content
|
||||
draft.content = await requestEncrypt(draft.content, pubkey);
|
||||
|
||||
const signed = await requestSignature(draft);
|
||||
const pub = new NostrPublishAction("Send DM", writeRelays, signed);
|
||||
|
||||
reset();
|
||||
} catch (e) {
|
||||
if (e instanceof Error) toast({ status: "error", description: e.message });
|
||||
}
|
||||
});
|
||||
|
||||
const messages = useSubject(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
return (
|
||||
<Card size="sm" borderRadius="md" w={expanded ? "md" : "xs"} variant="outline">
|
||||
<CardHeader display="flex" gap="2" alignItems="center">
|
||||
<Heading size="md" mr="8">
|
||||
<UserName pubkey={pubkey} />
|
||||
</Heading>
|
||||
<IconButton
|
||||
aria-label="Toggle Window"
|
||||
onClick={() => setExpanded((v) => !v)}
|
||||
variant="ghost"
|
||||
icon={expanded ? <ChevronDownIcon /> : <ChevronUpIcon />}
|
||||
ml="auto"
|
||||
size="sm"
|
||||
/>
|
||||
<CloseButton onClick={onClose} />
|
||||
</CardHeader>
|
||||
{expanded && (
|
||||
<>
|
||||
<CardBody
|
||||
maxH="lg"
|
||||
overflowX="hidden"
|
||||
overflowY="auto"
|
||||
pt="0"
|
||||
display="flex"
|
||||
flexDirection="column-reverse"
|
||||
gap="2"
|
||||
>
|
||||
<LightboxProvider>
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
{messages.map((event) => (
|
||||
<MessageBlock key={event.id} events={event} />
|
||||
))}
|
||||
</IntersectionObserverProvider>
|
||||
</LightboxProvider>
|
||||
</CardBody>
|
||||
<Flex as="form" onSubmit={submit} gap="2">
|
||||
<MagicTextArea
|
||||
isRequired
|
||||
value={getValues().content}
|
||||
onChange={(e) => setValue("content", e.target.value, { shouldDirty: true })}
|
||||
/>
|
||||
<Button type="submit" isLoading={formState.isSubmitting}>
|
||||
Send
|
||||
</Button>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
Button,
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
CloseButton,
|
||||
Heading,
|
||||
IconButton,
|
||||
Input,
|
||||
InputGroup,
|
||||
InputLeftElement,
|
||||
} from "@chakra-ui/react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { ChevronDownIcon, ChevronUpIcon, SearchIcon } from "../icons";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import directMessagesService from "../../services/direct-messages";
|
||||
import UserAvatar from "../user-avatar";
|
||||
import UserName from "../user-name";
|
||||
|
||||
export default function ContactsWindow({
|
||||
onClose,
|
||||
onSelectPubkey,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
onSelectPubkey: (pubkey: string) => void;
|
||||
}) {
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
|
||||
// TODO: find a better way to load recent contacts
|
||||
const [from, setFrom] = useState(() => dayjs().subtract(2, "days").unix());
|
||||
const conversations = useSubject(directMessagesService.conversations);
|
||||
useEffect(() => directMessagesService.loadDateRange(from), [from]);
|
||||
const sortedConversations = useMemo(() => {
|
||||
return Array.from(conversations).sort((a, b) => {
|
||||
const latestA = directMessagesService.getUserMessages(a).value[0]?.created_at ?? 0;
|
||||
const latestB = directMessagesService.getUserMessages(b).value[0]?.created_at ?? 0;
|
||||
|
||||
return latestB - latestA;
|
||||
});
|
||||
}, [conversations]);
|
||||
|
||||
return (
|
||||
<Card size="sm" borderRadius="md" minW={expanded ? "sm" : 0}>
|
||||
<CardHeader display="flex" gap="2" alignItems="center">
|
||||
<Heading size="md" mr="8">
|
||||
Contacts
|
||||
</Heading>
|
||||
<IconButton
|
||||
aria-label="Toggle Window"
|
||||
onClick={() => setExpanded((v) => !v)}
|
||||
variant="ghost"
|
||||
icon={expanded ? <ChevronDownIcon /> : <ChevronUpIcon />}
|
||||
ml="auto"
|
||||
size="sm"
|
||||
/>
|
||||
<CloseButton onClick={onClose} />
|
||||
</CardHeader>
|
||||
{expanded && (
|
||||
<CardBody maxH="lg" overflowX="hidden" overflowY="auto" pt="0" display="flex" flexDirection="column" gap="2">
|
||||
<Alert status="warning">
|
||||
<AlertIcon />
|
||||
Work in progress!
|
||||
</Alert>
|
||||
{/* <InputGroup>
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon />
|
||||
</InputLeftElement>
|
||||
<Input autoFocus />
|
||||
</InputGroup> */}
|
||||
{sortedConversations.map((pubkey) => (
|
||||
<Button
|
||||
key={pubkey}
|
||||
leftIcon={<UserAvatar pubkey={pubkey} size="sm" />}
|
||||
justifyContent="flex-start"
|
||||
p="2"
|
||||
variant="ghost"
|
||||
onClick={() => onSelectPubkey(pubkey)}
|
||||
>
|
||||
<UserName pubkey={pubkey} />
|
||||
</Button>
|
||||
))}
|
||||
</CardBody>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { Flex, IconButton } from "@chakra-ui/react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useLocalStorage } from "react-use";
|
||||
|
||||
import ContactsWindow from "./contacts-window";
|
||||
import { DirectMessagesIcon } from "../icons";
|
||||
import ChatWindow from "./chat-window";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
|
||||
export default function ChatWindows() {
|
||||
const account = useCurrentAccount();
|
||||
const [pubkeys, setPubkeys] = useState<string[]>([]);
|
||||
const [show, setShow] = useLocalStorage("show-chat-windows", false);
|
||||
|
||||
const openPubkey = useCallback(
|
||||
(pubkey: string) => {
|
||||
setPubkeys((keys) => (keys.includes(pubkey) ? keys : keys.concat(pubkey)));
|
||||
},
|
||||
[setPubkeys],
|
||||
);
|
||||
|
||||
const closePubkey = useCallback(
|
||||
(pubkey: string) => {
|
||||
setPubkeys((keys) => keys.filter((key) => key !== pubkey));
|
||||
},
|
||||
[setPubkeys],
|
||||
);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!show) {
|
||||
return (
|
||||
<IconButton
|
||||
icon={<DirectMessagesIcon boxSize={6} />}
|
||||
aria-label="Show Contacts"
|
||||
onClick={() => setShow(true)}
|
||||
position="fixed"
|
||||
bottom="0"
|
||||
right="0"
|
||||
size="lg"
|
||||
zIndex={1}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex direction="row-reverse" position="fixed" bottom="0" right="0" gap="4" alignItems="flex-end" zIndex={1}>
|
||||
<ContactsWindow onClose={() => setShow(false)} onSelectPubkey={openPubkey} />
|
||||
{pubkeys.map((pubkey) => (
|
||||
<ChatWindow key={pubkey} pubkey={pubkey} onClose={() => closePubkey(pubkey)} />
|
||||
))}
|
||||
</Flex>
|
||||
);
|
||||
}
|
@ -12,7 +12,6 @@ import GhostToolbar from "./ghost-toolbar";
|
||||
import { useBreakpointValue } from "../../providers/breakpoint-provider";
|
||||
import SearchModal from "../search-modal";
|
||||
import { useLocation } from "react-router-dom";
|
||||
// import ChatWindows from "../chat-windows";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const isMobile = useBreakpointValue({ base: true, md: false });
|
||||
@ -66,7 +65,6 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
</Flex>
|
||||
{isGhost && <GhostToolbar />}
|
||||
{searchModal.isOpen && <SearchModal isOpen onClose={searchModal.onClose} />}
|
||||
{/* {!isMobile && <ChatWindows />} */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Button, Code, Flex, Spinner, useForceUpdate } from "@chakra-ui/react";
|
||||
import WebTorrent from "../../lib/webtorrent";
|
||||
import type { Torrent } from "webtorrent";
|
||||
|
||||
import { safeDecode } from "../../helpers/nip19";
|
||||
import useSingleEvent from "../../hooks/use-single-event";
|
||||
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import { getTorrentMagnetLink } from "../../helpers/nostr/torrents";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import { ChevronLeftIcon } from "../../components/icons";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
|
||||
const client = new WebTorrent();
|
||||
|
||||
// @ts-ignore
|
||||
window.torrentClient = client;
|
||||
|
||||
function TorrentPreview({ torrent }: { torrent: Torrent; event: NostrEvent }) {
|
||||
const update = useForceUpdate();
|
||||
const preview = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
torrent.on("metadata", update);
|
||||
torrent.on("ready", update);
|
||||
torrent.on("done", update);
|
||||
return () => {
|
||||
// torrent.off("metadata", update);
|
||||
};
|
||||
}, [torrent]);
|
||||
|
||||
return (
|
||||
<Flex gap="4">
|
||||
<Flex direction="column">
|
||||
{torrent.files.map((file) => (
|
||||
<Button key={file.path}>{file.name}</Button>
|
||||
))}
|
||||
</Flex>
|
||||
<Code as="pre">{JSON.stringify({ ready: torrent.ready, name: torrent.name }, null, 2)}</Code>
|
||||
<div ref={preview} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function TorrentPreviewPage({ event }: { event: NostrEvent }) {
|
||||
const navigate = useNavigate();
|
||||
const magnet = getTorrentMagnetLink(event);
|
||||
|
||||
const [torrent, setTorrent] = useState<Torrent>();
|
||||
useEffect(() => {
|
||||
setTorrent(
|
||||
client.add(magnet, (t) => {
|
||||
console.log(t);
|
||||
}),
|
||||
);
|
||||
return () => {
|
||||
client.remove(magnet);
|
||||
setTorrent(undefined);
|
||||
};
|
||||
}, [magnet]);
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2">
|
||||
<Button leftIcon={<ChevronLeftIcon />} onClick={() => navigate(-1)}>
|
||||
Back
|
||||
</Button>
|
||||
</Flex>
|
||||
{torrent && <TorrentPreview torrent={torrent} event={event} />}
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TorrentPreviewView() {
|
||||
const { id } = useParams() as { id: string };
|
||||
const parsed = useMemo(() => {
|
||||
const result = safeDecode(id);
|
||||
if (!result) return;
|
||||
if (result.type === "note") return { id: result.data };
|
||||
if (result.type === "nevent") return result.data;
|
||||
}, [id]);
|
||||
const torrent = useSingleEvent(parsed?.id, parsed?.relays ?? []);
|
||||
|
||||
if (!torrent) return <Spinner />;
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<TorrentPreviewPage event={torrent} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user