diff --git a/.changeset/nice-hornets-own.md b/.changeset/nice-hornets-own.md new file mode 100644 index 000000000..9cb33d3d0 --- /dev/null +++ b/.changeset/nice-hornets-own.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Make notes clickable diff --git a/src/components/embed-event/event-types/embedded-note.tsx b/src/components/embed-event/event-types/embedded-note.tsx index 9267c2b8f..bc98a895f 100644 --- a/src/components/embed-event/event-types/embedded-note.tsx +++ b/src/components/embed-event/event-types/embedded-note.tsx @@ -15,13 +15,7 @@ import Timestamp from "../../timestamp"; import { getSharableEventAddress } from "../../../helpers/nip19"; import { InlineNoteContent } from "../../note/inline-note-content"; import { useNavigateInDrawer } from "../../../providers/drawer-sub-view-provider"; -import styled from "@emotion/styled"; - -const HoverLinkOverlay = styled(LinkOverlay)` - &:hover:before { - background-color: var(--chakra-colors-card-hover-overlay); - } -`; +import HoverLinkOverlay from "../../hover-link-overlay"; export default function EmbeddedNote({ event, ...props }: Omit & { event: NostrEvent }) { const { showSignatureVerification } = useSubject(appSettings); diff --git a/src/components/embed-types/image.tsx b/src/components/embed-types/image.tsx index 69ee6220c..16bd0ac86 100644 --- a/src/components/embed-types/image.tsx +++ b/src/components/embed-types/image.tsx @@ -8,7 +8,7 @@ import { useRef, useState, } from "react"; -import { Image, ImageProps } from "@chakra-ui/react"; +import { Image, ImageProps, Link, LinkProps } from "@chakra-ui/react"; import appSettings from "../../services/settings/app-settings"; import { useTrusted } from "../../providers/trust"; @@ -61,23 +61,69 @@ export const TrustImage = forwardRef((props, else return ; }); -export type EmbeddedImageProps = TrustImageProps & { +export type EmbeddedImageProps = Omit & { + src?: string; event?: NostrEvent; + imageProps?: TrustImageProps; }; -export const EmbeddedImage = forwardRef(({ src, event, ...props }, ref) => { - const thumbnail = appSettings.value.imageProxy - ? new URL(`/256,fit/${src}`, appSettings.value.imageProxy).toString() - : src; - - ref = ref || useRef(null); - const { show } = useRegisterSlide( - ref as MutableRefObject, - src ? { type: "image", src, event } : undefined, - ); +function useImageThumbnail(src?: string) { + return appSettings.value.imageProxy ? new URL(`/256,fit/${src}`, appSettings.value.imageProxy).toString() : src; +} - return ; -}); +export const EmbeddedImage = forwardRef( + ({ src, event, imageProps, ...props }, ref) => { + const thumbnail = useImageThumbnail(src); + + ref = ref || useRef(null); + const { show } = useRegisterSlide( + ref as MutableRefObject, + src ? { type: "image", src, event } : undefined, + ); + const handleClick = useCallback>( + (e) => { + !e.isPropagationStopped() && show(); + e.preventDefault(); + }, + [show], + ); + + // NOTE: the parent
has display=block and and has inline-block + // this is so that the element can act like a block without being full width + return ( +
+ + + +
+ ); + }, +); + +export const GalleryImage = forwardRef( + ({ src, event, imageProps, ...props }, ref) => { + const thumbnail = useImageThumbnail(src); + + ref = ref || useRef(null); + const { show } = useRegisterSlide( + ref as MutableRefObject, + src ? { type: "image", src, event } : undefined, + ); + const handleClick = useCallback>( + (e) => { + !e.isPropagationStopped() && show(); + e.preventDefault(); + }, + [show], + ); + + return ( + + + + ); + }, +); export function ImageGallery({ images, event }: { images: string[]; event?: NostrEvent }) { const photos = useMemo(() => { @@ -93,7 +139,9 @@ export function ImageGallery({ images, event }: { images: string[]; event?: Nost } + renderPhoto={({ photo, imageProps, wrapperStyle }) => ( + + )} targetRowHeight={(containerWidth) => containerWidth / rowMultiplier} /> ); @@ -165,5 +213,5 @@ export function embedImageGallery(content: EmbedableContent, event?: NostrEvent) export function renderImageUrl(match: URL) { if (!isImageURL(match)) return null; - return ; + return ; } diff --git a/src/components/hover-link-overlay.tsx b/src/components/hover-link-overlay.tsx new file mode 100644 index 000000000..6d961436e --- /dev/null +++ b/src/components/hover-link-overlay.tsx @@ -0,0 +1,10 @@ +import { LinkOverlay } from "@chakra-ui/react"; +import styled from "@emotion/styled"; + +const HoverLinkOverlay = styled(LinkOverlay)` + &:hover:before { + background-color: var(--chakra-colors-card-hover-overlay); + } +`; + +export default HoverLinkOverlay; diff --git a/src/components/note/index.tsx b/src/components/note/index.tsx index f96974534..0659c77c1 100644 --- a/src/components/note/index.tsx +++ b/src/components/note/index.tsx @@ -10,6 +10,7 @@ import { Flex, IconButton, Link, + LinkBox, Text, useDisclosure, } from "@chakra-ui/react"; @@ -44,14 +45,16 @@ import { getSharableEventAddress } from "../../helpers/nip19"; import { COMMUNITY_DEFINITION_KIND, getCommunityName } from "../../helpers/nostr/communities"; import useReplaceableEvent from "../../hooks/use-replaceable-event"; import { useBreakpointValue } from "../../providers/breakpoint-provider"; +import HoverLinkOverlay from "../hover-link-overlay"; +import { nip19 } from "nostr-tools"; export type NoteProps = Omit & { event: NostrEvent; variant?: CardProps["variant"]; showReplyButton?: boolean; hideDrawerButton?: boolean; - hideThreadLink?: boolean; registerIntersectionEntity?: boolean; + clickable?: boolean; }; export const Note = React.memo( ({ @@ -59,8 +62,8 @@ export const Note = React.memo( variant = "outline", showReplyButton, hideDrawerButton, - hideThreadLink, registerIntersectionEntity = true, + clickable = true, ...props }: NoteProps) => { const account = useCurrentAccount(); @@ -87,29 +90,26 @@ export const Note = React.memo( + {clickable && } - {!hideThreadLink && ( - - thread - - )} {showSignatureVerification && } {!hideDrawerButton && ( )} - + - + {community && ( diff --git a/src/components/timeline-page/media-timeline/index.tsx b/src/components/timeline-page/media-timeline/index.tsx index c908b0fdc..29ba73042 100644 --- a/src/components/timeline-page/media-timeline/index.tsx +++ b/src/components/timeline-page/media-timeline/index.tsx @@ -7,7 +7,7 @@ import useSubject from "../../../hooks/use-subject"; import { getMatchLink } from "../../../helpers/regexp"; import { LightboxProvider } from "../../lightbox-provider"; import { isImageURL } from "../../../helpers/url"; -import { EmbeddedImage, EmbeddedImageProps } from "../../embed-types"; +import { EmbeddedImage, EmbeddedImageProps, GalleryImage } from "../../embed-types"; import { TrustProvider } from "../../../providers/trust"; import PhotoGallery, { PhotoWithoutSize } from "../../photo-gallery"; import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer"; @@ -15,11 +15,11 @@ import { NostrEvent } from "../../../types/nostr-event"; import { getEventUID } from "../../../helpers/nostr/events"; import { useBreakpointValue } from "../../../providers/breakpoint-provider"; -function GalleryImage({ event, ...props }: EmbeddedImageProps & { event: NostrEvent }) { +function CustomGalleryImage({ event, ...props }: EmbeddedImageProps & { event: NostrEvent }) { const ref = useRef(null); useRegisterIntersectionEntity(ref, getEventUID(event)); - return ; + return ; } type PhotoWithEvent = PhotoWithoutSize & { event: NostrEvent }; @@ -30,7 +30,9 @@ function ImageGallery({ images }: { images: PhotoWithEvent[] }) { layout="masonry" photos={images} - renderPhoto={({ photo, imageProps }) => } + renderPhoto={({ photo, imageProps }) => ( + + )} columns={rowMultiplier} /> ); diff --git a/src/theme/index.ts b/src/theme/index.ts index 2bba8c9aa..868d5d103 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -33,8 +33,8 @@ export default function buildTheme( semanticTokens: { colors: { "card-hover-overlay": { - _light: "blackAlpha.100", - _dark: "whiteAlpha.100", + _light: "blackAlpha.50", + _dark: "whiteAlpha.50", }, }, }, diff --git a/src/views/note/components/thread-post.tsx b/src/views/note/components/thread-post.tsx index 4e4f8373f..0b67484ff 100644 --- a/src/views/note/components/thread-post.tsx +++ b/src/views/note/components/thread-post.tsx @@ -47,8 +47,8 @@ export const ThreadPost = ({ post, initShowReplies, focusId }: ThreadItemProps) )} diff --git a/src/views/note/index.tsx b/src/views/note/index.tsx index 5749c6dc0..d6627aabb 100644 --- a/src/views/note/index.tsx +++ b/src/views/note/index.tsx @@ -53,13 +53,13 @@ export default function NoteView() { pageContent = ( <> {parentPosts.map((parent) => ( - + ))} ); } else if (events[focusId]) { - pageContent = ; + pageContent = ; } return {pageContent};