create-csch5-monorepo 1.0.2 → 1.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-csch5-monorepo",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Create a mobile H5 monorepo project with Vue 3 + Vite + Turborepo",
5
5
  "type": "module",
6
6
  "bin": "./bin/index.js",
@@ -1,7 +1,130 @@
1
1
  <template>
2
2
  <div class="about">
3
- <h1>关于页面</h1>
4
- <button @click="router.back()">返回</button>
3
+ <!-- 背景动画 -->
4
+ <div class="bg-gradient"></div>
5
+
6
+ <!-- 导航栏 -->
7
+ <div class="navbar glass">
8
+ <button class="back-btn" @click="router.back()">
9
+ <span class="arrow">←</span>
10
+ <span>返回</span>
11
+ </button>
12
+ <h2 class="nav-title">使用方法</h2>
13
+ <div class="placeholder"></div>
14
+ </div>
15
+
16
+ <div class="content">
17
+ <!-- 目录结构 -->
18
+ <div class="card glass animate-slide-up" style="--delay: 0.1s">
19
+ <div class="card-header">
20
+ <span class="icon">📁</span>
21
+ <span class="card-title">目录结构</span>
22
+ </div>
23
+ <div class="structure">
24
+ <div class="structure-item">
25
+ <span class="folder">📂 apps/</span>
26
+ <span class="desc">子应用目录</span>
27
+ </div>
28
+ <div class="structure-item indent">
29
+ <span class="folder">└─ 📂 your-app/</span>
30
+ <span class="desc">具体应用</span>
31
+ </div>
32
+ <div class="structure-item">
33
+ <span class="folder">📂 packages/</span>
34
+ <span class="desc">共享包目录</span>
35
+ </div>
36
+ <div class="structure-item indent">
37
+ <span class="folder">├─ 📦 bridge/</span>
38
+ <span class="desc">JSBridge</span>
39
+ </div>
40
+ <div class="structure-item indent">
41
+ <span class="folder">├─ 📦 request/</span>
42
+ <span class="desc">请求封装</span>
43
+ </div>
44
+ <div class="structure-item indent">
45
+ <span class="folder">├─ 📦 utils/</span>
46
+ <span class="desc">工具函数</span>
47
+ </div>
48
+ <div class="structure-item indent">
49
+ <span class="folder">└─ 📦 vconsole/</span>
50
+ <span class="desc">调试工具</span>
51
+ </div>
52
+ <div class="structure-item">
53
+ <span class="folder">📂 scripts/</span>
54
+ <span class="desc">构建脚本</span>
55
+ </div>
56
+ </div>
57
+ </div>
58
+
59
+ <!-- 快速开始 -->
60
+ <div class="card glass animate-slide-up" style="--delay: 0.2s">
61
+ <div class="card-header">
62
+ <span class="icon">🚀</span>
63
+ <span class="card-title">快速开始</span>
64
+ </div>
65
+ <div class="steps">
66
+ <div class="step">
67
+ <div class="step-num">1</div>
68
+ <div class="step-content">
69
+ <p class="step-title">安装依赖</p>
70
+ <code class="code-block">pnpm install</code>
71
+ </div>
72
+ </div>
73
+ <div class="step">
74
+ <div class="step-num">2</div>
75
+ <div class="step-content">
76
+ <p class="step-title">启动开发服务器</p>
77
+ <code class="code-block">pnpm --filter &lt;app-name&gt; dev</code>
78
+ </div>
79
+ </div>
80
+ <div class="step">
81
+ <div class="step-num">3</div>
82
+ <div class="step-content">
83
+ <p class="step-title">构建生产版本</p>
84
+ <code class="code-block">pnpm --filter &lt;app-name&gt; build</code>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ <!-- 常用命令 -->
91
+ <div class="card glass animate-slide-up" style="--delay: 0.3s">
92
+ <div class="card-header">
93
+ <span class="icon">📝</span>
94
+ <span class="card-title">常用命令</span>
95
+ </div>
96
+ <div class="commands">
97
+ <div class="command-item">
98
+ <code class="command-code">pnpm dev</code>
99
+ <span class="command-desc">启动所有应用</span>
100
+ </div>
101
+ <div class="command-item">
102
+ <code class="command-code">pnpm build</code>
103
+ <span class="command-desc">构建所有应用</span>
104
+ </div>
105
+ <div class="command-item">
106
+ <code class="command-code">pnpm preview</code>
107
+ <span class="command-desc">预览构建产物</span>
108
+ </div>
109
+ <div class="command-item">
110
+ <code class="command-code">turbo run dev</code>
111
+ <span class="command-desc">使用 Turborepo 运行</span>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ <!-- 添加新应用 -->
117
+ <div class="card glass animate-slide-up" style="--delay: 0.4s">
118
+ <div class="card-header">
119
+ <span class="icon">➕</span>
120
+ <span class="card-title">添加新应用</span>
121
+ </div>
122
+ <div class="tips">
123
+ <p class="tip-text">在 apps 目录下复制现有应用并修改 package.json 中的 name 即可</p>
124
+ <code class="code-block small">cp -r apps/app1 apps/app2</code>
125
+ </div>
126
+ </div>
127
+ </div>
5
128
  </div>
