import { Trans } from "@lingui/macro" import { createStyles, Group } from "@mantine/core" import { Constants } from "app/constants" import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries" import { redirectToFeed } from "app/slices/redirect" import { useAppDispatch, useAppSelector } from "app/store" import { Entry } from "app/types" import { openLinkInBackgroundTab } from "app/utils" import { throttle, truncate } from "lodash" import { useEffect } from "react" import { Item, Menu, Separator, useContextMenu } from "react-contexify" import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb" interface FeedEntryContextMenuProps { entry: Entry } const iconSize = 16 const useStyles = createStyles(theme => ({ menu: { // apply mantine theme from MenuItem.styles.ts fontSize: theme.fontSizes.sm, "--contexify-item-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, "--contexify-activeItem-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, "--contexify-activeItem-bgColor": `${ theme.colorScheme === "dark" ? theme.fn.rgba(theme.colors.dark[3], 0.35) : theme.colors.gray[1] } !important`, }, })) const menuId = (entry: Entry) => entry.id export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) { const { classes, theme } = useStyles() const sourceType = useAppSelector(state => state.entries.source.type) const dispatch = useAppDispatch() return ( { window.open(props.entry.url, "_blank", "noreferrer") dispatch(markEntry({ entry: props.entry, read: true })) }} > Open link in new tab { openLinkInBackgroundTab(props.entry.url) dispatch(markEntry({ entry: props.entry, read: true })) }} > Open link in new background tab dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}> {props.entry.starred ? : } {props.entry.starred ? Unstar : Star} dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}> {props.entry.read ? : } {props.entry.read ? Keep unread : Mark as read} dispatch(markEntriesUpToEntry(props.entry))}> Mark as read up to here {sourceType === "category" && ( <> { dispatch(redirectToFeed(props.entry.feedId)) }} > Go to {truncate(props.entry.feedName)} )} ) } export function useFeedEntryContextMenu(entry: Entry) { const contextMenu = useContextMenu({ id: menuId(entry), }) const onContextMenu = (event: React.MouseEvent) => { event.preventDefault() contextMenu.show({ event, }) } // close context menu on scroll useEffect(() => { const scrollArea = document.getElementById(Constants.dom.mainScrollAreaId) const listener = () => contextMenu.hideAll() const throttledListener = throttle(listener, 100) scrollArea?.addEventListener("scroll", throttledListener) return () => scrollArea?.removeEventListener("scroll", throttledListener) }, [contextMenu]) return { onContextMenu } }