From 922df61be0328cd8159208b13e7db8641f09bebe Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 10 Sep 2025 17:41:07 +0800 Subject: [PATCH] feat: audio and video icon in all item --- .../modules/entry-column/Items/all-item.tsx | 102 ++++++++++++++---- .../entry-column/layouts/EntryItemWrapper.tsx | 5 +- icons/mgc/music_2_cute_fi.svg | 1 + icons/mgc/video_cute_re.svg | 1 + 4 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 icons/mgc/music_2_cute_fi.svg create mode 100644 icons/mgc/video_cute_re.svg 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 d06520a2a..ba132b534 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 @@ -7,15 +7,18 @@ import { TooltipTrigger, } from "@follow/components/ui/tooltip/index.js" import { EllipsisHorizontalTextWithTooltip } from "@follow/components/ui/typography/index.js" +import { IN_ELECTRON } from "@follow/shared/constants" import { useCollectionEntry, useIsEntryStarred } from "@follow/store/collection/hooks" import { useEntry } from "@follow/store/entry/hooks" import type { EntryModel } from "@follow/store/entry/types" import { useFeedById } from "@follow/store/feed/hooks" import { useInboxById } from "@follow/store/inbox/hooks" +import { transformVideoUrl } from "@follow/utils/url-for-video" import { cn, isSafari } from "@follow/utils/utils" import { useMemo } from "react" import { titleCase } from "title-case" +import { AudioPlayer, useAudioPlayerAtomSelector } from "~/atoms/player" import { useGeneralSettingKey } from "~/atoms/settings/general" import { useUISettingKey } from "~/atoms/settings/ui" import { RelativeTime } from "~/components/ui/datetime" @@ -34,11 +37,19 @@ import { readableContentMaxWidth } from "../styles" import type { EntryItemStatelessProps, UniversalItemProps } from "../types" import { MediaGallery } from "./media-gallery" +const ViewTag = IN_ELECTRON ? "webview" : "iframe" + const entrySelector = (state: EntryModel) => { const { feedId, inboxHandle, read } = state const { authorAvatar, authorUrl, description, publishedAt, title } = state const audios = state.attachments?.filter((a) => a.mime_type?.startsWith("audio") && a.url) + const video = transformVideoUrl({ + url: state?.url ?? "", + isIframe: !IN_ELECTRON, + attachments: state?.attachments, + mini: true, + }) const firstAudio = audios?.[0] const media = state.media || [] const firstMedia = media?.[0] @@ -59,6 +70,7 @@ const entrySelector = (state: EntryModel) => { read, title, titleEntry, + video, } } export function AllItem({ entryId, entryPreview, translation }: UniversalItemProps) { @@ -179,28 +191,8 @@ export function AllItem({ entryId, entryPreview, translation }: UniversalItemPro )} - {/* TODO */} - {/* {hasAudio && entry.firstAudio && ( - - } - feed={feed || inbox} - entry={entry?.iconEntry} - size={80} - className="m-0 rounded" - useMedia - noMargin - /> - } - /> - )} */} + {entry.firstAudio && } + {entry.video && }
) + +function AudioIcon({ entryId, src }: { entryId: string; src: string }) { + const playStatus = useAudioPlayerAtomSelector((playerValue) => + playerValue.src === src && playerValue.show ? playerValue.status : false, + ) + + const handleClickPlay = (e: React.MouseEvent) => { + e.stopPropagation() + e.preventDefault() + if (!playStatus) { + // switch this to play + AudioPlayer.mount({ + type: "audio", + entryId, + src, + currentTime: 0, + }) + } else { + // switch between play and pause + AudioPlayer.togglePlayAndPause() + } + } + + return ( +
+
+ +
+
+ ) +} + +function VideoIcon({ src }: { src: string }) { + return ( + + + + + + + +
+ +
+
+
+
+
+ ) +} diff --git a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx index 1ef9da01c..ad6d7bf92 100644 --- a/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx +++ b/apps/desktop/layer/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx @@ -252,7 +252,10 @@ const ActionBar = ({ entryId }: { entryId: string }) => { animate={{ opacity: 1, scale: 1, translateY: "-1/2" }} exit={{ opacity: 0, scale: 0.9, translateY: "-1/2" }} transition={Spring.presets.smooth} - className="absolute -right-2 top-0 -translate-y-1/2 rounded-lg border border-gray-200 bg-white/90 p-1 shadow-sm backdrop-blur-sm dark:border-neutral-900 dark:bg-neutral-900" + className={cn( + "absolute -right-2 top-0 -translate-y-1/2 rounded-lg border border-gray-200 bg-white/90 p-1 shadow-sm backdrop-blur-sm dark:border-neutral-900 dark:bg-neutral-900", + view === FeedViewType.All && "top-1/2", + )} onClick={(e) => { e.stopPropagation() e.preventDefault() diff --git a/icons/mgc/music_2_cute_fi.svg b/icons/mgc/music_2_cute_fi.svg new file mode 100644 index 000000000..08c8bc260 --- /dev/null +++ b/icons/mgc/music_2_cute_fi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icons/mgc/video_cute_re.svg b/icons/mgc/video_cute_re.svg new file mode 100644 index 000000000..863cf8939 --- /dev/null +++ b/icons/mgc/video_cute_re.svg @@ -0,0 +1 @@ + \ No newline at end of file