Skip to content

Commit d79e566

Browse files
authored
Implement Ctrl/Cmd + K Search Shortcut with Animated, Focused Overlay… (#1177)
* Implement Ctrl/Cmd + K Search Shortcut with Animated, Focused Overlay Input #1176 * Implement Ctrl/Cmd + K Search Shortcut with Animated, Focused Overlay Input #1176
1 parent e6df7ad commit d79e566

File tree

1 file changed

+55
-11
lines changed

1 file changed

+55
-11
lines changed

frontend/src/components/Navbar.jsx

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useContext, useEffect, useState } from "react";
1+
import { useContext, useEffect, useRef, useState } from "react";
22
import { Link, Outlet, useNavigate } from "react-router-dom";
33
import { UserContext } from "../App";
44
import UserNavigationPanel from "./UserNavigationPanel";
@@ -11,6 +11,7 @@ const Navbar = () => {
1111
const [searchBoxVisibility, setSearchBoxVisibility] = useState(false);
1212
const [userNavPanel, setUserNavPanel] = useState(false);
1313
const [showSubscribeModal, setShowSubscribeModal] = useState(false);
14+
const searchRef = useRef(null);
1415

1516
let navigate = useNavigate();
1617

@@ -45,6 +46,38 @@ const Navbar = () => {
4546
}
4647
}
4748

49+
useEffect(() => {
50+
const handleKeyDown = (event) => {
51+
if ((event.metaKey && event.key === 'k') || (event.ctrlKey && event.key === 'k')) {
52+
event.preventDefault();
53+
event.stopPropagation();
54+
55+
// Check screen width - show mobile-style search for tablet and below
56+
if (window.innerWidth >= 1024) { // Desktop (lg screens)
57+
setTimeout(() => {
58+
if (searchRef.current) {
59+
searchRef.current.focus();
60+
searchRef.current.select();
61+
}
62+
}, 10);
63+
} else { // Tablet and mobile
64+
setSearchBoxVisibility(true);
65+
setTimeout(() => {
66+
if (searchRef.current) {
67+
searchRef.current.focus();
68+
}
69+
}, 100);
70+
}
71+
}
72+
};
73+
74+
document.addEventListener('keydown', handleKeyDown, true);
75+
76+
return () => {
77+
document.removeEventListener('keydown', handleKeyDown, true);
78+
};
79+
}, []);
80+
4881
const handleBlur = () => {
4982
setTimeout(() => {
5083
setUserNavPanel(false);
@@ -61,22 +94,33 @@ const Navbar = () => {
6194
<Link to="/" className="flex-none w-10">
6295
<img src="/logo.png" alt="" className="w-full rounded-md" />
6396
</Link>
64-
6597
<div
66-
className={"absolute bg-[#fafafa] dark:bg-[#09090b] w-full left-0 top-full mt-0.5 border-b border-gray-200 dark:border-[#27272a] py-4 px-[5vw] md:border-0 md:relative md:inset-0 md:p-0 md:w-auto " +
67-
(searchBoxVisibility ? "show" : "hidden md:block")}
98+
className={`absolute bg-[#fafafa] dark:bg-[#09090b] w-full left-0 top-full mt-0.5 border-b border-gray-200 dark:border-[#27272a] py-4 px-[5vw] lg:border-0 lg:relative lg:inset-0 lg:p-0 ${
99+
searchBoxVisibility ? "block" : "hidden lg:block"
100+
}`}
68101
>
69102
<input
70103
type="text"
71-
placeholder="Search"
72-
className="w-full md:w-auto bg-[#ffffff] dark:bg-[#18181b] p-4 pl-6 pr-[12%] md:pr-6 rounded-full placeholder:text-dark-grey dark:placeholder:text-gray-400 md:pl-12"
104+
placeholder={searchBoxVisibility ? "Search" : "Press Ctrl+K"}
105+
id="search-bar"
106+
ref={searchRef}
107+
className="w-full lg:w-58 bg-[#ffffff] dark:bg-[#18181b] p-4 pl-6 pr-[12%] lg:pr-6 rounded-full placeholder:text-dark-grey dark:placeholder:text-gray-400 lg:pl-12 transition-all duration-300 focus:lg:w-96"
73108
onKeyDown={handleSearch}
109+
onFocus={() => setSearchBoxVisibility(true)}
110+
onBlur={() => {
111+
if (window.innerWidth < 1024) {
112+
setSearchBoxVisibility(false);
113+
}
114+
}}
74115
/>
75-
<i className="fi fi-rr-search absolute right-[10%] md:pointer-events-none md:left-5 top-1/2 -translate-y-1/2 text-xl text-dark-grey dark:text-gray-400"></i>
116+
<i className="fi fi-rr-search absolute right-[10%] lg:pointer-events-none lg:left-5 top-1/2 -translate-y-1/2 text-xl text-dark-grey dark:text-gray-400"></i>
76117
</div>
77118

78-
<div className="flex items-center gap-3 md:gap-6 ml-auto">
79-
<button className="md:hidden hover:bg-gray-200 hover:dark:bg-[#27272a] w-12 h-12 rounded-full flex items-center justify-center" onClick={() => setSearchBoxVisibility(!searchBoxVisibility)}>
119+
<div className="flex items-center justify-end gap-3 md:gap-6 w-full ">
120+
<button
121+
className="lg:hidden hover:bg-gray-200 hover:dark:bg-[#27272a] w-12 h-12 rounded-full flex items-center justify-center"
122+
onClick={() => setSearchBoxVisibility(!searchBoxVisibility)}
123+
>
80124
<i className="fi fi-rr-search text-xl text-dark-grey dark:text-gray-400"></i>
81125
</button>
82126

@@ -125,7 +169,7 @@ const Navbar = () => {
125169
<Link className="bg-black dark:bg-gray-200 text-white dark:text-gray-800 py-2 px-5 rounded-full hover:bg-gray-800 dark:hover:bg-[#ffffff] transition" to="/login">
126170
Login
127171
</Link>
128-
<Link className="bg-gray-200 dark:bg-black text-gray-800 dark:text-white py-2 px-5 rounded-full hidden md:block hover:bg-gray-300 dark:hover:bg-[#27272a] transition" to="/signup">
172+
<Link className="bg-gray-200 dark:bg-black text-gray-800 dark:text-white py-2 px-5 rounded-full hidden md:block hover:bg-gray-300 dark:hover:bg-[#27272a] transition " to="/signup">
129173
Sign Up
130174
</Link>
131175
</>
@@ -140,4 +184,4 @@ const Navbar = () => {
140184
)
141185
}
142186

143-
export default Navbar;
187+
export default Navbar;

0 commit comments

Comments
 (0)