mirror of
https://github.com/usememos/memos.git
synced 2025-12-18 22:59:24 +08:00
chore: use select/dropdown instead of popover
This commit is contained in:
parent
d32924ec48
commit
c1708df7a2
9 changed files with 57 additions and 97 deletions
|
|
@ -40,7 +40,7 @@ const HomeSidebar = observer((props: Props) => {
|
|||
return (
|
||||
<aside
|
||||
className={cn(
|
||||
"relative w-full h-full overflow-auto flex flex-col justify-start items-start bg-sidebar text-sidebar-foreground",
|
||||
"relative w-full h-full overflow-auto flex flex-col justify-start items-start bg-background text-sidebar-foreground",
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { CheckSquareIcon, Code2Icon, SquareSlashIcon } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../../ui/dropdown-menu";
|
||||
import { EditorRefActions } from "../Editor";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -60,41 +60,33 @@ const MarkdownMenu = (props: Props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">
|
||||
<SquareSlashIcon className="size-5" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="start" className="text-sm p-1">
|
||||
<div className="flex flex-col text-sm gap-0.5">
|
||||
<button
|
||||
onClick={handleCodeBlockClick}
|
||||
className="flex items-center gap-2 px-2 py-1 text-left text-foreground hover:bg-background outline-none rounded"
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={handleCodeBlockClick}>
|
||||
<Code2Icon className="w-4 h-auto text-muted-foreground" />
|
||||
{t("markdown.code-block")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleCheckboxClick}>
|
||||
<CheckSquareIcon className="w-4 h-auto text-muted-foreground" />
|
||||
{t("markdown.checkbox")}
|
||||
</DropdownMenuItem>
|
||||
<div className="px-2 -mt-1">
|
||||
<a
|
||||
className="text-xs text-primary hover:underline"
|
||||
href="https://www.usememos.com/docs/getting-started/content-syntax"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Code2Icon className="w-4 h-auto" />
|
||||
<span>{t("markdown.code-block")}</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCheckboxClick}
|
||||
className="flex items-center gap-2 px-2 py-1 text-left text-foreground hover:bg-background outline-none rounded"
|
||||
>
|
||||
<CheckSquareIcon className="w-4 h-auto" />
|
||||
<span>{t("markdown.checkbox")}</span>
|
||||
</button>
|
||||
<div className="pl-2">
|
||||
<a
|
||||
className="text-xs text-primary hover:underline"
|
||||
href="https://www.usememos.com/docs/getting-started/content-syntax"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t("markdown.content-syntax")}
|
||||
</a>
|
||||
</div>
|
||||
{t("markdown.content-syntax")}
|
||||
</a>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { ChevronDownIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import VisibilityIcon from "@/components/VisibilityIcon";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Visibility } from "@/types/proto/api/v1/memo_service";
|
||||
import { useTranslate } from "@/utils/i18n";
|
||||
|
||||
|
|
@ -10,13 +7,11 @@ interface Props {
|
|||
value: Visibility;
|
||||
onChange: (visibility: Visibility) => void;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const VisibilitySelector = (props: Props) => {
|
||||
const { value, onChange } = props;
|
||||
const t = useTranslate();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const visibilityOptions = [
|
||||
{ value: Visibility.PRIVATE, label: t("memo.visibility.private") },
|
||||
|
|
@ -24,53 +19,26 @@ const VisibilitySelector = (props: Props) => {
|
|||
{ value: Visibility.PUBLIC, label: t("memo.visibility.public") },
|
||||
];
|
||||
|
||||
const currentOption = visibilityOptions.find((option) => option.value === value);
|
||||
|
||||
const handleSelect = (visibility: Visibility) => {
|
||||
onChange(visibility);
|
||||
handleOpenChange(false);
|
||||
};
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setOpen(open);
|
||||
if (props.onOpenChange) {
|
||||
props.onOpenChange(open);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={handleOpenChange}>
|
||||
<PopoverTrigger asChild>
|
||||
<button
|
||||
className={cn(
|
||||
`flex items-center justify-center gap-1 px-0.5 text-xs rounded hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 transition-colors`,
|
||||
props.className,
|
||||
)}
|
||||
type="button"
|
||||
>
|
||||
<VisibilityIcon className="w-3 h-3" visibility={value} />
|
||||
<span>{currentOption?.label}</span>
|
||||
<ChevronDownIcon className="w-3 h-3 opacity-60" />
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-1!" align="end" sideOffset={2} alignOffset={-4}>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
{visibilityOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
onClick={() => handleSelect(option.value)}
|
||||
className={cn(
|
||||
`flex items-center gap-1 px-1 py-1 text-xs text-left hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 rounded transition-colors`,
|
||||
option.value === value ? "bg-muted" : "",
|
||||
)}
|
||||
>
|
||||
<VisibilityIcon className="w-3 h-3" visibility={option.value} />
|
||||
<span>{option.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Select value={value.toString()} onValueChange={onChange} onOpenChange={handleOpenChange}>
|
||||
<SelectTrigger size="xs" className="!bg-background">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent align="end">
|
||||
{visibilityOptions.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value.toString()}>
|
||||
<VisibilityIcon className="size-3.5" visibility={option.value} />
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ const MemoEditor = observer((props: Props) => {
|
|||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute right-1 top-1 opacity-60",
|
||||
"absolute right-1 top-1",
|
||||
"flex flex-row justify-end items-center gap-1",
|
||||
"invisible group-focus-within:visible group-hover:visible hover:visible focus-within:visible",
|
||||
(isVisibilitySelectorOpen || memoName) && "visible",
|
||||
|
|
|
|||
|
|
@ -33,15 +33,15 @@ const SearchBar = observer(() => {
|
|||
|
||||
return (
|
||||
<div className="relative w-full h-auto flex flex-row justify-start items-center">
|
||||
<SearchIcon className="absolute left-2 w-4 h-auto opacity-40 text-muted-foreground" />
|
||||
<SearchIcon className="absolute left-2 w-4 h-auto opacity-40 text-sidebar-foreground" />
|
||||
<input
|
||||
className={cn("w-full text-muted-foreground leading-6 bg-muted border border-border text-sm rounded-lg p-1 pl-8 outline-0")}
|
||||
className={cn("w-full text-sidebar-foreground leading-6 bg-sidebar border border-border text-sm rounded-lg p-1 pl-8 outline-0")}
|
||||
placeholder={t("memo.search-placeholder")}
|
||||
value={queryText}
|
||||
onChange={onTextChange}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<MemoDisplaySettingMenu className="absolute right-2 top-2 text-muted-foreground" />
|
||||
<MemoDisplaySettingMenu className="absolute right-2 top-2 text-sidebar-foreground" />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,24 +41,24 @@ const UserBanner = (props: Props) => {
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuItem onClick={() => navigateTo(`/u/${encodeURIComponent(currentUser.username)}`)}>
|
||||
<SquareUserIcon className="w-4 h-auto text-muted-foreground" />
|
||||
<span className="truncate">{t("common.profile")}</span>
|
||||
<SquareUserIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.profile")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigateTo(Routes.ARCHIVED)}>
|
||||
<ArchiveIcon className="w-4 h-auto text-muted-foreground" />
|
||||
<span className="truncate">{t("common.archived")}</span>
|
||||
<ArchiveIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.archived")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigateTo(Routes.INBOX)}>
|
||||
<BellIcon className="w-4 h-auto text-muted-foreground" />
|
||||
<span className="truncate">{t("common.inbox")}</span>
|
||||
<BellIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.inbox")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigateTo(Routes.SETTING)}>
|
||||
<SettingsIcon className="w-4 h-auto text-muted-foreground" />
|
||||
<span className="truncate">{t("common.settings")}</span>
|
||||
<SettingsIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.settings")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleSignOut}>
|
||||
<LogOutIcon className="w-4 h-auto text-muted-foreground" />
|
||||
<span className="truncate">{t("common.sign-out")}</span>
|
||||
<LogOutIcon className="size-4 text-muted-foreground" />
|
||||
{t("common.sign-out")}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ function SelectTrigger({
|
|||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default";
|
||||
size?: "xs" | "sm" | "default";
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-2 py-1 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-8 data-[size=sm]:h-7 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"border-border data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between rounded-md border bg-transparent text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-8 data-[size=default]:gap-2 data-[size=default]:px-2 data-[size=default]:py-1 data-[size=sm]:h-7 data-[size=sm]:gap-2 data-[size=sm]:px-2 data-[size=sm]:py-1 data-[size=xs]:h-6 data-[size=xs]:gap-1 data-[size=xs]:px-1 data-[size=xs]:py-0.5 data-[size=xs]:text-xs *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@
|
|||
"visibility": {
|
||||
"disabled": "Public memos are disabled",
|
||||
"private": "Private",
|
||||
"protected": "Workspace",
|
||||
"protected": "Protected",
|
||||
"public": "Public"
|
||||
},
|
||||
"list": "List",
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
"visibility": {
|
||||
"disabled": "Memo publik dinonaktifkan",
|
||||
"private": "Pribadi",
|
||||
"protected": "Workspace",
|
||||
"protected": "Protected",
|
||||
"public": "Publik"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue