cleanup list view

This commit is contained in:
hzrd149
2023-10-10 08:31:33 -05:00
parent cdfdc71517
commit 45736a4d3f
6 changed files with 122 additions and 94 deletions

View File

@@ -21,14 +21,14 @@ export default function EmbeddedList({ list: list, ...props }: Omit<CardProps, "
{getListName(list)} {getListName(list)}
</Link> </Link>
</Heading> </Heading>
<ListFeedButton list={list} ml="auto" size="sm" />
</CardHeader>
<CardBody p="2">
<Flex gap="2"> <Flex gap="2">
<Text>Created by:</Text> <Text>by</Text>
<UserAvatarLink pubkey={list.pubkey} size="xs" /> <UserAvatarLink pubkey={list.pubkey} size="xs" />
<UserLink pubkey={list.pubkey} isTruncated fontWeight="bold" fontSize="lg" /> <UserLink pubkey={list.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
</Flex> </Flex>
<ListFeedButton list={list} ml="auto" size="sm" />
</CardHeader>
<CardBody p="2">
<ListCardContent list={list} /> <ListCardContent list={list} />
</CardBody> </CardBody>
</Card> </Card>

View File

@@ -177,7 +177,13 @@ export const StarHalfIcon = createIcon({
export const ErrorIcon = AlertTriangle; export const ErrorIcon = AlertTriangle;
export const BookmarkIcon = Bookmark; export const BookmarkIcon = Bookmark;
export const BookmarkedIcon = BookmarkCheck;
// TODO: switch to untitled UI solid icon
export const BookmarkedIcon = createIcon({
displayName: "BookmarkedIcon",
d: "M4 2H20C20.5523 2 21 2.44772 21 3V22.2763C21 22.5525 20.7761 22.7764 20.5 22.7764C20.4298 22.7764 20.3604 22.7615 20.2963 22.7329L12 19.0313L3.70373 22.7329C3.45155 22.8455 3.15591 22.7322 3.04339 22.4801C3.01478 22.4159 3 22.3465 3 22.2763V3C3 2.44772 3.44772 2 4 2ZM12 13.5L14.9389 15.0451L14.3776 11.7725L16.7553 9.45492L13.4695 8.97746L12 6L10.5305 8.97746L7.24472 9.45492L9.62236 11.7725L9.06107 15.0451L12 13.5Z",
defaultProps,
});
export const V4VStreamIcon = PlayCircle; export const V4VStreamIcon = PlayCircle;
export const V4VStopIcon = StopCircle; export const V4VStopIcon = StopCircle;

View File

@@ -1,13 +1,13 @@
import { Box, Button, ButtonProps, Text } from "@chakra-ui/react"; import { Box, Button, ButtonProps, Text } from "@chakra-ui/react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { Link as RouterLink } from "react-router-dom";
import { import {
BadgeIcon, BadgeIcon,
DirectMessagesIcon, DirectMessagesIcon,
CommunityIcon, CommunityIcon,
EmojiPacksIcon, EmojiPacksIcon,
NoteFeedIcon,
GoalIcon, GoalIcon,
ListsIcon, ListsIcon,
LiveStreamIcon, LiveStreamIcon,
@@ -24,7 +24,6 @@ import { useCurrentAccount } from "../../hooks/use-current-account";
import accountService from "../../services/account"; import accountService from "../../services/account";
export default function NavItems() { export default function NavItems() {
const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const account = useCurrentAccount(); const account = useCurrentAccount();
@@ -59,7 +58,8 @@ export default function NavItems() {
return ( return (
<> <>
<Button <Button
onClick={() => navigate("/")} as={RouterLink}
to="/"
leftIcon={<NotesIcon boxSize={6} />} leftIcon={<NotesIcon boxSize={6} />}
colorScheme={active === "notes" ? "primary" : undefined} colorScheme={active === "notes" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -69,7 +69,8 @@ export default function NavItems() {
{account && ( {account && (
<> <>
<Button <Button
onClick={() => navigate("/notifications")} as={RouterLink}
to="/notifications"
leftIcon={<NotificationsIcon boxSize={6} />} leftIcon={<NotificationsIcon boxSize={6} />}
colorScheme={active === "notifications" ? "primary" : undefined} colorScheme={active === "notifications" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -77,7 +78,8 @@ export default function NavItems() {
Notifications Notifications
</Button> </Button>
<Button <Button
onClick={() => navigate("/dm")} as={RouterLink}
to={"/dm"}
leftIcon={<DirectMessagesIcon boxSize={6} />} leftIcon={<DirectMessagesIcon boxSize={6} />}
colorScheme={active === "dm" ? "primary" : undefined} colorScheme={active === "dm" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -87,7 +89,8 @@ export default function NavItems() {
</> </>
)} )}
<Button <Button
onClick={() => navigate("/search")} as={RouterLink}
to="/search"
leftIcon={<SearchIcon boxSize={6} />} leftIcon={<SearchIcon boxSize={6} />}
colorScheme={active === "search" ? "primary" : undefined} colorScheme={active === "search" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -96,7 +99,8 @@ export default function NavItems() {
</Button> </Button>
{account?.pubkey && ( {account?.pubkey && (
<Button <Button
onClick={() => navigate("/u/" + nip19.npubEncode(account.pubkey))} as={RouterLink}
to={"/u/" + nip19.npubEncode(account.pubkey)}
leftIcon={<ProfileIcon boxSize={6} />} leftIcon={<ProfileIcon boxSize={6} />}
colorScheme={active === "profile" ? "primary" : undefined} colorScheme={active === "profile" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -105,7 +109,8 @@ export default function NavItems() {
</Button> </Button>
)} )}
<Button <Button
onClick={() => navigate("/relays")} as={RouterLink}
to="/relays"
leftIcon={<RelayIcon boxSize={6} />} leftIcon={<RelayIcon boxSize={6} />}
colorScheme={active === "relays" ? "primary" : undefined} colorScheme={active === "relays" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -116,7 +121,8 @@ export default function NavItems() {
Other Stuff Other Stuff
</Text> </Text>
<Button <Button
onClick={() => navigate("/streams")} as={RouterLink}
to="/streams"
leftIcon={<LiveStreamIcon boxSize={6} />} leftIcon={<LiveStreamIcon boxSize={6} />}
colorScheme={active === "streams" ? "primary" : undefined} colorScheme={active === "streams" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -124,7 +130,8 @@ export default function NavItems() {
Streams Streams
</Button> </Button>
<Button <Button
onClick={() => navigate("/communities")} as={RouterLink}
to="/communities"
leftIcon={<CommunityIcon boxSize={6} />} leftIcon={<CommunityIcon boxSize={6} />}
colorScheme={active === "communities" ? "primary" : undefined} colorScheme={active === "communities" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -132,7 +139,8 @@ export default function NavItems() {
Communities Communities
</Button> </Button>
<Button <Button
onClick={() => navigate("/lists")} as={RouterLink}
to="/lists"
leftIcon={<ListsIcon boxSize={6} />} leftIcon={<ListsIcon boxSize={6} />}
colorScheme={active === "lists" ? "primary" : undefined} colorScheme={active === "lists" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -140,7 +148,8 @@ export default function NavItems() {
Lists Lists
</Button> </Button>
<Button <Button
onClick={() => navigate("/goals")} as={RouterLink}
to="/goals"
leftIcon={<GoalIcon boxSize={6} />} leftIcon={<GoalIcon boxSize={6} />}
colorScheme={active === "goals" ? "primary" : undefined} colorScheme={active === "goals" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -148,7 +157,8 @@ export default function NavItems() {
Goals Goals
</Button> </Button>
<Button <Button
onClick={() => navigate("/badges")} as={RouterLink}
to="/badges"
leftIcon={<BadgeIcon boxSize={6} />} leftIcon={<BadgeIcon boxSize={6} />}
colorScheme={active === "badges" ? "primary" : undefined} colorScheme={active === "badges" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -156,7 +166,8 @@ export default function NavItems() {
Badges Badges
</Button> </Button>
<Button <Button
onClick={() => navigate("/emojis")} as={RouterLink}
to="/emojis"
leftIcon={<EmojiPacksIcon boxSize={6} />} leftIcon={<EmojiPacksIcon boxSize={6} />}
colorScheme={active === "emojis" ? "primary" : undefined} colorScheme={active === "emojis" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -164,7 +175,8 @@ export default function NavItems() {
Emojis Emojis
</Button> </Button>
<Button <Button
onClick={() => navigate("/tools")} as={RouterLink}
to="/tools"
leftIcon={<ToolsIcon boxSize={6} />} leftIcon={<ToolsIcon boxSize={6} />}
colorScheme={active === "tools" ? "primary" : undefined} colorScheme={active === "tools" ? "primary" : undefined}
{...buttonProps} {...buttonProps}
@@ -173,7 +185,8 @@ export default function NavItems() {
</Button> </Button>
<Box h="4" /> <Box h="4" />
<Button <Button
onClick={() => navigate("/settings")} as={RouterLink}
to="/settings"
leftIcon={<SettingsIcon boxSize={6} />} leftIcon={<SettingsIcon boxSize={6} />}
colorScheme={active === "settings" ? "primary" : undefined} colorScheme={active === "settings" ? "primary" : undefined}
{...buttonProps} {...buttonProps}

View File

@@ -69,7 +69,7 @@ function BrowseListPage() {
</Switch> </Switch>
</Flex> </Flex>
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> <SimpleGrid columns={{ base: 1, lg: 2 }} spacing="2">
{lists.map((event) => ( {lists.map((event) => (
<ListCard key={getEventUID(event)} list={event} /> <ListCard key={getEventUID(event)} list={event} />
))} ))}

View File

@@ -5,7 +5,6 @@ import {
ButtonGroup, ButtonGroup,
Card, Card,
CardBody, CardBody,
CardFooter,
CardHeader, CardHeader,
CardProps, CardProps,
Flex, Flex,
@@ -66,6 +65,9 @@ export function ListCardContent({ list, ...props }: Omit<CardProps, "children">
return ( return (
<> <>
<Text>
Updated: <Timestamp timestamp={list.created_at} />
</Text>
{people.length > 0 && ( {people.length > 0 && (
<> <>
<Text>People ({people.length}):</Text> <Text>People ({people.length}):</Text>
@@ -77,31 +79,26 @@ export function ListCardContent({ list, ...props }: Omit<CardProps, "children">
</> </>
)} )}
{notes.length > 0 && ( {notes.length > 0 && (
<> <Flex gap="2" overflow="hidden" wrap="wrap">
<Text>Notes ({notes.length}):</Text> <Text>Notes ({notes.length}):</Text>
<Flex gap="2" overflow="hidden">
{notes.slice(0, 4).map(({ id, relay }) => ( {notes.slice(0, 4).map(({ id, relay }) => (
<NoteLink key={id} noteId={id} /> <NoteLink key={id} noteId={id} />
))} ))}
</Flex> </Flex>
</>
)} )}
{references.length > 0 && ( {references.length > 0 && (
<> <Flex gap="2" overflow="hidden" wrap="wrap">
<Text>References ({references.length})</Text> <Text>References ({references.length})</Text>
<Flex gap="2" overflow="hidden">
{references.slice(0, 3).map(({ url, petname }) => ( {references.slice(0, 3).map(({ url, petname }) => (
<Link maxW="200" href={url} isExternal whiteSpace="pre" color="blue.500" isTruncated> <Link maxW="200" href={url} isExternal whiteSpace="pre" color="blue.500" isTruncated>
{petname || url} {petname || url}
</Link> </Link>
))} ))}
</Flex> </Flex>
</>
)} )}
{communities.length > 0 && ( {communities.length > 0 && (
<> <Flex gap="2" overflow="hidden" wrap="wrap">
<Text>Communities ({communities.length}):</Text> <Text>Communities ({communities.length}):</Text>
<Flex gap="2" overflow="hidden">
{communities.map((pointer) => ( {communities.map((pointer) => (
<Link <Link
key={JSON.stringify(pointer)} key={JSON.stringify(pointer)}
@@ -113,23 +110,24 @@ export function ListCardContent({ list, ...props }: Omit<CardProps, "children">
</Link> </Link>
))} ))}
</Flex> </Flex>
</>
)} )}
{articles.length > 0 && ( {articles.length > 0 && (
<> <Flex overflow="hidden" direction="column" wrap="wrap">
<Text>Articles ({articles.length}):</Text> <Text>Articles ({articles.length}):</Text>
<Flex overflow="hidden" direction="column">
{articles.slice(0, 4).map((pointer) => ( {articles.slice(0, 4).map((pointer) => (
<ArticleLinkLoader key={JSON.stringify(pointer)} pointer={pointer} isTruncated /> <ArticleLinkLoader key={JSON.stringify(pointer)} pointer={pointer} isTruncated />
))} ))}
</Flex> </Flex>
</>
)} )}
</> </>
); );
} }
function ListCardRender({ list, ...props }: Omit<CardProps, "children"> & { list: NostrEvent }) { function ListCardRender({
list,
hideCreator = false,
...props
}: Omit<CardProps, "children"> & { list: NostrEvent; hideCreator?: boolean }) {
const link = isSpecialListKind(list.kind) ? createCoordinate(list.kind, list.pubkey) : getSharableEventAddress(list); const link = isSpecialListKind(list.kind) ? createCoordinate(list.kind, list.pubkey) : getSharableEventAddress(list);
// if there is a parent intersection observer, register this card // if there is a parent intersection observer, register this card
@@ -138,36 +136,43 @@ function ListCardRender({ list, ...props }: Omit<CardProps, "children"> & { list
return ( return (
<Card ref={ref} variant="outline" {...props}> <Card ref={ref} variant="outline" {...props}>
<CardHeader display="flex" alignItems="center" p="2" pb="0"> <CardHeader display="flex" gap="2" alignItems="center" p="2" pb="0">
<Heading size="md" isTruncated> <Heading size="md" isTruncated>
<Link as={RouterLink} to={`/lists/${link}`}> <Link as={RouterLink} to={`/lists/${link}`}>
{getListName(list)} {getListName(list)}
</Link> </Link>
</Heading> </Heading>
<Link as={RouterLink} to={`/lists/${link}`} ml="auto"> {!hideCreator && (
<Timestamp timestamp={list.created_at} /> <>
</Link> <Text>by</Text>
</CardHeader>
<CardBody py="0" px="2">
<ListCardContent list={list} />
</CardBody>
<CardFooter p="2" display="flex" alignItems="center" whiteSpace="pre" gap="2">
<Text>Created by:</Text>
<UserAvatarLink pubkey={list.pubkey} size="xs" /> <UserAvatarLink pubkey={list.pubkey} size="xs" />
<UserLink pubkey={list.pubkey} isTruncated fontWeight="bold" fontSize="lg" /> <UserLink pubkey={list.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
</>
)}
<ButtonGroup size="xs" variant="ghost" ml="auto"> <ButtonGroup size="xs" variant="ghost" ml="auto">
<ListFavoriteButton list={list} /> <ListFavoriteButton list={list} />
<ListMenu list={list} aria-label="list menu" /> <ListMenu list={list} aria-label="list menu" />
</ButtonGroup> </ButtonGroup>
</CardFooter> </CardHeader>
<CardBody p="2">
<ListCardContent list={list} />
</CardBody>
</Card> </Card>
); );
} }
function ListCard({ cord, list: maybeEvent }: { cord?: string; list?: NostrEvent }) { function ListCard({
cord,
list: maybeEvent,
hideCreator,
}: {
cord?: string;
list?: NostrEvent;
hideCreator?: boolean;
}) {
const event = maybeEvent ?? (cord ? useReplaceableEvent(cord as string) : undefined); const event = maybeEvent ?? (cord ? useReplaceableEvent(cord as string) : undefined);
if (!event) return null; if (!event) return null;
else return <ListCardRender list={event} />; else return <ListCardRender list={event} hideCreator={hideCreator} />;
} }
export default memo(ListCard); export default memo(ListCard);

View File

@@ -44,40 +44,44 @@ function ListsPage() {
</Button> </Button>
</Flex> </Flex>
<Heading size="md">Special lists</Heading> <Heading size="lg" mt="2">
<Divider /> Special lists
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> </Heading>
<ListCard cord={`${Kind.Contacts}:${account.pubkey}`} /> <SimpleGrid columns={{ base: 1, lg: 2 }} spacing="2">
<ListCard cord={`${MUTE_LIST_KIND}:${account.pubkey}`} /> <ListCard cord={`${Kind.Contacts}:${account.pubkey}`} hideCreator />
<ListCard cord={`${PIN_LIST_KIND}:${account.pubkey}`} /> <ListCard cord={`${MUTE_LIST_KIND}:${account.pubkey}`} hideCreator />
<ListCard cord={`${PIN_LIST_KIND}:${account.pubkey}`} hideCreator />
</SimpleGrid> </SimpleGrid>
{peopleLists.length > 0 && ( {peopleLists.length > 0 && (
<> <>
<Heading size="md">People lists</Heading> <Heading size="lg" mt="2">
<Divider /> People lists
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> </Heading>
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing="2">
{peopleLists.map((event) => ( {peopleLists.map((event) => (
<ListCard key={getEventUID(event)} list={event} /> <ListCard key={getEventUID(event)} list={event} hideCreator />
))} ))}
</SimpleGrid> </SimpleGrid>
</> </>
)} )}
{noteLists.length > 0 && ( {noteLists.length > 0 && (
<> <>
<Heading size="md">Bookmark lists</Heading> <Heading size="lg" mt="2">
<Divider /> Bookmark lists
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> </Heading>
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing="2">
{noteLists.map((event) => ( {noteLists.map((event) => (
<ListCard key={getEventUID(event)} list={event} /> <ListCard key={getEventUID(event)} list={event} hideCreator />
))} ))}
</SimpleGrid> </SimpleGrid>
</> </>
)} )}
{favoriteLists.length > 0 && ( {favoriteLists.length > 0 && (
<> <>
<Heading size="md">Favorite lists</Heading> <Heading size="lg" mt="2">
<Divider /> Favorite lists
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> </Heading>
<SimpleGrid columns={{ base: 1, lg: 2 }} spacing="2">
{favoriteLists.map((event) => ( {favoriteLists.map((event) => (
<ListCard key={getEventUID(event)} list={event} /> <ListCard key={getEventUID(event)} list={event} />
))} ))}