parent
58b55e3c32
commit
a4e6709c46
|
|
@ -1,5 +1,4 @@
|
|||
import { getOS } from "@renderer/lib/utils"
|
||||
import { memoize } from "lodash-es"
|
||||
import type { FC } from "react"
|
||||
|
||||
const SpecialKeys = {
|
||||
|
|
@ -23,11 +22,10 @@ const SpecialKeys = {
|
|||
},
|
||||
}
|
||||
|
||||
const os = memoize(getOS)
|
||||
export const Kbd: FC<{
|
||||
children: string
|
||||
}> = ({ children }) => {
|
||||
const specialKeys = SpecialKeys[os()]
|
||||
const specialKeys = SpecialKeys[getOS()]
|
||||
let key = children
|
||||
if (children.toLowerCase() in specialKeys) {
|
||||
key = specialKeys[children.toLowerCase()]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { ClassValue } from "clsx"
|
||||
import { clsx } from "clsx"
|
||||
import { memoize } from "lodash-es"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
import { FEED_COLLECTION_LIST, levels } from "./constants"
|
||||
|
|
@ -42,7 +43,7 @@ export function getEntriesParams({
|
|||
}
|
||||
|
||||
export type OS = "macOS" | "iOS" | "Windows" | "Android" | "Linux" | ""
|
||||
export function getOS(): OS {
|
||||
export const getOS = memoize((): OS => {
|
||||
const { userAgent } = window.navigator,
|
||||
{ platform } = window.navigator,
|
||||
macosPlatforms = ["Macintosh", "MacIntel", "MacPPC", "Mac68K"],
|
||||
|
|
@ -63,7 +64,7 @@ export function getOS(): OS {
|
|||
}
|
||||
|
||||
return os as OS
|
||||
}
|
||||
})
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
export const isASCII = (str) => /^[\u0000-\u007F]*$/.test(str)
|
||||
|
|
@ -74,7 +75,13 @@ export const isBizId = (id) => {
|
|||
// id is uuid or snowflake
|
||||
|
||||
// 0. check is uuid
|
||||
if (id.length === 36 && id[8] === "-" && id[13] === "-" && id[18] === "-" && id[23] === "-") {
|
||||
if (
|
||||
id.length === 36 &&
|
||||
id[8] === "-" &&
|
||||
id[13] === "-" &&
|
||||
id[18] === "-" &&
|
||||
id[23] === "-"
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +119,8 @@ export function formatXml(xml: string, indent = 4) {
|
|||
return formatted.trim()
|
||||
}
|
||||
|
||||
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||
export const sleep = (ms: number) =>
|
||||
new Promise((resolve) => setTimeout(resolve, ms))
|
||||
|
||||
export const capitalizeFirstLetter = (string: string) =>
|
||||
string.charAt(0).toUpperCase() + string.slice(1)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ import {
|
|||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react"
|
||||
|
|
@ -184,7 +183,7 @@ const ListHeader: FC<{
|
|||
}, [feedId, folderIds, routerParams])
|
||||
|
||||
const headerTitle = useFeedHeaderTitle()
|
||||
const os = useMemo(getOS, [])
|
||||
const os = getOS()
|
||||
|
||||
const titleAtBottom = window.electron && os === "macOS"
|
||||
const titleInfo = (
|
||||
|
|
@ -222,70 +221,71 @@ const ListHeader: FC<{
|
|||
)}
|
||||
>
|
||||
{!titleAtBottom && titleInfo}
|
||||
{!isInCollectionList && (
|
||||
<div
|
||||
className="relative z-[1] flex items-center gap-1 self-baseline text-zinc-500"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{views[view].wideMode &&
|
||||
entryId &&
|
||||
entryId !== ROUTE_ENTRY_PENDING && (
|
||||
<>
|
||||
<EntryHeader view={view} entryId={entryId} />
|
||||
<DividerVertical className="w-px" />
|
||||
</>
|
||||
)}
|
||||
{feed?.ownerUserId === user?.id && isBizId(routerParams.feedId) && (
|
||||
<ActionButton
|
||||
tooltip="Refresh"
|
||||
// shortcut={shortcuts.entries.toggleUnreadOnly.key}
|
||||
onClick={() => {
|
||||
refreshFeed()
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className={cn(
|
||||
"i-mgc-refresh-2-cute-re",
|
||||
isPending && "animate-spin",
|
||||
)}
|
||||
/>
|
||||
</ActionButton>
|
||||
)}
|
||||
|
||||
<div
|
||||
className={cn("relative z-[1] flex items-center gap-1 self-baseline text-zinc-500", isInCollectionList && "pointer-events-none opacity-0",
|
||||
|
||||
)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{views[view].wideMode &&
|
||||
entryId &&
|
||||
entryId !== ROUTE_ENTRY_PENDING && (
|
||||
<>
|
||||
<EntryHeader view={view} entryId={entryId} />
|
||||
<DividerVertical className="w-px" />
|
||||
</>
|
||||
)}
|
||||
{feed?.ownerUserId === user?.id && isBizId(routerParams.feedId) && (
|
||||
<ActionButton
|
||||
tooltip={unreadOnly ? "Unread Only" : "All"}
|
||||
shortcut={shortcuts.entries.toggleUnreadOnly.key}
|
||||
onClick={() => setGeneralSetting("unreadOnly", !unreadOnly)}
|
||||
tooltip="Refresh"
|
||||
// shortcut={shortcuts.entries.toggleUnreadOnly.key}
|
||||
onClick={() => {
|
||||
refreshFeed()
|
||||
}}
|
||||
>
|
||||
{unreadOnly ? (
|
||||
<i className="i-mgc-round-cute-fi" />
|
||||
) : (
|
||||
<i className="i-mgc-round-cute-re" />
|
||||
)}
|
||||
<i
|
||||
className={cn(
|
||||
"i-mgc-refresh-2-cute-re",
|
||||
isPending && "animate-spin",
|
||||
)}
|
||||
/>
|
||||
</ActionButton>
|
||||
<Popover open={markPopoverOpen} onOpenChange={setMarkPopoverOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<ActionButton
|
||||
shortcut={shortcuts.entries.markAllAsRead.key}
|
||||
tooltip="Mark All as Read"
|
||||
>
|
||||
<i className="i-mgc-check-circle-cute-re" />
|
||||
</ActionButton>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="flex w-fit flex-col items-center justify-center gap-3 text-[0.94rem] font-medium">
|
||||
<div>Mark all as read?</div>
|
||||
<div className="space-x-4">
|
||||
<PopoverClose>
|
||||
<StyledButton variant="outline">Cancel</StyledButton>
|
||||
</PopoverClose>
|
||||
{/* TODO */}
|
||||
<StyledButton onClick={handleMarkAllAsRead}>
|
||||
Confirm
|
||||
</StyledButton>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
<ActionButton
|
||||
tooltip={unreadOnly ? "Unread Only" : "All"}
|
||||
shortcut={shortcuts.entries.toggleUnreadOnly.key}
|
||||
onClick={() => setGeneralSetting("unreadOnly", !unreadOnly)}
|
||||
>
|
||||
{unreadOnly ? (
|
||||
<i className="i-mgc-round-cute-fi" />
|
||||
) : (
|
||||
<i className="i-mgc-round-cute-re" />
|
||||
)}
|
||||
</ActionButton>
|
||||
<Popover open={markPopoverOpen} onOpenChange={setMarkPopoverOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<ActionButton
|
||||
shortcut={shortcuts.entries.markAllAsRead.key}
|
||||
tooltip="Mark All as Read"
|
||||
>
|
||||
<i className="i-mgc-check-circle-cute-re" />
|
||||
</ActionButton>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="flex w-fit flex-col items-center justify-center gap-3 text-[0.94rem] font-medium">
|
||||
<div>Mark all as read?</div>
|
||||
<div className="space-x-4">
|
||||
<PopoverClose>
|
||||
<StyledButton variant="outline">Cancel</StyledButton>
|
||||
</PopoverClose>
|
||||
{/* TODO */}
|
||||
<StyledButton onClick={handleMarkAllAsRead}>
|
||||
Confirm
|
||||
</StyledButton>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
{titleAtBottom && titleInfo}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { apiClient } from "@renderer/lib/api-fetch"
|
||||
import { ROUTE_FEED_IN_FOLDER } from "@renderer/lib/constants"
|
||||
import { FEED_COLLECTION_LIST, ROUTE_FEED_IN_FOLDER } from "@renderer/lib/constants"
|
||||
import { FeedViewType } from "@renderer/lib/enum"
|
||||
import { capitalizeFirstLetter } from "@renderer/lib/utils"
|
||||
import type { SubscriptionModel } from "@renderer/models"
|
||||
|
|
@ -156,12 +156,14 @@ export const useSubscriptionByFeedId = (feedId: FeedId) =>
|
|||
useSubscriptionStore((state) => state.data[feedId])
|
||||
|
||||
export const useFolderFeedsByFeedId = (feedId?: string) =>
|
||||
useSubscriptionStore((state) => {
|
||||
if (typeof feedId !== "string") return
|
||||
useSubscriptionStore((state): string[] => {
|
||||
if (typeof feedId !== "string") return []
|
||||
if (feedId === FEED_COLLECTION_LIST) { return [feedId] }
|
||||
|
||||
if (!feedId.startsWith(ROUTE_FEED_IN_FOLDER)) {
|
||||
return
|
||||
return []
|
||||
}
|
||||
|
||||
const folderName = feedId.replace(ROUTE_FEED_IN_FOLDER, "")
|
||||
const feedIds: string[] = []
|
||||
for (const feedId in state.data) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue