@farris/cli 2.3.2 → 2.3.4

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.
Files changed (66) hide show
  1. package/lib/commands/add-app.js +1 -1
  2. package/lib/commands/add-app.js.map +1 -1
  3. package/lib/commands/add-lib.js +1 -1
  4. package/lib/commands/add-lib.js.map +1 -1
  5. package/lib/commands/add-project.js +2 -2
  6. package/lib/commands/add-project.js.map +1 -1
  7. package/lib/commands/build-components.js +4 -1
  8. package/lib/commands/build-components.js.map +1 -1
  9. package/lib/commands/create.js +8 -9
  10. package/lib/commands/create.js.map +1 -1
  11. package/lib/commands/dev-serve.js +1 -1
  12. package/lib/commands/dev-serve.js.map +1 -1
  13. package/lib/common/get-vite-config.js +64 -2
  14. package/lib/common/get-vite-config.js.map +1 -1
  15. package/lib/common/project-layout.js +53 -12
  16. package/lib/common/project-layout.js.map +1 -1
  17. package/lib/common/safety.js +4 -4
  18. package/lib/common/safety.js.map +1 -1
  19. package/lib/common/verifier.js +21 -14
  20. package/lib/common/verifier.js.map +1 -1
  21. package/lib/common/workspace-contract.js +28 -3
  22. package/lib/common/workspace-contract.js.map +1 -1
  23. package/lib/index.js +4 -2
  24. package/lib/index.js.map +1 -1
  25. package/lib/plugins/mock.js +293 -0
  26. package/lib/plugins/mock.js.map +1 -0
  27. package/package.json +1 -1
  28. package/templates/create/AGENTS.md +28 -4
  29. package/templates/create/README.md +2 -0
  30. package/templates/lib/components/index.ts +3 -10
  31. package/templates/lib/src/App.vue +2 -4
  32. package/templates/lib/test/index.spec.ts +9 -0
  33. package/templates/lib/test/index.spec.tsx +9 -0
  34. package/templates/mobile/farris.config.mjs +7 -1
  35. package/templates/mobile/mock/README.md +34 -0
  36. package/templates/mobile/src/App.tsx +21 -0
  37. package/templates/mobile/src/components/TheButton.tsx +9 -0
  38. package/templates/mobile/src/main.ts +1 -1
  39. package/templates/mobile/src/router/index.ts +2 -2
  40. package/templates/mobile/src/views/AboutView.tsx +12 -0
  41. package/templates/mobile/src/views/HomeView.tsx +13 -0
  42. package/templates/mobile/test/src/components/TheButton.spec.ts +2 -2
  43. package/templates/mobile/test/src/components/TheButton.spec.tsx +2 -2
  44. package/templates/web/farris.config.mjs +7 -1
  45. package/templates/web/mock/README.md +34 -0
  46. package/templates/web/src/App.tsx +25 -0
  47. package/templates/web/src/components/TheButton.tsx +9 -0
  48. package/templates/web/src/main.ts +1 -1
  49. package/templates/web/src/router/index.ts +2 -2
  50. package/templates/web/src/views/AboutView.tsx +12 -0
  51. package/templates/web/src/views/HomeView.tsx +13 -0
  52. package/templates/web/test/src/components/TheButton.spec.ts +2 -2
  53. package/templates/web/test/src/components/TheButton.spec.tsx +2 -2
  54. package/templates/lib/components/button/index.ts +0 -7
  55. package/templates/lib/components/button/src/button.scss +0 -10
  56. package/templates/lib/components/button/src/button.vue +0 -12
  57. package/templates/lib/test/components/button/button.spec.ts +0 -11
  58. package/templates/lib/test/components/button/button.spec.tsx +0 -11
  59. package/templates/mobile/src/App.vue +0 -80
  60. package/templates/mobile/src/components/TheButton.vue +0 -3
  61. package/templates/mobile/src/views/AboutView.vue +0 -15
  62. package/templates/mobile/src/views/HomeView.vue +0 -9
  63. package/templates/web/src/App.vue +0 -84
  64. package/templates/web/src/components/TheButton.vue +0 -3
  65. package/templates/web/src/views/AboutView.vue +0 -15
  66. package/templates/web/src/views/HomeView.vue +0 -9
