[WEB-3978] chore: cmd k search result redirection improvements (#7012)

* fix: work item tab highlight

* chore: projectListOpen state and toggle method added to command palette store

* chore: openProjectAndScrollToSidebar helper function and highlight keyframes added

* chore: SidebarProjectsListItem updated

* chore: openProjectAndScrollToSidebar implementation

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor
This commit is contained in:
Anmol Singh Bhatia 2025-05-12 19:15:39 +05:30 committed by GitHub
parent 5f8d5ea388
commit 079c3a3a99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 72 additions and 5 deletions

View file

@ -0,0 +1,25 @@
import { store } from "@/lib/store-context";
export const openProjectAndScrollToSidebar = (itemProjectId: string | undefined) => {
if (!itemProjectId) {
console.warn("No project id provided. Cannot open project and scroll to sidebar.");
return;
}
// open the project list
store.commandPalette.toggleProjectListOpen(itemProjectId, true);
// scroll to the element
const scrollElementId = `sidebar-${itemProjectId}-JOINED`;
const scrollElement = document.getElementById(scrollElementId);
// if the element exists, scroll to it
if (scrollElement) {
setTimeout(() => {
scrollElement.scrollIntoView({ behavior: "smooth", block: "start" });
// Restart the highlight animation every time
scrollElement.style.animation = "none";
// Trigger a reflow to ensure the animation is restarted
void scrollElement.offsetWidth;
// Restart the highlight animation
scrollElement.style.animation = "highlight 2s ease-in-out";
});
}
};

View file

@ -1,6 +1,7 @@
"use client";
import { Command } from "cmdk";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane imports
import { IWorkspaceSearchResults } from "@plane/types";
@ -8,13 +9,15 @@ import { IWorkspaceSearchResults } from "@plane/types";
import { useAppRouter } from "@/hooks/use-app-router";
// plane web imports
import { commandGroups } from "@/plane-web/components/command-palette";
// helpers
import { openProjectAndScrollToSidebar } from "./helper";
type Props = {
closePalette: () => void;
results: IWorkspaceSearchResults;
};
export const CommandPaletteSearchResults: React.FC<Props> = (props) => {
export const CommandPaletteSearchResults: React.FC<Props> = observer((props) => {
const { closePalette, results } = props;
// router
const router = useAppRouter();
@ -38,6 +41,12 @@ export const CommandPaletteSearchResults: React.FC<Props> = (props) => {
onSelect={() => {
closePalette();
router.push(currentSection.path(item, projectId));
const itemProjectId =
item?.project_id ||
(Array.isArray(item?.project_ids) && item?.project_ids?.length > 0
? item?.project_ids[0]
: undefined);
if (itemProjectId) openProjectAndScrollToSidebar(itemProjectId);
}}
value={`${key}-${item?.id}-${item.name}-${item.project__identifier ?? ""}-${item.sequence_id ?? ""}`}
className="focus:outline-none"
@ -54,4 +63,4 @@ export const CommandPaletteSearchResults: React.FC<Props> = (props) => {
})}
</>
);
};
});

View file

@ -24,7 +24,7 @@ import { LeaveProjectModal, PublishProjectModal } from "@/components/project";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { useAppTheme, useCommandPalette, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane-web components
import { ProjectNavigationRoot } from "@/plane-web/components/sidebar";
@ -64,12 +64,13 @@ export const SidebarProjectsListItem: React.FC<Props> = observer((props) => {
const { getPartialProjectById } = useProject();
const { isMobile } = usePlatformOS();
const { allowPermissions } = useUserPermissions();
const { getIsProjectListOpen, toggleProjectListOpen } = useCommandPalette();
// states
const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false);
const [publishModalOpen, setPublishModal] = useState(false);
const [isMenuActive, setIsMenuActive] = useState(false);
const [isDragging, setIsDragging] = useState(false);
const [isProjectListOpen, setIsProjectListOpen] = useState(false);
const isProjectListOpen = getIsProjectListOpen(projectId);
const [instruction, setInstruction] = useState<"DRAG_OVER" | "DRAG_BELOW" | undefined>(undefined);
// refs
const actionSectionRef = useRef<HTMLDivElement | null>(null);
@ -79,6 +80,8 @@ export const SidebarProjectsListItem: React.FC<Props> = observer((props) => {
const { workspaceSlug, projectId: URLProjectId } = useParams();
// derived values
const project = getPartialProjectById(projectId);
// toggle project list open
const setIsProjectListOpen = (value: boolean) => toggleProjectListOpen(projectId, value);
// auth
const isAdmin = allowPermissions(
[EUserPermissions.ADMIN],
@ -198,7 +201,7 @@ export const SidebarProjectsListItem: React.FC<Props> = observer((props) => {
if (URLProjectId === project.id) setIsProjectListOpen(true);
}, [URLProjectId]);
const handleItemClick = () => setIsProjectListOpen((prev) => !prev);
const handleItemClick = () => setIsProjectListOpen(!isProjectListOpen);
return (
<>
<PublishProjectModal isOpen={publishModalOpen} project={project} onClose={() => setPublishModal(false)} />