diff --git a/.gitignore b/.gitignore index 196742530..6bec08d32 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ buildServer.json apps/desktop/build/appxmanifest.xml .claude/settings.local.json +.serena diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/Items/all-item.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/Items/all-item.tsx index 9351cb857..b02bfaabb 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/Items/all-item.tsx +++ b/apps/desktop/layer/renderer/src/modules/entry-column/Items/all-item.tsx @@ -73,7 +73,7 @@ const entrySelector = (state: EntryModel) => { video, } } -export function AllItem({ entryId, translation }: UniversalItemProps) { +export function AllItem({ entryId, translation, currentFeedTitle }: UniversalItemProps) { const entry = useEntry(entryId, entrySelector) const simple = true @@ -132,32 +132,37 @@ export function AllItem({ entryId, translation }: UniversalItemProps) { const related = feed || inbox + const thisFeedTitle = getPreferredTitle(related, entry?.titleEntry) return (
- -
-
- - - + {currentFeedTitle !== thisFeedTitle && ( +
+ +
+ + + +
+ )} +
{entry.firstMedia && ( @@ -201,22 +206,26 @@ export function AllItem({ entryId, translation }: UniversalItemProps) { isRead && dimRead && "text-text-secondary", )} > - {entry?.title ? ( - - ) : ( - - )} + + {entry?.title ? ( + + ) : ( + + )} + {!!isInCollection && }
{!simple && ( diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/components/VirtualRowItem.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/components/VirtualRowItem.tsx index ba1d9a7e6..f35ae2fe9 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/components/VirtualRowItem.tsx +++ b/apps/desktop/layer/renderer/src/modules/entry-column/components/VirtualRowItem.tsx @@ -18,6 +18,7 @@ interface VirtualRowItemProps { isStickyItem: boolean isActiveStickyItem: boolean measureElement: (element: Element | null) => void + currentFeedTitle?: string } const EntryHeadDateItem: FC<{ @@ -50,6 +51,7 @@ export const VirtualRowItem: FC = memo( isStickyItem, isActiveStickyItem, measureElement, + currentFeedTitle, }) => { return ( @@ -76,6 +78,7 @@ export const VirtualRowItem: FC = memo( )} - + ) }) -export const EntryItem: FC = memo(({ entryId, view }) => { +export const EntryItem: FC = memo(({ entryId, view, currentFeedTitle }) => { const hasEntry = useHasEntry(entryId) if (!hasEntry) return null - return + return }) export const EntryVirtualListItem = ({ @@ -58,6 +57,7 @@ export const EntryVirtualListItem = ({ entryId, view, className, + currentFeedTitle, ...props }: EntryItemProps & React.DetailedHTMLProps, HTMLDivElement> & { @@ -69,7 +69,7 @@ export const EntryVirtualListItem = ({ return (
- +
) } diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx index ada22590a..e4e7b3e28 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx +++ b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx @@ -22,10 +22,11 @@ import { useFollow } from "~/hooks/biz/useFollow" import { getRouteParams, useRouteParams } from "~/hooks/biz/useRouteParams" import { COMMAND_ID } from "~/modules/command/commands/id" import { useRunCommandFn } from "~/modules/command/hooks/use-command" -import { useCommandShortcuts } from "~/modules/command/hooks/use-command-binding" +import { useCommandShortcut } from "~/modules/command/hooks/use-command-binding" import { EntryHeader } from "~/modules/entry-content/components/entry-header" +import { FeedIcon } from "~/modules/feed/feed-icon" import { useRefreshFeedMutation } from "~/queries/feed" -import { useFeedHeaderTitle } from "~/store/feed/hooks" +import { useFeedHeaderIcon, useFeedHeaderTitle } from "~/store/feed/hooks" import { MarkAllReadButton } from "../components/mark-all-button" import { useIsPreviewFeed } from "../hooks/useIsPreviewFeed" @@ -47,9 +48,11 @@ export const EntryListHeader: FC<{ const isPreview = useIsPreviewFeed() const headerTitle = useFeedHeaderTitle() + const feedIcon = useFeedHeaderIcon() const titleInfo = !!headerTitle && (
+ {feedIcon && } {headerTitle} @@ -73,7 +76,7 @@ export const EntryListHeader: FC<{ } const feedColumnShow = useSubscriptionColumnShow() - const commandShortcuts = useCommandShortcuts() + const toggleUnreadOnlyShortcut = useCommandShortcut(COMMAND_ID.timeline.unreadOnly) const runCmdFn = useRunCommandFn() const aiEnabled = useFeature("ai") @@ -149,7 +152,7 @@ export const EntryListHeader: FC<{ ? t("entry_list_header.show_unread_only") : t("entry_list_header.show_all") } - shortcut={commandShortcuts[COMMAND_ID.timeline.unreadOnly]} + shortcut={toggleUnreadOnlyShortcut} onClick={() => runCmdFn(COMMAND_ID.timeline.unreadOnly, [!unreadOnly])()} > {unreadOnly ? ( diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/list.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/list.tsx index 949a9aff0..af264aea0 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/list.tsx +++ b/apps/desktop/layer/renderer/src/modules/entry-column/list.tsx @@ -13,6 +13,7 @@ import { useEventCallback } from "usehooks-ts" import { useGeneralSettingKey } from "~/atoms/settings/general" import { m } from "~/components/common/Motion" +import { useFeedHeaderTitle } from "~/store/feed/hooks" import { VirtualRowItem } from "./components/VirtualRowItem" import { EntryColumnShortcutHandler } from "./EntryColumnShortcutHandler" @@ -187,6 +188,8 @@ export const EntryList: FC = memo( }) }, []) + const currentFeedTitle = useFeedHeaderTitle()! + return ( <>
= memo( isStickyItem={isStickyItem} isActiveStickyItem={isActiveStickyItem} measureElement={rowVirtualizer.measureElement} + currentFeedTitle={currentFeedTitle} /> ) })} diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/types.ts b/apps/desktop/layer/renderer/src/modules/entry-column/types.ts index 7a785d65c..fca34dd41 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/types.ts +++ b/apps/desktop/layer/renderer/src/modules/entry-column/types.ts @@ -6,6 +6,7 @@ import type { FC } from "react" export type UniversalItemProps = { entryId: string translation?: EntryTranslation + currentFeedTitle?: string } export type EntryListItemFC

= FC

& { diff --git a/apps/desktop/layer/renderer/src/store/feed/hooks.ts b/apps/desktop/layer/renderer/src/store/feed/hooks.ts index 045fe002f..f03bba752 100644 --- a/apps/desktop/layer/renderer/src/store/feed/hooks.ts +++ b/apps/desktop/layer/renderer/src/store/feed/hooks.ts @@ -1,9 +1,11 @@ import { views } from "@follow/constants" import type { EntryModel } from "@follow/store/entry/types" import { useFeedById, usePrefetchFeed } from "@follow/store/feed/hooks" +import { feedIconSelector } from "@follow/store/feed/selectors" import { useListById, usePrefetchListById } from "@follow/store/list/hooks" import { getSubscriptionByFeedId } from "@follow/store/subscription/getter" import { useTranslation } from "react-i18next" +import { useShallow } from "zustand/shallow" import { FEED_COLLECTION_LIST, @@ -64,3 +66,22 @@ export const useFeedHeaderTitle = () => { } } } + +export const useFeedHeaderIcon = () => { + const { feedId: currentFeedId, listId: currentListId } = useRouteParams() + + const feedIcon = useFeedById(currentFeedId, useShallow(feedIconSelector)) + const listIcon = useListById( + currentListId, + useShallow((feed) => ({ + type: feed.type, + ownerUserId: feed.ownerUserId, + id: feed.id, + title: feed.title, + url: (feed as any).url || "", + image: feed.image, + })), + ) + + return feedIcon || listIcon +}