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.
- package/.eslintrc.json +28 -0
- package/.github/workflows/ci.yml +96 -0
- package/.prettierrc.json +10 -0
- package/CHANGELOG.md +55 -0
- package/README.md +138 -0
- package/__tests__/cli-e2e.test.ts +145 -0
- package/__tests__/config.test.ts +268 -0
- package/__tests__/filesystem.test.ts +453 -0
- package/__tests__/logger.test.ts +274 -0
- package/__tests__/template-engine.test.ts +450 -0
- package/__tests__/types.test.ts +25 -0
- package/deep_todos.md +766 -0
- package/dist/cli/commands/create.d.ts +26 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +308 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/git.d.ts +10 -0
- package/dist/cli/commands/git.d.ts.map +1 -0
- package/dist/cli/commands/git.js +887 -0
- package/dist/cli/commands/git.js.map +1 -0
- package/dist/cli/commands/list.d.ts +10 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +90 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/index.d.ts +15 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +62 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/config.d.ts +35 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +260 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/filesystem.d.ts +84 -0
- package/dist/core/filesystem.d.ts.map +1 -0
- package/dist/core/filesystem.js +417 -0
- package/dist/core/filesystem.js.map +1 -0
- package/dist/core/git-token.d.ts +81 -0
- package/dist/core/git-token.d.ts.map +1 -0
- package/dist/core/git-token.js +244 -0
- package/dist/core/git-token.js.map +1 -0
- package/dist/core/git.d.ts +70 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +367 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/prompt.d.ts +28 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +253 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/template-engine.d.ts +52 -0
- package/dist/core/template-engine.d.ts.map +1 -0
- package/dist/core/template-engine.js +308 -0
- package/dist/core/template-engine.js.map +1 -0
- package/dist/core/template-manager.d.ts +54 -0
- package/dist/core/template-manager.d.ts.map +1 -0
- package/dist/core/template-manager.js +330 -0
- package/dist/core/template-manager.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +244 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +51 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +68 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +140 -0
- package/dist/utils/logger.js.map +1 -0
- package/memory.md +241 -0
- package/need-debug.md +395 -0
- package/package.json +42 -0
- package/src/cli/commands/create.ts +326 -0
- package/src/cli/commands/git.ts +1001 -0
- package/src/cli/commands/list.ts +97 -0
- package/src/cli/index.ts +71 -0
- package/src/core/config.ts +262 -0
- package/src/core/filesystem.ts +408 -0
- package/src/core/git-token.ts +248 -0
- package/src/core/git.ts +384 -0
- package/src/core/prompt.ts +345 -0
- package/src/core/template-engine.ts +324 -0
- package/src/core/template-manager.ts +338 -0
- package/src/index.ts +19 -0
- package/src/types/index.ts +259 -0
- package/src/utils/logger.ts +150 -0
- package/templates/pages/basic/README.md.mustache +63 -0
- package/templates/pages/basic/package.json.mustache +23 -0
- package/templates/pages/basic/public/css/style.css +199 -0
- package/templates/pages/basic/public/index.html.mustache +72 -0
- package/templates/pages/basic/public/js/main.js +103 -0
- package/templates/pages/basic/template.json +38 -0
- package/templates/pages/basic/tsconfig.json +21 -0
- package/templates/pages/basic/wrangler.toml.mustache +14 -0
- package/templates/pages/basic-js/README.md.mustache +62 -0
- package/templates/pages/basic-js/package.json.mustache +25 -0
- package/templates/pages/basic-js/public/css/style.css +212 -0
- package/templates/pages/basic-js/public/index.html.mustache +53 -0
- package/templates/pages/basic-js/public/js/main.js +134 -0
- package/templates/pages/basic-js/template.json +35 -0
- package/templates/pages/basic-js/wrangler.toml.mustache +14 -0
- package/templates/pages/react/README.md.mustache +97 -0
- package/templates/pages/react/index.html.mustache +14 -0
- package/templates/pages/react/package.json.mustache +34 -0
- package/templates/pages/react/src/App.css +168 -0
- package/templates/pages/react/src/App.tsx.mustache +62 -0
- package/templates/pages/react/src/index.css +53 -0
- package/templates/pages/react/src/main.tsx.mustache +10 -0
- package/templates/pages/react/src/vite-env.d.ts +1 -0
- package/templates/pages/react/template.json +54 -0
- package/templates/pages/react/tsconfig.json +21 -0
- package/templates/pages/react/tsconfig.node.json +10 -0
- package/templates/pages/react/vite.config.ts +16 -0
- package/templates/worker/basic/README.md.mustache +56 -0
- package/templates/worker/basic/package.json.mustache +29 -0
- package/templates/worker/basic/src/index.ts.mustache +125 -0
- package/templates/worker/basic/template.json +30 -0
- package/templates/worker/basic/tsconfig.json +24 -0
- package/templates/worker/basic/wrangler.toml.mustache +33 -0
- package/templates/worker/basic-js/README.md.mustache +55 -0
- package/templates/worker/basic-js/package.json.mustache +25 -0
- package/templates/worker/basic-js/src/index.js.mustache +146 -0
- package/templates/worker/basic-js/template.json +27 -0
- package/templates/worker/basic-js/wrangler.toml.mustache +33 -0
- package/templates/worker/hono/README.md.mustache +79 -0
- package/templates/worker/hono/package.json.mustache +33 -0
- package/templates/worker/hono/src/index.ts.mustache +64 -0
- package/templates/worker/hono/src/routes/index.ts.mustache +165 -0
- package/templates/worker/hono/template.json +34 -0
- package/templates/worker/hono/tsconfig.json +24 -0
- package/templates/worker/hono/wrangler.toml.mustache +36 -0
- package/templates/worker/hono-js/README.md.mustache +67 -0
- package/templates/worker/hono-js/package.json.mustache +29 -0
- package/templates/worker/hono-js/src/index.js.mustache +55 -0
- package/templates/worker/hono-js/src/routes/index.js.mustache +127 -0
- package/templates/worker/hono-js/template.json +31 -0
- package/templates/worker/hono-js/wrangler.toml.mustache +36 -0
- package/thoughts/ledgers/CONTINUITY_ses_287e.md +74 -0
- package/thoughts/ledgers/CONTINUITY_ses_28b5.md +85 -0
- package/tsconfig.json +30 -0
- package/vitest.config.ts +20 -0
- 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,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 @@
|
|
|
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
|
+
}
|