@nsnanocat/preference-panes 0.9.9 → 0.9.10

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.
@@ -12,7 +12,7 @@ import { mountPanel } from "./panel.mjs";
12
12
  */
13
13
  export function mount(boxjs, css = "") {
14
14
  if (typeof css !== "string") throw new TypeError("CSS must be a string");
15
- const catalog = new BoxJS(boxjs);
15
+ const catalog = boxjs instanceof BoxJS ? boxjs : new BoxJS(boxjs);
16
16
  const metadata = catalog.module.metadata;
17
17
  const image = metadata.icon || metadata.icons?.[1] || metadata.icons?.[0];
18
18
  if (image) resourceURL(image);
@@ -57,23 +57,6 @@
57
57
  min-width: 0;
58
58
  overflow-wrap: anywhere;
59
59
  }
60
- /* 模块图标位于固定搜索工具栏左侧;嵌入宿主仍可使用纯文字原生标题栏。
61
- * Keep the module icon beside the fixed search field while embedded hosts use text-only native titles. */
62
- .pp-module-logo {
63
- display: none;
64
- width: 36px;
65
- height: 36px;
66
- flex: none;
67
- }
68
- .pp-module-logo:not(:empty) {
69
- display: block;
70
- }
71
- .pp-module-logo img {
72
- display: block;
73
- width: 100%;
74
- height: 100%;
75
- object-fit: contain;
76
- }
77
60
  .pp-nav-spacer {
78
61
  width: 44px;
79
62
  flex: none;
@@ -97,18 +80,6 @@
97
80
  opacity: 0.5;
98
81
  cursor: wait;
99
82
  }
100
- /* 固定工具区与滚动视口共用弹性布局,不按工具栏高度拼接页面偏移。
101
- * Fixed tools and the scrolling viewport share a flex layout without toolbar-height offsets. */
102
- .pp-toolbar {
103
- flex: none;
104
- min-width: 0;
105
- padding: 12px max(16px, calc((100% - 688px) / 2));
106
- display: flex;
107
- align-items: center;
108
- gap: 12px;
109
- background: var(--pp-surface);
110
- border-bottom: 1px solid var(--pp-border);
111
- }
112
83
  .pp-viewport {
113
84
  position: relative;
114
85
  flex: 1;
@@ -175,12 +146,6 @@
175
146
  border: 0;
176
147
  border-radius: 6px;
177
148
  }
178
- .pp-search {
179
- flex: 1;
180
- width: 100%;
181
- min-width: 0;
182
- margin: 0;
183
- }
184
149
  .pp-panel .pp-multiline {
185
150
  display: block;
186
151
  }
@@ -1,6 +1,6 @@
1
1
  import { ActionMenu } from "./ActionMenu.mjs";
2
2
  import { createPreferencesClient } from "./client.mjs";
3
- import { errorView, fieldControl, icon, element as node, requestConfirmation, resourceURL, settingRow } from "./components.mjs";
3
+ import { errorView, fieldControl, element as node, requestConfirmation, resourceURL, settingRow } from "./components.mjs";
4
4
  import { Navigation } from "./Navigation.mjs";
5
5
 
6
6
  /**
@@ -30,17 +30,10 @@ export function mountPanel(root, catalog) {
30
30
  const menu = new ActionMenu(id => runAction(id));
31
31
  const trailing = node("span", "pp-nav-spacer");
32
32
  trailing.append(menu.element);
33
- const logo = node("span", "pp-module-logo");
34
- logo.setAttribute("aria-hidden", "true");
35
- const image = icon(catalog.module.metadata, "");
36
- if (image) logo.append(image);
37
- const toolbar = node("div", "pp-toolbar");
38
- toolbar.setAttribute("role", "search");
39
- toolbar.hidden = true;
40
33
  const viewport = node("div", "pp-viewport");
41
34
  let toast;
42
35
  header.append(back, heading, trailing);
43
- shell.append(header, toolbar, viewport);
36
+ shell.append(header, viewport);
44
37
  root.append(shell);
45
38
  // 嵌入模式向宿主发布导航状态,宿主不读取或修改模块内部 DOM。
46
39
  // Embedded mode publishes navigation state without host reads or mutations of the module DOM.
@@ -131,7 +124,6 @@ export function mountPanel(root, catalog) {
131
124
  async function open(module) {
132
125
  const version = ++generation;
133
126
  active = module;
134
- toolbar.hidden = true;
135
127
  back.disabled = window.history.length <= 1;
136
128
  heading.textContent = module;
137
129
  publishNavigation();
@@ -154,14 +146,6 @@ export function mountPanel(root, catalog) {
154
146
  const { definition, values } = client.snapshot(active);
155
147
  heading.textContent = definition.metadata?.name || active;
156
148
  const view = node("section", "pp-fields");
157
- const search = node("input", "");
158
- search.type = "search";
159
- search.placeholder = "搜索设置项";
160
- search.setAttribute("aria-label", "搜索设置");
161
- const searchField = fieldControl(search);
162
- searchField.classList.add("pp-search");
163
- toolbar.replaceChildren(logo, searchField);
164
- const searchRows = [];
165
149
  /**
166
150
  * 挂载后执行的多行高度更新
167
151
  * Textarea sizing callbacks run after mounting.
@@ -180,7 +164,6 @@ export function mountPanel(root, catalog) {
180
164
  */
