mirror of
https://github.com/yang991178/fluent-reader.git
synced 2025-04-15 10:47:36 +02:00
improve fonts and menu focus
This commit is contained in:
parent
6a751be533
commit
76a97852a1
@ -109,6 +109,7 @@ class Article extends React.Component<ArticleProps, ArticleState> {
|
|||||||
webview.addEventListener("new-window", this.popUpHandler)
|
webview.addEventListener("new-window", this.popUpHandler)
|
||||||
webview.addEventListener("will-navigate", this.navigationHandler)
|
webview.addEventListener("will-navigate", this.navigationHandler)
|
||||||
this.webview = webview
|
this.webview = webview
|
||||||
|
webview.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidUpdate = (prevProps: ArticleProps) => {
|
componentDidUpdate = (prevProps: ArticleProps) => {
|
||||||
|
@ -5,7 +5,7 @@ import { Nav, INavLink, INavLinkGroup } from "office-ui-fabric-react/lib/Nav"
|
|||||||
import { SourceGroup } from "../scripts/models/group"
|
import { SourceGroup } from "../scripts/models/group"
|
||||||
import { SourceState, RSSSource } from "../scripts/models/source"
|
import { SourceState, RSSSource } from "../scripts/models/source"
|
||||||
import { ALL } from "../scripts/models/feed"
|
import { ALL } from "../scripts/models/feed"
|
||||||
import { AnimationClassNames, Stack } from "@fluentui/react"
|
import { AnimationClassNames, Stack, FocusZone, FocusZoneDirection } from "@fluentui/react"
|
||||||
|
|
||||||
export type MenuProps = {
|
export type MenuProps = {
|
||||||
status: boolean,
|
status: boolean,
|
||||||
@ -26,7 +26,7 @@ export type MenuProps = {
|
|||||||
export class Menu extends React.Component<MenuProps> {
|
export class Menu extends React.Component<MenuProps> {
|
||||||
countOverflow = (count: number) => count >= 1000 ? "999+" : String(count)
|
countOverflow = (count: number) => count >= 1000 ? "999+" : String(count)
|
||||||
|
|
||||||
getItems = (): INavLinkGroup[] => [
|
getLinkGroups = (): INavLinkGroup[] => [
|
||||||
{
|
{
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
@ -46,28 +46,28 @@ export class Menu extends React.Component<MenuProps> {
|
|||||||
url: null
|
url: null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: intl.get("menu.subscriptions"),
|
||||||
|
links: this.props.groups.filter(g => g.sids.length > 0).map((g, i) => {
|
||||||
|
if (g.isMultiple) {
|
||||||
|
let sources = g.sids.map(sid => this.props.sources[sid])
|
||||||
|
return {
|
||||||
|
name: g.name,
|
||||||
|
ariaLabel: this.countOverflow(sources.map(s => s.unreadCount).reduce((a, b) => a + b, 0)),
|
||||||
|
key: "g-" + i,
|
||||||
|
url: null,
|
||||||
|
isExpanded: g.expanded,
|
||||||
|
onClick: () => this.props.selectSourceGroup(g, "g-" + i),
|
||||||
|
links: sources.map(this.getSource)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.getSource(this.props.sources[g.sids[0]])
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
getGroups = (): INavLinkGroup[] => [{
|
|
||||||
links: this.props.groups.filter(g => g.sids.length > 0).map((g, i) => {
|
|
||||||
if (g.isMultiple) {
|
|
||||||
let sources = g.sids.map(sid => this.props.sources[sid])
|
|
||||||
return {
|
|
||||||
name: g.name,
|
|
||||||
ariaLabel: this.countOverflow(sources.map(s => s.unreadCount).reduce((a, b) => a + b, 0)),
|
|
||||||
key: "g-" + i,
|
|
||||||
url: null,
|
|
||||||
isExpanded: g.expanded,
|
|
||||||
onClick: () => this.props.selectSourceGroup(g, "g-" + i),
|
|
||||||
links: sources.map(this.getSource)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return this.getSource(this.props.sources[g.sids[0]])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)}]
|
|
||||||
|
|
||||||
getSource = (s: RSSSource): INavLink => ({
|
getSource = (s: RSSSource): INavLink => ({
|
||||||
name: s.name,
|
name: s.name,
|
||||||
ariaLabel: this.countOverflow(s.unreadCount),
|
ariaLabel: this.countOverflow(s.unreadCount),
|
||||||
@ -106,6 +106,10 @@ export class Menu extends React.Component<MenuProps> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_onRenderGroupHeader = (group: INavLinkGroup): JSX.Element => {
|
||||||
|
return <p className={"subs-header " + AnimationClassNames.slideDownIn10}>{group.name}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.props.status && (
|
return this.props.status && (
|
||||||
<div className="menu-container" onClick={this.props.toggleMenu} style={{display: this.props.display ? "block" : "none"}}>
|
<div className="menu-container" onClick={this.props.toggleMenu} style={{display: this.props.display ? "block" : "none"}}>
|
||||||
@ -116,15 +120,11 @@ export class Menu extends React.Component<MenuProps> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="nav-wrapper">
|
<div className="nav-wrapper">
|
||||||
<Nav
|
<Nav
|
||||||
|
onRenderGroupHeader={this._onRenderGroupHeader}
|
||||||
onRenderLink={this._onRenderLink}
|
onRenderLink={this._onRenderLink}
|
||||||
groups={this.getItems()}
|
groups={this.getLinkGroups()}
|
||||||
selectedKey={this.props.selected} />
|
|
||||||
<p className={"subs-header " + AnimationClassNames.slideDownIn10}>{intl.get("menu.subscriptions")}</p>
|
|
||||||
<Nav
|
|
||||||
selectedKey={this.props.selected}
|
selectedKey={this.props.selected}
|
||||||
onRenderLink={this._onRenderLink}
|
onLinkExpandClick={(event, item) => this.props.updateGroupExpansion(event, item.key, this.props.selected)} />
|
||||||
onLinkExpandClick={(event, item) => this.props.updateGroupExpansion(event, item.key, this.props.selected)}
|
|
||||||
groups={this.getGroups()} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
"copyTitle": "复制标题",
|
"copyTitle": "复制标题",
|
||||||
"copyURL": "复制链接",
|
"copyURL": "复制链接",
|
||||||
"copy": "复制",
|
"copy": "复制",
|
||||||
"search": "使用Google搜索“{text}”",
|
"search": "使用 Google 搜索“{text}”",
|
||||||
"view": "视图",
|
"view": "视图",
|
||||||
"cardView": "卡片视图",
|
"cardView": "卡片视图",
|
||||||
"listView": "列表视图",
|
"listView": "列表视图",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as db from "../db"
|
import * as db from "../db"
|
||||||
import intl = require("react-intl-universal")
|
import intl = require("react-intl-universal")
|
||||||
import { rssParser, domParser, htmlDecode, ActionStatus, AppThunk } from "../utils"
|
import { domParser, htmlDecode, ActionStatus, AppThunk } from "../utils"
|
||||||
import { RSSSource } from "./source"
|
import { RSSSource } from "./source"
|
||||||
import { FeedActionTypes, INIT_FEED, LOAD_MORE } from "./feed"
|
import { FeedActionTypes, INIT_FEED, LOAD_MORE } from "./feed"
|
||||||
import Parser = require("@yang991178/rss-parser")
|
import Parser = require("@yang991178/rss-parser")
|
||||||
@ -152,7 +152,7 @@ export function fetchItems(): AppThunk<Promise<void>> {
|
|||||||
((s.lastFetched ? s.lastFetched.getTime() : 0) + (s.fetchFrequency || 0) * 60000) <= timenow
|
((s.lastFetched ? s.lastFetched.getTime() : 0) + (s.fetchFrequency || 0) * 60000) <= timenow
|
||||||
)
|
)
|
||||||
for (let source of sources) {
|
for (let source of sources) {
|
||||||
let promise = RSSSource.fetchItems(source, rssParser)
|
let promise = RSSSource.fetchItems(source)
|
||||||
promise.finally(() => dispatch(fetchItemsIntermediate()))
|
promise.finally(() => dispatch(fetchItemsIntermediate()))
|
||||||
promises.push(promise)
|
promises.push(promise)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Parser = require("@yang991178/rss-parser")
|
import Parser = require("@yang991178/rss-parser")
|
||||||
import intl = require("react-intl-universal")
|
import intl = require("react-intl-universal")
|
||||||
import * as db from "../db"
|
import * as db from "../db"
|
||||||
import { rssParser, fetchFavicon, ActionStatus, AppThunk, parseRSS } from "../utils"
|
import { fetchFavicon, ActionStatus, AppThunk, parseRSS } from "../utils"
|
||||||
import { RSSItem, insertItems, ItemActionTypes, FETCH_ITEMS, MARK_READ, MARK_UNREAD, MARK_ALL_READ } from "./item"
|
import { RSSItem, insertItems, ItemActionTypes, FETCH_ITEMS, MARK_READ, MARK_UNREAD, MARK_ALL_READ } from "./item"
|
||||||
import { SourceGroup } from "./group"
|
import { SourceGroup } from "./group"
|
||||||
import { saveSettings } from "./app"
|
import { saveSettings } from "./app"
|
||||||
@ -28,16 +28,16 @@ export class RSSSource {
|
|||||||
this.lastFetched = new Date()
|
this.lastFetched = new Date()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchMetaData(parser: Parser) {
|
static async fetchMetaData(source: RSSSource) {
|
||||||
let feed = await parseRSS(this.url)
|
let feed = await parseRSS(source.url)
|
||||||
if (!this.name) {
|
if (!source.name) {
|
||||||
if (feed.title) this.name = feed.title.trim()
|
if (feed.title) source.name = feed.title.trim()
|
||||||
this.name = this.name || intl.get("sources.untitled")
|
source.name = source.name || intl.get("sources.untitled")
|
||||||
}
|
}
|
||||||
let domain = this.url.split("/").slice(0, 3).join("/")
|
let domain = source.url.split("/").slice(0, 3).join("/")
|
||||||
try {
|
try {
|
||||||
let f = await fetchFavicon(domain)
|
let f = await fetchFavicon(domain)
|
||||||
if (f !== null) this.iconurl = f
|
if (f !== null) source.iconurl = f
|
||||||
} finally {
|
} finally {
|
||||||
return feed
|
return feed
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ export class RSSSource {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async fetchItems(source: RSSSource, parser: Parser) {
|
static async fetchItems(source: RSSSource) {
|
||||||
let feed = await parseRSS(source.url)
|
let feed = await parseRSS(source.url)
|
||||||
db.sdb.update({ sid: source.sid }, { $set: { lastFetched: new Date() } })
|
db.sdb.update({ sid: source.sid }, { $set: { lastFetched: new Date() } })
|
||||||
return await this.checkItems(source, feed.items)
|
return await this.checkItems(source, feed.items)
|
||||||
@ -236,7 +236,7 @@ export function addSource(url: string, name: string = null, batch = false): AppT
|
|||||||
if (app.sourceInit) {
|
if (app.sourceInit) {
|
||||||
dispatch(addSourceRequest(batch))
|
dispatch(addSourceRequest(batch))
|
||||||
let source = new RSSSource(url, name)
|
let source = new RSSSource(url, name)
|
||||||
return source.fetchMetaData(rssParser)
|
return RSSSource.fetchMetaData(source)
|
||||||
.then(feed => {
|
.then(feed => {
|
||||||
return dispatch(insertSource(source))
|
return dispatch(insertSource(source))
|
||||||
.then(inserted => {
|
.then(inserted => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { remote, ipcRenderer } from "electron"
|
import { remote, ipcRenderer } from "electron"
|
||||||
import { ViewType } from "./models/page"
|
import { ViewType } from "./models/page"
|
||||||
import { IPartialTheme, loadTheme, values } from "@fluentui/react"
|
import { IPartialTheme, loadTheme } from "@fluentui/react"
|
||||||
import locales from "./i18n/_locales"
|
import locales from "./i18n/_locales"
|
||||||
import Store = require("electron-store")
|
import Store = require("electron-store")
|
||||||
import { schemaTypes } from "./config-schema"
|
import { schemaTypes } from "./config-schema"
|
||||||
@ -51,7 +51,7 @@ export const setDefaultView = (viewType: ViewType) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lightTheme: IPartialTheme = {
|
const lightTheme: IPartialTheme = {
|
||||||
defaultFontStyle: { fontFamily: '"Source Han Sans SC Regular", "Microsoft YaHei", sans-serif' }
|
defaultFontStyle: { fontFamily: '"Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif' }
|
||||||
}
|
}
|
||||||
const darkTheme: IPartialTheme = {
|
const darkTheme: IPartialTheme = {
|
||||||
...lightTheme,
|
...lightTheme,
|
||||||
|
@ -17,7 +17,7 @@ export type AppThunk<ReturnType = void> = ThunkAction<
|
|||||||
export type AppDispatch = ThunkDispatch<RootState, undefined, AnyAction>
|
export type AppDispatch = ThunkDispatch<RootState, undefined, AnyAction>
|
||||||
|
|
||||||
import Parser = require("@yang991178/rss-parser")
|
import Parser = require("@yang991178/rss-parser")
|
||||||
export const rssParser = new Parser({
|
const rssParser = new Parser({
|
||||||
customFields: {
|
customFields: {
|
||||||
item: ["thumb", "image", ["content:encoded", "fullContent"]] as Parser.CustomFieldItem[]
|
item: ["thumb", "image", ["content:encoded", "fullContent"]] as Parser.CustomFieldItem[]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user