Files
cms-SiteForge/themes/trade-pro/pages/case.html
T
浅念 0ec826bd4b feat: port cms case layout into trade-pro
Task 10g: rewrite pages/case.html from the thin 1-line variant to the cms
projects/[slug].astro design (pixel baseline dist/hesupipe/en/projects/):
PageHero (breadcrumb Home > Cases > title, cover bg) + 1.2fr/0.8fr detail
grid (overview block with location/industry rows + rich body via the 10d
typography layer; sticky side column with main photo, 3-col gallery tiles
and Results card) + Recommended Products + Other Projects (groups['case']
minus self), all empty-data sections hidden. Results points come from the
open fields.results convention (semicolon/newline separated); cms
dictionary fallback copy is never ported (fake data across sites).

Listing case branch (10c evaluation): core form (hero + cols-3 cards +
pagination) already matches cms projects list; only the hero copy voice
differed, so listing.html gains a case-aware eyebrow/lead fallback
(OUR PROJECTS). cms-specific tabs (no data source) and the FEATURED CASE
STUDY band (HESU-static dictionary content) stay unported, documented in
the template header.

Adds test_trade_pro_case_layout_structure (build-flow: gallery/results
structure, related-case dedup, empty-data hiding, /cases/ hero voice).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-23 16:59:52 +08:00

