cf-yoyo 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 (141) hide show
  1. package/.eslintrc.json +28 -0
  2. package/.github/workflows/ci.yml +96 -0
  3. package/.prettierrc.json +10 -0
  4. package/CHANGELOG.md +55 -0
  5. package/README.md +138 -0
  6. package/__tests__/cli-e2e.test.ts +145 -0
  7. package/__tests__/config.test.ts +268 -0
  8. package/__tests__/filesystem.test.ts +453 -0
  9. package/__tests__/logger.test.ts +274 -0
  10. package/__tests__/template-engine.test.ts +450 -0
  11. package/__tests__/types.test.ts +25 -0
  12. package/deep_todos.md +766 -0
  13. package/dist/cli/commands/create.d.ts +26 -0
  14. package/dist/cli/commands/create.d.ts.map +1 -0
  15. package/dist/cli/commands/create.js +308 -0
  16. package/dist/cli/commands/create.js.map +1 -0
  17. package/dist/cli/commands/git.d.ts +10 -0
  18. package/dist/cli/commands/git.d.ts.map +1 -0
  19. package/dist/cli/commands/git.js +887 -0
  20. package/dist/cli/commands/git.js.map +1 -0
  21. package/dist/cli/commands/list.d.ts +10 -0
  22. package/dist/cli/commands/list.d.ts.map +1 -0
  23. package/dist/cli/commands/list.js +90 -0
  24. package/dist/cli/commands/list.js.map +1 -0
  25. package/dist/cli/index.d.ts +15 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +62 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/core/config.d.ts +35 -0
  30. package/dist/core/config.d.ts.map +1 -0
  31. package/dist/core/config.js +260 -0
  32. package/dist/core/config.js.map +1 -0
  33. package/dist/core/filesystem.d.ts +84 -0
  34. package/dist/core/filesystem.d.ts.map +1 -0
  35. package/dist/core/filesystem.js +417 -0
  36. package/dist/core/filesystem.js.map +1 -0
  37. package/dist/core/git-token.d.ts +81 -0
  38. package/dist/core/git-token.d.ts.map +1 -0
  39. package/dist/core/git-token.js +244 -0
  40. package/dist/core/git-token.js.map +1 -0
  41. package/dist/core/git.d.ts +70 -0
  42. package/dist/core/git.d.ts.map +1 -0
  43. package/dist/core/git.js +367 -0
  44. package/dist/core/git.js.map +1 -0
  45. package/dist/core/prompt.d.ts +28 -0
  46. package/dist/core/prompt.d.ts.map +1 -0
  47. package/dist/core/prompt.js +253 -0
  48. package/dist/core/prompt.js.map +1 -0
  49. package/dist/core/template-engine.d.ts +52 -0
  50. package/dist/core/template-engine.d.ts.map +1 -0
  51. package/dist/core/template-engine.js +308 -0
  52. package/dist/core/template-engine.js.map +1 -0
  53. package/dist/core/template-manager.d.ts +54 -0
  54. package/dist/core/template-manager.d.ts.map +1 -0
  55. package/dist/core/template-manager.js +330 -0
  56. package/dist/core/template-manager.js.map +1 -0
  57. package/dist/index.d.ts +12 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +19 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/types/index.d.ts +244 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/types/index.js +51 -0
  64. package/dist/types/index.js.map +1 -0
  65. package/dist/utils/logger.d.ts +68 -0
  66. package/dist/utils/logger.d.ts.map +1 -0
  67. package/dist/utils/logger.js +140 -0
  68. package/dist/utils/logger.js.map +1 -0
  69. package/memory.md +241 -0
  70. package/need-debug.md +395 -0
  71. package/package.json +42 -0
  72. package/src/cli/commands/create.ts +326 -0
  73. package/src/cli/commands/git.ts +1001 -0
  74. package/src/cli/commands/list.ts +97 -0
  75. package/src/cli/index.ts +71 -0
  76. package/src/core/config.ts +262 -0
  77. package/src/core/filesystem.ts +408 -0
  78. package/src/core/git-token.ts +248 -0
  79. package/src/core/git.ts +384 -0
  80. package/src/core/prompt.ts +345 -0
  81. package/src/core/template-engine.ts +324 -0
  82. package/src/core/template-manager.ts +338 -0
  83. package/src/index.ts +19 -0
  84. package/src/types/index.ts +259 -0
  85. package/src/utils/logger.ts +150 -0
  86. package/templates/pages/basic/README.md.mustache +63 -0
  87. package/templates/pages/basic/package.json.mustache +23 -0
  88. package/templates/pages/basic/public/css/style.css +199 -0
  89. package/templates/pages/basic/public/index.html.mustache +72 -0
  90. package/templates/pages/basic/public/js/main.js +103 -0
  91. package/templates/pages/basic/template.json +38 -0
  92. package/templates/pages/basic/tsconfig.json +21 -0
  93. package/templates/pages/basic/wrangler.toml.mustache +14 -0
  94. package/templates/pages/basic-js/README.md.mustache +62 -0
  95. package/templates/pages/basic-js/package.json.mustache +25 -0
  96. package/templates/pages/basic-js/public/css/style.css +212 -0
  97. package/templates/pages/basic-js/public/index.html.mustache +53 -0
  98. package/templates/pages/basic-js/public/js/main.js +134 -0
  99. package/templates/pages/basic-js/template.json +35 -0
  100. package/templates/pages/basic-js/wrangler.toml.mustache +14 -0
  101. package/templates/pages/react/README.md.mustache +97 -0
  102. package/templates/pages/react/index.html.mustache +14 -0
  103. package/templates/pages/react/package.json.mustache +34 -0
  104. package/templates/pages/react/src/App.css +168 -0
  105. package/templates/pages/react/src/App.tsx.mustache +62 -0
  106. package/templates/pages/react/src/index.css +53 -0
  107. package/templates/pages/react/src/main.tsx.mustache +10 -0
  108. package/templates/pages/react/src/vite-env.d.ts +1 -0
  109. package/templates/pages/react/template.json +54 -0
  110. package/templates/pages/react/tsconfig.json +21 -0
  111. package/templates/pages/react/tsconfig.node.json +10 -0
  112. package/templates/pages/react/vite.config.ts +16 -0
  113. package/templates/worker/basic/README.md.mustache +56 -0
  114. package/templates/worker/basic/package.json.mustache +29 -0
  115. package/templates/worker/basic/src/index.ts.mustache +125 -0
  116. package/templates/worker/basic/template.json +30 -0
  117. package/templates/worker/basic/tsconfig.json +24 -0
  118. package/templates/worker/basic/wrangler.toml.mustache +33 -0
  119. package/templates/worker/basic-js/README.md.mustache +55 -0
  120. package/templates/worker/basic-js/package.json.mustache +25 -0
  121. package/templates/worker/basic-js/src/index.js.mustache +146 -0
  122. package/templates/worker/basic-js/template.json +27 -0
  123. package/templates/worker/basic-js/wrangler.toml.mustache +33 -0
  124. package/templates/worker/hono/README.md.mustache +79 -0
  125. package/templates/worker/hono/package.json.mustache +33 -0
  126. package/templates/worker/hono/src/index.ts.mustache +64 -0
  127. package/templates/worker/hono/src/routes/index.ts.mustache +165 -0
  128. package/templates/worker/hono/template.json +34 -0
  129. package/templates/worker/hono/tsconfig.json +24 -0
  130. package/templates/worker/hono/wrangler.toml.mustache +36 -0
  131. package/templates/worker/hono-js/README.md.mustache +67 -0
  132. package/templates/worker/hono-js/package.json.mustache +29 -0
  133. package/templates/worker/hono-js/src/index.js.mustache +55 -0
  134. package/templates/worker/hono-js/src/routes/index.js.mustache +127 -0
  135. package/templates/worker/hono-js/template.json +31 -0
  136. package/templates/worker/hono-js/wrangler.toml.mustache +36 -0
  137. package/thoughts/ledgers/CONTINUITY_ses_287e.md +74 -0
  138. package/thoughts/ledgers/CONTINUITY_ses_28b5.md +85 -0
  139. package/tsconfig.json +30 -0
  140. package/vitest.config.ts +20 -0
  141. package//351/240/205/347/233/256/350/241/250.md +140 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * 主要 JavaScript 檔案
