feat: introduce media layout to unify video and picture layout
This commit is contained in:
parent
7eec68a830
commit
9ab7400a33
|
|
@ -30,18 +30,9 @@ import { EntryTitle } from "../EntryTitle"
|
|||
import { SupportCreator } from "../SupportCreator"
|
||||
import { MediaTranscript, TranscriptToggle, useTranscription } from "./shared"
|
||||
import { ArticleAudioPlayer } from "./shared/AudioPlayer"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
|
||||
interface ArticleLayoutProps {
|
||||
entryId: string
|
||||
compact?: boolean
|
||||
noMedia?: boolean
|
||||
translation?: {
|
||||
content?: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const ArticleLayout: React.FC<ArticleLayoutProps> = ({
|
||||
export const ArticleLayout: React.FC<EntryLayoutProps> = ({
|
||||
entryId,
|
||||
compact = false,
|
||||
noMedia = false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import { useEntry } from "@follow/store/entry/hooks"
|
||||
import { transformVideoUrl } from "@follow/utils/url-for-video"
|
||||
|
||||
import { ArticleLayout } from "./ArticleLayout"
|
||||
import { PicturesLayout } from "./PicturesLayout"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
import { VideosLayout } from "./VideosLayout"
|
||||
|
||||
export const MediaLayout: React.FC<EntryLayoutProps> = (props) => {
|
||||
const entry = useEntry(props.entryId, (state) => ({
|
||||
media: state.media,
|
||||
id: state.id,
|
||||
url: state.url,
|
||||
attachments: state.attachments,
|
||||
}))
|
||||
|
||||
if (!entry) return null
|
||||
|
||||
// Detect media types - more comprehensive video detection
|
||||
const hasVideoMedia = entry.media?.some((media) => media.type === "video")
|
||||
const hasVideoUrl =
|
||||
transformVideoUrl({
|
||||
url: entry.url ?? "",
|
||||
isIframe: true,
|
||||
attachments: entry.attachments,
|
||||
}) !== null
|
||||
const hasVideo = hasVideoMedia || hasVideoUrl
|
||||
const hasImages = entry.media?.some((media) => media.type === "photo")
|
||||
|
||||
// Video has absolute priority - show video whenever it exists, regardless of noMedia
|
||||
const shouldShowVideo = hasVideo
|
||||
const shouldShowImages = !hasVideo && hasImages && !props.noMedia
|
||||
|
||||
if (shouldShowVideo) {
|
||||
// Use VideosLayout for video content
|
||||
return <VideosLayout {...props} noMedia={false} />
|
||||
}
|
||||
|
||||
if (shouldShowImages) {
|
||||
// Use PicturesLayout for image content
|
||||
return <PicturesLayout {...props} />
|
||||
}
|
||||
|
||||
// Fallback: use ArticleLayout when no media content is detected
|
||||
return <ArticleLayout {...props} />
|
||||
}
|
||||
|
|
@ -6,18 +6,9 @@ import { SwipeMedia } from "~/components/ui/media/SwipeMedia"
|
|||
import { readableContentMaxWidthClassName } from "~/constants/ui"
|
||||
|
||||
import { AuthorHeader, ContentBody } from "./shared"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
|
||||
interface PicturesLayoutProps {
|
||||
entryId: string
|
||||
compact?: boolean
|
||||
noMedia?: boolean
|
||||
translation?: {
|
||||
content?: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const PicturesLayout: React.FC<PicturesLayoutProps> = ({
|
||||
export const PicturesLayout: React.FC<EntryLayoutProps> = ({
|
||||
entryId,
|
||||
compact = false,
|
||||
noMedia = false,
|
||||
|
|
|
|||
|
|
@ -7,18 +7,9 @@ import { readableContentMaxWidthClassName } from "~/constants/ui"
|
|||
|
||||
import { AuthorHeader } from "./shared/AuthorHeader"
|
||||
import { ContentBody } from "./shared/ContentBody"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
|
||||
interface SocialMediaLayoutProps {
|
||||
entryId: string
|
||||
compact?: boolean
|
||||
noMedia?: boolean
|
||||
translation?: {
|
||||
content?: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const SocialMediaLayout: React.FC<SocialMediaLayoutProps> = ({
|
||||
export const SocialMediaLayout: React.FC<EntryLayoutProps> = ({
|
||||
entryId,
|
||||
compact = false,
|
||||
noMedia = false,
|
||||
|
|
|
|||
|
|
@ -4,18 +4,9 @@ import { useState } from "react"
|
|||
import { EntryTitle } from "../EntryTitle"
|
||||
import { ContentBody, MediaTranscript, TranscriptToggle, useTranscription } from "./shared"
|
||||
import { VideoPlayer } from "./shared/VideoPlayer"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
|
||||
interface VideosLayoutProps {
|
||||
entryId: string
|
||||
compact?: boolean
|
||||
noMedia?: boolean
|
||||
translation?: {
|
||||
content?: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const VideosLayout: React.FC<VideosLayoutProps> = ({
|
||||
export const VideosLayout: React.FC<EntryLayoutProps> = ({
|
||||
entryId,
|
||||
compact = false,
|
||||
noMedia = false,
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
import { FeedViewType } from "@follow/constants"
|
||||
import type { FC } from "react"
|
||||
|
||||
import { ArticleLayout } from "./ArticleLayout"
|
||||
import { PicturesLayout } from "./PicturesLayout"
|
||||
import { MediaLayout } from "./MediaLayout"
|
||||
import { SocialMediaLayout } from "./SocialMediaLayout"
|
||||
import { VideosLayout } from "./VideosLayout"
|
||||
import type { EntryLayoutProps } from "./types"
|
||||
|
||||
const EntryContentLayoutFactory = {
|
||||
type EntryLayoutComponent = FC<EntryLayoutProps>
|
||||
|
||||
const EntryContentLayoutFactory: Record<FeedViewType, EntryLayoutComponent> = {
|
||||
[FeedViewType.All]: ArticleLayout, // Use article layout as fallback for all view
|
||||
[FeedViewType.Articles]: ArticleLayout,
|
||||
[FeedViewType.SocialMedia]: SocialMediaLayout,
|
||||
[FeedViewType.Pictures]: PicturesLayout,
|
||||
[FeedViewType.Videos]: VideosLayout,
|
||||
[FeedViewType.Pictures]: MediaLayout, // Use unified media layout for pictures
|
||||
[FeedViewType.Videos]: MediaLayout, // Use unified media layout for videos
|
||||
[FeedViewType.Audios]: ArticleLayout, // Use article layout as fallback for audio
|
||||
[FeedViewType.Notifications]: ArticleLayout, // Use article layout as fallback for notifications
|
||||
}
|
||||
|
||||
export const getEntryContentLayout = (viewType: FeedViewType) => {
|
||||
export const getEntryContentLayout = (viewType: FeedViewType): EntryLayoutComponent => {
|
||||
return EntryContentLayoutFactory[viewType] || ArticleLayout
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* Shared props interface for all entry content layout components
|
||||
*/
|
||||
export interface EntryLayoutProps {
|
||||
entryId: string
|
||||
compact?: boolean
|
||||
noMedia?: boolean
|
||||
translation?: {
|
||||
content?: string
|
||||
title?: string
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue