mono/packages/ui/src/modules/posts/views/renderers/CompactRenderer.tsx
2026-03-21 20:18:25 +01:00

190 lines
9.8 KiB
TypeScript

import React, { } from "react";
import { useNavigate } from "react-router-dom";
import { useOrganization } from "@/contexts/OrganizationContext";
import { PostRendererProps } from '../types';
import { useMediaQuery } from "@/hooks/use-media-query";
import { isVideoType, normalizeMediaType, detectMediaType } from "@/lib/mediaRegistry";
// Extracted Components
import { MobileGroupedFeed } from "./components/MobileGroupedFeed";
import { CompactPostHeader } from "./components/CompactPostHeader";
import { CompactMediaDetails } from "./components/CompactMediaDetails";
import { Gallery } from "./components/Gallery";
// Lazy load ImageEditor
const ImageEditor = React.lazy(() => import("@/components/ImageEditor").then(module => ({ default: module.ImageEditor })));
export const CompactRenderer: React.FC<PostRendererProps> = (props) => {
const {
post, authorProfile, mediaItems, mediaItem,
isOwner, isLiked, likesCount,
onEditPost, onViewModeChange, onExportMarkdown,
onDeletePost, onDeletePicture, onLike, onEditPicture,
onMediaSelect, onExpand, onDownload, onCategoryManagerOpen,
currentImageIndex, videoPlaybackUrl, videoPosterUrl,
versionImages, handlePrevImage, handleNavigate, navigationData,
isEditMode, localPost, setLocalPost, localMediaItems, setLocalMediaItems, onMoveItem,
onEditModeToggle, onSaveChanges, onGalleryPickerOpen
} = props;
const [expandedComments, setExpandedComments] = React.useState<Record<string, boolean>>({});
const [expandedDescriptions, setExpandedDescriptions] = React.useState<Record<string, boolean>>({});
const [showImageEditor, setShowImageEditor] = React.useState(false);
const [cacheBustKeys, setCacheBustKeys] = React.useState<Record<string, number>>({});
const navigate = useNavigate();
const { orgSlug } = useOrganization();
const isDesktop = useMediaQuery("(min-width: 1024px)");
const showDesktopLayout = isDesktop;
const effectiveType = mediaItem.type || detectMediaType(mediaItem.image_url);
const isVideo = isVideoType(normalizeMediaType(effectiveType));
return (
<div className={props.className || 'h-[inherit]'}>
{/* Mobile Header - Controls and Info at Top */}
<div className="lg:hidden landscape:hidden py-4 bg-card ">
<CompactPostHeader
isEditMode={!!isEditMode}
post={post}
localPost={localPost}
setLocalPost={setLocalPost!}
mediaItem={mediaItem}
authorProfile={authorProfile!}
isOwner={!!isOwner}
embedded={props.embedded}
onViewModeChange={onViewModeChange!}
onExportMarkdown={onExportMarkdown!}
onSaveChanges={onSaveChanges!}
onEditModeToggle={onEditModeToggle!}
onEditPost={onEditPost!}
onDeletePicture={onDeletePicture!}
onDeletePost={onDeletePost!}
onCategoryManagerOpen={onCategoryManagerOpen}
mediaItems={mediaItems}
localMediaItems={localMediaItems}
/>
</div>
{/* Desktop layout: Media on left, content on right */}
<div className="overflow-hidden-x group h-[inherit]">
<div className="grid grid-cols-1 lg:grid-cols-2 h-[inherit]">
{/* Left Column - Media */}
<div className={`${isVideo ? 'aspect-video' : 'aspect-square'} lg:aspect-auto bg-background border flex flex-col relative h-full w-full`}>
{/* Desktop Gallery - Combines Media Viewer + Filmstrip */}
<div className="hidden lg:block h-full">
<Gallery
mediaItems={mediaItems}
selectedItem={mediaItem}
onMediaSelect={onMediaSelect}
onExpand={onExpand}
isOwner={!!isOwner}
isEditMode={!!isEditMode}
localMediaItems={localMediaItems}
setLocalMediaItems={setLocalMediaItems}
onDeletePicture={onDeletePicture!}
onGalleryPickerOpen={onGalleryPickerOpen!}
cacheBustKeys={cacheBustKeys}
navigationData={navigationData}
handleNavigate={handleNavigate!}
navigate={navigate}
videoPlaybackUrl={videoPlaybackUrl}
videoPosterUrl={videoPosterUrl}
showDesktopLayout={!!showDesktopLayout}
/>
</div>
{/* Mobile View - Grouped Feed - Hidden on Desktop */}
<MobileGroupedFeed
mediaItems={mediaItems}
isOwner={!!isOwner}
isLiked={!!isLiked}
onMediaSelect={onMediaSelect}
onLike={onLike}
onDeletePicture={onDeletePicture!}
onGalleryPickerOpen={onGalleryPickerOpen!}
onExpand={onExpand}
onEditPicture={onEditPicture!}
onDownload={onDownload!}
setShowImageEditor={setShowImageEditor}
post={post}
orgSlug={orgSlug}
expandedComments={expandedComments}
setExpandedComments={setExpandedComments}
expandedDescriptions={expandedDescriptions}
setExpandedDescriptions={setExpandedDescriptions}
cacheBustKeys={cacheBustKeys}
/>
</div>
{/* Right Column - Content */}
<div className="hidden lg:flex landscape:flex flex-col lg:h-full landscape:h-full lg:overflow-y-auto landscape:overflow-y-auto scrollbar-custom">
<div className="hidden lg:block landscape:block">
<CompactPostHeader
isEditMode={!!isEditMode}
post={post}
localPost={localPost}
setLocalPost={setLocalPost!}
mediaItem={mediaItem}
authorProfile={authorProfile!}
isOwner={!!isOwner}
embedded={props.embedded}
onViewModeChange={onViewModeChange!}
onExportMarkdown={onExportMarkdown!}
onSaveChanges={onSaveChanges!}
onEditModeToggle={onEditModeToggle!}
onEditPost={onEditPost!}
onDeletePicture={onDeletePicture!}
onDeletePost={onDeletePost!}
onCategoryManagerOpen={onCategoryManagerOpen}
mediaItems={mediaItems}
localMediaItems={localMediaItems}
/>
</div>
<CompactMediaDetails
isEditMode={!!isEditMode}
localMediaItems={localMediaItems}
setLocalMediaItems={setLocalMediaItems}
mediaItem={mediaItem}
versionImages={versionImages} // @ts-ignore or fix upstream
isLiked={!!isLiked}
likesCount={likesCount}
onLike={onLike}
onExpand={onExpand}
isOwner={!!isOwner}
setShowImageEditor={setShowImageEditor}
onDeletePicture={onDeletePicture!}
onAddAfter={() => onGalleryPickerOpen!(currentImageIndex + 1)}
onEditPicture={onEditPicture!}
onDownload={onDownload!}
isVideo={isVideo}
post={post}
orgSlug={orgSlug}
embedded={!!props.embedded}
/>
</div>
</div>
</div>
{showImageEditor && (
<div className="fixed inset-0 z-[100] bg-background">
<React.Suspense fallback={<div className="flex items-center justify-center h-full"><div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div></div>}>
<ImageEditor
imageUrl={mediaItem.image_url}
pictureId={mediaItem.id}
onClose={() => setShowImageEditor(false)}
onSave={() => {
setCacheBustKeys(prev => ({ ...prev, [mediaItem.id]: Date.now() }));
setShowImageEditor(false);
onLike();
}}
/>
</React.Suspense>
</div>
)}
</div>
);
}