@nsnanocat/preference-panes 0.8.0 → 0.8.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.
@@ -106,7 +106,8 @@
106
106
  }
107
107
  }
108
108
  .pp-fields,
109
- .pp-choice-page {
109
+ .pp-choice-page,
110
+ .pp-cache-page {
110
111
  position: absolute;
111
112
  inset: 0;
112
113
  overflow: auto;
@@ -283,27 +284,13 @@ select.pp-input {
283
284
  color: inherit;
284
285
  text-decoration: underline;
285
286
  }
286
- .pp-maintenance {
287
- margin-top: 24px;
288
- }
289
- .pp-actions {
290
- display: flex;
291
- flex-wrap: wrap;
292
- gap: 8px;
293
- }
294
- .pp-actions button,
295
287
  .pp-error button {
296
288
  min-height: 44px;
297
289
  padding: 8px 12px;
298
290
  border-radius: 6px;
299
291
  background: var(--pp-surface);
300
292
  }
301
- .pp-panel .pp-danger {
302
- color: #e45656;
303
- }
304
293
  .pp-cache {
305
- max-height: 320px;
306
- overflow: auto;
307
294
  white-space: pre-wrap;
308
295
  overflow-wrap: anywhere;
309
296
  }
@@ -1,3 +1,4 @@
1
+ import { ActionMenu } from "./ActionMenu.mjs";
1
2
  import { createPreferencesClient } from "./client.mjs";
2
3
  import { errorView, icon, element as node, resourceURL } from "./components.mjs";
3
4
  import { Navigation } from "./Navigation.mjs";
@@ -20,6 +21,15 @@ export function mountPanel(root, catalog) {
20
21
  back.setAttribute("aria-label", "返回");
21
22
  back.type = "button";
22
23
  const heading = node("h1", "pp-title", title);
24
+ const handlers = new Map();
25
+ const menuItems = [
26
+ { id: "viewCaches", label: "查看缓存" },
27
+ { id: "clearCaches", label: "清空缓存", destructive: true },
28
+ { id: "reset", label: "重置模块", destructive: true },
29
+ ];
30
+ const menu = new ActionMenu(id => handlers.get(id)());
31
+ const trailing = node("span", "pp-nav-spacer");
32
+ trailing.append(menu.element);
23
33
  const brand = node("div", "pp-brand");
24
34
  const logo = node("span", "pp-brand-icon");
25
35
  logo.setAttribute("aria-hidden", "true");
@@ -30,20 +40,26 @@ export function mountPanel(root, catalog) {
30
40
  const toast = node("div", "pp-toast");
31
41
  toast.setAttribute("role", "status");
32
42
  toast.hidden = true;
33
- header.append(back, brand, node("span", "pp-nav-spacer"));
43
+ header.append(back, brand, trailing);
34
44
  shell.append(header, viewport, toast);
35
45
  root.append(shell);
36
46
  // 嵌入模式向宿主发布导航状态,宿主不读取或修改模块内部 DOM。
37
47
  // Embedded mode publishes navigation state without host reads or mutations of the module DOM.
38
48
  const publishNavigation = () => {
49
+ const actions = handlers.size ? menuItems : [];
50
+ menu.update(actions, saving);
39
51
  const frame = window.frameElement;
40
52
  if (!frame?.dataset.preferencePanes) return;
41
53
  frame.dispatchEvent(
42
54
  new frame.ownerDocument.defaultView.CustomEvent("preferencepanes:change", {
43
- detail: { title: heading.textContent, module: catalog.module.module, busy: saving, canGoBack: !back.disabled },
55
+ detail: { title: heading.textContent, module: catalog.module.module, busy: saving, canGoBack: !back.disabled, actions },
44
56
  }),
45
57
  );
46
58
  };
59
+ const onAction = event => {
60
+ if (!saving && handlers.has(event.detail)) handlers.get(event.detail)();
61
+ };
62
+ window.frameElement?.addEventListener("preferencepanes:action", onAction);
47
63
  let timer,
48
64
  navigation,
49
65
  generation = 0,
@@ -353,17 +369,13 @@ export function mountPanel(root, catalog) {
353
369
  if (eventName === "input") inputContainer.addEventListener("compositionend", event => event.target.dispatchEvent(new window.Event("input", { bubbles: true })));
354
370
  groups.get(group).append(row);
355
371
  }
356
- const maintenance = node("section", "pp-maintenance");
357
- maintenance.append(node("h2", "pp-title", "模块数据"));
358
- const actions = node("div", "pp-actions");
359
- const cacheView = node("button", "", "查看 Caches");
360
- const cacheClear = node("button", "", "清空 Caches");
361
- const reset = node("button", "pp-danger", "重置模块");
372
+ const cachePage = node("section", "pp-cache-page");
362
373
  const output = node("pre", "pp-cache");
363
- output.hidden = true;
374
+ output.textContent = "暂无缓存";
364
375
  output.setAttribute("aria-label", "Caches 内容");
365
- for (const button of [cacheView, cacheClear, reset]) button.type = "button";
366
- cacheView.onclick = () => {
376
+ cachePage.append(output);
377
+ editors.set("$caches", { node: cachePage, title: "缓存" });
378
+ handlers.set("viewCaches", () => {
367
379
  if (saving) return;
368
380
  let value;
369
381
  return perform(
@@ -377,12 +389,11 @@ export function mountPanel(root, catalog) {
377
389
  },
378
390
  () => {
379
391
  output.textContent = value === undefined ? "暂无缓存" : JSON.stringify(value, null, 2);
380
- output.hidden = false;
381
- cacheView.textContent = "刷新 Caches";
392
+ navigation.open("$caches");
382
393
  },
383
394
  );
384
- };
385
- cacheClear.onclick = () => {
395
+ });
396
+ handlers.set("clearCaches", () => {
386
397
  if (saving) return;
387
398
  if (!window.confirm(`清空 ${active} 的全部 Caches?`)) return;
388
399
  return perform(
@@ -391,15 +402,12 @@ export function mountPanel(root, catalog) {
391
402
  output.textContent = "暂无缓存";
392
403
  },
393
404
  );
394
- };
395
- reset.onclick = () => {
405
+ });
406
+ handlers.set("reset", () => {
396
407
  if (saving) return;
397
408
  if (!window.confirm(`重置 ${active}?这将删除该模块的 Settings、Caches 和其它持久化数据。`)) return;
398
409
  return perform(() => client.reset(active), controls);
399
- };
400
- actions.append(cacheView, cacheClear, reset);
401
- maintenance.append(actions, output);
402
- view.append(maintenance);
410
+ });
403
411
  navigation?.destroy();
404
412
  navigation = new Navigation(viewport, view, key => editors.get(key)?.node);
405
413
  navigation.addEventListener("change", updateNavigation);
@@ -425,6 +433,8 @@ export function mountPanel(root, catalog) {
425
433
  */
426
434
  destroy() {
427
435
  destroyed = true;
436
+ menu.destroy();
437
+ window.frameElement?.removeEventListener("preferencepanes:action", onAction);
428
438
  navigation?.destroy();
429
439
  generation++;
430
440
  if (active && !saving) client.leave(active);