6
129
  </template>
7
130
 
@@ -17,14 +140,250 @@ defineOptions({
17
140
 
18
141
  <style scoped>
19
142
  .about {
20
- padding: 20px;
143
+ min-height: 100vh;
144
+ position: relative;
145
+ overflow: hidden;
146
+ }
147
+
148
+ /* 背景渐变 */
149
+ .bg-gradient {
150
+ position: fixed;
151
+ inset: 0;
152
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
153
+ z-index: -1;
154
+ }
155
+
156
+ /* 导航栏 */
157
+ .navbar {
158
+ position: sticky;
159
+ top: 0;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: space-between;
163
+ padding: 16px 20px;
164
+ z-index: 100;
21
165
  }
22
166
 
23
- button {
167
+ .glass {
168
+ background: rgba(255, 255, 255, 0.15);
169
+ backdrop-filter: blur(20px);
170
+ -webkit-backdrop-filter: blur(20px);
171
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
172
+ }
173
+
174
+ .back-btn {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: 6px;
178
+ background: rgba(255, 255, 255, 0.2);
179
+ border: none;
180
+ color: white;
24
181
  padding: 8px 16px;
25
- border: 1px solid #d1d5db;
26
- border-radius: 4px;
27
- background: white;
182
+ border-radius: 20px;
28
183
  cursor: pointer;
184
+ font-size: 14px;
185
+ transition: all 0.3s ease;
186
+ }
187
+
188
+ .back-btn:hover {
189
+ background: rgba(255, 255, 255, 0.3);
190
+ }
191
+
192
+ .arrow {
193
+ font-size: 18px;
194
+ }
195
+
196
+ .nav-title {
197
+ color: white;
198
+ font-size: 18px;
199
+ font-weight: 600;
200
+ margin: 0;
201
+ }
202
+
203
+ .placeholder {
204
+ width: 80px;
205
+ }
206
+
207
+ /* 内容 */
208
+ .content {
209
+ padding: 20px;
210
+ max-width: 500px;
211
+ margin: 0 auto;
212
+ }
213
+
214
+ /* 卡片 */
215
+ .card {
216
+ background: rgba(255, 255, 255, 0.15);
217
+ backdrop-filter: blur(20px);
218
+ -webkit-backdrop-filter: blur(20px);
219
+ border-radius: 16px;
220
+ padding: 20px;
221
+ margin-bottom: 16px;
222
+ border: 1px solid rgba(255, 255, 255, 0.2);
223
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
224
+ }
225
+
226
+ .card-header {
227
+ display: flex;
228
+ align-items: center;
229
+ gap: 10px;
230
+ margin-bottom: 16px;
231
+ }
232
+
233
+ .icon {
234
+ font-size: 24px;
235
+ }
236
+
237
+ .card-title {
238
+ font-size: 18px;
239
+ font-weight: 600;
240
+ color: white;
241
+ }
242
+
243
+ /* 目录结构 */
244
+ .structure-item {
245
+ display: flex;
246
+ justify-content: space-between;
247
+ align-items: center;
248
+ padding: 8px 0;
249
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
250
+ }
251
+
252
+ .structure-item:last-child {
253
+ border-bottom: none;
254
+ }
255
+
256
+ .structure-item.indent {
257
+ padding-left: 20px;
258
+ }
259
+
260
+ .folder {
261
+ color: white;
262
+ font-size: 14px;
263
+ font-family: 'Monaco', 'Consolas', monospace;
264
+ }
265
+
266
+ .desc {
267
+ color: rgba(255, 255, 255, 0.7);
268
+ font-size: 13px;
269
+ }
270
+
271
+ /* 步骤 */
272
+ .steps {
273
+ display: flex;
274
+ flex-direction: column;
275
+ gap: 16px;
276
+ }
277
+
278
+ .step {
279
+ display: flex;
280
+ gap: 16px;
281
+ align-items: flex-start;
282
+ }
283
+
284
+ .step-num {
285
+ width: 32px;
286
+ height: 32px;
287
+ background: linear-gradient(135deg, #fff, #f0f0f0);
288
+ color: #764ba2;
289
+ border-radius: 50%;
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ font-weight: 700;
294
+ font-size: 14px;
295
+ flex-shrink: 0;
296
+ }
297
+
298
+ .step-content {
299
+ flex: 1;
300
+ }
301
+
302
+ .step-title {
303
+ color: white;
304
+ font-size: 14px;
305
+ font-weight: 500;
306
+ margin: 0 0 8px 0;
307
+ }
308
+
309
+ .code-block {
310
+ display: block;
311
+ background: rgba(0, 0, 0, 0.3);
312
+ color: #0f0;
313
+ padding: 10px 14px;
314
+ border-radius: 8px;
315
+ font-family: 'Monaco', 'Consolas', monospace;
316
+ font-size: 13px;
317
+ overflow-x: auto;
318
+ }
319
+
320
+ .code-block.small {
321
+ font-size: 12px;
322
+ padding: 8px 12px;
323
+ }
324
+
325
+ /* 命令列表 */
326
+ .commands {
327
+ display: flex;
328
+ flex-direction: column;
329
+ gap: 12px;
330
+ }
331
+
332
+ .command-item {
333
+ display: flex;
334
+ justify-content: space-between;
335
+ align-items: center;
336
+ padding: 10px 0;
337
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
338
+ }
339
+
340
+ .command-item:last-child {
341
+ border-bottom: none;
342
+ }
343
+
344
+ .command-code {
345
+ background: rgba(0, 0, 0, 0.3);
346
+ color: #0f0;
347
+ padding: 6px 12px;
348
+ border-radius: 6px;
349
+ font-family: 'Monaco', 'Consolas', monospace;
350
+ font-size: 12px;
351
+ }
352
+
353
+ .command-desc {
354
+ color: rgba(255, 255, 255, 0.8);
355
+ font-size: 13px;
356
+ }
357
+
358
+ /* 提示 */
359
+ .tips {
360
+ background: rgba(255, 255, 255, 0.1);
361
+ padding: 14px;
362
+ border-radius: 10px;
363
+ }
364
+
365
+ .tip-text {
366
+ color: rgba(255, 255, 255, 0.9);
367
+ font-size: 13px;
368
+ margin: 0 0 10px 0;
369
+ line-height: 1.5;
370
+ }
371
+
372
+ /* 动画 */
373
+ .animate-slide-up {
374
+ animation: slideUp 0.6s ease forwards;
375
+ animation-delay: var(--delay, 0s);
376
+ opacity: 0;
377
+ }
378
+
379
+ @keyframes slideUp {
380
+ from {
381
+ opacity: 0;
382
+ transform: translateY(30px);
383
+ }
384
+ to {
385
+ opacity: 1;
386
+ transform: translateY(0);
387
+ }
29
388
  }
30
389
  </style>
@@ -1,35 +1,85 @@
1
1
  <template>
2
2
  <div class="home">
3
- <h1>首页</h1>
4
- <p>欢迎来到 {{ projectName }}</p>
5
- <p>用户名: {{ userStore.userInfo?.name || '未登录' }}</p>
6
- <button @click="userStore.setUserInfo({ name: '张三' })">设置用户</button>
7
- <button @click="router.push('/about')">跳转到关于</button>
8
- <button @click="testBridge">测试桥接</button>
3
+ <!-- 背景动画 -->
4
+ <div class="bg-gradient"></div>
5
+ <div class="bg-particles">
6
+ <span v-for="i in 20" :key="i" class="particle" :style="getParticleStyle(i)"></span>
7
+ </div>
8
+
9
+ <div class="content">
10
+ <!-- 头部 -->
11
+ <div class="header animate-fade-in">
12
+ <div class="logo-wrapper">
13
+ <div class="logo-ring"></div>
14
+ <div class="logo">🚀</div>
15
+ </div>
16
+ <h1 class="title glitch" :data-text="projectName">{{ projectName }}</h1>
17
+ <p class="subtitle">Mobile H5 Monorepo Project</p>
18
+ </div>
19
+
20
+ <!-- 项目简介 -->
21
+ <div class="card glass animate-slide-up" style="--delay: 0.1s">
22
+ <div class="card-header">
23
+ <span class="icon pulse">📦</span>
24
+ <span class="card-title">项目简介</span>
25
+ </div>
26
+ <p class="card-content">
27
+ 一个基于 Vue 3 + Vite 的移动端 H5 Monorepo 项目模板,集成状态管理、路由、埋点等完整解决方案。
28
+ </p>
29
+ </div>
30
+
31
+ <!-- 技术栈 -->
32
+ <div class="card glass animate-slide-up" style="--delay: 0.2s">
33
+ <div class="card-header">
34
+ <span class="icon pulse">⚡</span>
35
+ <span class="card-title">技术栈</span>
36
+ </div>
37
+ <div class="tech-stack">
38
+ <div class="tech-badge">Vue 3</div>
39
+ <div class="tech-badge">Vite 6</div>
40
+ <div class="tech-badge">Pinia 3</div>
41
+ <div class="tech-badge">Vue Router 5</div>
42
+ <div class="tech-badge">Turborepo</div>
43
+ <div class="tech-badge">pnpm</div>
44
+ </div>
45
+ </div>
46
+
47
+ <!-- 作者信息 -->
48
+ <div class="card glass animate-slide-up" style="--delay: 0.3s">
49
+ <div class="card-header">
50
+ <span class="icon pulse">👤</span>
51
+ <span class="card-title">作者</span>
52
+ </div>
53
+ <p class="author-name">csch5</p>
54
+ </div>
55
+
56
+ <!-- 按钮 -->
57
+ <button class="btn-primary animate-slide-up" style="--delay: 0.4s" @click="router.push('/about')">
58
+ <span class="btn-icon">📖</span>
59
+ <span>查看使用方法</span>
60
+ <span class="btn-arrow">→</span>
61
+ </button>
62
+ </div>
9
63
  </div>
10
64
  </template>
11
65
 
12
66
  <script setup>
13
- import { useUserStore } from '../stores';
14
67
  import { useRouter } from 'vue-router';
15
- import { onMounted } from 'vue';
16
68
 
17
69
  const router = useRouter();
18
- const userStore = useUserStore();
19
70
  const projectName = import.meta.env.VITE_APP_NAME || '{{projectName}}';
20
71
 
21
- onMounted(() => {
22
- console.log('当前路由:', router.currentRoute.value.path);
23
- console.log('是否iOS:', window.isIOS);
24
- console.log('是否Android:', window.isAndroid);
25
- });
26
-
27
- const testBridge = () => {
28
- if (window.isIOS || window.isAndroid) {
29
- window.getAppVersion?.();
30
- } else {
31
- console.log('当前在Web环境,无法测试桥接');
32
- }
72
+ // 随机粒子样式
73
+ const getParticleStyle = (index) => {
74
+ const size = Math.random() * 4 + 2;
75
+ return {
76
+ width: `${size}px`,
77
+ height: `${size}px`,
78
+ left: `${Math.random() * 100}%`,
79
+ top: `${Math.random() * 100}%`,
80
+ animationDelay: `${Math.random() * 10}s`,
81
+ animationDuration: `${Math.random() * 10 + 10}s`
82
+ };
33
83
  };
34
84
 
35
85
  defineOptions({
@@ -39,16 +89,301 @@ defineOptions({
39
89
 
40
90
  <style scoped>
41
91
  .home {
92
+ min-height: 100vh;
93
+ position: relative;
94
+ overflow: hidden;
95
+ }
96
+
97
+ /* 背景渐变 */
98
+ .bg-gradient {
99
+ position: fixed;
100
+ inset: 0;
101
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
102
+ z-index: -2;
103
+ }
104
+
105
+ /* 粒子背景 */
106
+ .bg-particles {
107
+ position: fixed;
108
+ inset: 0;
109
+ z-index: -1;
110
+ }
111
+
112
+ .particle {
113
+ position: absolute;
114
+ background: rgba(255, 255, 255, 0.5);
115
+ border-radius: 50%;
116
+ animation: float linear infinite;
117
+ }
118
+
119
+ @keyframes float {
120
+ 0%, 100% {
121
+ transform: translateY(0) translateX(0);
122
+ opacity: 0;
123
+ }
124
+ 10% {
125
+ opacity: 1;
126
+ }
127
+ 90% {
128
+ opacity: 1;
129
+ }
130
+ 100% {
131
+ transform: translateY(-100vh) translateX(50px);
132
+ opacity: 0;
133
+ }
134
+ }
135
+
136
+ /* 内容 */
137
+ .content {
138
+ padding: 40px 20px;
139
+ max-width: 500px;
140
+ margin: 0 auto;
141
+ }
142
+
143
+ /* 头部 */
144
+ .header {
145
+ text-align: center;
146
+ margin-bottom: 30px;
147
+ }
148
+
149
+ .logo-wrapper {
150
+ position: relative;
151
+ width: 100px;
152
+ height: 100px;
153
+ margin: 0 auto 20px;
154
+ }
155
+
156
+ .logo {
157
+ font-size: 50px;
158
+ position: relative;
159
+ z-index: 2;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ width: 100%;
164
+ height: 100%;
165
+ }
166
+
167
+ .logo-ring {
168
+ position: absolute;
169
+ inset: 0;
170
+ border-radius: 50%;
171
+ border: 3px solid rgba(255, 255, 255, 0.5);
172
+ animation: ring-pulse 2s ease-in-out infinite;
173
+ }
174
+
175
+ @keyframes ring-pulse {
176
+ 0%, 100% {
177
+ transform: scale(1);
178
+ opacity: 1;
179
+ }
180
+ 50% {
181
+ transform: scale(1.2);
182
+ opacity: 0.5;
183
+ }
184
+ }
185
+
186
+ .title {
187
+ font-size: 32px;
188
+ font-weight: 800;
189
+ color: white;
190
+ margin: 0;
191
+ text-shadow: 0 2px 20px rgba(0, 0, 0, 0.3);
192
+ letter-spacing: 2px;
193
+ }
194
+
195
+ /* 故障效果 */
196
+ .glitch {
197
+ position: relative;
198
+ }
199
+
200
+ .glitch::before,
201
+ .glitch::after {
202
+ content: attr(data-text);
203
+ position: absolute;
204
+ left: 0;
205
+ top: 0;
206
+ width: 100%;
207
+ height: 100%;
208
+ }
209
+
210
+ .glitch::before {
211
+ color: #0ff;
212
+ animation: glitch-1 2s infinite linear alternate-reverse;
213
+ clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
214
+ }
215
+
216
+ .glitch::after {
217
+ color: #f0f;
218
+ animation: glitch-2 2s infinite linear alternate-reverse;
219
+ clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
220
+ }
221
+
222
+ @keyframes glitch-1 {
223
+ 0%, 100% { transform: translate(0); }
224
+ 20% { transform: translate(-2px, 2px); }
225
+ 40% { transform: translate(2px, -2px); }
226
+ 60% { transform: translate(-2px, 0); }
227
+ 80% { transform: translate(2px, 2px); }
228
+ }
229
+
230
+ @keyframes glitch-2 {
231
+ 0%, 100% { transform: translate(0); }
232
+ 20% { transform: translate(2px, -2px); }
233
+ 40% { transform: translate(-2px, 2px); }
234
+ 60% { transform: translate(2px, 0); }
235
+ 80% { transform: translate(-2px, -2px); }
236
+ }
237
+
238
+ .subtitle {
239
+ color: rgba(255, 255, 255, 0.9);
240
+ font-size: 16px;
241
+ margin-top: 8px;
242
+ letter-spacing: 1px;
243
+ }
244
+
245
+ /* 玻璃卡片 */
246
+ .card {
247
+ background: rgba(255, 255, 255, 0.15);
248
+ backdrop-filter: blur(20px);
249
+ -webkit-backdrop-filter: blur(20px);
250
+ border-radius: 16px;
42
251
  padding: 20px;
252
+ margin-bottom: 16px;
253
+ border: 1px solid rgba(255, 255, 255, 0.2);
254
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
255
+ }
256
+
257
+ .card-header {
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 10px;
261
+ margin-bottom: 12px;
262
+ }
263
+
264
+ .icon {
265
+ font-size: 24px;
266
+ }
267
+
268
+ .icon.pulse {
269
+ animation: icon-pulse 2s ease-in-out infinite;
270
+ }
271
+
272
+ @keyframes icon-pulse {
273
+ 0%, 100% { transform: scale(1); }
274
+ 50% { transform: scale(1.1); }
275
+ }
276
+
277
+ .card-title {
278
+ font-size: 18px;
279
+ font-weight: 600;
280
+ color: white;
281
+ }
282
+
283
+ .card-content {
284
+ color: rgba(255, 255, 255, 0.9);
285
+ font-size: 14px;
286
+ line-height: 1.6;
287
+ margin: 0;
288
+ }
289
+
290
+ /* 技术栈徽章 */
291
+ .tech-stack {
292
+ display: flex;
293
+ flex-wrap: wrap;
294
+ gap: 8px;
295
+ }
296
+
297
+ .tech-badge {
298
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.1));
299
+ color: white;
300
+ padding: 6px 14px;
301
+ border-radius: 20px;
302
+ font-size: 13px;
303
+ font-weight: 500;
304
+ border: 1px solid rgba(255, 255, 255, 0.3);
305
+ transition: all 0.3s ease;
306
+ }
307
+
308
+ .tech-badge:hover {
309
+ background: rgba(255, 255, 255, 0.3);
310
+ transform: translateY(-2px);
311
+ }
312
+
313
+ /* 作者 */
314
+ .author-name {
315
+ color: white;
316
+ font-size: 18px;
317
+ font-weight: 600;
318
+ margin: 0;
43
319
  }
44
320
 
45
- button {
46
- margin-right: 10px;
47
- margin-bottom: 10px;
48
- padding: 8px 16px;
49
- border: 1px solid #d1d5db;
50
- border-radius: 4px;
51
- background: white;
321
+ /* 主按钮 */
322
+ .btn-primary {
323
+ width: 100%;
324
+ padding: 16px 24px;
325
+ background: linear-gradient(135deg, #fff, #f0f0f0);
326
+ border: none;
327
+ border-radius: 50px;
328
+ color: #764ba2;
329
+ font-size: 16px;
330
+ font-weight: 600;
52
331
  cursor: pointer;
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ gap: 10px;
336
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
337
+ transition: all 0.3s ease;
338
+ margin-top: 20px;
339
+ }
340
+
341
+ .btn-primary:hover {
342
+ transform: translateY(-3px);
343
+ box-shadow: 0 15px 50px rgba(0, 0, 0, 0.3);
344
+ }
345
+
346
+ .btn-primary:active {
347
+ transform: translateY(-1px);
348
+ }
349
+
350
+ .btn-icon {
351
+ font-size: 20px;
352
+ }
353
+
354
+ .btn-arrow {
355
+ font-size: 18px;
356
+ transition: transform 0.3s ease;
357
+ }
358
+
359
+ .btn-primary:hover .btn-arrow {
360
+ transform: translateX(5px);
361
+ }
362
+
363
+ /* 动画 */
364
+ .animate-fade-in {
365
+ animation: fadeIn 0.8s ease forwards;
366
+ }
367
+
368
+ .animate-slide-up {
369
+ animation: slideUp 0.6s ease forwards;
370
+ animation-delay: var(--delay, 0s);
371
+ opacity: 0;
372
+ }
373
+
374
+ @keyframes fadeIn {
375
+ from { opacity: 0; }
376
+ to { opacity: 1; }
377
+ }
378
+
379
+ @keyframes slideUp {
380
+ from {
381
+ opacity: 0;
382
+ transform: translateY(30px);
383
+ }
384
+ to {
385
+ opacity: 1;
386
+ transform: translateY(0);
387
+ }
53
388
  }
54
389
  </style>