feat(search): 效果五快捷栏加入本地搜索
- 引擎选项新增「本地」并作为默认;本地模式回车打开第一个匹配条目/分组 - 快捷栏改为贴在搜索框右侧内部展开,贴合效果五 - 外部引擎仍在新标签页搜索,输入时本地过滤逻辑保持
This commit is contained in:
@@ -63,6 +63,7 @@ type Route =
|
||||
| { kind: 'api' }
|
||||
|
||||
const SEARCH_ENGINES = [
|
||||
{ key: 'local', name: '本地', search: '' },
|
||||
{ key: 'google', name: 'Google', search: 'https://www.google.com/search?q=' },
|
||||
{ key: 'bing', name: 'Bing', search: 'https://www.bing.com/search?q=' },
|
||||
{ key: 'baidu', name: '百度', search: 'https://www.baidu.com/s?wd=' },
|
||||
@@ -202,6 +203,24 @@ function matches(entry: Record<string, unknown>, keyword: string): boolean {
|
||||
return text.includes(keyword)
|
||||
}
|
||||
|
||||
/** 本地搜索回车时打开第一个匹配项;没有条目命中但分组名命中时打开分组 */
|
||||
function findLocalTarget(
|
||||
groups: GroupNode[],
|
||||
keyword: string,
|
||||
): { group: GroupNode; entry?: Record<string, unknown> } | undefined {
|
||||
for (const group of groups) {
|
||||
if (group.enabled === false) continue
|
||||
if (group.title.toLowerCase().includes(keyword)) return { group }
|
||||
const entry = (group.entries as unknown as Record<string, unknown>[]).find((item) =>
|
||||
matches(item, keyword),
|
||||
)
|
||||
if (entry !== undefined) return { group, entry }
|
||||
const child = findLocalTarget(group.children, keyword)
|
||||
if (child !== undefined) return child
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export default function AppNext() {
|
||||
const { status, projects, error, live, refreshing, refresh } = useProjects()
|
||||
const { route, navigate } = useRoute()
|
||||
@@ -388,6 +407,20 @@ export default function AppNext() {
|
||||
}
|
||||
if (event.key !== 'Enter' || keyword.trim() === '') return
|
||||
event.preventDefault()
|
||||
setEngineOpen(false)
|
||||
|
||||
if (searchEngine.key === 'local') {
|
||||
const target = findLocalTarget(manage.groups, keywordLower)
|
||||
if (target !== undefined) {
|
||||
navigate(
|
||||
target.entry === undefined
|
||||
? `/g/${encodeURIComponent(target.group.key)}`
|
||||
: `/g/${encodeURIComponent(target.group.key)}/i/${encodeURIComponent(String(target.entry.id))}`,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
window.open(
|
||||
`${searchEngine.search}${encodeURIComponent(keyword.trim())}`,
|
||||
'_blank',
|
||||
@@ -396,7 +429,7 @@ export default function AppNext() {
|
||||
}
|
||||
input.addEventListener('keydown', handleKeyDown)
|
||||
return () => input.removeEventListener('keydown', handleKeyDown)
|
||||
}, [keyword, searchEngine])
|
||||
}, [keyword, keywordLower, manage.groups, navigate, searchEngine])
|
||||
|
||||
const chooseEngine = (next: SearchEngine) => {
|
||||
setSearchEngine(next)
|
||||
@@ -797,8 +830,16 @@ export default function AppNext() {
|
||||
value={keyword}
|
||||
onChange={setKeyword}
|
||||
inputRef={searchRef}
|
||||
placeholder="搜索本地项目…"
|
||||
label="搜索本地项目,回车使用当前搜索引擎"
|
||||
placeholder={
|
||||
searchEngine.key === 'local'
|
||||
? '搜索本地项目…'
|
||||
: `用 ${searchEngine.name} 搜索,回车打开…`
|
||||
}
|
||||
label={
|
||||
searchEngine.key === 'local'
|
||||
? '搜索本地项目,回车打开第一个匹配项'
|
||||
: `用 ${searchEngine.name} 搜索,回车打开新标签页`
|
||||
}
|
||||
variant="card"
|
||||
hotkey="k"
|
||||
suffix={
|
||||
@@ -809,7 +850,11 @@ export default function AppNext() {
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={engineOpen}
|
||||
aria-label={`搜索引擎:${searchEngine.name},点击切换`}
|
||||
title={`当前:${searchEngine.name};回车用该引擎搜索`}
|
||||
title={
|
||||
searchEngine.key === 'local'
|
||||
? '当前:本地搜索;回车打开第一个匹配项'
|
||||
: `当前:${searchEngine.name};回车用该引擎搜索`
|
||||
}
|
||||
onClick={() => setEngineOpen((open) => !open)}
|
||||
>
|
||||
{searchEngine.name}
|
||||
|
||||
Reference in New Issue
Block a user