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 9f16ebf13..67e3246f9 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,7 +1,9 @@ import { useMobile } from "@follow/components/hooks/useMobile.js" -import { ActionButton } from "@follow/components/ui/button/index.js" +import { AutoResizeHeight } from "@follow/components/ui/auto-resize-height/index.js" +import { ActionButton, MotionButtonBase } from "@follow/components/ui/button/index.js" import { Skeleton } from "@follow/components/ui/skeleton/index.jsx" import type { MediaModel } from "@follow/shared/hono" +import { LRUCache } from "@follow/utils/lru-cache" import { cn } from "@follow/utils/utils" import { atom } from "jotai" import { useLayoutEffect, useMemo, useRef, useState } from "react" @@ -50,7 +52,7 @@ export const SocialMediaItem: EntryListItemFC = ({ entryId, entryPreview, transl if (ref.current) { jotaiStore.set(socialMediaContentWidthAtom, ref.current.offsetWidth) } - }, [ref.current]) + }, []) // NOTE: prevent 0 height element, react virtuoso will not stop render any more if (!entry || !feed) return @@ -101,12 +103,14 @@ export const SocialMediaItem: EntryListItemFC = ({ entryId, entryPreview, transl
- + + + {!!entry.collections && }
@@ -355,3 +359,50 @@ const SocialMediaGallery = ({ media }: { media: MediaModel[] }) => { ) } + +const collapsedHeight = 300 +const collapsedItemCache = new LRUCache(100) +const CollapsedSocialMediaItem: Component<{ + entryId: string +}> = ({ children, entryId }) => { + 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) + } + }, [children]) + + return ( + +
+ {children} +
+ {isOverflow && !isShowMore && ( +
+ { + setIsShowMore(true) + collapsedItemCache.put(entryId, true) + }} + aria-hidden + className="flex items-center justify-center text-xs" + > + + Show more + +
+ )} +
+ ) +} diff --git a/apps/renderer/src/modules/entry-column/index.tsx b/apps/renderer/src/modules/entry-column/index.tsx index 193fc9696..72ac94e57 100644 --- a/apps/renderer/src/modules/entry-column/index.tsx +++ b/apps/renderer/src/modules/entry-column/index.tsx @@ -1,6 +1,6 @@ import { useMobile } from "@follow/components/hooks/useMobile.js" import { Button } from "@follow/components/ui/button/index.js" -import { views } from "@follow/constants" +import { FeedViewType, views } from "@follow/constants" import { useTitle } from "@follow/hooks" import type { FeedModel } from "@follow/models/types" import { isBizId } from "@follow/utils/utils" @@ -187,6 +187,7 @@ function EntryColumnImpl() { ) ) : ( void groupCounts?: number[] + gap?: number Footer?: FC | ReactNode @@ -93,6 +94,7 @@ export const EntryList: FC = memo( Footer, listRef, onRangeChange, + gap, }) => { // Prevent scroll list move when press up/down key, the up/down key should be taken over by the shortcut key we defined. const handleKeyDown: React.KeyboardEventHandler = useCallback((e) => { @@ -121,6 +123,7 @@ export const EntryList: FC = memo( count: entriesIds.length + 1, estimateSize: () => 112, overscan: 5, + gap, getScrollElement: () => scrollRef, initialOffset: offsetCache.get(feedId) ?? 0, initialMeasurementsCache: measurementsCache.get(feedId) ?? [], diff --git a/configs/tailwind-extend.css b/configs/tailwind-extend.css index 8e60cf943..08a9e9b6d 100644 --- a/configs/tailwind-extend.css +++ b/configs/tailwind-extend.css @@ -395,3 +395,27 @@ animation: rocketAnimation 1s infinite ease-out; } } + +@layer components { + .mask-b { + mask-image: linear-gradient(rgb(255, 255, 255) calc(100% - 20px), rgba(255, 255, 255, 0) 100%); + } + + .mask-b-lg { + mask-image: linear-gradient(rgb(255, 255, 255) calc(100% - 50px), rgba(255, 255, 255, 0) 100%); + } + + .mask-b-xl { + mask-image: linear-gradient(rgb(255, 255, 255) calc(100% - 70px), rgba(255, 255, 255, 0) 100%); + } + + .mask-horizontal { + mask-image: linear-gradient( + 90deg, + rgba(255, 255, 255, 0) 0%, + rgba(255, 255, 255, 1) 14%, + rgba(255, 255, 255, 1) 86%, + rgba(255, 255, 255, 0) 100% + ); + } +}