add following and discover tabs to home view

This commit is contained in:
hzrd149
2023-02-07 17:04:18 -06:00
parent effb45f3c9
commit 2a34b370cd
11 changed files with 163 additions and 38 deletions

View File

@@ -10,7 +10,7 @@ import {
ModalOverlay,
} from "@chakra-ui/react";
import { NostrEvent } from "../types/nostr-event";
import { PostContents } from "./post-contents";
import { PostContents } from "./post/post-contents";
export type PostModalProps = {
event: NostrEvent;

View File

@@ -20,7 +20,7 @@ import { UserAvatarLink } from "../user-avatar-link";
import { getUserDisplayName } from "../../helpers/user-metadata";
import { Bech32Prefix, normalizeToBech32 } from "../../helpers/nip-19";
import { PostContents } from "../post-contents";
import { PostContents } from "./post-contents";
import { PostMenu } from "./post-menu";
import { PostCC } from "./post-cc";
@@ -35,7 +35,7 @@ export const Post = React.memo(({ event }: PostProps) => {
<Card padding="2" variant="outline">
<CardHeader padding="0" mb="2">
<HStack spacing="4">
<Flex flex="1" gap="2" alignItems="center" flexWrap="wrap">
<Flex flex="1" gap="2">
<UserAvatarLink pubkey={event.pubkey} size="sm" />
<Box>

View File

@@ -23,7 +23,7 @@ export const PostCC = ({ event }: { event: NostrEvent }) => {
if (!hasCC) return null;
return (
<Text fontSize="sm">
<Text fontSize="sm" color="gray.500">
<span>Replying to: </span>
{event.tags
.filter((t) => t[0] === "p")

View File

@@ -13,8 +13,8 @@ import remarkUnwrapImages from "remark-unwrap-images";
import rehypeExternalLinks from "rehype-external-links";
// @ts-ignore
import linkifyRegex from "remark-linkify-regex";
import { InlineInvoiceCard } from "./inline-invoice-card";
import { TweetEmbed } from "./tweet-embed";
import { InlineInvoiceCard } from "../inline-invoice-card";
import { TweetEmbed } from "../tweet-embed";
const lightningInvoiceRegExp = /(lightning:)?LNBC[A-Za-z0-9]+/i;

View File

@@ -1,3 +1,4 @@
import moment from "moment";
import { createRoot } from "react-dom/client";
import { App } from "./app";
import { Providers } from "./providers";
@@ -11,3 +12,7 @@ root.render(
<App />
</Providers>
);
if (import.meta.env.DEV) {
window.moment = moment;
}

View File

@@ -75,10 +75,10 @@ export const GlobalView = () => {
flexDirection="column"
flexGrow="1"
overflow="hidden"
isManual
isLazy
>
<TabList>
<Tab>Posts</Tab>
<Tab>Notes</Tab>
<Tab>Replies</Tab>
</TabList>
<TabPanels overflow="auto" height="100%">

View File

@@ -1,28 +0,0 @@
import { HStack } from "@chakra-ui/react";
import { UserAvatarLink } from "../components/user-avatar-link";
import { normalizeToHex } from "../helpers/nip-19";
export const HomeView = () => {
return (
<HStack spacing=".5rem">
<UserAvatarLink pubkey="32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245" />
<UserAvatarLink
pubkey={
normalizeToHex(
"npub1dergggklka99wwrs92yz8wdjs952h2ux2ha2ed598ngwu9w7a6fsh9xzpc"
) ?? ""
}
/>
<UserAvatarLink pubkey="00000000827ffaa94bfea288c3dfce4422c794fbb96625b6b31e9049f729d700" />
<UserAvatarLink pubkey="82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2" />
<UserAvatarLink pubkey="85080d3bad70ccdcd7f74c29a44f55bb85cbcd3dd0cbb957da1d215bdb931204" />
<UserAvatarLink pubkey="e88a691e98d9987c964521dff60025f60700378a4879180dcbbb4a5027850411" />
<UserAvatarLink pubkey="8c0da4862130283ff9e67d889df264177a508974e2feb96de139804ea66d6168" />
<UserAvatarLink pubkey="c4eabae1be3cf657bc1855ee05e69de9f059cb7a059227168b80b89761cbc4e0" />
<UserAvatarLink pubkey="e33fe65f1fde44c6dc17eeb38fdad0fceaf1cae8722084332ed1e32496291d42" />
<UserAvatarLink pubkey="c5cfda98d01f152b3493d995eed4cdb4d9e55a973925f6f9ea24769a5a21e778" />
<UserAvatarLink pubkey="3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" />
<UserAvatarLink pubkey="04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9" />
</HStack>
);
};

View File

@@ -0,0 +1,77 @@
import { useEffect, useState } from "react";
import { Flex, Text } from "@chakra-ui/react";
import moment from "moment";
import { mergeAll, from } from "rxjs";
import { Post } from "../../components/post";
import { useEventDir } from "../../hooks/use-event-dir";
import useSubject from "../../hooks/use-subject";
import { useSubscription } from "../../hooks/use-subscription";
import { useUserContacts } from "../../hooks/use-user-contacts";
import identity from "../../services/identity";
import settings from "../../services/settings";
import userContacts from "../../services/user-contacts";
function useExtendedContacts(pubkey: string) {
const relays = useSubject(settings.relays);
const [extendedContacts, setExtendedContacts] = useState<string[]>([]);
const { contacts } = useUserContacts(pubkey);
useEffect(() => {
if (contacts) {
const following = contacts.contacts.map((c) => c.pubkey);
const subscriptions = contacts.contacts.map((contact) =>
userContacts.requestUserContacts(contact.pubkey, relays)
);
const rxSub = from(subscriptions)
.pipe(mergeAll())
.subscribe((contacts) => {
if (contacts) {
setExtendedContacts((value) => {
const more = contacts.contacts
.map((c) => c.pubkey)
.filter((key) => !following.includes(key));
return Array.from(new Set([...value, ...more]));
});
}
});
return () => rxSub.unsubscribe();
}
}, [contacts, setExtendedContacts]);
return extendedContacts;
}
export const DiscoverTab = () => {
const relays = useSubject(settings.relays);
const pubkey = useSubject(identity.pubkey);
const contactsOfContacts = useExtendedContacts(pubkey);
const [since, setSince] = useState(moment().subtract(1, "hour"));
const [after, setAfter] = useState(moment());
const sub = useSubscription(
relays,
{
authors: contactsOfContacts,
kinds: [1],
since: since.unix(),
},
"home-discover"
);
const { events } = useEventDir(sub);
const timeline = Object.values(events).sort(
(a, b) => b.created_at - a.created_at
);
return (
<Flex direction="column" overflow="auto" gap="2">
{timeline.map((event) => (
<Post key={event.id} event={event} />
))}
</Flex>
);
};

View File

@@ -0,0 +1,43 @@
import { Flex } from "@chakra-ui/react";
import moment from "moment";
import { useState } from "react";
import { Post } from "../../components/post";
import { useEventDir } from "../../hooks/use-event-dir";
import useSubject from "../../hooks/use-subject";
import { useSubscription } from "../../hooks/use-subscription";
import { useUserContacts } from "../../hooks/use-user-contacts";
import identity from "../../services/identity";
import settings from "../../services/settings";
export const FollowingTab = () => {
const relays = useSubject(settings.relays);
const pubkey = useSubject(identity.pubkey);
const { contacts } = useUserContacts(pubkey);
const [since, setSince] = useState(moment().subtract(1, "hour"));
const [after, setAfter] = useState(moment());
const following = contacts?.contacts.map((contact) => contact.pubkey) || [];
const sub = useSubscription(
relays,
{
authors: following,
kinds: [1],
since: since.unix(),
},
"home-following"
);
const { events } = useEventDir(sub);
const timeline = Object.values(events).sort(
(a, b) => b.created_at - a.created_at
);
return (
<Flex direction="column" overflow="auto" gap="2">
{timeline.map((event) => (
<Post key={event.id} event={event} />
))}
</Flex>
);
};

28
src/views/home/index.tsx Normal file
View File

@@ -0,0 +1,28 @@
import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
import { DiscoverTab } from "./discover-tab";
import { FollowingTab } from "./following-tab";
export const HomeView = () => {
return (
<Tabs
display="flex"
flexDirection="column"
flexGrow="1"
overflow="hidden"
isLazy
>
<TabList>
<Tab>Following</Tab>
<Tab>Discover</Tab>
</TabList>
<TabPanels overflow="auto" height="100%">
<TabPanel pr={0} pl={0}>
<FollowingTab />
</TabPanel>
<TabPanel pr={0} pl={0}>
<DiscoverTab />
</TabPanel>
</TabPanels>
</Tabs>
);
};

View File

@@ -85,10 +85,10 @@ export const UserView = ({ pubkey }: UserViewProps) => {
flexDirection="column"
flexGrow="1"
overflow="hidden"
isManual
isLazy
>
<TabList>
<Tab>Posts</Tab>
<Tab>Notes</Tab>
{/* <Tab>Replies</Tab> */}
<Tab>Following</Tab>
<Tab>Relays</Tab>