128 lines
6.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{# trade-pro case detail — cms 案例详情设计移植(Task 10g)。
区块序列对照 D:/project/cms/runtimes/astro-site-runtime/src/pages/[locale]/projects/[slug].astro
(像素基准 dist/hesupipe/en/projects/<slug>/):
PageHero(面包屑 Home › Cases › 标题 + 封面底图 + 眉题/h1/导语)→
detail-grid 双栏(1.2fr 文案列:Project Overview 眉题 + h2 + ● location/
industry 行 + 富文本正文;0.8fr sticky 侧列:主图 + 3 列相册缩略图 +
Results 成果卡)→ Recommended Products(soft 底产品卡)→ Other Projects
(相关案例卡,排除自身)。
与 cms 的结构决策:
1. cms 文案列是 customerBackground / challenge / solution 三个结构化字段
(空时回退 HESU 词典段落);平台案例只有单一富文本 body——概览块后
正文一整块渲染(10d sf-tp-article-body 排版层双挂),Challenge/
Solution 分段由正文自身的 h2/h3 标题承担;不移植词典兜底段落
(那是 HESU 站点文案,跨站即假数据)。
2. 侧列数据映射:相册 = make_context 的 gallery(cover + fields.gallery
去重,与 10b 产品画廊同源);主图 gallery[0],缩略图全量含首图
(cms 同款,>1 张才渲染缩略图行);无图回退 sf-tp-photo-plain 占位。
Results 成果卡 = fields.results 开放字段(分号/换行分隔要点;cms 的
resultsPoints 词典兜底不移植),空则整段隐藏——绝不编造成果;
✓ 圆徽用 Task 9 check SVG 图标,非文本字符。
3. ● location 行 = blueprints 为 case 定义的字段 location + industry
(cms 的 item.text 单行对应物);均空时行隐藏,概览块(眉题 + h2)
保留 cms 结构位。
4. Recommended Products = 产品/车型前 4(cms fetchProducts 前 4 同构),
空则整段隐藏;Other Projects = groups['case'] 排除自身前 4,动作位
回 /cases/(cms 回 /projects/,平台栏目根)。
5. 页尾 Cta 横幅由 pro.html 的 .pro-end-cta 承担(10b/10d 同决策);
cms 的 CreativeWork JSON-LD 不移植(pro.html 的 og:type=article 已覆盖
分享语义)。 #}
{% set tp_case_others = groups['case']|rejectattr('route','equalto',page.route)|list %}
{% set tp_case_products = (groups['product'] + groups['vehicle'])[:4] %}
{% set tp_results = ((fields.get('results') or '')|string|replace('\r\n','\n')|replace('\r','\n')|replace(';','\n')|trim).split('\n')|map('trim')|reject('equalto','')|list %}
<section class="sf-tp-page-hero sf-tp-case-hero">
{% if safe_image(page.cover) %}<img class="sf-tp-page-hero-bg" src="{{ safe_image(page.cover) }}" alt="" width="1600" height="900" fetchpriority="high" decoding="async">{% endif %}
<div class="sf-tp-page-hero-overlay" aria-hidden="true"></div>
<div class="wrap">
<nav class="sf-tp-breadcrumb" aria-label="Breadcrumb" data-reveal>
<a href="/">Home</a><a href="/cases/">Cases</a><span class="sf-tp-breadcrumb-current">{{ page.title }}</span>
</nav>
<div class="sf-tp-page-hero-copy" data-reveal style="--reveal-i: 1">
<span class="eyebrow">OUR PROJECTS</span>
<h1>{{ page.title }}</h1>
{% if page.summary %}<p class="sf-tp-page-hero-lead">{{ page.summary }}</p>{% endif %}
</div>
</div>
</section>
<section class="section sf-tp-case-detail">
<div class="wrap sf-tp-case-grid">
<div class="sf-tp-case-copy" data-reveal>
<div class="sf-tp-case-overview">
<span class="eyebrow">PROJECT OVERVIEW</span>
<h2>{{ page.title }}</h2>
{% if fields.get('location') %}<p class="sf-tp-case-location"><span aria-hidden="true">●</span> {{ fields.get('location') }}</p>{% endif %}
{% if fields.get('industry') %}<p class="sf-tp-case-location"><span aria-hidden="true">●</span> {{ fields.get('industry') }}</p>{% endif %}
</div>
<div class="sf-tp-case-body sf-tp-article-body">{{ body_copy(content, page) }}</div>
</div>
<div class="sf-tp-case-side">
<div class="sf-tp-photo" data-reveal style="--reveal-i: 1">
{% if gallery %}<img src="{{ gallery[0] }}" alt="{{ page.title }}" width="800" height="600" loading="lazy" decoding="async">
{% else %}<div class="sf-tp-photo-plain" aria-hidden="true"><span>CASE STUDY</span></div>{% endif %}
</div>
{% if gallery|length > 1 %}
<div class="sf-tp-case-gallery" data-reveal style="--reveal-i: 2" aria-label="Project photo gallery">
{% for shot in gallery %}<img src="{{ shot }}" alt="{{ page.title }} photo {{ loop.index }}" width="200" height="140" loading="lazy" decoding="async">{% endfor %}
</div>
{% endif %}
{% if tp_results %}
<div class="sf-tp-case-results" data-reveal style="--reveal-i: 2">
<h3>Results</h3>
<ul>
{% for point in tp_results %}<li><span class="sf-tp-case-check" aria-hidden="true">{{ icon('check', size='12') }}</span>{{ point }}</li>{% endfor %}
</ul>
</div>
{% endif %}
</div>
</div>
</section>
{% if tp_case_products %}
<section class="section section--soft sf-tp-case-products">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">APPLICATIONS</span>
<h2>Recommended products</h2>
</div>
</div>
<div class="sf-tp-card-grid">
{% for tp_item in tp_case_products %}
<article class="sf-tp-card" data-reveal style="--reveal-i: {{ loop.index0 % 4 }}">
<div class="sf-tp-card-media">{{ cover(tp_item, 'product') }}</div>
<div class="sf-tp-card-body">
<h3>{{ tp_item.title }}</h3>
<p>{{ (tp_item.summary or 'Published specifications available on request.').split('.')[0] }}.</p>
<a class="sf-tp-more" href="{{ safe_href(tp_item.route) }}">View details {{ icon('arrow-right', cls='sf-tp-icon--sm') }}</a>
</div>
</article>
{% endfor %}
</div>
</div>
</section>
{% endif %}
{% if tp_case_others %}
<section class="section sf-tp-case-related">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">OUR PROJECTS</span>
<h2>Other projects</h2>
</div>
<a class="sf-tp-more" href="/cases/">View all projects {{ icon('arrow-right', cls='sf-tp-icon--sm') }}</a>
</div>
<div class="sf-tp-card-grid">
{% for tp_item in tp_case_others[:4] %}
<article class="sf-tp-card" data-reveal style="--reveal-i: {{ loop.index0 % 4 }}">
<div class="sf-tp-card-media">{{ cover(tp_item, 'case') }}</div>
<div class="sf-tp-card-body">
<h3>{{ tp_item.title }}</h3>
<p>{{ (tp_item.summary or 'Project reference available on request.').split('.')[0] }}.</p>
<a class="sf-tp-more" href="{{ safe_href(tp_item.route) }}">View details {{ icon('arrow-right', cls='sf-tp-icon--sm') }}</a>
</div>
</article>
{% endfor %}
</div>
</div>
</section>
{% endif %}