doctor-mail/apps/web/src/components/models/post/detail/PostHeader.tsx

149 lines
3.9 KiB
TypeScript
Raw Normal View History

2025-01-24 00:19:02 +08:00
import { useContext } from "react";
import { PostDetailContext } from "./context/PostDetailContext";
import { motion } from "framer-motion";
import {
CalendarIcon,
UserCircleIcon,
LockClosedIcon,
LockOpenIcon,
StarIcon,
ClockIcon,
EyeIcon,
ChatBubbleLeftIcon,
} from "@heroicons/react/24/outline";
2025-01-24 17:39:41 +08:00
2025-01-24 00:19:02 +08:00
import { useVisitor } from "@nice/client";
2025-01-24 17:39:41 +08:00
import { PostState, VisitType } from "@nice/common";
import {
CommentOutlined,
EyeOutlined,
LikeFilled,
LikeOutlined,
} from "@ant-design/icons";
import dayjs from "dayjs";
import { TitleSection } from "./PostHeader/TitleSection";
import {
AuthorBadge,
DateBadge,
TermBadge,
UpdatedBadge,
VisibilityBadge,
} from "./PostHeader/InfoBadge";
import { StatsSection } from "./PostHeader/StatsSection";
2025-01-24 00:19:02 +08:00
export default function PostHeader() {
const { post, user } = useContext(PostDetailContext);
2025-01-24 17:39:41 +08:00
const { like, unLike } = useVisitor();
2025-01-24 00:19:02 +08:00
function likeThisPost() {
if (!post?.liked) {
2025-01-24 17:39:41 +08:00
post.likes += 1;
post.liked = true;
2025-01-24 00:19:02 +08:00
like.mutateAsync({
data: {
visitorId: user?.id || null,
postId: post.id,
type: VisitType.LIKE,
},
});
2025-01-24 17:39:41 +08:00
} else {
post.likes -= 1;
post.liked = false;
unLike.mutateAsync({
where: {
visitorId: user?.id || null,
postId: post.id,
type: VisitType.LIKE,
},
});
2025-01-24 00:19:02 +08:00
}
}
return (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="relative bg-gradient-to-br from-[#E6E9F0] via-[#EDF0F8] to-[#D8E2EF] rounded-lg p-6 shadow-lg border border-[#97A9C4]/30">
{/* Corner Decorations */}
<div className="absolute top-0 left-0 w-5 h-5 border-t-2 border-l-2 border-[#97A9C4] rounded-tl-lg" />
<div className="absolute bottom-0 right-0 w-5 h-5 border-b-2 border-r-2 border-[#97A9C4] rounded-br-lg" />
{/* Title Section */}
2025-01-24 17:39:41 +08:00
<TitleSection
title={post?.title}
state={post?.state as PostState}></TitleSection>
2025-01-24 00:19:02 +08:00
<div className="space-y-4">
{/* First Row - Basic Info */}
<div className="flex flex-wrap gap-4">
{/* Author Info Badge */}
2025-01-24 17:39:41 +08:00
<AuthorBadge
name={
post?.author?.showname || "匿名用户"
}></AuthorBadge>
2025-01-24 00:19:02 +08:00
{/* Date Info Badge */}
{post?.createdAt && (
2025-01-24 17:39:41 +08:00
<DateBadge
date={dayjs(post?.createdAt).format("YYYY-MM-DD")}
label="创建于:"></DateBadge>
2025-01-24 00:19:02 +08:00
)}
{/* Last Updated Badge */}
{post?.updatedAt && post.updatedAt !== post.createdAt && (
2025-01-24 17:39:41 +08:00
<UpdatedBadge
date={dayjs(post?.updatedAt).format(
"YYYY-MM-DD"
)}></UpdatedBadge>
2025-01-24 00:19:02 +08:00
)}
{/* Visibility Status Badge */}
2025-01-24 17:39:41 +08:00
<VisibilityBadge
isPublic={post?.isPublic}></VisibilityBadge>
2025-01-24 00:19:02 +08:00
</div>
{/* Second Row - Term and Tags */}
<div className="flex flex-wrap gap-4">
{/* Term Badge */}
{post?.term?.name && (
2025-01-24 17:39:41 +08:00
<TermBadge term={post.term.name}></TermBadge>
2025-01-24 00:19:02 +08:00
)}
{/* Tags Badges */}
2025-01-24 17:39:41 +08:00
{post?.meta?.tags &&
post.meta.tags.length > 0 &&
post.meta.tags.map((tag, index) => (
<motion.span
key={index}
whileHover={{ scale: 1.05 }}
className="inline-flex items-center bg-[#507AAF]/10 px-3 py-1.5 rounded border border-[#97A9C4]/50 shadow-md hover:bg-[#507AAF]/20">
<span className="text-sm text-[#2B4C7E]">
#{tag}
</span>
</motion.span>
))}
2025-01-24 00:19:02 +08:00
</div>
</div>
{/* Content Section */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.6 }}
className="mt-6 text-[#2B4C7E]">
<div
className="ql-editor space-y-4 leading-relaxed bg-white/60 p-4 rounded-md border border-[#97A9C4]/30 shadow-inner hover:bg-white/80 transition-colors duration-300"
dangerouslySetInnerHTML={{ __html: post?.content || "" }}
/>
</motion.div>
{/* Stats Section */}
2025-01-24 17:39:41 +08:00
<StatsSection
likes={post?.likes}
views={post?.views}
commentsCount={post?.commentsCount}
liked={post?.liked}
onLikeClick={likeThisPost}></StatsSection>
2025-01-24 00:19:02 +08:00
</motion.div>
);
}