User report: product detail page was wrong — section titles are
per-product custom data (CMS wppop_sections migration: Packing &
Delivery / Our Exhibition / Our Certifications / Our Company / FAQ),
not fixed headings; they must drive an anchor tab system like the
CMS [locale]/products/[slug].astro detailTabs.
Data side (both layers, task option 1 + 2):
- theme_pro.product_detail_sections: fields.sections
[{title, content}] JSON is the structured source; legacy sync
output that appended sections as trailing body H2 blocks is
recognized by known/data titles and split out (overview keeps the
rest; same-title blocks dedupe to the structured version; Features
body block drops when fields.features renders it)
- sync_cms_data.build_product: store sections/features as structured
fields JSON, stop appending H2 blocks to the body; stats now count
entries with a sections field
- Specifications table no longer leaks structural JSON field keys
(sections/features/specs/gallery/categories) — scalar spec keys
only
Template side (trade-pro product.html, replaces 12a panel
switching):
- tab sequence is fully data-driven and matches the CMS: Product
Details (always) -> custom sections (data titles) ->
Specifications / Features (shown only when data exists)
- tabs are #anchor links, not panel toggles: all sections render
flat with visible titles (readable and crawlable without JS; native
anchor jump), JS adds smooth scrolling + scrollspy highlight +
tab centering in the horizontal scroll row
- section ids are slug-derived (sec-packing-delivery), duplicate
titles get an index suffix; features grid ports the CMS
detail-feature-row
Tests: test_trade_pro_product_layout_structure rewritten for the
anchor-tab contract — sections via fields, legacy body-H2 fallback,
spec/features conditional tabs, no-sections product showing only
Product Details + Specifications, spec table free of JSON key leaks,
updated pro.css needles. 30 passed; the 1 failure
(test_trade_pro_blocks_visual_bridge) fails identically on the
previous commit (pre-existing, unrelated).
Co-Authored-By: Claude Code <noreply@example.com>
Pull hesupipe published products/news/cases from the CMS control-api
public endpoints (the same refined data src/content/{products,news,cases}.ts
fetch at build time; those TS files are fetchers, not literal arrays) and
sync them into SiteForge entries via login + PATCH/POST:
- match by route slug (product /product/<slug>/, post keeps legacy WP
route on update, slug-col truncation fallback), create when unmatched,
never delete SiteForge-only entries
- port wp-text.ts cleaning (Gutenberg comments, [caption] -> figure,
trailing form blocks, H1 -> H2, wrapInlineInP, excerpt) so bodies land
sanitized (bleach on the API side strips aligncenter classes/styles)
- upload CMS media (/v1/media/... and local /images/ design fallbacks)
through the SiteForge media API, rewriting body refs to media/<file>;
per-target temp-dir cache dedupes uploads across runs
- product fields: color/standard/category + specs dict flattened into
scalar keys (trade-pro Specifications table renders scalars only) +
gallery as semicolon list; post fields: publish_date/category/tags;
case fields: results/location/industry/gallery
- sync site name/tagline from site.ts SITE literal and set locale=en
via PUT /api/i18n/sites/{id}/locale
Verified against a local uvicorn on a temp snapshot of the container DB:
52 products (47 updated + 5 created), 129 posts updated, 0 failures,
181 media covers, idempotent re-run, theme registry tests unchanged
(30 pass, 1 pre-existing failure).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Root causes:
1. Font/color CSS consumption rules were added to platform blocks.css
but editor preview uses the THEME's blocks.css (which lacked them)
2. Reset buttons sent empty string which failed validation → 400 →
preview died silently
Fix: Added --sf-title-size/--sf-text-size/--sf-accent-c/--sf-btn-c
consumption rules to themes/trade-pro/blocks.css; reset now uses
clearStyleField() which deletes the key instead of setting ''.
Co-Authored-By: Claude Code <noreply@anthropic.com>
- blueprints.py: validate + render 5 new style properties as CSS vars
- editor.js: slider controls for title/text size, color pickers for
text/accent/button colors with reset buttons
- blocks.css: CSS variable consumption rules (--sf-title-size, etc.)
Co-Authored-By: Claude Code <noreply@anthropic.com>
- blueprints: register trust_bar (icon/title/text items) and applications_band
(2x2 dark-band tiles) block types; render with escaped items, ordinal icon
fallback, 8-item cap; auto-exposed in editor via /api/editor/blocks and
grouped under business in the studio palette
- blocks.css: platform base layer for both blocks (app/static + trade-pro
Layer A kept verbatim in sync) + trade-pro bridge vocabulary (icon-circle,
hairline dividers, navy->brand gradient band, glass tiles, 900/620
breakpoints, reduced-motion) without touching canvas hooks
- tests: test_trade_pro_home_block_driven covers the full studio-draft
PUT -> publish -> build chain; 8 block types on the homepage, template
markers absent under layout_mode=replace, clean build report
- scripts/setup_home_blocks.py: production write path for site 483295c29ea0
(login -> draft -> publish -> build -> verify); real catalogue counts feed
the stats block; run after the Docker image picks up the new block types
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 13a. Rewrite themes/trade-pro/blocks.css as two layers:
- Layer A: current app/static/blocks.css verbatim (old theme copy was stale,
missing V8.34+ hero slider / layout-variant / card-style rules); keeps all
platform contracts (site-runtime.js hero track, responsive.py 820/540 device
semantics, card-style/fit variants, V8.33.1 section-vs-inner class fix).
- Layer B: .sf-theme-trade-pro scoped bridge to the sf-tp-* template language:
hero (dark gradient + scrim + inverse button), features (soft band + white
cards + icon-circle index), collection (hairline cards, hover lift, 4:3
media, pill tag), image_text (1fr/1.22fr + photo frame), stats (white stat
bar with hairline dividers), cta (gradient band + ghost button), richtext
(article-body typography incl. tables), plus gallery/faq/tabs/carousel/
video/pricing/attributes in the same tokens. 68 distinct --sf-tp-* token
references; breakpoints 900/620 follow the template.
Section backgrounds use a .sf-canvas chain (0,4,0) so they beat pro-base's
later-loading .pro-custom-content rules in both static and editor cascades;
user inline --sf-bg/--sf-fg still win via var() fallbacks; canvas hooks
(block-id attrs, selection outlines, site-design padding/h1 controls)
untouched.
Tests: test_trade_pro_blocks_visual_bridge covers distribution (theme file
served verbatim, not platform), full multi-block DOM structure with pro.js
filter hooks, scoped rule/token/breakpoint contracts and editor-safety
red lines. 36/36 in test_theme_registry + test_theme_pro_v3; full suite
453 passed / 11 failed (identical to pre-change baseline).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Template content was rendering above the block canvas, pushing editable
blocks below the fold. Replace mode shows only blocks in preview,
making the full preview area clickable. Saved layout_mode unchanged.
Co-Authored-By: Claude Code <noreply@anthropic.com>
User feedback: only show configurable nav items, remove template-injected
Products dropdown and Search link.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The api() helper takes positional args, not fetch-style options object.
This caused 'not a valid HTTP method' error on save/publish.
Co-Authored-By: Claude Code <noreply@anthropic.com>
- 外观与设计: nav edit button opens modal directly in workspace,
no page editor redirect needed; add/remove/reorder/edit nav items
with save-draft + publish buttons
- 内容与页面: type tabs now use segmented-control design (active
blue pill group with counts) instead of scattered buttons
Co-Authored-By: Claude Code <noreply@anthropic.com>
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>
Plain overlay (33 items, same-source lineage, zero patch replay).
Theme suites 35/35; full run 453 passed + 10 known Windows env fails
(suspect-module rerun confirms identical failure set).
Live: container 8.34.1-dev.1; hesupipe home leftover industrial-preset
blocks cleared via studio draft+publish flow — home now renders pure
trade-pro template (sf-section/Chinese blocks = 0).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 11 (layout port finale): rebuild the five thin variant pages in the
sf-tp design language, informed by upstream industrial/automotive
1.3.0/1.4.0 information architecture.
- brand: page-hero (breadcrumb Home > Brands > name, cover bg, anchor
button) + related-product card grid (fields.brand == page title) +
brand profile body only when authored; derived placeholder summary
excluded, empty brands get an empty state, never fabricated intros.
- service: page-hero + 1.2/0.8 detail grid (article-body typography +
sticky CTA card with contact/back links); empty body collapses to a
centered solo column with the CTA card kept.
- faq: page-hero + article-body for the rich-text body (platform has no
faq content type; sanitize strips details/summary so the typography
layer carries it, block-driven details coexist via sf-canvas) +
dark contact-guidance card; empty body swaps to an empty state.
- search: adopts the same platform mechanism as all four upstream
themes (site-runtime.js ?q= client search over dist-root
search-index.json); #sf-search/#sf-search-results/#sf-search-count
hooks and .sf-search-page kept as JS contract, panel and injected
result cards restyled via scoped cms-token overrides.
- notfound: branded dark-band 404 (icon macro, giant 404 h1, English
copy, back-home + browse-products buttons); no end-cta.
CSS: Task 11 block appended to pro.css (new sf-tp-* classes only, own
900/620 media queries; shared hero/grid/typography responsive rules
come from existing 10a/10c/10d blocks; search overrides beat
factory.css by specificity without touching hooks).
Tests: test_trade_pro_variant_pages_structure covers brand fixture
(related filtering, empty forms), service/faq body-vs-empty, search
mechanism contract + noindex + index asset, 404 structure, v3 spot
checks (single h1, chrome, SVG arrows) and clean build report.
Co-Authored-By: Claude Code <noreply@anthropic.com>
V8.33.0 absorbed our entire platform patch set as native features
(discovery/env_for macro override/blocks.css priority/type-mapping fix/
frontend entries/locale override) and synced trade-pro from our remote;
V8.33.1 adds HESU PIPE industrial-theme home fixes (1.3.1).
Zero patch re-application this round — all verified native. Theme
suites 35/35; full run 428 passed + same 10 known Windows env fails
(FAILED set unchanged). Live: container 8.33.1-dev.1 healthy, hesupipe
192 entries intact, trade-pro build 203 pages 0 errors.
Patch registry retired to archive — future upgrades are plain overlay.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 10j: reshape the platform chrome DOM (sf-site-head/pro-header/
pro-navigation/pro-mega/pro-footer) into the cms Header.astro/Footer.astro
design via a pure CSS layer in trade-pro pro.css (--pro-* token bridge +
scoped 0,2,0 overrides): sticky glass header, right-aligned semibold nav
with brand underline hover, white dropdown cards with desktop hover/focus
reveal (>=1025px only; drawer semantics below), cms button CTA, dark
four-column-style footer with hairline copyright bar, cms wrap geometry.
Mobile drawer reuses the upstream V8.21.3 four-theme mechanism verbatim
(commercial.css locked styles + pro.js generic [data-pro-menu]/
#pro-navigation hooks trade-pro already emits); mobile_tabs is
template-driven so trade-pro gains the render block (English labels,
data-mobile-open-menu opens the shared drawer).
pro.html: +footer_nav-gated <h3>Quick Links</h3> (cms column heading),
+mobile tabs block. No DOM restructuring elsewhere; site_design data flow
(announcement/CTA/search/footer/mobile_tabs) and pro.js hooks intact.
Tests: +test_trade_pro_chrome_layout (structure/hooks/EN fallback nav/
css evidence/drawer assets + safe-area/mobile_tabs publish cycle).
35 passed in theme suite; full run 364 passed + same 10 known infra fails.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 10h (last regular layout). Design sources: cms applications.astro +
support.astro (generic content pages). Common form = PageHero (eyebrow/h1/
lead + in-page anchor button + cover bg) then content area.
- The structured sections in both sources (application card grid,
FeatureGrid bands, anchor nav strip, doc cards, FAQ) are HESU dictionary
content, not layout - not ported (fake data across sites). The platform
standard page content is the rich-text body: section structure is carried
by the body's own h2/img/tables (10g decision), typeset via the 10d
sf-tp-article-body layer double-attached with sf-tp-standard-body.
- Empty body hides the body section and the hero anchor button (cms
isRichAbout ternary); empty cover/summary hide bg/lead independently.
- Breadcrumb Home > title per platform page-level convention (10e/10f);
support's trailing Cta stays covered by pro.html pro-end-cta.
- Zero new CSS rules: applications.astro itself ships no scoped styles and
the template is pure composition (10c hero / 10b breadcrumb / 10a
section-head / theme.css baselines); decision documented in pro.css.
- Test test_trade_pro_standard_layout_structure: build-flow page entry
asserts hero/body containers; bootstrap /services/ page (meta.
page_template='standard') verifies the template is not route-bound
(explicit meta beats route-prefix inference) and the empty-data hiding.
Co-Authored-By: Claude Code <noreply@anthropic.com>
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>
Task 10f. contact.html rebuilt from contact.astro + LeadForm.astro:
PageHero (breadcrumb/cover bg) -> 0.85/1.25 info+form-card grid ->
rich body section (body only). No-fake-submit dual form: configured
HTTPS form_endpoint renders external form (name/email/message +
pro-honeypot, 10b contract); unconfigured renders no <form> at all,
guidance card with real mailto when footer_email exists. Contact
items render only with real fields (email mailto; no fabricated
phone/address), cms map band dropped (no address data source).
CSS appended to pro.css with own 900/620 media blocks; new test
test_trade_pro_contact_layout_structure covers both shapes.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 10e: rewrite pages/about.html from the 2-row thin variant to the
full cms about page design (about.astro, pixel baseline
dist/hesupipe/en/about/): page hero with breadcrumb + cover backdrop +
in-page anchor button, company intro two-col with derived stats bar,
rich body (gated on body), advantages grid, dark mission band with
gallery backdrop and glass feature cards, gallery-driven facility card
grid (hidden when empty), certifications grid.
Data mapping: about page = ordinary page entry; cms dict-only stats and
factory copy have no platform fields, so stats reuse the 10a home
derivation (products/categories/brands/cases counts, hidden when all
empty) and facility cards are driven by page.cover + fields.gallery
(make_context gallery, deduped, cover first); markFloatImages is not
ported (sanitize strips class attributes, same conclusion as 10d) and
the body renders through body_copy + the 10d sf-tp-article-body
typography layer via dual classing.
CSS lands in pro.css under sf-tp-about-* reusing the 10a/10b/10c
components (two-col, stats, feature/card grids, section head, page
hero, breadcrumb); responsive collapse comes from the existing 10a/10c
media blocks, with about-specific 900/620 rules in a dedicated block
(767 intentionally empty, covered by 10c page-hero).
Tests: test_trade_pro_about_layout_structure drives a data-rich /about/
(PATCHed bootstrap entry with cover/summary/rich body/gallery + product
and post entries) and an empty custom-route about page
(meta.page_template), asserting structure, data mapping, and empty-data
section hiding.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Task 10d: rewrite trade-pro article.html from the thin pro-article
skeleton to the cms news/[slug].astro design (pixel baseline
dist/hesupipe/en/news/<slug>/):
- hero reuses the 10c sf-tp-page-hero component (cover as bg image +
brand-soft overlay) with the breadcrumb inside; the platform contract
class .pro-article-hero stays on the hero section and the pro-base
centered/giant-h1 skeleton is flattened by specificity in pro.css
- meta row (category pill - publish_date - author), rich-text body via
body_copy with a cms rich-body typographic layer, divider, author
card, next-story navigation
- related band below the content: More News side box (120px thumb rows,
3 items, self and next-story excluded) + dark side CTA + back link,
1fr+300px grid collapsing at 900/620
- date field is meta.fields.publish_date (blueprints post definition),
rendered raw as YYYY-MM-DD
- new responsive rules live in the 10d media blocks appended at the end
of pro.css to avoid the 10c source-order cascade trap; the 620 hero
h1 compact size is re-declared at the same specificity because the
10d no-media h1 reset (0,4,0) outranks the 10c 620 rule (0,3,0)
- tests: test_trade_pro_article_layout_structure builds a site with a
cover/date/rich-body post plus 4 other posts and asserts hero/meta/
body/author/next/related structure, .pro-article-hero presence, no
bare arrow characters
Co-Authored-By: Claude Code <noreply@anthropic.com>
- listing grid collapses at 900/620 (source-order fix), route-substring
kind fallback gated to empty non-category listings, section-head shows
item/page counts, Popular reads linked, category h1 assertions
- compose: SITEFORGE_BUILD_TIMEOUT_SECONDS now passed to web service
(enqueue side reads it — upstream gap found during mirror builds)
- chore: ignore runtime state files
Co-Authored-By: Claude Code <noreply@anthropic.com>
Quality review fixes for Task 10c (2 Important + 5 Minor):
- [I1] sf-tp-card-grid--listing now collapses to 2 cols at 900px and
compact gap at 620px: the 3-col declaration sits after the 10a media
blocks in source order, so the fold rules must live in the new 10c
media blocks to win at equal specificity
- [I2] tp_post_like trusts the first listing item's content type when
the list is non-empty; the route-substring fallback now only applies
to empty listings of kind=='listing' — /categories/post-sales-service/
style slugs can no longer flip a product category page into the news
branch
- [M3] empty-state negative assertions check the rendered attribute
string, not the selector literal (previously always true)
- [M4] catalogue section-head intro is now an item/page count instead
of duplicating the hero lead
- [M5] Popular reads entries link to the posts (same data as Latest,
no analytics source on the platform)
- [M6] both /categories/pumps/ pagination pages assert exactly one h1
- [M7] side-panel sticky top uses --sf-tp-space-24
Co-Authored-By: Claude Code <noreply@anthropic.com>