From 16425ed650745f70d75b7a97f2bec56a051680be Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 23 Oct 2025 21:20:15 +0800 Subject: [PATCH] feat(web): improve ReactionSelector UX with hover visibility - Add hover-based visibility for reaction selector in memo cards - Show reaction selector only on card hover or when popover is open - Add onOpenChange callback to ReactionSelector for state management - Reorder action buttons for better visual hierarchy - Simplify conditional rendering of comment link --- web/src/components/MemoView.tsx | 37 ++++++++++++++----------- web/src/components/ReactionSelector.tsx | 15 +++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/web/src/components/MemoView.tsx b/web/src/components/MemoView.tsx index 1c63a01ce..2eb00f684 100644 --- a/web/src/components/MemoView.tsx +++ b/web/src/components/MemoView.tsx @@ -46,6 +46,7 @@ const MemoView: React.FC = observer((props: Props) => { const [showEditor, setShowEditor] = useState(false); const [creator, setCreator] = useState(userStore.getUserByName(memo.creator)); const [showNSFWContent, setShowNSFWContent] = useState(props.showNsfwContent); + const [reactionSelectorOpen, setReactionSelectorOpen] = useState(false); const [previewImage, setPreviewImage] = useState<{ open: boolean; urls: string[]; index: number }>({ open: false, urls: [], @@ -136,7 +137,7 @@ const MemoView: React.FC = observer((props: Props) => { ) : (
@@ -177,22 +178,16 @@ const MemoView: React.FC = observer((props: Props) => { )}
-
- {props.showVisibility && memo.visibility !== Visibility.PRIVATE && ( - - - - - - - {t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)} - - )} - {currentUser && !isArchived && } -
- {!isInMemoDetailPage && commentAmount > 0 && ( + {currentUser && !isArchived && ( + + )} + {!isInMemoDetailPage && ( = observer((props: Props) => { {commentAmount > 0 && {commentAmount}} )} + {props.showVisibility && memo.visibility !== Visibility.PRIVATE && ( + + + + + + + {t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)} + + )} {props.showPinned && memo.pinned && ( diff --git a/web/src/components/ReactionSelector.tsx b/web/src/components/ReactionSelector.tsx index 5c8042a02..a4822e482 100644 --- a/web/src/components/ReactionSelector.tsx +++ b/web/src/components/ReactionSelector.tsx @@ -12,10 +12,11 @@ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; interface Props { memo: Memo; className?: string; + onOpenChange?: (open: boolean) => void; } const ReactionSelector = observer((props: Props) => { - const { memo, className } = props; + const { memo, className, onOpenChange } = props; const currentUser = useCurrentUser(); const [open, setOpen] = useState(false); const containerRef = useRef(null); @@ -23,8 +24,14 @@ const ReactionSelector = observer((props: Props) => { useClickAway(containerRef, () => { setOpen(false); + onOpenChange?.(false); }); + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + onOpenChange?.(newOpen); + }; + const hasReacted = (reactionType: string) => { return memo.reactions.some((r) => r.reactionType === reactionType && r.creator === currentUser?.name); }; @@ -51,15 +58,15 @@ const ReactionSelector = observer((props: Props) => { } catch { // skip error. } - setOpen(false); + handleOpenChange(false); }; return ( - +