@@ -1,9 +1,17 @@
1
1
  # <%= title %> — AI 协作契约
2
2
 
3
- 本文件是本 workspace 的**唯一真源**。子工程内不放任何 AI 配置文件;所有工具(Claude Code / Cursor / Windsurf / Copilot / Codex / Zed / VS Code …)都读这一份。
3
+ 本文件是本 workspace 的**唯一真源**:所有 AI 协作约定都写在这里。根目录 `CLAUDE.md` 只是指向本文件的一行指针。
4
+
5
+ ## 项目速览
6
+
7
+ <%= projectOverview %>
4
8
 
5
9
  ## 1. 全局契约
6
10
 
11
+ ### AI 文件落点
12
+
13
+ - 只在 workspace 根保留本文件(唯一真源)与 `CLAUDE.md`(一行指针);**子工程内不得新增任何 AI 配置文件**(`AGENTS.md`、`CLAUDE.md`、`.cursorrules`、`.windsurfrules` 等),公共约定一律写在本文件里。
14
+
7
15
  ### 目录分层
8
16
 
9
17
  | 目录 | 含义 | 构建产物 |
@@ -11,6 +19,8 @@
11
19
  | `<%= appContainer %>/` | 应用,可部署 | `dist/` |
12
20
  | `<%= libContainer %>/` | 组件库,可发布 | `lib/` |
13
21
 
22
+ 两类容器目录按需生成:只有存在对应类型的工程时才出现(首次 `add-app` / `add-lib` 时自动补建),不用空目录占位。
23
+
14
24
  ### 命令契约
15
25
 
16
26
  | 命令 | 作用 |
@@ -19,10 +29,12 @@
19
29
  | `farris-cli add-app <name>` | 添加应用 |
20
30
  | `farris-cli add-lib <name>` | 添加组件库 |
21
31
  | `farris-cli create-app [name]` | 在当前位置就地创建独立工程(不要用于 workspace 内) |
22
- | `farris-cli workspace create [target]` | workspace 初始化(等价于 create) |
32
+ | `farris-cli workspace create [target]` | `create` 的适配器(参数与行为一致) |
23
33
  | `farris-cli workspace verify` | 校验 workspace 规范 |
24
34
 
25
- ### 根脚本
35
+ - 改动 workspace 结构、根脚本、容器、配置或增删工程后,执行 `pnpm verify` 自检,不通过先修复再提交。
36
+
37
+ ### 命令速查
26
38
 
27
39
  <%= commandTable %>
28
40
 
@@ -30,7 +42,19 @@
30
42
 
31
43
  - 依赖版本统一由根 `pnpm-workspace.yaml` 的 `catalog:` 提供;子工程里属于 catalog 的依赖一律写 `"catalog:"`。
32
44
  - 禁止手工 `npm install` 单个子包;禁止手改 `pnpm-workspace.yaml` 的 `packages` glob 或 `catalog` 版本。
33
- - 根脚本一律 `pnpm --recursive --if-present run <script>`。**根目录没有 `dev` / `preview` 是有意为之**:长驻服务不递归执行,避免多工程抢端口、日志交织。
45
+ - 除 `verify` / `add-app` / `add-lib` 是 CLI 转发外,其余根脚本一律 `pnpm --recursive --if-present run <script>`。**根目录没有 `dev` / `preview` 是有意为之**:长驻服务不递归执行,避免多工程抢端口、日志交织。
46
+
47
+ ### 数据来源与 Mock
48
+
49
+ - 开发期接口数据默认来自工程内 `mock/` 目录,写法与行为见该目录 README;未命中请求按 `farris.config.mjs` 的 `proxy` 转发,联调真实后端在**工程目录内**执行 `pnpm dev --no-mock`,业务代码不改动。
50
+ - 请求路径必须与 mock 的 url 逐字一致;禁止在组件内散落假数据;mock 不得进入构建产物。
51
+
52
+ ### 工程内生成器
53
+
54
+ - `farris-cli generate view <name> [--with-route] [--with-props]`:生成页面;`--with-route` 自动注册路由。
55
+ - `farris-cli generate component <name> [--style none|css|scss]`:生成 `src/components/` 通用组件。
56
+ - `farris-cli generate api <name> -e /api/v1/orders [-m get]`:生成 `src/api/` 接口模块。
57
+ - 路由注册依赖 `src/router/index.ts`(或 `src/router/routes.ts`)中的 `routes = [...]` 赋值形式数组;自己重写 router 必须保留该形式,否则 `--with-route` 不会生效。
34
58
 
