use browser extension to open tab in background (#1074)

This commit is contained in:
Athou
2023-06-10 22:16:02 +02:00
parent e2eeba90ef
commit 22e0f1f382
37 changed files with 717 additions and 325 deletions

View File

@@ -1,183 +1,192 @@
import { Trans } from "@lingui/macro"
import { Kbd, Table } from "@mantine/core"
import { Anchor, Box, Kbd, Stack, Table } from "@mantine/core"
import { Constants } from "app/constants"
export function KeyboardShortcutsHelp() {
return (
<Table striped highlightOnHover>
<tbody>
<tr>
<td>
<Trans>Refresh</Trans>
</td>
<td>
<Kbd>R</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open next entry</Trans>
</td>
<td>
<Kbd>J</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open previous entry</Trans>
</td>
<td>
<Kbd>K</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Set focus on next entry without opening it</Trans>
</td>
<td>
<Kbd>N</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Set focus on previous entry without opening it</Trans>
</td>
<td>
<Kbd>P</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Move the page down</Trans>
</td>
<td>
<Kbd>
<Trans>Space</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Move the page up</Trans>
</td>
<td>
<Kbd>
<Trans>Shift</Trans>
</Kbd>
<span> + </span>
<Kbd>
<Trans>Space</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open/close current entry</Trans>
</td>
<td>
<Kbd>O</Kbd>
<span>, </span>
<Kbd>
<Trans>Enter</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open current entry in a new tab</Trans>
</td>
<td>
<Kbd>V</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open current entry in a new tab in the background</Trans>
</td>
<td>
<Kbd>B</Kbd>
<span>, </span>
<Kbd>
<Trans>Middle click</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Toggle read status of current entry</Trans>
</td>
<td>
<Kbd>M</Kbd>
<span>, </span>
<Trans>Swipe header to the right</Trans>
</td>
</tr>
<tr>
<td>
<Trans>Mark all entries as read</Trans>
</td>
<td>
<Kbd>
<Trans>Shift</Trans>
</Kbd>
<span> + </span>
<Kbd>A</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Go to the All view</Trans>
</td>
<td>
<Kbd>G</Kbd>
<span> </span>
<Kbd>A</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Navigate to a subscription by entering its name</Trans>
</td>
<td>
<Kbd>
<Trans>Ctrl</Trans>
</Kbd>
<span> + </span>
<Kbd>K</Kbd>
<span>, </span>
<Kbd>G</Kbd>
<span> </span>
<Kbd>U</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show entry menu (desktop)</Trans>
</td>
<td>
<Kbd>
<Trans>Right click</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show entry menu (mobile)</Trans>
</td>
<td>
<Kbd>
<Trans>Long press</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show keyboard shortcut help</Trans>
</td>
<td>
<Kbd>?</Kbd>
</td>
</tr>
</tbody>
</Table>
<Stack spacing="xs">
<Table striped highlightOnHover>
<tbody>
<tr>
<td>
<Trans>Refresh</Trans>
</td>
<td>
<Kbd>R</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open next entry</Trans>
</td>
<td>
<Kbd>J</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open previous entry</Trans>
</td>
<td>
<Kbd>K</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Set focus on next entry without opening it</Trans>
</td>
<td>
<Kbd>N</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Set focus on previous entry without opening it</Trans>
</td>
<td>
<Kbd>P</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Move the page down</Trans>
</td>
<td>
<Kbd>
<Trans>Space</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Move the page up</Trans>
</td>
<td>
<Kbd>
<Trans>Shift</Trans>
</Kbd>
<span> + </span>
<Kbd>
<Trans>Space</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open/close current entry</Trans>
</td>
<td>
<Kbd>O</Kbd>
<span>, </span>
<Kbd>
<Trans>Enter</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open current entry in a new tab</Trans>
</td>
<td>
<Kbd>V</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Open current entry in a new tab in the background</Trans>
</td>
<td>
<Kbd>B</Kbd>
<span>*, </span>
<Kbd>
<Trans>Middle click</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Toggle read status of current entry</Trans>
</td>
<td>
<Kbd>M</Kbd>
<span>, </span>
<Trans>Swipe header to the right</Trans>
</td>
</tr>
<tr>
<td>
<Trans>Mark all entries as read</Trans>
</td>
<td>
<Kbd>
<Trans>Shift</Trans>
</Kbd>
<span> + </span>
<Kbd>A</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Go to the All view</Trans>
</td>
<td>
<Kbd>G</Kbd>
<span> </span>
<Kbd>A</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Navigate to a subscription by entering its name</Trans>
</td>
<td>
<Kbd>
<Trans>Ctrl</Trans>
</Kbd>
<span> + </span>
<Kbd>K</Kbd>
<span>, </span>
<Kbd>G</Kbd>
<span> </span>
<Kbd>U</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show entry menu (desktop)</Trans>
</td>
<td>
<Kbd>
<Trans>Right click</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show entry menu (mobile)</Trans>
</td>
<td>
<Kbd>
<Trans>Long press</Trans>
</Kbd>
</td>
</tr>
<tr>
<td>
<Trans>Show keyboard shortcut help</Trans>
</td>
<td>
<Kbd>?</Kbd>
</td>
</tr>
</tbody>
</Table>
<Box>
<span>* </span>
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
<Trans>Browser extension required</Trans>
</Anchor>
</Box>
</Stack>
)
}

View File

@@ -13,9 +13,9 @@ import {
} from "app/slices/entries"
import { redirectToRootCategory } from "app/slices/redirect"
import { useAppDispatch, useAppSelector } from "app/store"
import { openLinkInBackgroundTab } from "app/utils"
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
import { Loader } from "components/Loader"
import { useBrowserExtension } from "hooks/useBrowserExtension"
import { useMousetrap } from "hooks/useMousetrap"
import { useViewMode } from "hooks/useViewMode"
import { useEffect } from "react"
@@ -33,6 +33,7 @@ export function FeedEntries() {
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
const scrollingToEntry = useAppSelector(state => state.entries.scrollingToEntry)
const dispatch = useAppDispatch()
const { isBrowserExtensionInstalled, openLinkInBackgroundTab } = useBrowserExtension()
const selectedEntry = entries.find(e => e.id === selectedEntryId)
@@ -211,7 +212,7 @@ export function FeedEntries() {
window.open(selectedEntry.url, "_blank", "noreferrer")
})
useMousetrap("b", () => {
// simulate ctrl+click to open tab in background
if (!isBrowserExtensionInstalled) return
if (!selectedEntry) return
openLinkInBackgroundTab(selectedEntry.url)
})

View File

@@ -5,7 +5,8 @@ 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, truncate } from "app/utils"
import { truncate } from "app/utils"
import { useBrowserExtension } from "hooks/useBrowserExtension"
import { useEffect } from "react"
import { Item, Menu, Separator, useContextMenu } from "react-contexify"
import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb"
@@ -34,6 +35,7 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
const { classes, theme } = useStyles()
const sourceType = useAppSelector(state => state.entries.source.type)
const dispatch = useAppDispatch()
const { isBrowserExtensionInstalled, openLinkInBackgroundTab } = useBrowserExtension()
return (
<Menu id={menuId(props.entry)} theme={theme.colorScheme} animation={false} className={classes.menu}>
@@ -48,17 +50,19 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
<Trans>Open link in new tab</Trans>
</Group>
</Item>
<Item
onClick={() => {
openLinkInBackgroundTab(props.entry.url)
dispatch(markEntry({ entry: props.entry, read: true }))
}}
>
<Group>
<TbExternalLink size={iconSize} />
<Trans>Open link in new background tab</Trans>
</Group>
</Item>
{isBrowserExtensionInstalled && (
<Item
onClick={() => {
openLinkInBackgroundTab(props.entry.url)
dispatch(markEntry({ entry: props.entry, read: true }))
}}
>
<Group>
<TbExternalLink size={iconSize} />
<Trans>Open link in new background tab</Trans>
</Group>
</Item>
)}
<Separator />

View File

@@ -23,7 +23,7 @@ export function Header() {
const settings = useAppSelector(state => state.user.settings)
const profile = useAppSelector(state => state.user.profile)
const searchFromStore = useAppSelector(state => state.entries.search)
const { isBrowserExtension, openSettingsPage, openAppInNewTab } = useBrowserExtension()
const { isBrowserExtensionPopup, openSettingsPage, openAppInNewTab } = useBrowserExtension()
const dispatch = useAppDispatch()
const searchForm = useForm<{ search: string }>({
@@ -90,7 +90,7 @@ export function Header() {
<ProfileMenu control={<ActionButton icon={<TbUser size={iconSize} />} label={profile?.name} />} />
{isBrowserExtension && (
{isBrowserExtensionPopup && (
<>
<HeaderDivider />