htmlgen-mcp 0.2.0__py3-none-any.whl

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.

Potentially problematic release.


This version of htmlgen-mcp might be problematic. Click here for more details.

@@ -0,0 +1,1770 @@
1
+ """页面模板相关工具"""
2
+ from __future__ import annotations
3
+
4
+ import html
5
+ import urllib.parse
6
+ from pathlib import Path
7
+
8
+
9
+ def create_html_file(
10
+ file_path: str,
11
+ title: str = "New Page",
12
+ content: str = "",
13
+ style: str = "ultra_modern",
14
+ sections: list | dict | None = None,
15
+ ) -> str:
16
+ """创建HTML文件,支持多风格模板(统一引用 assets 目录)"""
17
+
18
+ style_key = (style or "ultra_modern").lower().replace("-", "_")
19
+
20
+ def hero_ultra() -> str:
21
+ return f"""
22
+ <header id=\"home\" class=\"hero hero-ultra section text-center\" data-bg-topic=\"hero premium gradient glassmorphism\" data-parallax=\"0.25\">
23
+ <div class=\"hero-floating\" aria-hidden=\"true\">
24
+ <div class=\"floating-shape shape-one\"></div>
25
+ <div class=\"floating-shape shape-two\"></div>
26
+ </div>
27
+ <div class=\"container hero-inner\">
28
+ <span class=\"badge badge-soft mb-3\">全新发布</span>
29
+ <h1 class=\"display-5 mb-3\">{title}</h1>
30
+ <p class=\"section-lead mx-auto\">一句话定义品牌价值主张:简洁而有力,体现高级感与专业度。</p>
31
+ <div class=\"mt-4 d-flex justify-content-center gap-3\">
32
+ <a href=\"#contact\" class=\"btn btn-primary btn-lg px-4\">立即咨询</a>
33
+ <a href=\"#showcase\" class=\"btn btn-secondary btn-lg px-4\">查看案例</a>
34
+ </div>
35
+ </div>
36
+ <div class=\"shape-bottom\" aria-hidden=\"true\">
37
+ <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1440 320\"><path fill=\"#f8f9fa\" d=\"M0,128L48,117.3C96,107,192,85,288,112C384,139,480,213,576,229.3C672,245,768,203,864,165.3C960,128,1056,96,1152,85.3C1248,75,1344,85,1392,90.7L1440,96L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z\"></path></svg>
38
+ </div>
39
+ </header>
40
+ """
41
+
42
+ def body_ultra() -> str:
43
+ return f"""
44
+ <main>
45
+ <section class=\"section section-sm\">
46
+ <div class=\"container\">
47
+ <div class=\"text-center text-muted mb-3\">受信任的合作伙伴</div>
48
+ <div class=\"d-flex flex-wrap align-items-center justify-content-center gap-4 opacity-75 marquee-clients\">
49
+ <div class=\"fw-bold\">ALPHA</div>
50
+ <div class=\"fw-bold\">BETA</div>
51
+ <div class=\"fw-bold\">GAMMA</div>
52
+ <div class=\"fw-bold\">OMEGA</div>
53
+ <div class=\"fw-bold\">NOVA</div>
54
+ </div>
55
+ </div>
56
+ </section>
57
+
58
+ <section class=\"section section-sm\">
59
+ <div class=\"container\">
60
+ <div class=\"row g-4 text-center\">
61
+ <div class=\"col-md-3\"><div class=\"feature-card glass p-4 reveal\" data-tilt><div class=\"display-6 fw-bold counter\" data-target=\"120\">0</div><div class=\"text-muted mt-2\">成功项目</div></div></div>
62
+ <div class=\"col-md-3\"><div class=\"feature-card glass p-4 reveal\" data-tilt><div class=\"display-6 fw-bold counter\" data-target=\"50\">0</div><div class=\"text-muted mt-2\">行业客户</div></div></div>
63
+ <div class=\"col-md-3\"><div class=\"feature-card glass p-4 reveal\" data-tilt><div class=\"display-6 fw-bold counter\" data-target=\"98\">0</div><div class=\"text-muted mt-2\">满意度(%)</div></div></div>
64
+ <div class=\"col-md-3\"><div class=\"feature-card glass p-4 reveal\" data-tilt><div class=\"display-6 fw-bold counter\" data-target=\"7\">0</div><div class=\"text-muted mt-2\">年行业经验</div></div></div>
65
+ </div>
66
+ </div>
67
+ </section>
68
+
69
+ <section id=\"services\" class=\"section\">
70
+ <div class=\"container\">
71
+ <h2 class=\"h3 text-center section-title\">我们打造一流体验</h2>
72
+ <p class=\"section-lead text-center\">以品牌级视觉与工程化质控,交付可直接上线的商业作品。</p>
73
+ <div class=\"row g-4 mt-2\">
74
+ <div class=\"col-md-4\">
75
+ <div class=\"feature-card reveal text-start\" data-tilt>
76
+ <img data-topic=\"premium product hero\" alt=\"产品图\" class=\"mb-3 rounded shadow-sm\">
77
+ <div class=\"feature-icon\" aria-hidden=\"true\">🚀</div>
78
+ <h3 class=\"h5 mb-2\">高端设计系统</h3>
79
+ <p class=\"mb-0 text-muted\">统一配色/字体/动效/圆角/阴影,保持品牌一致性。</p>
80
+ </div>
81
+ </div>
82
+ <div class=\"col-md-4\">
83
+ <div class=\"feature-card reveal text-start\" data-tilt>
84
+ <img data-topic=\"lifestyle scene premium\" alt=\"场景图\" class=\"mb-3 rounded shadow-sm\">
85
+ <div class=\"feature-icon\" aria-hidden=\"true\">🎯</div>
86
+ <h3 class=\"h5 mb-2\">结果导向体验</h3>
87
+ <p class=\"mb-0 text-muted\">移动优先、性能优化、可用性与可访问性全面考虑。</p>
88
+ </div>
89
+ </div>
90
+ <div class=\"col-md-4\">
91
+ <div class=\"feature-card reveal text-start\" data-tilt>
92
+ <img data-topic=\"detail macro elegant\" alt=\"细节图\" class=\"mb-3 rounded shadow-sm\">
93
+ <div class=\"feature-icon\" aria-hidden=\"true\">💎</div>
94
+ <h3 class=\"h5 mb-2\">精致细节</h3>
95
+ <p class=\"mb-0 text-muted\">玻璃态/渐变/光扫等细节,赋予质感与层次。</p>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </section>
101
+
102
+ <section id=\"showcase\" class=\"section section-sm\">
103
+ <div class=\"container\">
104
+ <h2 class=\"h3 text-center section-title\">精选案例</h2>
105
+ <p class=\"section-lead text-center\">来自不同行业的视觉与体验实践。</p>
106
+ <div id=\"product-grid\" class=\"row g-4 mt-2 product-grid\"></div>
107
+ </div>
108
+ </section>
109
+
110
+ <section class=\"section section-sm\">
111
+ <div class=\"container\">
112
+ <div class=\"row g-4\">
113
+ <div class=\"col-md-4\">
114
+ <div class=\"feature-card glass reveal\" data-tilt>
115
+ <div class=\"d-flex align-items-center gap-3 mb-3\">
116
+ <img class=\"rounded-circle\" width=\"48\" height=\"48\" alt=\"顾客\" data-topic=\"portrait minimal premium\">
117
+ <div class=\"fw-semibold\">Alex Chen</div>
118
+ </div>
119
+ <p class=\"mb-0 text-muted\">“设计质感与转化率提升明显,是一次非常愉快的合作。”</p>
120
+ </div>
121
+ </div>
122
+ <div class=\"col-md-4\">
123
+ <div class=\"feature-card glass reveal\" data-tilt>
124
+ <div class=\"d-flex align-items-center gap-3 mb-3\">
125
+ <img class=\"rounded-circle\" width=\"48\" height=\"48\" alt=\"顾客\" data-topic=\"portrait minimal premium\">
126
+ <div class=\"fw-semibold\">Liang Wu</div>
127
+ </div>
128
+ <p class=\"mb-0 text-muted\">“移动端体验极佳,品牌形象焕然一新。”</p>
129
+ </div>
130
+ </div>
131
+ <div class=\"col-md-4\">
132
+ <div class=\"feature-card glass reveal\" data-tilt>
133
+ <div class=\"d-flex align-items-center gap-3 mb-3\">
134
+ <img class=\"rounded-circle\" width=\"48\" height=\"48\" alt=\"顾客\" data-topic=\"portrait minimal premium\">
135
+ <div class=\"fw-semibold\">Yvonne Zhao</div>
136
+ </div>
137
+ <p class=\"mb-0 text-muted\">“细节到位,交互顺畅,交付质量超出预期。”</p>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </div>
142
+ </section>
143
+
144
+ <section id=\"pricing\" class=\"section\">
145
+ <div class=\"container\">
146
+ <h2 class=\"h3 text-center section-title\">灵活定价</h2>
147
+ <p class=\"section-lead text-center\">按需选择,快速启动高质感网站项目。</p>
148
+ <div class=\"row g-4 mt-2\">
149
+ <div class=\"col-md-4\">
150
+ <div class=\"feature-card glass text-start reveal\" data-tilt>
151
+ <h3 class=\"h5 mb-1\">起步</h3>
152
+ <div class=\"display-6 fw-bold mb-3\">¥ 9,999</div>
153
+ <ul class=\"text-muted mb-4\">
154
+ <li>基础单页/落地页</li>
155
+ <li>品牌配色与排版</li>
156
+ <li>移动端适配</li>
157
+ </ul>
158
+ <a class=\"btn btn-primary w-100\" href=\"#contact\">咨询方案</a>
159
+ </div>
160
+ </div>
161
+ <div class=\"col-md-4\">
162
+ <div class=\"feature-card glass text-start reveal\" data-tilt>
163
+ <h3 class=\"h5 mb-1\">专业</h3>
164
+ <div class=\"display-6 fw-bold mb-3\">¥ 29,999</div>
165
+ <ul class=\"text-muted mb-4\">
166
+ <li>多页面信息架构</li>
167
+ <li>图片智能注入与动效</li>
168
+ <li>明/暗主题切换</li>
169
+ </ul>
170
+ <a class=\"btn btn-primary w-100\" href=\"#contact\">咨询方案</a>
171
+ </div>
172
+ </div>
173
+ <div class=\"col-md-4\">
174
+ <div class=\"feature-card glass text-start reveal\" data-tilt>
175
+ <h3 class=\"h5 mb-1\">旗舰</h3>
176
+ <div class=\"display-6 fw-bold mb-3\">¥ 59,999</div>
177
+ <ul class=\"text-muted mb-4\">
178
+ <li>定制视觉语言与插画</li>
179
+ <li>复杂交互与多端适配</li>
180
+ <li>性能优化与SEO结构化</li>
181
+ </ul>
182
+ <a class=\"btn btn-primary w-100\" href=\"#contact\">咨询方案</a>
183
+ </div>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </section>
188
+
189
+ <section class=\"section section-sm\">
190
+ <div class=\"container\">
191
+ <div class=\"p-5 cta text-center reveal\" data-parallax=\"-0.35\">
192
+ <h2 class=\"h4 mb-2\">准备好升级你的品牌体验?</h2>
193
+ <p class=\"mb-3\">我们将用设计与工程,让每一个像素都有价值。</p>
194
+ <a class=\"btn btn-light btn-lg px-4\" href=\"#contact\">立即联系</a>
195
+ </div>
196
+ </div>
197
+ </section>
198
+
199
+ <section class=\"section section-sm\">
200
+ <div class=\"container\">
201
+ <h2 class=\"h3 text-center section-title\">常见问题</h2>
202
+ <div class=\"mx-auto\" style=\"max-width:900px;\">
203
+ <details class=\"feature-card mb-3\" data-tilt><summary class=\"fw-semibold\">项目周期一般多久?</summary><div class=\"mt-2 text-muted\">典型项目 2-4 周,复杂项目按需评估并排期。</div></details>
204
+ <details class=\"feature-card mb-3\" data-tilt><summary class=\"fw-semibold\">是否支持品牌升级与重构?</summary><div class=\"mt-2 text-muted\">支持,提供配色、字体、组件体系与页面模板重塑。</div></details>
205
+ <details class=\"feature-card mb-3\" data-tilt><summary class=\"fw-semibold\">如何保障交付质量?</summary><div class=\"mt-2 text-muted\">完善的设计系统、代码规范与多端测试,确保上线质量。</div></details>
206
+ </div>
207
+ </div>
208
+ </section>
209
+
210
+ <section id=\"contact\" class=\"section\">
211
+ <div class=\"container\">
212
+ <h2 class=\"h3 text-center section-title\">联系我们</h2>
213
+ <p class=\"section-lead text-center\">留下您的需求,我们会尽快与您联系。</p>
214
+ <form class=\"mx-auto mt-3 reveal form-floating-cards\" style=\"max-width:560px;\">
215
+ <div class=\"mb-3\">
216
+ <label class=\"form-label\">姓名</label>
217
+ <input type=\"text\" class=\"form-control\" placeholder=\"请输入姓名\" aria-label=\"姓名\">
218
+ </div>
219
+ <div class=\"mb-3\">
220
+ <label class=\"form-label\">邮箱</label>
221
+ <input type=\"email\" class=\"form-control\" placeholder=\"name@example.com\" aria-label=\"邮箱\">
222
+ </div>
223
+ <div class=\"mb-3\">
224
+ <label class=\"form-label\">留言</label>
225
+ <textarea class=\"form-control\" rows=\"4\" placeholder=\"想聊点什么?\" aria-label=\"留言\"></textarea>
226
+ </div>
227
+ <button type=\"submit\" class=\"btn btn-primary w-100\">发送</button>
228
+ </form>
229
+ </div>
230
+ </section>
231
+ </main>
232
+
233
+ <footer class=\"py-5 bg-dark text-white\">
234
+ <div class=\"container\">
235
+ <div class=\"row g-4\">
236
+ <div class=\"col-md-4\">
237
+ <div class=\"fw-bold mb-2\">{title}</div>
238
+ <div class=\"text-muted\">以设计驱动增长,以工程保障质量。</div>
239
+ </div>
240
+ <div class=\"col-md-2\">
241
+ <div class=\"fw-semibold mb-2\">产品</div>
242
+ <ul class=\"list-unstyled text-muted\"><li>方案</li><li>案例</li><li>支持</li></ul>
243
+ </div>
244
+ <div class=\"col-md-2\">
245
+ <div class=\"fw-semibold mb-2\">公司</div>
246
+ <ul class=\"list-unstyled text-muted\"><li>关于</li><li>加入我们</li><li>联系</li></ul>
247
+ </div>
248
+ <div class=\"col-md-4\">
249
+ <div class=\"fw-semibold mb-2\">订阅更新</div>
250
+ <div class=\"d-flex gap-2\">
251
+ <input class=\"form-control\" placeholder=\"输入邮箱\" aria-label=\"订阅邮箱\">
252
+ <button class=\"btn btn-primary\">订阅</button>
253
+ </div>
254
+ </div>
255
+ </div>
256
+ <div class=\"text-center small mt-4 text-muted\">© {title}. 保留所有权利。</div>
257
+ </div>
258
+ </footer>
259
+ """
260
+
261
+ def hero_minimal() -> str:
262
+ return f"""
263
+ <header id=\"home\" class=\"hero hero-minimal section\" data-bg-topic=\"minimal luxury interior\">
264
+ <div class=\"container hero-inner minimal-grid\">
265
+ <div class=\"hero-minimal__content\">
266
+ <span class=\"tagline\">{title}</span>
267
+ <h1 class=\"display-4\">策略驱动的品牌体验设计</h1>
268
+ <p class=\"section-lead\">以视觉、文字与交互的克制表达,呈现具有收藏价值的数字作品。</p>
269
+ <div class=\"hero-minimal__cta\">
270
+ <a href=\"#showcase\" class=\"btn btn-outline-light btn-lg\">浏览作品集</a>
271
+ <a href=\"#contact\" class=\"btn btn-primary btn-lg\">预约咨询</a>
272
+ </div>
273
+ </div>
274
+ <div class=\"hero-minimal__gallery\">
275
+ <figure class=\"gallery-card\" data-topic=\"modern architecture warm light\"></figure>
276
+ <figure class=\"gallery-card\" data-topic=\"editorial design minimal\"></figure>
277
+ <figure class=\"gallery-card tall\" data-topic=\"art installation premium\"></figure>
278
+ </div>
279
+ </div>
280
+ </header>
281
+ """
282
+
283
+ def body_minimal() -> str:
284
+ return f"""
285
+ <main>
286
+ <section class=\"section section-alt\">
287
+ <div class=\"container\">
288
+ <div class=\"section-heading\">
289
+ <span class=\"eyebrow\">合作品牌</span>
290
+ <h2 class=\"h3\">与行业前沿品牌共同成长</h2>
291
+ </div>
292
+ <div class=\"brand-grid\">
293
+ <span>ALPHA</span>
294
+ <span>BARNES</span>
295
+ <span>EMBER</span>
296
+ <span>NEBULA</span>
297
+ <span>FRAME</span>
298
+ <span>STUDIO</span>
299
+ </div>
300
+ </div>
301
+ </section>
302
+
303
+ <section id=\"showcase\" class=\"section\">
304
+ <div class=\"container\">
305
+ <div class=\"section-heading d-flex justify-content-between align-items-center\">
306
+ <div>
307
+ <span class=\"eyebrow\">Selected Works</span>
308
+ <h2 class=\"h3\">精选作品集</h2>
309
+ </div>
310
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">下载作品集</a>
311
+ </div>
312
+ <div class=\"row g-4\">
313
+ <article class=\"case-card reveal\">
314
+ <div class=\"case-media\" data-bg-topic=\"luxury fashion website mockup\"></div>
315
+ <div class=\"case-content\">
316
+ <span class=\"eyebrow\">电商体验</span>
317
+ <h3>Atelier Aurora</h3>
318
+ <p class=\"text-muted\">为奢侈时尚品牌打造沉浸式购物体验,提升平均客单价 35%。</p>
319
+ </div>
320
+ </article>
321
+ <article class=\"case-card reveal\">
322
+ <div class=\"case-media\" data-bg-topic=\"digital product dashboard gradient\"></div>
323
+ <div class=\"case-content\">
324
+ <span class=\"eyebrow\">SaaS 平台</span>
325
+ <h3>Nova Metrics</h3>
326
+ <p class=\"text-muted\">打造全新数据可视化界面,信息更聚焦,决策效率提升 2 倍。</p>
327
+ </div>
328
+ </article>
329
+ <article class=\"case-card reveal\">
330
+ <div class=\"case-media\" data-bg-topic=\"editorial magazine layout photography\"></div>
331
+ <div class=\"case-content\">
332
+ <span class=\"eyebrow\">品牌官网</span>
333
+ <h3>Studio Linear</h3>
334
+ <p class=\"text-muted\">为创意工作室重塑线上形象,建立统一设计语言与内容矩阵。</p>
335
+ </div>
336
+ </article>
337
+ </div>
338
+ </div>
339
+ </section>
340
+
341
+ <section class=\"section\">
342
+ <div class=\"container\">
343
+ <div class=\"section-heading\">
344
+ <span class=\"eyebrow\">Capabilities</span>
345
+ <h2 class=\"h3\">服务能力</h2>
346
+ </div>
347
+ <div class=\"row g-4\">
348
+ <article class=\"service-card reveal\">
349
+ <h3>品牌体验战略</h3>
350
+ <p class=\"text-muted\">从品牌故事到视觉语言的系统构建,保持所有触点的一致性与辨识度。</p>
351
+ <ul>
352
+ <li>品牌识别系统</li>
353
+ <li>体验旅程地图</li>
354
+ <li>数字资产手册</li>
355
+ </ul>
356
+ </article>
357
+ <article class=\"service-card reveal\">
358
+ <h3>高保真视觉设计</h3>
359
+ <p class=\"text-muted\">兼顾商业目标与审美品味,交付可直接上线的视觉稿与规范。</p>
360
+ <ul>
361
+ <li>高保真界面</li>
362
+ <li>动效与交互动线</li>
363
+ <li>组件库与设计系统</li>
364
+ </ul>
365
+ </article>
366
+ <article class=\"service-card reveal\">
367
+ <h3>体验工程实现</h3>
368
+ <p class=\"text-muted\">工程团队协同,保证设计高复用与性能优化,上线即精品。</p>
369
+ <ul>
370
+ <li>响应式前端开发</li>
371
+ <li>性能优化与SEO</li>
372
+ <li>多端测试与迭代</li>
373
+ </ul>
374
+ </article>
375
+ </div>
376
+ </div>
377
+ </section>
378
+
379
+ <section class=\"section section-alt\">
380
+ <div class=\"container\">
381
+ <div class=\"row g-4 align-items-center\">
382
+ <div class=\"col-lg-6\">
383
+ <div class=\"testimonial-card reveal\">
384
+ <p class=\"quotation\">“合作过程高效顺畅,设计稿上线几乎零返工,品牌形象全面升级。”</p>
385
+ <div class=\"d-flex align-items-center gap-3 mt-3\">
386
+ <img class=\"rounded-circle\" width=\"48\" height=\"48\" data-topic=\"portrait minimal premium\" alt=\"客户头像\">
387
+ <div>
388
+ <div class=\"fw-semibold\">Evelyn Wang</div>
389
+ <div class=\"text-muted\">CMO · Aurora Studio</div>
390
+ </div>
391
+ </div>
392
+ </div>
393
+ </div>
394
+ <div class=\"col-lg-6\">
395
+ <div class=\"numbers-card reveal\">
396
+ <div><span class=\"display-5 fw-bold counter\" data-target=\"120\">0</span><span class=\"text-muted\">+ 完成项目</span></div>
397
+ <div><span class=\"display-5 fw-bold counter\" data-target=\"98\">0</span><span class=\"text-muted\">% 客户满意度</span></div>
398
+ <div><span class=\"display-5 fw-bold counter\" data-target=\"7\">0</span><span class=\"text-muted\">年行业经验</span></div>
399
+ </div>
400
+ </div>
401
+ </div>
402
+ </div>
403
+ </section>
404
+
405
+ <section class=\"section\">
406
+ <div class=\"container\">
407
+ <div class=\"section-heading\">
408
+ <span class=\"eyebrow\">Service Plans</span>
409
+ <h2 class=\"h3\">合作方案</h2>
410
+ </div>
411
+ <div class=\"row g-4\">
412
+ <article class=\"pricing-card reveal\">
413
+ <div class=\"pricing-card__header\">
414
+ <span class=\"eyebrow\">Lite</span>
415
+ <h3>起步方案</h3>
416
+ <p class=\"display-6 fw-bold\">¥9,999</p>
417
+ </div>
418
+ <ul>
419
+ <li>单页落地页设计</li>
420
+ <li>品牌视觉与排版系统</li>
421
+ <li>基础动效与滚动体验</li>
422
+ </ul>
423
+ <a class=\"btn btn-outline-light\" href=\"#contact\">预约沟通</a>
424
+ </article>
425
+ <article class=\"pricing-card reveal featured\">
426
+ <div class=\"pricing-card__header\">
427
+ <span class=\"eyebrow\">Signature</span>
428
+ <h3>旗舰方案</h3>
429
+ <p class=\"display-6 fw-bold\">¥29,999</p>
430
+ </div>
431
+ <ul>
432
+ <li>多页面信息架构</li>
433
+ <li>定制插画与交互动效</li>
434
+ <li>明/暗主题切换与高端展示</li>
435
+ </ul>
436
+ <a class=\"btn btn-primary\" href=\"#contact\">立即咨询</a>
437
+ </article>
438
+ <article class=\"pricing-card reveal\">
439
+ <div class=\"pricing-card__header\">
440
+ <span class=\"eyebrow\">Enterprise</span>
441
+ <h3>企业方案</h3>
442
+ <p class=\"display-6 fw-bold\">¥59,999+</p>
443
+ </div>
444
+ <ul>
445
+ <li>全链路品牌与产品体验</li>
446
+ <li>复杂信息架构与系统设计</li>
447
+ <li>性能优化、SEO 与 A/B 测试</li>
448
+ </ul>
449
+ <a class=\"btn btn-outline-light\" href=\"#contact\">定制方案</a>
450
+ </article>
451
+ </div>
452
+ </div>
453
+ </section>
454
+
455
+ <section id=\"contact\" class=\"section section-alt\">
456
+ <div class=\"container\">
457
+ <div class=\"row g-4\">
458
+ <div class=\"col-md-7\">
459
+ <h2 class=\"h4 mb-3\">项目洽谈</h2>
460
+ <form class=\"contact-form reveal\">
461
+ <div class=\"field-pair\"><label>姓名</label><input type=\"text\" placeholder=\"您的名字\" required></div>
462
+ <div class=\"field-pair\"><label>邮箱</label><input type=\"email\" placeholder=\"name@example.com\" required></div>
463
+ <div class=\"field-pair\"><label>预算范围</label><select><option>¥10k-30k</option><option>¥30k-60k</option><option>¥60k+</option></select></div>
464
+ <div class=\"field-pair\"><label>项目简介</label><textarea rows=\"4\" placeholder=\"请描述您的项目目标和期望体验\" required></textarea></div>
465
+ <button class=\"btn btn-primary\" type=\"submit\">发送需求</button>
466
+ </form>
467
+ </div>
468
+ <div class=\"col-md-5\">
469
+ <div class=\"info-card reveal\">
470
+ <h3>联系方式</h3>
471
+ <p class=\"text-muted\">hello@example.com</p>
472
+ <p class=\"text-muted\">+86 021 8888 6666</p>
473
+ <div class=\"d-flex gap-2 mt-3\">
474
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">Behance</a>
475
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">Dribbble</a>
476
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">LinkedIn</a>
477
+ </div>
478
+ </div>
479
+ </div>
480
+ </div>
481
+ </div>
482
+ </section>
483
+ </main>
484
+
485
+ <footer class=\"footer-minimal\">
486
+ <div class=\"container\">
487
+ <div class=\"footer-brand\">
488
+ <span>{title}</span>
489
+ <p>Crafted with taste & clarity</p>
490
+ </div>
491
+ <div class=\"footer-meta\">
492
+ <span>© {title}</span>
493
+ <a href=\"mailto:hello@example.com\">hello@example.com</a>
494
+ </div>
495
+ </div>
496
+ </footer>
497
+ """
498
+
499
+ def hero_creative() -> str:
500
+ return f"""
501
+ <header id=\"home\" class=\"hero hero-creative text-center\" data-bg-topic=\"futuristic gradient landscape\">
502
+ <div class=\"hero-creative__orbit\" aria-hidden=\"true\">
503
+ <div class=\"orbit-layer layer-one\"></div>
504
+ <div class=\"orbit-layer layer-two\"></div>
505
+ <div class=\"orbit-layer layer-three\"></div>
506
+ </div>
507
+ <div class=\"container\">
508
+ <span class=\"badge badge-soft mb-3\">Immersive Experience Lab</span>
509
+ <h1 class=\"display-4\">{title}</h1>
510
+ <p class=\"section-lead mx-auto\">打造沉浸式数字体验,融合艺术美学、交互叙事与工程实现,让品牌被看见、被记住。</p>
511
+ <div class=\"d-inline-flex gap-3 mt-4\">
512
+ <a href=\"#showcase\" class=\"btn btn-primary btn-lg\">探索世界观</a>
513
+ <a href=\"#services\" class=\"btn btn-outline-light btn-lg\">查看能力矩阵</a>
514
+ </div>
515
+ </div>
516
+ </header>
517
+ """
518
+
519
+ def body_creative() -> str:
520
+ return f"""
521
+ <main>
522
+ <section class=\"section\" id=\"mission\">
523
+ <div class=\"container\">
524
+ <div class=\"row g-4 align-items-center\">
525
+ <div class=\"col-md-6\">
526
+ <div class=\"mission-sphere\" data-bg-topic=\"abstract 3d gradient sphere\"></div>
527
+ </div>
528
+ <div class=\"col-md-6\">
529
+ <span class=\"eyebrow\">设计使命</span>
530
+ <h2 class=\"h3\">我们为先锋品牌构建沉浸式体验</h2>
531
+ <p class=\"text-muted\">融合创意叙事、交互设计与工程能力,让用户在触达的每个瞬间感知品牌世界观。</p>
532
+ <ul class=\"list-check\">
533
+ <li>跨终端视觉与交互统一</li>
534
+ <li>沉浸式故事体验</li>
535
+ <li>工程落地与持续运营</li>
536
+ </ul>
537
+ </div>
538
+ </div>
539
+ </div>
540
+ </section>
541
+
542
+ <section class=\"section section-sm\" id=\"services\">
543
+ <div class=\"container\">
544
+ <span class=\"eyebrow\">能力矩阵</span>
545
+ <h2 class=\"h3\">体验设计全链条服务</h2>
546
+ <div class=\"row g-4\">
547
+ <article class=\"ability-card reveal\" data-topic=\"3d abstract gradient\">
548
+ <h3>世界观构建</h3>
549
+ <p class=\"text-muted\">打造品牌叙事逻辑与视觉体系,让用户沉浸在统一的世界观中。</p>
550
+ </article>
551
+ <article class=\"ability-card reveal\" data-topic=\"ux design futuristic\">
552
+ <h3>交互叙事设计</h3>
553
+ <p class=\"text-muted\">结合交互节奏与微动画语言,构建具有情绪记忆的体验线索。</p>
554
+ </article>
555
+ <article class=\"ability-card reveal\" data-topic=\"creative code art\">
556
+ <h3>创意代码实现</h3>
557
+ <p class=\"text-muted\">通过 WebGL / Three.js 等技术,将创意视觉无缝落地。</p>
558
+ </article>
559
+ </div>
560
+ </div>
561
+ </section>
562
+
563
+ <section class=\"section section-alt\" id=\"showcase\">
564
+ <div class=\"container\">
565
+ <span class=\"eyebrow\">Signature Projects</span>
566
+ <h2 class=\"h3\">沉浸式体验案例</h2>
567
+ <div class=\"row g-4\">
568
+ <article class=\"orbit-card reveal\">
569
+ <div class=\"orbit-card__visual\" data-bg-topic=\"metaverse hero visual\"></div>
570
+ <h3>MetaSpace</h3>
571
+ <p class=\"text-muted\">Web3 沉浸式社区官网,结合粒子动态与实时数据可视化。</p>
572
+ </article>
573
+ <article class=\"orbit-card reveal\">
574
+ <div class=\"orbit-card__visual\" data-bg-topic=\"futuristic product launch\"></div>
575
+ <h3>Nova Launch</h3>
576
+ <p class=\"text-muted\">科技新品发布会互动官网,通过滚动驱动叙事呈现产品亮点。</p>
577
+ </article>
578
+ <article class=\"orbit-card reveal\">
579
+ <div class=\"orbit-card__visual\" data-bg-topic=\"immersive art installation\"></div>
580
+ <h3>Immersive Gallery</h3>
581
+ <p class=\"text-muted\">艺术展览数字门票体验,整合3D展位地图与在线预约。</p>
582
+ </article>
583
+ </div>
584
+ </div>
585
+ </section>
586
+
587
+ <section class=\"section\" id=\"labs\">
588
+ <div class=\"container\">
589
+ <div class=\"row g-4\">
590
+ <div class=\"col-lg-8\">
591
+ <div class=\"labs-capsule reveal\">
592
+ <h3>Experience Lab</h3>
593
+ <p class=\"text-muted\">探索生成式设计、沉浸式叙事与可持续体验的边界,持续迭代最佳实践。</p>
594
+ <ul class=\"tag-list\">
595
+ <li>Generative Design</li>
596
+ <li>Immersive Storytelling</li>
597
+ <li>Creative Code</li>
598
+ <li>Multisensory</li>
599
+ </ul>
600
+ </div>
601
+ </div>
602
+ <div class=\"col-lg-4\">
603
+ <div class=\"lab-stats reveal\">
604
+ <div>
605
+ <span class=\"display-5 fw-bold counter\" data-target=\"42\">0</span>
606
+ <span class=\"text-muted\">Lab Experiments</span>
607
+ </div>
608
+ <div>
609
+ <span class=\"display-5 fw-bold counter\" data-target=\"12\">0</span>
610
+ <span class=\"text-muted\">Awards</span>
611
+ </div>
612
+ </div>
613
+ </div>
614
+ </div>
615
+ </div>
616
+ </section>
617
+
618
+ <section class=\"section section-alt\" id=\"contact\">
619
+ <div class=\"container\">
620
+ <div class=\"contact-capsule reveal\" data-parallax=\"-0.25\">
621
+ <h2 class=\"h3\">合作邀约</h2>
622
+ <p class=\"text-muted\">请留下品牌简介或项目愿景,我们将在 24 小时内联系您。</p>
623
+ <form class=\"row g-3\">
624
+ <div class=\"col-md-6\"><label class=\"form-label\">姓名 / Name</label><input type=\"text\" class=\"form-control\" placeholder=\"Your Name\" required></div>
625
+ <div class=\"col-md-6\"><label class=\"form-label\">邮箱 / Email</label><input type=\"email\" class=\"form-control\" placeholder=\"name@example.com\" required></div>
626
+ <div class=\"col-12\"><label class=\"form-label\">项目愿景 / Project Vision</label><textarea class=\"form-control\" rows=\"3\" placeholder=\"请描述项目背景与期待体验\" required></textarea></div>
627
+ <div class=\"col-12\"><label class=\"form-label\">预算范围 / Budget</label><select class=\"form-select\"><option>¥50k-100k</option><option>¥100k-200k</option><option>¥200k+</option></select></div>
628
+ <div class=\"col-12\"><button class=\"btn btn-primary w-100\" type=\"submit\">发送愿景</button></div>
629
+ </form>
630
+ </div>
631
+ </div>
632
+ </section>
633
+ </main>
634
+
635
+ <footer class=\"footer-creative\">
636
+ <div class=\"container\">
637
+ <div class=\"footer-creative__meta\">
638
+ <span>{title}</span>
639
+ <p>Immersive Experience Lab</p>
640
+ </div>
641
+ <div class=\"footer-creative__links\">
642
+ <a href=\"#services\">能力矩阵</a>
643
+ <a href=\"#showcase\">作品宇宙</a>
644
+ <a href=\"#contact\">成为伙伴</a>
645
+ </div>
646
+ </div>
647
+ </footer>
648
+ """
649
+
650
+ layouts = {
651
+ "ultra_modern": lambda: hero_ultra() + body_ultra(),
652
+ "minimal_elegant": lambda: hero_minimal() + body_minimal(),
653
+ "creative_gradient": lambda: hero_creative() + body_creative(),
654
+ }
655
+
656
+ if isinstance(sections, dict):
657
+ ordered = []
658
+ for key, value in sections.items():
659
+ ordered.append(value if value.strip().startswith("<section") else f"<section>{value}</section>")
660
+ default_content = "\n".join(ordered)
661
+ elif isinstance(sections, list):
662
+ normalized = []
663
+ for block in sections:
664
+ if isinstance(block, str):
665
+ normalized.append(block if block.strip().startswith("<section") else f"<section>{block}</section>")
666
+ default_content = "\n".join(normalized) if normalized else layouts.get(style_key, layouts["ultra_modern"])()
667
+ else:
668
+ default_content = layouts.get(style_key, layouts["ultra_modern"])()
669
+
670
+ html_template = f"""<!DOCTYPE html>
671
+ <html lang=\"zh-CN\">
672
+ <head>
673
+ <meta charset=\"UTF-8\">
674
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
675
+ <title>{title}</title>
676
+ <link rel=\"stylesheet\" href=\"assets/css/style.css\">
677
+ <!-- 兜底响应式图片,防止样式文件未生成时体验过差 -->
678
+ <style>
679
+ img {{ max-width: 100%; height: auto; display: block; }}
680
+ </style>
681
+ </head>
682
+ <body>
683
+ {content if content else default_content}
684
+
685
+ <script src=\"assets/js/main.js\"></script>
686
+ </body>
687
+ </html>"""
688
+
689
+ def is_full_document(s: str) -> bool:
690
+ low = (s or "").lower()
691
+ return "<html" in low or "<!doctype" in low
692
+
693
+ def strip_nested_docs(s: str) -> str:
694
+ low = s.lower()
695
+ start = low.find("<!doctype html", 1)
696
+ while start != -1:
697
+ end = low.find("</html>", start)
698
+ if end == -1:
699
+ break
700
+ s = s[:start] + s[end + len("</html>") :]
701
+ low = s.lower()
702
+ start = low.find("<!doctype html", 1)
703
+ return s
704
+
705
+ def ensure_assets_links(s: str) -> str:
706
+ has_css = "assets/css/style.css" in s
707
+ has_js = "assets/js/main.js" in s
708
+ if "</head>" in s and not has_css:
709
+ s = s.replace("</head>", " <link rel=\"stylesheet\" href=\"assets/css/style.css\">\n</head>")
710
+ if "</body>" in s and not has_js:
711
+ s = s.replace("</body>", " <script src=\"assets/js/main.js\"></script>\n</body>")
712
+ return s
713
+
714
+ try:
715
+ Path(file_path).parent.mkdir(parents=True, exist_ok=True)
716
+ out = html_template
717
+ if content and is_full_document(content):
718
+ doc = strip_nested_docs(content)
719
+ doc = ensure_assets_links(doc)
720
+ out = doc
721
+ with open(file_path, "w", encoding="utf-8") as f:
722
+ f.write(out)
723
+ return f"HTML文件创建成功: {file_path}"
724
+ except Exception as exc: # noqa: BLE001
725
+ raise RuntimeError(f"创建HTML文件失败: {str(exc)}")
726
+
727
+
728
+ def create_menu_page(file_path: str, project_name: str | None = None) -> str:
729
+ """创建餐厅/咖啡店的“菜单”页面"""
730
+ brand = (project_name or "Coffee & Menu").strip()
731
+ title = f"{brand} · 菜单 Menu"
732
+ html_doc = f"""<!DOCTYPE html>
733
+ <html lang=\"zh-CN\">
734
+ <head>
735
+ <meta charset=\"UTF-8\" />
736
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />
737
+ <title>{title}</title>
738
+ <link rel=\"stylesheet\" href=\"assets/css/style.css\" />
739
+ </head>
740
+ <body>
741
+ <header class=\"hero hero-ultra section text-center\" data-bg-topic=\"cozy coffee shop interior, warm light, depth of field\" id=\"home\">
742
+ <div class=\"container hero-inner\">
743
+ <span class=\"badge badge-soft mb-3\">菜单 MENU</span>
744
+ <h1 class=\"display-5 mb-2\">{brand}</h1>
745
+ <p class=\"section-lead mx-auto\">精品咖啡与精致甜点的完美搭配</p>
746
+ </div>
747
+ </header>
748
+
749
+ <main>
750
+ <nav class=\"section section-sm\" aria-label=\"菜单分类导航\">
751
+ <div class=\"container\">
752
+ <ul class=\"nav nav-pills justify-content-center gap-2\">
753
+ <li class=\"nav-item\"><a class=\"nav-link active\" href=\"#coffee\">咖啡 Coffee</a></li>
754
+ <li class=\"nav-item\"><a class=\"nav-link\" href=\"#tea\">茶饮 Tea</a></li>
755
+ <li class=\"nav-item\"><a class=\"nav-link\" href=\"#desserts\">甜点 Desserts</a></li>
756
+ <li class=\"nav-item\"><a class=\"nav-link\" href=\"#signature\">招牌 Specials</a></li>
757
+ </ul>
758
+ </div>
759
+ </nav>
760
+
761
+ <section class=\"section\" id=\"coffee\">
762
+ <div class=\"container\">
763
+ <h2 class=\"h3 text-center mb-4\">手工咖啡 Coffee</h2>
764
+ <div class=\"row g-4\">
765
+ <article class=\"menu-card reveal col-md-4\">
766
+ <img data-topic=\"latte art, coffee cup, warm light\" alt=\"精品拿铁\" class=\"img-fluid rounded shadow-sm\">
767
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
768
+ <h3 class=\"h5 mb-0\">招牌拿铁</h3>
769
+ <span class=\"price\">¥ 36</span>
770
+ </div>
771
+ <p class=\"text-muted mt-2\">醇厚意式浓缩搭配自制牛奶泡沫,入口绵密。</p>
772
+ </article>
773
+ <article class=\"menu-card reveal col-md-4\">
774
+ <img data-topic=\"pour over coffee, minimal setup\" alt=\"手冲咖啡\" class=\"img-fluid rounded shadow-sm\">
775
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
776
+ <h3 class=\"h5 mb-0\">单品手冲</h3>
777
+ <span class=\"price\">¥ 42</span>
778
+ </div>
779
+ <p class=\"text-muted mt-2\">精选小农庄豆种,手工萃取层次丰富的水果酸甜。</p>
780
+ </article>
781
+ <article class=\"menu-card reveal col-md-4\">
782
+ <img data-topic=\"cold brew coffee glass\" alt=\"冷萃咖啡\" class=\"img-fluid rounded shadow-sm\">
783
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
784
+ <h3 class=\"h5 mb-0\">冷萃特调</h3>
785
+ <span class=\"price\">¥ 38</span>
786
+ </div>
787
+ <p class=\"text-muted mt-2\">16 小时低温萃取,风味清爽,尾韵甘甜。</p>
788
+ </article>
789
+ </div>
790
+ </div>
791
+ </section>
792
+
793
+ <section class=\"section section-alt\" id=\"tea\">
794
+ <div class=\"container\">
795
+ <h2 class=\"h3 text-center mb-4\">臻选茶饮 Tea</h2>
796
+ <div class=\"row g-4\">
797
+ <article class=\"menu-card reveal col-md-4\">
798
+ <img data-topic=\"matcha latte with latte art\" alt=\"抹茶拿铁\" class=\"img-fluid rounded shadow-sm\">
799
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
800
+ <h3 class=\"h5 mb-0\">宇治抹茶拿铁</h3>
801
+ <span class=\"price\">¥ 38</span>
802
+ </div>
803
+ <p class=\"text-muted mt-2\">选用一番摘宇治抹茶,奶香与茶香层层绽放。</p>
804
+ </article>
805
+ <article class=\"menu-card reveal col-md-4\">
806
+ <img data-topic=\"fruit tea highball glass\" alt=\"鲜果茶\" class=\"img-fluid rounded shadow-sm\">
807
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
808
+ <h3 class=\"h5 mb-0\">初夏鲜果茶</h3>
809
+ <span class=\"price\">¥ 34</span>
810
+ </div>
811
+ <p class=\"text-muted mt-2\">四季鲜果冷泡乌龙,酸甜清爽,层次丰富。</p>
812
+ </article>
813
+ <article class=\"menu-card reveal col-md-4\">
814
+ <img data-topic=\"earl grey tea setup warm light\" alt=\"伯爵茶\" class=\"img-fluid rounded shadow-sm\">
815
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
816
+ <h3 class=\"h5 mb-0\">伯爵奶香</h3>
817
+ <span class=\"price\">¥ 32</span>
818
+ </div>
819
+ <p class=\"text-muted mt-2\">经典佛手柑香气,搭配丝滑奶沫,馥郁优雅。</p>
820
+ </article>
821
+ </div>
822
+ </div>
823
+ </section>
824
+
825
+ <section class=\"section\" id=\"desserts\">
826
+ <div class=\"container\">
827
+ <h2 class=\"h3 text-center mb-4\">法式甜点 Desserts</h2>
828
+ <div class=\"row g-4\">
829
+ <article class=\"menu-card reveal col-md-4\">
830
+ <img data-topic=\"tiramisu close up\" alt=\"提拉米苏\" class=\"img-fluid rounded shadow-sm\">
831
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
832
+ <h3 class=\"h5 mb-0\">经典提拉米苏</h3>
833
+ <span class=\"price\">¥ 42</span>
834
+ </div>
835
+ <p class=\"text-muted mt-2\">马斯卡彭与手指饼干的完美比例,口感细腻柔滑。</p>
836
+ </article>
837
+ <article class=\"menu-card reveal col-md-4\">
838
+ <img data-topic=\"lemon tart minimal\" alt=\"柠檬塔\" class=\"img-fluid rounded shadow-sm\">
839
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
840
+ <h3 class=\"h5 mb-0\">柠檬奶油塔</h3>
841
+ <span class=\"price\">¥ 38</span>
842
+ </div>
843
+ <p class=\"text-muted mt-2\">酸甜平衡的柠檬凝乳,搭配酥脆塔皮。</p>
844
+ </article>
845
+ <article class=\"menu-card reveal col-md-4\">
846
+ <img data-topic=\"croissant bakery setup\" alt=\"可颂\" class=\"img-fluid rounded shadow-sm\">
847
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
848
+ <h3 class=\"h5 mb-0\">黄油可颂</h3>
849
+ <span class=\"price\">¥ 28</span>
850
+ </div>
851
+ <p class=\"text-muted mt-2\">百层黄油折叠,外酥内软,香气浓郁。</p>
852
+ </article>
853
+ </div>
854
+ </div>
855
+ </section>
856
+
857
+ <section class=\"section section-alt\" id=\"signature\">
858
+ <div class=\"container\">
859
+ <h2 class=\"h3 text-center mb-4\">招牌组合 Specials</h2>
860
+ <div class=\"row g-4\">
861
+ <article class=\"menu-card reveal col-md-4\">
862
+ <img data-topic=\"coffee beans with packaging\" alt=\"咖啡礼盒\" class=\"img-fluid rounded shadow-sm\">
863
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
864
+ <h3 class=\"h5 mb-0\">精品豆礼盒</h3>
865
+ <span class=\"price\">¥ 158</span>
866
+ </div>
867
+ <p class=\"text-muted mt-2\">季节限定咖啡豆搭配手冲器具,馈赠自用皆宜。</p>
868
+ </article>
869
+ <article class=\"menu-card reveal col-md-4\">
870
+ <img data-topic=\"coffee and dessert pairing\" alt=\"咖啡甜点双人套餐\" class=\"img-fluid rounded shadow-sm\">
871
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
872
+ <h3 class=\"h5 mb-0\">双人下午茶</h3>
873
+ <span class=\"price\">¥ 128</span>
874
+ </div>
875
+ <p class=\"text-muted mt-2\">两杯咖啡搭配两款甜点,分享美味时光。</p>
876
+ </article>
877
+ <article class=\"menu-card reveal col-md-4\">
878
+ <img data-topic=\"coffee beans roasting\" alt=\"烘焙体验\" class=\"img-fluid rounded shadow-sm\">
879
+ <div class=\"d-flex justify-content-between align-items-center mt-3\">
880
+ <h3 class=\"h5 mb-0\">烘焙体验课</h3>
881
+ <span class=\"price\">¥ 198</span>
882
+ </div>
883
+ <p class=\"text-muted mt-2\">手把手体验烘焙流程,带走专属烘焙豆。</p>
884
+ </article>
885
+ </div>
886
+ </div>
887
+ </section>
888
+ </main>
889
+
890
+ <footer class=\"footer-minimal\"><div class=\"container\"><div class=\"footer-brand\"><span>{brand}</span><p>See you in our cafe</p></div><div class=\"footer-meta\"><span>© {brand}</span><a href=\"mailto:hello@example.com\">hello@example.com</a></div></div></footer>
891
+ <script src=\"assets/js/main.js\"></script>
892
+ </body>
893
+ </html>"""
894
+ return create_html_file(file_path=file_path, title=title, content=html_doc, style="minimal_elegant")
895
+
896
+
897
+ THEME_KEYWORDS: dict[str, tuple[str, ...]] = {
898
+ "transport": ("公交", "巴士", "bus", "交通", "出行", "地铁", "shuttle", "线路", "换乘", "班车"),
899
+ "cafe": ("咖啡", "coffee", "烘焙", "甜点", "饮品", "餐饮", "latte", "menu", "brew"),
900
+ }
901
+
902
+ THEME_ALIASES: dict[str, str] = {
903
+ "public-transport": "transport",
904
+ "transportation": "transport",
905
+ "mobility": "transport",
906
+ "bus": "transport",
907
+ "shuttle": "transport",
908
+ "restaurant": "cafe",
909
+ "food": "cafe",
910
+ "coffee": "cafe",
911
+ "cafe": "cafe",
912
+ }
913
+
914
+ THEME_LIBRARY: dict[str, dict] = {
915
+ "transport": {
916
+ "hero": {
917
+ "tagline": "{brand}",
918
+ "title": "连接亦城出行的每一站",
919
+ "lead": "我们聚合亦城科技中心周边公交线路、站点与换乘数据,提供实时、准确的出行指引。",
920
+ "bg_topic": "smart city bus transit hub at dusk",
921
+ "gallery_topics": [
922
+ "modern city bus stop at golden hour",
923
+ "commuters boarding bus aerial view",
924
+ "urban transit data dashboard in use"
925
+ ],
926
+ },
927
+ "vision": {
928
+ "eyebrow": "我们的使命",
929
+ "title": "让城市出行信息更透明",
930
+ "description": "围绕公交线路的实时数据、站点体验与周边服务,我们构建面向园区、企业与居民的智慧出行服务。",
931
+ "bullets": [
932
+ "多源数据实时汇聚,分钟级更新线路与站点状态",
933
+ "按站点、线路和企业场景提供可视化决策与报表",
934
+ "与运营方协同优化站点设施与换乘体验"
935
+ ],
936
+ "media_topic": "transportation analytics teamwork",
937
+ },
938
+ "metrics": [
939
+ {"value": "180+", "label": "覆盖站点"},
940
+ {"value": "65", "label": "整合线路"},
941
+ {"value": "5min", "label": "数据刷新"},
942
+ {"value": "25+", "label": "合作园区"},
943
+ ],
944
+ "team": [
945
+ {
946
+ "name": "张雪",
947
+ "role": "数据运营负责人",
948
+ "desc": "负责公交线路数据采集、质量监测与指标体系搭建。",
949
+ "topic": "female data analyst working on city transport dashboard",
950
+ },
951
+ {
952
+ "name": "李晨",
953
+ "role": "城市交通研究员",
954
+ "desc": "分析亦城园区出行需求,与运营方共创站点优化方案。",
955
+ "topic": "urban mobility planner reviewing maps",
956
+ },
957
+ {
958
+ "name": "王可",
959
+ "role": "产品体验负责人",
960
+ "desc": "设计出行助手、站点详情与班车服务的用户体验。",
961
+ "topic": "product designer showcasing transit app interface",
962
+ },
963
+ {
964
+ "name": "周阳",
965
+ "role": "技术平台架构师",
966
+ "desc": "构建数据平台、实时监控与多端 API 服务能力。",
967
+ "topic": "software architect in control room",
968
+ },
969
+ ],
970
+ "services": [
971
+ {
972
+ "title": "线路数据中心",
973
+ "desc": "整合亦城 5 公里范围公交线路、站点与换乘关系。",
974
+ "bullets": [
975
+ "实时线路状态与班次频率监测",
976
+ "站点配套、步行换乘与周边服务标签",
977
+ "异常事件、绕行信息即时推送",
978
+ ],
979
+ "topic": "city bus map interface on tablet",
980
+ },
981
+ {
982
+ "title": "智能出行助手",
983
+ "desc": "让园区员工与居民快速获取最优出行方案。",
984
+ "bullets": [
985
+ "早晚高峰拥堵预测与出发提醒",
986
+ "收藏常用站点与线路,跨端同步",
987
+ "个性化换乘方案与步行时间估算",
988
+ ],
989
+ "topic": "commuter using mobile transit app",
990
+ },
991
+ {
992
+ "title": "企业班车与定制化服务",
993
+ "desc": "为园区企业提供接驳方案与数据分析。",
994
+ "bullets": [
995
+ "企业定制班车线路规划与动态调整",
996
+ "乘车签到、满载率与满意度数据仪表板",
997
+ "与物业、运营方联动的服务回路",
998
+ ],
999
+ "topic": "corporate shuttle planning meeting",
1000
+ },
1001
+ ],
1002
+ "partners": {
1003
+ "eyebrow": "合作生态",
1004
+ "title": "携手打造智慧出行网络",
1005
+ "items": [
1006
+ "BDA Transit",
1007
+ "Metro Link",
1008
+ "SmartCity Lab",
1009
+ "亦庄产业联盟",
1010
+ "LYF Shuttle",
1011
+ "Urban Data Lab",
1012
+ ],
1013
+ },
1014
+ "culture": {
1015
+ "values_title": "我们的价值观",
1016
+ "values": [
1017
+ "以数据驱动公共交通体验升级",
1018
+ "保持透明、开放的跨部门协作",
1019
+ "以用户出行感受为第一优先",
1020
+ ],
1021
+ "method_title": "我们的工作方法",
1022
+ "methods": [
1023
+ "日常线路巡检与数据校验机制",
1024
+ "园区走访与乘客调研同步推进",
1025
+ "滚动迭代的产品反馈与发布节奏",
1026
+ ],
1027
+ },
1028
+ "cta": {
1029
+ "title": "想要定制园区或企业班车方案?",
1030
+ "lead": "无论是新增线路、优化乘车体验还是数据接口合作,欢迎与我们联系。",
1031
+ "button_text": "提出合作需求",
1032
+ "button_href": "#contact",
1033
+ },
1034
+ "contact": {
1035
+ "address": "北京市经济技术开发区 亦城科技中心",
1036
+ "hours": "工作日 09:00 - 18:00",
1037
+ "email": "contact@yicheng-bus.com",
1038
+ "phone": "+86 010 8888 2025",
1039
+ "social": [
1040
+ {"label": "小程序", "href": "#"},
1041
+ {"label": "企业微信", "href": "#"},
1042
+ {"label": "公众号", "href": "#"},
1043
+ ],
1044
+ "map_topic": "smart bus stop map illustration",
1045
+ },
1046
+ "footer_subtitle": "让出行更简单、更可信。",
1047
+ },
1048
+ "cafe": {
1049
+ "hero": {
1050
+ "tagline": "{brand}",
1051
+ "title": "用一杯咖啡连接亦城人的灵感时刻",
1052
+ "lead": "我们扎根亦城科技中心,每天精选烘焙,为周边社区带来香气、灵感与交谈。",
1053
+ "bg_topic": "artisan coffee shop interior morning light",
1054
+ "gallery_topics": [
1055
+ "fresh roasted coffee beans in roastery",
1056
+ "barista pouring latte art close up",
1057
+ "coffee shop community event evening",
1058
+ ],
1059
+ },
1060
+ "vision": {
1061
+ "eyebrow": "品牌愿景",
1062
+ "title": "把精品咖啡带到工作与生活的每一个瞬间",
1063
+ "description": "我们对风味的研究、空间体验的营造与社区活动的组织,共同构成亦城人的咖啡日常。",
1064
+ "bullets": [
1065
+ "坚持 48 小时内烘焙,锁住豆种原产地风味",
1066
+ "把咖啡学院课程开放给每一位好奇者",
1067
+ "与园区社区联动,打造共享的第三空间",
1068
+ ],
1069
+ "media_topic": "coffee cupping workshop enthusiasts",
1070
+ },
1071
+ "metrics": [
1072
+ {"value": "12年", "label": "品牌历程"},
1073
+ {"value": "18", "label": "手冲配方"},
1074
+ {"value": "120+", "label": "日均服务顾客"},
1075
+ {"value": "5", "label": "联营城市"},
1076
+ ],
1077
+ "team": [
1078
+ {
1079
+ "name": "林暮",
1080
+ "role": "首席烘焙师",
1081
+ "desc": "负责豆种甄选、烘焙曲线设计与杯测标准。",
1082
+ "topic": "coffee roaster inspecting beans",
1083
+ },
1084
+ {
1085
+ "name": "宋以",
1086
+ "role": "体验主理人",
1087
+ "desc": "打造门店陈列、音乐与香气的感官动线。",
1088
+ "topic": "coffee shop manager arranging space",
1089
+ },
1090
+ {
1091
+ "name": "陈路",
1092
+ "role": "咖啡学院教练",
1093
+ "desc": "带领咖啡入门、拉花与杯测课程,培养社区咖啡师。",
1094
+ "topic": "barista teaching latte art class",
1095
+ },
1096
+ {
1097
+ "name": "高礼",
1098
+ "role": "营运经理",
1099
+ "desc": "统筹供应链、会员体系与联名合作。",
1100
+ "topic": "operations manager reviewing cafe dashboard",
1101
+ },
1102
+ ],
1103
+ "services": [
1104
+ {
1105
+ "title": "精品咖啡研发实验室",
1106
+ "desc": "持续探索单品手冲、拼配意式与冷萃新品。",
1107
+ "bullets": [
1108
+ "全程记录豆种、烘焙与萃取参数",
1109
+ "与产区合作,共建季节性风味",
1110
+ "发布杯测报告与风味指南",
1111
+ ],
1112
+ "topic": "coffee lab with tasting notes",
1113
+ },
1114
+ {
1115
+ "title": "空间体验与活动策划",
1116
+ "desc": "为园区与社区打造可聚会、可办公的第三空间。",
1117
+ "bullets": [
1118
+ "定期举办音乐、小型展览与分享会",
1119
+ "提供会客、路演与培训定制布置",
1120
+ "与本地品牌共创限定周边",
1121
+ ],
1122
+ "topic": "coffee shop community event",
1123
+ },
1124
+ {
1125
+ "title": "企业咖啡解决方案",
1126
+ "desc": "为企业提供驻场咖啡吧、咖啡培训与福利礼盒。",
1127
+ "bullets": [
1128
+ "企业驻点咖啡师与移动咖啡车",
1129
+ "员工咖啡入门与精品品鉴课堂",
1130
+ "节日礼盒与专属烘焙纪念豆",
1131
+ ],
1132
+ "topic": "corporate coffee catering setup",
1133
+ },
1134
+ ],
1135
+ "partners": {
1136
+ "eyebrow": "合作伙伴",
1137
+ "title": "与我们一起端出好咖啡",
1138
+ "items": [
1139
+ "Origin Farm",
1140
+ "Brew Lab",
1141
+ "Slow Bar",
1142
+ "亦城社区联盟",
1143
+ "Creative Hub",
1144
+ "City Roast",
1145
+ ],
1146
+ },
1147
+ "culture": {
1148
+ "values_title": "我们的坚持",
1149
+ "values": [
1150
+ "尊重咖啡产区与农作伙伴",
1151
+ "把风味讲给每一位顾客听",
1152
+ "让咖啡空间成为社区链接",
1153
+ ],
1154
+ "method_title": "我们的方式",
1155
+ "methods": [
1156
+ "每日开放杯测,邀请顾客参与评测",
1157
+ "记录每一批烘焙数据并透明公示",
1158
+ "与社区联合发起公益与环保活动",
1159
+ ],
1160
+ },
1161
+ "cta": {
1162
+ "title": "预约烘焙课程或企业咖啡方案",
1163
+ "lead": "欢迎企业福利合作、烘焙课堂与活动场地预约。",
1164
+ "button_text": "联系咖啡顾问",
1165
+ "button_href": "#contact",
1166
+ },
1167
+ "contact": {
1168
+ "address": "北京市经济技术开发区 荣华南路 咖啡共享空间",
1169
+ "hours": "每日 08:00 - 21:00",
1170
+ "email": "hello@yicheng-coffee.com",
1171
+ "phone": "+86 010 6688 2020",
1172
+ "social": [
1173
+ {"label": "微博", "href": "#"},
1174
+ {"label": "小红书", "href": "#"},
1175
+ {"label": "Instagram", "href": "#"},
1176
+ ],
1177
+ "map_topic": "coffee shop map illustration",
1178
+ },
1179
+ "footer_subtitle": "好咖啡与好故事在此相遇。",
1180
+ },
1181
+ "default": {
1182
+ "hero": {
1183
+ "tagline": "{brand}",
1184
+ "title": "与 {brand} 一起创造值得信赖的体验",
1185
+ "lead": "我们帮助团队把愿景落地为可持续增长的数字与空间体验。",
1186
+ "bg_topic": "modern creative studio interior",
1187
+ "gallery_topics": [
1188
+ "design team collaborating on strategy",
1189
+ "customer journey mapping workshop",
1190
+ "developers shipping product features",
1191
+ ],
1192
+ },
1193
+ "vision": {
1194
+ "eyebrow": "愿景",
1195
+ "title": "以策略、体验与技术驱动业务成长",
1196
+ "description": "我们聚焦品牌叙事、体验设计与工程落地,帮助组织在复杂环境中保持增长力。",
1197
+ "bullets": [
1198
+ "深入理解用户旅程与业务需求",
1199
+ "以设计系统保障体验一致性",
1200
+ "以数据驱动快速迭代与优化",
1201
+ ],
1202
+ "media_topic": "team reviewing product roadmaps",
1203
+ },
1204
+ "metrics": [
1205
+ {"value": "120+", "label": "完成项目"},
1206
+ {"value": "50+", "label": "服务行业"},
1207
+ {"value": "98%", "label": "客户满意度"},
1208
+ {"value": "7年", "label": "交付经验"},
1209
+ ],
1210
+ "team": [
1211
+ {
1212
+ "name": "Evelyn Zhang",
1213
+ "role": "体验策略合伙人",
1214
+ "desc": "擅长品牌叙事与体验创新,帮助客户构建可持续的体验体系。",
1215
+ "topic": "female strategist leading workshop",
1216
+ },
1217
+ {
1218
+ "name": "Leo Chen",
1219
+ "role": "产品设计总监",
1220
+ "desc": "负责设计系统、跨平台体验与可视化呈现。",
1221
+ "topic": "ux designer presenting interface",
1222
+ },
1223
+ {
1224
+ "name": "Mia Wu",
1225
+ "role": "产品策略负责人",
1226
+ "desc": "搭建需求洞察与数据分析机制,确保产品迭代与业务目标一致。",
1227
+ "topic": "product manager analyzing data",
1228
+ },
1229
+ {
1230
+ "name": "Jason Li",
1231
+ "role": "技术负责人",
1232
+ "desc": "带领工程团队以高质量代码与自动化流程保障交付。",
1233
+ "topic": "software lead reviewing code",
1234
+ },
1235
+ ],
1236
+ "services": [
1237
+ {
1238
+ "title": "策略洞察",
1239
+ "desc": "帮助品牌厘清定位、价值主张与用户旅程。",
1240
+ "bullets": [
1241
+ "市场与用户调研",
1242
+ "品牌与体验定位",
1243
+ "增长机会识别",
1244
+ ],
1245
+ "topic": "strategy workshop with sticky notes",
1246
+ },
1247
+ {
1248
+ "title": "体验设计",
1249
+ "desc": "从概念到落地,打造兼具美感与可用性的体验。",
1250
+ "bullets": [
1251
+ "跨平台界面设计",
1252
+ "设计系统与组件库",
1253
+ "可用性测试与验证",
1254
+ ],
1255
+ "topic": "designers collaborating on interface",
1256
+ },
1257
+ {
1258
+ "title": "技术工程",
1259
+ "desc": "以现代工程实践保障体验的稳定与性能。",
1260
+ "bullets": [
1261
+ "前端工程与性能优化",
1262
+ "自动化测试与交付",
1263
+ "数据驱动的运维与监控",
1264
+ ],
1265
+ "topic": "developers deploying product",
1266
+ },
1267
+ ],
1268
+ "partners": {
1269
+ "eyebrow": "合作伙伴",
1270
+ "title": "与不同规模的团队携手",
1271
+ "items": [
1272
+ "ALPHA",
1273
+ "NOVA",
1274
+ "FRAME",
1275
+ "UNITY",
1276
+ "ORBIT",
1277
+ "SPECTRA",
1278
+ ],
1279
+ },
1280
+ "culture": {
1281
+ "values_title": "我们的价值观",
1282
+ "values": [
1283
+ "以用户与业务结果为最终衡量",
1284
+ "保持诚实与透明的沟通",
1285
+ "持续学习并拥抱新技术",
1286
+ ],
1287
+ "method_title": "我们的工作方式",
1288
+ "methods": [
1289
+ "跨学科团队共创",
1290
+ "以数据与实验驱动决策",
1291
+ "短周期迭代与可持续交付",
1292
+ ],
1293
+ },
1294
+ "cta": {
1295
+ "title": "准备好与我们合作了吗?",
1296
+ "lead": "告诉我们你的挑战与目标,我们会为你组建合适的项目团队。",
1297
+ "button_text": "与我们交流",
1298
+ "button_href": "#contact",
1299
+ },
1300
+ "contact": {
1301
+ "address": "上海市徐汇区 漕溪北路 333 号",
1302
+ "hours": "工作日 10:00 - 19:00",
1303
+ "email": "hello@example.com",
1304
+ "phone": "+86 021 8888 6666",
1305
+ "social": [
1306
+ {"label": "LinkedIn", "href": "#"},
1307
+ {"label": "Behance", "href": "#"},
1308
+ {"label": "WeChat", "href": "#"},
1309
+ ],
1310
+ "map_topic": "city map illustration",
1311
+ },
1312
+ "footer_subtitle": "以体验驱动业务增长。",
1313
+ },
1314
+ }
1315
+
1316
+
1317
+ def _guess_theme(brand: str, ctx: dict, nav_items: list[dict], site_hint: str) -> str:
1318
+ candidates = []
1319
+ if site_hint:
1320
+ candidates.append(site_hint)
1321
+ for key in ("theme", "site_type", "project_type"):
1322
+ value = ctx.get(key)
1323
+ if isinstance(value, str):
1324
+ candidates.append(value.lower())
1325
+
1326
+ for candidate in candidates:
1327
+ alias = THEME_ALIASES.get(candidate, candidate)
1328
+ if alias in THEME_LIBRARY:
1329
+ return alias
1330
+
1331
+ text_parts = [brand]
1332
+ for key in ("project_description", "project_summary", "description", "mission", "keywords"):
1333
+ value = ctx.get(key)
1334
+ if isinstance(value, str):
1335
+ text_parts.append(value)
1336
+ for item in nav_items:
1337
+ text_parts.append(str(item.get("name", "")))
1338
+ text_parts.append(str(item.get("href", "")))
1339
+
1340
+ text = " ".join(text_parts).lower()
1341
+ for theme_key, keywords in THEME_KEYWORDS.items():
1342
+ if any(keyword in text for keyword in keywords):
1343
+ return theme_key
1344
+
1345
+ return "default"
1346
+
1347
+
1348
+ def create_about_page(
1349
+ file_path: str,
1350
+ project_name: str | None = None,
1351
+ context: dict | None = None,
1352
+ theme: str | None = None,
1353
+ ) -> str:
1354
+ """创建行业感知的“关于我们”页面"""
1355
+
1356
+ brand = (project_name or "Modern Brand").strip()
1357
+ ctx = context.copy() if isinstance(context, dict) else {}
1358
+ nav_items_raw = ctx.get("nav_items") if isinstance(ctx.get("nav_items"), list) else []
1359
+ nav_items: list[dict] = [item for item in nav_items_raw if isinstance(item, dict)]
1360
+
1361
+ site_hint = (theme or ctx.get("theme") or ctx.get("site_type") or "").lower()
1362
+ theme_key = _guess_theme(brand, ctx, nav_items, site_hint)
1363
+ theme_key = THEME_ALIASES.get(theme_key, theme_key)
1364
+ config = THEME_LIBRARY.get(theme_key, THEME_LIBRARY["default"])
1365
+
1366
+ city = ctx.get("city") or ctx.get("region") or ctx.get("area") or ""
1367
+
1368
+ def fmt(value: str | None) -> str:
1369
+ if not value:
1370
+ return ""
1371
+ replacements = {
1372
+ "brand": brand,
1373
+ "project": brand,
1374
+ "city": city or brand,
1375
+ "area": city,
1376
+ }
1377
+ try:
1378
+ return value.format(**replacements)
1379
+ except Exception:
1380
+ return value
1381
+
1382
+ def escape(text: str | None) -> str:
1383
+ return html.escape(text or "")
1384
+
1385
+ hero_cfg = config.get("hero", {})
1386
+ hero_tagline = fmt(hero_cfg.get("tagline"))
1387
+ hero_title = fmt(hero_cfg.get("title")) or f"{brand} · 关于我们"
1388
+ hero_lead = fmt(hero_cfg.get("lead"))
1389
+ hero_bg_topic = hero_cfg.get("bg_topic", "modern gradient background")
1390
+ hero_placeholder = (
1391
+ f"https://placehold.co/1200x800/EEE/31343C?text="
1392
+ f"{urllib.parse.quote_plus(hero_bg_topic[:40])}"
1393
+ )
1394
+ hero_remote = (
1395
+ f"https://image.pollinations.ai/prompt/{urllib.parse.quote_plus(hero_bg_topic)}"
1396
+ "?width=1200&height=800"
1397
+ )
1398
+ hero_style = (
1399
+ f"background-image:url('{hero_placeholder}');"
1400
+ "background-size:cover;background-position:center;background-repeat:no-repeat;"
1401
+ )
1402
+ gallery_topics = hero_cfg.get("gallery_topics", [])
1403
+
1404
+ gallery_html = ""
1405
+ for idx, topic in enumerate(gallery_topics):
1406
+ card_class = "gallery-card tall" if idx == len(gallery_topics) - 1 and len(gallery_topics) > 2 else "gallery-card"
1407
+ gallery_html += (
1408
+ f" <figure class=\"{card_class}\" data-topic=\"{escape(topic)}\"></figure>\n"
1409
+ )
1410
+
1411
+ hero_tagline_html = (
1412
+ f" <span class=\"tagline\">{escape(hero_tagline)}</span>\n" if hero_tagline else ""
1413
+ )
1414
+
1415
+ hero_html = f"""
1416
+ <header class=\"hero hero-minimal section\" data-bg-topic=\"{escape(hero_bg_topic)}\" id=\"home\" style=\"{hero_style}\" data-ai-image=\"bg\" data-remote-bg=\"{hero_remote}\">
1417
+ <div class=\"container hero-inner minimal-grid\">
1418
+ <div class=\"hero-minimal__content\">
1419
+ {hero_tagline_html} <h1 class=\"display-4\">{escape(hero_title)}</h1>
1420
+ <p class=\"section-lead\">{escape(hero_lead)}</p>
1421
+ </div>
1422
+ <div class=\"hero-minimal__gallery\">\n{gallery_html} </div>
1423
+ </div>
1424
+ </header>
1425
+ """
1426
+
1427
+ metrics_cfg = config.get("metrics", [])
1428
+ metrics_html = ""
1429
+ if metrics_cfg:
1430
+ metric_cards = []
1431
+ for metric in metrics_cfg:
1432
+ metric_cards.append(
1433
+ " <div class=\"col-md-3\">\n"
1434
+ " <div class=\"feature-card glass p-4 reveal\" data-tilt>\n"
1435
+ f" <div class=\"display-6 fw-bold\">{escape(fmt(metric.get('value')))}</div>\n"
1436
+ f" <div class=\"text-muted mt-2\">{escape(fmt(metric.get('label')))}</div>\n"
1437
+ " </div>\n </div>\n"
1438
+ )
1439
+ metrics_html = (
1440
+ " <section class=\"section section-sm\">\n"
1441
+ " <div class=\"container\">\n"
1442
+ " <div class=\"row g-4 text-center\">\n"
1443
+ + "".join(metric_cards)
1444
+ + " </div>\n </div>\n </section>\n"
1445
+ )
1446
+
1447
+ vision_cfg = config.get("vision", {})
1448
+ vision_bullets = vision_cfg.get("bullets", [])
1449
+ vision_list_html = "".join(
1450
+ f" <li>{escape(fmt(item))}</li>\n" for item in vision_bullets if item
1451
+ )
1452
+ vision_section_html = ""
1453
+ if vision_cfg:
1454
+ vision_section_html = f"""
1455
+ <section class=\"section\" id=\"vision\">
1456
+ <div class=\"container\">
1457
+ <div class=\"row g-5 align-items-center\">
1458
+ <div class=\"col-lg-6\">
1459
+ <div class=\"vision-capsule reveal\">
1460
+ <span class=\"eyebrow\">{escape(fmt(vision_cfg.get('eyebrow')) or '愿景')}</span>
1461
+ <h2 class=\"h3\">{escape(fmt(vision_cfg.get('title')) or '与团队共同迈向下一程')}</h2>
1462
+ <p class=\"text-muted\">{escape(fmt(vision_cfg.get('description')))}</p>
1463
+ <ul class=\"list-check\">\n{vision_list_html} </ul>
1464
+ </div>
1465
+ </div>
1466
+ <div class=\"col-lg-6\">
1467
+ <div class=\"vision-media reveal\" data-bg-topic=\"{escape(vision_cfg.get('media_topic', 'team collaboration workshop'))}\"></div>
1468
+ </div>
1469
+ </div>
1470
+ </div>
1471
+ </section>
1472
+ """
1473
+
1474
+ team_cfg = config.get("team", [])
1475
+ team_cards_html = ""
1476
+ for member in team_cfg:
1477
+ team_cards_html += f"""
1478
+ <article class=\"team-card reveal col-md-3\">
1479
+ <img data-topic=\"{escape(member.get('topic', 'team portrait'))}\" alt=\"{escape(fmt(member.get('role')) or '团队成员')}\" class=\"img-fluid rounded shadow-sm\">
1480
+ <h3 class=\"h6 mt-3\">{escape(fmt(member.get('name')) or 'Team Member')}</h3>
1481
+ <p class=\"text-muted\">{escape(fmt(member.get('desc')))}</p>
1482
+ </article>\n"""
1483
+ team_section_html = ""
1484
+ if team_cards_html:
1485
+ team_section_html = (
1486
+ " <section class=\"section section-alt\" id=\"team\">\n"
1487
+ " <div class=\"container\">\n"
1488
+ " <span class=\"eyebrow\">团队</span>\n"
1489
+ " <h2 class=\"h3\">核心团队</h2>\n"
1490
+ " <div class=\"row g-4\">\n"
1491
+ + team_cards_html
1492
+ + " </div>\n </div>\n </section>\n"
1493
+ )
1494
+
1495
+ services_cfg = config.get("services", [])
1496
+ service_cards_html = ""
1497
+ for service in services_cfg:
1498
+ bullets = service.get("bullets", [])
1499
+ bullet_html = "".join(
1500
+ f" <li>{escape(fmt(bullet))}</li>\n" for bullet in bullets if bullet
1501
+ )
1502
+ service_cards_html += f"""
1503
+ <article class=\"service-card reveal col-md-4\">
1504
+ <h3>{escape(fmt(service.get('title')))}</h3>
1505
+ <p class=\"text-muted\">{escape(fmt(service.get('desc')))}</p>
1506
+ <ul>\n{bullet_html} </ul>
1507
+ </article>\n"""
1508
+ services_section_html = ""
1509
+ if service_cards_html:
1510
+ services_section_html = (
1511
+ " <section class=\"section\" id=\"services\">\n"
1512
+ " <div class=\"container\">\n"
1513
+ " <span class=\"eyebrow\">我们提供</span>\n"
1514
+ " <h2 class=\"h3\">服务与能力</h2>\n"
1515
+ " <div class=\"row g-4\">\n"
1516
+ + service_cards_html
1517
+ + " </div>\n </div>\n </section>\n"
1518
+ )
1519
+
1520
+ partners_cfg = config.get("partners", {})
1521
+ partner_items = partners_cfg.get("items", [])
1522
+ partners_html = ""
1523
+ if partner_items:
1524
+ partner_spans = "".join(f" <span>{escape(fmt(item))}</span>\n" for item in partner_items)
1525
+ partners_html = f"""
1526
+ <section class=\"section section-alt\" id=\"partners\">
1527
+ <div class=\"container\">
1528
+ <span class=\"eyebrow\">{escape(fmt(partners_cfg.get('eyebrow')) or '合作伙伴')}</span>
1529
+ <h2 class=\"h3\">{escape(fmt(partners_cfg.get('title')) or '与我们同行的伙伴')}</h2>
1530
+ <div class=\"partner-grid\">\n{partner_spans} </div>
1531
+ </div>
1532
+ </section>
1533
+ """
1534
+
1535
+ culture_cfg = config.get("culture", {})
1536
+ values_html = "".join(
1537
+ f" <li>{escape(fmt(item))}</li>\n" for item in culture_cfg.get("values", []) if item
1538
+ )
1539
+ methods_html = "".join(
1540
+ f" <li>{escape(fmt(item))}</li>\n" for item in culture_cfg.get("methods", []) if item
1541
+ )
1542
+ culture_section_html = ""
1543
+ if values_html or methods_html:
1544
+ culture_section_html = f"""
1545
+ <section class=\"section\" id=\"culture\">
1546
+ <div class=\"container\">
1547
+ <div class=\"row g-4\">
1548
+ <div class=\"col-md-6\">
1549
+ <div class=\"culture-card reveal\">
1550
+ <h3>{escape(fmt(culture_cfg.get('values_title')) or '我们的价值观')}</h3>
1551
+ <ul>\n{values_html} </ul>
1552
+ </div>
1553
+ </div>
1554
+ <div class=\"col-md-6\">
1555
+ <div class=\"culture-card reveal\">
1556
+ <h3>{escape(fmt(culture_cfg.get('method_title')) or '我们的工作方式')}</h3>
1557
+ <ul>\n{methods_html} </ul>
1558
+ </div>
1559
+ </div>
1560
+ </div>
1561
+ </div>
1562
+ </section>
1563
+ """
1564
+
1565
+ cta_cfg = config.get("cta", {})
1566
+ cta_html = f"""
1567
+ <section class=\"section\" id=\"cta\">
1568
+ <div class=\"container\">
1569
+ <div class=\"cta-card reveal\" data-parallax=\"-0.25\">
1570
+ <h2 class=\"h3\">{escape(fmt(cta_cfg.get('title')) or '期待与你合作')}</h2>
1571
+ <p class=\"text-muted\">{escape(fmt(cta_cfg.get('lead')))}</p>
1572
+ <a class=\"btn btn-primary btn-lg\" href=\"{escape(cta_cfg.get('button_href') or '#contact')}\">{escape(fmt(cta_cfg.get('button_text')) or '联系团队')}</a>
1573
+ </div>
1574
+ </div>
1575
+ </section>
1576
+ """
1577
+
1578
+ contact_cfg = config.get("contact", {}).copy()
1579
+ contact_override = ctx.get("contact") if isinstance(ctx.get("contact"), dict) else {}
1580
+ contact_cfg.update(contact_override)
1581
+ for key in ("address", "email", "phone", "hours"):
1582
+ override_value = ctx.get(key)
1583
+ if isinstance(override_value, str):
1584
+ contact_cfg[key] = override_value
1585
+ contact_cfg.setdefault("email", "hello@example.com")
1586
+ contact_cfg.setdefault("phone", "+86 021 8888 6666")
1587
+ contact_cfg.setdefault("address", f"{city or '中国'}")
1588
+ contact_cfg.setdefault("hours", "工作日 09:00 - 18:00")
1589
+ contact_cfg.setdefault("social", config.get("contact", {}).get("social", []))
1590
+ contact_cfg.setdefault("map_topic", "city map illustration")
1591
+
1592
+ social_html = "".join(
1593
+ f" <a class=\"btn btn-outline-light btn-sm\" href=\"{escape(fmt(s.get('href')) or '#')}\">{escape(fmt(s.get('label')))}</a>\n"
1594
+ for s in contact_cfg.get("social", [])
1595
+ if isinstance(s, dict)
1596
+ )
1597
+
1598
+ contact_section_html = f"""
1599
+ <section class=\"section section-alt\" id=\"contact\">
1600
+ <div class=\"container\">
1601
+ <div class=\"row g-4\">
1602
+ <div class=\"col-md-6\">
1603
+ <div class=\"contact-card reveal\">
1604
+ <h3>{escape(fmt(contact_cfg.get('title')) or '到访我们')}</h3>
1605
+ <p class=\"text-muted\">{escape(fmt(contact_cfg.get('address')))}</p>
1606
+ <p class=\"text-muted\">{escape(fmt(contact_cfg.get('hours')))}</p>
1607
+ <div class=\"contact-map\" data-bg-topic=\"{escape(contact_cfg.get('map_topic'))}\"></div>
1608
+ </div>
1609
+ </div>
1610
+ <div class=\"col-md-6\">
1611
+ <div class=\"contact-card reveal\">
1612
+ <h3>{escape(fmt(contact_cfg.get('subtitle')) or '联系我们')}</h3>
1613
+ <p class=\"text-muted\">{escape(fmt(contact_cfg.get('email')))}</p>
1614
+ <p class=\"text-muted\">{escape(fmt(contact_cfg.get('phone')))}</p>
1615
+ <div class=\"d-flex flex-wrap gap-2 mt-3\">
1616
+ {social_html} </div>
1617
+ </div>
1618
+ </div>
1619
+ </div>
1620
+ </div>
1621
+ </section>
1622
+ """
1623
+
1624
+ footer_subtitle = escape(fmt(config.get("footer_subtitle")) or "与我们一起创造更多价值。")
1625
+
1626
+ sections_html = "".join(
1627
+ part
1628
+ for part in (
1629
+ metrics_html,
1630
+ vision_section_html,
1631
+ team_section_html,
1632
+ services_section_html,
1633
+ partners_html,
1634
+ culture_section_html,
1635
+ )
1636
+ if part
1637
+ )
1638
+
1639
+ title = f"{brand} · 关于我们"
1640
+ html_doc = f"""<!DOCTYPE html>
1641
+ <html lang=\"zh-CN\">
1642
+ <head>
1643
+ <meta charset=\"UTF-8\" />
1644
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />
1645
+ <title>{escape(title)}</title>
1646
+ <link rel=\"stylesheet\" href=\"assets/css/style.css\" />
1647
+ </head>
1648
+ <body>
1649
+ {hero_html} <main>
1650
+ {sections_html}{cta_html}{contact_section_html} </main>
1651
+
1652
+ <footer class=\"footer-minimal\">
1653
+ <div class=\"container\">
1654
+ <div class=\"footer-brand\">
1655
+ <span>{escape(brand)}</span>
1656
+ <p>{footer_subtitle}</p>
1657
+ </div>
1658
+ <div class=\"footer-meta\">
1659
+ <span>© {escape(brand)}</span>
1660
+ <a href=\"mailto:{escape(fmt(contact_cfg.get('email')))}\">{escape(fmt(contact_cfg.get('email')))}</a>
1661
+ </div>
1662
+ </div>
1663
+ </footer>
1664
+ <script src=\"assets/js/main.js\"></script>
1665
+ </body>
1666
+ </html>"""
1667
+
1668
+ return create_html_file(
1669
+ file_path=file_path,
1670
+ title=title,
1671
+ content=html_doc,
1672
+ style="minimal_elegant",
1673
+ )
1674
+
1675
+
1676
+ def create_contact_page(file_path: str, project_name: str | None = None) -> str:
1677
+ """创建“联系我们”页面"""
1678
+ brand = (project_name or "Modern Brand").strip()
1679
+ title = f"{brand} · 联系我们"
1680
+ html_doc = f"""<!DOCTYPE html>
1681
+ <html lang=\"zh-CN\">
1682
+ <head>
1683
+ <meta charset=\"UTF-8\" />
1684
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />
1685
+ <title>{title}</title>
1686
+ <link rel=\"stylesheet\" href=\"assets/css/style.css\" />
1687
+ </head>
1688
+ <body>
1689
+ <header class=\"hero hero-ultra section text-center\" data-bg-topic=\"customer support modern office\" id=\"home\">
1690
+ <div class=\"container hero-inner\">
1691
+ <span class=\"badge badge-soft mb-3\">Contact</span>
1692
+ <h1 class=\"display-5 mb-2\">与 {brand} 取得联系</h1>
1693
+ <p class=\"section-lead mx-auto\">我们在这里倾听需求、提供支持,帮助你启动或升级项目。</p>
1694
+ </div>
1695
+ </header>
1696
+
1697
+ <main>
1698
+ <section class=\"section\">
1699
+ <div class=\"container\">
1700
+ <div class=\"row g-4\">
1701
+ <div class=\"col-md-5\">
1702
+ <div class=\"contact-info-card reveal\">
1703
+ <h2 class=\"h4 mb-3\">联系渠道</h2>
1704
+ <ul class=\"list-unstyled text-muted\">
1705
+ <li class=\"mb-2\"><strong>邮箱</strong>:hello@example.com</li>
1706
+ <li class=\"mb-2\"><strong>商务合作</strong>:business@example.com</li>
1707
+ <li class=\"mb-2\"><strong>电话</strong>:+86 021 8888 6666</li>
1708
+ <li class=\"mb-2\"><strong>地址</strong>:上海市徐汇区 漕溪北路 333 号 8F</li>
1709
+ </ul>
1710
+ <div class=\"d-flex gap-2 mt-3\">
1711
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">LinkedIn</a>
1712
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">Behance</a>
1713
+ <a class=\"btn btn-outline-light btn-sm\" href=\"#\">WeChat</a>
1714
+ </div>
1715
+ </div>
1716
+ </div>
1717
+ <div class=\"col-md-7\">
1718
+ <h2 class=\"h4 mb-3\">发送消息</h2>
1719
+ <form class=\"contact-form reveal\">
1720
+ <div class=\"field-pair\"><label>姓名</label><input type=\"text\" placeholder=\"您的名字\" required></div>
1721
+ <div class=\"field-pair\"><label>邮箱</label><input type=\"email\" placeholder=\"name@example.com\" required></div>
1722
+ <div class=\"field-pair\"><label>电话</label><input type=\"tel\" placeholder=\"您的联系电话\"></div>
1723
+ <div class=\"field-pair\"><label>留言</label><textarea rows=\"4\" placeholder=\"请描述您的需求或预约时间\" required></textarea></div>
1724
+ <button class=\"btn btn-primary\" type=\"submit\">提交</button>
1725
+ </form>
1726
+ </div>
1727
+ </div>
1728
+ </div>
1729
+ </section>
1730
+
1731
+ <section class=\"section section-alt\">
1732
+ <div class=\"container\">
1733
+ <div class=\"row g-4\">
1734
+ <div class=\"col-md-4\">
1735
+ <div class=\"feature-card glass p-3 reveal\">
1736
+ <strong>营业时间</strong>
1737
+ <ul class=\"text-muted mb-0\" style=\"list-style:none; padding-left:0;\">
1738
+ <li>周一至周五:09:30 - 18:30</li>
1739
+ <li>周六(预约制):10:00 - 16:00</li>
1740
+ </ul>
1741
+ </div>
1742
+ </div>
1743
+ <div class=\"col-md-4\">
1744
+ <div class=\"feature-card glass p-3 reveal\">
1745
+ <strong>项目合作</strong>
1746
+ <p class=\"text-muted mb-1\">欢迎邮件简要介绍品牌现状、目标和时间节点。</p>
1747
+ <p class=\"text-muted mb-0\">我们将在 24 小时内回复。</p>
1748
+ </div>
1749
+ </div>
1750
+ <div class=\"col-md-4\">
1751
+ <div class=\"feature-card glass p-3 reveal\" data-bg-topic=\"city map marker illustration\" style=\"height:200px; border-radius: var(--radius-lg);\" aria-label=\"地图占位\"></div>
1752
+ </div>
1753
+ </div>
1754
+ </div>
1755
+ </section>
1756
+ </main>
1757
+
1758
+ <footer class=\"footer-minimal\"><div class=\"container\"><div class=\"footer-brand\"><span>{brand}</span><p>期待与你合作</p></div><div class=\"footer-meta\"><span>© {brand}</span><a href=\"mailto:hello@example.com\">hello@example.com</a></div></div></footer>
1759
+ <script src=\"assets/js/main.js\"></script>
1760
+ </body>
1761
+ </html>"""
1762
+ return create_html_file(file_path=file_path, title=title, content=html_doc, style="ultra_modern")
1763
+
1764
+
1765
+ __all__ = [
1766
+ "create_html_file",
1767
+ "create_menu_page",
1768
+ "create_about_page",
1769
+ "create_contact_page",
1770
+ ]