From b14cb9ea1fb5fad8c2c5b1927661ee8a84707153 Mon Sep 17 00:00:00 2001 From: Ou Date: Mon, 28 Oct 2024 00:42:08 +0800 Subject: [PATCH] feat(ui): show diff position when refresh --- shared/types.ts | 1 + src/components/column/card.tsx | 53 +++++++++++++++++++++++++++++++--- src/styles/globals.css | 2 +- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/shared/types.ts b/shared/types.ts index 2f0e877..6905e04 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -93,6 +93,7 @@ export interface NewsItem { hover?: string date?: number | string info?: false | string + diff?: number icon?: false | string | { url: string scale: number diff --git a/src/components/column/card.tsx b/src/components/column/card.tsx index a051405..bce7a13 100644 --- a/src/components/column/card.tsx +++ b/src/components/column/card.tsx @@ -1,9 +1,9 @@ import type { NewsItem, SourceID, SourceResponse } from "@shared/types" import { useQuery } from "@tanstack/react-query" import clsx from "clsx" -import { useInView } from "framer-motion" +import { AnimatePresence, motion, useInView } from "framer-motion" import { useAtom } from "jotai" -import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef } from "react" +import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react" import { sources } from "@shared/sources" import type { SyntheticListenerMap } from "@dnd-kit/core/dist/hooks/utilities" import { ofetch } from "ofetch" @@ -54,6 +54,7 @@ export const CardWrapper = forwardRef(({ id, isDragg ) }) +const prevSourceItems: Partial> = {} function NewsCard({ id, inView, handleListeners }: NewsCardProps) { const [focusSources, setFocusSources] = useAtom(focusSourcesAtom) const [refetchSource, setRefetchSource] = useAtom(refetchSourcesAtom) @@ -72,10 +73,28 @@ function NewsCard({ id, inView, handleListeners }: NewsCardProps) { timeout: 10000, headers, }) + + try { + if (response.items && sources[_id].type === "hottest" && prevSourceItems[_id]) { + response.items.forEach((item, i) => { + const o = prevSourceItems[_id]!.findIndex(k => k.id === item.id) + item.extra = { + ...item?.extra, + diff: o === -1 ? undefined : o - i, + } + }) + } + } catch (e) { + console.log(e) + } + return response }, // refetch 时显示原有的数据 - placeholderData: prev => prev, + placeholderData: (prev) => { + if (prev?.items && sources[id].type === "hottest") prevSourceItems[id] = prev.items + return prev + }, staleTime: 1000 * 60 * 5, enabled: inView, }) @@ -162,6 +181,31 @@ function UpdatedTime({ isError, updatedTime }: { updatedTime: any, isError: bool return "加载中..." } +function DiffNumber({ diff }: { diff: number }) { + const [shown, setShown] = useState(true) + useEffect(() => { + setShown(true) + const timer = setTimeout(() => { + setShown(false) + }, 5000) + return () => clearTimeout(timer) + }, [setShown, diff]) + + return ( + + { shown && ( + + {diff > 0 ? `+${diff}` : diff} + + )} + + ) +} function ExtraInfo({ item }: { item: NewsItem }) { if (item?.extra?.info) { return <>{item.extra.info} @@ -196,13 +240,14 @@ function NewsListHot({ items }: { items: NewsItem[] }) { key={item.id} title={item.extra?.hover} className={clsx( - "flex gap-2 items-center mb-2 items-stretch", + "flex gap-2 items-center mb-2 items-stretch relative", "hover:bg-neutral-400/10 rounded-md pr-1 visited:(text-neutral-400)", )} > {i + 1} + {!!item.extra?.diff && } {item.title} diff --git a/src/styles/globals.css b/src/styles/globals.css index 6fe3b2d..5455692 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -50,4 +50,4 @@ button:disabled { #dropdown-menu li { --at-apply: hover:bg-neutral-400/10 rounded-md flex items-center p-1 gap-1; -} \ No newline at end of file +}