fix: workspace level toggle position, paddings, and tab navigation (#6580)

* fix: workspace level toggle position, paddings, and tab navigation

* chore: platform-specific command icons

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
Vihar Kurama 2025-02-11 17:40:31 +05:30 committed by GitHub
parent ac74cd9e92
commit 6aa139a851
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -5,13 +5,13 @@ import { Command } from "cmdk";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import useSWR from "swr"; import useSWR from "swr";
import { FolderPlus, Search, Settings } from "lucide-react"; import { CommandIcon, FolderPlus, Search, Settings } from "lucide-react";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
// plane imports // plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n"; import { useTranslation } from "@plane/i18n";
import { IWorkspaceSearchResults } from "@plane/types"; import { IWorkspaceSearchResults } from "@plane/types";
import { LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui"; import { LayersIcon, Loader, ToggleSwitch } from "@plane/ui";
// components // components
import { import {
ChangeIssueAssignee, ChangeIssueAssignee,
@ -66,13 +66,13 @@ export const CommandModal: React.FC = observer(() => {
page: [], page: [],
}, },
}); });
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false); const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(true);
const [pages, setPages] = useState<string[]>([]); const [pages, setPages] = useState<string[]>([]);
// plane hooks // plane hooks
const { t } = useTranslation(); const { t } = useTranslation();
// hooks // hooks
const { workspaceProjectIds } = useProject(); const { workspaceProjectIds } = useProject();
const { isMobile } = usePlatformOS(); const { platform, isMobile } = usePlatformOS();
const { canPerformAnyCreateAction } = useUser(); const { canPerformAnyCreateAction } = useUser();
const { isCommandPaletteOpen, toggleCommandPaletteModal, toggleCreateIssueModal, toggleCreateProjectModal } = const { isCommandPaletteOpen, toggleCommandPaletteModal, toggleCreateIssueModal, toggleCreateProjectModal } =
useCommandPalette(); useCommandPalette();
@ -176,22 +176,60 @@ export const CommandModal: React.FC = observer(() => {
leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
> >
<Dialog.Panel className="relative flex w-full max-w-2xl transform items-center justify-center divide-y divide-custom-border-200 divide-opacity-10 rounded-lg bg-custom-background-100 shadow-custom-shadow-md transition-all"> <Dialog.Panel className="relative flex w-full max-w-2xl transform flex-col items-center justify-center divide-y divide-custom-border-200 divide-opacity-10 rounded-lg bg-custom-background-100 shadow-custom-shadow-md transition-all">
<div className="w-full max-w-2xl"> <div className="w-full max-w-2xl">
<Command <Command
filter={(value, search) => { filter={(value, search) => {
if (value.toLowerCase().includes(search.toLowerCase())) return 1; if (value.toLowerCase().includes(search.toLowerCase())) return 1;
return 0; return 0;
}} }}
onKeyDown={(e) => { shouldFilter={searchTerm.length > 0}
// when search term is not empty, esc should clear the search term onKeyDown={(e: any) => {
if (e.key === "Escape" && searchTerm) setSearchTerm(""); if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault();
e.stopPropagation();
closePalette();
return;
}
// when user tries to close the modal with esc if (e.key === "Tab") {
if (e.key === "Escape" && !page && !searchTerm) closePalette(); e.preventDefault();
const commandList = document.querySelector("[cmdk-list]");
const items = commandList?.querySelectorAll("[cmdk-item]") || [];
const selectedItem = commandList?.querySelector('[aria-selected="true"]');
if (items.length === 0) return;
const currentIndex = Array.from(items).indexOf(selectedItem as Element);
let nextIndex;
if (e.shiftKey) {
nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
} else {
nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
}
const nextItem = items[nextIndex] as HTMLElement;
if (nextItem) {
nextItem.setAttribute("aria-selected", "true");
selectedItem?.setAttribute("aria-selected", "false");
nextItem.focus();
nextItem.scrollIntoView({
behavior: "smooth",
block: "nearest",
});
}
}
if (e.key === "Escape" && searchTerm) {
e.preventDefault();
setSearchTerm("");
}
if (e.key === "Escape" && !page && !searchTerm) {
e.preventDefault();
closePalette();
}
// Escape goes to previous page
// Backspace goes to previous page when search is empty
if (e.key === "Escape" || (e.key === "Backspace" && !searchTerm)) { if (e.key === "Escape" || (e.key === "Backspace" && !searchTerm)) {
e.preventDefault(); e.preventDefault();
setPages((pages) => pages.slice(0, -1)); setPages((pages) => pages.slice(0, -1));
@ -200,7 +238,7 @@ export const CommandModal: React.FC = observer(() => {
}} }}
> >
<div <div
className={`flex gap-4 p-3 pb-0 sm:items-center ${ className={`flex gap-4 pb-0 sm:items-center ${
issueDetails ? "flex-col justify-between sm:flex-row" : "justify-end" issueDetails ? "flex-col justify-between sm:flex-row" : "justify-end"
}`} }`}
> >
@ -216,23 +254,6 @@ export const CommandModal: React.FC = observer(() => {
{issueDetails.name} {issueDetails.name}
</div> </div>
)} )}
{projectId && (
<Tooltip tooltipContent="Toggle workspace level search" isMobile={isMobile}>
<div className="flex flex-shrink-0 cursor-pointer items-center gap-1 self-end text-xs sm:self-center">
<button
type="button"
onClick={() => setIsWorkspaceLevel((prevData) => !prevData)}
className="flex-shrink-0"
>
Workspace Level
</button>
<ToggleSwitch
value={isWorkspaceLevel}
onChange={() => setIsWorkspaceLevel((prevData) => !prevData)}
/>
</div>
</Tooltip>
)}
</div> </div>
<div className="relative"> <div className="relative">
<Search <Search
@ -413,6 +434,28 @@ export const CommandModal: React.FC = observer(() => {
</Command.List> </Command.List>
</Command> </Command>
</div> </div>
{/* Bottom overlay */}
<div className="w-full flex items-center justify-between px-4 py-2 border-t border-custom-border-200 bg-custom-background-90/80 rounded-b-lg">
<div className="flex items-center gap-2">
<span className="text-xs text-custom-text-300">Actions</span>
<div className="flex items-center gap-1">
<div className="grid h-6 min-w-[1.5rem] place-items-center rounded bg-custom-background-80 border-[0.5px] border-custom-border-200 px-1.5 text-[10px] text-custom-text-200">
{platform === "MacOS" ? <CommandIcon className="h-2.5 w-2.5 text-custom-text-200" /> : "Ctrl"}
</div>
<kbd className="grid h-6 min-w-[1.5rem] place-items-center rounded bg-custom-background-80 border-[0.5px] border-custom-border-200 px-1.5 text-[10px] text-custom-text-200">
K
</kbd>
</div>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-custom-text-300">Workspace Level</span>
<ToggleSwitch
value={isWorkspaceLevel}
onChange={() => setIsWorkspaceLevel((prevData) => !prevData)}
size="sm"
/>
</div>
</div>
</Dialog.Panel> </Dialog.Panel>
</Transition.Child> </Transition.Child>
</div> </div>