Commit 16425ed6 authored by Claude's avatar Claude

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
parent 16e00494
...@@ -46,6 +46,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => { ...@@ -46,6 +46,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
const [showEditor, setShowEditor] = useState<boolean>(false); const [showEditor, setShowEditor] = useState<boolean>(false);
const [creator, setCreator] = useState(userStore.getUserByName(memo.creator)); const [creator, setCreator] = useState(userStore.getUserByName(memo.creator));
const [showNSFWContent, setShowNSFWContent] = useState(props.showNsfwContent); const [showNSFWContent, setShowNSFWContent] = useState(props.showNsfwContent);
const [reactionSelectorOpen, setReactionSelectorOpen] = useState<boolean>(false);
const [previewImage, setPreviewImage] = useState<{ open: boolean; urls: string[]; index: number }>({ const [previewImage, setPreviewImage] = useState<{ open: boolean; urls: string[]; index: number }>({
open: false, open: false,
urls: [], urls: [],
...@@ -136,7 +137,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => { ...@@ -136,7 +137,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
) : ( ) : (
<div <div
className={cn( className={cn(
"relative flex flex-col justify-start items-start bg-card w-full px-4 py-3 mb-2 gap-2 text-card-foreground rounded-lg border border-border transition-colors", "relative group flex flex-col justify-start items-start bg-card w-full px-4 py-3 mb-2 gap-2 text-card-foreground rounded-lg border border-border transition-colors",
className, className,
)} )}
> >
...@@ -177,22 +178,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => { ...@@ -177,22 +178,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
)} )}
</div> </div>
<div className="flex flex-row justify-end items-center select-none shrink-0 gap-2"> <div className="flex flex-row justify-end items-center select-none shrink-0 gap-2">
<div className="w-auto flex flex-row justify-between items-center gap-2"> {currentUser && !isArchived && (
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && ( <ReactionSelector
<Tooltip> className={cn("border-none w-auto h-auto", reactionSelectorOpen && "!block", "hidden group-hover:block")}
<TooltipTrigger> memo={memo}
<span className="flex justify-center items-center rounded-md p-1 hover:opacity-80"> onOpenChange={setReactionSelectorOpen}
<VisibilityIcon visibility={memo.visibility} /> />
</span> )}
</TooltipTrigger> {!isInMemoDetailPage && (
<TooltipContent>{t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)}</TooltipContent>
</Tooltip>
)}
{currentUser && !isArchived && <ReactionSelector className="border-none w-auto h-auto" memo={memo} />}
</div>
{!isInMemoDetailPage && commentAmount > 0 && (
<Link <Link
className={cn("flex flex-row justify-start items-center rounded-md p-1 hover:opacity-80", commentAmount === 0 && "invisible")} className="flex flex-row justify-start items-center rounded-md p-1 hover:opacity-80"
to={`/${memo.name}#comments`} to={`/${memo.name}#comments`}
viewTransition viewTransition
state={{ state={{
...@@ -203,6 +198,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => { ...@@ -203,6 +198,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
{commentAmount > 0 && <span className="text-xs text-muted-foreground">{commentAmount}</span>} {commentAmount > 0 && <span className="text-xs text-muted-foreground">{commentAmount}</span>}
</Link> </Link>
)} )}
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && (
<Tooltip>
<TooltipTrigger>
<span className="flex justify-center items-center rounded-md hover:opacity-80">
<VisibilityIcon visibility={memo.visibility} />
</span>
</TooltipTrigger>
<TooltipContent>{t(`memo.visibility.${convertVisibilityToString(memo.visibility).toLowerCase()}` as any)}</TooltipContent>
</Tooltip>
)}
{props.showPinned && memo.pinned && ( {props.showPinned && memo.pinned && (
<TooltipProvider> <TooltipProvider>
<Tooltip> <Tooltip>
......
...@@ -12,10 +12,11 @@ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; ...@@ -12,10 +12,11 @@ import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
interface Props { interface Props {
memo: Memo; memo: Memo;
className?: string; className?: string;
onOpenChange?: (open: boolean) => void;
} }
const ReactionSelector = observer((props: Props) => { const ReactionSelector = observer((props: Props) => {
const { memo, className } = props; const { memo, className, onOpenChange } = props;
const currentUser = useCurrentUser(); const currentUser = useCurrentUser();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
...@@ -23,8 +24,14 @@ const ReactionSelector = observer((props: Props) => { ...@@ -23,8 +24,14 @@ const ReactionSelector = observer((props: Props) => {
useClickAway(containerRef, () => { useClickAway(containerRef, () => {
setOpen(false); setOpen(false);
onOpenChange?.(false);
}); });
const handleOpenChange = (newOpen: boolean) => {
setOpen(newOpen);
onOpenChange?.(newOpen);
};
const hasReacted = (reactionType: string) => { const hasReacted = (reactionType: string) => {
return memo.reactions.some((r) => r.reactionType === reactionType && r.creator === currentUser?.name); return memo.reactions.some((r) => r.reactionType === reactionType && r.creator === currentUser?.name);
}; };
...@@ -51,15 +58,15 @@ const ReactionSelector = observer((props: Props) => { ...@@ -51,15 +58,15 @@ const ReactionSelector = observer((props: Props) => {
} catch { } catch {
// skip error. // skip error.
} }
setOpen(false); handleOpenChange(false);
}; };
return ( return (
<Popover open={open} onOpenChange={setOpen}> <Popover open={open} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<span <span
className={cn( className={cn(
"h-7 w-7 flex justify-center items-center rounded-full border cursor-pointer transition-colors hover:opacity-80", "h-7 w-7 flex justify-center items-center rounded-full border cursor-pointer transition-all hover:opacity-80",
className, className,
)} )}
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment