import { useEffect, useRef, useState } from 'react' import { Icon } from '#/components/icon' import { PostText } from '#/components/post-text' import { Avatar, AvatarFallback, AvatarImage } from '#/components/ui/avatar' import { Badge } from '#/components/ui/badge' import { Button } from '#/components/ui/button' import type { ResearchPost } from '#/features/platforms/types' const dateFormatter = new Intl.DateTimeFormat('ja-JP', { month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Tokyo', }) export function ResearchPostCard({ post, citationRequest, citationSnapshot, }: { post: ResearchPost citationRequest?: number citationSnapshot?: boolean }) { const [revealed, setRevealed] = useState(false) const [highlighted, setHighlighted] = useState(false) const article = useRef(null) // biome-ignore lint/correctness/useExhaustiveDependencies: Re-scroll when a snapshot moves to its live feed position. useEffect(() => { if (citationRequest === undefined) { setHighlighted(false) return } setHighlighted(true) article.current?.focus({ preventScroll: true }) article.current?.scrollIntoView({ block: 'center', inline: 'center', behavior: window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ? 'instant' : 'smooth', }) const timer = setTimeout(() => setHighlighted(false), 2500) return () => clearTimeout(timer) }, [citationRequest, citationSnapshot]) const concealed = Boolean(post.contentWarning || post.sensitive) return (
{citationSnapshot ? ( 調査時に取得した投稿 ) : null} {post.boostedBy ? (

{post.boostedBy.name} がブースト

) : null}
{post.author.name.slice(0, 1)}
{post.author.name} @{post.author.handle.replace(/^@/, '')}
{post.createdAt ? ( ) : null}
{concealed ? (

{post.contentWarning || 'センシティブなメディアを含む投稿'}

) : null} {!concealed || revealed ? ( <> {post.html !== undefined ? (
) : (

)} {post.media?.map((media) => media.type === 'photo' ? ( {media.alt ) : ( 動画を開く ), )} {post.quotedPost ? (
{post.quotedPost.author.name}

引用元を開く
) : null} ) : null}
) }