fix: read history delay to polling
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
e2fec9c250
commit
f6f8ec84db
|
|
@ -1,7 +1,6 @@
|
|||
import { getColorScheme, stringToHue } from "@renderer/lib/color"
|
||||
import { cn } from "@renderer/lib/utils"
|
||||
import { cn, getUrlIcon } from "@renderer/lib/utils"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { parse } from "tldts"
|
||||
|
||||
import { PlatformIcon } from "./ui/platform-icon"
|
||||
|
||||
|
|
@ -21,8 +20,7 @@ export function SiteIcon({
|
|||
fallback?: boolean
|
||||
fallbackText?: string
|
||||
}) {
|
||||
let host: string
|
||||
let src: string
|
||||
let src = ""
|
||||
let fallbackUrl = ""
|
||||
|
||||
const colors = useMemo(
|
||||
|
|
@ -37,19 +35,9 @@ export function SiteIcon({
|
|||
|
||||
if (!url) return null
|
||||
|
||||
try {
|
||||
host = new URL(url).host
|
||||
const pureDomain = parse(host).domainWithoutSuffix
|
||||
fallbackUrl = `https://avatar.vercel.sh/${pureDomain}.svg?text=${pureDomain
|
||||
?.slice(0, 2)
|
||||
.toUpperCase()}`
|
||||
src = `https://unavatar.follow.is/${host}?fallback=${fallback}`
|
||||
} catch {
|
||||
const pureDomain = parse(url).domainWithoutSuffix
|
||||
src = `https://avatar.vercel.sh/${pureDomain}.svg?text=${pureDomain
|
||||
?.slice(0, 2)
|
||||
.toUpperCase()}`
|
||||
}
|
||||
const ret = getUrlIcon(url, fallback)
|
||||
src = ret.src
|
||||
fallbackUrl = ret.fallbackUrl
|
||||
|
||||
return (
|
||||
<PlatformIcon
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { ClassValue } from "clsx"
|
|||
import { clsx } from "clsx"
|
||||
import { memoize } from "lodash-es"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { parse } from "tldts"
|
||||
|
||||
import { FEED_COLLECTION_LIST, ROUTE_FEED_PENDING } from "../constants/app"
|
||||
import { FeedViewType } from "./enum"
|
||||
|
|
@ -88,10 +89,7 @@ export function detectBrowser() {
|
|||
return "Safari"
|
||||
} else if (userAgent.includes("Opera")) {
|
||||
return "Opera"
|
||||
} else if (
|
||||
userAgent.includes("Trident") ||
|
||||
userAgent.includes("MSIE")
|
||||
) {
|
||||
} else if (userAgent.includes("Trident") || userAgent.includes("MSIE")) {
|
||||
return "Internet Explorer"
|
||||
}
|
||||
|
||||
|
|
@ -220,3 +218,28 @@ export const sortByAlphabet = (a: string, b: string) => {
|
|||
|
||||
return a.localeCompare(b, "zh-CN")
|
||||
}
|
||||
|
||||
export const getUrlIcon = (url: string, fallback?: boolean | undefined) => {
|
||||
let src: string
|
||||
let fallbackUrl = ""
|
||||
|
||||
try {
|
||||
const { host } = new URL(url)
|
||||
const pureDomain = parse(host).domainWithoutSuffix
|
||||
fallbackUrl = `https://avatar.vercel.sh/${pureDomain}.svg?text=${pureDomain
|
||||
?.slice(0, 2)
|
||||
.toUpperCase()}`
|
||||
src = `https://unavatar.follow.is/${host}?fallback=${fallback || false}`
|
||||
} catch {
|
||||
const pureDomain = parse(url).domainWithoutSuffix
|
||||
src = `https://avatar.vercel.sh/${pureDomain}.svg?text=${pureDomain
|
||||
?.slice(0, 2)
|
||||
.toUpperCase()}`
|
||||
}
|
||||
const ret = {
|
||||
src,
|
||||
fallbackUrl,
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { Queries } from "@renderer/queries"
|
|||
import { useEntryReadHistory } from "@renderer/store/entry"
|
||||
import { useUserById } from "@renderer/store/user"
|
||||
import { LayoutGroup, m } from "framer-motion"
|
||||
import { Fragment } from "react"
|
||||
import { Fragment, useEffect, useState } from "react"
|
||||
|
||||
import { usePresentUserProfileModal } from "../../profile/hooks"
|
||||
|
||||
|
|
@ -24,9 +24,20 @@ export const EntryReadHistory: Component<{ entryId: string }> = ({
|
|||
const me = useWhoami()
|
||||
const entryHistory = useEntryReadHistory(entryId)
|
||||
|
||||
const [isEnabledPolling, setIsEnabledPolling] = useState(false)
|
||||
useAuthQuery(Queries.entries.entryReadingHistory(entryId), {
|
||||
refetchInterval: 1000 * 60,
|
||||
enabled: isEnabledPolling,
|
||||
})
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setIsEnabledPolling(true)
|
||||
}, 1000 * 60)
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [entryId])
|
||||
|
||||
if (!entryHistory) return null
|
||||
if (!me) return null
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import { EntryTranslation } from "../entry-column/translation"
|
|||
import { setEntryContentScrollToTop, setEntryTitleMeta } from "./atoms"
|
||||
import { EntryPlaceholderLogo } from "./components/EntryPlaceholderLogo"
|
||||
import { EntryHeader } from "./header"
|
||||
import { EntryContentLoading } from "./loading"
|
||||
import { EntryContentProvider } from "./provider"
|
||||
|
||||
export const EntryContent = ({ entryId }: { entryId: ActiveEntryId }) => {
|
||||
|
|
@ -242,13 +243,11 @@ export const EntryContentRender: Component<{ entryId: string }> = ({
|
|||
</ErrorBoundary>
|
||||
</div>
|
||||
</WrappedElementProvider>
|
||||
|
||||
{!content && (
|
||||
<div className="center mt-16">
|
||||
{isPending ? (
|
||||
<LoadingWithIcon
|
||||
size="large"
|
||||
icon={<i className="i-mgc-rss-cute-fi text-accent" />}
|
||||
/>
|
||||
<EntryContentLoading icon={feed?.siteUrl!} />
|
||||
) : error ?
|
||||
(
|
||||
<div className="center flex flex-col gap-2">
|
||||
|
|
@ -331,7 +330,10 @@ const ReadabilityContent = ({ entryId }: { entryId: string }) => {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<HTML as="article" className="prose dark:prose-invert prose-h1:text-[1.6em]">
|
||||
<HTML
|
||||
as="article"
|
||||
className="prose dark:prose-invert prose-h1:text-[1.6em]"
|
||||
>
|
||||
{result?.content ?? ""}
|
||||
</HTML>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { Avatar, AvatarImage } from "@renderer/components/ui/avatar"
|
||||
import {
|
||||
LoadingCircle,
|
||||
LoadingWithIcon,
|
||||
} from "@renderer/components/ui/loading"
|
||||
import { getUrlIcon } from "@renderer/lib/utils"
|
||||
|
||||
export const EntryContentLoading = (props: { icon?: string }) => {
|
||||
if (!props.icon) {
|
||||
return (
|
||||
<LoadingWithIcon
|
||||
size="large"
|
||||
icon={<i className="i-mgc-sparkles-2-cute-re" />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className="center flex flex-col gap-4">
|
||||
<Avatar className="animate-pulse rounded-sm">
|
||||
<AvatarImage src={getUrlIcon(props.icon).src} />
|
||||
</Avatar>
|
||||
<LoadingCircle size="medium" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue