"use client"; /** * PostCard — renders one post in the public feed and the /u/me feed. * * • Author header — avatar + display name + @handle on the left, * three-dot overflow menu on the right. Menu contents vary by * viewer (see PostCardMenu): author sees Delete; signed-in * non-author sees Block + Report; anonymous sees Report. * • Caption in serif (locked, can't be edited) * • Image grid (max 5; collapses to one column on the cheap) * • "Source" link back to the page the quote came from * • Optional onDelete callback — passed through to PostCardMenu so * Delete actually does something on owner views (parent confirms + * calls the API; same pattern as before the menu refactor). * * The source link always lands the user on the original passage with `?hl=` * highlighting. If the stored source_url already carries `?hl=` we use it * verbatim; otherwise we synthesise one from the post's caption so older * posts (or imported data) still scroll to + highlight the text on click. */ import Image from "next/image"; import Link from "next/link"; import { ExternalLink, Repeat2 } from "lucide-react"; import type { Post } from "@/lib/social"; import { displaySourceLabel } from "@/lib/source-reference"; import { appendHighlight, hasHighlight } from "@/lib/text-highlight"; import { UserAvatar } from "@/components/ui/user-avatar"; import { timeAgo } from "@/lib/time"; import { PostActionsFooter } from "./post-actions-footer"; import { PostCardMenu } from "./post-card-menu"; export function PostCard({ post, onDelete, }: { post: Post; onDelete?: (id: string) => void; }) { const sourceHref = hasHighlight(post.source_url) || !post.caption ? post.source_url : appendHighlight(post.source_url, post.caption); const authorName = post.author_name || "Unknown"; const authorHandle = post.author_handle ?? null; return (
{/* Reshare attribution — only on rows that are themselves reshares. The link goes to the original author's profile; their handle is rendered inline so the source is obvious. The post body below shows the resharer as the author (this IS their post — likes, comments, and background all belong to them, independent from the original). */} {post.reshared_from_post_id && post.original_author_handle ? ( Reshared from{" "} @{post.original_author_handle} ) : null} {/* Author header — identity on the left, overflow menu on the right. The menu trigger only renders when there are items to show (delete for owners, block/report for everyone else), so a view with nothing to expose simply hides the dot. */}
{authorHandle ? ( {authorName} ) : (

{authorName}

)}

{authorHandle ? <>@{authorHandle} · : null} {timeAgo(post.created_at)}

“{post.caption}”

{post.images && post.images.length > 0 ? (
{post.images.map((img) => (
))}
) : null}
{displaySourceLabel(post.source_url, post.source_title)} {new Date(post.created_at).toLocaleDateString()}
{/* Action footer — like / comment / reshare on the left, add to collection on the right. */}
); }