mirror of
https://github.com/yang991178/fluent-reader.git
synced 2026-09-18 13:41:51 +00:00
refactor: convert Feed to functional component
This commit is contained in:
@@ -181,6 +181,8 @@ declare global {
|
||||
utils: typeof utilsBridge
|
||||
fontList: Array<string>
|
||||
}
|
||||
var utils: typeof utilsBridge
|
||||
var fontList: Array<string>
|
||||
}
|
||||
|
||||
export default utilsBridge
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from "react"
|
||||
import { useState, useEffect, useCallback, useRef } from "react"
|
||||
import intl from "react-intl-universal"
|
||||
import { FeedProps } from "./feed"
|
||||
import DefaultCard from "../cards/default-card"
|
||||
@@ -6,64 +7,63 @@ import { PrimaryButton, FocusZone } from "office-ui-fabric-react"
|
||||
import { RSSItem } from "../../scripts/models/item"
|
||||
import { List, AnimationClassNames } from "@fluentui/react"
|
||||
|
||||
class CardsFeed extends React.Component<FeedProps> {
|
||||
observer: ResizeObserver
|
||||
state = { width: window.innerWidth, height: window.innerHeight }
|
||||
const CardsFeed: React.FC<FeedProps> = props => {
|
||||
const [width, setWidth] = useState(window.innerWidth)
|
||||
const [height, setHeight] = useState(window.innerHeight)
|
||||
const observerRef = useRef<ResizeObserver>(null)
|
||||
|
||||
updateWindowSize = (entries: ResizeObserverEntry[]) => {
|
||||
if (entries) {
|
||||
this.setState({
|
||||
width: entries[0].contentRect.width - 40,
|
||||
height: window.innerHeight,
|
||||
})
|
||||
useEffect(() => {
|
||||
setWidth(document.querySelector(".main").clientWidth - 40)
|
||||
observerRef.current = new ResizeObserver(
|
||||
(entries: ResizeObserverEntry[]) => {
|
||||
if (entries) {
|
||||
setWidth(entries[0].contentRect.width - 40)
|
||||
setHeight(window.innerHeight)
|
||||
}
|
||||
}
|
||||
)
|
||||
observerRef.current.observe(document.querySelector(".main"))
|
||||
return () => {
|
||||
observerRef.current.disconnect()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
width: document.querySelector(".main").clientWidth - 40,
|
||||
})
|
||||
this.observer = new ResizeObserver(this.updateWindowSize)
|
||||
this.observer.observe(document.querySelector(".main"))
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.observer.disconnect()
|
||||
}
|
||||
|
||||
getItemCountForPage = () => {
|
||||
let elemPerRow = Math.floor(this.state.width / 280)
|
||||
let rows = Math.ceil(this.state.height / 304)
|
||||
const getItemCountForPage = useCallback(() => {
|
||||
let elemPerRow = Math.floor(width / 280)
|
||||
let rows = Math.ceil(height / 304)
|
||||
return elemPerRow * rows
|
||||
}
|
||||
getPageHeight = () => {
|
||||
return this.state.height + (304 - (this.state.height % 304))
|
||||
}
|
||||
}, [width, height])
|
||||
|
||||
flexFixItems = () => {
|
||||
let elemPerRow = Math.floor(this.state.width / 280)
|
||||
let elemLastRow = this.props.items.length % elemPerRow
|
||||
let items = [...this.props.items]
|
||||
const getPageHeight = useCallback(() => {
|
||||
return height + (304 - (height % 304))
|
||||
}, [height])
|
||||
|
||||
const flexFixItems = () => {
|
||||
let elemPerRow = Math.floor(width / 280)
|
||||
let elemLastRow = props.items.length % elemPerRow
|
||||
let items = [...props.items]
|
||||
for (let i = 0; i < elemPerRow - elemLastRow; i += 1) items.push(null)
|
||||
return items
|
||||
}
|
||||
onRenderItem = (item: RSSItem, index: number) =>
|
||||
|
||||
const onRenderItem = (item: RSSItem, index: number) =>
|
||||
item ? (
|
||||
<DefaultCard
|
||||
feedId={this.props.feed._id}
|
||||
feedId={props.feed._id}
|
||||
key={item._id}
|
||||
item={item}
|
||||
source={this.props.sourceMap[item.source]}
|
||||
filter={this.props.filter}
|
||||
shortcuts={this.props.shortcuts}
|
||||
markRead={this.props.markRead}
|
||||
contextMenu={this.props.contextMenu}
|
||||
showItem={this.props.showItem}
|
||||
source={props.sourceMap[item.source]}
|
||||
filter={props.filter}
|
||||
shortcuts={props.shortcuts}
|
||||
markRead={props.markRead}
|
||||
contextMenu={props.contextMenu}
|
||||
showItem={props.showItem}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-fix" key={"f-" + index}></div>
|
||||
)
|
||||
|
||||
canFocusChild = (el: HTMLElement) => {
|
||||
const canFocusChild = (el: HTMLElement) => {
|
||||
if (el.id === "load-more") {
|
||||
const container = document.getElementById("refocus")
|
||||
const result =
|
||||
@@ -76,43 +76,39 @@ class CardsFeed extends React.Component<FeedProps> {
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
this.props.feed.loaded && (
|
||||
<FocusZone
|
||||
as="div"
|
||||
id="refocus"
|
||||
className="cards-feed-container"
|
||||
shouldReceiveFocus={this.canFocusChild}
|
||||
data-is-scrollable>
|
||||
<List
|
||||
className={AnimationClassNames.slideUpIn10}
|
||||
items={this.flexFixItems()}
|
||||
onRenderCell={this.onRenderItem}
|
||||
getItemCountForPage={this.getItemCountForPage}
|
||||
getPageHeight={this.getPageHeight}
|
||||
ignoreScrollingState
|
||||
usePageCache
|
||||
/>
|
||||
{this.props.feed.loaded && !this.props.feed.allLoaded ? (
|
||||
<div className="load-more-wrapper">
|
||||
<PrimaryButton
|
||||
id="load-more"
|
||||
text={intl.get("loadMore")}
|
||||
disabled={this.props.feed.loading}
|
||||
onClick={() =>
|
||||
this.props.loadMore(this.props.feed)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{this.props.items.length === 0 && (
|
||||
<div className="empty">{intl.get("article.empty")}</div>
|
||||
)}
|
||||
</FocusZone>
|
||||
)
|
||||
return (
|
||||
props.feed.loaded && (
|
||||
<FocusZone
|
||||
as="div"
|
||||
id="refocus"
|
||||
className="cards-feed-container"
|
||||
shouldReceiveFocus={canFocusChild}
|
||||
data-is-scrollable>
|
||||
<List
|
||||
className={AnimationClassNames.slideUpIn10}
|
||||
items={flexFixItems()}
|
||||
onRenderCell={onRenderItem}
|
||||
getItemCountForPage={getItemCountForPage}
|
||||
getPageHeight={getPageHeight}
|
||||
ignoreScrollingState
|
||||
usePageCache
|
||||
/>
|
||||
{props.feed.loaded && !props.feed.allLoaded ? (
|
||||
<div className="load-more-wrapper">
|
||||
<PrimaryButton
|
||||
id="load-more"
|
||||
text={intl.get("loadMore")}
|
||||
disabled={props.feed.loading}
|
||||
onClick={() => props.loadMore(props.feed)}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{props.items.length === 0 && (
|
||||
<div className="empty">{intl.get("article.empty")}</div>
|
||||
)}
|
||||
</FocusZone>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export default CardsFeed
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import * as React from "react"
|
||||
import { RSSItem } from "../../scripts/models/item"
|
||||
import { FeedReduxProps } from "../../containers/feed-container"
|
||||
import { RSSFeed, FeedFilter } from "../../scripts/models/feed"
|
||||
import { useCallback } from "react"
|
||||
import { RSSItem, markRead, itemShortcuts } from "../../scripts/models/item"
|
||||
import { openItemMenu } from "../../scripts/models/app"
|
||||
import { RSSFeed, FeedFilter, loadMore } from "../../scripts/models/feed"
|
||||
import { showItem } from "../../scripts/models/page"
|
||||
import { useAppSelector, useAppDispatch } from "../../scripts/reducer"
|
||||
import { ViewType, ViewConfigs } from "../../schema-types"
|
||||
import CardsFeed from "./cards-feed"
|
||||
import ListFeed from "./list-feed"
|
||||
|
||||
export type FeedProps = FeedReduxProps & {
|
||||
export type FeedProps = {
|
||||
feed: RSSFeed
|
||||
viewType: ViewType
|
||||
viewConfigs?: ViewConfigs
|
||||
@@ -21,15 +24,64 @@ export type FeedProps = FeedReduxProps & {
|
||||
showItem: (fid: string, item: RSSItem) => void
|
||||
}
|
||||
|
||||
export class Feed extends React.Component<FeedProps> {
|
||||
render() {
|
||||
switch (this.props.viewType) {
|
||||
case ViewType.Cards:
|
||||
return <CardsFeed {...this.props} />
|
||||
case ViewType.Magazine:
|
||||
case ViewType.Compact:
|
||||
case ViewType.List:
|
||||
return <ListFeed {...this.props} />
|
||||
}
|
||||
interface FeedOwnProps {
|
||||
feedId: string
|
||||
viewType: ViewType
|
||||
}
|
||||
|
||||
export const Feed: React.FC<FeedOwnProps> = ({ feedId, viewType }) => {
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const feed = useAppSelector(s => s.feeds[feedId])
|
||||
const items = useAppSelector(s =>
|
||||
s.feeds[feedId] ? s.feeds[feedId].iids.map(iid => s.items[iid]) : []
|
||||
)
|
||||
const sourceMap = useAppSelector(s => s.sources)
|
||||
const filter = useAppSelector(s => s.page.filter)
|
||||
const viewConfigs = useAppSelector(s => s.page.viewConfigs)
|
||||
const currentItem = useAppSelector(s => s.page.itemId)
|
||||
|
||||
const handleShortcuts = useCallback(
|
||||
(item: RSSItem, e: KeyboardEvent) => dispatch(itemShortcuts(item, e)),
|
||||
[]
|
||||
)
|
||||
const handleMarkRead = useCallback(
|
||||
(item: RSSItem) => dispatch(markRead(item)),
|
||||
[]
|
||||
)
|
||||
const handleContextMenu = useCallback(
|
||||
(fid: string, item: RSSItem, e) => dispatch(openItemMenu(item, fid, e)),
|
||||
[]
|
||||
)
|
||||
const handleLoadMore = useCallback((f: RSSFeed) => {
|
||||
dispatch(loadMore(f))
|
||||
}, [])
|
||||
const handleShowItem = useCallback(
|
||||
(fid: string, item: RSSItem) => dispatch(showItem(fid, item)),
|
||||
[]
|
||||
)
|
||||
|
||||
const feedProps: FeedProps = {
|
||||
feed,
|
||||
viewType,
|
||||
viewConfigs,
|
||||
items,
|
||||
currentItem,
|
||||
sourceMap,
|
||||
filter,
|
||||
shortcuts: handleShortcuts,
|
||||
markRead: handleMarkRead,
|
||||
contextMenu: handleContextMenu,
|
||||
loadMore: handleLoadMore,
|
||||
showItem: handleShowItem,
|
||||
}
|
||||
|
||||
switch (viewType) {
|
||||
case ViewType.Cards:
|
||||
return <CardsFeed {...feedProps} />
|
||||
case ViewType.Magazine:
|
||||
case ViewType.Compact:
|
||||
case ViewType.List:
|
||||
return <ListFeed {...feedProps} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,39 +15,39 @@ import MagazineCard from "../cards/magazine-card"
|
||||
import CompactCard from "../cards/compact-card"
|
||||
import { Card } from "../cards/card"
|
||||
|
||||
class ListFeed extends React.Component<FeedProps> {
|
||||
onRenderItem = (item: RSSItem) => {
|
||||
const props = {
|
||||
feedId: this.props.feed._id,
|
||||
const ListFeed: React.FC<FeedProps> = props => {
|
||||
const onRenderItem = (item: RSSItem) => {
|
||||
const cardProps = {
|
||||
feedId: props.feed._id,
|
||||
key: item._id,
|
||||
item: item,
|
||||
source: this.props.sourceMap[item.source],
|
||||
filter: this.props.filter,
|
||||
viewConfigs: this.props.viewConfigs,
|
||||
shortcuts: this.props.shortcuts,
|
||||
markRead: this.props.markRead,
|
||||
contextMenu: this.props.contextMenu,
|
||||
showItem: this.props.showItem,
|
||||
source: props.sourceMap[item.source],
|
||||
filter: props.filter,
|
||||
viewConfigs: props.viewConfigs,
|
||||
shortcuts: props.shortcuts,
|
||||
markRead: props.markRead,
|
||||
contextMenu: props.contextMenu,
|
||||
showItem: props.showItem,
|
||||
} as Card.Props
|
||||
if (
|
||||
this.props.viewType === ViewType.List &&
|
||||
this.props.currentItem === item._id
|
||||
props.viewType === ViewType.List &&
|
||||
props.currentItem === item._id
|
||||
) {
|
||||
props.selected = true
|
||||
cardProps.selected = true
|
||||
}
|
||||
|
||||
switch (this.props.viewType) {
|
||||
switch (props.viewType) {
|
||||
case ViewType.Magazine:
|
||||
return <MagazineCard {...props} />
|
||||
return <MagazineCard {...cardProps} />
|
||||
case ViewType.Compact:
|
||||
return <CompactCard {...props} />
|
||||
return <CompactCard {...cardProps} />
|
||||
default:
|
||||
return <ListCard {...props} />
|
||||
return <ListCard {...cardProps} />
|
||||
}
|
||||
}
|
||||
|
||||
getClassName = () => {
|
||||
switch (this.props.viewType) {
|
||||
const getClassName = () => {
|
||||
switch (props.viewType) {
|
||||
case ViewType.Magazine:
|
||||
return "magazine-feed"
|
||||
case ViewType.Compact:
|
||||
@@ -57,7 +57,7 @@ class ListFeed extends React.Component<FeedProps> {
|
||||
}
|
||||
}
|
||||
|
||||
canFocusChild = (el: HTMLElement) => {
|
||||
const canFocusChild = (el: HTMLElement) => {
|
||||
if (el.id === "load-more") {
|
||||
const container = document.getElementById("refocus")
|
||||
const result =
|
||||
@@ -70,42 +70,38 @@ class ListFeed extends React.Component<FeedProps> {
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
this.props.feed.loaded && (
|
||||
<FocusZone
|
||||
as="div"
|
||||
id="refocus"
|
||||
direction={FocusZoneDirection.vertical}
|
||||
className={this.getClassName()}
|
||||
shouldReceiveFocus={this.canFocusChild}
|
||||
data-is-scrollable>
|
||||
<List
|
||||
className={AnimationClassNames.slideUpIn10}
|
||||
items={this.props.items}
|
||||
onRenderCell={this.onRenderItem}
|
||||
ignoreScrollingState
|
||||
usePageCache
|
||||
/>
|
||||
{this.props.feed.loaded && !this.props.feed.allLoaded ? (
|
||||
<div className="load-more-wrapper">
|
||||
<PrimaryButton
|
||||
id="load-more"
|
||||
text={intl.get("loadMore")}
|
||||
disabled={this.props.feed.loading}
|
||||
onClick={() =>
|
||||
this.props.loadMore(this.props.feed)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{this.props.items.length === 0 && (
|
||||
<div className="empty">{intl.get("article.empty")}</div>
|
||||
)}
|
||||
</FocusZone>
|
||||
)
|
||||
return (
|
||||
props.feed.loaded && (
|
||||
<FocusZone
|
||||
as="div"
|
||||
id="refocus"
|
||||
direction={FocusZoneDirection.vertical}
|
||||
className={getClassName()}
|
||||
shouldReceiveFocus={canFocusChild}
|
||||
data-is-scrollable>
|
||||
<List
|
||||
className={AnimationClassNames.slideUpIn10}
|
||||
items={props.items}
|
||||
onRenderCell={onRenderItem}
|
||||
ignoreScrollingState
|
||||
usePageCache
|
||||
/>
|
||||
{props.feed.loaded && !props.feed.allLoaded ? (
|
||||
<div className="load-more-wrapper">
|
||||
<PrimaryButton
|
||||
id="load-more"
|
||||
text={intl.get("loadMore")}
|
||||
disabled={props.feed.loading}
|
||||
onClick={() => props.loadMore(props.feed)}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{props.items.length === 0 && (
|
||||
<div className="empty">{intl.get("article.empty")}</div>
|
||||
)}
|
||||
</FocusZone>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export default ListFeed
|
||||
|
||||
+46
-44
@@ -14,15 +14,16 @@ import {
|
||||
openMarkAllMenu,
|
||||
} from "../scripts/models/app"
|
||||
import { toggleSearch } from "../scripts/models/page"
|
||||
import { ViewType , WindowStateListenerType } from "../schema-types"
|
||||
import { ViewType, WindowStateListenerType } from "../schema-types"
|
||||
|
||||
const Nav: React.FC = () => {
|
||||
const dispatch = useDispatch()
|
||||
const state = useSelector((state: RootState) => state.app)
|
||||
const itemShown = useSelector(
|
||||
(state: RootState) => state.page.itemId && state.page.viewType !== ViewType.List
|
||||
(state: RootState) =>
|
||||
state.page.itemId && state.page.viewType !== ViewType.List
|
||||
)
|
||||
const [maximized, setMaximized] = useState(window.utils.isMaximized())
|
||||
const [maximized, setMaximized] = useState(globalThis.utils.isMaximized())
|
||||
|
||||
const setBodyFocusState = useCallback((focused: boolean) => {
|
||||
if (focused) document.body.classList.remove("blur")
|
||||
@@ -103,13 +104,23 @@ const Nav: React.FC = () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
[state.settings.display, itemShown, menu, search, fetch, markAll, logs, views, settings]
|
||||
[
|
||||
state.settings.display,
|
||||
itemShown,
|
||||
menu,
|
||||
search,
|
||||
fetch,
|
||||
markAll,
|
||||
logs,
|
||||
views,
|
||||
settings,
|
||||
]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setBodyFocusState(window.utils.isFocused())
|
||||
setBodyFullscreenState(window.utils.isFullscreen())
|
||||
window.utils.addWindowStateListener(windowStateListener)
|
||||
setBodyFocusState(globalThis.utils.isFocused())
|
||||
setBodyFullscreenState(globalThis.utils.isFullscreen())
|
||||
globalThis.utils.addWindowStateListener(windowStateListener)
|
||||
|
||||
return () => {
|
||||
// Cleanup will be handled by the event listener removal effect
|
||||
@@ -118,8 +129,8 @@ const Nav: React.FC = () => {
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("keydown", navShortcutsHandler)
|
||||
if (window.utils.platform === "darwin")
|
||||
window.utils.addTouchBarEventsListener(navShortcutsHandler)
|
||||
if (globalThis.utils.platform === "darwin")
|
||||
globalThis.utils.addTouchBarEventsListener(navShortcutsHandler)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", navShortcutsHandler)
|
||||
@@ -127,19 +138,19 @@ const Nav: React.FC = () => {
|
||||
}, [navShortcutsHandler])
|
||||
|
||||
const minimize = () => {
|
||||
window.utils.minimizeWindow()
|
||||
globalThis.utils.minimizeWindow()
|
||||
}
|
||||
|
||||
const maximize = () => {
|
||||
window.utils.maximizeWindow()
|
||||
globalThis.utils.maximizeWindow()
|
||||
setMaximized(!maximized)
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
window.utils.closeWindow()
|
||||
globalThis.utils.closeWindow()
|
||||
}
|
||||
|
||||
const fetching = () => (!canFetch() ? " fetching" : "")
|
||||
const fetching = () => (canFetch() ? "" : " fetching")
|
||||
|
||||
const getClassNames = () => {
|
||||
const classNames = new Array<string>()
|
||||
@@ -158,42 +169,39 @@ const Nav: React.FC = () => {
|
||||
return (
|
||||
<nav className={getClassNames()}>
|
||||
<div className="btn-group">
|
||||
<a
|
||||
<button
|
||||
className="btn hide-wide"
|
||||
title={intl.get("nav.menu")}
|
||||
onClick={menu}>
|
||||
<Icon
|
||||
iconName={
|
||||
window.utils.platform === "darwin"
|
||||
globalThis.utils.platform === "darwin"
|
||||
? "SidePanel"
|
||||
: "GlobalNavButton"
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
<span className="title">{state.title}</span>
|
||||
<div className="btn-group" style={{ float: "right" }}>
|
||||
<a
|
||||
<button
|
||||
className={"btn" + fetching()}
|
||||
onClick={fetch}
|
||||
title={intl.get("nav.refresh")}>
|
||||
<Icon iconName="Refresh" />
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn"
|
||||
id="mark-all-toggle"
|
||||
onClick={markAll}
|
||||
title={intl.get("nav.markAllRead")}
|
||||
onMouseDown={e => {
|
||||
if (
|
||||
state.contextMenu.event ===
|
||||
"#mark-all-toggle"
|
||||
)
|
||||
if (state.contextMenu.event === "#mark-all-toggle")
|
||||
e.stopPropagation()
|
||||
}}>
|
||||
<Icon iconName="InboxCheck" />
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn"
|
||||
id="log-toggle"
|
||||
title={intl.get("nav.notifications")}
|
||||
@@ -203,36 +211,33 @@ const Nav: React.FC = () => {
|
||||
) : (
|
||||
<Icon iconName="Ringer" />
|
||||
)}
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn"
|
||||
id="view-toggle"
|
||||
title={intl.get("nav.view")}
|
||||
onClick={views}
|
||||
onMouseDown={e => {
|
||||
if (
|
||||
state.contextMenu.event ===
|
||||
"#view-toggle"
|
||||
)
|
||||
if (state.contextMenu.event === "#view-toggle")
|
||||
e.stopPropagation()
|
||||
}}>
|
||||
<Icon iconName="View" />
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn"
|
||||
title={intl.get("nav.settings")}
|
||||
onClick={settings}>
|
||||
<Icon iconName="Settings" />
|
||||
</a>
|
||||
</button>
|
||||
<span className="seperator"></span>
|
||||
<a
|
||||
<button
|
||||
className="btn system"
|
||||
title={intl.get("nav.minimize")}
|
||||
onClick={minimize}
|
||||
style={{ fontSize: 12 }}>
|
||||
<Icon iconName="Remove" />
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn system"
|
||||
title={intl.get("nav.maximize")}
|
||||
onClick={maximize}>
|
||||
@@ -242,18 +247,15 @@ const Nav: React.FC = () => {
|
||||
style={{ fontSize: 11 }}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
iconName="Checkbox"
|
||||
style={{ fontSize: 10 }}
|
||||
/>
|
||||
<Icon iconName="Checkbox" style={{ fontSize: 10 }} />
|
||||
)}
|
||||
</a>
|
||||
<a
|
||||
</button>
|
||||
<button
|
||||
className="btn system close"
|
||||
title={intl.get("close")}
|
||||
onClick={close}>
|
||||
<Icon iconName="Cancel" />
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
{!canFetch() && (
|
||||
<ProgressIndicator
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from "react"
|
||||
import { useCallback } from "react"
|
||||
import { FeedContainer } from "../containers/feed-container"
|
||||
import { Feed } from "./feeds/feed"
|
||||
import { Icon, FocusTrapZone } from "@fluentui/react"
|
||||
import ArticleContainer from "../containers/article-container"
|
||||
import { ViewType } from "../schema-types"
|
||||
@@ -47,7 +47,7 @@ const Page: React.FC = () => {
|
||||
className={"list-main" + (menuOn ? " menu-on" : "")}>
|
||||
<ArticleSearch />
|
||||
<div className="list-feed-container">
|
||||
<FeedContainer
|
||||
<Feed
|
||||
viewType={viewType}
|
||||
feedId={feedId}
|
||||
key={feedId}
|
||||
@@ -79,7 +79,7 @@ const Page: React.FC = () => {
|
||||
{settingsOn ? null : (
|
||||
<div key="card" className={"main" + (menuOn ? " menu-on" : "")}>
|
||||
<ArticleSearch />
|
||||
<FeedContainer
|
||||
<Feed
|
||||
viewType={viewType}
|
||||
feedId={feedId}
|
||||
key={feedId + viewType}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import { connect } from "react-redux"
|
||||
import { createSelector } from "reselect"
|
||||
import { RootState } from "../scripts/reducer"
|
||||
import { markRead, RSSItem, itemShortcuts } from "../scripts/models/item"
|
||||
import { openItemMenu } from "../scripts/models/app"
|
||||
import { loadMore, RSSFeed } from "../scripts/models/feed"
|
||||
import { showItem } from "../scripts/models/page"
|
||||
import { ViewType } from "../schema-types"
|
||||
import { Feed } from "../components/feeds/feed"
|
||||
|
||||
interface FeedContainerProps {
|
||||
feedId: string
|
||||
viewType: ViewType
|
||||
}
|
||||
|
||||
const getSources = (state: RootState) => state.sources
|
||||
const getItems = (state: RootState) => state.items
|
||||
const getFeed = (state: RootState, props: FeedContainerProps) =>
|
||||
state.feeds[props.feedId]
|
||||
const getFilter = (state: RootState) => state.page.filter
|
||||
const getView = (_, props: FeedContainerProps) => props.viewType
|
||||
const getViewConfigs = (state: RootState) => state.page.viewConfigs
|
||||
const getCurrentItem = (state: RootState) => state.page.itemId
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
return createSelector(
|
||||
[
|
||||
getSources,
|
||||
getItems,
|
||||
getFeed,
|
||||
getView,
|
||||
getFilter,
|
||||
getViewConfigs,
|
||||
getCurrentItem,
|
||||
],
|
||||
(sources, items, feed, viewType, filter, viewConfigs, currentItem) => ({
|
||||
feed: feed,
|
||||
items: feed.iids.map(iid => items[iid]),
|
||||
sourceMap: sources,
|
||||
filter: filter,
|
||||
viewType: viewType,
|
||||
viewConfigs: viewConfigs,
|
||||
currentItem: currentItem,
|
||||
})
|
||||
)
|
||||
}
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
shortcuts: (item: RSSItem, e: KeyboardEvent) =>
|
||||
dispatch(itemShortcuts(item, e)),
|
||||
markRead: (item: RSSItem) => dispatch(markRead(item)),
|
||||
contextMenu: (feedId: string, item: RSSItem, e) =>
|
||||
dispatch(openItemMenu(item, feedId, e)),
|
||||
loadMore: (feed: RSSFeed) => dispatch(loadMore(feed)),
|
||||
showItem: (fid: string, item: RSSItem) => dispatch(showItem(fid, item)),
|
||||
}
|
||||
}
|
||||
|
||||
const connector = connect(makeMapStateToProps, mapDispatchToProps)
|
||||
export type FeedReduxProps = typeof connector
|
||||
export const FeedContainer = connector(Feed)
|
||||
Reference in New Issue
Block a user