Commit f2a01d9c authored by Johnny's avatar Johnny

chore: use popover instead of dropdown/menu

parent 522da2a1
import { Dropdown, Menu, MenuButton, MenuItem, Tooltip } from "@mui/joy"; import { Tooltip } from "@mui/joy";
import { Edit3Icon, MoreVerticalIcon, TrashIcon, PlusIcon } from "lucide-react"; import { Edit3Icon, MoreVerticalIcon, TrashIcon, PlusIcon } from "lucide-react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { shortcutServiceClient } from "@/grpcweb"; import { shortcutServiceClient } from "@/grpcweb";
...@@ -10,6 +10,7 @@ import { Shortcut } from "@/types/proto/api/v1/shortcut_service"; ...@@ -10,6 +10,7 @@ import { Shortcut } from "@/types/proto/api/v1/shortcut_service";
import { cn } from "@/utils"; import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import showCreateShortcutDialog from "../CreateShortcutDialog"; import showCreateShortcutDialog from "../CreateShortcutDialog";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/Popover";
const emojiRegex = /^(\p{Emoji_Presentation}|\p{Emoji}\uFE0F)$/u; const emojiRegex = /^(\p{Emoji_Presentation}|\p{Emoji}\uFE0F)$/u;
...@@ -56,21 +57,29 @@ const ShortcutsSection = observer(() => { ...@@ -56,21 +57,29 @@ const ShortcutsSection = observer(() => {
{emoji && <span className="text-base mr-1">{emoji}</span>} {emoji && <span className="text-base mr-1">{emoji}</span>}
{title.trim()} {title.trim()}
</span> </span>
<Dropdown> <Popover>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<MoreVerticalIcon className="w-4 h-auto shrink-0 opacity-40" /> <MoreVerticalIcon className="w-4 h-auto shrink-0 opacity-40 cursor-pointer hover:opacity-70" />
</MenuButton> </PopoverTrigger>
<Menu size="sm" placement="bottom-start"> <PopoverContent align="start" sideOffset={2}>
<MenuItem onClick={() => showCreateShortcutDialog({ shortcut })}> <div className="flex flex-col gap-0.5">
<button
onClick={() => showCreateShortcutDialog({ shortcut })}
className="flex items-center gap-1 px-2 py-1 text-sm text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<Edit3Icon className="w-4 h-auto" /> <Edit3Icon className="w-4 h-auto" />
{t("common.edit")} {t("common.edit")}
</MenuItem> </button>
<MenuItem color="danger" onClick={() => handleDeleteShortcut(shortcut)}> <button
onClick={() => handleDeleteShortcut(shortcut)}
className="flex items-center gap-1 px-2 py-1 text-sm text-left text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<TrashIcon className="w-4 h-auto" /> <TrashIcon className="w-4 h-auto" />
{t("common.delete")} {t("common.delete")}
</MenuItem> </button>
</Menu> </div>
</Dropdown> </PopoverContent>
</Popover>
</div> </div>
); );
})} })}
......
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { Switch } from "@usememos/mui"; import { Switch } from "@usememos/mui";
import { Edit3Icon, HashIcon, MoreVerticalIcon, TagsIcon, TrashIcon } from "lucide-react"; import { Edit3Icon, HashIcon, MoreVerticalIcon, TagsIcon, TrashIcon } from "lucide-react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
...@@ -75,24 +74,32 @@ const TagsSection = observer((props: Props) => { ...@@ -75,24 +74,32 @@ const TagsSection = observer((props: Props) => {
key={tag} key={tag}
className="shrink-0 w-auto max-w-full text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800" className="shrink-0 w-auto max-w-full text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800"
> >
<Dropdown> <Popover>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<div className="shrink-0 group"> <div className="shrink-0 group cursor-pointer">
<HashIcon className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" /> <HashIcon className="group-hover:hidden w-4 h-auto shrink-0 opacity-40" />
<MoreVerticalIcon className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60" /> <MoreVerticalIcon className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60" />
</div> </div>
</MenuButton> </PopoverTrigger>
<Menu size="sm" placement="bottom-start"> <PopoverContent align="start" sideOffset={2}>
<MenuItem onClick={() => showRenameTagDialog({ tag: tag })}> <div className="flex flex-col gap-0.5">
<button
onClick={() => showRenameTagDialog({ tag: tag })}
className="flex items-center gap-1 px-2 py-1 text-sm text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<Edit3Icon className="w-4 h-auto" /> <Edit3Icon className="w-4 h-auto" />
{t("common.rename")} {t("common.rename")}
</MenuItem> </button>
<MenuItem color="danger" onClick={() => handleDeleteTag(tag)}> <button
onClick={() => handleDeleteTag(tag)}
className="flex items-center gap-1 px-2 py-1 text-sm text-left text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<TrashIcon className="w-4 h-auto" /> <TrashIcon className="w-4 h-auto" />
{t("common.delete")} {t("common.delete")}
</MenuItem> </button>
</Menu> </div>
</Dropdown> </PopoverContent>
</Popover>
<div <div
className={cn("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")} className={cn("inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]")}
onClick={() => handleTagClick(tag)} onClick={() => handleTagClick(tag)}
......
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
import { import {
ArchiveIcon, ArchiveIcon,
...@@ -22,6 +21,7 @@ import { NodeType } from "@/types/proto/api/v1/markdown_service"; ...@@ -22,6 +21,7 @@ import { NodeType } from "@/types/proto/api/v1/markdown_service";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils"; import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
interface Props { interface Props {
memo: Memo; memo: Memo;
...@@ -163,55 +163,75 @@ const MemoActionMenu = observer((props: Props) => { ...@@ -163,55 +163,75 @@ const MemoActionMenu = observer((props: Props) => {
}; };
return ( return (
<Dropdown> <Popover>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<span className={cn("flex justify-center items-center rounded-full hover:opacity-70", props.className)}> <span className={cn("flex justify-center items-center rounded-full hover:opacity-70 cursor-pointer", props.className)}>
<MoreVerticalIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" /> <MoreVerticalIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
</span> </span>
</MenuButton> </PopoverTrigger>
<Menu className="text-sm" size="sm" placement="bottom-end"> <PopoverContent align="end" sideOffset={2}>
<div className="flex flex-col text-sm gap-0.5">
{!readonly && !isArchived && ( {!readonly && !isArchived && (
<> <>
{!isComment && ( {!isComment && (
<MenuItem onClick={handleTogglePinMemoBtnClick}> <button
onClick={handleTogglePinMemoBtnClick}
className="flex items-center gap-2 px-2 py-1 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{memo.pinned ? <BookmarkMinusIcon className="w-4 h-auto" /> : <BookmarkPlusIcon className="w-4 h-auto" />} {memo.pinned ? <BookmarkMinusIcon className="w-4 h-auto" /> : <BookmarkPlusIcon className="w-4 h-auto" />}
{memo.pinned ? t("common.unpin") : t("common.pin")} {memo.pinned ? t("common.unpin") : t("common.pin")}
</MenuItem> </button>
)} )}
<MenuItem onClick={handleEditMemoClick}> <button
onClick={handleEditMemoClick}
className="flex items-center gap-2 px-2 py-1 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<Edit3Icon className="w-4 h-auto" /> <Edit3Icon className="w-4 h-auto" />
{t("common.edit")} {t("common.edit")}
</MenuItem> </button>
</> </>
)} )}
{!isArchived && ( {!isArchived && (
<MenuItem onClick={handleCopyLink}> <button
onClick={handleCopyLink}
className="flex items-center gap-2 px-2 py-1 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<CopyIcon className="w-4 h-auto" /> <CopyIcon className="w-4 h-auto" />
{t("memo.copy-link")} {t("memo.copy-link")}
</MenuItem> </button>
)} )}
{!readonly && ( {!readonly && (
<> <>
{!isArchived && !isComment && hasCompletedTaskList && ( {!isArchived && !isComment && hasCompletedTaskList && (
<MenuItem color="warning" onClick={handleRemoveCompletedTaskListItemsClick}> <button
onClick={handleRemoveCompletedTaskListItemsClick}
className="flex items-center gap-2 px-2 py-1 text-left text-amber-600 dark:text-amber-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<SquareCheckIcon className="w-4 h-auto" /> <SquareCheckIcon className="w-4 h-auto" />
{t("memo.remove-completed-task-list-items")} {t("memo.remove-completed-task-list-items")}
</MenuItem> </button>
)} )}
{!isComment && ( {!isComment && (
<MenuItem color="warning" onClick={handleToggleMemoStatusClick}> <button
onClick={handleToggleMemoStatusClick}
className="flex items-center gap-2 px-2 py-1 text-left text-amber-600 dark:text-amber-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{isArchived ? <ArchiveRestoreIcon className="w-4 h-auto" /> : <ArchiveIcon className="w-4 h-auto" />} {isArchived ? <ArchiveRestoreIcon className="w-4 h-auto" /> : <ArchiveIcon className="w-4 h-auto" />}
{isArchived ? t("common.restore") : t("common.archive")} {isArchived ? t("common.restore") : t("common.archive")}
</MenuItem> </button>
)} )}
<MenuItem color="danger" onClick={handleDeleteMemoClick}> <button
onClick={handleDeleteMemoClick}
className="flex items-center gap-2 px-2 py-1 text-left text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
<TrashIcon className="w-4 h-auto" /> <TrashIcon className="w-4 h-auto" />
{t("common.delete")} {t("common.delete")}
</MenuItem> </button>
</> </>
)} )}
</Menu> </div>
</Dropdown> </PopoverContent>
</Popover>
); );
}); });
......
...@@ -22,7 +22,7 @@ const MemoDisplaySettingMenu = observer(({ className }: Props) => { ...@@ -22,7 +22,7 @@ const MemoDisplaySettingMenu = observer(({ className }: Props) => {
<Settings2Icon className="w-4 h-auto shrink-0" /> <Settings2Icon className="w-4 h-auto shrink-0" />
</PopoverTrigger> </PopoverTrigger>
<PopoverContent align="end" alignOffset={-12} sideOffset={14}> <PopoverContent align="end" alignOffset={-12} sideOffset={14}>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2 p-1">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="text-sm shrink-0 mr-3 dark:text-zinc-400">{t("memo.direction")}</span> <span className="text-sm shrink-0 mr-3 dark:text-zinc-400">{t("memo.direction")}</span>
<Select <Select
......
import { Dropdown, Menu, MenuButton, MenuItem, Link } from "@mui/joy"; import { Link } from "@mui/joy";
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import { CheckSquareIcon, Code2Icon, SquareSlashIcon } from "lucide-react"; import { CheckSquareIcon, Code2Icon, SquareSlashIcon } from "lucide-react";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/Popover";
import { EditorRefActions } from "../Editor"; import { EditorRefActions } from "../Editor";
interface Props { interface Props {
...@@ -61,28 +62,34 @@ const MarkdownMenu = (props: Props) => { ...@@ -61,28 +62,34 @@ const MarkdownMenu = (props: Props) => {
}; };
return ( return (
<Dropdown> <Popover>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<Button variant="plain" className="p-0"> <Button variant="plain" className="p-0">
<SquareSlashIcon className="w-5 h-5" /> <SquareSlashIcon className="w-5 h-5" />
</Button> </Button>
</MenuButton> </PopoverTrigger>
<Menu className="text-sm" size="sm" placement="bottom-start"> <PopoverContent align="start" className="text-sm p-1">
<MenuItem onClick={handleCodeBlockClick}> <button
onClick={handleCodeBlockClick}
className="w-full flex items-center gap-2 px-2 py-1.5 text-left text-sm hover:bg-gray-100 rounded-md"
>
<Code2Icon className="w-4 h-auto" /> <Code2Icon className="w-4 h-auto" />
<span>{t("markdown.code-block")}</span> <span>{t("markdown.code-block")}</span>
</MenuItem> </button>
<MenuItem onClick={handleCheckboxClick}> <button
onClick={handleCheckboxClick}
className="w-full flex items-center gap-2 px-2 py-1.5 text-left text-sm hover:bg-gray-100 rounded-md"
>
<CheckSquareIcon className="w-4 h-auto" /> <CheckSquareIcon className="w-4 h-auto" />
<span>{t("markdown.checkbox")}</span> <span>{t("markdown.checkbox")}</span>
</MenuItem> </button>
<div className="-mt-0.5 pl-2"> <div className="-mt-0.5 pl-2">
<Link fontSize={12} href="https://www.usememos.com/docs/getting-started/content-syntax" target="_blank"> <Link fontSize={12} href="https://www.usememos.com/docs/getting-started/content-syntax" target="_blank">
{t("markdown.content-syntax")} {t("markdown.content-syntax")}
</Link> </Link>
</div> </div>
</Menu> </PopoverContent>
</Dropdown> </Popover>
); );
}; };
......
import { Dropdown, Menu, MenuButton } from "@mui/joy";
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import { HashIcon } from "lucide-react"; import { HashIcon } from "lucide-react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
...@@ -7,6 +6,7 @@ import useClickAway from "react-use/lib/useClickAway"; ...@@ -7,6 +6,7 @@ import useClickAway from "react-use/lib/useClickAway";
import OverflowTip from "@/components/kit/OverflowTip"; import OverflowTip from "@/components/kit/OverflowTip";
import { userStore } from "@/store/v2"; import { userStore } from "@/store/v2";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/Popover";
import { EditorRefActions } from "../Editor"; import { EditorRefActions } from "../Editor";
interface Props { interface Props {
...@@ -41,13 +41,13 @@ const TagSelector = observer((props: Props) => { ...@@ -41,13 +41,13 @@ const TagSelector = observer((props: Props) => {
}; };
return ( return (
<Dropdown open={open} onOpenChange={(_, isOpen) => setOpen(isOpen)}> <Popover open={open} onOpenChange={setOpen}>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<Button variant="plain" className="p-0"> <Button variant="plain" className="p-0">
<HashIcon className="w-5 h-5" /> <HashIcon className="w-5 h-5" />
</Button> </Button>
</MenuButton> </PopoverTrigger>
<Menu className="relative" component="div" size="sm" placement="bottom-start"> <PopoverContent align="start" sideOffset={2}>
<div ref={containerRef}> <div ref={containerRef}>
{tags.length > 0 ? ( {tags.length > 0 ? (
<div className="flex flex-row justify-start items-start flex-wrap px-3 py-1 max-w-48 h-auto max-h-48 overflow-y-auto gap-x-2 gap-y-1"> <div className="flex flex-row justify-start items-start flex-wrap px-3 py-1 max-w-48 h-auto max-h-48 overflow-y-auto gap-x-2 gap-y-1">
...@@ -69,8 +69,8 @@ const TagSelector = observer((props: Props) => { ...@@ -69,8 +69,8 @@ const TagSelector = observer((props: Props) => {
</p> </p>
)} )}
</div> </div>
</Menu> </PopoverContent>
</Dropdown> </Popover>
); );
}); });
......
import { Dropdown, Menu, MenuButton } from "@mui/joy";
import { SmilePlusIcon } from "lucide-react"; import { SmilePlusIcon } from "lucide-react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
...@@ -8,6 +7,7 @@ import useCurrentUser from "@/hooks/useCurrentUser"; ...@@ -8,6 +7,7 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { memoStore, workspaceStore } from "@/store/v2"; import { memoStore, workspaceStore } from "@/store/v2";
import { Memo } from "@/types/proto/api/v1/memo_service"; import { Memo } from "@/types/proto/api/v1/memo_service";
import { cn } from "@/utils"; import { cn } from "@/utils";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
interface Props { interface Props {
memo: Memo; memo: Memo;
...@@ -55,18 +55,18 @@ const ReactionSelector = observer((props: Props) => { ...@@ -55,18 +55,18 @@ const ReactionSelector = observer((props: Props) => {
}; };
return ( return (
<Dropdown open={open} onOpenChange={(_, isOpen) => setOpen(isOpen)}> <Popover open={open} onOpenChange={setOpen}>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<span <span
className={cn( className={cn(
"h-7 w-7 flex justify-center items-center rounded-full border border-zinc-200 dark:border-zinc-700 hover:opacity-70", "h-7 w-7 flex justify-center items-center rounded-full border border-zinc-200 dark:border-zinc-700 hover:opacity-70 cursor-pointer",
className, className,
)} )}
> >
<SmilePlusIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" /> <SmilePlusIcon className="w-4 h-4 mx-auto text-gray-500 dark:text-gray-400" />
</span> </span>
</MenuButton> </PopoverTrigger>
<Menu className="relative" component="div" size="sm" placement="bottom-start"> <PopoverContent align="start" sideOffset={2}>
<div ref={containerRef}> <div ref={containerRef}>
<div className="flex flex-row flex-wrap py-0.5 px-2 h-auto gap-1 max-w-56"> <div className="flex flex-row flex-wrap py-0.5 px-2 h-auto gap-1 max-w-56">
{workspaceMemoRelatedSetting.reactions.map((reactionType) => { {workspaceMemoRelatedSetting.reactions.map((reactionType) => {
...@@ -85,8 +85,8 @@ const ReactionSelector = observer((props: Props) => { ...@@ -85,8 +85,8 @@ const ReactionSelector = observer((props: Props) => {
})} })}
</div> </div>
</div> </div>
</Menu> </PopoverContent>
</Dropdown> </Popover>
); );
}); });
......
import { Dropdown, Menu, MenuButton, MenuItem, Radio, RadioGroup } from "@mui/joy"; import { Radio, RadioGroup } from "@mui/joy";
import { Button, Input } from "@usememos/mui"; import { Button, Input } from "@usememos/mui";
import { sortBy } from "lodash-es"; import { sortBy } from "lodash-es";
import { MoreVerticalIcon } from "lucide-react"; import { MoreVerticalIcon } from "lucide-react";
...@@ -12,6 +12,7 @@ import { State } from "@/types/proto/api/v1/common"; ...@@ -12,6 +12,7 @@ import { State } from "@/types/proto/api/v1/common";
import { User, User_Role } from "@/types/proto/api/v1/user_service"; import { User, User_Role } from "@/types/proto/api/v1/user_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import showCreateUserDialog from "../CreateUserDialog"; import showCreateUserDialog from "../CreateUserDialog";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/Popover";
interface LocalState { interface LocalState {
creatingUser: User; creatingUser: User;
...@@ -214,22 +215,46 @@ const MemberSection = observer(() => { ...@@ -214,22 +215,46 @@ const MemberSection = observer(() => {
{currentUser?.name === user.name ? ( {currentUser?.name === user.name ? (
<span>{t("common.yourself")}</span> <span>{t("common.yourself")}</span>
) : ( ) : (
<Dropdown> <Popover>
<MenuButton size="sm"> <PopoverTrigger asChild>
<button className="flex items-center justify-center p-1 hover:bg-gray-100 dark:hover:bg-zinc-700 rounded">
<MoreVerticalIcon className="w-4 h-auto" /> <MoreVerticalIcon className="w-4 h-auto" />
</MenuButton> </button>
<Menu placement="bottom-end" size="sm"> </PopoverTrigger>
<MenuItem onClick={() => showCreateUserDialog(user, () => fetchUsers())}>{t("common.update")}</MenuItem> <PopoverContent align="end" sideOffset={2}>
<div className="flex flex-col gap-0.5 text-sm">
<button
onClick={() => showCreateUserDialog(user, () => fetchUsers())}
className="flex items-center gap-2 px-2 py-1.5 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("common.update")}
</button>
{user.state === State.NORMAL ? ( {user.state === State.NORMAL ? (
<MenuItem onClick={() => handleArchiveUserClick(user)}>{t("setting.member-section.archive-member")}</MenuItem> <button
onClick={() => handleArchiveUserClick(user)}
className="flex items-center gap-2 px-2 py-1.5 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("setting.member-section.archive-member")}
</button>
) : ( ) : (
<> <>
<MenuItem onClick={() => handleRestoreUserClick(user)}>{t("common.restore")}</MenuItem> <button
<MenuItem onClick={() => handleDeleteUserClick(user)}>{t("setting.member-section.delete-member")}</MenuItem> onClick={() => handleRestoreUserClick(user)}
className="flex items-center gap-2 px-2 py-1.5 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("common.restore")}
</button>
<button
onClick={() => handleDeleteUserClick(user)}
className="flex items-center gap-2 px-2 py-1.5 text-left text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("setting.member-section.delete-member")}
</button>
</> </>
)} )}
</Menu> </div>
</Dropdown> </PopoverContent>
</Popover>
)} )}
</td> </td>
</tr> </tr>
......
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import { MoreVerticalIcon, PenLineIcon } from "lucide-react"; import { MoreVerticalIcon, PenLineIcon } from "lucide-react";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
...@@ -6,6 +5,7 @@ import { useTranslate } from "@/utils/i18n"; ...@@ -6,6 +5,7 @@ import { useTranslate } from "@/utils/i18n";
import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog"; import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog";
import showUpdateAccountDialog from "../UpdateAccountDialog"; import showUpdateAccountDialog from "../UpdateAccountDialog";
import UserAvatar from "../UserAvatar"; import UserAvatar from "../UserAvatar";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/Popover";
import AccessTokenSection from "./AccessTokenSection"; import AccessTokenSection from "./AccessTokenSection";
const MyAccountSection = () => { const MyAccountSection = () => {
...@@ -30,16 +30,21 @@ const MyAccountSection = () => { ...@@ -30,16 +30,21 @@ const MyAccountSection = () => {
<PenLineIcon className="w-4 h-4 mx-auto mr-1" /> <PenLineIcon className="w-4 h-4 mx-auto mr-1" />
{t("common.edit")} {t("common.edit")}
</Button> </Button>
<Dropdown> <Popover>
<MenuButton slots={{ root: "div" }}> <PopoverTrigger asChild>
<Button variant="outlined"> <Button variant="outlined">
<MoreVerticalIcon className="w-4 h-4 mx-auto" /> <MoreVerticalIcon className="w-4 h-4 mx-auto" />
</Button> </Button>
</MenuButton> </PopoverTrigger>
<Menu className="text-sm" size="sm" placement="bottom"> <PopoverContent align="start" className="text-sm p-1">
<MenuItem onClick={() => showChangeMemberPasswordDialog(user)}>{t("setting.account-section.change-password")}</MenuItem> <button
</Menu> onClick={() => showChangeMemberPasswordDialog(user)}
</Dropdown> className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md"
>
{t("setting.account-section.change-password")}
</button>
</PopoverContent>
</Popover>
</div> </div>
<AccessTokenSection /> <AccessTokenSection />
......
import { Divider, Dropdown, List, ListItem, Menu, MenuButton, MenuItem } from "@mui/joy"; import { Divider, List, ListItem } from "@mui/joy";
import { Button } from "@usememos/mui"; import { Button } from "@usememos/mui";
import { MoreVerticalIcon } from "lucide-react"; import { MoreVerticalIcon } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
...@@ -9,6 +9,7 @@ import { IdentityProvider } from "@/types/proto/api/v1/idp_service"; ...@@ -9,6 +9,7 @@ import { IdentityProvider } from "@/types/proto/api/v1/idp_service";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import showCreateIdentityProviderDialog from "../CreateIdentityProviderDialog"; import showCreateIdentityProviderDialog from "../CreateIdentityProviderDialog";
import LearnMore from "../LearnMore"; import LearnMore from "../LearnMore";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/Popover";
const SSOSection = () => { const SSOSection = () => {
const t = useTranslate(); const t = useTranslate();
...@@ -60,17 +61,29 @@ const SSOSection = () => { ...@@ -60,17 +61,29 @@ const SSOSection = () => {
</p> </p>
</div> </div>
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<Dropdown> <Popover>
<MenuButton size="sm"> <PopoverTrigger asChild>
<button className="flex items-center justify-center p-1 hover:bg-gray-100 dark:hover:bg-zinc-700 rounded">
<MoreVerticalIcon className="w-4 h-auto" /> <MoreVerticalIcon className="w-4 h-auto" />
</MenuButton> </button>
<Menu placement="bottom-end" size="sm"> </PopoverTrigger>
<MenuItem onClick={() => showCreateIdentityProviderDialog(identityProvider, fetchIdentityProviderList)}> <PopoverContent align="end" sideOffset={2}>
<div className="flex flex-col gap-0.5 text-sm">
<button
onClick={() => showCreateIdentityProviderDialog(identityProvider, fetchIdentityProviderList)}
className="flex items-center gap-2 px-2 py-1 text-left dark:text-zinc-300 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("common.edit")} {t("common.edit")}
</MenuItem> </button>
<MenuItem onClick={() => handleDeleteIdentityProvider(identityProvider)}>{t("common.delete")}</MenuItem> <button
</Menu> onClick={() => handleDeleteIdentityProvider(identityProvider)}
</Dropdown> className="flex items-center gap-2 px-2 py-1 text-left text-red-600 dark:text-red-400 hover:bg-gray-100 dark:hover:bg-zinc-700 outline-none rounded transition-colors"
>
{t("common.delete")}
</button>
</div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
))} ))}
......
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { ArchiveIcon, LogOutIcon, User2Icon, SquareUserIcon, SettingsIcon, BellIcon } from "lucide-react"; import { ArchiveIcon, LogOutIcon, User2Icon, SquareUserIcon, SettingsIcon, BellIcon } from "lucide-react";
import { authServiceClient } from "@/grpcweb"; import { authServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
...@@ -7,6 +6,7 @@ import { Routes } from "@/router"; ...@@ -7,6 +6,7 @@ import { Routes } from "@/router";
import { cn } from "@/utils"; import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
import UserAvatar from "./UserAvatar"; import UserAvatar from "./UserAvatar";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
interface Props { interface Props {
collapsed?: boolean; collapsed?: boolean;
...@@ -25,8 +25,8 @@ const UserBanner = (props: Props) => { ...@@ -25,8 +25,8 @@ const UserBanner = (props: Props) => {
return ( return (
<div className="relative w-full h-auto px-1 shrink-0"> <div className="relative w-full h-auto px-1 shrink-0">
<Dropdown> <Popover>
<MenuButton disabled={!currentUser} slots={{ root: "div" }}> <PopoverTrigger asChild disabled={!currentUser}>
<div <div
className={cn( className={cn(
"w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400", "w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400",
...@@ -44,30 +44,45 @@ const UserBanner = (props: Props) => { ...@@ -44,30 +44,45 @@ const UserBanner = (props: Props) => {
</span> </span>
)} )}
</div> </div>
</MenuButton> </PopoverTrigger>
<Menu size="sm" placement="bottom-start" style={{ zIndex: "9999" }}> <PopoverContent align="start" className="p-1" style={{ zIndex: "9999" }}>
<MenuItem onClick={() => navigateTo(`/u/${encodeURIComponent(currentUser.username)}`)}> <button
onClick={() => navigateTo(`/u/${encodeURIComponent(currentUser.username)}`)}
className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md outline-none"
>
<SquareUserIcon className="w-4 h-auto opacity-60" /> <SquareUserIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.profile")}</span> <span className="truncate">{t("common.profile")}</span>
</MenuItem> </button>
<MenuItem onClick={() => navigateTo(Routes.ARCHIVED)}> <button
onClick={() => navigateTo(Routes.ARCHIVED)}
className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md outline-none"
>
<ArchiveIcon className="w-4 h-auto opacity-60" /> <ArchiveIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.archived")}</span> <span className="truncate">{t("common.archived")}</span>
</MenuItem> </button>
<MenuItem onClick={() => navigateTo(Routes.INBOX)}> <button
onClick={() => navigateTo(Routes.INBOX)}
className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md outline-none"
>
<BellIcon className="w-4 h-auto opacity-60" /> <BellIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.inbox")}</span> <span className="truncate">{t("common.inbox")}</span>
</MenuItem> </button>
<MenuItem onClick={() => navigateTo(Routes.SETTING)}> <button
onClick={() => navigateTo(Routes.SETTING)}
className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md outline-none"
>
<SettingsIcon className="w-4 h-auto opacity-60" /> <SettingsIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.settings")}</span> <span className="truncate">{t("common.settings")}</span>
</MenuItem> </button>
<MenuItem onClick={handleSignOut}> <button
onClick={handleSignOut}
className="w-full flex items-center gap-2 px-2 py-1 text-left text-sm hover:bg-gray-100 rounded-md outline-none"
>
<LogOutIcon className="w-4 h-auto opacity-60" /> <LogOutIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.sign-out")}</span> <span className="truncate">{t("common.sign-out")}</span>
</MenuItem> </button>
</Menu> </PopoverContent>
</Dropdown> </Popover>
</div> </div>
); );
}; };
......
...@@ -16,7 +16,7 @@ const PopoverContent = React.forwardRef< ...@@ -16,7 +16,7 @@ const PopoverContent = React.forwardRef<
align={align} align={align}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-2000 w-auto rounded-md bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-2 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", "z-2000 w-auto rounded-md bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 p-1 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className, className,
)} )}
{...props} {...props}
......
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