@nsnanocat/preference-panes 0.7.2 → 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.
package/README.md CHANGED
@@ -1,56 +1,39 @@
1
1
  # @nsnanocat/preference-panes
2
2
 
3
- PreferencePanes **只负责具体模块的设置页**。外部输入为这个模块的 BoxJS JSON 和可选 CSS;省略 CSS 使用默认样式。
3
+ PreferencePanes 负责具体模块的设置页、共享导航和本地持久化 API。模块页面只接受 BoxJS JSON 与可选 CSS;业务模块自己发布版本对应的 JSON,项目网站维护定制主页、入口探测和主题。
4
4
 
5
- 项目定制主页由 github.io 等调用方独立维护。主页只探测各模块的 JSON 是否可访问,并提供入口;它的布局、品牌、按钮目录不属于 PreferencePanes。本包不生成主页、模块选择目录或安装选择器。
5
+ ## 通用 API(0.8.0 form 契约)
6
6
 
7
- ## 导入一个模块
7
+ 业务模块安装同一个 `https://github.com/NSNanoCat/PreferencePanes/releases/latest/download/api.js`,不再生成绑定业务配置的读写脚本,也不需要额外安装独立设置插件。该文件由本仓库 Release 工作流发布,自动更新遵循代理工具的缓存周期。
8
8
 
9
- ```js
10
- import { mount } from "@nsnanocat/preference-panes/browser";
11
- import boxjs from "./Module.boxjs.json" with { type: "json" };
12
-
13
- const page = mount(boxjs, ".pp-panel { --pp-accent: #16866a; }");
14
- // 离开模块页时释放视图、样式、监听器和会话。
15
- // Release the view, styles, listeners and session when leaving the module page.
16
- page.destroy();
17
- ```
18
-
19
- 调用后直接显示该 JSON 对应的模块设置,不先显示入口页,也不按当前 URL 选择其它模块。一次输入必须恰好包含一个可推导模块;多模块文件会报错,不会生成菜单。支持字段数组、单 app 和只包含该模块的 apps 订阅。
20
-
21
- `@Root.Module.Settings.key` 推导根、模块和字段路径;app 的 id/name 不替代存储映射。模块名、标题、说明、图标和选项来自 BoxJS。CSS 是正文字符串,作用于该模块文档;嵌入项目主页时应使用独立模块页面或 iframe,避免样式作用到宿主。
22
-
23
- ## 构建模块产物
9
+ API 为 POST /api/get、/api/set、/api/delete。form 字段名是完整 `@root.path`;读取和删除的值留空,写入值可以是普通文本或 JSON。API 不鉴权,不下载 JSON,也不校验控件和枚举。
24
10
 
25
11
  ```js
26
- import { build } from "@nsnanocat/preference-panes";
27
-
28
- const files = await build(boxjs, css);
12
+ await fetch("/api/set", {
13
+ method: "POST",
14
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
15
+ body: new URLSearchParams([["@BiliBili.Enhanced.Settings.Home.Top_left", JSON.stringify("mine")]]),
16
+ });
29
17
  ```
30
18
 
31
- 返回相对路径到正文的映射,调用方写出并托管即可。每次只生成该模块的 HTML、CSS、BoxJS、读写脚本、配置 Mock 和公共启动 JS。模块文件名独立,可以合并不同模块的产物;不会输出或覆盖项目的 `settings/index.html`。
32
-
33
- 直接访问 `/settings/{module}` 时,启动器先导入 `/configs/{module}` JSON 与该模块 CSS,再调用 mount。JSON 缺失或与 URL 不符时不生成表单。项目主页可自行 HEAD `/configs/{module}` 判断入口可用性;PreferencePanes 不接管主页探测逻辑。
19
+ 前端统一 JSON.stringify 再做 form 编码,保留字符串、布尔值、数值、null、数组和对象的区别。API 通过 util Storage/Lodash 读取根、操作目标路径、写回一次;不会在写入后额外读取。缺失键返回 404,写入/删除成功返回 200。旧 /api/{module}/{path} 接口移除。
34
20
 
35
- 也支持为模块页传入 JSON/CSS **资源 URL**:
21
+ ## 页面与输入
36
22
 
