{/* Likes */}
@@ -641,11 +652,11 @@ const VideoCard = ({
{/* Caption / Description section */}
- {(!isLikelyFilename(title) && title) && (
+ {showTitle && (!isLikelyFilename(title) && title) && (
{title}
)}
- {description && (
+ {showDescription && description && (
diff --git a/packages/ui/src/components/feed/FeedCard.tsx b/packages/ui/src/components/feed/FeedCard.tsx
index 11bf4344..b4cc5ddf 100644
--- a/packages/ui/src/components/feed/FeedCard.tsx
+++ b/packages/ui/src/components/feed/FeedCard.tsx
@@ -1,12 +1,16 @@
import React, { useState } from 'react';
import { FeedPost } from '@/modules/posts/client-posts';
import { FeedCarousel } from './FeedCarousel';
-import { Heart } from 'lucide-react';
+import { Heart, MessageCircle } from 'lucide-react';
+import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
-import * as db from '@/lib/db';
import { useNavigate } from "react-router-dom";
import { normalizeMediaType } from "@/lib/mediaRegistry";
import { toggleLike } from '@/modules/posts/client-pictures';
+import UserAvatarBlock from '@/components/UserAvatarBlock';
+import MarkdownRenderer from '@/components/MarkdownRenderer';
+import { formatDate } from '@/utils/textUtils';
+import { T } from '@/i18n';
interface FeedCardProps {
post: FeedPost;
@@ -15,13 +19,17 @@ interface FeedCardProps {
onComment?: () => void;
onShare?: () => void;
onNavigate?: (id: string) => void;
+ showTitle?: boolean;
+ showDescription?: boolean;
}
export const FeedCard: React.FC
= ({
post,
currentUserId,
onLike,
- onNavigate
+ onNavigate,
+ showTitle = false,
+ showDescription = false,
}) => {
const navigate = useNavigate();
// Initialize from precomputed status (post.cover.is_liked or post.is_liked)
@@ -104,7 +112,18 @@ export const FeedCard: React.FC = ({
return (
-
+ {/* Header: Author Info */}
+
+
+
+ {post.created_at ? formatDate(post.created_at) : ''}
+
+
{/* Media Carousel */}
@@ -116,18 +135,52 @@ export const FeedCard: React.FC
= ({
authorId={post.user_id}
authorAvatarUrl={post.author?.avatar_url}
onItemClick={handleItemClick}
+ showContent={false} // Silence internal card UI
+ showAuthor={false}
+ showActions={false}
+ showTitle={false}
+ showDescription={false}
/>
-
- {/* Double tap heart animation overlay */}
-
-
-
- {/* Actions Bar - Removed as actions are now per-item in the carousel */}
+ {/* Actions Bar */}
+
+
+ {likeCount > 0 && (
+ {likeCount}
+ )}
+
+
+
+
+ {/* Caption: Title & Description */}
+
+ {showTitle && post.title && (
+
{post.title}
+ )}
+ {showDescription && post.description && (
+
+
+
+ )}
+
);
};
diff --git a/packages/ui/src/components/feed/FeedCarousel.tsx b/packages/ui/src/components/feed/FeedCarousel.tsx
index 10a97ed7..70e27bb6 100644
--- a/packages/ui/src/components/feed/FeedCarousel.tsx
+++ b/packages/ui/src/components/feed/FeedCarousel.tsx
@@ -14,6 +14,10 @@ interface CarouselProps {
authorAvatarUrl?: string | null;
onItemClick?: (id: string) => void;
showContent?: boolean;
+ showTitle?: boolean;
+ showDescription?: boolean;
+ showAuthor?: boolean;
+ showActions?: boolean;
}
export const FeedCarousel: React.FC = ({
@@ -25,7 +29,11 @@ export const FeedCarousel: React.FC = ({
authorId,
authorAvatarUrl,
onItemClick,
- showContent = true
+ showContent = true,
+ showTitle,
+ showDescription,
+ showAuthor,
+ showActions
}) => {
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: false });
const [selectedIndex, setSelectedIndex] = useState(0);
@@ -92,6 +100,10 @@ export const FeedCarousel: React.FC = ({
description={item.description}
created_at={item.created_at}
showContent={showContent}
+ showTitle={showTitle}
+ showDescription={showDescription}
+ showAuthor={showAuthor}
+ showActions={showActions}
onClick={onItemClick}
job={item.job}
responsive={item.responsive}
diff --git a/packages/ui/src/components/feed/MobileFeed.tsx b/packages/ui/src/components/feed/MobileFeed.tsx
index 0a1180dd..9f895b80 100644
--- a/packages/ui/src/components/feed/MobileFeed.tsx
+++ b/packages/ui/src/components/feed/MobileFeed.tsx
@@ -20,10 +20,10 @@ interface MobileFeedProps {
contentType?: 'posts' | 'pages' | 'pictures' | 'files';
visibilityFilter?: 'invisible' | 'private';
center?: boolean;
+ showTitle?: boolean;
+ showDescription?: boolean;
}
-const PRELOAD_BUFFER = 3;
-
export const MobileFeed: React.FC = ({
source = 'home',
sourceId,
@@ -33,7 +33,9 @@ export const MobileFeed: React.FC = ({
categoryIds,
contentType,
visibilityFilter,
- center
+ center,
+ showTitle,
+ showDescription,
}) => {
const { user } = useAuth();
@@ -140,6 +142,8 @@ export const MobileFeed: React.FC = ({
posts={posts}
currentUser={user}
onNavigate={onNavigate}
+ showTitle={showTitle}
+ showDescription={showDescription}
/>
));
}
@@ -148,8 +152,8 @@ export const MobileFeed: React.FC = ({
if (item.type === 'page-vfs-folder') return 'Folders';
if (item._searchSource === 'picture') return 'Pictures';
if (item._searchSource === 'file') {
- if (item.thumbnail_url || item.cover || (item.pictures && item.pictures.length > 0)) return 'Pictures';
- return 'Files';
+ if (item.thumbnail_url || item.cover || (item.pictures && item.pictures.length > 0)) return 'Pictures';
+ return 'Files';
}
if (item._searchSource === 'page') return 'Pages';
if (item._searchSource === 'post') return 'Posts';
@@ -168,13 +172,13 @@ export const MobileFeed: React.FC = ({
for (const group of orderedGroups) {
if (groups.has(group)) {
- elements.push(
+ elements.push(
{group}
- );
- elements.push(
- ...groups.get(group)!.map((post: any, index: number) => (
+ );
+ elements.push(
+ ...groups.get(group)!.map((post: any, index: number) => (
= ({
posts={posts}
currentUser={user}
onNavigate={onNavigate}
+ showTitle={showTitle}
+ showDescription={showDescription}
/>
- ))
- );
+ ))
+ );
}
}
@@ -204,38 +210,24 @@ const FeedItemWrapper: React.FC<{
index: number,
posts: FeedPost[],
currentUser: any,
- onNavigate?: (id: string) => void
-}> = ({ post, index, posts, currentUser, onNavigate }) => {
- const { ref, inView } = useInView({
+ onNavigate?: (id: string) => void;
+ showTitle?: boolean;
+ showDescription?: boolean;
+}> = ({ post, index, posts, currentUser, onNavigate, showTitle, showDescription }) => {
+ const { ref } = useInView({
triggerOnce: false,
- rootMargin: '200px 0px', // Trigger slightly before
+ rootMargin: '200px 0px',
threshold: 0.1
});
- useEffect(() => {
- /*
- if (inView) {
- // Preload next 5 posts' Main Image
- const bufferEnd = Math.min(index + 1 + PRELOAD_BUFFER, posts.length);
- for (let i = index + 1; i < bufferEnd; i++) {
- const nextPost = posts[i];
- if (nextPost.cover?.image_url) {
- const img = new Image();
- img.src = nextPost.cover.image_url;
- }
- // If the next post has multiple images, maybe preload the second one too?
- // Keeping it light: only cover for now.
- }
- }
- */
- }, [inView, index, posts]);
-
return (
);
diff --git a/packages/ui/src/components/widgets/HomeWidget.tsx b/packages/ui/src/components/widgets/HomeWidget.tsx
index 5d5b44a6..e39302bb 100644
--- a/packages/ui/src/components/widgets/HomeWidget.tsx
+++ b/packages/ui/src/components/widgets/HomeWidget.tsx
@@ -339,7 +339,7 @@ const HomeWidget: React.FC = ({
return viewMode === 'list' ? (
) : (
- window.location.href = `/post/${id}`} />
+ window.location.href = `/post/${id}`} showTitle={showTitle} showDescription={showDescription} />
);
}
diff --git a/packages/ui/src/modules/pages/PageCard.tsx b/packages/ui/src/modules/pages/PageCard.tsx
index 65a7d9f9..25ebb600 100644
--- a/packages/ui/src/modules/pages/PageCard.tsx
+++ b/packages/ui/src/modules/pages/PageCard.tsx
@@ -26,6 +26,10 @@ interface PageCardProps extends Omit {
versionCount?: number;
preset?: CardPreset;
className?: string;
+ showTitle?: boolean;
+ showDescription?: boolean;
+ showAuthor?: boolean;
+ showActions?: boolean;
}
const PageCard: React.FC = ({
@@ -52,7 +56,11 @@ const PageCard: React.FC = ({
versionCount,
preset,
type,
- className
+ className,
+ showTitle,
+ showDescription,
+ showAuthor,
+ showActions
}) => {
// Determine image source
// If url is missing or empty, fallback to picsum
@@ -94,7 +102,7 @@ const PageCard: React.FC = ({
{/* Author + Actions row */}
- {preset?.showAuthor !== false && (
+ {(showAuthor ?? preset?.showAuthor) !== false && (
= ({
createdAt={created_at}
/>
)}
- {preset?.showActions !== false && (
+ {(showActions ?? preset?.showActions) !== false && (
} />
+
SMTP Servers
Loading...
}>
-
+
} />
+
My Gallery
@@ -292,7 +294,25 @@ const Profile = () => {
onDelete={handleImageDelete}
onNavigate={navigate}
/>
-
+
+ } />
+
+
+
+ My Files
+
+
+ Loading...
}>
+
+
+
+