3
+ * Cloudflare Pages 靜態網站
4
+ */
5
+
6
+ // 等待 DOM 加載完成
7
+ document.addEventListener('DOMContentLoaded', () => {
8
+ initTimestamp();
9
+ initButton();
10
+ });
11
+
12
+ /**
13
+ * 初始化時間戳顯示
14
+ */
15
+ function initTimestamp() {
16
+ const timestampElement = document.getElementById('timestamp');
17
+ if (timestampElement) {
18
+ updateTimestamp(timestampElement);
19
+ // 每秒更新時間
20
+ setInterval(() => updateTimestamp(timestampElement), 1000);
21
+ }
22
+ }
23
+
24
+ /**
25
+ * 更新時間戳
26
+ * @param {HTMLElement} element - 時間戳元素
27
+ */
28
+ function updateTimestamp(element) {
29
+ const now = new Date();
30
+ const options = {
31
+ year: 'numeric',
32
+ month: '2-digit',
33
+ day: '2-digit',
34
+ hour: '2-digit',
35
+ minute: '2-digit',
36
+ second: '2-digit',
37
+ hour12: false,
38
+ };
39
+ element.textContent = now.toLocaleString('zh-TW', options);
40
+ }
41
+
42
+ /**
43
+ * 初始化按鈕事件
44
+ */
45
+ function initButton() {
46
+ const clickBtn = document.getElementById('clickBtn');
47
+ const messageElement = document.getElementById('message');
48
+
49
+ if (clickBtn && messageElement) {
50
+ let clickCount = 0;
51
+ const messages = [
52
+ '你好!這是你的第一個 Cloudflare Pages 網站 🎉',
53
+ '繼續點擊!你會發現更多驚喜 ✨',
54
+ '太棒了!你已經點擊 3 次了 🚀',
55
+ '還在點?你真的很喜歡這個按鈕呢 😄',
56
+ '哇!你已經成為點擊大師了 🏆',
57
+ '好吧,這是最後一條訊息了,謝謝你的支持!🙏',
58
+ ];
59
+
60
+ clickBtn.addEventListener('click', () => {
61
+ clickCount++;
62
+
63
+ // 根據點擊次數顯示不同訊息
64
+ const messageIndex = Math.min(clickCount - 1, messages.length - 1);
65
+ messageElement.textContent = `${messages[messageIndex]} (點擊次數: ${clickCount})`;
66
+
67
+ // 添加動畫效果
68
+ messageElement.style.animation = 'none';
69
+ messageElement.offsetHeight; // 觸發重繪
70
+ messageElement.style.animation = 'fadeIn 0.3s ease';
71
+
72
+ // 按鈕動畫
73
+ clickBtn.style.transform = 'scale(0.95)';
74
+ setTimeout(() => {
75
+ clickBtn.style.transform = 'scale(1)';
76
+ }, 100);
77
+
78
+ console.log(`Button clicked ${clickCount} times`);
79
+ });
80
+ }
81
+ }
82
+
83
+ /**
84
+ * 工具函數:格式化日期
85
+ * @param {Date} date - 日期對象
86
+ * @returns {string} 格式化後的日期字串
87
+ */
88
+ export function formatDate(date) {
89
+ return new Intl.DateTimeFormat('zh-TW', {
90
+ year: 'numeric',
91
+ month: 'long',
92
+ day: 'numeric',
93
+ }).format(date);
94
+ }
95
+
96
+ /**
97
+ * 工具函數:防抖
98
+ * @param {Function} func - 要防抖的函數
99
+ * @param {number} wait - 等待時間(毫秒)
100
+ * @returns {Function} 防抖後的函數
101
+ */
102
+ export function debounce(func, wait) {
103
+ let timeout;
104
+ return function executedFunction(...args) {
105
+ const later = () => {
106
+ clearTimeout(timeout);
107
+ func(...args);
108
+ };
109
+ clearTimeout(timeout);
110
+ timeout = setTimeout(later, wait);
111
+ };
112
+ }
113
+
114
+ /**
115
+ * 工具函數:節流
116
+ * @param {Function} func - 要節流的函數
117
+ * @param {number} limit - 限制時間(毫秒)
118
+ * @returns {Function} 節流後的函數
119
+ */
120
+ export function throttle(func, limit) {
121
+ let inThrottle;
122
+ return function executedFunction(...args) {
123
+ if (!inThrottle) {
124
+ func(...args);
125
+ inThrottle = true;
126
+ setTimeout(() => (inThrottle = false), limit);
127
+ }
128
+ };
129
+ }
130
+
131
+ // 導出主要功能(支援 ES Module)
132
+ export { initTimestamp, initButton };
133
+
134
+ console.log('🚀 Cloudflare Pages site loaded!');
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "基礎 Cloudflare Pages (JavaScript)",
3
+ "description": "純靜態 HTML/CSS/JS 的 Cloudflare Pages 專案,使用 JavaScript",
4
+ "projectType": "pages",
5
+ "templateType": "static",
6
+ "language": "javascript",
7
+ "files": [
8
+ {
9
+ "sourcePath": "package.json.mustache",
10
+ "targetPath": "package.json"
11
+ },
12
+ {
13
+ "sourcePath": "wrangler.toml.mustache",
14
+ "targetPath": "wrangler.toml"
15
+ },
16
+ {
17
+ "sourcePath": "public/index.html.mustache",
18
+ "targetPath": "public/index.html"
19
+ },
20
+ {
21
+ "sourcePath": "public/css/style.css",
22
+ "targetPath": "public/css/style.css"
23
+ },
24
+ {
25
+ "sourcePath": "public/js/main.js",
26
+ "targetPath": "public/js/main.js"
27
+ },
28
+ {
29
+ "sourcePath": "README.md.mustache",
30
+ "targetPath": "README.md"
31
+ }
32
+ ],
33
+ "requiredVars": ["projectName", "projectType", "template"],
34
+ "optionalVars": ["author", "email", "description", "license"]
35
+ }
@@ -0,0 +1,14 @@
1
+ #:schema node_modules/wrangler/config-schema.json
2
+ name = "{{projectName}}"
3
+
4
+ # Cloudflare Pages 配置
5
+ [build]
6
+ command = ""
7
+
8
+ [site]
9
+ bucket = "./public"
10
+
11
+ # 環境變數
12
+ [env.production]
13
+
14
+ [env.development]
@@ -0,0 +1,97 @@
1
+ # {{projectName}}
2
+
3
+ {{description}}
4
+
5
+ 這是一個基於 React + Vite + TypeScript 的 Cloudflare Pages 專案,使用 create-cf-project 腳手架工具建立。
6
+
7
+ ## 🚀 快速開始
8
+
9
+ ### 安裝依賴
10
+
11
+ \`\`\`bash
12
+ npm install
13
+ \`\`\`
14
+
15
+ ### 開發模式
16
+
17
+ \`\`\`bash
18
+ npm run dev
19
+ \`\`\`
20
+
21
+ 這會啟動 Vite 開發伺服器,你可以在 http://localhost:3000 預覽網站。
22
+
23
+ ### 建置
24
+
25
+ \`\`\`bash
26
+ npm run build
27
+ \`\`\`
28
+
29
+ ### 預覽生產版本
30
+
31
+ \`\`\`bash
32
+ npm run preview
33
+ \`\`\`
34
+
35
+ ### 部署
36
+
37
+ \`\`\`bash
38
+ npm run deploy
39
+ \`\`\`
40
+
41
+ ## 📁 專案結構
42
+
43
+ \`\`\`
44
+ {{projectName}}/
45
+ ├── src/ # 原始碼目錄
46
+ │ ├── App.tsx # 主應用組件
47
+ │ ├── App.css # 應用樣式
48
+ │ ├── main.tsx # 入口檔案
49
+ │ ├── index.css # 全局樣式
50
+ │ └── vite-env.d.ts # Vite 類型定義
51
+ ├── dist/ # 建置輸出(由 Vite 生成)
52
+ ├── index.html # HTML 入口
53
+ ├── vite.config.ts # Vite 配置
54
+ ├── tsconfig.json # TypeScript 配置
55
+ ├── tsconfig.node.json # Node 類型配置
56
+ ├── package.json # 專案配置
57
+ └── README.md # 本文件
58
+ \`\`\`
59
+
60
+ ## 🛠️ 技術棧
61
+
62
+ - **框架**: React 18
63
+ - **語言**: TypeScript
64
+ - **構建工具**: Vite
65
+ - **部署平台**: Cloudflare Pages
66
+ - **包管理器**: npm
67
+
68
+ ## 📚 可用腳本
69
+
70
+ | 腳本 | 描述 |
71
+ |------|------|
72
+ | `npm run dev` | 啟動開發伺服器 |
73
+ | `npm run build` | 建置生產版本 |
74
+ | `npm run preview` | 預覽生產版本 |
75
+ | `npm run deploy` | 部署到 Cloudflare Pages |
76
+ | `npm run lint` | 執行 ESLint |
77
+ | `npm run type-check` | 執行 TypeScript 類型檢查 |
78
+
79
+ ## 🎨 自定義
80
+
81
+ 你可以隨意修改 `src/` 目錄下的檔案來自定義你的應用:
82
+
83
+ - 編輯 `src/App.tsx` 修改主頁內容
84
+ - 編輯 `src/App.css` 修改樣式
85
+ - 添加新組件到 `src/components/`
86
+
87
+ ## 📖 相關資源
88
+
89
+ - [React 文檔](https://react.dev)
90
+ - [Vite 文檔](https://vitejs.dev)
91
+ - [Cloudflare Pages 文檔](https://developers.cloudflare.com/pages/)
92
+
93
+ ## 📝 授權
94
+
95
+ {{#license}}{{license}}{{/license}}{{^license}}MIT{{/license}}
96
+
97
+ 建立於 {{date}} | {{year}}
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="zh-TW">
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
+ <meta name="description" content="{{description}}">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ <script type="module" src="/src/main.tsx"></script>
13
+ </body>
14
+ </html>
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "1.0.0",
5
+ "type": "module",
6
+ "description": "{{description}}",
7
+ "scripts": {
8
+ "dev": "vite",
9
+ "build": "tsc && vite build",
10
+ "preview": "wrangler pages dev dist",
11
+ "deploy": "wrangler pages deploy dist",
12
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
13
+ "type-check": "tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "react": "^18.2.0",
17
+ "react-dom": "^18.2.0"
18
+ },
19
+ "devDependencies": {
20
+ "@types/react": "^18.2.55",
21
+ "@types/react-dom": "^18.2.19",
22
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
23
+ "@typescript-eslint/parser": "^7.0.0",
24
+ "@vitejs/plugin-react": "^4.2.1",
25
+ "eslint": "^8.57.0",
26
+ "eslint-plugin-react-hooks": "^4.6.0",
27
+ "eslint-plugin-react-refresh": "^0.4.5",
28
+ "typescript": "^5.3.0",
29
+ "vite": "^5.1.0",
30
+ "wrangler": "^3.39.0"
31
+ },
32
+ "author": "{{#author}}{{author}}{{/author}}{{^author}}Anonymous{{/author}}",
33
+ "license": "{{#license}}{{license}}{{/license}}{{^license}}MIT{{/license}}"
34
+ }
@@ -0,0 +1,168 @@
1
+ /* 主應用樣式 */
2
+ .app {
3
+ min-height: 100vh;
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+
8
+ .hero {
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ color: white;
11
+ padding: 6rem 2rem;
12
+ text-align: center;
13
+ }
14
+
15
+ .hero h1 {
16
+ font-size: 3.5rem;
17
+ font-weight: 700;
18
+ margin-bottom: 1rem;
19
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
20
+ }
21
+
22
+ .description {
23
+ font-size: 1.25rem;
24
+ opacity: 0.9;
25
+ max-width: 600px;
26
+ margin: 0 auto 2rem;
27
+ line-height: 1.7;
28
+ }
29
+
30
+ .badges {
31
+ display: flex;
32
+ gap: 1rem;
33
+ justify-content: center;
34
+ flex-wrap: wrap;
35
+ }
36
+
37
+ .badge {
38
+ background: rgba(255, 255, 255, 0.2);
39
+ backdrop-filter: blur(10px);
40
+ padding: 0.5rem 1rem;
41
+ border-radius: 20px;
42
+ font-size: 0.875rem;
43
+ font-weight: 500;
44
+ }
45
+
46
+ .card {
47
+ background: #f8f9fa;
48
+ padding: 3rem;
49
+ text-align: center;
50
+ border-bottom: 1px solid #e9ecef;
51
+ }
52
+
53
+ .card button {
54
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
55
+ color: white;
56
+ border: none;
57
+ padding: 1rem 2rem;
58
+ font-size: 1.1rem;
59
+ border-radius: 8px;
60
+ cursor: pointer;
61
+ transition:
62
+ transform 0.2s,
63
+ box-shadow 0.2s;
64
+ font-weight: 600;
65
+ }
66
+
67
+ .card button:hover {
68
+ transform: translateY(-2px);
69
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
70
+ }
71
+
72
+ .card p {
73
+ margin-top: 1.5rem;
74
+ color: #666;
75
+ }
76
+
77
+ .card code {
78
+ background: #e9ecef;
79
+ padding: 0.2rem 0.4rem;
80
+ border-radius: 4px;
81
+ font-family: 'Fira Code', monospace;
82
+ }
83
+
84
+ .features {
85
+ padding: 4rem 2rem;
86
+ flex: 1;
87
+ background: white;
88
+ }
89
+
90
+ .features h2 {
91
+ text-align: center;
92
+ font-size: 2rem;
93
+ margin-bottom: 3rem;
94
+ color: #333;
95
+ }
96
+
97
+ .feature-grid {
98
+ display: grid;
99
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
100
+ gap: 2rem;
101
+ max-width: 1200px;
102
+ margin: 0 auto;
103
+ }
104
+
105
+ .feature-card {
106
+ background: #f8f9fa;
107
+ padding: 2rem;
108
+ border-radius: 12px;
109
+ text-align: center;
110
+ transition:
111
+ transform 0.3s,
112
+ box-shadow 0.3s;
113
+ }
114
+
115
+ .feature-card:hover {
116
+ transform: translateY(-5px);
117
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
118
+ }
119
+
120
+ .feature-icon {
121
+ font-size: 2.5rem;
122
+ margin-bottom: 1rem;
123
+ }
124
+
125
+ .feature-card h3 {
126
+ font-size: 1.25rem;
127
+ margin-bottom: 0.5rem;
128
+ color: #333;
129
+ }
130
+
131
+ .feature-card p {
132
+ color: #666;
133
+ line-height: 1.6;
134
+ }
135
+
136
+ footer {
137
+ background: #333;
138
+ color: white;
139
+ padding: 2rem;
140
+ text-align: center;
141
+ }
142
+
143
+ footer p {
144
+ opacity: 0.8;
145
+ margin: 0.5rem 0;
146
+ }
147
+
148
+ @media (max-width: 768px) {
149
+ .hero {
150
+ padding: 4rem 1.5rem;
151
+ }
152
+
153
+ .hero h1 {
154
+ font-size: 2.5rem;
155
+ }
156
+
157
+ .description {
158
+ font-size: 1rem;
159
+ }
160
+
161
+ .card {
162
+ padding: 2rem 1.5rem;
163
+ }
164
+
165
+ .features {
166
+ padding: 3rem 1.5rem;
167
+ }
168
+ }
@@ -0,0 +1,62 @@
1
+ import { useState } from 'react';
2
+ import './App.css';
3
+
4
+ function App() {
5
+ const [count, setCount] = useState(0);
6
+
7
+ return (
8
+ <div className="app">
9
+ <div className="hero">
10
+ <h1>⚡ {{projectName}}</h1>
11
+ <p className="description">{{description}}</p>
12
+ <div className="badges">
13
+ <span className="badge">React</span>
14
+ <span className="badge">Vite</span>
15
+ <span className="badge">Cloudflare Pages</span>
16
+ </div>
17
+ </div>
18
+
19
+ <div className="card">
20
+ <button onClick={() => setCount((count) => count + 1)}>
21
+ count is {count}
22
+ </button>
23
+ <p>
24
+ Edit <code>src/App.tsx</code> and save to test HMR
25
+ </p>
26
+ </div>
27
+
28
+ <div className="features">
29
+ <h2>✨ 技術棧</h2>
30
+ <div className="feature-grid">
31
+ <div className="feature-card">
32
+ <div className="feature-icon">⚛️</div>
33
+ <h3>React 18</h3>
34
+ <p>最新版本的 React,包含 Concurrent Features</p>
35
+ </div>
36
+ <div className="feature-card">
37
+ <div className="feature-icon">🔥</div>
38
+ <h3>Vite</h3>
39
+ <p>下一代前端工具鏈,極速的開發體驗</p>
40
+ </div>
41
+ <div className="feature-card">
42
+ <div className="feature-icon">📘</div>
43
+ <h3>TypeScript</h3>
44
+ <p>靜態類型檢查,提升代碼質量</p>
45
+ </div>
46
+ <div className="feature-card">
47
+ <div className="feature-icon">🚀</div>
48
+ <h3>Cloudflare Pages</h3>
49
+ <p>全球邊緣部署,極速載入</p>
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ <footer>
55
+ <p>建立於 {{date}} | {{year}}</p>
56
+ <p>使用 create-cf-project 生成</p>
57
+ </footer>
58
+ </div>
59
+ );
60
+ }
61
+
62
+ export default App;
@@ -0,0 +1,53 @@
1
+ /* 全局樣式 */
2
+ :root {
3
+ font-family:
4
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
5
+ line-height: 1.5;
6
+ font-weight: 400;
7
+ color-scheme: light dark;
8
+ font-synthesis: none;
9
+ text-rendering: optimizeLegibility;
10
+ -webkit-font-smoothing: antialiased;
11
+ -moz-osx-font-smoothing: grayscale;
12
+ }
13
+
14
+ * {
15
+ margin: 0;
16
+ padding: 0;
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ body {
21
+ margin: 0;
22
+ display: flex;
23
+ place-items: center;
24
+ min-width: 320px;
25
+ min-height: 100vh;
26
+ }
27
+
28
+ #root {
29
+ width: 100%;
30
+ }
31
+
32
+ /* 滾動條樣式 */
33
+ ::-webkit-scrollbar {
34
+ width: 8px;
35
+ }
36
+
37
+ ::-webkit-scrollbar-track {
38
+ background: #f1f1f1;
39
+ }
40
+
41
+ ::-webkit-scrollbar-thumb {
42
+ background: #888;
43
+ border-radius: 4px;
44
+ }
45
+
46
+ ::-webkit-scrollbar-thumb:hover {
47
+ background: #555;
48
+ }
49
+
50
+ /* 選中文字樣式 */
51
+ ::selection {
52
+ background: rgba(102, 126, 234, 0.3);
53
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App.tsx';
4
+ import './index.css';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>
10
+ );
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "React Cloudflare Pages",
3
+ "description": "使用 React 框架的 Cloudflare Pages 專案,支援現代前端開發",
4
+ "projectType": "pages",
5
+ "templateType": "react",
6
+ "files": [
7
+ {
8
+ "sourcePath": "package.json.mustache",
9
+ "targetPath": "package.json"
10
+ },
11
+ {
12
+ "sourcePath": "vite.config.ts",
13
+ "targetPath": "vite.config.ts"
14
+ },
15
+ {
16
+ "sourcePath": "index.html.mustache",
17
+ "targetPath": "index.html"
18
+ },
19
+ {
20
+ "sourcePath": "src/main.tsx.mustache",
21
+ "targetPath": "src/main.tsx"
22
+ },
23
+ {
24
+ "sourcePath": "src/App.tsx.mustache",
25
+ "targetPath": "src/App.tsx"
26
+ },
27
+ {
28
+ "sourcePath": "src/App.css",
29
+ "targetPath": "src/App.css"
30
+ },
31
+ {
32
+ "sourcePath": "src/index.css",
33
+ "targetPath": "src/index.css"
34
+ },
35
+ {
36
+ "sourcePath": "src/vite-env.d.ts",
37
+ "targetPath": "src/vite-env.d.ts"
38
+ },
39
+ {
40
+ "sourcePath": "tsconfig.json",
41
+ "targetPath": "tsconfig.json"
42
+ },
43
+ {
44
+ "sourcePath": "tsconfig.node.json",
45
+ "targetPath": "tsconfig.node.json"
46
+ },
47
+ {
48
+ "sourcePath": "README.md.mustache",
49
+ "targetPath": "README.md"
50
+ }
51
+ ],
52
+ "requiredVars": ["projectName", "projectType", "template"],
53
+ "optionalVars": ["author", "email", "description", "license"]
54
+ }