35
59
  ## 2. 工程类型差异速查表
36
60
 
@@ -12,6 +12,8 @@
12
12
  └── package.json # 根脚本
13
13
  ```
14
14
 
15
+ 两类容器目录按需生成:只有存在对应类型的工程时才出现(首次 `add-app` / `add-lib` 时自动补建),不会被空目录占位。
16
+
15
17
  ## 快速上手
16
18
 
17
19
  ```bash
@@ -1,10 +1,3 @@
1
- import type { App } from 'vue';
2
- import { Button } from './button';
3
-
4
- export { Button };
5
-
6
- export default {
7
- install(app: App) {
8
- app.use(Button);
9
- }
10
- };
1
+ // 发布物唯一入口(当前为空组件仓库)。
2
+ // 在 components/ 下新增组件后,在此做命名导出;需要全局安装时可用 ../components/common 的 withInstall 包装。
3
+ export {};
@@ -1,7 +1,5 @@
1
- <script setup lang="ts">
2
- import { Button } from '../components';
3
- </script>
1
+ <script setup lang="ts"></script>
4
2
 
5
3
  <template>
6
- <Button type="primary">Lib demo</Button>
4
+ <p>这是一个空组件仓库。在 components/ 下添加组件后,可在此预览。</p>
7
5
  </template>
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ describe('component library entry', () => {
4
+ it('provides an empty publish entry', async () => {
5
+ const entry = await import('../components/index');
6
+
7
+ expect(entry).toBeDefined();
8
+ });
9
+ });
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ describe('component library entry (tsx collection)', () => {
4
+ it('is collected by the unified vitest include', async () => {
5
+ const entry = await import('../components/index');
6
+
7
+ expect(entry).toBeDefined();
8
+ });
9
+ });
@@ -1,7 +1,7 @@
1
1
  import { fileURLToPath, URL } from 'node:url';
2
2
 
3
3
  export default {
4
- // 相对路径 base:微前端(IBP)与静态托管(iGIX iframe)都适用
4
+ // 相对路径 base:微前端(IBP)与 iframe 嵌入场景都适用
5
5
  base: './',
6
6
  routerMode: 'hash',
7
7
  // iife: IBP 微前端单文件产物(默认);如需普通 ESM 站点产物,执行 pnpm build:es
@@ -23,6 +23,12 @@ export default {
23
23
  ],
24
24
  // 插件 默认值 [vue(), vueJsx()] 不要重复添加
25
25
  // plugins: [],
26
+ // 开发期 mock 默认开启:接口数据来自工程内 mock/ 目录,未命中的请求按下方 proxy 转发
27
+ // mock: true,
28
+ // 开发代理:未命中 mock 的接口转发到真实后端;联调时执行 pnpm dev --no-mock 可整体关闭 mock
29
+ // proxy: {
30
+ // '/api': { target: 'http://localhost:8080', changeOrigin: true }
31
+ // },
26
32
  // viteConfig 配置项
27
33
  viteConfig: {}
28
34
  };
