74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import { Post, PostMedia } from '../posts/posts.ts'
|
|
import { Link } from 'react-router-dom'
|
|
import { useEffect, useState } from 'react'
|
|
|
|
interface PostItemProps {
|
|
post: Post
|
|
}
|
|
|
|
export default function PostItem({ post }: PostItemProps) {
|
|
const formattedDate = post.createdAt.toLocaleString('en-US', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
})
|
|
|
|
const [visible, setVisible] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const timeout = setTimeout(() => setVisible(true))
|
|
return () => {
|
|
clearTimeout(timeout)
|
|
}
|
|
}, [])
|
|
|
|
const opacity = visible ? 'opacity-100' : 'opacity-0'
|
|
|
|
return (
|
|
<article className={`w-full p-4 ${opacity} transition-opacity duration-500`} key={post.postId}>
|
|
<div className="text-sm text-gray-500 mb-3">
|
|
<Link to={`/u/${post.authorName}`} className="text-gray-400 hover:underline mr-2">
|
|
@{post.authorName}
|
|
</Link>
|
|
• {formattedDate}
|
|
</div>
|
|
|
|
<div className="text-gray-800 mb-4 whitespace-pre-wrap">{post.content}</div>
|
|
|
|
{post.media.length > 0 && (
|
|
<div className="grid gap-4 grid-cols-1">
|
|
{post.media.map((media) => (
|
|
<PostMediaItem key={media.url.toString()} media={media} />
|
|
))}
|
|
</div>
|
|
)}
|
|
</article>
|
|
)
|
|
}
|
|
|
|
interface PostMediaProps {
|
|
media: PostMedia
|
|
}
|
|
|
|
function PostMediaItem({ media }: PostMediaProps) {
|
|
const url = new URL(media.url.toString())
|
|
|
|
if (location.protocol === 'https:' && url.protocol !== 'https:') {
|
|
url.protocol = 'https:'
|
|
}
|
|
|
|
const width = media.width ?? undefined
|
|
const height = media.height ?? undefined
|
|
return (
|
|
<img
|
|
width={width}
|
|
height={height}
|
|
src={url.toString()}
|
|
alt="todo sry :("
|
|
className="w-full h-auto"
|
|
loading="lazy"
|
|
/>
|
|
)
|
|
}
|