mirror of https://github.com/usememos/memos.git
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
This commit is contained in:
parent
16e0049490
commit
16425ed650
|
|
@ -46,6 +46,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
|
|||
const [showEditor, setShowEditor] = useState<boolean>(false);
|
||||
const [creator, setCreator] = useState(userStore.getUserByName(memo.creator));
|
||||
const [showNSFWContent, setShowNSFWContent] = useState(props.showNsfwContent);
|
||||
const [reactionSelectorOpen, setReactionSelectorOpen] = useState<boolean>(false);
|
||||
const [previewImage, setPreviewImage] = useState<{ open: boolean; urls: string[]; index: number }>({
|
||||
open: false,
|
||||
urls: [],
|
||||
|
|
@ -136,7 +137,7 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
|
|||
) : (
|
||||
<div
|
||||
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,
|
||||
)}
|
||||
>
|
||||
|
|
@ -177,22 +178,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
|
|||
)}
|
||||
</div>
|
||||
<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">
|
||||
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<span className="flex justify-center items-center rounded-md p-1 hover:opacity-80">
|
||||
<VisibilityIcon visibility={memo.visibility} />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<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 && (
|
||||
{currentUser && !isArchived && (
|
||||
<ReactionSelector
|
||||
className={cn("border-none w-auto h-auto", reactionSelectorOpen && "!block", "hidden group-hover:block")}
|
||||
memo={memo}
|
||||
onOpenChange={setReactionSelectorOpen}
|
||||
/>
|
||||
)}
|
||||
{!isInMemoDetailPage && (
|
||||
<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`}
|
||||
viewTransition
|
||||
state={{
|
||||
|
|
@ -203,6 +198,16 @@ const MemoView: React.FC<Props> = observer((props: Props) => {
|
|||
{commentAmount > 0 && <span className="text-xs text-muted-foreground">{commentAmount}</span>}
|
||||
</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 && (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
|
|
|
|||
|
|
@ -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<HTMLDivElement>(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 (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<Popover open={open} onOpenChange={handleOpenChange}>
|
||||
<PopoverTrigger asChild>
|
||||
<span
|
||||
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,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in New Issue