37
- ```http
38
- GET /settings/Module?json=%2Fconfigs%2FModule&css=%2Ftheme.css
39
- ```
23
+ 主页状态行使用 `@nsnanocat/preference-panes/navigation` 的 `ModuleStatus`。组件只 HEAD 配置地址,失败显示“未安装”,成功读取 X-PreferencePanes-Version 显示业务模块版本;旧配置未提供版本头时显示“版本未知”。状态行始终占据第二行,不读取持久化设置。
40
24
 
41
- ```http
42
- GET /settings/Module
43
- X-PreferencePanes-JSON: /configs/Module
44
- X-PreferencePanes-CSS: /theme.css
25
+ ```js
26
+ import { mount } from "@nsnanocat/preference-panes/browser";
27
+ const page = mount(boxjs, ".pp-panel { --pp-accent: #16866a; }");
28
+ page.destroy();
45
29
  ```
46
30
 
47
- 每个 Header 分别优先于对应查询参数,未提供时使用上述模块约定;CSS 传空字符串时仅使用内置默认样式。资源必须为 HTTP(S) 或相对 URL,跨域资源需要允许浏览器 CORS。模块身份仍需与 BoxJS 一致,不改变存储根绑定。
31
+ 支持字段数组、单 app 和仅包含一个模块的 apps 订阅。控件、名称、图标和默认值从 BoxJS 解析;`@Root.Module.Settings.key` 直接给出存储根与键路径,不需要额外映射配置。省略 CSS 使用内置样式。
48
32
 
49
- 静态 HTML 无法读取请求头。网页使用共用 `ModuleFrame` 容器:它从原始请求 URL/Header 解析模块上下文,保存在 iframe 元素上,HTML 原样加载。启动器读取容器上下文,不从 about:srcdoc 推断模块,不通过修改 HTML 补 meta 或注入 CSS。原生 WebView 直接携带 Header 导航时,仍由代理生成上下文。
33
+ `/settings/{module}` 由通用 api.js 返回模块文档。页面可通过 json/css 查询参数或 X-PreferencePanes-JSON/CSS Header 指定资源 URL;默认 JSON /configs/{module},CSS 默认空。Header 分别优先。
50
34
 
51
35
  ```js