@@ -0,0 +1,34 @@
1
+ # mock 目录
2
+
3
+ 开发期接口数据。一个领域一个文件,命名 `*.mock.ts`,默认导出路由数组:
4
+
5
+ ```ts
6
+ export default [
7
+ {
8
+ url: '/api/v1/users', // 必须与代码中的请求路径逐字一致
9
+ method: 'GET', // 默认 GET
10
+ timeout: 300, // 可选 模拟延迟毫秒
11
+ status: 200, // 可选 响应状态码
12
+ response: ({ query, params, body }) => ({
13
+ data: [],
14
+ total: 0
15
+ })
16
+ }
17
+ ];
18
+ ```
19
+
20
+ 规则:
21
+
22
+ - url 必须与代码中的请求路径逐字一致,见 `src/api/` 下的接口模块。
23
+ - 路径参数在 url 里用 `:参数名` 表示,例如 `/api/v1/users/:id`;查询参数不写进 url,在 response 的 `query` 里读取。
24
+ - mock 响应体必须能被工程的 HTTP 客户端正确消费,形状跟着客户端出口走。
25
+ - 同一 url 不允许在多个 mock 文件中重复定义,重复时开发服务启动即报错。
26
+ - mock 只用于开发期:不进构建产物,也不要在组件里散落假数据。
27
+
28
+ 行为:
29
+
30
+ - 命中 mock → 返回 mock 数据。
31
+ - 未命中 → 按 `farris.config.mjs` 的 `proxy` 配置转发真实后端。
32
+ - 未命中且未配代理的 `/api` 路径 → 返回 404 并提示,便于排查漏配。
33
+
34
+ 开关:在工程目录执行 `pnpm dev` 默认生效;`pnpm dev --no-mock` 或 `MOCK=none pnpm dev` 进入真实后端联调。
@@ -0,0 +1,21 @@
1
+ import { defineComponent } from 'vue';
2
+ import { RouterLink, RouterView } from 'vue-router';
3
+
4
+ export default defineComponent({
5
+ name: 'App',
6
+ setup() {
7
+ return () => (
8
+ <>
9
+ <header>
10
+ <div class="wrapper">
11
+ <nav>
12
+ <RouterLink to="/">Home</RouterLink>
13
+ <RouterLink to="/about">About</RouterLink>
14
+ </nav>
15
+ </div>
16
+ </header>
17
+ <RouterView />
18
+ </>
19
+ );
20
+ }
21
+ });
@@ -0,0 +1,9 @@
1
+ import { defineComponent } from 'vue';
2
+ import { Button } from '@farris/mobile-ui-vue';
3
+
4
+ export default defineComponent({
5
+ name: 'TheButton',
6
+ setup() {
7
+ return () => <Button>按钮</Button>;
8
+ }
9
+ });
@@ -1,7 +1,7 @@
1
1
  import { createApp, type App as VueApp } from 'vue';
2
2
  import FarrisVue from '@farris/mobile-ui-vue';
3
3
  import '@farris/mobile-ui-vue/style.css';
4
- import App from './App.vue';
4
+ import App from './App';
5
5
  import router from './router';<%= styleImport %>
6
6
  import { localResources } from './locales';
7
7
 
@@ -6,12 +6,12 @@ export const routes: RouteRecordRaw[] = [
6
6
  {
7
7
  path: '/',
8
8
  name: 'Home',
9
- component: () => import('../views/HomeView.vue')
9
+ component: () => import('../views/HomeView')
10
10
  },
11
11
  {
12
12
  path: '/about',
13
13
  name: 'About',
14
- component: () => import('../views/AboutView.vue')
14
+ component: () => import('../views/AboutView')
15
15
  }
16
16
  ];
17
17
 
@@ -0,0 +1,12 @@
1
+ import { defineComponent } from 'vue';
2
+
3
+ export default defineComponent({
4
+ name: 'AboutView',
5
+ setup() {
6
+ return () => (
7
+ <div class="about">
8
+ <h1>This is an about page</h1>
9
+ </div>
10
+ );
11
+ }
12
+ });
@@ -0,0 +1,13 @@
1
+ import { defineComponent } from 'vue';
2
+ import TheButton from '../components/TheButton';
3
+
4
+ export default defineComponent({
5
+ name: 'HomeView',
6
+ setup() {
7
+ return () => (
8
+ <main>
9
+ <TheButton />
10
+ </main>
11
+ );
12
+ }
13
+ });
@@ -1,12 +1,12 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import { describe, expect, it } from 'vitest';
3
- import TheButton from '../../../src/components/TheButton.vue';
3
+ import TheButton from '../../../src/components/TheButton';
4
4
 
