chore: use select/dropdown instead of popover

pull/4833/head
Steven 4 months ago
parent d32924ec48
commit c1708df7a2

@ -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"
}
},
@ -346,4 +346,4 @@
"delete-tag": "Hapus Tag",
"no-tag-found": "Tidak ada tag ditemukan"
}
}
}
Loading…
Cancel
Save