feat(search): 内置 DuckDuckGo,内置引擎不允许删除

- 默认引擎清单加 duckduckgo(https://duckduckgo.com/?q={query}),图标用组件库 0.3.5 的 DuckDuckGo 品牌图标
- 后端:内置六个必须存在,缺了返回 400;老库读取时按 id 补齐缺的内置引擎(插在内置那一组里,不覆盖用户改过的值)
- 后台:内置引擎不渲染「删除」按钮,removeEngine 也做了兜底;自定义引擎照常可删
This commit is contained in:
2026-11-06 12:40:31 +08:00
parent fdfd17657c
commit 733c1552ce
4 changed files with 112 additions and 5 deletions
+6 -1
View File
@@ -37,6 +37,7 @@ import { LoginDialog } from '../auth/LoginDialog'
import { GroupMark as GroupGlyph } from '../common/GroupMark'
import { isDarkScheme, readThemeOverride, writeThemeOverride } from '../../theme'
import {
BUILTIN_SEARCH_ENGINE_IDS,
DEFAULT_SEARCH_ENGINES,
fetchSettings,
saveSettings,
@@ -2110,6 +2111,8 @@ function SearchPanel({
}
const removeEngine = (id: string) => {
// 内置引擎只能停用,不能删
if (BUILTIN_SEARCH_ENGINE_IDS.some((builtin) => builtin === id)) return
const engines = value.engines.filter((engine) => engine.id !== id)
onChange({
...value,
@@ -2156,7 +2159,9 @@ function SearchPanel({
label={`启用 ${engine.name || engine.id}`}
onChange={(enabled) => updateEngine(engine.id, { enabled })}
/>
<TextButton onClick={() => removeEngine(engine.id)}>删除</TextButton>
{!BUILTIN_SEARCH_ENGINE_IDS.some((builtin) => builtin === engine.id) && (
<TextButton onClick={() => removeEngine(engine.id)}>删除</TextButton>
)}
</div>
</div>
<div className="search-engine-fields">
+17
View File
@@ -132,8 +132,25 @@ export const DEFAULT_SEARCH_ENGINES: SearchEngineSettings[] = [
icon: '',
enabled: true,
},
{
id: 'duckduckgo',
name: 'DuckDuckGo',
url: 'https://duckduckgo.com/?q={query}',
icon: '',
enabled: true,
},
]
/** 内置引擎:有品牌图标、后台不能删除(只能改名 / 改地址 / 停用) */
export const BUILTIN_SEARCH_ENGINE_IDS = [
'google',
'bing',
'baidu',
'sogou',
'360',
'duckduckgo',
] as const
export type SiteSettings = {
header: {
enabled: boolean