1
1
import { useClickAway , useCreation , useReactive } from "ahooks" ;
2
2
import clsx from "clsx" ;
3
- import { isNil , noop } from "lodash-es" ;
3
+ import { isNil , lowerCase , noop } from "lodash-es" ;
4
4
import { Copy , Link , SquareArrowOutUpRight } from "lucide-react" ;
5
- import { cloneElement , useEffect , useRef } from "react" ;
5
+ import { cloneElement , useEffect , useRef , useState } from "react" ;
6
6
import { useTranslation } from "react-i18next" ;
7
7
8
8
import { useOSKeyPress } from "@/hooks/useOSKeyPress" ;
@@ -11,6 +11,7 @@ import { copyToClipboard, OpenURLWithBrowser } from "@/utils";
11
11
import { isMac } from "@/utils/platform" ;
12
12
import { CONTEXT_MENU_PANEL_ID } from "@/constants" ;
13
13
import { useShortcutsStore } from "@/stores/shortcutsStore" ;
14
+ import { Input } from "@headlessui/react" ;
14
15
15
16
interface State {
16
17
activeMenuIndex : number ;
@@ -36,6 +37,15 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
36
37
const selectedSearchContent = useSearchStore ( ( state ) => {
37
38
return state . selectedSearchContent ;
38
39
} ) ;
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 ] ) ;
39
49
40
50
const menus = useCreation ( ( ) => {
41
51
if ( isNil ( selectedSearchContent ) ) return [ ] ;
@@ -45,7 +55,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
45
55
46
56
const menus = [
47
57
{
48
- name : "search.contextMenu.open" ,
58
+ name : t ( "search.contextMenu.open" ) ,
49
59
icon : < SquareArrowOutUpRight /> ,
50
60
keys : isMac ? [ "↩︎" ] : [ "Enter" ] ,
51
61
shortcut : "enter" ,
@@ -57,7 +67,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
57
67
} ,
58
68
} ,
59
69
{
60
- name : "search.contextMenu.copyLink" ,
70
+ name : t ( "search.contextMenu.copyLink" ) ,
61
71
icon : < Link /> ,
62
72
keys : isMac ? [ "⌘" , "L" ] : [ "Ctrl" , "L" ] ,
63
73
shortcut : isMac ? "meta.l" : "ctrl.l" ,
@@ -67,7 +77,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
67
77
} ,
68
78
} ,
69
79
{
70
- name : "search.contextMenu.copyAnswer" ,
80
+ name : t ( "search.contextMenu.copyAnswer" ) ,
71
81
icon : < Copy /> ,
72
82
keys : isMac ? [ "↩︎" ] : [ "Enter" ] ,
73
83
shortcut : "enter" ,
@@ -77,7 +87,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
77
87
} ,
78
88
} ,
79
89
{
80
- name : "search.contextMenu.copyUppercaseAnswer" ,
90
+ name : t ( "search.contextMenu.copyUppercaseAnswer" ) ,
81
91
icon : < Copy /> ,
82
92
keys : isMac ? [ "⌘" , "↩︎" ] : [ "Ctrl" , "Enter" ] ,
83
93
shortcut : "meta.enter" ,
@@ -87,7 +97,7 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
87
97
} ,
88
98
} ,
89
99
{
90
- name : "search.contextMenu.copyQuestionAndAnswer" ,
100
+ name : t ( "search.contextMenu.copyQuestionAndAnswer" ) ,
91
101
icon : < Copy /> ,
92
102
keys : isMac ? [ "⌘" , "L" ] : [ "Ctrl" , "L" ] ,
93
103
shortcut : "meta.l" ,
@@ -98,7 +108,11 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
98
108
} ,
99
109
] ;
100
110
101
- return menus . filter ( ( item ) => ! item . hide ) ;
111
+ const filterMenus = menus . filter ( ( item ) => ! item . hide ) ;
112
+
113
+ setSearchMenus ( filterMenus ) ;
114
+
115
+ return filterMenus ;
102
116
} , [ selectedSearchContent ] ) ;
103
117
104
118
const shortcuts = useCreation ( ( ) => {
@@ -182,23 +196,25 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
182
196
ref = { containerRef }
183
197
id = { visibleContextMenu ? CONTEXT_MENU_PANEL_ID : "" }
184
198
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 " ,
186
200
{
187
201
"!scale-100" : visibleContextMenu ,
188
202
}
189
203
) }
190
204
>
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 ) => {
193
209
const { name, icon, keys, clickEvent } = item ;
194
210
195
211
return (
196
212
< li
197
213
key = { name }
198
214
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" ,
200
216
{
201
- "bg-black/5 dark:bg-white/5 " :
217
+ "bg-[#EDEDED] dark:bg-[#202126] " :
202
218
index === state . activeMenuIndex ,
203
219
}
204
220
) }
@@ -210,15 +226,15 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
210
226
< div className = "flex items-center gap-2 text-black/80 dark:text-white/80" >
211
227
{ cloneElement ( icon , { className : "size-4" } ) }
212
228
213
- < span > { t ( name ) } </ span >
229
+ < span > { name } </ span >
214
230
</ div >
215
231
216
232
< div className = "flex gap-[4px] text-black/60 dark:text-white/60" >
217
233
{ keys . map ( ( key ) => (
218
234
< kbd
219
235
key = { key }
220
236
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] " ,
222
238
{
223
239
"px-1" : key . length > 1 ,
224
240
}
@@ -232,6 +248,25 @@ const ContextMenu = ({ hideCoco }: ContextMenuProps) => {
232
248
) ;
233
249
} ) }
234
250
</ 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 >
235
270
</ div >
236
271
</ >
237
272
) ;
0 commit comments