wanzhuang-cli 1.0.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 (87) hide show
  1. package/.gitattributes +41 -0
  2. package/README.md +113 -0
  3. package/dist/commands/create.d.ts +10 -0
  4. package/dist/commands/create.js +145 -0
  5. package/dist/commands/generate.d.ts +8 -0
  6. package/dist/commands/generate.js +26 -0
  7. package/dist/commands/update.d.ts +6 -0
  8. package/dist/commands/update.js +26 -0
  9. package/dist/createApiTest/displayEnumLabel.d.ts +3 -0
  10. package/dist/createApiTest/displayEnumLabel.js +10 -0
  11. package/dist/createApiTest/displayTypeLabel.d.ts +19 -0
  12. package/dist/createApiTest/displayTypeLabel.js +135 -0
  13. package/dist/createApiTest/index.d.ts +6 -0
  14. package/dist/createApiTest/index.js +24 -0
  15. package/dist/createApiTest/pet.d.ts +58 -0
  16. package/dist/createApiTest/pet.js +102 -0
  17. package/dist/createApiTest/store.d.ts +28 -0
  18. package/dist/createApiTest/store.js +48 -0
  19. package/dist/createApiTest/types.d.ts +110 -0
  20. package/dist/createApiTest/types.js +17 -0
  21. package/dist/createApiTest/user.d.ts +50 -0
  22. package/dist/createApiTest/user.js +85 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +52 -0
  25. package/dist/utils/api.d.ts +1 -0
  26. package/dist/utils/api.js +48 -0
  27. package/dist/utils/configGen.d.ts +28 -0
  28. package/dist/utils/configGen.js +178 -0
  29. package/dist/utils/deps.d.ts +13 -0
  30. package/dist/utils/deps.js +47 -0
  31. package/dist/utils/fileOps.d.ts +29 -0
  32. package/dist/utils/fileOps.js +124 -0
  33. package/dist/utils/template.d.ts +12 -0
  34. package/dist/utils/template.js +31 -0
  35. package/package.json +44 -0
  36. package/src/commands/create.ts +141 -0
  37. package/src/commands/generate.ts +23 -0
  38. package/src/commands/update.ts +22 -0
  39. package/src/createApiTest/displayEnumLabel.ts +13 -0
  40. package/src/createApiTest/displayTypeLabel.ts +160 -0
  41. package/src/createApiTest/index.ts +10 -0
  42. package/src/createApiTest/pet.ts +159 -0
  43. package/src/createApiTest/store.ts +71 -0
  44. package/src/createApiTest/types.ts +134 -0
  45. package/src/createApiTest/user.ts +131 -0
  46. package/src/index.ts +54 -0
  47. package/src/utils/api.ts +47 -0
  48. package/src/utils/configGen.ts +139 -0
  49. package/src/utils/deps.ts +40 -0
  50. package/src/utils/fileOps.ts +86 -0
  51. package/src/utils/template.ts +32 -0
  52. package/templates/react/README.md +12 -0
  53. package/templates/react/eslint.config.js +33 -0
  54. package/templates/react/index.html +13 -0
  55. package/templates/react/package.json +27 -0
  56. package/templates/react/public/vite.svg +1 -0
  57. package/templates/react/src/App.css +42 -0
  58. package/templates/react/src/App.jsx +35 -0
  59. package/templates/react/src/assets/react.svg +1 -0
  60. package/templates/react/src/index.css +68 -0
  61. package/templates/react/src/main.jsx +10 -0
  62. package/templates/react/vite.config.js +7 -0
  63. package/templates/uniapp/index.html +20 -0
  64. package/templates/uniapp/package.json +67 -0
  65. package/templates/uniapp/shims-uni.d.ts +10 -0
  66. package/templates/uniapp/src/App.vue +17 -0
  67. package/templates/uniapp/src/main.js +10 -0
  68. package/templates/uniapp/src/manifest.json +72 -0
  69. package/templates/uniapp/src/pages/index/index.vue +48 -0
  70. package/templates/uniapp/src/pages.json +16 -0
  71. package/templates/uniapp/src/shime-uni.d.ts +6 -0
  72. package/templates/uniapp/src/static/logo.png +0 -0
  73. package/templates/uniapp/src/uni.scss +76 -0
  74. package/templates/uniapp/vite.config.js +8 -0
  75. package/templates/vue/.vscode/extensions.json +3 -0
  76. package/templates/vue/README.md +5 -0
  77. package/templates/vue/index.html +13 -0
  78. package/templates/vue/package.json +18 -0
  79. package/templates/vue/public/vite.svg +1 -0
  80. package/templates/vue/src/App.vue +30 -0
  81. package/templates/vue/src/assets/vue.svg +1 -0
  82. package/templates/vue/src/components/HelloWorld.vue +43 -0
  83. package/templates/vue/src/main.js +5 -0
  84. package/templates/vue/src/style.css +79 -0
  85. package/templates/vue/vite.config.js +7 -0
  86. package/tsconfig.json +19 -0
  87. package/vitest.config.ts +8 -0
