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%
+ );
+ }
+}