fix context menu & shortcuts
This commit is contained in:
parent
b51f62895d
commit
f7a1fc9b24
|
@ -114,11 +114,22 @@ class Article extends React.Component<ArticleProps, ArticleState> {
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
this.props.offsetItem(input.key === "ArrowLeft" ? -1 : 1)
|
this.props.offsetItem(input.key === "ArrowLeft" ? -1 : 1)
|
||||||
break
|
break
|
||||||
case "l":
|
case "l": case "L":
|
||||||
this.toggleWebpage()
|
this.toggleWebpage()
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
this.props.shortcuts(this.props.item, input.key)
|
this.props.shortcuts(this.props.item, input.key)
|
||||||
|
const keyboardEvent = new KeyboardEvent("keydown", {
|
||||||
|
code: input.code,
|
||||||
|
key: input.key,
|
||||||
|
shiftKey: input.shift,
|
||||||
|
altKey: input.alt,
|
||||||
|
ctrlKey: input.control,
|
||||||
|
metaKey: input.meta,
|
||||||
|
repeat: input.isAutoRepeat,
|
||||||
|
bubbles: true
|
||||||
|
})
|
||||||
|
document.dispatchEvent(keyboardEvent)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,15 @@ import { ProgressIndicator } from "@fluentui/react"
|
||||||
import { getWindowBreakpoint } from "../scripts/utils"
|
import { getWindowBreakpoint } from "../scripts/utils"
|
||||||
|
|
||||||
type NavProps = {
|
type NavProps = {
|
||||||
state: AppState,
|
state: AppState
|
||||||
itemShown: boolean,
|
itemShown: boolean
|
||||||
fetch: () => void,
|
menu: () => void
|
||||||
menu: () => void,
|
search: () => void
|
||||||
logs: () => void,
|
|
||||||
views: () => void,
|
|
||||||
settings: () => void,
|
|
||||||
markAllRead: () => void
|
markAllRead: () => void
|
||||||
|
fetch: () => void
|
||||||
|
logs: () => void
|
||||||
|
views: () => void
|
||||||
|
settings: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type NavState = {
|
type NavState = {
|
||||||
|
@ -44,6 +45,9 @@ class Nav extends React.Component<NavProps, NavState> {
|
||||||
case "F1":
|
case "F1":
|
||||||
this.props.menu()
|
this.props.menu()
|
||||||
break
|
break
|
||||||
|
case "F2":
|
||||||
|
this.props.search()
|
||||||
|
break
|
||||||
case "F5":
|
case "F5":
|
||||||
this.fetch()
|
this.fetch()
|
||||||
break
|
break
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ArticleSearch from "./utils/article-search"
|
||||||
|
|
||||||
type PageProps = {
|
type PageProps = {
|
||||||
menuOn: boolean
|
menuOn: boolean
|
||||||
|
contextOn: boolean
|
||||||
settingsOn: boolean
|
settingsOn: boolean
|
||||||
feeds: string[]
|
feeds: string[]
|
||||||
itemId: string
|
itemId: string
|
||||||
|
@ -35,6 +36,7 @@ class Page extends React.Component<PageProps> {
|
||||||
</div>}
|
</div>}
|
||||||
{this.props.itemId && (
|
{this.props.itemId && (
|
||||||
<FocusTrapZone
|
<FocusTrapZone
|
||||||
|
disabled={this.props.contextOn}
|
||||||
ignoreExternalFocusing={true}
|
ignoreExternalFocusing={true}
|
||||||
isClickableOutsideFocusTrap={true}
|
isClickableOutsideFocusTrap={true}
|
||||||
className="article-container"
|
className="article-container"
|
||||||
|
|
|
@ -41,6 +41,7 @@ class ArticleSearch extends React.Component<SearchProps, SearchState> {
|
||||||
|
|
||||||
componentDidUpdate(prevProps: SearchProps) {
|
componentDidUpdate(prevProps: SearchProps) {
|
||||||
if (this.props.searchOn && !prevProps.searchOn) {
|
if (this.props.searchOn && !prevProps.searchOn) {
|
||||||
|
this.setState({ query: this.props.initQuery })
|
||||||
this.inputRef.current.focus()
|
this.inputRef.current.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { createSelector } from "reselect"
|
||||||
import { RootState } from "../scripts/reducer"
|
import { RootState } from "../scripts/reducer"
|
||||||
import { fetchItems, markAllRead } from "../scripts/models/item"
|
import { fetchItems, markAllRead } from "../scripts/models/item"
|
||||||
import { toggleMenu, toggleLogMenu, toggleSettings, openViewMenu } from "../scripts/models/app"
|
import { toggleMenu, toggleLogMenu, toggleSettings, openViewMenu } from "../scripts/models/app"
|
||||||
import { ViewType } from "../scripts/models/page"
|
import { ViewType, toggleSearch } from "../scripts/models/page"
|
||||||
import Nav from "../components/nav"
|
import Nav from "../components/nav"
|
||||||
|
|
||||||
const getState = (state: RootState) => state.app
|
const getState = (state: RootState) => state.app
|
||||||
|
@ -25,6 +25,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
logs: () => dispatch(toggleLogMenu()),
|
logs: () => dispatch(toggleLogMenu()),
|
||||||
views: () => dispatch(openViewMenu()),
|
views: () => dispatch(openViewMenu()),
|
||||||
settings: () => dispatch(toggleSettings()),
|
settings: () => dispatch(toggleSettings()),
|
||||||
|
search: () => dispatch(toggleSearch()),
|
||||||
markAllRead: () => {
|
markAllRead: () => {
|
||||||
remote.dialog.showMessageBox(remote.getCurrentWindow(), {
|
remote.dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||||
title: intl.get("nav.markAllRead"),
|
title: intl.get("nav.markAllRead"),
|
||||||
|
|
|
@ -4,17 +4,20 @@ import { RootState } from "../scripts/reducer"
|
||||||
import Page from "../components/page"
|
import Page from "../components/page"
|
||||||
import { AppDispatch } from "../scripts/utils"
|
import { AppDispatch } from "../scripts/utils"
|
||||||
import { dismissItem, showOffsetItem } from "../scripts/models/page"
|
import { dismissItem, showOffsetItem } from "../scripts/models/page"
|
||||||
|
import { ContextMenuType } from "../scripts/models/app"
|
||||||
|
|
||||||
const getPage = (state: RootState) => state.page
|
const getPage = (state: RootState) => state.page
|
||||||
const getSettings = (state: RootState) => state.app.settings.display
|
const getSettings = (state: RootState) => state.app.settings.display
|
||||||
const getMenu = (state: RootState) => state.app.menu
|
const getMenu = (state: RootState) => state.app.menu
|
||||||
|
const getContext = (state: RootState) => state.app.contextMenu.type != ContextMenuType.Hidden
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
[getPage, getSettings, getMenu],
|
[getPage, getSettings, getMenu, getContext],
|
||||||
(page, settingsOn, menuOn) => ({
|
(page, settingsOn, menuOn, contextOn) => ({
|
||||||
feeds: [page.feedId],
|
feeds: [page.feedId],
|
||||||
settingsOn: settingsOn,
|
settingsOn: settingsOn,
|
||||||
menuOn: menuOn,
|
menuOn: menuOn,
|
||||||
|
contextOn: contextOn,
|
||||||
itemId: page.itemId,
|
itemId: page.itemId,
|
||||||
viewType: page.viewType
|
viewType: page.viewType
|
||||||
})
|
})
|
||||||
|
|
|
@ -66,8 +66,12 @@ if (process.platform === 'darwin') {
|
||||||
{
|
{
|
||||||
label: "Edit",
|
label: "Edit",
|
||||||
submenu: [
|
submenu: [
|
||||||
|
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
|
||||||
|
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
|
||||||
|
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
|
||||||
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
|
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
|
||||||
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
|
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
|
||||||
|
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -266,10 +266,7 @@ export function appReducer(
|
||||||
}
|
}
|
||||||
case INIT_FEEDS:
|
case INIT_FEEDS:
|
||||||
switch (action.status) {
|
switch (action.status) {
|
||||||
case ActionStatus.Request: return {
|
case ActionStatus.Request: return state
|
||||||
...state,
|
|
||||||
feedInit: false
|
|
||||||
}
|
|
||||||
default: return {
|
default: return {
|
||||||
...state,
|
...state,
|
||||||
feedInit: true
|
feedInit: true
|
||||||
|
|
|
@ -266,17 +266,18 @@ export function toggleHidden(item: RSSItem): AppThunk {
|
||||||
export function itemShortcuts(item: RSSItem, key: string): AppThunk {
|
export function itemShortcuts(item: RSSItem, key: string): AppThunk {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "m":
|
case "m": case "M":
|
||||||
if (item.hasRead) dispatch(markUnread(item))
|
if (item.hasRead) dispatch(markUnread(item))
|
||||||
else dispatch(markRead(item))
|
else dispatch(markRead(item))
|
||||||
break
|
break
|
||||||
case "b":
|
case "b": case "B":
|
||||||
|
if (!item.hasRead) dispatch(markRead(item))
|
||||||
openExternal(item.link)
|
openExternal(item.link)
|
||||||
break
|
break
|
||||||
case "s":
|
case "s": case "S":
|
||||||
dispatch(toggleStarred(item))
|
dispatch(toggleStarred(item))
|
||||||
break
|
break
|
||||||
case "h":
|
case "h": case "H":
|
||||||
dispatch(toggleHidden(item))
|
dispatch(toggleHidden(item))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ALL, SOURCE, loadMore, FeedFilter, FilterType, initFeeds } from "./feed"
|
import { ALL, SOURCE, loadMore, FeedFilter, FilterType, initFeeds, FeedActionTypes, INIT_FEED } from "./feed"
|
||||||
import { getWindowBreakpoint, AppThunk } from "../utils"
|
import { getWindowBreakpoint, AppThunk, ActionStatus } from "../utils"
|
||||||
import { getDefaultView } from "../settings"
|
import { getDefaultView } from "../settings"
|
||||||
import { RSSItem, markRead } from "./item"
|
import { RSSItem, markRead } from "./item"
|
||||||
import { SourceActionTypes, DELETE_SOURCE } from "./source"
|
import { SourceActionTypes, DELETE_SOURCE } from "./source"
|
||||||
|
@ -104,7 +104,7 @@ export const toggleSearch = (): AppThunk => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
let state = getState()
|
let state = getState()
|
||||||
dispatch(({ type: TOGGLE_SEARCH }))
|
dispatch(({ type: TOGGLE_SEARCH }))
|
||||||
if (!getWindowBreakpoint()) {
|
if (!getWindowBreakpoint() && state.app.menu) {
|
||||||
dispatch(toggleMenu())
|
dispatch(toggleMenu())
|
||||||
}
|
}
|
||||||
if (state.page.searchOn) {
|
if (state.page.searchOn) {
|
||||||
|
@ -214,7 +214,7 @@ export class PageState {
|
||||||
|
|
||||||
export function pageReducer(
|
export function pageReducer(
|
||||||
state = new PageState(),
|
state = new PageState(),
|
||||||
action: PageActionTypes | SourceActionTypes
|
action: PageActionTypes | SourceActionTypes | FeedActionTypes
|
||||||
): PageState {
|
): PageState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SELECT_PAGE:
|
case SELECT_PAGE:
|
||||||
|
@ -244,6 +244,14 @@ export function pageReducer(
|
||||||
...state,
|
...state,
|
||||||
itemId: action.item._id
|
itemId: action.item._id
|
||||||
}
|
}
|
||||||
|
case INIT_FEED: switch (action.status) {
|
||||||
|
case ActionStatus.Success: return {
|
||||||
|
...state,
|
||||||
|
itemId: (action.feed._id === state.feedId && action.items.filter(i => i._id === state.itemId).length === 0)
|
||||||
|
? null : state.itemId
|
||||||
|
}
|
||||||
|
default: return state
|
||||||
|
}
|
||||||
case DELETE_SOURCE:
|
case DELETE_SOURCE:
|
||||||
case DISMISS_ITEM: return {
|
case DISMISS_ITEM: return {
|
||||||
...state,
|
...state,
|
||||||
|
|
Loading…
Reference in New Issue