@ bitakit/ 应用程序首选项
BitaKit 的设置 UI: 生成的设置页面、 设置控件、 设置路由 它的导航、搜索和插件概览,以及允许导航和快速的 URL 动作 搜索到达每个设置页面 .
它不拥有价值。 插件以 defineSettings 内 settings.ts· ;
@bitakit/core 证实、储存和坚守 settings.storage 合同),以及
@bitakit/ui 揭穿他们 useSetting 财务报告和审定财务报表 useSettingsCatalog。仅此套件
使状态和呼叫 set 财务报告和审定财务报表 reset。 。 。 .
用这个
安装软件包; 发现激活其插件( E)bitakit.plugin: ./foundation) 及其定义
样式。 挂起路线一次 :
// src/app/settings/[[...section]]/page.tsx (Next.js; TanStack: a `settings.$` route)
'use client';
import { SettingsRoute } from '@bitakit/app-preferences';
export default function Page() {
return <SettingsRoute />;
}
/settings 显示第一页; /settings/<path> 显示一个区域。 路径名和链接到来
从框架适配器(@bitakit/next, (中文(简体) ), @bitakit/tanstack),它也提供了nuqs
搜索参数的适配器。 添加 @bitakit/app-preferences/locales/<lang>.json 页:1
主机消息目录 .
在任何插件(或应用程序)中声明设置,并在生成的页面上出现 :
// src/plugins/todos/settings.ts
import { defineSettings, setting } from '@bitakit/core';
export default defineSettings({ pageSize: setting({ default: 20 }) });
打开 /settings/todos:其导航条目,页面和数字控制生成.
读取值为 useSetting('todos.pageSize') 在反应。 在此开始; 下面的所有选项都是可选的 .
后来:标签、控制和类别
// src/plugins/todos/settings.ts
import { defineSettings, setting } from '@bitakit/core';
export default defineSettings(
{
pageSize: setting({ default: 20, label: 'Items per page' }),
layout: setting({
default: 'list',
control: 'cards',
options: [
{ value: 'list', label: 'List', description: 'One task per row.' },
{ value: 'board', label: 'Board' },
],
}),
showDone: setting({ default: true, scope: 'device', group: 'advanced' }),
},
{ title: 'Todos', category: 'general', order: 5, shortcut: 'Alt+Shift+T' },
);
- 每个模块一个默认的章节,宣布可见设置或设置页面;可选的额外页面共享相同的目录. 它的 URL 部分是
path(默认:插件 ID,general因为应用. - 字段在卡片中渲染;设置有
group获得他们自己的名片.hidden设置 停止使用生成的页面,但继续通过useSetting财务报告和审定财务报表<SettingField settingKey>。 。 。 . - 控制紧随其后
control,否则值:布尔 = 切换、选项 = 选择、数字 = 编号、字符串、列表、列表(添加和去掉短文本)、包含选项的列表 复选框(其中几个).radio, (中文(简体) ),cards财务报告和审定财务报表textarea明确选择。 其它 值(对象)需要自定义页面. - 分类 :
general, (中文(简体) ),appearance, (中文(简体) ),account, (中文(简体) ),organization, (中文(简体) ),plugins, (中文(简体) ),administration顺序settingsCategories);后面的其他类别 标题。 没有分类的一节列于下文plugins,应用程序下general。 。 。 .
替换生成的页面
一个插件的 ui/settings/page.tsx 替换其生成的页面。 默认导出收到
{ section } 并可再利用生成的部件:
// src/plugins/todos/ui/settings/page.tsx
import {
SettingField,
SettingsFields,
type SettingsCatalogSection,
} from '@bitakit/app-preferences';
export default function TodoSettings({ section }: { section: SettingsCatalogSection }) {
return (
<>
<SettingsFields section={section} exclude={['todos.layout']} />
<SettingField settingKey="todos.layout" />
</>
);
}
页面标题(标题和描述)围绕它来提供。 控制出口用于
自定义布局; 每张都用 SettingControlProps<T> (单位:千美元)field, (中文(简体) ), id, (中文(简体) ), value, (中文(简体) ), onChange, (中文(简体) ),
disabled, (中文(简体) ), describedBy),并且只使价值成为了一个新的值并报告.
设置扩展槽
安装普通 appPreferencesPlugin (自动发现于生成的主机).
其现有的目录现在预测每个可见页面有一个导航行动和一个按键正文.
作者保留 settings.ts 财务报告和审定财务报表 ui/settings/page.tsx;没有人工身体或导航登记.
| 槽 | 内容 | 上下文/选择 |
|---|---|---|
app-preferences.navigation | 行动 | 目录页加明确设置的目的地 |
app-preferences.navigation.footer | 构成部分 | 侧边栏部件 |
app-preferences.page.body | 密钥组件 | entryKey 是目录页 ID; 由目录适配器维护 |
app-preferences.page.after | 构成部分清单 | { pageId }; 几个命令的扩展可以瞄准同一页 |
app-preferences.page.toolbar | 行动 | { pageId } 每个动作输入的地图 |
// audit/ui/slots/app-preferences.page.after.tsx
import type { SlotPredicate } from '@bitakit/core';
import type { SlotProps } from '@bitakit/ui';
export const order = 20;
export const when: SlotPredicate<'app-preferences.page.after'> = ({ payload }) =>
payload.pageId === 'billing/history';
export default function Audit({ payload }: SlotProps<'app-preferences.page.after'>) {
return <p>History for {payload.pageId}</p>;
}
when 是一个纯粹的每个输出的上游。 它接收到解析后的有效载荷,不会改变全球
附加状态。 部件内的反应行为使用现有的服务/设置钩;
用于工具栏 visible编号 :enabled 和绘图输入.
// audit/actions/export.ts
export default defineAction<string>({
title: 'Export',
slots: [{ slot: 'app-preferences.page.toolbar', input: ({ payload }) => payload.pageId }],
visible: ({ input }) => input === 'billing/history',
execute: ({ input, services }) => services.audit.export(input),
});
自定义页面仍然收到 { section, renderField }。 。 。 . showHeader: false 给出页面
拥有其标题。 额外页保留诸如 billing/history独立
uRL 覆盖和翻译;每个额外的页面也可以指定 showHeader。 。 。 .
// billing/ui/settings/page.tsx
export default {
component: BillingPage,
boundary: BillingAccess, // ({ children }) => allowed ? children : existing access UI
pages: [{ id: 'history', title: 'History', component: HistoryPage }],
};
可选边界包含标题、工具栏、正文和扩展名。 额外页面继承它
或者宣布他们自己的。 默认组件导出可以使用 export const boundary = BillingAccess。 。 。 .
重用自有集成的访问政策; 此 UI 边界不授权存储或
服务器操作。 第一当事方账户/组织页与其现有守卫共享
扩展。 复制体键失败; 扩展 page.after 而不是替换一个预计的机体.
导航使用有本地链接和守护的实时动作控制 linkProps({ href }) 页:1
路由基/搜索适应。 现有的 nuqs 搜索、 字段、 类别分组和翻译
留下来。 行动用途 slots: ['app-preferences.navigation'] 默认为
一般类; 团体从不选择其位置。 搜索目录页面仍然包含
字段标签/选项。 (a) 通过现有寿命周期对排放源或排放源进行预测;
兼容的显式主机更新也重建了组件读取预测. 结构变化
仍然需要整个结构的替换.
服务器上的持久设置
数值通过 settings.storage 合同; 浏览器存储为默认值。 一个主机
替换为一个服务:
// src/services/settings-storage.ts
import { defineService, settingsStorage } from '@bitakit/core';
export default defineService(
() => ({
// context: { scope, userId, organizationId } of the value
async load(key, context) {
const response = await fetch(`/api/settings/${key}?scope=${context.scope}`);
return response.json(); // { value, writable }
},
async save(key, value) {
await fetch(`/api/settings/${key}`, { method: 'PUT', body: JSON.stringify(value) });
},
}),
{ provides: settingsStorage },
);
运行时重装值 auth 合同报告另一个用户或组织。 这个
服务器决定什么是可写; UI 显示只读设置.
API 密码
@bitakit/app-preferences (客户部分):
| 导出 | 目的 |
|---|---|
SettingsRoute({ basePath?, pathname?, backHref?, linkComponent? }) | 整个 /settings/[[...section]] 路由; 基础路径显示第一页. |
SettingsShell({ basePath?, pathname?, backHref?, embedded?, children }) | 框架:有搜索的侧边栏(窄屏幕上的抽屉),跳过链接,面包屑. |
SettingsNavigation({ basePath?, pathname?, query? }) | 按类别划分的页面; 标记当前页; 无匹配时的状态 . |
SettingsPage({ basePath?, pathname?, unavailable? }) | 页面在 pathname,或者不可用状态. |
SettingsSectionPage({ section, showHeader? }) | 页眉,然后是插件自己的页面或生成的字段. |
SettingsFields({ section?, fields?, exclude? }) | 生成的卡片字段,按 group; 空状态. |
SettingField({ field } | { settingKey }) | 标签,描述,控制,保存状态,内置出错并重置. |
SwitchControl . CheckboxesControl (9个控制) | 标准控制 : (props: SettingControlProps<T>)。 。 。 . |
controlFor(field) | 控制字段使用, 或未定义 . |
SettingsOverview({ basePath?, query?, showSearch? }) | 每页有其地,可取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取. |
PluginsOverview() | 已安装的插件; 一个插件的细节和设置 ?plugin=<id>。 。 。 . |
settingsCategories | 已知类别及其顺序. |
sectionHref(basePath, section), (中文(简体) ), settingHref(basePath, section, key) | 链接到一个页面,或者一个设置(参见链接到一个设置). |
settingAnchor(key) | 设定的锚, setting-<key>:其领域之id. |
SettingControlProps, (中文(简体) ), SettingsCatalogSection, (中文(简体) ), SettingsCatalogField | 类型. |
九个控制器是 SwitchControl, (中文(简体) ), SelectControl, (中文(简体) ), RadioControl, (中文(简体) ), CardsControl, (中文(简体) ),
TextControl, (中文(简体) ), TextareaControl, (中文(简体) ), NumberControl, (中文(简体) ), ListControl 财务报告和审定财务报表 CheckboxesControl。 。 。 . embedded 打开 SettingsShell 丢弃
后链接并保持侧边栏在宽屏幕上打开,用于主机对话框.
@bitakit/app-preferences/foundation (默认导出) : appPreferencesPlugin({ basePath?, groups?, slots?, searchShortcut? })。 。 。 .
basePath (默认) /settings必须与路线相匹配; groups (默认) ['navigation']已经
“设置”条目的逻辑组. slots 选择其放置目标;默认情况下,安装时会加入壳牌导航. slots: [] 省略导航定位。 不明目标失败. searchShortcut (默认) /(中文(简体) )
这是 app-preferences.search 动作的密钥: 当设置打开时, 它会聚焦设置搜索,
显示空键; false 关掉.
URL 动作
固定的 app-preferences.settings 目的地为公众 ActionMap 财务报告和审定财务报表
不需要输入。 它可以直接与 ActionLink 在严格生成的应用程序.
使用 slots: [] 当主机提供自己的定位而不是壳牌的主要导航时.
插件的设置将目录投放到动作列表中, 因此快速搜索和导航需要 无设置代码 :
settings.section.<id>每页:格里夫<basePath>/<path>图标、顺序和shortcut组合settings.pages页:1settings.category.<category>。 。 。 .app-preferences.settings: "定居"条目(ref)basePath(单位:千美元)groups。 。 。 .settings.plugins.<id>每个插件: href<basePath>/plugins?plugin=<id>组合settings.plugins,由"Plugins"(英语:settings.plugins.heading) (中文(简体) ).
每个载体 destinationMetadata (单位:千美元)settings 或者说 plugin 和自有插件). 标题如下
翻译器和每个注册器都带有插件.
连接到一个设置
每个生成的字段都有ID setting-<key>,所以链接可以命名一个设置:
settingHref('/settings', { path: 'theme' }, 'shell.theme') 给
/settings/theme#setting-shell.theme。打开它,或修改页面上的散列,滚动
字段到中间(在设定减少运动时不动画),使其控制重点和
以主题的焦点环来简短地突出它. 用于搜索结果、帮助文本或一个
帮助将人送到一个设置.
查询参数
q 是设置搜索(边栏和概览), pluginSearch 插件列表搜索和
plugin 概览中显示的插件。 读取它们的部件在悬疑中产生.
翻译
目录决定 <plugin>.settings.<name>.label|description, (中文(简体) ),
<plugin>.settings.<name>.options.<value>.label|description, (中文(简体) ), <plugin>.settings.title|description (应用程序使用
app) (中文(简体) ). 此软件包添加:
<plugin>.settings.groups.<group>: 字段组的标题(默认:组名).settings.categories.<id>.title: 类标题 (默认: 标题情况下的ID).plugins.<id>.name|description: 概览和搜索中的插件名称.app-preferences.ui.*: 本软件包所制作的每个文本( e)locales/en.json, (中文(简体) ),locales/de.json) (中文(简体) ).
来源地图
| 路径 | 责任 |
|---|---|
src/index.ts, (中文(简体) ), src/foundation.ts | 公开条目 |
src/plugin.ts | appPreferencesPlugin: 自有区域、插件页面、设置 |
src/navigation.ts | 自主导航行动和按键机身投影 |
src/catalog.ts | settingsCatalog(): 无头双胞胎 useSettingsCatalog() |
src/slots.ts | 键入的设置导航、正文、扩展名、工具栏和页脚定义 |
src/categories.ts, (中文(简体) ), src/search.ts | 分类顺序和分组,搜索匹配 |
src/paths.ts, (中文(简体) ), src/text.ts, (中文(简体) ), src/id.ts | 路径, 英文文本和翻译助手,插件ID |
src/components/settings-*.tsx | 路线、外壳、导航、页面、字段、概览 |
src/components/setting-field.tsx | 一个设置:状态、写、出错、重置 |
src/components/controls.tsx | 标准控制和 controlFor |
src/components/plugins-overview.tsx | 插件列表和细节 |
src/components/ui/ | shadcn Radix Vega 原始 此软件包需要超出 @bitakit/ui/components |
限制
- 明确兼容
runtime.reconcilePlugins更新重新启动组件读取 目录预测; 支持的结构变化使用相同的等待寿命周期 。 供应商 配置道具更改仍然替换运行时间 .scopeModules, (中文(简体) ),scopeTranslation和范围自有的生命周期观测再利用目录. 服务及提供翻译均更新标题而无需替换正文附件. SettingsShell拥有 aSidebarProvider。在另一边栏布局中央提供者 报告Mod+B已注册的快捷键.
验证
npm test --workspace @bitakit/app-preferences # build, type check, node --test (jsdom)
依赖性 : @bitakit/core, (中文(简体) ), @bitakit/ui, (中文(简体) ), nuqs, (中文(简体) ), radix-ui, (中文(简体) ), reicon-react, (中文(简体) ), zod; 对等点 react。 。 。 .
消费者:设置路线的应用程序, @bitakit/shell,快速搜索(通过预测)
行动).
一个插件的多页
保留现有的 ui.settings.component 用于默认页面。 添加 ui.settings.pages
有条目 { id, component, title, description?, path?, category?, order?, icon?, shortcut?, showHeader?, boundary? }。 。 。 .
路径相对 /settings; 无 path,使用页面 <default section path>/<id>。 。 。 .
每页都有稳定的目录 ID <plugin>/<id> 当目标元数据保留
正在拥有插件 ID 。 其他页面不重复设置字段或运行时间存储 .
反应钩子和导航动作使用相同的目录执行 @bitakit/ui。 。 。 .
发现的 ui/settings/page.tsx 可能将此对象导出为默认导出,而不是
组件。 现有部件出口继续发挥作用。 设置主机拥有标题;
内容组件应保留其格式和工具栏而无需重复页面标题.
分组导航;它们不准许访问。 页面和服务器 API 执行权限 .
插件概览布局
设置 shell 拥有单一内容滚动区域 。 插件列表和详细流程
页面,包括其标题和搜索控件;它们不添加嵌入式滚动条.
区域框架保存内容高度, 所以贝壳的响应性底垫仍然保留
在上一张卡后可见,包括提供自己标题的页面.
插件细节通过拥有插件ID列出每个目录页,
包括 App 首选项自己的页面。 当元数据供应时, 版本使用标准徽章
a 版本; 缺少的版本没有被发明. ui.settings.showHeader: false 允许自定义
页面拥有它的标题。 共享 PageHeader.before 在标题上方放置后方导航位置.
插件目录元数据
插件元数据可能声明 tags: readonly string[] 财务报告和审定财务报表 coverImage标记是可选的,
大小写敏感分类标签( 偏好短小写名称, 如 security, (中文(简体) ),
非权限或依赖性。 目录从已安装的插件中获取标签选择;
没有标记注册 。 多个所选标签匹配任何所选标签并结合文本搜索; pluginTag 财务报告和审定财务报表
pluginSearch 是 nuqs URL 状态并保存细节/回向导航。 现有插件没有
没有选择标签时,标记仍然可见。 名称,描述和标记参与文本搜索.
宣告元数据在 definePlugin({ metadata: { tags, coverImage } })当地
plugin.config.ts 元数据或软件包.json bitakit.tags 编号 : bitakit.coverImage。保留顶级软件包字段
遗产的后退。 发现和软件包的构建保护了这两个字段。 封面是可选的;
缺少、不安全或失败的图像使用插件图标(或标准拼图倒回) .
App 首选项使用共享标准卡和项目原始文件 @bitakit/ui/components
还有徽章 契约团体使用 sm 仅在条目之间有分隔符的行;
没有额外的群体差距。 列表保留了卡环和焦点大纲的内部间隔,
但代表滚动到设置外壳。 Radix Scrollrea 仍然为明确出口
其他地方的构成。 不需要应用程序 CSS .
每行在插件名称旁放置一个宣布的版本,然后是描述,
可选作者和包装标签。 列表中遗漏了缺少的版本;细节
页面报告为未具体说明。 名称,描述和长标签可以以狭长的宽度来包装.
语义列表使用 .app-preferences-plugins; 每个链接行使用
.app-preferences-plugin。这些钩子可以识别自有的表面和物品; 本地链接
重点和共享组件状态仍然具有权威性.
该页面显示每个没有页码的被过滤插件 。 状态过滤器旁边
标记提供所有插件( 默认) , 启用和禁用 。 它结合了搜索和标记,
使用与开关相同的库存状态,并在切换插件时更新。 失败
插件出现在禁用下, 匹配它们的再试开关 . pluginStatus 使用键入nuqs
字面解析器和从细节/回向导航及搜索和标记中存活下来。 遗产
pagination 查询参数不再限制列表. 链接行
保留本地键盘焦点和导航,但没有全行盘旋背景.
当没有插件匹配时, 现有的标准空组件会显示搜索图标, 简洁
标题和本地化引导以调整搜索或过滤器。 现有的过滤控制
上方仍可提供.
插件概览消耗 useRuntimeInventory 用于公共元数据和申报.
反应图标仍然是可序列快照以外的演示值. 已安装软件包
没有运行中的实例不会被合成到这个仅运行时间的概览中.
bitakit add settings-page <plugin> 脚手架保留自定义页面 renderField; 生成
航行和身体登记仍自动进行.
设置正文和扩展部件使用 UI 软件包的标准每次贡献渲染 边界。 失败的自定义/ 生成的机构识别页面插件; 兄弟姐妹/ 导航 继续使用。 重试后退保留在现有页面访问边界内并消失 当访问被取消时。 这不会改变服务启动政策或服务器授权.
共享布局和扩展区域
贝壳拥有 brand, (中文(简体) ), header.start/center/end, (中文(简体) ), header.rows上下文 header.row.start/end, (中文(简体) ),
content.before/after, (中文(简体) ), footer, (中文(简体) ), drawer.header/body/footer, (中文(简体) ), navigation.group.before/after
和可选 state.content/actions 下划线 shell. 前缀。 现有 sidebar.header/footer, (中文(简体) ),
sidebar.body, (中文(简体) ), app-bar.end 和动作时段 shell.navigation 仍然是明确的合同.
ShellSurface 是共享基础 AppShell.Content 财务报告和审定财务报表 AppShell.FullPage; 命名布局
使用现有的 src/layouts/ 公约. blank 仍为赤裸. 一次是童子军.
使用 AppShell.HeaderRow 有独特的行ID, AppShell.NavigationGroup 明确行动
插槽,以及 AppShell.Drawer 有个独特的抽屉身份证 贡献过滤行/组 Id/ DrawerId
结束 when; 故意省略它会选择所有事件。 半径 工作表保留焦点
和模式;侧为逻辑起始/结尾,带有明确/继承的Radix方向.
PageState/错误的帮助者接受 content 组成和任择 surfaceId 键入
信息/列表恢复区域。 由主机拥有的倒计时/重试从不需要核心. 可选
区域要防止丢失/中断运行时间,客户端要失败。 这样不行
捕获 SSR 或任意同步错误。 基本恢复停留在失败插件之外 .
App 首选项额外拥有 navigation.header, (中文(简体) ), navigation.group.before/after 与
groupId,以及 page.header/before/footer 与 pageId. 页面区域仍然在现有
页面访问边界。 导航-壳区不受单个页面边界的保护.
没有引入第二个设置目录,存储,路由注册或布局引擎.
进步实例和完整区域表: apps/docs/content/docs/reference/layouts.mdx。 。 。 .
会话插件控制
每个已安装的行绑定主机主机 runtime.plugins.change 通过标准采取行动
切换。 核心预览操作并在确认后再次检查. 禁用确认
所有受到影响的依附/拥有的插件;它从不默不作声地级联或未安装代码。 重新启用
在消费者之前提供供应商。 残缺的定义及其设置仍然可用.
这些控制只更改此运行时会话; 重新加载恢复主机配置和
服务 - 本地内存在重新启动时可能重置.
App首选项和壳被保留. 核心额外区块身份/储存/提供者 和需要重新启动的其他组件。 禁用控制显示其翻译原因 通过键盘聚焦工具提示。 待定的工作会使操作相互冲突。 失败 启动允许重试; 失败的清理需要资源回收和新的运行时间 。 这个 如果其目录投影 被不成功的更新所阻止; 其他设置页面保持正常所有者可用性规则 .
套装组
平面仍然是默认值 . pluginView=grouped 显示 此应用程序, 已知捆绑, 未解决
捆绑、一般用途和未分配. pluginBundle 过滤这些段落并合并
带有搜索、标记和状态;所有控制通过nuqs和细节/回向导航进行回转.
重复行共享一次运行的ID并切换. 科数计算出相;共计
计数不同的插件。 主持人 bundles 标签和核心清单是唯一分组
投入。 见 元数据参考。 。 。 .
设置导航类标题是独立的可折叠触发器. 组开始 打开、 保存现有的标题和链接样式, 并隐藏其条目和分组扩展名 关闭时的区域。 活动设置页面仍然挂载 。 更改搜索查询打开 再次匹配组合 。 折叠状态是挂载导航的局部状态,而不是一个持续的设置.