mvframe 1.0.94 → 1.0.96

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/dist/vendor.js CHANGED
@@ -13477,7 +13477,7 @@ const xr = (e, o = {}) => {
13477
13477
  }, Nr = {
13478
13478
  name: "Matt Avias Frame",
13479
13479
  copyright: "©2026",
13480
- version: "1.0.94",
13480
+ version: "1.0.96",
13481
13481
  author: "Matt Avias",
13482
13482
  date: "2026-02-26",
13483
13483
  /** 默认语言 key,与 `$getLang`、localStorage `lang` 一致;业务在 app.use(mvframe, { config }) 里覆盖 */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mvframe",
3
3
  "packageManager": "yarn@4.4.1",
4
- "version": "1.0.94",
4
+ "version": "1.0.96",
5
5
  "author": "matt avis",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -34,6 +34,7 @@
34
34
  "import": "./dist/util.js",
35
35
  "require": "./dist/util.js"
36
36
  },
37
+ "./style/mixin": "./src/style/chip/mixin.scss",
37
38
  "./style": "./dist/css/style.css",
38
39
  "./style/cpt": "./dist/css/cpt.css",
39
40
  "./package.json": "./package.json"
@@ -43,6 +44,8 @@
43
44
  "d": "node scripts/dev-with-notify.js",
44
45
  "notify": "node scripts/notify-server.js",
45
46
  "build": "node scripts/prebuild.js",
47
+ "init-rules": "node scripts/init-rules.js",
48
+ "install-cursor-rules": "node scripts/install-cursor-rules.js",
46
49
  "install-cursor-skill": "node scripts/install-cursor-skill.js",
47
50
  "install-codex-rules": "node scripts/install-codex-agents.js",
48
51
  "scaffold-app": "node scripts/scaffold-app.js",
@@ -53,15 +56,20 @@
53
56
  "mvframe-b": "scripts/build-host.js",
54
57
  "mvframe-d": "scripts/dev-with-notify.js",
55
58
  "mvframe-init-app": "scripts/scaffold-app.js",
59
+ "mvframe-init-rules": "scripts/init-rules.js",
56
60
  "mvframe-install-codex-rules": "scripts/install-codex-agents.js",
61
+ "mvframe-install-cursor-rules": "scripts/install-cursor-rules.js",
57
62
  "mvframe-install-cursor-skill": "scripts/install-cursor-skill.js",
58
63
  "mvframe-notify": "scripts/notify-server.js"
59
64
  },