package/src/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from 'commander';
4
+ import { generateApi } from './commands/generate';
5
+ import { updateDeps } from './commands/update';
6
+ import { createProject } from './commands/create';
7
+ import { join } from 'path';
8
+ import { readFileSync } from 'fs';
9
+
10
+ // 读取 package.json 中的版本号
11
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
12
+
13
+ program.name('wz').description('万桩项目脚手架工具').version(packageJson.version);
14
+
15
+ program
16
+ .command('create <name>')
17
+ .description('创建新项目')
18
+ .option('-t, --template <template>', '项目模板 (react、vue 或 uniapp)', 'react')
19
+ .option('-f, --force', '强制覆盖已存在的目录')
20
+ .action(async (name, options) => {
21
+ try {
22
+ await createProject(name, options);
23
+ } catch (error) {
24
+ console.error('创建项目失败:', error);
25
+ process.exit(1);
26
+ }
27
+ });
28
+
29
+ program
30
+ .command('api <url>')
31
+ .description('生成 API')
32
+ .option('-o, --output <dir>', '输出目录', './src/api')
33
+ .action(async (url, options) => {
34
+ try {
35
+ await generateApi(url, options);
36
+ } catch (error) {
37
+ console.error('生成 API 失败:', error);
38
+ process.exit(1);
39
+ }
40
+ });
41
+
42
+ program
43
+ .command('update')
44
+ .description('更新依赖')
45
+ .action(async () => {
46
+ try {
47
+ await updateDeps();
48
+ } catch (error) {
49
+ console.error('更新依赖失败:', error);
50
+ process.exit(1);
51
+ }
52
+ });
53
+
54
+ program.parse();
@@ -0,0 +1,47 @@
1
+ import { generateService } from 'openapi-ts-request';
2
+ import { ensureDir, writeFile, readFile } from 'fs-extra';
3
+ import { format } from 'prettier';
4
+ import { join, resolve } from 'path';
5
+
6
+ export async function generateApi(schemaPath: string, outputDir: string): Promise<void> {
7
+ try {
8
+ // 确保输出目录存在
9
+ const absoluteOutputDir = resolve(process.cwd(), outputDir);
10
+ await ensureDir(absoluteOutputDir);
11
+
12
+ // 生成 API 代码
13
+ await generateService({
14
+ schemaPath,
15
+ serversPath: absoluteOutputDir,
16
+ requestLibPath: './request',
17
+ isGenReactQuery: false,
18
+ isDisplayTypeLabel: true,
19
+ isGenJsonSchemas: false,
20
+ isCamelCase: true,
21
+ enableLogging: true,
22
+ });
23
+
24
+ // 格式化生成的文件
25
+ const files = ['api.ts', 'types.ts', 'request.ts'];
26
+ for (const file of files) {
27
+ const filePath = join(absoluteOutputDir, file);
28
+ try {
29
+ const content = await readFile(filePath, 'utf-8');
30
+ const formattedContent = await format(content, {
31
+ parser: 'typescript',
32
+ singleQuote: true,
33
+ trailingComma: 'all',
34
+ printWidth: 100,
35
+ });
36
+ await writeFile(filePath, formattedContent);
37
+ } catch (error) {
38
+ console.warn(`警告:无法格式化 ${file}:`, error);
39
+ }
40
+ }
41
+
42
+ console.log('API 生成成功');
43
+ } catch (error) {
44
+ console.error('生成 API 时出错:', error);
45
+ throw error;
46
+ }
47
+ }
@@ -0,0 +1,139 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ /**
5
+ * 生成 tsconfig.json,支持 react/vue/uniapp
6
+ * @param targetDir 目标目录
7
+ * @param type 模板类型
8
+ */
9
+ export function genTsConfig(targetDir: string, type: 'react' | 'vue' | 'uniapp') {
10
+ const tsconfigPath = path.join(targetDir, 'tsconfig.json');
11
+ if (fs.existsSync(tsconfigPath)) return;
12
+ let config: any = {
13
+ compilerOptions: {
14
+ target: 'ESNext',
15
+ useDefineForClassFields: true,
16
+ lib: ['DOM', 'DOM.Iterable', 'ESNext'],
17
+ allowJs: true,
18
+ skipLibCheck: true,
19
+ esModuleInterop: true,
20
+ allowSyntheticDefaultImports: true,
21
+ strict: true,
22
+ forceConsistentCasingInFileNames: true,
23
+ module: 'ESNext',
24
+ moduleResolution: 'Node',
25
+ resolveJsonModule: true,
26
+ isolatedModules: true,
27
+ noEmit: true,
28
+ },
29
+ include: ['src'],
30
+ references: []
31
+ };
32
+ if (type === 'react') config.compilerOptions.jsx = 'react-jsx';
33
+ if (type === 'vue' || type === 'uniapp') config.compilerOptions.jsx = 'preserve';
34
+ fs.writeFileSync(tsconfigPath, JSON.stringify(config, null, 2));
35
+ }
36
+
37
+ /**
38
+ * 生成 .eslintrc.json,自动适配类型和 features
39
+ * @param targetDir 目标目录
40
+ * @param type 模板类型
41
+ * @param features 功能选项
42
+ */
43
+ export function genEslintConfig(targetDir: string, type: string, features: string[]) {
44
+ const eslintrcPath = path.join(targetDir, '.eslintrc.json');
45
+ if (fs.existsSync(eslintrcPath)) return;
46
+ const useTS = features.includes('typescript');
47
+ const usePrettier = features.includes('prettier');
48
+ const baseConfig: any = {
49
+ env: { browser: true, es2021: true },
50
+ extends: [
51
+ 'eslint:recommended',
52
+ type === 'react' ? 'plugin:react/recommended' : null,
53
+ (type === 'vue' || type === 'uniapp') ? 'plugin:vue/vue3-recommended' : null,
54
+ useTS ? 'plugin:@typescript-eslint/recommended' : null,
55
+ usePrettier ? 'plugin:prettier/recommended' : null
56
+ ].filter(Boolean),
57
+ parser: useTS ? ((type === 'vue' || type === 'uniapp') ? 'vue-eslint-parser' : '@typescript-eslint/parser') : undefined,
58
+ parserOptions: {
59
+ ecmaVersion: 'latest',
60
+ sourceType: 'module',
61
+ ecmaFeatures: { jsx: type === 'react' }
62
+ },
63
+ plugins: [
64
+ type === 'react' ? 'react' : null,
65
+ type === 'react' ? 'react-hooks' : null,
66
+ (type === 'vue' || type === 'uniapp') ? 'vue' : null,
67
+ useTS ? '@typescript-eslint' : null
68
+ ].filter(Boolean),
69
+ rules: {
70
+ 'react/react-in-jsx-scope': 'off',
71
+ 'react/prop-types': 'off',
72
+ 'react-hooks/rules-of-hooks': 'error',
73
+ 'react-hooks/exhaustive-deps': 'warn',
74
+ 'vue/multi-word-component-names': 'off',
75
+ },
76
+ settings: type === 'react' ? { react: { version: 'detect' } } : undefined
77
+ };
78
+ fs.writeFileSync(eslintrcPath, JSON.stringify(baseConfig, null, 2));
79
+ }
80
+
81
+ /**
82
+ * 生成 .prettierrc 和 .prettierignore
83
+ * @param targetDir 目标目录
84
+ */
85
+ export function genPrettierConfig(targetDir: string) {
86
+ const prettierRcPath = path.join(targetDir, '.prettierrc');
87
+ if (!fs.existsSync(prettierRcPath)) {
88
+ fs.writeFileSync(prettierRcPath, JSON.stringify({
89
+ semi: false,
90
+ singleQuote: true,
91
+ trailingComma: 'all',
92
+ printWidth: 100
93
+ }, null, 2));
94
+ }
95
+ const prettierIgnorePath = path.join(targetDir, '.prettierignore');
96
+ if (!fs.existsSync(prettierIgnorePath)) {
97
+ fs.writeFileSync(prettierIgnorePath, 'node_modules\ndist\n');
98
+ }
99
+ }
100
+
101
+ /**
102
+ * 生成 uno.config.ts
103
+ * @param targetDir 目标目录
104
+ */
105
+ export function genUnoConfig(targetDir: string) {
106
+ const unoConfigPath = path.join(targetDir, 'uno.config.ts');
107
+ if (!fs.existsSync(unoConfigPath)) {
108
+ fs.writeFileSync(unoConfigPath, `import { defineConfig, presetUno } from 'unocss'
109
+
110
+ export default defineConfig({
111
+ presets: [presetUno()],
112
+ })
113
+ `);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * 生成 tailwind.config.js 和 postcss.config.js
119
+ * @param targetDir 目标目录
120
+ */
121
+ export function genTailwindConfig(targetDir: string) {
122
+ const tailwindConfigPath = path.join(targetDir, 'tailwind.config.js');
123
+ if (!fs.existsSync(tailwindConfigPath)) {
124
+ fs.writeFileSync(tailwindConfigPath, `module.exports = {
125
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue}'],
126
+ theme: { extend: {} },
127
+ plugins: [],
128
+ }`);
129
+ }
130
+ const postcssConfigPath = path.join(targetDir, 'postcss.config.js');
131
+ if (!fs.existsSync(postcssConfigPath)) {
132
+ fs.writeFileSync(postcssConfigPath, `module.exports = {
133
+ plugins: {
134
+ tailwindcss: {},
135
+ autoprefixer: {},
136
+ },
137
+ }`);
138
+ }
139
+ }
@@ -0,0 +1,40 @@
1
+ import { execSync } from 'child_process';
2
+
3
+ /**
4
+ * 根据模板类型和 features 组装 devDependencies
5
+ * @param type 模板类型(react/vue/uniapp)
6
+ * @param features 功能选项
7
+ * @returns 依赖包名数组
8
+ */
9
+ export function getDevDeps(type: string, features: string[]): string[] {
10
+ const featureMap: Record<string, string[]> = {
11
+ typescript: ['typescript', '@typescript-eslint/eslint-plugin', '@typescript-eslint/parser'],
12
+ prettier: ['prettier', 'eslint-config-prettier', 'eslint-plugin-prettier'],
13
+ eslint: ['eslint'],
14
+ unocss: ['unocss'],
15
+ tailwindcss: ['tailwindcss', 'postcss', 'autoprefixer'],
16
+ react: ['@types/react', '@types/react-dom', 'eslint-plugin-react', 'eslint-plugin-react-hooks', '@vitejs/plugin-react'],
17
+ vue: ['eslint-plugin-vue', '@vitejs/plugin-vue', 'vue-eslint-parser'],
18
+ uniapp: ['eslint-plugin-vue', 'vue-eslint-parser'],
19
+ };
20
+ let deps: string[] = [];
21
+ for (const f of features) {
22
+ if (featureMap[f]) deps = deps.concat(featureMap[f]);
23
+ }
24
+ // 保证类型相关依赖
25
+ if (type === 'react') deps = deps.concat(featureMap.react);
26
+ if (type === 'vue') deps = deps.concat(featureMap.vue);
27
+ if (type === 'uniapp') deps = deps.concat(featureMap.uniapp);
28
+ // 去重
29
+ return Array.from(new Set(deps));
30
+ }
31
+
32
+ /**
33
+ * 安装 devDependencies
34
+ * @param targetDir 目标目录
35
+ * @param deps 依赖包名数组
36
+ */
37
+ export function installDevDeps(targetDir: string, deps: string[]) {
38
+ if (!deps.length) return;
39
+ execSync(`pnpm add -D ${deps.join(' ')}`, { cwd: targetDir, stdio: 'inherit' });
40
+ }
@@ -0,0 +1,86 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ /**
5
+ * 递归将所有 fromExt 文件重命名为 toExt
6
+ * @param dir 目录路径
7
+ * @param fromExt 原始扩展名(如 .js)
8
+ * @param toExt 目标扩展名(如 .ts)
9
+ */
10
+ export function convertExtRecursive(dir: string, fromExt: string, toExt: string) {
11
+ const files = fs.readdirSync(dir);
12
+ for (const file of files) {
13
+ const fullPath = path.join(dir, file);
14
+ const stat = fs.statSync(fullPath);
15
+ if (stat.isDirectory()) {
16
+ convertExtRecursive(fullPath, fromExt, toExt);
17
+ } else if (file.endsWith(fromExt)) {
18
+ const newPath = fullPath.replace(new RegExp(fromExt + '$'), toExt);
19
+ fs.renameSync(fullPath, newPath);
20
+ }
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 递归替换 import 路径中的扩展名
26
+ * @param dir 目录路径
27
+ * @param fromExt 原始扩展名(如 .js)
28
+ * @param toExt 目标扩展名(如 .ts)
29
+ */
30
+ export function replaceImportExtRecursive(dir: string, fromExt: string, toExt: string) {
31
+ const files = fs.readdirSync(dir);
32
+ for (const file of files) {
33
+ const fullPath = path.join(dir, file);
34
+ const stat = fs.statSync(fullPath);
35
+ if (stat.isDirectory()) {
36
+ replaceImportExtRecursive(fullPath, fromExt, toExt);
37
+ } else if (file.endsWith(toExt)) {
38
+ let content = fs.readFileSync(fullPath, 'utf-8');
39
+ const reg = new RegExp(`(from ['\"].*?)${fromExt}(['\"])`, 'g');
40
+ content = content.replace(reg, `$1${toExt}$2`);
41
+ fs.writeFileSync(fullPath, content);
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ * 为单个 .vue 文件的 <script> 标签加 lang="ts"
48
+ * @param filePath .vue 文件路径
49
+ */
50
+ export function addLangTsToVueScript(filePath: string) {
51
+ let content = fs.readFileSync(filePath, 'utf-8');
52
+ content = content.replace(/<script(\s+lang=["']\w+["'])?/, '<script lang="ts"');
53
+ fs.writeFileSync(filePath, content);
54
+ }
55
+
56
+ /**
57
+ * 递归为所有 .vue 文件加 lang="ts"
58
+ * @param dir 目录路径
59
+ */
60
+ export function addLangTsToAllVue(dir: string) {
61
+ const files = fs.readdirSync(dir);
62
+ for (const file of files) {
63
+ const fullPath = path.join(dir, file);
64
+ const stat = fs.statSync(fullPath);
65
+ if (stat.isDirectory()) {
66
+ addLangTsToAllVue(fullPath);
67
+ } else if (file.endsWith('.vue')) {
68
+ addLangTsToVueScript(fullPath);
69
+ }
70
+ }
71
+ }
72
+
73
+ /**
74
+ * 将根目录 vite.config.js 转为 vite.config.ts
75
+ * @param targetDir 目标项目目录
76
+ */
77
+ export function convertViteConfigToTs(targetDir: string) {
78
+ const viteConfigJs = path.join(targetDir, 'vite.config.js');
79
+ const viteConfigTs = path.join(targetDir, 'vite.config.ts');
80
+ if (fs.existsSync(viteConfigJs)) {
81
+ let content = fs.readFileSync(viteConfigJs, 'utf-8');
82
+ // 可选:如需做内容适配,可在这里处理
83
+ fs.writeFileSync(viteConfigTs, content);
84
+ fs.unlinkSync(viteConfigJs);
85
+ }
86
+ }
@@ -0,0 +1,32 @@
1
+ import { join } from 'path';
2
+ import { readFileSync, writeFileSync } from 'fs';
3
+ import { copySync } from 'fs-extra';
4
+
5
+ /**
6
+ * 复制项目模板到目标目录
7
+ * @param template - 模板名称
8
+ * @param targetDir - 目标目录路径
9
+ */
10
+ export async function copyTemplate(template: string, targetDir: string) {
11
+ const templatePath = join(__dirname, '../../templates', template);
12
+ copySync(templatePath, targetDir);
13
+ }
14
+
15
+ /**
16
+ * 更新项目的 package.json 文件
17
+ * @param targetDir - 目标目录路径
18
+ * @param projectName - 项目名称
19
+ */
20
+ export async function updatePackageJson(targetDir: string, projectName: string) {
21
+ const packageJsonPath = join(targetDir, 'package.json');
22
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
23
+
24
+ // 更新项目基本信息
25
+ packageJson.name = projectName;
26
+ packageJson.version = '1.0.0';
27
+ packageJson.description = `${projectName} - 基于万桩UI组件库的项目`;
28
+
29
+ // 将更新后的内容写入文件
30
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
31
+ }
32
+
@@ -0,0 +1,12 @@
1
+ # React + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9
+
10
+ ## Expanding the ESLint configuration
11
+
12
+ If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
@@ -0,0 +1,33 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+
6
+ export default [
7
+ { ignores: ['dist'] },
8
+ {
9
+ files: ['**/*.{js,jsx}'],
10
+ languageOptions: {
11
+ ecmaVersion: 2020,
12
+ globals: globals.browser,
13
+ parserOptions: {
14
+ ecmaVersion: 'latest',
15
+ ecmaFeatures: { jsx: true },
16
+ sourceType: 'module',
17
+ },
18
+ },
19
+ plugins: {
20
+ 'react-hooks': reactHooks,
21
+ 'react-refresh': reactRefresh,
22
+ },
23
+ rules: {
24
+ ...js.configs.recommended.rules,
25
+ ...reactHooks.configs.recommended.rules,
26
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
27
+ 'react-refresh/only-export-components': [
28
+ 'warn',
29
+ { allowConstantExport: true },
30
+ ],
31
+ },
32
+ },
33
+ ]
@@ -0,0 +1,13 @@
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>Vite + React</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "react",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "react": "^19.1.0",
14
+ "react-dom": "^19.1.0"
15
+ },
16
+ "devDependencies": {
17
+ "@eslint/js": "^9.25.0",
18
+ "@types/react": "^19.1.2",
19
+ "@types/react-dom": "^19.1.2",
20
+ "@vitejs/plugin-react": "^4.4.1",
21
+ "eslint": "^9.25.0",
22
+ "eslint-plugin-react-hooks": "^5.2.0",
23
+ "eslint-plugin-react-refresh": "^0.4.19",
24
+ "globals": "^16.0.0",
25
+ "vite": "^6.3.5"
26
+ }
27
+ }
@@ -0,0 +1 @@
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>
@@ -0,0 +1,42 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
@@ -0,0 +1,35 @@
1
+ import { useState } from 'react'
2
+ import reactLogo from './assets/react.svg'
3
+ import viteLogo from '/vite.svg'
4
+ import './App.css'
5
+
6
+ function App() {
7
+ const [count, setCount] = useState(0)
8
+
9
+ return (
10
+ <>
11
+ <div>
12
+ <a href="https://vite.dev" target="_blank">
13
+ <img src={viteLogo} className="logo" alt="Vite logo" />
14
+ </a>
15
+ <a href="https://react.dev" target="_blank">
16
+ <img src={reactLogo} className="logo react" alt="React logo" />
17
+ </a>
18
+ </div>
19
+ <h1>Vite + React</h1>
20
+ <div className="card">
21
+ <button onClick={() => setCount((count) => count + 1)}>
22
+ count is {count}
23
+ </button>
24
+ <p>
25
+ Edit <code>src/App.jsx</code> and save to test HMR
26
+ </p>
27
+ </div>
28
+ <p className="read-the-docs">
29
+ Click on the Vite and React logos to learn more
30
+ </p>
31
+ </>
32
+ )
33
+ }
34
+
35
+ export default App
@@ -0,0 +1 @@
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>
@@ -0,0 +1,68 @@
1
+ :root {
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ a {
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
+ }
21
+ a:hover {
22
+ color: #535bf2;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ display: flex;
28
+ place-items: center;
29
+ min-width: 320px;
30
+ min-height: 100vh;
31
+ }
32
+
33
+ h1 {
34
+ font-size: 3.2em;
35
+ line-height: 1.1;
36
+ }
37
+
38
+ button {
39
+ border-radius: 8px;
40
+ border: 1px solid transparent;
41
+ padding: 0.6em 1.2em;
42
+ font-size: 1em;
43
+ font-weight: 500;
44
+ font-family: inherit;
45
+ background-color: #1a1a1a;
46
+ cursor: pointer;
47
+ transition: border-color 0.25s;
48
+ }
49
+ button:hover {
50
+ border-color: #646cff;
51
+ }
52
+ button:focus,
53
+ button:focus-visible {
54
+ outline: 4px auto -webkit-focus-ring-color;
55
+ }
56
+
57
+ @media (prefers-color-scheme: light) {
58
+ :root {
59
+ color: #213547;
60
+ background-color: #ffffff;
61
+ }
62
+ a:hover {
63
+ color: #747bff;
64
+ }
65
+ button {
66
+ background-color: #f9f9f9;
67
+ }
68
+ }
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.jsx'
5
+
6
+ createRoot(document.getElementById('root')).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })