Regression / regression (push) Canceled after 0s
## 品牌标识(本次会话) 起因:品牌此前没有任何图形标识 —— 唯一 favicon 是内联 data-URI 里的字母「A」, 那是 v2.0.0「Aurora Admin → Kole UI」改名漏掉的一处(PC 顶栏也是「A」, 移动端站已是「K」;移动端文档站则完全没有 favicon)。 - 几何:24 网格三个互不接触的笔画(竖 + 两斜),圆头描边; 描边 2.25 → 16px 标签页尺寸下正好 1.5px = 规范原文「描边1.5px」 - 取色分两套(刻意):favicon 硬编码品牌蓝/白(渲染在浏览器标签栏,不继承 kole-dark); 顶栏标记走 currentColor(实测暗色下自动转 rgb(20,22,28)) - 新增 theme-color 双条(light #FFFFFF / dark #1C1F26,取 --kole-color-card-bg) - 修 site/app.js hero 标语 KOLE ADMIN → KOLE UI(改名变形残留) - 移动端 7 个模板补 favicon(此前计数 0) 验收:门禁 9 条全 OK(site-routing/site-routes/mobile-docs/mobile-site/isolation/ theme/nav/i18n/icons);PC 回归 1464/1464 · 移动端 807/807,各连跑 8 次一致; 两端 favicon 405 字节逐字节一致;PC 站控制台错误 1→0。 ## 并行会话成果(本次一并入库) - 图标系统:2576 图标(TDesign/Element Plus,MIT)+ 11 端注入 + 5 个构建门禁工具 + IconPreview 预览页 + ICON-SPEC.md 冻结规格 - 移动端平台:47 组件 × 6 端 + 文档站 53 页 + 隔离门禁 - PC 组件:103 个大后台组件 / 组件11 批次 - uni-app:PC 端试点 + 移动端端实现 + 真实编译验证 ## 工程 - .gitignore 补 .scratch/ 与 .zcode-preexisting-*.txt(会话中间产物,实测 9.1MB,不入库) - CHANGELOG 补品牌标识条目 - ROADMAP 登 S8-P4(品牌标识任务包 + og:image/apple-touch-icon 未做部分)
306 lines
17 KiB
JavaScript
306 lines
17 KiB
JavaScript
/**
|
||
* family-model.mjs - 组件族的唯一真源(数据层)
|
||
*
|
||
* 设计目标:把「同一交互/结构的重复组件」表达为「1 个基座组件 + N 个参数取值」。
|
||
*
|
||
* 硬约束(改这个文件前必须读):
|
||
* - frameworks/ 必须恰好 395 文件(79 × 5),任何族成员都不得增删文件;
|
||
* - site/data.json 必须保持完整 79 个 slug(对外承诺,见 AGENTS.md 铁律 5);
|
||
* - 族的合并发生在「实现来源」层(一份模板 + 参数)与「契约/API」层,
|
||
* 不改变组件身份(slug)、class 前缀与视觉契约。
|
||
*
|
||
* 每个族的 `mergeBasis` 必须写明实测依据,禁止凭名字臆断。
|
||
* 依据来源:.design_library/kole-ui/components/<slug>.json 的
|
||
* semanticTypeCandidates / variantDimensions / anatomy / structurePatterns / doNotInvent。
|
||
*/
|
||
|
||
/** 参数取值类型:enum=枚举、bool=开关、list=数组、string=字符串、int=整数 */
|
||
export const FAMILIES = [
|
||
{
|
||
id: 'nav-menu',
|
||
label: '导航菜单',
|
||
base: 'sidemenu',
|
||
mergeBasis:
|
||
'topmenu 与 sidemenu 的 semanticTypeCandidates 分别为 menu|topnav 与 menu|sidebar,同一 menu 语义的两个 direction 取值;' +
|
||
'mixednavigation 的 anatomy 即 [top/side/sync/memory],本身就是前两者的参数化组合。' +
|
||
'sidemenu 实现内已存在通用 menu 词汇(kole-menu-item/icon/label/badge/arrow/children/pop)。',
|
||
paramSurface: [
|
||
{ name: 'direction', type: 'enum', values: ['top', 'side', 'mixed'], default: 'side', desc: '导航方向,决定一级菜单的排布' },
|
||
{ name: 'collapsed', type: 'bool', default: false, desc: '侧边模式折叠为仅图标,悬停弹出子级' },
|
||
{ name: 'level', type: 'enum', values: ['1', '2'], default: '2', desc: '最大层级;mixed 固定 2 级(顶一级 + 侧二级)' },
|
||
{ name: 'badge', type: 'bool', default: false, desc: '菜单项徽章' },
|
||
{ name: 'indicator', type: 'enum', values: ['none', 'top', 'left'], default: 'left', desc: '选中指示条;top 模式默认 top,side 模式默认 left' },
|
||
],
|
||
members: [
|
||
{ slug: 'sidemenu', role: 'base', params: { direction: 'side', indicator: 'left', collapsed: false } },
|
||
{ slug: 'topmenu', role: 'variant', params: { direction: 'top', indicator: 'top', collapsed: false } },
|
||
{ slug: 'mixednavigation', role: 'variant', params: { direction: 'mixed', level: '2', collapsed: false } },
|
||
],
|
||
},
|
||
{
|
||
id: 'table',
|
||
label: '数据表格',
|
||
base: 'table',
|
||
mergeBasis:
|
||
'六个成员的 semanticTypeCandidates 首项均为 table;每个变体的 anatomy 都是 Table 骨架(header/row/cell/selectedRow)加一个能力维度。' +
|
||
'treetable 额外带 indent/arrow/parentRow/childRow,是 table 的超集而非并列组件。',
|
||
paramSurface: [
|
||
{ name: 'expandable', type: 'bool', default: false, desc: '行展开;anatomy 增 icon/content/state' },
|
||
{ name: 'fixedTarget', type: 'enum', values: ['none', 'left', 'right', 'header'], default: 'none', desc: '固定列 / 固定表头' },
|
||
{ name: 'mergeAxis', type: 'enum', values: ['none', 'vertical', 'horizontal'], default: 'none', desc: '单元格合并轴向' },
|
||
{ name: 'summary', type: 'enum', values: ['none', 'top', 'bottom'], default: 'none', desc: '统计行位置' },
|
||
{ name: 'treeMode', type: 'bool', default: false, desc: '树形层级(缩进 16px/级 + 展开箭头)' },
|
||
],
|
||
members: [
|
||
{ slug: 'table', role: 'base', params: {} },
|
||
{ slug: 'expandabletable', role: 'variant', params: { expandable: true } },
|
||
{ slug: 'fixedcolumntable', role: 'variant', params: { fixedTarget: 'left' } },
|
||
{ slug: 'mergedcelltable', role: 'variant', params: { mergeAxis: 'vertical' } },
|
||
{ slug: 'summaryrowtable', role: 'variant', params: { summary: 'bottom' } },
|
||
{ slug: 'treetable', role: 'variant', params: { treeMode: true } },
|
||
],
|
||
},
|
||
{
|
||
id: 'masked-input',
|
||
label: '掩码输入',
|
||
base: 'input',
|
||
mergeBasis:
|
||
'七个成员的 semanticTypeCandidates 第二项均为 input;anatomy 均为 input 加 format / validate / segment 的子集。' +
|
||
'差异只是掩码规则与校验规则不同,结构完全同源。',
|
||
paramSurface: [
|
||
{ name: 'mask', type: 'string', default: '', desc: '掩码模式(每 4 位空格、6/8/4 分段、7/8 位车牌等)' },
|
||
{ name: 'length', type: 'int', default: 0, desc: '期望长度;0 表示不限' },
|
||
{ name: 'segment', type: 'list', default: [], desc: '分段长度数组,如 [6,8,4]' },
|
||
{ name: 'validate', type: 'enum', values: ['none', 'luhn', 'checksum', 'regex'], default: 'none', desc: '校验规则' },
|
||
{ name: 'scan', type: 'bool', default: false, desc: '扫码 / 识别入口' },
|
||
{ name: 'autoFocusNext', type: 'bool', default: false, desc: '输入满格自动跳下一格' },
|
||
{ name: 'masked', type: 'bool', default: false, desc: '回显脱敏(密码)' },
|
||
],
|
||
members: [
|
||
{ slug: 'input', role: 'base', params: {} },
|
||
{ slug: 'codeinput', role: 'variant', params: { length: 6, autoFocusNext: true, scan: false } },
|
||
{ slug: 'passwordinput', role: 'variant', params: { masked: true } },
|
||
{ slug: 'phoneinput', role: 'variant', params: { mask: '3-4-4', length: 11 } },
|
||
{ slug: 'idcardinput', role: 'variant', params: { segment: [6, 8, 4], length: 18, scan: true } },
|
||
{ slug: 'bankcardinput', role: 'variant', params: { mask: '4-4-4-4', validate: 'luhn', scan: true } },
|
||
{ slug: 'plateinput', role: 'variant', params: { length: 7, validate: 'regex' } },
|
||
],
|
||
},
|
||
{
|
||
id: 'modal-shell',
|
||
label: '对话弹窗',
|
||
base: 'modal',
|
||
mergeBasis:
|
||
'alertmodal 与 confirmmodal 的 doNotInvent 原文写着「弹窗尺寸档位(见 Modal 契约)」——规范自身声明从属。' +
|
||
'四个变体的 anatomy 均为 mask/container/title/content/footer 的子集或替换。' +
|
||
'popconfirm(240px 无遮罩面板)与 bottomsheet(底部滑出)不属本族:archetype 不同。',
|
||
paramSurface: [
|
||
{ name: 'size', type: 'enum', values: ['sm', 'md', 'lg'], default: 'md', desc: '宽度档位' },
|
||
{ name: 'tone', type: 'enum', values: ['none', 'success', 'error', 'warning', 'info'], default: 'none', desc: '语义色 + 图标' },
|
||
{ name: 'footer', type: 'enum', values: ['none', 'confirm', 'confirm-cancel'], default: 'confirm-cancel', desc: '底部操作' },
|
||
{ name: 'columns', type: 'enum', values: ['1', '2'], default: '1', desc: '表单类弹窗的列数' },
|
||
{ name: 'fullscreen', type: 'bool', default: false, desc: '全屏铺满' },
|
||
],
|
||
members: [
|
||
{ slug: 'modal', role: 'base', params: {} },
|
||
{ slug: 'alertmodal', role: 'variant', params: { tone: 'info', footer: 'confirm' } },
|
||
{ slug: 'confirmmodal', role: 'variant', params: { footer: 'confirm-cancel' } },
|
||
{ slug: 'formmodal', role: 'variant', params: { columns: '2', footer: 'confirm-cancel' } },
|
||
{ slug: 'fullscreenmodal', role: 'variant', params: { fullscreen: true } },
|
||
],
|
||
},
|
||
{
|
||
id: 'preference-switcher',
|
||
label: '偏好切换器',
|
||
base: 'themeswitcher',
|
||
mergeBasis:
|
||
'三个成员的 anatomy 全部包含 persist,structurePatterns 全部写着持久化到 localStorage,' +
|
||
'semanticTypeCandidates 末项均为 preference,变体维度均为同一形态的 3 档选项。三者完全同构,仅选项内容不同。',
|
||
paramSurface: [
|
||
{ name: 'options', type: 'list', default: [], desc: '选项数组 [{value,label,preview?}]' },
|
||
{ name: 'selected', type: 'string', default: '', desc: '当前选中值' },
|
||
{ name: 'persistKey', type: 'string', default: '', desc: 'localStorage 键名;空则持久化到内存' },
|
||
{ name: 'applyScope', type: 'enum', values: ['global', 'local'], default: 'global', desc: '生效范围:全站令牌 / 局部预览' },
|
||
{ name: 'extra', type: 'enum', values: ['none', 'brand-palette', 'demo-list'], default: 'none', desc: '附加区块(品牌色板 / 示例列表)' },
|
||
],
|
||
members: [
|
||
{ slug: 'themeswitcher', role: 'base', params: { extra: 'brand-palette', applyScope: 'global' } },
|
||
{ slug: 'layoutswitcher', role: 'variant', params: { extra: 'none', applyScope: 'global' } },
|
||
{ slug: 'densityswitcher', role: 'variant', params: { extra: 'demo-list', applyScope: 'global' } },
|
||
],
|
||
},
|
||
{
|
||
id: 'card-shell',
|
||
label: '卡片容器',
|
||
base: 'card',
|
||
mergeBasis:
|
||
'四个成员的 semanticTypeCandidates 均含 card 或 panel,anatomy 均为 card 骨架(style/padding/section)加各自填充区。' +
|
||
'本轮不合并实现:employeecard 有独立的字段面(status/contact),合并会污染 card 参数面,仅登记族关系。',
|
||
paramSurface: [
|
||
{ name: 'style', type: 'enum', values: ['plain', 'outlined'], default: 'plain', desc: '描边 / 阴影' },
|
||
{ name: 'padding', type: 'enum', values: ['md', 'lg'], default: 'md', desc: '内边距档位' },
|
||
{ name: 'sections', type: 'list', default: [], desc: '区块序列:header/body/footer/media' },
|
||
{ name: 'actions', type: 'list', default: [], desc: '操作区按钮' },
|
||
{ name: 'layout', type: 'enum', values: ['vertical', 'horizontal'], default: 'vertical', desc: '内容排布方向' },
|
||
],
|
||
members: [
|
||
{ slug: 'card', role: 'base', params: {} },
|
||
{ slug: 'dashboardcard', role: 'variant', params: { layout: 'horizontal' } },
|
||
{ slug: 'employeecard', role: 'variant', params: { sections: ['media', 'body'] } },
|
||
{ slug: 'chartpanel', role: 'variant', params: { sections: ['header', 'body'] } },
|
||
],
|
||
mergeStatus: 'registered-only',
|
||
},
|
||
{
|
||
id: 'feedback-page',
|
||
label: '结果与异常页',
|
||
base: 'resultvariants',
|
||
mergeBasis:
|
||
'三个成员的 semanticTypeCandidates 分别为 result|feedback-page、exception|error-page、empty|placeholder,' +
|
||
'均为「占满内容区的状态说明 + 插画 + 操作」。resultvariants.status[4] 与 exceptionvariants.code[4] 同构。',
|
||
paramSurface: [
|
||
{ name: 'status', type: 'enum', values: ['success', 'error', 'warning', 'info', 'empty'], default: 'info', desc: '状态语义' },
|
||
{ name: 'illustration', type: 'enum', values: ['none', 'icon', 'image'], default: 'icon', desc: '插画形态' },
|
||
{ name: 'extra', type: 'list', default: [], desc: '底部操作区' },
|
||
],
|
||
members: [
|
||
{ slug: 'resultvariants', role: 'base', params: {} },
|
||
{ slug: 'exceptionvariants', role: 'variant', params: { status: 'error' } },
|
||
{ slug: 'emptypro', role: 'variant', params: { status: 'empty' } },
|
||
],
|
||
},
|
||
{
|
||
id: 'loading-state',
|
||
label: '加载态',
|
||
base: 'loadingoverlay',
|
||
mergeBasis:
|
||
'三个成员的 semanticTypeCandidates 分别为 overlay|loading、skeleton|placeholder、progress|indicator,' +
|
||
'是同一语义(加载中)的三种承载形态,共享 coverage / status / showText 三要素。',
|
||
paramSurface: [
|
||
{ name: 'shape', type: 'enum', values: ['overlay', 'block', 'bar'], default: 'overlay', desc: '承载形态:遮罩 / 占位块 / 进度条' },
|
||
{ name: 'status', type: 'enum', values: ['active', 'success', 'exception'], default: 'active', desc: '状态' },
|
||
{ name: 'coverage', type: 'enum', values: ['full', 'local'], default: 'local', desc: '覆盖范围' },
|
||
{ name: 'showText', type: 'bool', default: false, desc: '显示文案 / 百分比' },
|
||
],
|
||
members: [
|
||
{ slug: 'loadingoverlay', role: 'base', params: { shape: 'overlay' } },
|
||
{ slug: 'skeletonpro', role: 'variant', params: { shape: 'block' } },
|
||
{ slug: 'progressvariants', role: 'variant', params: { shape: 'bar' } },
|
||
],
|
||
},
|
||
{
|
||
id: 'steps',
|
||
label: '步骤',
|
||
base: 'steps',
|
||
mergeBasis:
|
||
'steps 与 steplist 的 semanticTypeCandidates 完全相同(均为 steps|wizard),变体维度同为 orientation[2] + state[3]。' +
|
||
'唯一差异是节点形态(横向步骤条 / 纵向列表)。',
|
||
paramSurface: [
|
||
{ name: 'nodeStyle', type: 'enum', values: ['bar', 'list'], default: 'bar', desc: '步骤条 / 步骤列表' },
|
||
{ name: 'orientation', type: 'enum', values: ['horizontal', 'vertical'], default: 'horizontal', desc: '排布方向' },
|
||
{ name: 'editable', type: 'bool', default: false, desc: '可点击回退' },
|
||
],
|
||
members: [
|
||
{ slug: 'steps', role: 'base', params: { nodeStyle: 'bar' } },
|
||
{ slug: 'steplist', role: 'variant', params: { nodeStyle: 'list', orientation: 'vertical' } },
|
||
],
|
||
},
|
||
{
|
||
id: 'tabs',
|
||
label: '标签页',
|
||
base: 'tabs',
|
||
mergeBasis:
|
||
'tabs 的 semanticTypeCandidates 为 tabs|tabnav,enhancedtabnav 为 tabs|browser-tabs;' +
|
||
'enhancedtabnav 的变体维度 state[4]+feature[2] 是 tabs 的 state[4] 超集 —— 增强项即参数。',
|
||
paramSurface: [
|
||
{ name: 'type', type: 'enum', values: ['line', 'card'], default: 'line', desc: '标签形态' },
|
||
{ name: 'draggable', type: 'bool', default: false, desc: '拖拽排序' },
|
||
{ name: 'contextMenu', type: 'bool', default: false, desc: '右键菜单' },
|
||
{ name: 'unsavedMark', type: 'bool', default: false, desc: '未保存标记' },
|
||
],
|
||
members: [
|
||
{ slug: 'tabs', role: 'base', params: {} },
|
||
{ slug: 'enhancedtabnav', role: 'variant', params: { draggable: true, contextMenu: true, unsavedMark: true } },
|
||
],
|
||
},
|
||
{
|
||
id: 'notice',
|
||
label: '全局轻提示',
|
||
base: 'messagepro',
|
||
mergeBasis:
|
||
'messagepro 为 message|toast、notificationpro 为 notification|notice,同属全局轻提示;' +
|
||
'差异只在承载形态(顶部条 / 卡片)与位置,type/action/duration 三要素共享。',
|
||
paramSurface: [
|
||
{ name: 'placement', type: 'enum', values: ['top', 'top-right', 'bottom'], default: 'top', desc: '出现位置' },
|
||
{ name: 'type', type: 'enum', values: ['success', 'error', 'warning', 'info', 'loading'], default: 'info', desc: '语义类型' },
|
||
{ name: 'action', type: 'bool', default: false, desc: '操作按钮' },
|
||
{ name: 'duration', type: 'int', default: 3000, desc: '自动关闭毫秒数;0 为不自动关闭' },
|
||
],
|
||
members: [
|
||
{ slug: 'messagepro', role: 'base', params: { placement: 'top' } },
|
||
{ slug: 'notificationpro', role: 'variant', params: { placement: 'top-right', action: true } },
|
||
],
|
||
},
|
||
{
|
||
id: 'selection-card',
|
||
label: '选择卡片',
|
||
base: 'radiocard',
|
||
mergeBasis:
|
||
'radiocard(radio|card)与 checkboxcard(checkbox|card)的 anatomy 同为 card + 选中态 + 内嵌操作,' +
|
||
'变体维度均含 selection,差异仅为单选 / 多选语义。',
|
||
paramSurface: [
|
||
{ name: 'mode', type: 'enum', values: ['single', 'multiple'], default: 'single', desc: '单选 / 多选' },
|
||
{ name: 'content', type: 'enum', values: ['text', 'rich'], default: 'text', desc: '内容形态' },
|
||
{ name: 'innerActions', type: 'bool', default: false, desc: '卡片内嵌操作区' },
|
||
],
|
||
members: [
|
||
{ slug: 'radiocard', role: 'base', params: { mode: 'single' } },
|
||
{ slug: 'checkboxcard', role: 'variant', params: { mode: 'multiple', innerActions: true } },
|
||
],
|
||
},
|
||
{
|
||
id: 'combobox',
|
||
label: '候选输入',
|
||
base: 'autocomplete',
|
||
mergeBasis:
|
||
'autocomplete(combobox|input)与 mention(mention|input)的 anatomy 均为 input + 候选面板 + 键盘选择,' +
|
||
'类名集合 Jaccard 0.448(全库最高组之一);差异仅为触发方式(连续输入 / 触发符)与插入行为。',
|
||
paramSurface: [
|
||
{ name: 'trigger', type: 'enum', values: ['input', 'symbol'], default: 'input', desc: '触发方式:连续输入 / 触发符' },
|
||
{ name: 'suggestionSource', type: 'enum', values: ['static', 'async'], default: 'static', desc: '候选来源' },
|
||
{ name: 'itemRender', type: 'enum', values: ['plain', 'custom'], default: 'plain', desc: '候选项渲染' },
|
||
{ name: 'insert', type: 'enum', values: ['replace', 'token'], default: 'replace', desc: '选中后插入行为' },
|
||
],
|
||
members: [
|
||
{ slug: 'autocomplete', role: 'base', params: { trigger: 'input' } },
|
||
{ slug: 'mention', role: 'variant', params: { trigger: 'symbol', insert: 'token' } },
|
||
],
|
||
},
|
||
];
|
||
|
||
/** 本批次实际用生成器重写实现的族(其余仅登记契约层族关系) */
|
||
export const IMPLEMENTED_FAMILIES = ['nav-menu'];
|
||
|
||
/** 全部族成员 slug(去重) */
|
||
export function allMemberSlugs() {
|
||
const set = new Set();
|
||
for (const f of FAMILIES) for (const m of f.members) set.add(m.slug);
|
||
return [...set];
|
||
}
|
||
|
||
/** slug -> {family, role, params} */
|
||
export function memberIndex() {
|
||
const map = {};
|
||
for (const f of FAMILIES) {
|
||
for (const m of f.members) {
|
||
if (map[m.slug]) throw new Error(`组件 ${m.slug} 同时属于多个族:${map[m.slug].family} 与 ${f.id}`);
|
||
map[m.slug] = { family: f.id, role: m.role, params: m.params, base: f.base };
|
||
}
|
||
}
|
||
return map;
|
||
}
|
||
|
||
export function familyById(id) {
|
||
return FAMILIES.find((f) => f.id === id) || null;
|
||
}
|