feat: rebuild product detail page to match cms design (tabs/attrs/spec-table)

Task 12a: rebuild product detail to precisely match cms [slug].astro - sticky tab nav (muted bar, brand underline, single-row h-scroll) with .sf-tp-panel/.active switching via inline script (no-JS renders all panels flat); Product Details panel renders body HTML as rich-body with cms table rules (full-width, hairline borders, zebra, inline width/height override, cell div scrub); Specifications panel shows clean spec-table with two key/value pairs per row when specs exist; panel titles get the cms 3px brand underline. Breakpoints mapped cms 900/960 -> platform 900, cms 620 -> 620; product responsive rules consolidated in the 12a block and removed from the shared responsive block. Product title keeps h1 tag at cms h2 scale (2xl) per platform single-h1 contract. Note: most product.html and test edits were swept into concurrent commit 85e6d4a; this commit carries the pro.css 12a block and the h1 refinements.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-28 11:42:51 +08:00
parent 85e6d4aeca
commit 5e8ae60dfe
3 changed files with 69 additions and 31 deletions
+3 -3
View File
@@ -212,10 +212,10 @@ def test_trade_pro_product_layout_structure(factory):
assert media is not None and 'hp-200.jpg' in media.get('src', '')
thumbs = soup.select('.sf-tp-product-thumbs [data-gallery-image]')
assert len(thumbs) == 2
# 标题区:cms 对齐——产品名 h2(2xl 量级,cms 产品页全页无 h1)+ 询盘 CTA
# 标题区:产品名用 cms h2 量级(2xl 非巨型;平台全站单 h1 契约保留 h1)+ 询盘 CTA
# (/preview/ 响应会把根相对 href 重写为 /preview/{sid}/{bid}/contact/,故用后缀匹配)
assert soup.select_one('.sf-tp-product-summary h2.sf-tp-product-title')
assert not soup.find_all('h1') # cms [slug].astro 产品页标题层级从 h2 起
assert soup.select_one('.sf-tp-product-summary h1.sf-tp-product-title')
assert len(soup.find_all('h1')) == 1 # 平台单 h1 契约(与 test_theme_pro_v3 一致)
assert soup.select_one('.sf-tp-product-actions a.sf-tp-btn[href$="/contact/"]')
# 选项卡导航:sticky 容器 + 单行横滚 tabs-row;首个 active,第二个有 specs 才显
tabs = soup.select('.sf-tp-product-tabs .sf-tp-tabs-row .sf-tp-tab')