feat: mention
This commit is contained in:
@@ -29,15 +29,17 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { ImageIcon, Repeat2 } from "lucide-react";
|
||||
import { AtSign, ImageIcon, Repeat2 } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { Post, PostImage } from "@/lib/social";
|
||||
import { displaySourceLabel } from "@/lib/source-reference";
|
||||
import { useMediaQuery } from "@/components/selection-toolbar/shared";
|
||||
import { useAuth } from "@/components/auth/auth-provider";
|
||||
import { postSourceHref, quoteCardBgStyle } from "./post-card-shared";
|
||||
import { PostActionsFooter } from "./post-actions-footer";
|
||||
import { PostCardMenu } from "./post-card-menu";
|
||||
import { UpdateBackgroundModal } from "./update-background-modal";
|
||||
import { MentionsDrawer } from "./mentions-drawer";
|
||||
|
||||
export function PostScrollCard({
|
||||
post,
|
||||
@@ -52,23 +54,40 @@ export function PostScrollCard({
|
||||
const hasImages = images.length > 0;
|
||||
const sourceHref = postSourceHref(post);
|
||||
const isMobile = useMediaQuery("(max-width: 767px)");
|
||||
const { user } = useAuth();
|
||||
const isAuthor = !!user && user.id === post.user_id;
|
||||
const [bgModal, setBgModal] = useState(false);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [mentionsOpen, setMentionsOpen] = useState(false);
|
||||
// Live mention count — seeded from the hydrated post, adjusted when the
|
||||
// author edits tags in the drawer, so the icon appears/disappears in place.
|
||||
const [mentionCount, setMentionCount] = useState(post.mentions_count ?? 0);
|
||||
|
||||
// Update Background stays as a media-overlay button — it's context-
|
||||
// specific to the visible card surface and reads more naturally
|
||||
// positioned over the image itself. Delete has moved into the
|
||||
// header's three-dot menu (PostCardMenu) where Block / Report also
|
||||
// live, so the overlay is now Update-Background-only.
|
||||
const ownerCluster = onUpdated ? (
|
||||
<div className="absolute top-3 right-3 z-10">
|
||||
<OwnerButton
|
||||
label="Update background"
|
||||
onClick={() => setBgModal(true)}
|
||||
icon={<ImageIcon className="size-4" />}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
// The author always gets the mentions entry point (to add/remove); everyone
|
||||
// else sees it only when the post actually tags someone.
|
||||
const showMentions = mentionCount > 0 || isAuthor;
|
||||
|
||||
// Top-right media overlay: a Mentions icon and the owner-only
|
||||
// Update-background button. Delete lives in the header menu.
|
||||
const topRight =
|
||||
showMentions || onUpdated ? (
|
||||
<div className="absolute top-3 right-3 z-10 flex items-center gap-2">
|
||||
{showMentions ? (
|
||||
<OwnerButton
|
||||
label="See who's mentioned"
|
||||
onClick={() => setMentionsOpen(true)}
|
||||
icon={<AtSign className="size-4" />}
|
||||
/>
|
||||
) : null}
|
||||
{onUpdated ? (
|
||||
<OwnerButton
|
||||
label="Update background"
|
||||
onClick={() => setBgModal(true)}
|
||||
icon={<ImageIcon className="size-4" />}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<article
|
||||
@@ -125,7 +144,7 @@ export function PostScrollCard({
|
||||
) : (
|
||||
<QuotePanel post={post} />
|
||||
)}
|
||||
{ownerCluster}
|
||||
{topRight}
|
||||
</div>
|
||||
|
||||
{/* Caption + citation — reference sits directly under the media
|
||||
@@ -162,6 +181,14 @@ export function PostScrollCard({
|
||||
onUpdated={onUpdated}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<MentionsDrawer
|
||||
open={mentionsOpen}
|
||||
postId={post.id}
|
||||
authorId={post.user_id}
|
||||
onClose={() => setMentionsOpen(false)}
|
||||
onCountChange={(d) => setMentionCount((c) => Math.max(0, c + d))}
|
||||
/>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user