feat(search): 效果五快捷栏加入本地搜索
- 引擎选项新增「本地」并作为默认;本地模式回车打开第一个匹配条目/分组 - 快捷栏改为贴在搜索框右侧内部展开,贴合效果五 - 外部引擎仍在新标签页搜索,输入时本地过滤逻辑保持
This commit is contained in:
+15
-2
@@ -1478,8 +1478,8 @@ html.theme-transition .site-background {
|
|||||||
|
|
||||||
.engine-menu {
|
.engine-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + 12px);
|
top: 50%;
|
||||||
right: 0;
|
right: calc(100% + 6px);
|
||||||
z-index: var(--su-z-float);
|
z-index: var(--su-z-float);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -1489,6 +1489,19 @@ html.theme-transition .site-background {
|
|||||||
border-radius: var(--su-radius-sm);
|
border-radius: var(--su-radius-sm);
|
||||||
background-color: var(--su-bg-card);
|
background-color: var(--su-bg-card);
|
||||||
box-shadow: var(--su-shadow-pop);
|
box-shadow: var(--su-shadow-pop);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
animation: engine-bar-in 140ms var(--su-ease-out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes engine-bar-in {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(6px, -50%);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.engine-option {
|
.engine-option {
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ type Route =
|
|||||||
| { kind: 'api' }
|
| { kind: 'api' }
|
||||||
|
|
||||||
const SEARCH_ENGINES = [
|
const SEARCH_ENGINES = [
|
||||||
|
{ key: 'local', name: '本地', search: '' },
|
||||||
{ key: 'google', name: 'Google', search: 'https://www.google.com/search?q=' },
|
{ key: 'google', name: 'Google', search: 'https://www.google.com/search?q=' },
|
||||||
{ key: 'bing', name: 'Bing', search: 'https://www.bing.com/search?q=' },
|
{ key: 'bing', name: 'Bing', search: 'https://www.bing.com/search?q=' },
|
||||||
{ key: 'baidu', name: '百度', search: 'https://www.baidu.com/s?wd=' },
|
{ 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)
|
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() {
|
export default function AppNext() {
|
||||||
const { status, projects, error, live, refreshing, refresh } = useProjects()
|
const { status, projects, error, live, refreshing, refresh } = useProjects()
|
||||||
const { route, navigate } = useRoute()
|
const { route, navigate } = useRoute()
|
||||||
@@ -388,6 +407,20 @@ export default function AppNext() {
|
|||||||
}
|
}
|
||||||
if (event.key !== 'Enter' || keyword.trim() === '') return
|
if (event.key !== 'Enter' || keyword.trim() === '') return
|
||||||
event.preventDefault()
|
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(
|
window.open(
|
||||||
`${searchEngine.search}${encodeURIComponent(keyword.trim())}`,
|
`${searchEngine.search}${encodeURIComponent(keyword.trim())}`,
|
||||||
'_blank',
|
'_blank',
|
||||||
@@ -396,7 +429,7 @@ export default function AppNext() {
|
|||||||
}
|
}
|
||||||
input.addEventListener('keydown', handleKeyDown)
|
input.addEventListener('keydown', handleKeyDown)
|
||||||
return () => input.removeEventListener('keydown', handleKeyDown)
|
return () => input.removeEventListener('keydown', handleKeyDown)
|
||||||
}, [keyword, searchEngine])
|
}, [keyword, keywordLower, manage.groups, navigate, searchEngine])
|
||||||
|
|
||||||
const chooseEngine = (next: SearchEngine) => {
|
const chooseEngine = (next: SearchEngine) => {
|
||||||
setSearchEngine(next)
|
setSearchEngine(next)
|
||||||
@@ -797,8 +830,16 @@ export default function AppNext() {
|
|||||||
value={keyword}
|
value={keyword}
|
||||||
onChange={setKeyword}
|
onChange={setKeyword}
|
||||||
inputRef={searchRef}
|
inputRef={searchRef}
|
||||||
placeholder="搜索本地项目…"
|
placeholder={
|
||||||
label="搜索本地项目,回车使用当前搜索引擎"
|
searchEngine.key === 'local'
|
||||||
|
? '搜索本地项目…'
|
||||||
|
: `用 ${searchEngine.name} 搜索,回车打开…`
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
searchEngine.key === 'local'
|
||||||
|
? '搜索本地项目,回车打开第一个匹配项'
|
||||||
|
: `用 ${searchEngine.name} 搜索,回车打开新标签页`
|
||||||
|
}
|
||||||
variant="card"
|
variant="card"
|
||||||
hotkey="k"
|
hotkey="k"
|
||||||
suffix={
|
suffix={
|
||||||
@@ -809,7 +850,11 @@ export default function AppNext() {
|
|||||||
aria-haspopup="menu"
|
aria-haspopup="menu"
|
||||||
aria-expanded={engineOpen}
|
aria-expanded={engineOpen}
|
||||||
aria-label={`搜索引擎:${searchEngine.name},点击切换`}
|
aria-label={`搜索引擎:${searchEngine.name},点击切换`}
|
||||||
title={`当前:${searchEngine.name};回车用该引擎搜索`}
|
title={
|
||||||
|
searchEngine.key === 'local'
|
||||||
|
? '当前:本地搜索;回车打开第一个匹配项'
|
||||||
|
: `当前:${searchEngine.name};回车用该引擎搜索`
|
||||||
|
}
|
||||||
onClick={() => setEngineOpen((open) => !open)}
|
onClick={() => setEngineOpen((open) => !open)}
|
||||||
>
|
>
|
||||||
{searchEngine.name}
|
{searchEngine.name}
|
||||||
|
|||||||
Reference in New Issue
Block a user