Skip to content

Commit 105ac5e

Browse files
[WEB-5569] chore: top nav search enhancements (#8226)
* chore: top nav power k search menu enhancements * chore: expandable search panel refactor
1 parent b8a41ad commit 105ac5e

File tree

4 files changed

+33
-7
lines changed

4 files changed

+33
-7
lines changed

apps/web/core/components/navigation/top-nav-power-k.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ export const TopNavPowerK = observer(() => {
272272
isWorkspaceLevel={isWorkspaceLevel}
273273
searchTerm={searchTerm}
274274
setSearchTerm={setSearchTerm}
275+
handleSearchMenuClose={() => closePanel()}
275276
/>
276277
</Command.List>
277278
<PowerKModalFooter

apps/web/core/components/power-k/ui/modal/commands-list.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type TPowerKCommandsListProps = {
1111
isWorkspaceLevel: boolean;
1212
searchTerm: string;
1313
setSearchTerm: (value: string) => void;
14+
handleSearchMenuClose?: () => void;
1415
};
1516

1617
export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) {
@@ -22,6 +23,7 @@ export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) {
2223
isWorkspaceLevel,
2324
searchTerm,
2425
setSearchTerm,
26+
handleSearchMenuClose,
2527
} = props;
2628

2729
return (
@@ -32,6 +34,7 @@ export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) {
3234
isWorkspaceLevel={!context.params.projectId || isWorkspaceLevel}
3335
searchTerm={searchTerm}
3436
updateSearchTerm={setSearchTerm}
37+
handleSearchMenuClose={handleSearchMenuClose}
3538
/>
3639
<PowerKContextBasedPagesList
3740
activeContext={context.activeContext}

apps/web/core/components/power-k/ui/modal/search-menu.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ type Props = {
2222
isWorkspaceLevel: boolean;
2323
searchTerm: string;
2424
updateSearchTerm: (value: string) => void;
25+
handleSearchMenuClose?: () => void;
2526
};
2627

2728
export function PowerKModalSearchMenu(props: Props) {
28-
const { activePage, context, isWorkspaceLevel, searchTerm, updateSearchTerm } = props;
29+
const { activePage, context, isWorkspaceLevel, searchTerm, updateSearchTerm, handleSearchMenuClose } = props;
2930
// states
3031
const [resultsCount, setResultsCount] = useState(0);
3132
const [isSearching, setIsSearching] = useState(false);
@@ -68,6 +69,11 @@ export function PowerKModalSearchMenu(props: Props) {
6869

6970
if (activePage) return null;
7071

72+
const handleClosePalette = () => {
73+
handleSearchMenuClose?.();
74+
togglePowerKModal(false);
75+
};
76+
7177
return (
7278
<>
7379
{searchTerm.trim() !== "" && (
@@ -97,9 +103,7 @@ export function PowerKModalSearchMenu(props: Props) {
97103
/>
98104
)}
99105

100-
{searchTerm.trim() !== "" && (
101-
<PowerKModalSearchResults closePalette={() => togglePowerKModal(false)} results={results} />
102-
)}
106+
{searchTerm.trim() !== "" && <PowerKModalSearchResults closePalette={handleClosePalette} results={results} />}
103107
</>
104108
);
105109
}

apps/web/core/hooks/use-expandable-search.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useRef, useState } from "react";
1+
import { useCallback, useEffect, useRef, useState } from "react";
22
import { useOutsideClickDetector } from "@plane/hooks";
33

44
type UseExpandableSearchOptions = {
@@ -8,6 +8,7 @@ type UseExpandableSearchOptions = {
88
/**
99
* Custom hook for expandable search input behavior
1010
* Handles focus management to prevent unwanted opening on programmatic focus restoration
11+
* Opens on click, typing, or keyboard shortcut (via PowerK Cmd+F)
1112
*/
1213
export const useExpandableSearch = (options?: UseExpandableSearchOptions) => {
1314
const { onClose } = options || {};
@@ -19,6 +20,7 @@ export const useExpandableSearch = (options?: UseExpandableSearchOptions) => {
1920
const containerRef = useRef<HTMLDivElement>(null);
2021
const inputRef = useRef<HTMLInputElement>(null);
2122
const wasClickedRef = useRef<boolean>(false);
23+
const wasKeyboardTriggeredRef = useRef<boolean>(false);
2224

2325
// Handle close
2426
const handleClose = useCallback(() => {
@@ -37,16 +39,32 @@ export const useExpandableSearch = (options?: UseExpandableSearchOptions) => {
3739
// Outside click detection
3840
useOutsideClickDetector(containerRef, handleOutsideClick);
3941

42+
// Track keyboard shortcuts that trigger focus (Cmd+F / Ctrl+F)
43+
useEffect(() => {
44+
const handleKeyDown = (e: KeyboardEvent) => {
45+
if ((e.metaKey || e.ctrlKey) && e.key === "f") {
46+
// Mark as keyboard triggered so handleFocus knows to open
47+
wasKeyboardTriggeredRef.current = true;
48+
}
49+
};
50+
51+
document.addEventListener("keydown", handleKeyDown);
52+
return () => {
53+
document.removeEventListener("keydown", handleKeyDown);
54+
};
55+
}, []);
56+
4057
// Track explicit clicks
4158
const handleMouseDown = useCallback(() => {
4259
wasClickedRef.current = true;
4360
}, []);
4461

45-
// Only open on explicit clicks, not programmatic focus
62+
// Open on explicit clicks or keyboard shortcut, not programmatic focus restoration
4663
const handleFocus = useCallback(() => {
47-
if (wasClickedRef.current) {
64+
if (wasClickedRef.current || wasKeyboardTriggeredRef.current) {
4865
setIsOpen(true);
4966
wasClickedRef.current = false;
67+
wasKeyboardTriggeredRef.current = false;
5068
}
5169
}, []);
5270

0 commit comments

Comments
 (0)