@nsnanocat/preference-panes 0.9.8 → 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);
@@ -18,7 +18,11 @@
18
18
  position: relative;
19
19
  display: flex;
20
20
  flex-direction: column;
21
+ width: 100%;
22
+ max-width: 100vw;
23
+ min-width: 0;
21
24
  height: 100vh;
25
+ overflow: hidden;
22
26
  }
23
27
 
24
28
  :root[data-theme="dark"] .pp-panel {
@@ -53,23 +57,6 @@
53
57
  min-width: 0;
54
58
  overflow-wrap: anywhere;
55
59
  }
56
- /* 模块图标在正文内;嵌入宿主可使用纯文字原生标题栏。
57
- * Keep module icons in content so embedded hosts can use text-only native titles. */
58
- .pp-module-logo {
59
- display: none;
60
- width: 64px;
61
- height: 64px;
62
- margin: 8px auto 20px;
63
- }
64
- .pp-module-logo:not(:empty) {
65
- display: block;
66
- }
67
- .pp-module-logo img {
68
- display: block;
69
- width: 100%;
70
- height: 100%;
71
- object-fit: contain;
72
- }
73
60
  .pp-nav-spacer {
74
61
  width: 44px;
75
62
  flex: none;
@@ -93,17 +80,10 @@
93
80
  opacity: 0.5;
94
81
  cursor: wait;
95
82
  }
96
- /* 固定工具区与滚动视口共用弹性布局,不按工具栏高度拼接页面偏移。
97
- * Fixed tools and the scrolling viewport share a flex layout without toolbar-height offsets. */
98
- .pp-toolbar {
99
- flex: none;
100
- padding: 12px max(16px, calc((100% - 688px) / 2));
101
- background: var(--pp-surface);
102
- border-bottom: 1px solid var(--pp-border);
103
- }
104
83
  .pp-viewport {
105
84
  position: relative;
106
85
  flex: 1;
86
+ min-width: 0;
107
87
  min-height: 0;
108
88
  overflow: hidden;
109
89
  }
@@ -120,7 +100,9 @@
120
100
  .pp-cache-page {
121
101
  position: absolute;
122
102
  inset: 0;
123
- overflow: auto;
103
+ min-width: 0;
104
+ overflow-x: hidden;
105
+ overflow-y: auto;
124
106
  padding: 12px max(16px, calc((100% - 688px) / 2)) calc(28px + env(safe-area-inset-bottom) + var(--pp-keyboard-height, 0px));
125
107
  scroll-padding-bottom: var(--pp-keyboard-height, 0px);
126
108
  background: var(--pp-background);
@@ -164,10 +146,6 @@
164
146
  border: 0;
165
147
  border-radius: 6px;
166
148
  }
167
- .pp-search {
168
- width: 100%;
169
- margin: 0;
170
- }
171
149
  .pp-panel .pp-multiline {
172
150
  display: block;
173
151
  }
@@ -205,6 +183,7 @@
205
183
  font-weight: 400;
206
184
  }
207
185
  .pp-row {
186
+ min-width: 0;
208
187
  min-height: 48px;
209
188
  padding: 16px;
210
189
  display: flex;
@@ -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,15 +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
- view.append(logo);
158
- const search = node("input", "");
159
- search.type = "search";
160
- search.placeholder = "搜索设置项";
161
- search.setAttribute("aria-label", "搜索设置");
162
- const searchField = fieldControl(search);
163
- searchField.classList.add("pp-search");
164
- toolbar.replaceChildren(searchField);
165
- const searchRows = [];
166
149
  /**
167
150
  * 挂载后执行的多行高度更新
168
151
  * Textarea sizing callbacks run after mounting.
@@ -181,7 +164,6 @@ export function mountPanel(root, catalog) {
181
164
  */
182
165
  const updateNavigation = () => {
183
166
  const editor = editors.get(navigation.current);
184
- toolbar.hidden = Boolean(navigation.current);
185
167
  heading.textContent = editor?.title ?? definition.metadata?.name ?? active;
186
168
  back.disabled = saving || !navigation.canGoBack;
187
169
  publishNavigation();
@@ -406,18 +388,7 @@ export function mountPanel(root, catalog) {
406
388
  });
407
389
  if (eventName === "input") inputContainer.addEventListener("compositionend", event => event.target.dispatchEvent(new window.Event("input", { bubbles: true })));
408
390
  groups.get(group).append(row);
409
- searchRows.push({ row, text: [field.name, field.key, field.description, ...(field.options ?? []).map(option => option.label)].join(" ").toLocaleLowerCase() });
410
391
  }
411
- const empty = node("p", "pp-description", "没有匹配的设置项");
412
- empty.hidden = true;
413
- empty.setAttribute("role", "status");
414
- view.append(empty);
415
- search.oninput = () => {
416
- const words = search.value.trim().toLocaleLowerCase().split(/\s+/);
417
- for (const { row, text } of searchRows) row.hidden = !words.every(word => text.includes(word));
418
- for (const rows of groups.values()) rows.parentElement.hidden = [...rows.children].every(row => row.hidden);
419
- empty.hidden = searchRows.some(({ row }) => !row.hidden);
420
- };
421
392
  const cachePage = node("section", "pp-cache-page");
422
393
  const output = node("pre", "pp-cache");
423
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 = [];