[WEB-127] fix: issue with command palette outside click detection. (#3812)

This commit is contained in:
Prateek Shourya 2024-02-28 15:19:11 +05:30 committed by GitHub
parent 6c70d3854a
commit 7e46cbcb52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -154,237 +154,239 @@ export const CommandModal: React.FC = observer(() => {
<div className="fixed inset-0 bg-custom-backdrop transition-opacity" /> <div className="fixed inset-0 bg-custom-backdrop transition-opacity" />
</Transition.Child> </Transition.Child>
<div className="fixed inset-0 z-30 overflow-y-auto p-4 sm:p-6 md:p-20"> <div className="fixed inset-0 z-30 overflow-y-auto">
<Transition.Child <div className="flex items-center justify-center p-4 sm:p-6 md:p-20">
as={React.Fragment} <Transition.Child
enter="ease-out duration-300" as={React.Fragment}
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter="ease-out duration-300"
enterTo="opacity-100 translate-y-0 sm:scale-100" enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
leave="ease-in duration-200" enterTo="opacity-100 translate-y-0 sm:scale-100"
leaveFrom="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" leaveFrom="opacity-100 translate-y-0 sm:scale-100"
> leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
<Dialog.Panel className="relative flex w-full items-center justify-center "> >
<div className="w-full max-w-2xl transform 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 items-center justify-center transform divide-y divide-custom-border-200 divide-opacity-10 rounded-lg bg-custom-background-100 shadow-custom-shadow-md transition-all">
<Command <div className="w-full max-w-2xl">
filter={(value, search) => { <Command
if (value.toLowerCase().includes(search.toLowerCase())) return 1; filter={(value, search) => {
return 0; if (value.toLowerCase().includes(search.toLowerCase())) return 1;
}} return 0;
onKeyDown={(e) => { }}
// when search is empty and page is undefined onKeyDown={(e) => {
// when user tries to close the modal with esc // when search is empty and page is undefined
if (e.key === "Escape" && !page && !searchTerm) closePalette(); // when user tries to close the modal with esc
if (e.key === "Escape" && !page && !searchTerm) closePalette();
// Escape goes to previous page // Escape goes to previous page
// Backspace goes to previous page when search is empty // 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));
setPlaceholder("Type a command or search..."); setPlaceholder("Type a command or search...");
} }
}} }}
>
<div
className={`flex gap-4 p-3 pb-0 sm:items-center ${
issueDetails ? "flex-col justify-between sm:flex-row" : "justify-end"
}`}
> >
{issueDetails && ( <div
<div className="overflow-hidden truncate rounded-md bg-custom-background-80 p-2 text-xs font-medium text-custom-text-200"> className={`flex gap-4 p-3 pb-0 sm:items-center ${
{projectDetails?.identifier}-{issueDetails.sequence_id} {issueDetails.name} issueDetails ? "flex-col justify-between sm:flex-row" : "justify-end"
</div> }`}
)} >
{projectId && ( {issueDetails && (
<Tooltip tooltipContent="Toggle workspace level search"> <div className="overflow-hidden truncate rounded-md bg-custom-background-80 p-2 text-xs font-medium text-custom-text-200">
<div className="flex flex-shrink-0 cursor-pointer items-center gap-1 self-end text-xs sm:self-center"> {projectDetails?.identifier}-{issueDetails.sequence_id} {issueDetails.name}
<button
type="button"
onClick={() => setIsWorkspaceLevel((prevData) => !prevData)}
className="flex-shrink-0"
>
Workspace Level
</button>
<ToggleSwitch
value={isWorkspaceLevel}
onChange={() => setIsWorkspaceLevel((prevData) => !prevData)}
/>
</div> </div>
</Tooltip> )}
)} {projectId && (
</div> <Tooltip tooltipContent="Toggle workspace level search">
<div className="relative"> <div className="flex flex-shrink-0 cursor-pointer items-center gap-1 self-end text-xs sm:self-center">
<Search <button
className="pointer-events-none absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-custom-text-200" type="button"
aria-hidden="true" onClick={() => setIsWorkspaceLevel((prevData) => !prevData)}
strokeWidth={2} className="flex-shrink-0"
/> >
<Command.Input Workspace Level
className="w-full border-0 border-b border-custom-border-200 bg-transparent p-4 pl-11 text-sm text-custom-text-100 outline-none placeholder:text-custom-text-400 focus:ring-0" </button>
placeholder={placeholder} <ToggleSwitch
value={searchTerm} value={isWorkspaceLevel}
onValueChange={(e) => setSearchTerm(e)} onChange={() => setIsWorkspaceLevel((prevData) => !prevData)}
autoFocus />
tabIndex={1} </div>
/> </Tooltip>
</div> )}
</div>
<div className="relative">
<Search
className="pointer-events-none absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-custom-text-200"
aria-hidden="true"
strokeWidth={2}
/>
<Command.Input
className="w-full border-0 border-b border-custom-border-200 bg-transparent p-4 pl-11 text-sm text-custom-text-100 outline-none placeholder:text-custom-text-400 focus:ring-0"
placeholder={placeholder}
value={searchTerm}
onValueChange={(e) => setSearchTerm(e)}
autoFocus
tabIndex={1}
/>
</div>
<Command.List className="max-h-96 overflow-scroll p-2 vertical-scrollbar scrollbar-sm"> <Command.List className="max-h-96 overflow-scroll p-2 vertical-scrollbar scrollbar-sm">
{searchTerm !== "" && ( {searchTerm !== "" && (
<h5 className="mx-[3px] my-4 text-xs text-custom-text-100"> <h5 className="mx-[3px] my-4 text-xs text-custom-text-100">
Search results for{" "} Search results for{" "}
<span className="font-medium"> <span className="font-medium">
{'"'} {'"'}
{searchTerm} {searchTerm}
{'"'} {'"'}
</span>{" "} </span>{" "}
in {!projectId || isWorkspaceLevel ? "workspace" : "project"}: in {!projectId || isWorkspaceLevel ? "workspace" : "project"}:
</h5> </h5>
)} )}
{!isLoading && resultsCount === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && ( {!isLoading && resultsCount === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
<div className="my-4 text-center text-sm text-custom-text-200">No results found.</div> <div className="my-4 text-center text-sm text-custom-text-200">No results found.</div>
)} )}
{(isLoading || isSearching) && ( {(isLoading || isSearching) && (
<Command.Loading> <Command.Loading>
<Loader className="space-y-3"> <Loader className="space-y-3">
<Loader.Item height="40px" /> <Loader.Item height="40px" />
<Loader.Item height="40px" /> <Loader.Item height="40px" />
<Loader.Item height="40px" /> <Loader.Item height="40px" />
<Loader.Item height="40px" /> <Loader.Item height="40px" />
</Loader> </Loader>
</Command.Loading> </Command.Loading>
)} )}
{debouncedSearchTerm !== "" && ( {debouncedSearchTerm !== "" && (
<CommandPaletteSearchResults closePalette={closePalette} results={results} /> <CommandPaletteSearchResults closePalette={closePalette} results={results} />
)} )}
{!page && ( {!page && (
<> <>
{/* issue actions */} {/* issue actions */}
{issueId && ( {issueId && (
<CommandPaletteIssueActions <CommandPaletteIssueActions
closePalette={closePalette} closePalette={closePalette}
issueDetails={issueDetails} issueDetails={issueDetails}
pages={pages} pages={pages}
setPages={(newPages) => setPages(newPages)} setPages={(newPages) => setPages(newPages)}
setPlaceholder={(newPlaceholder) => setPlaceholder(newPlaceholder)} setPlaceholder={(newPlaceholder) => setPlaceholder(newPlaceholder)}
setSearchTerm={(newSearchTerm) => setSearchTerm(newSearchTerm)} setSearchTerm={(newSearchTerm) => setSearchTerm(newSearchTerm)}
/> />
)} )}
<Command.Group heading="Issue"> <Command.Group heading="Issue">
<Command.Item
onSelect={() => {
closePalette();
setTrackElement("Command Palette");
toggleCreateIssueModal(true);
}}
className="focus:bg-custom-background-80"
>
<div className="flex items-center gap-2 text-custom-text-200">
<LayersIcon className="h-3.5 w-3.5" />
Create new issue
</div>
<kbd>C</kbd>
</Command.Item>
</Command.Group>
{workspaceSlug && (
<Command.Group heading="Project">
<Command.Item <Command.Item
onSelect={() => { onSelect={() => {
closePalette(); closePalette();
setTrackElement("Command palette"); setTrackElement("Command Palette");
toggleCreateProjectModal(true); toggleCreateIssueModal(true);
}}
className="focus:bg-custom-background-80"
>
<div className="flex items-center gap-2 text-custom-text-200">
<LayersIcon className="h-3.5 w-3.5" />
Create new issue
</div>
<kbd>C</kbd>
</Command.Item>
</Command.Group>
{workspaceSlug && (
<Command.Group heading="Project">
<Command.Item
onSelect={() => {
closePalette();
setTrackElement("Command palette");
toggleCreateProjectModal(true);
}}
className="focus:outline-none"
>
<div className="flex items-center gap-2 text-custom-text-200">
<FolderPlus className="h-3.5 w-3.5" />
Create new project
</div>
<kbd>P</kbd>
</Command.Item>
</Command.Group>
)}
{/* project actions */}
{projectId && <CommandPaletteProjectActions closePalette={closePalette} />}
<Command.Group heading="Workspace Settings">
<Command.Item
onSelect={() => {
setPlaceholder("Search workspace settings...");
setSearchTerm("");
setPages([...pages, "settings"]);
}} }}
className="focus:outline-none" className="focus:outline-none"
> >
<div className="flex items-center gap-2 text-custom-text-200"> <div className="flex items-center gap-2 text-custom-text-200">
<FolderPlus className="h-3.5 w-3.5" /> <Settings className="h-3.5 w-3.5" />
Create new project Search settings...
</div>
</Command.Item>
</Command.Group>
<Command.Group heading="Account">
<Command.Item onSelect={createNewWorkspace} className="focus:outline-none">
<div className="flex items-center gap-2 text-custom-text-200">
<FolderPlus className="h-3.5 w-3.5" />
Create new workspace
</div>
</Command.Item>
<Command.Item
onSelect={() => {
setPlaceholder("Change interface theme...");
setSearchTerm("");
setPages([...pages, "change-interface-theme"]);
}}
className="focus:outline-none"
>
<div className="flex items-center gap-2 text-custom-text-200">
<Settings className="h-3.5 w-3.5" />
Change interface theme...
</div> </div>
<kbd>P</kbd>
</Command.Item> </Command.Item>
</Command.Group> </Command.Group>
)}
{/* project actions */} {/* help options */}
{projectId && <CommandPaletteProjectActions closePalette={closePalette} />} <CommandPaletteHelpActions closePalette={closePalette} />
</>
)}
<Command.Group heading="Workspace Settings"> {/* workspace settings actions */}
<Command.Item {page === "settings" && workspaceSlug && (
onSelect={() => { <CommandPaletteWorkspaceSettingsActions closePalette={closePalette} />
setPlaceholder("Search workspace settings..."); )}
setSearchTerm("");
setPages([...pages, "settings"]);
}}
className="focus:outline-none"
>
<div className="flex items-center gap-2 text-custom-text-200">
<Settings className="h-3.5 w-3.5" />
Search settings...
</div>
</Command.Item>
</Command.Group>
<Command.Group heading="Account">
<Command.Item onSelect={createNewWorkspace} className="focus:outline-none">
<div className="flex items-center gap-2 text-custom-text-200">
<FolderPlus className="h-3.5 w-3.5" />
Create new workspace
</div>
</Command.Item>
<Command.Item
onSelect={() => {
setPlaceholder("Change interface theme...");
setSearchTerm("");
setPages([...pages, "change-interface-theme"]);
}}
className="focus:outline-none"
>
<div className="flex items-center gap-2 text-custom-text-200">
<Settings className="h-3.5 w-3.5" />
Change interface theme...
</div>
</Command.Item>
</Command.Group>
{/* help options */} {/* issue details page actions */}
<CommandPaletteHelpActions closePalette={closePalette} /> {page === "change-issue-state" && issueDetails && (
</> <ChangeIssueState closePalette={closePalette} issue={issueDetails} />
)} )}
{page === "change-issue-priority" && issueDetails && (
<ChangeIssuePriority closePalette={closePalette} issue={issueDetails} />
)}
{page === "change-issue-assignee" && issueDetails && (
<ChangeIssueAssignee closePalette={closePalette} issue={issueDetails} />
)}
{/* workspace settings actions */} {/* theme actions */}
{page === "settings" && workspaceSlug && ( {page === "change-interface-theme" && (
<CommandPaletteWorkspaceSettingsActions closePalette={closePalette} /> <CommandPaletteThemeActions
)} closePalette={() => {
closePalette();
{/* issue details page actions */} setPages((pages) => pages.slice(0, -1));
{page === "change-issue-state" && issueDetails && ( }}
<ChangeIssueState closePalette={closePalette} issue={issueDetails} /> />
)} )}
{page === "change-issue-priority" && issueDetails && ( </Command.List>
<ChangeIssuePriority closePalette={closePalette} issue={issueDetails} /> </Command>
)} </div>
{page === "change-issue-assignee" && issueDetails && ( </Dialog.Panel>
<ChangeIssueAssignee closePalette={closePalette} issue={issueDetails} /> </Transition.Child>
)} </div>
{/* theme actions */}
{page === "change-interface-theme" && (
<CommandPaletteThemeActions
closePalette={() => {
closePalette();
setPages((pages) => pages.slice(0, -1));
}}
/>
)}
</Command.List>
</Command>
</div>
</Dialog.Panel>
</Transition.Child>
</div> </div>
</Dialog> </Dialog>
</Transition.Root> </Transition.Root>