52
- import { ModuleFrame } from "@nsnanocat/preference-panes/navigation";
53
-
36
+ import { ModuleFrame, Navigation } from "@nsnanocat/preference-panes/navigation";
54
37
  const frame = new ModuleFrame("/settings/Module", {
55
38
  headers: { "X-PreferencePanes-JSON": "/configs/Module", "X-PreferencePanes-CSS": "/theme.css" },
56
39
  signal,
@@ -59,53 +42,19 @@ container.append(frame.element);
59
42
  await frame.load();
60
43
  frame.addEventListener("change", () => { title.textContent = frame.state.title; });
61
44
  back.onclick = () => frame.back();
62
- // 离开时取消加载及事件订阅,节点由 Navigation 在动画结束后移除。
63
- // Cancel loads and subscriptions on departure; Navigation removes the node after its transition.
64
45
  frame.destroy();
65
46
  ```
66
47
 
67
- iframe 隔离模块 CSS,模块二级页使用自身 fragment 历史。嵌入模式由框架自身布局隐藏内部顶栏并使用完整内容高度;容器通过 change/state 报告标题、写入忙碌状态和返回能力,宿主不查询或修改模块内部 DOM。Navigation 负责历史及退出动画,重新进入创建新 ModuleFrame;不使用 localStorage/sessionStorage 缓存输入或设置。
68
-
69
- ## 模块页行为
70
-
71
- ### 共用导航组件
48
+ ModuleFrame iframe 元素上保存原请求上下文,HTML 原样加载,不从 about:srcdoc 猜模块、不注入临时 CSS。框架自身管理嵌入模式,通过事件发布标题、忙碌状态和返回能力。Navigation 统一管理 fragment 历史、滑动、滚动保留、加载取消及动画结束后释放;项目提供根页、子页工厂和布局。
72
49
 
73
- 模块二级页与外部定制主页复用 `Navigation`,通过独立导出使用,不引入表单、BoxJS 或品牌目录:
50
+ 每次进入模块读取 JSON/CSS 和设置一次。二级多选返回复用内存缓存,修改立即写入;成功提示、失败回滚由公共组件处理。Caches 按需查看/清空,重置只删除指定模块子树。
74
51
 
75
- ```js
76
- import { Navigation } from "@nsnanocat/preference-panes/navigation";
77
-
78
- const navigation = new Navigation(container, home, (key, signal) => {
79
- // 返回由项目创建的子页节点;异步加载监听 signal,在退出时取消。
80
- // Return the project's detail node; async loads observe signal for cancellation on departure.
81
- return detailViews.get(key);
82
- });
83
- navigation.open("detail");
84
- navigation.addEventListener("change", () => { back.disabled = !navigation.canGoBack; });
85
- back.onclick = () => navigation.back();
86
- // 卸载整个组件时释放监听器和页面。
87
- // Release listeners and views when unmounting the entire component.
88
- navigation.destroy();
89
- ```
90
-
91
- 工厂返回 HTMLElement,未知键返回 undefined;布局、背景与内容由调用方 CSS/DOM 定义。容器内只放导航管理的节点,组件接管其子节点。根页一直保留,子页 280ms 滑入/滑出,返回动画结束后移除。模块内部返回缓存节点保留控件值与滚动;外部主页每次创建新 iframe,重新读取设置。快速切换会取消旧加载与动画,减少动态效果时立即切换。历史记录、书签初始根页和 srcdoc fragment 只在组件中处理;实例之间依靠浏览器联合历史,不跨 iframe 操作 DOM。
92
-
93
- `build` 额外输出公共 `settings/assets/navigation.mjs`,静态主页可直接导入该地址;它不生成或接管主页内容。
94
-
95
- 渲染器使用已导入的 JSON 创建控件,只 GET 一次设置子树;不会再次请求配置或探测其它模块。打开/刷新模块文档重新导入,再读取设置。单选为下拉框,多选为二级选项页;二级返回不刷新设置值。
96
-
97
- 修改立即串行 POST,200 后更新当前内存并通知;失败恢复已保存值。保留 Caches 查看/清空和模块重置,不展示逐字段保存或删除按钮。API 按 BoxJS 根和模块用 util 读写任意 JSON 路径,不重复校验控件或枚举。
98
-
99
- ## 文件导入测试台
100
-
101
- ```sh
102
- npm run preview
103
- ```
52
+ 模块数据操作位于标题栏右侧三点菜单,页面不再平铺维护按钮。`ActionMenu` 为独立页和宿主常驻顶栏共用组件;宿主将 `frame.state.actions` 传给 `menu.update(actions, busy)`,选择时调用 `frame.perform(id)`。缓存查看进入可返回的缓存子页,清空和重置仍要求确认。菜单组件处理外部点击、Escape、方向键与 Tab,宿主不访问 iframe 内部 DOM。
104
53
 
105
- 浏览器中选择一个模块的 JSON、可选 CSS,点击“生成”,在独立 iframe 查看模块页。不会自动装入示例,不会生成项目主页。CSS 隔离在预览文档内;测试数据只保存在内存,不访问用户代理存储。
54
+ ## 构建与验证
106
55
 
107
- ## 维护
56
+ `npm run build` 生成无业务配置的 dist/api.js 和公共前端;Release 工作流上传 api.js、index.html、app.mjs、navigation.mjs。`build(boxjs, css?)` 仅用于生成模块前端文件,不再输出配置副本或模块绑定脚本。
108
57
 
109
- 遵循 AGENTS.md 与通用 Biome 配置。运行 `npm run check` 和 `npm run apifox:check` 验证代码、类型、行为与文档。0.7.2 通过 ModuleFrame 保留 iframe 请求上下文,并与常驻顶栏同步导航状态;JSON/CSS 输入及存储接口保持不变,运行时无额外 npm 依赖。
58
+ `npm run preview` 提供文件导入测试台,上传 JSON/CSS 后在隔离 iframe 预览;测试存储只在内存中。`npm run check` 检查代码、类型、行为;`npm run apifox:generate` 和 `npm run apifox:check` 维护原生接口文档。
110
59
 
111
60
  [接口规范](apifox/Specification.md) · [Apifox JSON](apifox/preference-panes.apifox.json)