-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
950 additions
and
227 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"nostrudel": minor | ||
--- | ||
|
||
Add support for NIP-22 comments on media posts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"nostrudel": minor | ||
--- | ||
|
||
Add support for Olas media posts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Box, Button, ButtonGroup, Card, CardBody, CardFooter, CardHeader } from "@chakra-ui/react"; | ||
import { NostrEvent } from "nostr-tools"; | ||
import { Link as RouterLink } from "react-router-dom"; | ||
|
||
import UserAvatarLink from "../user/user-avatar-link"; | ||
import UserLink from "../user/user-link"; | ||
import UserDnsIdentity from "../user/user-dns-identity"; | ||
import DebugEventButton from "../debug-modal/debug-event-button"; | ||
import { TrustProvider } from "../../providers/local/trust-provider"; | ||
import EventReactionButtons from "../event-reactions/event-reactions"; | ||
import AddReactionButton from "../note/timeline-note/components/add-reaction-button"; | ||
import RepostButton from "../note/timeline-note/components/repost-button"; | ||
import QuoteEventButton from "../note/quote-event-button"; | ||
import MediaPostSlides from "./media-slides"; | ||
import MediaPostContents from "./media-post-content"; | ||
import { getSharableEventAddress } from "../../services/event-relay-hint"; | ||
import { ThreadIcon } from "../icons"; | ||
import EventZapIconButton from "../zap/event-zap-icon-button"; | ||
import Timestamp from "../timestamp"; | ||
|
||
export default function MediaPost({ post }: { post: NostrEvent }) { | ||
const nevent = getSharableEventAddress(post); | ||
|
||
return ( | ||
<TrustProvider event={post}> | ||
<Card maxW="2xl" mx="auto"> | ||
<CardHeader display="flex" alignItems="center" gap="2" p="2"> | ||
<UserAvatarLink pubkey={post.pubkey} /> | ||
<Box> | ||
<UserLink pubkey={post.pubkey} fontWeight="bold" /> <Timestamp timestamp={post.created_at} /> | ||
<br /> | ||
<UserDnsIdentity pubkey={post.pubkey} /> | ||
</Box> | ||
|
||
<Button as={RouterLink} to={`/media/${nevent}`} leftIcon={<ThreadIcon boxSize={5} />} ml="auto"> | ||
Comments | ||
</Button> | ||
</CardHeader> | ||
|
||
<CardBody p="0" position="relative" display="flex" flexDirection="column" gap="2" minH="md"> | ||
<MediaPostSlides post={post} /> | ||
|
||
{post.content.length > 0 && <MediaPostContents post={post} px="2" />} | ||
</CardBody> | ||
|
||
<CardFooter p="2" display="flex" gap="2"> | ||
<ButtonGroup size="sm" variant="ghost"> | ||
<EventZapIconButton event={post} aria-label="Zap post" /> | ||
<AddReactionButton event={post} /> | ||
<EventReactionButtons event={post} max={4} /> | ||
</ButtonGroup> | ||
|
||
<ButtonGroup size="sm" variant="ghost" ml="auto"> | ||
<RepostButton event={post} /> | ||
<QuoteEventButton event={post} /> | ||
<DebugEventButton event={post} variant="ghost" ml="auto" size="sm" alignSelf="flex-start" /> | ||
</ButtonGroup> | ||
</CardFooter> | ||
</Card> | ||
</TrustProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { Box, BoxProps } from "@chakra-ui/react"; | ||
import { NostrEvent } from "nostr-tools"; | ||
import { useRenderedContent } from "applesauce-react/hooks"; | ||
import { emojis, nostrMentions, links, hashtags } from "applesauce-content/text"; | ||
|
||
import { components } from "../content"; | ||
import { renderGenericUrl } from "../content/links"; | ||
import { nipDefinitions } from "../content/transform/nip-notation"; | ||
|
||
const transformers = [links, nostrMentions, emojis, hashtags, nipDefinitions]; | ||
|
||
const linkRenderers = [renderGenericUrl]; | ||
|
||
const MediaPostContentSymbol = Symbol.for("media-post-content"); | ||
|
||
export default function MediaPostContents({ post, ...props }: { post: NostrEvent } & Omit<BoxProps, "children">) { | ||
const content = useRenderedContent(post, components, { | ||
linkRenderers, | ||
transformers, | ||
cacheKey: MediaPostContentSymbol, | ||
}); | ||
|
||
return ( | ||
<Box whiteSpace="pre-wrap" dir="auto" {...props}> | ||
{content} | ||
</Box> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import { Box, Flex, FlexProps, IconButton, Spacer } from "@chakra-ui/react"; | ||
import { NostrEvent } from "nostr-tools"; | ||
import { getMediaAttachments, MediaAttachment } from "applesauce-core/helpers/media-attachment"; | ||
import { Carousel, useCarousel } from "nuka-carousel"; | ||
import styled from "@emotion/styled"; | ||
|
||
import { TrustImage, TrustVideo } from "../content/links"; | ||
import { isImageURL, isVideoURL } from "applesauce-core/helpers"; | ||
import { ChevronLeftIcon, ChevronRightIcon } from "../icons"; | ||
import ZapBubbles from "../note/timeline-note/components/zap-bubbles"; | ||
|
||
function CustomArrows() { | ||
const { currentPage, totalPages, wrapMode, goBack, goForward } = useCarousel(); | ||
|
||
const allowWrap = wrapMode === "wrap"; | ||
const enablePrevNavButton = allowWrap || currentPage > 0; | ||
const enableNextNavButton = allowWrap || currentPage < totalPages - 1; | ||
|
||
return ( | ||
<Flex justifyContent="space-between" position="absolute" top="50%" right="0" left="0"> | ||
<IconButton | ||
icon={<ChevronLeftIcon boxSize={8} />} | ||
onClick={goBack} | ||
aria-label="previous image" | ||
variant="ghost" | ||
h="24" | ||
w="12" | ||
isDisabled={!enablePrevNavButton} | ||
> | ||
PREV | ||
</IconButton> | ||
<IconButton | ||
icon={<ChevronRightIcon boxSize={8} />} | ||
onClick={goForward} | ||
aria-label="next image" | ||
variant="ghost" | ||
h="24" | ||
w="12" | ||
isDisabled={!enableNextNavButton} | ||
> | ||
NEXT | ||
</IconButton> | ||
</Flex> | ||
); | ||
} | ||
|
||
function cls(...classes: string[]) { | ||
return classes.filter(Boolean).join(" "); | ||
} | ||
function PageIndicators() { | ||
const { totalPages, currentPage, goToPage } = useCarousel(); | ||
|
||
const className = (index: number) => | ||
cls("nuka-page-indicator", currentPage === index ? "nuka-page-indicator-active" : ""); | ||
|
||
return ( | ||
<div className="nuka-page-container" data-testid="pageIndicatorContainer"> | ||
{[...Array(totalPages)].map((_, index) => ( | ||
<button key={index} onClick={() => goToPage(index)} className={className(index)}> | ||
<span className="nuka-hidden">{index + 1}</span> | ||
</button> | ||
))} | ||
</div> | ||
); | ||
} | ||
|
||
function MediaAttachmentSlide({ media }: { media: MediaAttachment }) { | ||
if (media.type?.startsWith("video/") || isVideoURL(media.url)) { | ||
return <TrustVideo src={media.url} poster={media.image} aria-description={media.alt} />; | ||
} else if (media.type?.startsWith("image/") || isImageURL(media.url)) { | ||
return <TrustImage src={media.url} alt={media.alt} maxH="full" />; | ||
} | ||
|
||
return ( | ||
<Box aspectRatio={1} minW="lg"> | ||
Unknown media type {media.type ?? "Unknown"} | ||
</Box> | ||
); | ||
} | ||
|
||
const CustomCarousel = styled(Carousel)` | ||
& { | ||
height: 100%; | ||
overflow: hidden; | ||
} | ||
.nuka-slide-container { | ||
height: 100%; | ||
overflow: hidden; | ||
} | ||
.nuka-overflow { | ||
overflow-x: scroll; | ||
overflow-y: hidden; | ||
height: 100%; | ||
} | ||
.nuka-wrapper { | ||
height: 100%; | ||
} | ||
`; | ||
|
||
export default function MediaPostSlides({ | ||
post, | ||
showZaps = true, | ||
...props | ||
}: { post: NostrEvent; showZaps?: boolean } & Omit<FlexProps, "children">) { | ||
const attachments = getMediaAttachments(post); | ||
|
||
if (attachments.length === 1) | ||
return ( | ||
<Flex gap="2" direction="column" {...props}> | ||
<Flex justifyContent="center" overflow="hidden" flexGrow={1} alignItems="flex-start"> | ||
<MediaAttachmentSlide media={attachments[0]} /> | ||
</Flex> | ||
{showZaps && <ZapBubbles event={post} px="2" />} | ||
</Flex> | ||
); | ||
|
||
return ( | ||
<Flex gap="2" direction="column" {...props}> | ||
<CustomCarousel | ||
scrollDistance="screen" | ||
showDots | ||
arrows={<CustomArrows />} | ||
showArrows | ||
dots={ | ||
<Flex gap="2" justifyContent="space-between" alignItems="center" px="2"> | ||
{showZaps && <ZapBubbles event={post} />} | ||
<Spacer /> | ||
<PageIndicators /> | ||
</Flex> | ||
} | ||
> | ||
{attachments.map((media) => ( | ||
<MediaAttachmentSlide key={media.sha256 || media.url} media={media} /> | ||
))} | ||
</CustomCarousel> | ||
</Flex> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.