diff --git a/apps/renderer/src/atoms/settings/general.ts b/apps/renderer/src/atoms/settings/general.ts index 1e7552015c..af799a8365 100644 --- a/apps/renderer/src/atoms/settings/general.ts +++ b/apps/renderer/src/atoms/settings/general.ts @@ -26,8 +26,9 @@ const createDefaultSettings = (): GeneralSettings => ({ hoverMarkUnread: true, renderMarkUnread: false, // UX - groupByDate: true, + autoExpandLongSocialMedia: false, + // Secure jumpOutLinkWarn: true, // TTS diff --git a/apps/renderer/src/components/ui/placeholder.tsx b/apps/renderer/src/components/ui/placeholder.tsx deleted file mode 100644 index 55a90a5ae2..0000000000 --- a/apps/renderer/src/components/ui/placeholder.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export const ReactVirtuosoItemPlaceholder = () => ( - // NOTE: prevent 0 height element, react virtuoso will not stop render any more -
-) diff --git a/apps/renderer/src/modules/entry-column/Items/picture-item.tsx b/apps/renderer/src/modules/entry-column/Items/picture-item.tsx index 1388e0fca2..57d84546ae 100644 --- a/apps/renderer/src/modules/entry-column/Items/picture-item.tsx +++ b/apps/renderer/src/modules/entry-column/Items/picture-item.tsx @@ -13,7 +13,6 @@ import { memo, useContext, useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { SwipeMedia } from "~/components/ui/media/SwipeMedia" -import { ReactVirtuosoItemPlaceholder } from "~/components/ui/placeholder" import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams" import { filterSmallMedia } from "~/lib/utils" import { EntryContent } from "~/modules/entry-content" @@ -33,7 +32,7 @@ export function PictureItem({ entryId, entryPreview, translation }: UniversalIte const { t } = useTranslation() const entryContent = useMemo(() => , [entryId]) const previewMedia = usePreviewMedia(entryContent) - if (!entry) return + if (!entry) return null return (
diff --git a/apps/renderer/src/modules/entry-column/Items/social-media-item.tsx b/apps/renderer/src/modules/entry-column/Items/social-media-item.tsx index d58220000a..35665fc7b4 100644 --- a/apps/renderer/src/modules/entry-column/Items/social-media-item.tsx +++ b/apps/renderer/src/modules/entry-column/Items/social-media-item.tsx @@ -1,3 +1,4 @@ +import { PassviseFragment } from "@follow/components/common/Fragment.js" import { useMobile } from "@follow/components/hooks/useMobile.js" import { AutoResizeHeight } from "@follow/components/ui/auto-resize-height/index.js" import { ActionButton } from "@follow/components/ui/button/index.js" @@ -9,6 +10,7 @@ import { atom } from "jotai" import { useLayoutEffect, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" +import { useGeneralSettingKey } from "~/atoms/settings/general" import { RelativeTime } from "~/components/ui/datetime" import { Media } from "~/components/ui/media" import { usePreviewMedia } from "~/components/ui/media/hooks" @@ -23,7 +25,6 @@ import { FeedTitle } from "~/modules/feed/feed-title" import { useEntry } from "~/store/entry/hooks" import { useFeedById } from "~/store/feed" -import { ReactVirtuosoItemPlaceholder } from "../../../components/ui/placeholder" import { filterSmallMedia } from "../../../lib/utils" import { StarIcon } from "../star-icon" import { EntryTranslation } from "../translation" @@ -52,14 +53,17 @@ export const SocialMediaItem: EntryListItemFC = ({ entryId, entryPreview, transl jotaiStore.set(socialMediaContentWidthAtom, ref.current.offsetWidth) } }, []) - // NOTE: prevent 0 height element, react virtuoso will not stop render any more - if (!entry || !feed) return + const autoExpandLongSocialMedia = useGeneralSettingKey("autoExpandLongSocialMedia") + + if (!entry || !feed) return null const content = entry.entries.content || entry.entries.description const parsed = parseSocialMedia(entry.entries) - const media = filterSmallMedia(entry.entries.media) + const EntryContentWrapper = autoExpandLongSocialMedia + ? PassviseFragment + : CollapsedSocialMediaItem return (
- + - + {!!entry.collections && }
@@ -368,6 +372,7 @@ const CollapsedSocialMediaItem: Component<{ const [isOverflow, setIsOverflow] = useState(false) const [isShowMore, setIsShowMore] = useState(() => collapsedItemCache.get(entryId) ?? false) const ref = useRef(null) + useLayoutEffect(() => { if (ref.current) { setIsOverflow(ref.current.scrollHeight > collapsedHeight) diff --git a/apps/renderer/src/modules/entry-column/Items/video-item.tsx b/apps/renderer/src/modules/entry-column/Items/video-item.tsx index 719205a787..d9ee52cb6e 100644 --- a/apps/renderer/src/modules/entry-column/Items/video-item.tsx +++ b/apps/renderer/src/modules/entry-column/Items/video-item.tsx @@ -20,7 +20,6 @@ import { FeedIcon } from "~/modules/feed/feed-icon" import { FeedTitle } from "~/modules/feed/feed-title" import { useEntry } from "~/store/entry/hooks" -import { ReactVirtuosoItemPlaceholder } from "../../../components/ui/placeholder" import { GridItem } from "../templates/grid-item-template" import type { EntryItemStatelessProps, UniversalItemProps } from "../types" @@ -62,7 +61,7 @@ export function VideoItem({ entryId, entryPreview, translation }: UniversalItemP } }, [hovered]) - if (!entry) return + if (!entry) return null return (
= memo(({ entryId, view }) => { const entry = useEntry(entryId) - if (!entry) return + if (!entry) return null return }) diff --git a/apps/renderer/src/modules/entry-column/templates/grid-item-template.tsx b/apps/renderer/src/modules/entry-column/templates/grid-item-template.tsx index ebe3735300..4e32720bce 100644 --- a/apps/renderer/src/modules/entry-column/templates/grid-item-template.tsx +++ b/apps/renderer/src/modules/entry-column/templates/grid-item-template.tsx @@ -2,7 +2,6 @@ import { TitleMarquee } from "@follow/components/ui/marquee/index.jsx" import { cn } from "@follow/utils/utils" import dayjs from "dayjs" -import { ReactVirtuosoItemPlaceholder } from "~/components/ui/placeholder" import { useAsRead } from "~/hooks/biz/useAsRead" import { EntryTranslation } from "~/modules/entry-column/translation" import { FeedIcon } from "~/modules/feed/feed-icon" @@ -21,7 +20,7 @@ export function GridItem(props: GridItemProps) { const { entryId, entryPreview, wrapperClassName, children, translation } = props const entry = useEntry(entryId) || entryPreview - if (!entry) return + if (!entry) return null return (
{children} diff --git a/apps/renderer/src/modules/entry-column/templates/list-item-template.tsx b/apps/renderer/src/modules/entry-column/templates/list-item-template.tsx index 99aec78ddc..e97d1b0852 100644 --- a/apps/renderer/src/modules/entry-column/templates/list-item-template.tsx +++ b/apps/renderer/src/modules/entry-column/templates/list-item-template.tsx @@ -17,7 +17,6 @@ import { useEntry } from "~/store/entry/hooks" import { getPreferredTitle, useFeedById } from "~/store/feed" import { useInboxById } from "~/store/inbox" -import { ReactVirtuosoItemPlaceholder } from "../../../components/ui/placeholder" import { StarIcon } from "../star-icon" import type { UniversalItemProps } from "../types" @@ -79,7 +78,7 @@ export function ListItem({ }, [translation?.title, translation?.description, settingWideMode]) // NOTE: prevent 0 height element, react virtuoso will not stop render any more - if (!entry || !(feed || inbox)) return + if (!entry || !(feed || inbox)) return null const displayTime = inInCollection ? entry.collections?.createdAt : entry.entries.publishedAt diff --git a/apps/renderer/src/modules/settings/tabs/general.tsx b/apps/renderer/src/modules/settings/tabs/general.tsx index 7eff98c86f..5c75ab4da1 100644 --- a/apps/renderer/src/modules/settings/tabs/general.tsx +++ b/apps/renderer/src/modules/settings/tabs/general.tsx @@ -91,6 +91,11 @@ export const SettingGeneral = () => { label: t("general.group_by_date.label"), description: t("general.group_by_date.description"), }), + + defineSettingItem("autoExpandLongSocialMedia", { + label: t("general.auto_expand_long_social_media.label"), + description: t("general.auto_expand_long_social_media.description"), + }), isMobile && defineSettingItem("showQuickTimeline", { label: t("general.show_quick_timeline.label"), diff --git a/changelog/next.md b/changelog/next.md index 7dd8188c3d..279af4e0fd 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -3,6 +3,7 @@ ## New Features - New `Move to Category` operation in feed subscription context menu +- New `Expand long social media` setting to automatically expand social media entries containing long text. ## Improvements diff --git a/locales/settings/en.json b/locales/settings/en.json index 7b45b484b7..7bff7b3d06 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -107,6 +107,8 @@ "feeds.tableHeaders.subscriptionCount": "Subs", "feeds.tableHeaders.tipAmount": "Tips", "general.app": "App", + "general.auto_expand_long_social_media.description": "Automatically expand social media entries containing long text.", + "general.auto_expand_long_social_media.label": "Expand long social media", "general.auto_group.description": "Automatically group feeds by site domain.", "general.auto_group.label": "Auto Group", "general.cache": "Cache", diff --git a/locales/settings/zh-CN.json b/locales/settings/zh-CN.json index 7205e0802f..a6aec49370 100644 --- a/locales/settings/zh-CN.json +++ b/locales/settings/zh-CN.json @@ -107,6 +107,8 @@ "feeds.tableHeaders.subscriptionCount": "订阅数", "feeds.tableHeaders.tipAmount": "收到的打赏", "general.app": "应用程序", + "general.auto_expand_long_social_media.description": "自动展开包含长文本的社交媒体条目。", + "general.auto_expand_long_social_media.label": "展开长社交媒体", "general.auto_group.description": "自动按网站域名分组订阅源。", "general.auto_group.label": "自动分组", "general.cache": "缓存", diff --git a/packages/components/src/common/Fragment.ts b/packages/components/src/common/Fragment.ts new file mode 100644 index 0000000000..9d44ab04a3 --- /dev/null +++ b/packages/components/src/common/Fragment.ts @@ -0,0 +1,6 @@ +import * as React from "react" +import { createElement } from "react" + +export const PassviseFragment = ({ children }: { children: React.ReactNode }) => { + return createElement(React.Fragment, null, children) +} diff --git a/packages/shared/src/interface/settings.ts b/packages/shared/src/interface/settings.ts index dcc8736b7a..702c7dba5a 100644 --- a/packages/shared/src/interface/settings.ts +++ b/packages/shared/src/interface/settings.ts @@ -19,6 +19,10 @@ export interface GeneralSettings { * Top timeline for mobile */ showQuickTimeline: boolean + /** + * Auto expand long social media + */ + autoExpandLongSocialMedia: boolean } export interface UISettings {