@component-hook/create-app 1.4.4 → 1.5.0

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 (106) hide show
  1. package/{template-shared/LICENSE → LICENSE} +1 -1
  2. package/README.md +1 -1
  3. package/dist/index.mjs +26 -23
  4. package/package.json +4 -4
  5. package/template-react/.vscode/extensions.json +0 -9
  6. package/template-react/.vscode/settings.json +0 -18
  7. package/template-react/README.md.art +0 -84
  8. package/template-react/eslint.config.js +0 -18
  9. package/template-react/index.html.art +0 -13
  10. package/template-react/lint-staged.config.js +0 -6
  11. package/template-react/package.json +0 -69
  12. package/template-react/public/vite.svg +0 -1
  13. package/template-react/src/App.tsx +0 -6
  14. package/template-react/src/__tests__/e2e/home.spec.ts +0 -40
  15. package/template-react/src/__tests__/unit/pages/home/components/HelloWorld.test.tsx +0 -45
  16. package/template-react/src/__tests__/unit/pages/home/index.test.tsx +0 -19
  17. package/template-react/src/__tests__/unit/render/index.tsx +0 -15
  18. package/template-react/src/assets/svg-icons/react.svg +0 -1
  19. package/template-react/src/components/common/index.ts +0 -1
  20. package/template-react/src/components/common/svg-icon/index.ts +0 -1
  21. package/template-react/src/components/common/svg-icon/src/index.tsx +0 -23
  22. package/template-react/src/main.tsx +0 -26
  23. package/template-react/src/mocks/browser.ts +0 -4
  24. package/template-react/src/mocks/handlers/index.ts +0 -1
  25. package/template-react/src/mocks/server.ts +0 -4
  26. package/template-react/src/pages/home/components/hello-world/index.tsx +0 -49
  27. package/template-react/src/pages/home/index.module.css +0 -8
  28. package/template-react/src/pages/home/index.tsx +0 -37
  29. package/template-react/src/plugins/i18n/index.ts +0 -15
  30. package/template-react/src/plugins/i18n/locales/en-US.json +0 -3
  31. package/template-react/src/plugins/i18n/locales/zh-TW.json +0 -3
  32. package/template-react/src/router/index.tsx +0 -22
  33. package/template-react/src/stores/constants.ts +0 -1
  34. package/template-react/src/stores/index.ts +0 -1
  35. package/template-react/src/stores/middleware.ts +0 -17
  36. package/template-react/src/stores/modules/config.ts +0 -27
  37. package/template-react/src/styles/base.css +0 -68
  38. package/template-react/src/styles/common/all.css +0 -1
  39. package/template-react/src/styles/common/button.css +0 -26
  40. package/template-react/src/styles/index.css +0 -3
  41. package/template-react/src/styles/tailwind.css +0 -14
  42. package/template-react/src/vite-env.d.ts +0 -9
  43. package/template-react/tsconfig.app.json +0 -32
  44. package/template-react/tsconfig.vitest.json +0 -10
  45. package/template-react/vite.config.ts +0 -40
  46. package/template-react/vitest.config.ts +0 -18
  47. package/template-react/vitest.setup.ts +0 -13
  48. package/template-shared/.browserslistrc +0 -10
  49. package/template-shared/.github/actions/setup-environment/action.yml +0 -21
  50. package/template-shared/.github/renovate.json +0 -14
  51. package/template-shared/.github/workflows/ci.yml +0 -22
  52. package/template-shared/.github/workflows/deploy.yml +0 -27
  53. package/template-shared/.github/workflows/preview.yml +0 -17
  54. package/template-shared/.gitlab/setup.yml +0 -18
  55. package/template-shared/.husky/commit-msg +0 -1
  56. package/template-shared/.husky/pre-commit +0 -1
  57. package/template-shared/_gitignore +0 -32
  58. package/template-shared/_gitlab-ci.yml +0 -22
  59. package/template-shared/commitlint.config.js +0 -3
  60. package/template-shared/playwright.config.ts +0 -49
  61. package/template-shared/postcss.config.js +0 -15
  62. package/template-shared/prettier.config.js +0 -13
  63. package/template-shared/scripts/build-info/index.ts +0 -21
  64. package/template-shared/tsconfig.json +0 -14
  65. package/template-shared/tsconfig.node.json +0 -12
  66. package/template-vue/.vscode/extensions.json +0 -10
  67. package/template-vue/.vscode/settings.json +0 -18
  68. package/template-vue/README.md.art +0 -80
  69. package/template-vue/eslint.config.js +0 -18
  70. package/template-vue/index.html.art +0 -28
  71. package/template-vue/lint-staged.config.js +0 -6
  72. package/template-vue/package.json +0 -68
  73. package/template-vue/public/vite.svg +0 -1
  74. package/template-vue/src/App.vue +0 -7
  75. package/template-vue/src/__tests__/e2e/home.spec.ts +0 -61
  76. package/template-vue/src/__tests__/unit/pages/home/components/HelloWorld.test.ts +0 -57
  77. package/template-vue/src/__tests__/unit/pages/home/index.test.ts +0 -17
  78. package/template-vue/src/__tests__/unit/render/index.ts +0 -28
  79. package/template-vue/src/assets/svg-icons/vue.svg +0 -1
  80. package/template-vue/src/components/common/index.ts +0 -1
  81. package/template-vue/src/components/common/svg-icon/index.ts +0 -1
  82. package/template-vue/src/components/common/svg-icon/src/index.vue +0 -29
  83. package/template-vue/src/locales/en-US.json +0 -3
  84. package/template-vue/src/locales/zh-TW.json +0 -3
  85. package/template-vue/src/main.ts +0 -21
  86. package/template-vue/src/mocks/browser.ts +0 -4
  87. package/template-vue/src/mocks/handlers/index.ts +0 -1
  88. package/template-vue/src/mocks/server.ts +0 -4
  89. package/template-vue/src/pages/home/components/HelloWorld.vue +0 -54
  90. package/template-vue/src/pages/home/index.vue +0 -46
  91. package/template-vue/src/plugins/i18n.ts +0 -11
  92. package/template-vue/src/router/index.ts +0 -23
  93. package/template-vue/src/stores/constants.ts.art +0 -1
  94. package/template-vue/src/stores/index.ts +0 -15
  95. package/template-vue/src/stores/modules/config.ts +0 -20
  96. package/template-vue/src/styles/base.css +0 -59
  97. package/template-vue/src/styles/common/all.css +0 -1
  98. package/template-vue/src/styles/common/button.css +0 -15
  99. package/template-vue/src/styles/index.css +0 -3
  100. package/template-vue/src/styles/tailwind.css +0 -1
  101. package/template-vue/src/vite-env.d.ts +0 -9
  102. package/template-vue/tsconfig.app.json +0 -12
  103. package/template-vue/tsconfig.vitest.json +0 -10
  104. package/template-vue/vite.config.ts +0 -46
  105. package/template-vue/vitest.config.ts +0 -18
  106. package/template-vue/vitest.setup.ts +0 -12
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c)
3
+ Copyright (c) 2023 Tzuyi
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Scaffolding a basic `typescript` project.
4
4
 