60
65
  "files": [
61
66
  "dist/*",
67
+ "src/style/chip/mixin.scss",
62
68
  "scripts/build-host.js",
63
69
  "scripts/dev-with-notify.js",
70
+ "scripts/init-rules.js",
64
71
  "scripts/install-codex-agents.js",
72
+ "scripts/install-cursor-rules.js",
65
73
  "scripts/install-cursor-skill.js",
66
74
  "scripts/notify-server.js",
67
75
  "scripts/scaffold-app.js",
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 一次初始化宿主项目的 MVFrame Codex + Cursor 规则。
4
+ *
5
+ * 用法:
6
+ * node path/to/mvframe/scripts/init-rules.js
7
+ * node path/to/mvframe/scripts/init-rules.js /abs/path/to/your-project
8
+ * yarn exec mvframe-init-rules
9
+ *
10
+ * 环境变量(可选):
11
+ * MVFRAME_INIT_RULES_OUT=/path/to/project 等价于第一个参数
12
+ */
13
+
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+ const { upsertCodexAgents } = require("./install-codex-agents.js");
17
+ const { installCursorRules } = require("./install-cursor-rules.js");
18
+
19
+ function main() {
20
+ const argPath = process.argv.find((a, i) => i >= 2 && !a.startsWith("--"));
21
+ const projectRoot = path.resolve(
22
+ process.env.MVFRAME_INIT_RULES_OUT || argPath || process.cwd(),
23
+ );
24
+
25
+ if (!fs.existsSync(projectRoot)) {
26
+ console.error("[mvframe] 目录不存在:", projectRoot);
27
+ process.exit(1);
28
+ }
29
+
30
+ installCursorRules(projectRoot);
31
+ upsertCodexAgents(projectRoot);
32
+
33
+ console.log("[mvframe] 已完成 MVFrame 规则初始化:");
34
+ console.log(" - Cursor: .cursor/rules/*.mdc");
35
+ console.log(" - Codex: AGENTS.md");
36
+ console.log("[mvframe] 请重开 Cursor / 开启新 Codex 会话,确保新规则被重新读取。");
37
+ }
38
+
39
+ if (require.main === module) {
40
+ main();
41
+ }
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 将 MVFrame 包内 `.cursor/rules/*.mdc` 补充到目标工程的 `.cursor/rules/`。
4
+ * 若宿主项目已存在同名规则文件,则保留宿主文件,不覆盖。
5
+ *
6
+ * 用法:
7
+ * node path/to/mvframe/scripts/install-cursor-rules.js
8
+ * node path/to/mvframe/scripts/install-cursor-rules.js /abs/path/to/your-project
9
+ *
10
+ * 环境变量(可选):
11
+ * MVFRAME_CURSOR_RULES_OUT=/path/to/project 等价于第一个参数
12
+ */
13
+
14
+ const fs = require("fs");
15
+ const path = require("path");
16
+
17
+ function installCursorRules(projectRoot) {
18
+ const targetRoot = path.resolve(projectRoot);
19
+ const rulesSrc = path.join(__dirname, "..", ".cursor", "rules");
20
+
21
+ if (!fs.existsSync(rulesSrc)) {
22
+ console.warn(
23
+ "[mvframe] 未找到包内 .cursor/rules(请使用含该目录的 mvframe 版本),跳过 Cursor 规则复制",
24
+ );
25
+ return;
26
+ }
27
+
28
+ const entries = fs.readdirSync(rulesSrc, { withFileTypes: true });
29
+ for (const ent of entries) {
30
+ if (!ent.isFile() || !ent.name.endsWith(".mdc")) continue;
31
+ const src = path.join(rulesSrc, ent.name);
32
+ const dest = path.join(targetRoot, ".cursor", "rules", ent.name);
33
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
34
+ if (fs.existsSync(dest)) {
35
+ console.log("[mvframe] 已存在 Cursor 规则,跳过:");
36
+ console.log(" ", dest);
37
+ continue;
38
+ }
39
+ fs.copyFileSync(src, dest);
40
+ console.log("[mvframe] 已写入 Cursor 规则:");
41
+ console.log(" ", dest);
42
+ }
43
+
44
+ console.log("[mvframe] Cursor 打开该项目后会读取 .cursor/rules/*.mdc。");
45
+ }
46
+
47
+ function main() {
48
+ const argPath = process.argv.find((a, i) => i >= 2 && !a.startsWith("--"));
49
+ const projectRoot = path.resolve(
50
+ process.env.MVFRAME_CURSOR_RULES_OUT || argPath || process.cwd(),
51
+ );
52
+
53
+ if (!fs.existsSync(projectRoot)) {
54
+ console.error("[mvframe] 目录不存在:", projectRoot);
55
+ process.exit(1);
56
+ }
57
+
58
+ installCursorRules(projectRoot);
59
+ }
60
+
61
+ if (require.main === module) {
62
+ main();
63
+ }
64
+
65
+ module.exports = {
66
+ installCursorRules,
67
+ };
@@ -17,6 +17,7 @@ const fs = require("fs");
17
17
  const path = require("path");
18
18
  const { execFileSync } = require("child_process");
19
19
  const { upsertCodexAgents } = require("./install-codex-agents.js");
20
+ const { installCursorRules } = require("./install-cursor-rules.js");
20
21
 
21
22
  const FORCE = process.argv.includes("--force") || process.argv.includes("-f");
22
23
  const NO_PKG = process.argv.includes("--no-package-json") || process.argv.includes("-n");
@@ -54,27 +55,6 @@ function appendGitignoreLines(lines) {
54
55
  console.log("[mvframe-init] 已更新 .gitignore");
55
56
  }
56
57
 
57
- /**
58
- * 将本包 `.cursor/rules/*.mdc` 复制到目标工程,与 mvframe 仓库内 Cursor 规则保持一致。
59
- * 发布包需在 `package.json` 的 `files` 中包含 `.cursor/rules`。
60
- */
61
- function copyCursorRulesFromPackage() {
62
- const rulesSrc = path.join(__dirname, "..", ".cursor", "rules");
63
- if (!fs.existsSync(rulesSrc)) {
64
- console.warn(
65
- "[mvframe-init] 未找到包内 .cursor/rules(请使用含该目录的 mvframe 版本),跳过 Cursor 规则复制",
66
- );
67
- return;
68
- }
69
- const entries = fs.readdirSync(rulesSrc, { withFileTypes: true });
70
- for (const ent of entries) {
71
- if (!ent.isFile() || !ent.name.endsWith(".mdc")) continue;
72
- const content = fs.readFileSync(path.join(rulesSrc, ent.name), "utf8");
73
- const rel = path.join(".cursor", "rules", ent.name);
74
- write(rel.replace(/\\/g, "/"), content);
75
- }
76
- }
77
-
78
58
  /** 与 main.js / vite.config 模板一致;版本号与 mvframe 本仓库对齐思路,可随发布调整 */
79
59
  // @vue/shared 为 Vue 3 内部包,传递依赖在部分包管理器下未提升时 Vite 解析失败,故写入直连依赖
80
60
  const SCAFFOLD_DEPENDENCIES = {
@@ -187,7 +167,7 @@ function main() {
187
167
  fs.mkdirSync(path.join(target, d), { recursive: true });
188
168
  }
189
169
 
190
- copyCursorRulesFromPackage();
170
+ installCursorRules(target);
191
171
  upsertCodexAgents(target);
192
172
  appendGitignoreLines([".env.local", ".env.mvframe-notify"]);
193
173
 
@@ -594,7 +574,8 @@ export {};
594
574
  "src/assets/style/index.scss",
595
575
  `/* 项目全局样式入口(main.js 已 import 本文件) */
596
576
  /* MVFrame:main.js 已 import "mvframe/style" 与 "mvframe/style/cpt"(发布包 CSS),勿在此处再 @import 同一路径,避免重复。 */
597
- /* 若需在 SCSS @use 变量/mixin,可指向 node_modules mvframe 源码路径或 monorepo workspace 路径。 */
577
+ /* 若需在业务 SCSS 内复用 mvframe 断点 / mixin,直接:@use "mvframe/style/mixin" as *; */
578
+ /* 例如:@include media-down(sm) { ... } */
598
579
 
599
580
  body {
600
581
  margin: 0;
@@ -867,6 +848,30 @@ yarn exec mvframe-d
867
848
 
868
849
  \`src/main.js\` 已包含 \`import "mvframe/style"\` 与 \`import "mvframe/style/cpt"\`(分别对应工具类/变量与 **Mvc\*** 组件 scoped 等样式),一般 **无需** 在 \`index.scss\` 再引一遍 mvframe 的 dist CSS,以免重复。项目级覆盖写在 \`src/assets/style/index.scss\` 即可。
869
850
 
851
+ 宿主项目如需在 SCSS 内复用 MVFrame 断点,直接:
852
+
853
+ \`\`\`scss
854
+ @use "mvframe/style/mixin" as *;
855
+
856
+ .Panel {
857
+ padding: 1.5rem;
858
+
859
+ @include media-down(sm) {
860
+ padding: 1rem;
861
+ }
862
+ }
863
+ \`\`\`
864
+
865
+ 发布包的 \`mvframe/style\` 还额外提供响应式工具类:\`{断点}-{up|down|only}-{工具类}\`,如 \`md-down-hide\`、\`lg-up-flexMode\`、\`xs-only-block\`。适合直接写在 template 上;复杂宽高/间距调整仍建议在业务 SCSS 里配合 media mixin 写。
866
+
867
+ 做 Grid 列数切换时,也可以直接在容器上写断点列数类,例如:
868
+
869
+ \`\`\`html
870
+ <div class="grid col2 md2 lg3 sm1 g16"></div>
871
+ \`\`\`
872
+
873
+ 表示默认 2 列,\`sm\` 1 列,\`md\` 2 列,\`lg\` 3 列。
874
+
870
875
  ## 表单 Label
871
876
 
872
877
  \`Input\`、\`Textarea\`、\`Select\`、\`SelectV2\` 支持统一的 label 接口:
@@ -951,6 +956,12 @@ await notify("需要发送到钉钉的消息");
951
956
 
952
957
  初始化脚本会写入/更新项目根 **\`AGENTS.md\`** 的 MVFrame 区块,供 Codex 在宿主项目内优先使用 **MVFrame 全局组件、全局方法与全局样式工具类**,并要求 **每次 AI 完成开发后调用 \`yarn exec mvframe-notify --once --message "..."\` 发送完成通知**。该区块带有 \`MVFRAME-CODEX-RULES\` 标记,重复执行脚手架会更新这段内容,不会覆盖你在 \`AGENTS.md\` 中的其它规则。
953
958
 
959
+ 同时初始化 Codex + Cursor 两侧规则:
960
+
961
+ \`\`\`bash
962
+ yarn exec mvframe-init-rules
963
+ \`\`\`
964
+
954
965
  仅安装 Codex 规则:
955
966
 
956
967
  \`\`\`bash
@@ -959,7 +970,13 @@ yarn exec mvframe-install-codex-rules
959
970
 
960
971
  ## Cursor 规则(\`.cursor/rules\`)
961
972
 
962
- 初始化脚本会把 **mvframe 包内**与仓库一致的 **\`*.mdc\`** 写入目标项目 **\`/.cursor/rules/\`**(\`component-hierarchy\`、\`script-setup\`、\`style-system\`、\`views\`、\`router\`、\`global-components\`、\`data\`、\`util\`)。若目录或文件已存在且未加 \`--force\` / \`-f\`,则跳过对应文件。
973
+ 初始化脚本会把 **mvframe 包内**与仓库一致的 **\`*.mdc\`** 补充到目标项目 **\`/.cursor/rules/\`**(\`component-hierarchy\`、\`script-setup\`、\`style-system\`、\`views\`、\`router\`、\`global-components\`、\`data\`、\`util\`)。若宿主项目已存在同名规则文件,则保留宿主文件,仅补缺失项。
974
+
975
+ 仅安装 Cursor 规则:
976
+
977
+ \`\`\`bash
978
+ yarn exec mvframe-install-cursor-rules
979
+ \`\`\`
963
980
 
964
981
  npm 包需在 \`files\` 中包含 \`.cursor/rules\`;使用本地 \`file:\` / 源码链接时同样可用。
965
982
 
@@ -0,0 +1,141 @@
1
+ @use "sass:list";
2
+ @use "sass:map";
3
+
4
+ // 响应式断点:xs < 40rem,sm 40rem~47.99875rem,md 48rem~63.99875rem,
5
+ // lg 64rem~79.99875rem,xl 80rem~95.99875rem,xxl >= 96rem。
6
+ $media-breakpoints: (
7
+ "xs": 0,
8
+ "sm": 40rem,
9
+ "md": 48rem,
10
+ "lg": 64rem,
11
+ "xl": 80rem,
12
+ "xxl": 96rem,
13
+ ) !default;
14
+
15
+ @function media-breakpoint($name) {
16
+ $value: map.get($media-breakpoints, $name);
17
+ @if $value == null {
18
+ @error "[mvframe media] Unknown breakpoint `#{$name}`. Available: #{map.keys($media-breakpoints)}";
19
+ }
20
+ @return $value;
21
+ }
22
+
23
+ @function media-next($name) {
24
+ $keys: map.keys($media-breakpoints);
25
+ $index: list.index($keys, $name);
26
+
27
+ @if $index == null {
28
+ @error "[mvframe media] Unknown breakpoint `#{$name}`. Available: #{$keys}";
29
+ }
30
+ @if $index == list.length($keys) {
31
+ @return null;
32
+ }
33
+ @return list.nth($keys, $index + 1);
34
+ }
35
+
36
+ @function media-range-max($name) {
37
+ $next: media-next($name);
38
+ @if $next == null {
39
+ @return null;
40
+ }
41
+ @return calc(#{media-breakpoint($next)} - 0.02px);
42
+ }
43
+
44
+ @mixin media-up($name) {
45
+ $min: media-breakpoint($name);
46
+ @if $min == 0 {
47
+ @content;
48
+ } @else {
49
+ @media (min-width: #{$min}) {
50
+ @content;
51
+ }
52
+ }
53
+ }
54
+
55
+ @mixin media-down($name) {
56
+ $max: media-range-max($name);
57
+ @if $max == null {
58
+ @content;
59
+ } @else {
60
+ @media (max-width: #{$max}) {
61
+ @content;
62
+ }
63
+ }
64
+ }
65
+
66
+ @mixin media-only($name) {
67
+ $min: media-breakpoint($name);
68
+ $max: media-range-max($name);
69
+
70
+ @if $min == 0 and $max == null {
71
+ @content;
72
+ } @else if $min == 0 {
73
+ @media (max-width: #{$max}) {
74
+ @content;
75
+ }
76
+ } @else if $max == null {
77
+ @media (min-width: #{$min}) {
78
+ @content;
79
+ }
80
+ } @else {
81
+ @media (min-width: #{$min}) and (max-width: #{$max}) {
82
+ @content;
83
+ }
84
+ }
85
+ }
86
+
87
+ @mixin media-between($from, $to) {
88
+ $keys: map.keys($media-breakpoints);
89
+ $from-index: list.index($keys, $from);
90
+ $to-index: list.index($keys, $to);
91
+
92
+ @if $from-index == null or $to-index == null {
93
+ @error "[mvframe media] Unknown breakpoint in `media-between(#{$from}, #{$to})`. Available: #{$keys}";
94
+ }
95
+ @if $from-index > $to-index {
96
+ @error "[mvframe media] `media-between` expects `$from <= $to`, got `#{$from}` > `#{$to}`.";
97
+ }
98
+
99
+ $min: media-breakpoint($from);
100
+ $max: media-range-max($to);
101
+
102
+ @if $min == 0 and $max == null {
103
+ @content;
104
+ } @else if $min == 0 {
105
+ @media (max-width: #{$max}) {
106
+ @content;
107
+ }
108
+ } @else if $max == null {
109
+ @media (min-width: #{$min}) {
110
+ @content;
111
+ }
112
+ } @else {
113
+ @media (min-width: #{$min}) and (max-width: #{$max}) {
114
+ @content;
115
+ }
116
+ }
117
+ }
118
+
119
+ // 发光阴影效果:::after 伪元素,可被 @include 复用
120
+ @mixin glow-shadow-after($css-var) {
121
+ position: relative;
122
+ isolation: isolate;
123
+ &::after {
124
+ content: "";
125
+ position: absolute;
126
+ top: 0;
127
+ left: 0;
128
+ width: 100%;
129
+ height: 100%;
130
+ opacity: 0.25;
131
+ background-color: var(#{$css-var});
132
+ transform: translateY(20%);
133
+ pointer-events: none;
134
+ filter: blur(0.625rem);
135
+ z-index: -1;
136
+ }
137
+ }
138
+ @mixin hover-box-shadow() {
139
+ box-shadow: 0 0.5rem 0.5rem
140
+ color-mix(in srgb, var(--color-body) 6%, rgba(0, 0, 0, 0.05));
141
+ }