5
5
  describe('TheButton', () => {
6
6
  it('mounts and renders its default slot', () => {
7
7
  const wrapper = mount(TheButton, {
8
8
  global: {
9
- stubs: { 'fm-button': { template: '<button><slot /></button>' } }
9
+ stubs: { FmButton: { template: '<button><slot /></button>' } }
10
10
  }
11
11
  });
12
12
 
@@ -1,12 +1,12 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import { describe, expect, it } from 'vitest';
3
- import TheButton from '../../../src/components/TheButton.vue';
3
+ import TheButton from '../../../src/components/TheButton';
4
4
 
5
5
  describe('TheButton (tsx collection)', () => {
6
6
  it('is collected by the unified vitest include', () => {
7
7
  const wrapper = mount(TheButton, {
8
8
  global: {
9
- stubs: { 'fm-button': { template: '<button><slot /></button>' } }
9
+ stubs: { FmButton: { template: '<button><slot /></button>' } }
10
10
  }
11
11
  });
12
12
 
@@ -1,7 +1,7 @@
1
1
  import { fileURLToPath, URL } from 'node:url';
2
2
 
3
3
  export default {
4
- // 相对路径 base:微前端(IBP)与静态托管(iGIX iframe)都适用
4
+ // 相对路径 base:微前端(IBP)与 iframe 嵌入场景都适用
5
5
  base: './',
6
6
  routerMode: 'hash',
7
7
  // iife: IBP 微前端单文件产物(默认);如需普通 ESM 站点产物,执行 pnpm build:es
@@ -23,6 +23,12 @@ export default {
23
23
  ],
24
24
  // 插件 默认值 [vue(), vueJsx()] 不要重复添加
25
25
  // plugins: [],
26
+ // 开发期 mock 默认开启:接口数据来自工程内 mock/ 目录,未命中的请求按下方 proxy 转发
27
+ // mock: true,
28
+ // 开发代理:未命中 mock 的接口转发到真实后端;联调时执行 pnpm dev --no-mock 可整体关闭 mock
29
+ // proxy: {
30
+ // '/api': { target: 'http://localhost:8080', changeOrigin: true }
31
+ // },
26
32
  // viteConfig 配置项
27
33
  viteConfig: {}
28
34
  };
@@ -0,0 +1,34 @@
1
+ # mock 目录
2
+
3
+ 开发期接口数据。一个领域一个文件,命名 `*.mock.ts`,默认导出路由数组:
4
+
5
+ ```ts
6
+ export default [
7
+ {
8
+ url: '/api/v1/users', // 必须与代码中的请求路径逐字一致
9
+ method: 'GET', // 默认 GET
10
+ timeout: 300, // 可选 模拟延迟毫秒
11
+ status: 200, // 可选 响应状态码
12
+ response: ({ query, params, body }) => ({
13
+ data: [],
14
+ total: 0
15
+ })
16
+ }
17
+ ];
18
+ ```
19
+
20
+ 规则:
21
+
22
+ - url 必须与代码中的请求路径逐字一致,见 `src/api/` 下的接口模块。
23
+ - 路径参数在 url 里用 `:参数名` 表示,例如 `/api/v1/users/:id`;查询参数不写进 url,在 response 的 `query` 里读取。
24
+ - mock 响应体必须能被工程的 HTTP 客户端正确消费,形状跟着客户端出口走。
25
+ - 同一 url 不允许在多个 mock 文件中重复定义,重复时开发服务启动即报错。
26
+ - mock 只用于开发期:不进构建产物,也不要在组件里散落假数据。
27
+
28
+ 行为:
29
+
30
+ - 命中 mock → 返回 mock 数据。
31
+ - 未命中 → 按 `farris.config.mjs` 的 `proxy` 配置转发真实后端。
32
+ - 未命中且未配代理的 `/api` 路径 → 返回 404 并提示,便于排查漏配。
33
+
34
+ 开关:在工程目录执行 `pnpm dev` 默认生效;`pnpm dev --no-mock` 或 `MOCK=none pnpm dev` 进入真实后端联调。
@@ -0,0 +1,25 @@
1
+ import { defineComponent } from 'vue';
2
+ import { RouterLink, RouterView } from 'vue-router';
3
+ import { setupMicroAppContext } from './micro/context';
4
+
5
+ export default defineComponent({
6
+ name: 'App',
7
+ setup() {
8
+ // 微前端环境:订阅主应用下发的上下文(语言 / 主题)
9
+ setupMicroAppContext();
10
+
11
+ return () => (
12
+ <>
13
+ <header>
14
+ <div class="wrapper">
15
+ <nav>
16
+ <RouterLink to="/">Home</RouterLink>
17
+ <RouterLink to="/about">About</RouterLink>
18
+ </nav>
19
+ </div>
20
+ </header>
21
+ <RouterView />
22
+ </>
23
+ );
24
+ }
25
+ });
@@ -0,0 +1,9 @@
1
+ import { defineComponent } from 'vue';
2
+ import { FButton } from '@farris/ui-vue';
3
+
4
+ export default defineComponent({
5
+ name: 'TheButton',
6
+ setup() {
7
+ return () => <FButton>按钮</FButton>;
8
+ }
9
+ });
@@ -1,7 +1,7 @@
1
1
  import { createApp, type App as VueApp } from 'vue';
2
2
  import FarrisVue from '@farris/ui-vue';
3
3
  import '@farris/ui-vue/index.css';
4
- import App from './App.vue';
4
+ import App from './App';
5
5
  import router from './router';<%= styleImport %>
6
6
  import { localResources } from './locales';
7
7
 
@@ -6,12 +6,12 @@ export const routes: RouteRecordRaw[] = [
6
6
  {
7
7
  path: '/',
8
8
  name: 'Home',
9
- component: () => import('../views/HomeView.vue')
9
+ component: () => import('../views/HomeView')
10
10
  },
11
11
  {
12
12
  path: '/about',
13
13
  name: 'About',
14
- component: () => import('../views/AboutView.vue')
14
+ component: () => import('../views/AboutView')
15
15
  }
16
16
  ];
17
17
 
@@ -0,0 +1,12 @@
1
+ import { defineComponent } from 'vue';
2
+
3
+ export default defineComponent({
4
+ name: 'AboutView',
5
+ setup() {
6
+ return () => (
7
+ <div class="about">
8
+ <h1>This is an about page</h1>
9
+ </div>
10
+ );
11
+ }
12
+ });
@@ -0,0 +1,13 @@
1
+ import { defineComponent } from 'vue';
2
+ import TheButton from '../components/TheButton';
3
+
4
+ export default defineComponent({
5
+ name: 'HomeView',
6
+ setup() {
7
+ return () => (
8
+ <main>
9
+ <TheButton />
10
+ </main>
11
+ );
12
+ }
13
+ });
@@ -1,12 +1,12 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import { describe, expect, it } from 'vitest';
3
- import TheButton from '../../../src/components/TheButton.vue';
3
+ import TheButton from '../../../src/components/TheButton';
4
4
 
5
5
  describe('TheButton', () => {
6
6
  it('mounts and renders its default slot', () => {
7
7
  const wrapper = mount(TheButton, {
8
8
  global: {
9
- stubs: { 'f-button': { template: '<button><slot /></button>' } }
9
+ stubs: { FButton: { template: '<button><slot /></button>' } }
10
10
  }
11
11
  });
12
12
 
@@ -1,12 +1,12 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import { describe, expect, it } from 'vitest';
3
- import TheButton from '../../../src/components/TheButton.vue';
3
+ import TheButton from '../../../src/components/TheButton';
4
4
 
5
5
  describe('TheButton (tsx collection)', () => {
6
6
  it('is collected by the unified vitest include', () => {
7
7
  const wrapper = mount(TheButton, {
8
8
  global: {
9
- stubs: { 'f-button': { template: '<button><slot /></button>' } }
9
+ stubs: { FButton: { template: '<button><slot /></button>' } }
10
10
  }
11
11
  });
12
12
 
@@ -1,7 +0,0 @@
1
- import Button from './src/button.vue';
2
- import { withInstall } from '../common/with-install';
3
-
4
- const FButton = withInstall(Button);
5
-
6
- export { FButton as Button };
7
- export default FButton;
@@ -1,10 +0,0 @@
1
- .f-button {
2
- display: inline-flex;
3
- align-items: center;
4
- padding: 4px 12px;
5
- }
6
-
7
- .f-button--primary {
8
- color: #fff;
9
- background: #2e77e5;
10
- }
@@ -1,12 +0,0 @@
1
- <script setup lang="ts">
2
- defineOptions({ name: 'Button' });
3
- defineProps<{
4
- type?: 'primary' | 'default';
5
- }>();
6
- </script>
7
-
8
- <template>
9
- <button class="f-button" :class="{ 'f-button--primary': type === 'primary' }">
10
- <slot />
11
- </button>
12
- </template>
@@ -1,11 +0,0 @@
1
- import { mount } from '@vue/test-utils';
2
- import { describe, expect, it } from 'vitest';
3
- import { Button } from '../../../../components/button/index';
4
-
5
- describe('Button', () => {
6
- it('renders its default slot', () => {
7
- const wrapper = mount(Button, { slots: { default: 'OK' } });
8
-
9
- expect(wrapper.text()).toContain('OK');
10
- });
11
- });
@@ -1,11 +0,0 @@
1
- import { mount } from '@vue/test-utils';
2
- import { describe, expect, it } from 'vitest';
3
- import { Button } from '../../../../components/button/index';
4
-
5
- describe('Button (tsx collection)', () => {
6
- it('is collected by the unified vitest include', () => {
7
- const wrapper = mount(Button, { slots: { default: 'OK' } });
8
-
9
- expect(wrapper.text()).toContain('OK');
10
- });
11
- });
@@ -1,80 +0,0 @@
1
- <script setup lang="ts">
2
- import { RouterLink, RouterView } from 'vue-router';
3
- </script>
4
-
5
- <template>
6
- <header>
7
- <div class="wrapper">
8
- <nav>
9
- <RouterLink to="/">Home</RouterLink>
10
- <RouterLink to="/about">About</RouterLink>
11
- </nav>
12
- </div>
13
- </header>
14
-
15
- <RouterView />
16
- </template>
17
-
18
- <style scoped>
19
- header {
20
- line-height: 1.5;
21
- max-height: 100vh;
22
- }
23
-
24
- .logo {
25
- display: block;
26
- margin: 0 auto 2rem;
27
- }
28
-
29
- nav {
30
- width: 100%;
31
- font-size: 12px;
32
- text-align: center;
33
- margin-top: 2rem;
34
- }
35
-
36
- nav a.router-link-exact-active {
37
- color: var(--color-text);
38
- }
39
-
40
- nav a.router-link-exact-active:hover {
41
- background-color: transparent;
42
- }
43
-
44
- nav a {
45
- display: inline-block;
46
- padding: 0 1rem;
47
- border-left: 1px solid var(--color-border);
48
- }
49
-
50
- nav a:first-of-type {
51
- border: 0;
52
- }
53
-
54
- @media (min-width: 1024px) {
55
- header {
56
- display: flex;
57
- place-items: center;
58
- padding-right: calc(var(--section-gap) / 2);
59
- }
60
-
61
- .logo {
62
- margin: 0 2rem 0 0;
63
- }
64
-
65
- header .wrapper {
66
- display: flex;
67
- place-items: flex-start;
68
- flex-wrap: wrap;
69
- }
70
-
71
- nav {
72
- text-align: left;
73
- margin-left: -1rem;
74
- font-size: 1rem;
75
-
76
- padding: 1rem 0;
77
- margin-top: 1rem;
78
- }
79
- }
80
- </style>
@@ -1,3 +0,0 @@
1
- <template>
2
- <fm-button>按钮</fm-button>
3
- </template>
@@ -1,15 +0,0 @@
1
- <template>
2
- <div class="about">
3
- <h1>This is an about page</h1>
4
- </div>
5
- </template>
6
-
7
- <style>
8
- @media (min-width: 1024px) {
9
- .about {
10
- min-height: 100vh;
11
- display: flex;
12
- align-items: center;
13
- }
14
- }
15
- </style>
@@ -1,9 +0,0 @@
1
- <script setup lang="ts">
2
- import TheButton from '../components/TheButton.vue';
3
- </script>
4
-
5
- <template>
6
- <main>
7
- <TheButton />
8
- </main>
9
- </template>