181
165
  const updateNavigation = () => {
182
166
  const editor = editors.get(navigation.current);
183
- toolbar.hidden = Boolean(navigation.current);
184
167
  heading.textContent = editor?.title ?? definition.metadata?.name ?? active;
185
168
  back.disabled = saving || !navigation.canGoBack;
186
169
  publishNavigation();
@@ -405,18 +388,7 @@ export function mountPanel(root, catalog) {
405
388
  });
406
389
  if (eventName === "input") inputContainer.addEventListener("compositionend", event => event.target.dispatchEvent(new window.Event("input", { bubbles: true })));
407
390
  groups.get(group).append(row);
408
- searchRows.push({ row, text: [field.name, field.key, field.description, ...(field.options ?? []).map(option => option.label)].join(" ").toLocaleLowerCase() });
409
391
  }
410
- const empty = node("p", "pp-description", "没有匹配的设置项");
411
- empty.hidden = true;
412
- empty.setAttribute("role", "status");
413
- view.append(empty);
414
- search.oninput = () => {
415
- const words = search.value.trim().toLocaleLowerCase().split(/\s+/);
416
- for (const { row, text } of searchRows) row.hidden = !words.every(word => text.includes(word));
417
- for (const rows of groups.values()) rows.parentElement.hidden = [...rows.children].every(row => row.hidden);
418
- empty.hidden = searchRows.some(({ row }) => !row.hidden);
419
- };
420
392
  const cachePage = node("section", "pp-cache-page");
421
393
  const output = node("pre", "pp-cache");
422
394
  output.textContent = "暂无缓存";
package/src/build.mjs CHANGED
@@ -12,12 +12,10 @@ export async function build(boxjs, css = "") {
12
12
  if (typeof css !== "string") throw new TypeError("CSS must be a string");
13
13
  const catalog = new BoxJS(boxjs);
14
14
  const module = catalog.module.module;
15
- const [html, app, navigation] = await Promise.all([readFile(new URL("../dist/module/index.html", import.meta.url), "utf8"), readFile(new URL("../dist/module/app.mjs", import.meta.url), "utf8"), readFile(new URL("../dist/module/navigation.mjs", import.meta.url), "utf8")]);
15
+ const [html, app] = await Promise.all([readFile(new URL("../dist/module/index.html", import.meta.url), "utf8"), readFile(new URL("../dist/module/app.mjs", import.meta.url), "utf8")]);
16
16
  return {
17
17
  [`settings/${module}/index.html`]: html,
18
- [`settings/assets/${module}.html`]: html,
19
18
  "settings/assets/app.mjs": app,
20
- "settings/assets/navigation.mjs": navigation,
21
19
  [`settings/assets/${module}.css`]: css,
22
20
  };
23
21
  }
package/src/lib/boxjs.mjs CHANGED
@@ -4,14 +4,15 @@ import { validatePathParts } from "./settings-path.mjs";
4
4
  /**
5
5
  * 将 BoxJS 数组、app 或订阅转换为模块字段,保留原文件为唯一字段来源。
6
6
  * Normalize a BoxJS array, app or subscription using the source JSON as the field authority.
7
- * @param {unknown} config BoxJS JSON / BoxJS document.
7
+ * @param {unknown | BoxJS} config BoxJS JSON 或已解析目录 / BoxJS document or parsed catalog.
8
8
  * @param {string} module API 第一段模块名 / First API path segment.
9
9
  * @returns {import("../index.js").ModuleDefinition} 存储根和字段 / Storage root and fields.
10
10
  * @throws {TypeError} 配置结构、字段路径、默认值或展示属性无效 / Invalid configuration, field path, default or presentation attribute.
11
11
  */
12
12
  export function normalizeBoxJs(config, module) {
13
13
  validatePathParts([module]);
14
- const target = new BoxJS(config).modules.get(module);
14
+ const catalog = config instanceof BoxJS ? config : new BoxJS(config);
15
+ const target = catalog.modules.get(module);
15
16
  if (!target) throw new TypeError(`No BoxJS settings for module: ${module}`);
16
17
  const { entries, storageKey, metadata } = target;
17
18
  const fields = [];