feat(client): 登录/注册页照原型重建,ds 真相源组件族统一全部屏
- 登录/注册(login.html/register.html 1:1):两栏卡片+品牌渐变面板+主题小衣服 pill(onSurface 变体)+记住我(记录并预填最近账号)+原型式 toast 校验; 登录 fidelity 1.4–2.1% 三主题全绿;注册暂不入闸(少 门店编号/兑换券 字段, 已记 CONTRACT,screens.mjs 留存根) - ds 原子补齐:DsToast(.toast 单例)/DsCheck(.check/.agree)/DsButton lg 档/ DsSelect 替换全部旧 DropdownButton/DsField label 在上/DsInput 后缀与密码形态 - 全屏统一:对话框按钮全 DsButton、盒式输入主题钉死(visualDensity.standard、 h38、InputDecorationTheme 渗漏修复)、图标全 lucide、JetBrains Mono 三端同源、 BrandMark 真相源 logo、只读模式写操作全量守卫(WriteGuard+DsToast) - 出入库列表:版式对齐原型(卡片对齐+搜索框居中)、KPI 近30天滚动、结清后 失效财务应收应付表;商品编辑抽屉介绍库改搜索下拉、图片双击全屏预览 - 删除旧 UI 死代码:DataTableCard/FormDialog/PageScaffold/SearchChip/ SelectProductDialog/tabStateProvider - golden/fidelity:stock-in/out 补注册(9%)、login 入册(8%)、goldens 全量重打; 修复 pubspec flutter_web_plugins 非法声明(CI pub get 阻断) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
@@ -25,6 +25,14 @@ const HEX = /Color\(0x[0-9A-Fa-f]{6,8}\)/;
|
||||
const NAMED = /\bColors\.(?!transparent\b)[a-zA-Z]\w*/;
|
||||
const IGNORE = /\/\/\s*ds-ignore/;
|
||||
|
||||
// 文件级豁免:对外公开页(顾客扫码固定品牌页)为**有意独立设计**
|
||||
// (warm-paper/酒红 bespoke 调色板,不随 A/B/C 主题,见 design/CONTRACT.md
|
||||
// 「公开商品/门店页」条目)——整页自成体系,不逐行豁免。
|
||||
const EXEMPT_FILES = [
|
||||
'lib/screens/public/public_product_screen.dart',
|
||||
'lib/screens/public/public_shop_products_screen.dart',
|
||||
];
|
||||
|
||||
function listDartFiles() {
|
||||
if (CHANGED) {
|
||||
let out = '';
|
||||
@@ -50,8 +58,12 @@ function listDartFiles() {
|
||||
return out;
|
||||
}
|
||||
|
||||
const isExempt = (f) =>
|
||||
EXEMPT_FILES.some((e) => f.replaceAll(path.sep, '/').endsWith(e));
|
||||
|
||||
const violations = [];
|
||||
for (const file of listDartFiles()) {
|
||||
if (isExempt(file)) continue; // 文件级豁免(对外公开页 bespoke 设计)
|
||||
const lines = fs.readFileSync(file, 'utf8').split('\n');
|
||||
lines.forEach((line, i) => {
|
||||
if (IGNORE.test(line)) return; // 显式豁免
|
||||
|
||||
@@ -21,13 +21,23 @@ const FIELDS = {
|
||||
'side-muted':'sideMuted','side-active-bg':'sideActiveBg','side-active-fg':'sideActiveFg',
|
||||
'side-border':'sideBorder','side-hover':'sideHover','menu-user-bg':'menuUserBg',
|
||||
'menu-user-fg':'menuUserFg','menu-user-hover':'menuUserHover',
|
||||
'toast-bg':'toastBg',
|
||||
};
|
||||
const DARK = { a:false, b:true, c:false };
|
||||
|
||||
// 基础 :root{}(无 data-theme 选择器)=三主题共用默认值(如 --toast-bg),
|
||||
// 主题块同名变量覆盖之。
|
||||
function baseBlock(){
|
||||
const m = css.match(/(?<!\])\n:root\s*\{([^}]*)\}/) || css.match(/^:root\s*\{([^}]*)\}/m);
|
||||
const out = {};
|
||||
if(m) for(const mm of m[1].matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/g)) out[mm[1]] = mm[2].trim();
|
||||
return out;
|
||||
}
|
||||
const BASE = null; // 惰性求值(css 定义在下方时避免顺序问题)
|
||||
function block(key){
|
||||
const m = css.match(new RegExp(`\\[data-theme="${key}"\\]\\s*\\{([^}]*)\\}`));
|
||||
if(!m) throw new Error('missing theme block: '+key);
|
||||
const out = {};
|
||||
const out = baseBlock();
|
||||
for(const mm of m[1].matchAll(/--([a-z0-9-]+)\s*:\s*([^;]+);/g)) out[mm[1]] = mm[2].trim();
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user