diff --git a/public/img/icon/like-active.svg b/public/img/icon/like-active.svg new file mode 100644 index 0000000..f78158f --- /dev/null +++ b/public/img/icon/like-active.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/img/icon/like.svg b/public/img/icon/like.svg new file mode 100644 index 0000000..5127207 --- /dev/null +++ b/public/img/icon/like.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/globals.css b/src/app/globals.css index 7fdd800..78882c0 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -26,6 +26,10 @@ input { outline: none; } +textarea { + outline: none; +} + @layer utilities { .text-balance { text-wrap: balance; diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index b0f322c..20dff32 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -9,7 +9,7 @@ interface Props { const Avatar = ({ src, alt = 'avatar', size, className = '' }: Props) => { return ( -
+
{alt}
); diff --git a/src/components/Comment/ButtonBar.tsx b/src/components/Comment/ButtonBar.tsx new file mode 100644 index 0000000..8e3cc28 --- /dev/null +++ b/src/components/Comment/ButtonBar.tsx @@ -0,0 +1,66 @@ +import { useEffect, useState } from 'react'; + +interface Props { + commentCount: number; + thumbupCount: number; + haveThumbup: boolean; + className?: string; + onShowInput: () => void; + onShowAll: () => Promise; + onThumbup: () => Promise; +} +export default function ButtonBar({ + commentCount, + thumbupCount, + haveThumbup, + className, + onShowAll, + onShowInput, + onThumbup, +}: Props) { + const [showAll, setShowAll] = useState(false); + const [thumbup, setThumbup] = useState(false); + + const handleShowAll = async () => { + const res = await onShowAll(); + setShowAll(res); + }; + + const handleThumbup = async () => { + const res = await onThumbup(); + if (res) setThumbup(!thumbup); + }; + + useEffect(() => { + setThumbup(haveThumbup); + }, []); + + return ( +
+ {/* 回复 */} +
+ 回复 +
+ {/* 展开回复 */} + {commentCount > 1 && !showAll && ( +
+ 展开{commentCount}条回复 +
+ )} + {/* 点赞 */} +
+ {thumbupCount > 0 && ( +
+ {thumbupCount} +
+ )} +
+
+
+ ); +} diff --git a/src/components/Comment/Comment.tsx b/src/components/Comment/Comment.tsx index 1d5e76e..8b56c23 100644 --- a/src/components/Comment/Comment.tsx +++ b/src/components/Comment/Comment.tsx @@ -1,20 +1,56 @@ +'use client'; + +import { useState, useEffect } from 'react'; + import { CommentForm, CommentHeader, CommentList } from '@/components'; +import { apiGetComment, apiCommentSave } from '@/services'; + +interface Props { + journalId: string; + className: string; + totalCommentReply: string; +} + +export default function Comment({ journalId, className, totalCommentReply }: Props) { + const [commentType, setCommentType] = useState<'hot' | 'new'>('hot'); + const [commentList, setCommentList] = useState([]); + const [page, setPage] = useState(1); + + // 切换热门/最新 + const handleChangeType = async (type: 'hot' | 'new') => { + setCommentType(type); + setPage(1); + }; + + // 发表评论 + const handleSubmit = async (content: string) => { + const res = await apiCommentSave({ journalId, parentId: '', content }); + return res.code === 200; + }; + + useEffect(() => { + const getCommentList = async () => { + if (page === 1) setCommentList([]); + const res = await apiGetComment({ type: commentType, journalId, page, size: 3 }); + if (res.code === 200 && res.data?.rows.length) { + setCommentList([...commentList, ...res.data.rows]); + } + }; + + getCommentList(); + }, [commentType, page]); -export default function Comment({ - commentList, - className, - totalCommentReply, -}: { - commentList: any; - className?: string; - totalCommentReply: number; -}) { return (
- + {!!totalCommentReply && ( <> - + handleChangeType(type)} + clssName="mt-[25px]" + /> )} diff --git a/src/components/Comment/CommentForm.tsx b/src/components/Comment/CommentForm.tsx index 590a6a5..e915333 100644 --- a/src/components/Comment/CommentForm.tsx +++ b/src/components/Comment/CommentForm.tsx @@ -1,3 +1,42 @@ -export default function CommentItem() { - return
; +'use client'; + +import { useState } from 'react'; + +import { Button } from '@/components'; + +interface Props { + onSubmit: (value: string) => Promise; +} + +export default function CommentItem({ onSubmit }: Props) { + const [value, setValue] = useState(''); + const [loading, setLoading] = useState(false); + + const handleSubmit = async () => { + setLoading(true); + await onSubmit(value); + setLoading(false); + }; + + return ( +
+