11import { useClickAway , useCreation , useReactive } from "ahooks" ;
22import clsx from "clsx" ;
3- import { isNil , noop } from "lodash-es" ;
3+ import { isNil , lowerCase , noop } from "lodash-es" ;
44import { Copy , Link , SquareArrowOutUpRight } from "lucide-react" ;
5- import { cloneElement , useEffect , useRef } from "react" ;
5+ import { cloneElement , useEffect , useRef , useState } from "react" ;
66import { useTranslation } from "react-i18next" ;
77
88import { useOSKeyPress } from "@/hooks/useOSKeyPress" ;
@@ -11,6 +11,7 @@ import { copyToClipboard, OpenURLWithBrowser } from "@/utils";
1111import { isMac } from "@/utils/platform" ;
1212import { CONTEXT_MENU_PANEL_ID } from "@/constants" ;
1313import { useShortcutsStore } from "@/stores/shortcutsStore" ;
14+ import { Input } from "@headlessui/react" ;
1415
1516interface State {
1617 activeMenuIndex : number ;
@@ -36,6 +37,15 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
3637 const selectedSearchContent = useSearchStore ( ( state ) => {
3738 return state . selectedSearchContent ;
3839 } ) ;
40+ const [ searchMenus , setSearchMenus ] = useState < typeof menus > ( [ ] ) ;
41+
42+ const title = useCreation ( ( ) => {
43+ if ( selectedSearchContent ?. id === "Calculator" ) {
44+ return t ( "search.contextMenu.title.calculator" ) ;
45+ }
46+
47+ return selectedSearchContent ?. title ;
48+ } , [ selectedSearchContent ] ) ;
3949
4050 const menus = useCreation ( ( ) => {
4151 if ( isNil ( selectedSearchContent ) ) return [ ] ;
@@ -45,7 +55,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
4555
4656 const menus = [
4757 {
48- name : "search.contextMenu.open" ,
58+ name : t ( "search.contextMenu.open" ) ,
4959 icon : < SquareArrowOutUpRight /> ,
5060 keys : isMac ? [ "↩︎" ] : [ "Enter" ] ,
5161 shortcut : "enter" ,
@@ -57,7 +67,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
5767 } ,
5868 } ,
5969 {
60- name : "search.contextMenu.copyLink" ,
70+ name : t ( "search.contextMenu.copyLink" ) ,
6171 icon : < Link /> ,
6272 keys : isMac ? [ "⌘" , "L" ] : [ "Ctrl" , "L" ] ,
6373 shortcut : isMac ? "meta.l" : "ctrl.l" ,
@@ -67,7 +77,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
6777 } ,
6878 } ,
6979 {
70- name : "search.contextMenu.copyAnswer" ,
80+ name : t ( "search.contextMenu.copyAnswer" ) ,
7181 icon : < Copy /> ,
7282 keys : isMac ? [ "↩︎" ] : [ "Enter" ] ,
7383 shortcut : "enter" ,
@@ -77,7 +87,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
7787 } ,
7888 } ,
7989 {
80- name : "search.contextMenu.copyUppercaseAnswer" ,
90+ name : t ( "search.contextMenu.copyUppercaseAnswer" ) ,
8191 icon : < Copy /> ,
8292 keys : isMac ? [ "⌘" , "↩︎" ] : [ "Ctrl" , "Enter" ] ,
8393 shortcut : "meta.enter" ,
@@ -87,7 +97,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
8797 } ,
8898 } ,
8999 {
90- name : "search.contextMenu.copyQuestionAndAnswer" ,
100+ name : t ( "search.contextMenu.copyQuestionAndAnswer" ) ,
91101 icon : < Copy /> ,
92102 keys : isMac ? [ "⌘" , "L" ] : [ "Ctrl" , "L" ] ,
93103 shortcut : "meta.l" ,
@@ -98,7 +108,11 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
98108 } ,
99109 ] ;
100110
101- return menus . filter ( ( item ) => ! item . hide ) ;
111+ const filterMenus = menus . filter ( ( item ) => ! item . hide ) ;
112+
113+ setSearchMenus ( filterMenus ) ;
114+
115+ return filterMenus ;
102116 } , [ selectedSearchContent ] ) ;
103117
104118 const shortcuts = useCreation ( ( ) => {
@@ -182,23 +196,25 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
182196 ref = { containerRef }
183197 id = { visibleContextMenu ? CONTEXT_MENU_PANEL_ID : "" }
184198 className = { clsx (
185- "absolute bottom-[40px ] right-[8px] min- w-[280px] scale-0 transition origin-bottom-right text-sm p-1 bg-white dark:bg-[#202126] rounded-lg shadow-xs border border-gray-200 dark:border-gray-700 " ,
199+ "absolute bottom-[50px ] right-[18px] w-[300px] flex flex-col gap-2 scale-0 transition origin-bottom-right text-sm p-3 pb-0 bg-white dark:bg-black rounded-lg shadow-xs border border-[#EDEDED] dark:border-[#272828] shadow-lg dark:shadow-white/15 " ,
186200 {
187201 "!scale-100" : visibleContextMenu ,
188202 }
189203 ) }
190204 >
191- < ul className = "flex flex-col" >
192- { menus . map ( ( item , index ) => {
205+ < div className = "text-[#999] dark:text-[#666] truncate" > { title } </ div >
206+
207+ < ul className = "flex flex-col -mx-2" >
208+ { searchMenus . map ( ( item , index ) => {
193209 const { name, icon, keys, clickEvent } = item ;
194210
195211 return (
196212 < li
197213 key = { name }
198214 className = { clsx (
199- "flex justify-between items-center gap-2 px-3 py-2 rounded-lg cursor-pointer" ,
215+ "flex justify-between items-center gap-2 px-2 py-2 rounded-lg cursor-pointer" ,
200216 {
201- "bg-black/5 dark:bg-white/5 " :
217+ "bg-[#EDEDED] dark:bg-[#202126] " :
202218 index === state . activeMenuIndex ,
203219 }
204220 ) }
@@ -210,15 +226,15 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
210226 < div className = "flex items-center gap-2 text-black/80 dark:text-white/80" >
211227 { cloneElement ( icon , { className : "size-4" } ) }
212228
213- < span > { t ( name ) } </ span >
229+ < span > { name } </ span >
214230 </ div >
215231
216232 < div className = "flex gap-[4px] text-black/60 dark:text-white/60" >
217233 { keys . map ( ( key ) => (
218234 < kbd
219235 key = { key }
220236 className = { clsx (
221- "flex justify-center items-center font-sans h-[20px] min-w-[20px] text-[10px] rounded-md border border-black/10 dark:border-white/10" ,
237+ "flex justify-center items-center font-sans h-[20px] min-w-[20px] text-[10px] rounded-md border border-[#EDEDED] dark:border-white/10 bg-white dark:bg-[#202126] " ,
222238 {
223239 "px-1" : key . length > 1 ,
224240 }
@@ -232,6 +248,25 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
232248 ) ;
233249 } ) }
234250 </ ul >
251+
252+ < div className = "-mx-3 p-2 border-t border-[#E6E6E6] dark:border-[#262626]" >
253+ { visibleContextMenu && (
254+ < Input
255+ autoFocus
256+ placeholder = { t ( "search.contextMenu.search" ) }
257+ className = "w-full bg-transparent"
258+ onChange = { ( event ) => {
259+ const value = event . target . value ;
260+
261+ const searchMenus = menus . filter ( ( item ) => {
262+ return lowerCase ( item . name ) . includes ( lowerCase ( value ) ) ;
263+ } ) ;
264+
265+ setSearchMenus ( searchMenus ) ;
266+ } }
267+ />
268+ ) }
269+ </ div >
235270 </ div >
236271 </ >
237272 ) ;
0 commit comments