5
5
  > **Compatibility Note:**
6
- > Requires [Node.js](https://nodejs.org/en/) version 20.19+. However, some templates require a higher Node.js version to work, please upgrade if your package manager warns about it.
6
+ > Requires [Node.js](https://nodejs.org/en/) version 20.19.6+. However, some templates require a higher Node.js version to work, please upgrade if your package manager warns about it.
7
7
 
8
8
  <p>
9
9
  <a href="https://npm-stat.com/charts.html?package=@component-hook/create-app">
package/dist/index.mjs CHANGED
@@ -8,7 +8,6 @@ import minimist from "minimist";
8
8
  import ora from "ora";
9
9
  import colors from "picocolors";
10
10
  import prompts from "prompts";
11
-
12
11
  //#region src/constants.ts
13
12
  const DEFAULT_PROJECT_NAME = "basic-project";
14
13
  const TEMPLATES = ["vue", "react"];
@@ -19,7 +18,6 @@ const CI = [
19
18
  "gitlab-ci",
20
19
  "none"
21
20
  ];
22
-
23
21
  //#endregion
24
22
  //#region src/utils.ts
25
23
  function formatTargetDir(targetDir) {
@@ -69,7 +67,6 @@ function getCiArtContent(ci = "") {
69
67
  if (!ciName) return "";
70
68
  return `- **CI/CD**: Integrates \`${ciName}\` for automated testing and deployment.`;
71
69
  }
72
-
73
70
  //#endregion
74
71
  //#region src/prompts.ts
75
72
  function builtinTemplate(template) {
@@ -141,7 +138,7 @@ function operationPrompts({ targetDir, template, ci }) {
141
138
  {
142
139
  type: builtinTemplate(template) ? null : "select",
143
140
  name: "framework",
144
- message: template ? styleTitle(`${colors.red(template)} isn't a valid template. Please choose from below:`) : styleTitle("Select a framework:"),
141
+ message: styleTitle(template ? `${colors.red(template)} isn't a valid template. Please choose from below:` : "Select a framework:"),
145
142
  initial: 0,
146
143
  choices: [{
147
144
  title: colors.green("Vue"),
@@ -154,7 +151,7 @@ function operationPrompts({ targetDir, template, ci }) {
154
151
  {
155
152
  type: checkCi(ci) ? null : "select",
156
153
  name: "ci",
157
- message: ci ? styleTitle(`${colors.red(ci)} isn't a valid CI/CD. Please choose from below:`) : styleTitle("Choose CI/CD:"),
154
+ message: styleTitle(ci ? `${colors.red(ci)} isn't a valid CI/CD. Please choose from below:` : "Choose CI/CD:"),
158
155
  choices: [
159
156
  {
160
157
  title: "GitHub Actions",
@@ -173,7 +170,6 @@ function operationPrompts({ targetDir, template, ci }) {
173
170
  }
174
171
  ], { onCancel });
175
172
  }
176
-
177
173
  //#endregion
178
174
  //#region src/index.ts
179
175
  const cwd = process.cwd();
@@ -223,9 +219,9 @@ async function writePackageJson(root, dir, packageName) {
223
219
  }
224
220
  async function copyFolder(root, dir, packageName, ci) {
225
221
  const files = await readdir(dir);
226
- const ignoreFiles = new Set(["package.json", ...ciFilters[ci] || ciFilters.none]);
222
+ const ignoreFiles = /* @__PURE__ */ new Set(["package.json", ...ciFilters[ci] || ciFilters.none]);
227
223
  const filterFiles = files.filter((file) => !ignoreFiles.has(file));
228
- const rewriteOrCopyFile = (file) => {
224
+ const rewriteOrCopyFile = async (file) => {
229
225
  const targetPath = path.join(root, renameFiles?.[file] ?? file);
230
226
  const templatePath = path.join(dir, file);
231
227
  if (file.endsWith(".art")) {
@@ -240,8 +236,10 @@ async function copyFolder(root, dir, packageName, ci) {
240
236
  }
241
237
  if (statSync(templatePath).isDirectory()) {
242
238
  const rewriteOrCopySubFilePromises = readdirSync(templatePath).map((subFile) => rewriteOrCopyFile(path.join(file, subFile)));
243
- return Promise.all(rewriteOrCopySubFilePromises).then(() => {});
244
- } else return copy(templatePath, targetPath);
239
+ await Promise.all(rewriteOrCopySubFilePromises);
240
+ return;
241
+ }
242
+ return copy(templatePath, targetPath);
245
243
  };
246
244
  return Promise.all(filterFiles.map((file) => rewriteOrCopyFile(file)));
247
245
  }
@@ -272,12 +270,13 @@ async function createApp() {
272
270
  const filePath = fileURLToPath(import.meta.url);
273
271
  const sharedDir = path.resolve(filePath, "../..", "template-shared");
274
272
  const templateDir = path.resolve(filePath, "../..", `template-${framework}`);
275
- Promise.all([
276
- copyFolder(root, sharedDir, packageName, ciName),
277
- copyFolder(root, templateDir, packageName, ciName),
278
- writePackageJson(root, templateDir, packageName),
279
- new Promise((resolve) => setTimeout(resolve, 300))
280
- ]).then(() => {
273
+ try {
274
+ await Promise.all([
275
+ copyFolder(root, sharedDir, packageName, ciName),
276
+ copyFolder(root, templateDir, packageName, ciName),
277
+ writePackageJson(root, templateDir, packageName),
278
+ new Promise((resolve) => setTimeout(resolve, 300))
279
+ ]);
281
280
  const cdProjectName = path.relative(cwd, root);
282
281
  const formattedCdProjectName = cdProjectName.includes(" ") ? `"${cdProjectName}"` : cdProjectName;
283
282
  spinner.succeed(`${colors.green("Scaffolded project in")} ${colors.yellow(root)}`);
@@ -291,13 +290,17 @@ async function createApp() {
291
290
  console.log(colors.cyan(` ${pkgManager} run dev`));
292
291
  }
293
292
  console.log();
294
- }).catch(() => {
293
+ } catch {
295
294
  spinner.fail(colors.red("Failed to scaffold project"));
296
- });
295
+ }
297
296
  }
298
- createApp().catch((error) => {
299
- console.error(colors.red(error.message));
300
- });
301
-
297
+ async function bootstrap() {
298
+ try {
299
+ await createApp();
300
+ } catch (error) {
301
+ console.error(colors.red(error instanceof Error ? error.message : String(error)));
302
+ }
303
+ }
304
+ bootstrap();
302
305
  //#endregion
303
- export { };
306
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@component-hook/create-app",
3
3
  "type": "module",
4
- "version": "1.4.4",
4
+ "version": "1.5.0",
5
5
  "description": "Scaffolding a basic typescript project",
6
6
  "author": "Tzuyi",
7
7
  "license": "MIT",
@@ -26,10 +26,10 @@
26
26
  "node": ">=20.19.6"
27
27
  },
28
28
  "dependencies": {
29
- "art-template": "^4.13.4",
30
- "fs-extra": "^11.3.3",
29
+ "art-template": "^4.13.7",
30
+ "fs-extra": "^11.3.6",
31
31
  "minimist": "^1.2.8",
32
- "ora": "^9.3.0",
32
+ "ora": "^9.4.1",
33
33
  "picocolors": "^1.1.1",
34
34
  "prompts": "^2.4.2"
35
35
  },
@@ -1,9 +0,0 @@
1
- {
2
- "recommendations": [
3
- "bradlc.vscode-tailwindcss",
4
- "esbenp.prettier-vscode",
5
- "csstools.postcss",
6
- "cpylua.language-postcss",
7
- "streetsidesoftware.code-spell-checker"
8
- ]
9
- }
@@ -1,18 +0,0 @@
1
- {
2
- "editor.tabSize": 2,
3
- "editor.formatOnSave": true,
4
- "editor.defaultFormatter": "esbenp.prettier-vscode",
5
-
6
- "[json]": {
7
- "editor.defaultFormatter": "esbenp.prettier-vscode"
8
- },
9
-
10
- "debug.javascript.autoAttachFilter": "smart",
11
-
12
- "typescript.tsdk": "node_modules/typescript/lib",
13
-
14
- "workbench.editor.splitInGroupLayout": "vertical",
15
- "terminal.integrated.shellIntegration.enabled": true,
16
-
17
- "cSpell.words": ["dotenv", "unplugin", "Sonarjs", "typecheck", "pxtorem", "norem", "partialize"]
18
- }
@@ -1,84 +0,0 @@
1
- # {{projectName}}
2
-
3
- This project is built with [react](https://react.dev/) + [vite](https://vite.dev/), using [pnpm](https://pnpm.io/) for package management and [zustand](https://zustand-demo.pmnd.rs/) for state management.
4
-
5
- ## Features
6
-
7
- - **Development Experience**: Written in [typeScript](https://www.typescriptlang.org/), styled with [tailwindcss](https://tailwindcss.com/), and structured with [react-router-dom](https://reactrouter.com/), and [react-i18next](https://react.i18next.com/). Supports SVGs ([vite-plugin-svg-icons](https://github.com/vbenjs/vite-plugin-svg-icons)).
8
- - **API & Mocking**: Handles requests with [axios](https://axios-http.com/docs/intro) and mocks APIs using [msw](https://mswjs.io/).
9
- - **Code Quality**: Enforces standards with [eslint](https://eslint.org/) and [prettier](https://prettier.io/), with [husky](https://www.npmjs.com/package/husky), [commitlint](https://commitlint.js.org/#/), and [lint-staged](https://github.com/okonet/lint-staged) for commit validation.
10
- - **Testing**: Uses [vitest](https://vitest.dev/) + [testing-library](https://testing-library.com/) for unit testing and [playwright](https://playwright.dev/) for E2E testing.
11
- - **Optimization**: Compresses CSS with [cssnano](https://cssnano.github.io/cssnano/), converts units with [postcss-pxtorem](https://www.npmjs.com/package/postcss-pxtorem), convert modern CSS into something most browsers can understand with [postcss-preset-env](https://www.npmjs.com/package/postcss-preset-env), and analyzes assets with [rollup-plugin-visualizer](https://github.com/btd/rollup-plugin-visualizer).
12
- {{ciContent}}
13
-
14
- ## Code Features / Opinions
15
-
16
- - Project root aliased as `@` to `<project_root>/src`
17
- - ESlint plugin use [@component-hook/eslint-plugin](https://www.npmjs.com/package/@component-hook/eslint-plugin?activeTab=readme)
18
- - if encounter npx: command not found, can execute `ln -s $(which npx) /usr/local/bin/npx` in zsh
19
- - Predefined and fully typed global variables:
20
- - `VITE_APP_VERSION` is read from `package.json` version at build time
21
- - `VITE_APP_LAST_COMMIT_HASH` is last commit hash at build time
22
- - `VITE_APP_BUILD_EPOCH` is populated as `Date.now()` at build time
23
- - `VITE_APP_MOCK` is use mock environment
24
-
25
- ## Project Files
26
-
27
- ```text
28
- src/
29
- ├── __tests__/
30
- │ ├── __mocks__/
31
- │ ├── e2e/*
32
- │ └── unit/*
33
- ├── assets/*
34
- │ └── svg-icons
35
- │ └── react.svg
36
- ├── components/
37
- │ └── common
38
- │ ├── svg-icon/
39
- │ │ ├── src
40
- │ │ │ └── index.tsx
41
- │ │ └── index.ts
42
- │ └── index.ts
43
- ├── constants/*
44
- ├── hooks/*
45
- ├── mocks/
46
- │ ├── handlers/*
47
- │ │ ├── modules/*
48
- │ │ └── index.ts
49
- │ │── browser.ts
50
- │ └── server.ts
51
- ├── pages/
52
- │ └── home/
53
- │ ├── components
54
- │ │ └── hello-world
55
- │ │ └── index.tsx
56
- │ ├── index.module.css
57
- │ └── index.tsx
58
- ├── plugins/
59
- │ └── i18n
60
- │ ├── locales
61
- │ │ ├── es-US.json
62
- │ │ └── zh-TW.json
63
- │ └── index.ts
64
- ├── router/
65
- │ └── index.tsx
66
- ├── stores/
67
- │ ├── modules
68
- │ │ └── config.ts
69
- │ ├── constants.ts
70
- │ ├── index.ts
71
- │ └── middleware.ts
72
- ├── styles/
73
- │ ├── common/
74
- | │ ├── all.css
75
- | │ └── button.css
76
- │ ├── base.css
77
- │ ├── index.css
78
- │ └── tailwind.css
79
- ├── types/*
80
- ├── utils/*
81
- ├── App.tsx
82
- ├── vite-env.d.ts
83
- └── main.tsx
84
- ```
@@ -1,18 +0,0 @@
1
- import componentHookPlugin from '@component-hook/eslint-plugin';
2
-
3
- export default [
4
- ...componentHookPlugin.configs.basic,
5
- ...componentHookPlugin.configs.react,
6
- componentHookPlugin.configs.prettier,
7
- ...componentHookPlugin.configs.sonarjs,
8
- componentHookPlugin.configs.security,
9
- ...componentHookPlugin.configs.markdown,
10
- {
11
- files: ['**/__tests__/unit/**/*.test.[jt]s?(x)'],
12
- ...componentHookPlugin.configs['testing-library/react'],
13
- },
14
- {
15
- files: ['**/__tests__/e2e/**/*.spec.[jt]s?(x)'],
16
- ...componentHookPlugin.configs.playwright,
17
- },
18
- ];
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>{{projectName}}</title>
8
- </head>
9
- <body>
10
- <div id="root"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
13
- </html>
@@ -1,6 +0,0 @@
1
- /** @type {import('lint-staged').Configuration} */
2
-
3
- export default {
4
- '*.{ts,tsx}': () => 'pnpm typecheck',
5
- '*.{ts,js,tsx,jsx}': () => 'pnpm lint',
6
- };
@@ -1,69 +0,0 @@
1
- {
2
- "name": "react-starter",
3
- "type": "module",
4
- "version": "0.0.0",
5
- "private": true,
6
- "packageManager": "pnpm@10.29.2",
7
- "scripts": {
8
- "dev": "vite",
9
- "dev:mock": "MOCK=true vite",
10
- "build": "pnpm typecheck && vite build",
11
- "lint": "eslint --fix .",
12
- "test:unit": "vitest --coverage",
13
- "test:e2e": "playwright test --headed",
14
- "test:ui-e2e": "playwright test --ui",
15
- "test:ci-e2e": "playwright test",
16
- "typecheck": "tsc --noEmit",
17
- "prepare": "husky",
18
- "preview": "vite preview"
19
- },
20
- "dependencies": {
21
- "axios": "^1.13.5",
22
- "i18next": "^25.8.4",
23
- "react": "^19.2.4",
24
- "react-dom": "^19.2.4",
25
- "react-i18next": "^16.5.4",
26
- "react-router-dom": "^7.13.0",
27
- "zustand": "^5.0.11"
28
- },
29
- "optionalDependencies": {
30
- "@commitlint/cli": "^20.4.1",
31
- "@commitlint/config-conventional": "^20.4.1",
32
- "husky": "^9.1.7",
33
- "lint-staged": "^16.2.7"
34
- },
35
- "devDependencies": {
36
- "@component-hook/eslint-plugin": "^1.4.2",
37
- "@playwright/test": "^1.58.2",
38
- "@tailwindcss/vite": "^4.1.18",
39
- "@testing-library/jest-dom": "^6.9.1",
40
- "@testing-library/react": "^16.3.2",
41
- "@testing-library/user-event": "^14.6.1",
42
- "@tsconfig/node24": "^24.0.4",
43
- "@types/node": "^22.19.11",
44
- "@types/react": "^19.2.13",
45
- "@types/react-dom": "^19.2.3",
46
- "@vitejs/plugin-react-swc": "^4.2.3",
47
- "@vitest/coverage-v8": "^4.0.18",
48
- "cssnano": "^7.1.2",
49
- "eslint": "^9.39.2",
50
- "fast-glob": "^3.3.3",
51
- "jsdom": "^28.1.0",
52
- "msw": "^2.12.10",
53
- "postcss": "^8.5.6",
54
- "postcss-preset-env": "^11.1.3",
55
- "postcss-pxtorem": "^6.1.0",
56
- "prettier": "^3.8.1",
57
- "prettier-plugin-tailwindcss": "^0.7.2",
58
- "tailwindcss": "^4.1.18",
59
- "typescript": "^5.9.3",
60
- "vite": "^7.3.1",
61
- "vite-plugin-svg-icons": "^2.0.1",
62
- "vitest": "^4.0.18"
63
- },
64
- "msw": {
65
- "workerDirectory": [
66
- "public"
67
- ]
68
- }
69
- }
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
@@ -1,6 +0,0 @@
1
- import { RouterProvider } from 'react-router-dom';
2
- import router from './router';
3
-
4
- export function App() {
5
- return <RouterProvider router={router} />;
6
- }
@@ -1,40 +0,0 @@
1
- import { expect, test } from '@playwright/test';
2
-
3
- test.beforeEach(async ({ page }) => {
4
- await page.goto('/');
5
- });
6
-
7
- test('click Vite logo open Vite official website blank tab', async ({ page }) => {
8
- const link = page.getByRole('link', { name: /vite logo/i });
9
-
10
- await expect(link).toBeVisible();
11
- const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
12
-
13
- await popup.waitForLoadState();
14
- await expect(popup).toHaveTitle('Vite | Next Generation Frontend Tooling');
15
- });
16
-
17
- test('click React logo open React official website blank tab', async ({ page }) => {
18
- await page.addStyleTag({ content: `* { animation: none !important; }` });
19
- const link = page.getByLabel(/react link/i);
20
-
21
- await expect(link).toBeVisible();
22
- const [popup] = await Promise.all([page.waitForEvent('popup'), link.evaluate((node: HTMLElement) => node.click())]);
23
-
24
- await popup.waitForLoadState();
25
- await expect(popup).toHaveTitle('React');
26
- });
27
-
28
- test('homepage count button interact', async ({ page }) => {
29
- await page.getByRole('button', { name: 'count is 0' }).click();
30
- await expect(page.getByRole('button', { name: 'count is 1' })).toBeVisible();
31
- await page.getByRole('button', { name: 'count is 1' }).click();
32
- await expect(page.getByRole('button', { name: 'count is 2' })).toBeVisible();
33
- });
34
-
35
- test('locale change interact', async ({ page }) => {
36
- await page.getByRole('button', { name: 'English' }).click();
37
- await expect(page.getByRole('button', { name: '中文' })).toBeVisible();
38
- await page.getByRole('button', { name: '中文' }).click();
39
- await expect(page.getByRole('button', { name: 'English' })).toBeVisible();
40
- });
@@ -1,45 +0,0 @@
1
- import { screen } from '@testing-library/react';
2
- import userEvent from '@testing-library/user-event';
3
- import { renderComponent } from '@/__tests__/unit/render';
4
- import { HelloWorld } from '@/pages/home/components/hello-world';
5
- import i18n from '@/plugins/i18n';
6
- import { useConfigStore } from '@/stores';
7
-
8
- describe('home page HelloWorld component', () => {
9
- const { t } = i18n;
10
-
11
- it('renders the correct content', () => {
12
- const title = 'Hello World!';
13
- const { appMeta } = useConfigStore.getState();
14
-
15
- renderComponent(<HelloWorld title={title} />);
16
- expect(screen.getByRole('heading', { name: title })).toBeInTheDocument();
17
- expect(screen.getByRole('button', { name: /count is 0/i })).toBeInTheDocument();
18
- expect(screen.getByText(/edit/i)).toBeInTheDocument();
19
- expect(screen.getByText(/src\/app\.tsx/i)).toBeInTheDocument();
20
- expect(screen.getByText(/save to test hmr/i)).toBeInTheDocument();
21
- expect(screen.getByText(/click on the vite and react logos to learn more/i)).toBeInTheDocument();
22
- expect(screen.getByText(`${appMeta.version} - Built at: ${appMeta.builtAt.toLocaleString()}`)).toBeInTheDocument();
23
- expect(screen.getByRole('button', { name: t('language') })).toBeInTheDocument();
24
- });
25
-
26
- it('count button interact', async () => {
27
- renderComponent(<HelloWorld />);
28
- const countButton = screen.getByRole('button', { name: /count is 0/i });
29
-
30
- await userEvent.click(countButton);
31
- expect(countButton).toHaveTextContent(/count is 1/i);
32
- await userEvent.click(countButton);
33
- await userEvent.click(countButton);
34
- expect(countButton).toHaveTextContent(/count is 3/i);
35
- });
36
-
37
- it('locale change interact', async () => {
38
- renderComponent(<HelloWorld />);
39
- const localeButton = screen.getByRole('button', { name: t('language') });
40
-
41
- expect(localeButton).toHaveTextContent('English');
42
- await userEvent.click(localeButton);
43
- expect(localeButton).toHaveTextContent('中文');
44
- });
45
- });
@@ -1,19 +0,0 @@
1
- import { screen } from '@testing-library/react';
2
- import { renderComponent } from '@/__tests__/unit/render';
3
- import { Home } from '@/pages/home';
4
-
5
- describe('home page', () => {
6
- it('renders the correct content', () => {
7
- renderComponent(<Home />);
8
- const viteLink = screen.getByRole('link', { name: /vite logo/i });
9
- const reactLink = screen.getByLabelText(/react link/i);
10
-
11
- expect(viteLink).toHaveAttribute('href', 'https://vite.dev');
12
- expect(viteLink).toHaveAttribute('rel', 'noreferrer');
13
- expect(viteLink).toHaveAttribute('target', '_blank');
14
-
15
- expect(reactLink).toHaveAttribute('href', 'https://react.dev');
16
- expect(reactLink).toHaveAttribute('rel', 'noreferrer');
17
- expect(reactLink).toHaveAttribute('target', '_blank');
18
- });
19
- });
@@ -1,15 +0,0 @@
1
- import { render } from '@testing-library/react';
2
- import { MemoryRouter } from 'react-router-dom';
3
- import type { RenderOptions } from '@testing-library/react/types';
4
- import type { ReactElement, ReactNode } from 'react';
5
-
6
- function ProvidersWrapper({ children }: { children: ReactNode }) {
7
- return <MemoryRouter>{children}</MemoryRouter>;
8
- }
9
-
10
- export function renderComponent(
11
- component: ReactElement,
12
- options?: Omit<RenderOptions, 'wrapper'>,
13
- ): ReturnType<typeof render> {
14
- return render(component, { wrapper: ProvidersWrapper, ...options });
15
- }
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
@@ -1 +0,0 @@
1
- export * from './svg-icon';
@@ -1 +0,0 @@
1
- export { SvgIcon } from './src/index';
@@ -1,23 +0,0 @@
1
- import type { HTMLAttributes } from 'react';
2
-
3
- type Props = HTMLAttributes<SVGElement> & {
4
- name: string;
5
- prefix?: string;
6
- color?: string;
7
- };
8
-
9
- export function SvgIcon({ name, prefix = 'icon', color = '#333', ...props }: Props) {
10
- const symbolId = `#${prefix}-${name}`;
11
-
12
- return (
13
- <svg
14
- {...props}
15
- aria-hidden="true"
16
- >
17
- <use
18
- href={symbolId}
19
- fill={color}
20
- />
21
- </svg>
22
- );
23
- }
@@ -1,26 +0,0 @@
1
- import { StrictMode } from 'react';
2
- import { createRoot } from 'react-dom/client';
3
- import { App } from './App.tsx';
4
-
5
- import 'virtual:svg-icons-register';
6
- import '@/plugins/i18n';
7
- import '@/styles/index.css';
8
-
9
- const root = createRoot(document.querySelector('#root') as HTMLElement);
10
- const isDev = import.meta.env.DEV;
11
-
12
- if (import.meta.env.VITE_APP_MOCK === 'service-worker') {
13
- const { worker } = await import('@/mocks/browser');
14
-
15
- worker.start();
16
- }
17
-
18
- if (isDev) {
19
- root.render(<App />);
20
- } else {
21
- root.render(
22
- <StrictMode>
23
- <App />
24
- </StrictMode>,
25
- );
26
- }
@@ -1,4 +0,0 @@
1
- import { setupWorker } from 'msw/browser';
2
- import { handlers } from './handlers';
3
-
4
- export const worker = setupWorker(...handlers);
@@ -1 +0,0 @@
1
- export const handlers = [];
@@ -1,4 +0,0 @@
1
- import { setupServer } from 'msw/node';
2
- import { handlers } from './handlers';
3
-
4
- export const mswServer = setupServer(...handlers);