feat(ui): refine post interaction surfaces

This commit is contained in:
zetaloop
2026-04-25 21:41:01 +08:00
parent 29db9e5c0c
commit 1ee512940e
3 changed files with 51 additions and 29 deletions
+39 -19
View File
@@ -5,10 +5,11 @@ import { toApiError } from "@/lib/errors"
import { notifyInfo } from "@/lib/toast"
import type { Comment } from "@/lib/types"
import { useRequireAuth } from "@/lib/use-require-auth"
import { Heart } from "lucide-react"
import { AlertCircle, Heart, MessageCircle } from "lucide-react"
import { useCallback, useEffect, useState } from "react"
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"
import { Button } from "./ui/button"
import { EmptyState } from "./ui/empty-state"
import { Textarea } from "./ui/textarea"
interface PostCommentsProps {
@@ -65,12 +66,15 @@ export function PostComments({ postId }: PostCommentsProps) {
return (
<div className="space-y-4">
<h2 className="font-semibold">
({loading && comments.length === 0 ? "..." : comments.length})
</h2>
<div className="flex items-center justify-between border-b border-border/60 pb-3">
<h2 className="font-semibold"></h2>
<span className="text-xs text-muted-foreground">
{loading && comments.length === 0 ? "加载中" : `${comments.length}`}
</span>
</div>
<form
className="flex gap-3"
className="space-y-3 rounded-xl border border-border/80 bg-card p-3 shadow-sm"
onSubmit={(event) => {
event.preventDefault()
requireAuth(async () => {
@@ -95,42 +99,58 @@ export function PostComments({ postId }: PostCommentsProps) {
>
<Textarea
placeholder="写下你的评论..."
className="flex-1"
className="min-h-20 resize-none bg-transparent"
rows={2}
value={content}
onChange={(event) => setContent(event.target.value)}
/>
<Button className="self-end" disabled={!content.trim() || submitting}>
</Button>
<div className="flex justify-end">
<Button size="sm" disabled={!content.trim() || submitting}>
</Button>
</div>
</form>
{loading && comments.length === 0 ? (
<p className="text-sm text-muted-foreground text-center py-8">...</p>
<EmptyState title="评论加载中" icon={MessageCircle} className="min-h-[180px]" />
) : loadError ? (
<p className="text-sm text-muted-foreground text-center py-8">{loadError}</p>
<EmptyState
title="评论加载失败"
description={loadError}
icon={AlertCircle}
className="min-h-[180px]"
/>
) : comments.length === 0 ? (
<p className="text-sm text-muted-foreground text-center py-8"></p>
<EmptyState
title="还没有评论"
description="可以写下第一条评论。"
icon={MessageCircle}
className="min-h-[180px] border-dashed"
/>
) : (
<div className="space-y-4">
<div className="overflow-hidden rounded-xl border border-border/80 bg-card shadow-sm">
{comments.map((comment) => (
<div key={comment.id} className="flex gap-3">
<div
key={comment.id}
className="flex gap-3 border-b border-border/60 p-4 last:border-0"
>
<Avatar className="h-8 w-8">
<AvatarImage src={comment.author.avatar} />
<AvatarFallback>{comment.author.nickname[0]}</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-0.5">
<div className="min-w-0 flex-1">
<div className="mb-0.5 flex items-center gap-2">
<span className="text-sm font-medium">{comment.author.nickname}</span>
<span className="text-xs text-muted-foreground">
{new Date(comment.createdAt).toLocaleString("zh-CN")}
</span>
</div>
<p className="text-sm">{comment.content}</p>
<p className="text-sm leading-relaxed">{comment.content}</p>
<button
type="button"
aria-label={comment.liked ? "取消点赞评论" : "点赞评论"}
disabled={pendingLike[comment.id]}
className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground mt-1 transition-colors"
className="mt-2 flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground disabled:pointer-events-none disabled:opacity-60"
onClick={() =>
requireAuth(() => {
if (pendingLike[comment.id]) return
@@ -177,7 +197,7 @@ export function PostComments({ postId }: PostCommentsProps) {
}
>
<Heart
className={`h-3 w-3 ${comment.liked ? "fill-red-500 text-red-500" : ""}`}
className={`h-3 w-3 ${comment.liked ? "fill-destructive text-destructive" : ""}`}
/>
{comment.likeCount}
</button>