@klarkxy/dsh-web-search-manager 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/docs/README.zh-CN.md +12 -12
- package/lib/client.inner.cjs +99 -68
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +99 -68
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[简体中文](docs/README.zh-CN.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Pick which service answers the model's web searches, set request limits, and let it read public pages — from one settings page with separate tabs for search, page reading, and request limits.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -12,39 +12,39 @@ Choose which service answers the model's web searches, set request limits, and l
|
|
|
12
12
|
dsh plugin --profile web add @klarkxy/dsh-web-search-manager
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Replace `web` with your profile name
|
|
15
|
+
Replace `web` with your profile name. Restart DSH Web, then open **Plugins → Web Search**. Restart after plugin updates too; refreshing the page alone does not load new search code.
|
|
16
16
|
|
|
17
17
|
## Set up search
|
|
18
18
|
|
|
19
|
-
DuckDuckGo works out of the box
|
|
19
|
+
DuckDuckGo works out of the box, no key needed. To use DeepSeek Search, Exa, Brave, Bocha, Serper, Firecrawl, Tavily, Perplexity, or You.com, enter its API key. Drag the list to reorder: each search uses the first ready service. Search services from other plugins, such as Zhihu, appear in the same list. New services are not enabled automatically.
|
|
20
20
|
|
|
21
|
-
The **Settings** tab sets the number of results, queries per call,
|
|
21
|
+
The **Settings** tab sets the number of results, queries per call, total timeout, and maximum page length.
|
|
22
22
|
|
|
23
23
|
## Read web pages
|
|
24
24
|
|
|
25
|
-
Turn on **Read web pages**, enable the services you want
|
|
25
|
+
Turn on **Read web pages**, enable the services you want, then drag them or use the up/down arrow keys to set priority. Each fetch uses the first configured, available service. Fetch services from other plugins also appear; new ones must be enabled manually. Temporarily unloaded services keep their selection and position.
|
|
26
26
|
|
|
27
|
-
Your previously selected fetch service
|
|
27
|
+
Your previously selected fetch service stays first. The bundled **Read web pages** service uses the free Jina Reader and falls back to one direct request if that fails; services from the host or other plugins use their own fetching method.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
**Firecrawl** can also read Markdown pages with the same API key as Firecrawl search; search and page reads are billed separately. Newly added services stay outside your priority lists until you enable them. Perplexity uses its Search API without generating answers; You.com returns web and news snippets without extra full-page extraction.
|
|
30
30
|
|
|
31
31
|
## Give the tools to the model
|
|
32
32
|
|
|
33
|
-
Add this to the plugin list of
|
|
33
|
+
Add this to the plugin list of your `agent.cordis.yml`:
|
|
34
34
|
|
|
35
35
|
```yaml
|
|
36
36
|
- name: '@klarkxy/dsh-web-search-manager/tools'
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
The model then gets `web_search` and `web_fetch` while search and fetch are
|
|
39
|
+
The model then gets `web_search` and `web_fetch` while search and fetch are on.
|
|
40
40
|
|
|
41
41
|
## Limits
|
|
42
42
|
|
|
43
|
-
- Paid services may charge
|
|
44
|
-
-
|
|
45
|
-
- Firecrawl page reads require a page status code and final URL in the
|
|
46
|
-
- Failed search or fetch requests do not switch to another service
|
|
47
|
-
- Cancellation and timeouts ask the active service to stop and wait for it to finish cleaning up. A third-party service that ignores cancellation can delay
|
|
43
|
+
- Paid services may charge per search or fetch; the plugin's counts are not a bill.
|
|
44
|
+
- The bundled Jina Reader sends page addresses to Jina; do not fetch URLs with private tokens.
|
|
45
|
+
- Firecrawl page reads require a page status code and final URL in the response; missing metadata errors out. Its page content may come from the service's cache. URLs go to the selected fetch service.
|
|
46
|
+
- Failed search or fetch requests do not switch to another service automatically.
|
|
47
|
+
- Cancellation and timeouts ask the active service to stop and wait for it to finish cleaning up. A third-party service that ignores cancellation can delay results and plugin unloading; the plugin cannot forcibly stop code running inside DSH.
|
|
48
48
|
|
|
49
49
|
## License
|
|
50
50
|
|
package/docs/README.zh-CN.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[English](../README.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
在一个设置页里选择由哪个服务回答模型的网络搜索、设置请求限制,并让模型读取公开网页。搜索服务、网页读取、请求限制各占一个页签。
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
dsh plugin --profile web add @klarkxy/dsh-web-search-manager
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
把 `web` 换成你的 profile
|
|
15
|
+
把 `web` 换成你的 profile 名。重启 DSH Web 后打开「插件 → 网页搜索」。更新插件后也要重启;仅刷新页面不会加载新版搜索代码。
|
|
16
16
|
|
|
17
17
|
## 配置搜索
|
|
18
18
|
|
|
19
|
-
DuckDuckGo
|
|
19
|
+
DuckDuckGo 默认可用,无需密钥。要用 DeepSeek 搜索、Exa、Brave、博查、Serper、Firecrawl、Tavily、Perplexity 或 You.com,填写对应 API Key。拖拽列表调整顺序:每次搜索使用第一个就绪的服务。其他插件提供的搜索服务(例如知乎)也在同一列表中。新服务不会自动开启。
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
「设置」页签设置结果条数、每次调用的查询数、总超时和网页正文长度上限。
|
|
22
22
|
|
|
23
23
|
## 读取网页
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
打开「网页读取」,选择参与的服务,拖拽或用上下方向键调整优先级。每次读取使用第一个已配置且可用的服务。其他插件接入的读取服务也会出现在列表中,新服务需手动开启;暂时未加载的服务保留原有选择和顺序。
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
原先选中的读取服务保留在首位。内置「网页读取」走免费的 Jina Reader,失败时改为直接请求一次;宿主或其他插件的服务按各自方式读取。
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
也可开启 **Firecrawl** 读取 Markdown 网页,与 Firecrawl 搜索共用 API Key;搜索与网页读取分别计费。新增服务需手动加入优先列表。Perplexity 使用 Search API,不生成回答;You.com 返回网页与新闻摘要,不额外请求全文提取。
|
|
30
30
|
|
|
31
31
|
## 让模型使用
|
|
32
32
|
|
|
@@ -36,15 +36,15 @@ DuckDuckGo 默认可用,无需密钥。也可以填写 API Key 启用 DeepSeek
|
|
|
36
36
|
- name: '@klarkxy/dsh-web-search-manager/tools'
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
搜索和网页读取开启时,模型获得 `web_search` 与 `web_fetch` 工具。
|
|
40
40
|
|
|
41
41
|
## 限制
|
|
42
42
|
|
|
43
43
|
- 付费服务可能按次收费;插件的计数不是账单。
|
|
44
|
-
-
|
|
45
|
-
- Firecrawl
|
|
46
|
-
-
|
|
47
|
-
-
|
|
44
|
+
- 内置 Jina Reader 会把网址发送给 Jina,请勿读取含私密令牌的链接。
|
|
45
|
+
- Firecrawl 网页读取要求服务返回网页状态码和最终网址,缺失时报错;正文可能来自服务缓存。网址会发送给所选服务。
|
|
46
|
+
- 搜索或网页读取失败时,不会自动换用列表中的其他服务。
|
|
47
|
+
- 取消与超时会请求当前服务停止并等待其完成清理。忽略取消的第三方服务可能延迟结果返回和插件卸载;插件无法强制终止 DSH 进程内运行的代码。
|
|
48
48
|
|
|
49
49
|
## 许可证
|
|
50
50
|
|
package/lib/client.inner.cjs
CHANGED
|
@@ -219,6 +219,17 @@ ${scope} {
|
|
|
219
219
|
/* --- Layout scaffolding. --- */
|
|
220
220
|
& .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
|
|
221
221
|
& .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
|
|
222
|
+
/* Plugin detail pages share one reading column. These are layout recipes;
|
|
223
|
+
* controls keep their own primitive styles. Form spacing follows the host's
|
|
224
|
+
* settings-form/fields.module.css and SettingsForm.module.css. */
|
|
225
|
+
& .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
|
|
226
|
+
& .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
|
|
227
|
+
&.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
|
|
228
|
+
& .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
|
|
229
|
+
& .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }
|
|
230
|
+
@media (max-width: 560px) {
|
|
231
|
+
& .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
|
|
232
|
+
}
|
|
222
233
|
& .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
223
234
|
& .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
224
235
|
& .dsh-ui-spacer { flex: 1; min-width: 0; }
|
|
@@ -246,6 +257,9 @@ ${scope} {
|
|
|
246
257
|
* official primitive, so this only owns the vertical rhythm. --- */
|
|
247
258
|
& .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
248
259
|
& .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
|
|
260
|
+
/* Grid fields share a row, so the stacked-field divider must not win later in
|
|
261
|
+
* the cascade. Reset it here, after the field recipe. */
|
|
262
|
+
& .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
|
|
249
263
|
& .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }
|
|
250
264
|
& .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
251
265
|
& .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
|
|
@@ -436,9 +450,87 @@ ${scope} {
|
|
|
436
450
|
& *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
|
|
437
451
|
}
|
|
438
452
|
}
|
|
439
|
-
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(
|
|
453
|
+
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
|
|
440
454
|
}
|
|
441
455
|
//#endregion
|
|
456
|
+
//#region src/client-styles.ts
|
|
457
|
+
/**
|
|
458
|
+
* The shared contract paints this page: the type tiers, the card, the field,
|
|
459
|
+
* the button row, the notice, the focus ring and the state colours. What is
|
|
460
|
+
* left here is only the geometry the contract does not cover — the reading
|
|
461
|
+
* width of the panel, the ranked three-column row, the drag affordance, the
|
|
462
|
+
* drop indicator, the screen-reader-only announcer and the limits grid.
|
|
463
|
+
*
|
|
464
|
+
* Nothing below declares a colour of its own beyond naming a host token, and
|
|
465
|
+
* nothing carries a literal fallback: the host publishes both themes and a
|
|
466
|
+
* literal would pin one of them.
|
|
467
|
+
*
|
|
468
|
+
* Every plugin rule nests under the plugin root, as the contract does, so a
|
|
469
|
+
* .ws-* or .web-search-* class never paints a neighbouring plugin. Selectors
|
|
470
|
+
* that start with an element name keep an explicit `&`, the form every
|
|
471
|
+
* nesting implementation accepts.
|
|
472
|
+
*/
|
|
473
|
+
const webSearchClientStyles = `${officialUiCss("ws-root")}
|
|
474
|
+
.ws-root {
|
|
475
|
+
|
|
476
|
+
.ws-card-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-bottom: 8px; }
|
|
477
|
+
.ws-sr-only {
|
|
478
|
+
position: absolute;
|
|
479
|
+
width: 1px;
|
|
480
|
+
height: 1px;
|
|
481
|
+
padding: 0;
|
|
482
|
+
margin: -1px;
|
|
483
|
+
overflow: hidden;
|
|
484
|
+
clip-path: inset(50%);
|
|
485
|
+
white-space: nowrap;
|
|
486
|
+
border: 0;
|
|
487
|
+
}
|
|
488
|
+
.ws-provider-note { display: flex; align-items: center; gap: 6px; }
|
|
489
|
+
.web-search-provider { display: grid; gap: 8px; min-width: 0; }
|
|
490
|
+
.web-search-provider-info { display: grid; gap: 3px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); overflow-wrap: anywhere; }
|
|
491
|
+
.web-search-provider-heading { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; min-height: 24px; }
|
|
492
|
+
& a { color: var(--dsw-alias-state-business-primary); font-size: 12px; line-height: 18px; text-underline-offset: 3px; }
|
|
493
|
+
/* The primitive renders a 32px control in an inline-flex wrapper; a settings
|
|
494
|
+
* field needs it to fill the column it sits in. */
|
|
495
|
+
.ws-input { width: 100%; }
|
|
496
|
+
.web-search-rank { margin: 0; padding: 0; list-style: none; }
|
|
497
|
+
.web-search-rank li {
|
|
498
|
+
position: relative;
|
|
499
|
+
display: grid;
|
|
500
|
+
grid-template-columns: 24px minmax(0, 1fr) auto;
|
|
501
|
+
gap: 10px;
|
|
502
|
+
align-items: start;
|
|
503
|
+
padding: 14px 0;
|
|
504
|
+
border-top: 0.5px solid var(--dsw-alias-border-l2);
|
|
505
|
+
}
|
|
506
|
+
& button.web-search-drag-handle {
|
|
507
|
+
display: grid;
|
|
508
|
+
place-items: center;
|
|
509
|
+
width: 24px;
|
|
510
|
+
height: 24px;
|
|
511
|
+
min-height: 24px;
|
|
512
|
+
padding: 0;
|
|
513
|
+
cursor: grab;
|
|
514
|
+
opacity: 0.65;
|
|
515
|
+
}
|
|
516
|
+
& button.web-search-drag-handle:hover { opacity: 1; }
|
|
517
|
+
& button.web-search-drag-handle:active { cursor: grabbing; }
|
|
518
|
+
& button.web-search-drag-handle[aria-disabled='true'] { cursor: wait; opacity: 0.4; }
|
|
519
|
+
.web-search-rank li[data-dragging] { opacity: 0.45; }
|
|
520
|
+
.web-search-rank li[data-drop]::after { content: ''; position: absolute; left: 0; right: 0; height: 2px; background: var(--dsw-alias-state-business-primary); pointer-events: none; }
|
|
521
|
+
.web-search-rank li[data-drop='before']::after { top: -1px; }
|
|
522
|
+
.web-search-rank li[data-drop='after']::after { bottom: -1px; }
|
|
523
|
+
.web-search-rank-index { color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; line-height: 24px; }
|
|
524
|
+
.web-search-rank-move { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; padding-top: 2px; }
|
|
525
|
+
.ws-danger:hover:not(:disabled),
|
|
526
|
+
.ws-danger[data-armed] { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); }
|
|
527
|
+
.ws-danger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-danger); }
|
|
528
|
+
@media (max-width: 560px) {
|
|
529
|
+
.web-search-rank-move { flex-direction: column; align-items: flex-end; }
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
`;
|
|
533
|
+
//#endregion
|
|
442
534
|
//#region ../dsh-plugin-kit/src/client-utils.ts
|
|
443
535
|
/** Fixed pause for failing background reads; manual work is never replayed. */
|
|
444
536
|
function createPluginReadGate(now = Date.now) {
|
|
@@ -1286,7 +1378,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1286
1378
|
setNote({ key: "keyDeleted" });
|
|
1287
1379
|
}
|
|
1288
1380
|
if (!status || !limitDraft) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1289
|
-
className: "web-search-settings ws-root dsh-ui-
|
|
1381
|
+
className: "web-search-settings ws-root dsh-ui-page",
|
|
1290
1382
|
children: [loadError ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1291
1383
|
role: "alert",
|
|
1292
1384
|
className: "dsh-ui-error",
|
|
@@ -1380,7 +1472,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1380
1472
|
});
|
|
1381
1473
|
}
|
|
1382
1474
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1383
|
-
className: "web-search-settings ws-root dsh-ui-
|
|
1475
|
+
className: "web-search-settings ws-root dsh-ui-page",
|
|
1384
1476
|
"data-testid": "web-search-settings",
|
|
1385
1477
|
children: [
|
|
1386
1478
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
|
|
@@ -1741,11 +1833,11 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1741
1833
|
hidden: tab !== "limits",
|
|
1742
1834
|
tabIndex: 0,
|
|
1743
1835
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("fieldset", {
|
|
1744
|
-
className: "
|
|
1836
|
+
className: "dsh-ui-fields-grid",
|
|
1745
1837
|
disabled: busy || reordering,
|
|
1746
1838
|
"aria-label": text.tabLimits,
|
|
1747
1839
|
children: LIMITS.map(([key, min, max]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1748
|
-
className: "
|
|
1840
|
+
className: "dsh-ui-field",
|
|
1749
1841
|
children: [
|
|
1750
1842
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1751
1843
|
className: "dsh-ui-label",
|
|
@@ -1784,7 +1876,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1784
1876
|
})
|
|
1785
1877
|
}),
|
|
1786
1878
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1787
|
-
className: "dsh-ui-
|
|
1879
|
+
className: "dsh-ui-form-footer dsh-ui-actions-end",
|
|
1788
1880
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1789
1881
|
className: "dsh-ui-meta",
|
|
1790
1882
|
children: limitsDirty || keysDirty ? text.unsaved : text.saveHint
|
|
@@ -1799,74 +1891,13 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1799
1891
|
]
|
|
1800
1892
|
});
|
|
1801
1893
|
}
|
|
1802
|
-
const styles = `${officialUiCss("ws-root")}
|
|
1803
|
-
.ws-root { max-width: 760px; }
|
|
1804
|
-
.ws-card-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding-bottom: 8px; }
|
|
1805
|
-
.ws-sr-only {
|
|
1806
|
-
position: absolute;
|
|
1807
|
-
width: 1px;
|
|
1808
|
-
height: 1px;
|
|
1809
|
-
padding: 0;
|
|
1810
|
-
margin: -1px;
|
|
1811
|
-
overflow: hidden;
|
|
1812
|
-
clip-path: inset(50%);
|
|
1813
|
-
white-space: nowrap;
|
|
1814
|
-
border: 0;
|
|
1815
|
-
}
|
|
1816
|
-
.ws-provider-note { display: flex; align-items: center; gap: 6px; }
|
|
1817
|
-
.web-search-provider { display: grid; gap: 8px; min-width: 0; }
|
|
1818
|
-
.web-search-provider-info { display: grid; gap: 3px; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); overflow-wrap: anywhere; }
|
|
1819
|
-
.web-search-provider-heading { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; min-height: 24px; }
|
|
1820
|
-
.web-search-settings a { color: var(--dsw-alias-state-business-primary); font-size: 12px; line-height: 18px; text-underline-offset: 3px; }
|
|
1821
|
-
/* The primitive renders a 32px control in an inline-flex wrapper; a settings
|
|
1822
|
-
* field needs it to fill the column it sits in. */
|
|
1823
|
-
.ws-input { width: 100%; }
|
|
1824
|
-
.web-search-rank { margin: 0; padding: 0; list-style: none; }
|
|
1825
|
-
.web-search-rank li {
|
|
1826
|
-
position: relative;
|
|
1827
|
-
display: grid;
|
|
1828
|
-
grid-template-columns: 24px minmax(0, 1fr) auto;
|
|
1829
|
-
gap: 10px;
|
|
1830
|
-
align-items: start;
|
|
1831
|
-
padding: 14px 0;
|
|
1832
|
-
border-top: 0.5px solid var(--dsw-alias-border-l2);
|
|
1833
|
-
}
|
|
1834
|
-
.web-search-settings button.web-search-drag-handle {
|
|
1835
|
-
display: grid;
|
|
1836
|
-
place-items: center;
|
|
1837
|
-
width: 24px;
|
|
1838
|
-
height: 24px;
|
|
1839
|
-
min-height: 24px;
|
|
1840
|
-
padding: 0;
|
|
1841
|
-
cursor: grab;
|
|
1842
|
-
opacity: 0.65;
|
|
1843
|
-
}
|
|
1844
|
-
.web-search-settings button.web-search-drag-handle:hover { opacity: 1; }
|
|
1845
|
-
.web-search-settings button.web-search-drag-handle:active { cursor: grabbing; }
|
|
1846
|
-
.web-search-settings button.web-search-drag-handle[aria-disabled='true'] { cursor: wait; opacity: 0.4; }
|
|
1847
|
-
.web-search-rank li[data-dragging] { opacity: 0.45; }
|
|
1848
|
-
.web-search-rank li[data-drop]::after { content: ''; position: absolute; left: 0; right: 0; height: 2px; background: var(--dsw-alias-state-business-primary); pointer-events: none; }
|
|
1849
|
-
.web-search-rank li[data-drop='before']::after { top: -1px; }
|
|
1850
|
-
.web-search-rank li[data-drop='after']::after { bottom: -1px; }
|
|
1851
|
-
.web-search-rank-index { color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; line-height: 24px; }
|
|
1852
|
-
.web-search-rank-move { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; padding-top: 2px; }
|
|
1853
|
-
.web-search-limits { margin: 0; border: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; }
|
|
1854
|
-
/* A two-column grid, so these fields keep the contract's caption and the
|
|
1855
|
-
* primitive's control and only own their vertical rhythm — a stacked list is
|
|
1856
|
-
* what draws the hairline between fields, and there is nothing to separate. */
|
|
1857
|
-
.ws-limit { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
1858
|
-
.ws-danger:hover:not(:disabled),
|
|
1859
|
-
.ws-danger[data-armed] { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); }
|
|
1860
|
-
.ws-danger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-danger); }
|
|
1861
|
-
@media (max-width: 560px) { .web-search-rank-move { flex-direction: column; align-items: flex-end; } .web-search-limits { grid-template-columns: minmax(0, 1fr); } }
|
|
1862
|
-
`;
|
|
1863
1894
|
function apply(ctx) {
|
|
1864
1895
|
const client = ctx;
|
|
1865
1896
|
ctx.effect(() => {
|
|
1866
1897
|
if (typeof document === "undefined") return () => {};
|
|
1867
1898
|
const style = document.createElement("style");
|
|
1868
1899
|
style.setAttribute("data-plugin", "@klarkxy/dsh-web-search-manager");
|
|
1869
|
-
style.textContent =
|
|
1900
|
+
style.textContent = webSearchClientStyles;
|
|
1870
1901
|
style.dataset.dshWebSearch = "";
|
|
1871
1902
|
document.head.appendChild(style);
|
|
1872
1903
|
return () => style.remove();
|