c318829ff3
Task 10a (Phase 3 first layout task). home.html now mirrors the cms astro-site-runtime homepage section sequence: full-bleed hero (single active slide; the platform has no multi-slide config, so the carousel dots/JS are not ported), trustbar, two-col about with floating stats, soft products band (4-card grid), dark applications band (2x2 case tiles), advantages feature grid, soft news band (3-card grid), and the closing cta band. Data maps to SiteForge context (page.cover/summary, showcase, cases, stories, category/brand counts); empty sections hide instead of rendering shells. All new component classes are sf-tp-* prefixed and compose on the Task 8 base utilities in theme.css (.wrap/.section/.eyebrow/.icon-circle/.sf-tp-btn). CSS: the five cms components' scoped styles (PageHero, FeatureGrid, CardGrid, Cta, SectionHead + the inline homepage bands) are extracted into pro.css as the sf-tp-* component layer, tokens rewritten to --sf-tp-*, breakpoints 900/767/620 preserved. theme.css accordingly drops the superseded generic .cards/.card/.feature mobile baselines and the .pro-home-hero em bridge, and retargets the dark-surface ghost button hook from .cta-band to .sf-tp-cta. Reveal: cms uses data-reveal everywhere; a ~15-line inline script at the pro.html tail adds html.js + an IntersectionObserver that toggles is-visible (the reduced-motion/no-JS exemptions already live in theme.css from Task 8). Tests: test_theme_registry gains test_trade_pro_home_layout_structure (preview-render contract: sf-tp-hero, card grid, feature grid, cta, no pro-industrial-hero residue, reveal script). The distinct-markup tripwire in test_theme_pro_v3 is legitimately updated 4 -> 5 (renamed to drop the stale "four"): with trade-pro now carrying its own sf-tp-hero class, five themes yield five distinct hero signatures, which is what the test always meant to enforce. Co-Authored-By: Claude Code <noreply@anthropic.com>
43 lines
7.6 KiB
HTML
43 lines
7.6 KiB
HTML
<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><base href="/"><title>{{ seo_title }}</title><meta name="description" content="{{ seo_description }}"><meta property="og:type" content="{{ 'article' if kind in ('article','case') else 'website' }}"><meta property="og:title" content="{{ seo_title }}"><meta property="og:description" content="{{ seo_description }}">{% if canonical %}<meta property="og:url" content="{{canonical}}">{% endif %}<meta name="theme-color" content="{{theme_color}}"><meta name="robots" content="{{ 'noindex,follow' if noindex else page.get('robots','index,follow') }}">{% if canonical and not noindex %}<link rel="canonical" href="{{ canonical }}">{% endif %}<link rel="stylesheet" href="assets/theme.css"><link rel="stylesheet" href="assets/blocks.css"><link rel="stylesheet" href="assets/factory.css"><link rel="stylesheet" href="assets/pro-base.css"><link rel="stylesheet" href="assets/pro.css"><link rel="stylesheet" href="assets/commercial.css">{% if theme_overrides %}<link rel="stylesheet" href="assets/theme-overrides.css">{% endif %}<link rel="stylesheet" href="assets/custom.css"></head><body class="sf-theme-trade-pro pro-trade-pro"><a class="pro-skip" href="#main-content">Skip to content</a>
|
|
{% from '_professional_components.html' import card,cover,grid,section_title,filters,footer_links,body_copy,icon with context %}
|
|
{# English fallback navigation (skeleton): the platform always fills nav with
|
|
Chinese defaults (首页/产品/品牌/新闻/案例/关于/联系) unless the site configured
|
|
its own navigation or published a site design. Detect "unconfigured" by
|
|
comparing the nav href set against the platform default href set (identical
|
|
for the make_context default and the bootstrap navigation), then render the
|
|
English fallback list. Routes are limited to sections every build
|
|
guarantees, so no fallback link can become a broken link. #}
|
|
{% set tp_default_hrefs=['/','/about/','/brands/','/cases/','/contact/','/news/','/products/'] %}
|
|
{% set tp_needs_en_nav=(not chrome_is_custom) and (nav|map(attribute='route')|list|sort==tp_default_hrefs) %}
|
|
{# Known false-positive window: the legacy nav editor can save settings.nav with
|
|
custom titles but no published site design (chrome_is_custom stays false). If
|
|
such a nav happens to keep exactly the default 7 hrefs, its titles are
|
|
overridden by the English fallback below. Mitigated (not eliminated) by
|
|
keeping all 7 default sections so only the labels change, never coverage. #}
|
|
{% set tp_nav=[{'title':'Home','route':'/'},{'title':'Products','route':'/products/'},{'title':'Brands','route':'/brands/'},{'title':'News','route':'/news/'},{'title':'Cases','route':'/cases/'},{'title':'About','route':'/about/'},{'title':'Contact','route':'/contact/'}] if tp_needs_en_nav else nav %}
|
|
{% if chrome_is_custom %}<div class="pro-utility"{% if not chrome.header.show_announcement %} hidden{% endif %}><div class="pro-wrap"><span>{{ chrome.header.announcement }}</span><span>{{ site.tagline or site.name }}</span></div></div>{% else %}<div class="pro-utility"><div class="pro-wrap"><span>GLOBAL SOURCING · QUALITY · DELIVERY</span><span>INTERNATIONAL B2B SOLUTIONS</span></div></div>{% endif %}
|
|
<header class="sf-site-head pro-header"><div class="pro-wrap pro-head-inner"><a class="pro-logo" href="/" aria-label="{{site.name}} home">{% if safe_image(site.logo) %}<img class="pro-brand-logo" src="{{safe_image(site.logo)}}" alt="{{site.name}} Logo">{% else %}<span class="pro-logo-symbol">▣</span>{% endif %}<span class="pro-logo-name">{{site.name}}<small> GLOBAL B2B</small></span></a><button class="pro-mobile-toggle" type="button" data-pro-menu aria-controls="pro-navigation" aria-expanded="false" aria-label="Open navigation">☰</button><nav id="pro-navigation" class="pro-navigation" aria-label="Main navigation">{% for link in tp_nav %}{% if link.children %}<div class="pro-nav-group"><a href="{{link.route}}">{{link.title}}</a><button type="button" class="pro-nav-disclose" aria-expanded="false" aria-label="Expand {{link.title}} submenu">{{ icon('chevron-down', cls='sf-tp-icon--sm') }}</button><div class="pro-nav-children" hidden>{% for child in link.children %}<a href="{{child.route}}">{{child.title}}</a>{% for leaf in child.children %}<a class="pro-nav-leaf" href="{{leaf.route}}">— {{leaf.title}}</a>{% endfor %}{% endfor %}</div></div>{% else %}<a href="{{link.route}}">{{link.title}}</a>{% endif %}{% endfor %}{% if chrome.header.show_search %}<a class="pro-search-link" href="/search/">Search {{ icon('search', cls='sf-tp-icon--sm') }}</a>{% endif %}</nav><button class="pro-catalog-toggle" type="button" data-pro-catalog aria-controls="pro-mega-content" aria-expanded="false">Products {{ icon('chevron-down', cls='sf-tp-icon--sm') }}</button>{% if chrome_is_custom %}{% if chrome.header.show_cta %}<a href="{{chrome.header.cta_href}}" class="sf-tp-btn pro-header-cta">{{chrome.header.cta_text}} <span>{{ icon('arrow-right') }}</span></a>{% endif %}{% else %}<a href="/contact/" class="sf-tp-btn pro-header-cta">Request a Quote <span>{{ icon('arrow-right') }}</span></a>{% endif %}</div>{% if categories %}<div class="pro-mega pro-wrap" data-pro-mega id="pro-mega-content" hidden><span>Product categories</span><div>{% for cat in categories[:12] %}<a href="{{cat.url}}">{{cat.name}} {{ icon('arrow-right') }}</a>{% endfor %}</div></div>{% endif %}</header>
|
|
{% if not designer_replace %}{% include 'trade-pro/pages/' ~ kind ~ '.html' %}{% endif %}
|
|
|
|
{% if has_custom and kind!='notfound' %}<main id="main-content" class="sf-canvas pro-custom-content">{{custom_blocks}}</main>{% else %}<main id="main-content" class="sf-canvas pro-custom-content" aria-hidden="true"></main>{% endif %}
|
|
{% if kind not in ('notfound','search') %}<section class="pro-end-cta"><div class="pro-wrap"><div><span class="pro-eyebrow">LET'S CONNECT</span><h2>Ready to source with confidence?</h2><p>{{site.tagline or 'Send your specifications and get a quotation within one business day.'}}</p></div><a class="sf-tp-btn" href="/contact/">Contact us <span>{{ icon('arrow-right') }}</span></a></div></section>{% endif %}
|
|
<footer class="sf-site-foot pro-footer"><div class="pro-wrap"><div class="pro-footer-top"><div><span class="pro-eyebrow">TRADE PARTNERSHIP</span><h2>{{chrome.footer.title or site.name}}</h2><p>{{footer_text if (chrome_is_custom or footer_text) else 'Quality products, transparent specifications and dependable worldwide delivery.'}}</p></div><div class="pro-footer-links">{{footer_links(tp_nav if footer_nav else [])}}</div><div><span class="pro-eyebrow">BUSINESS ENQUIRY</span><p>{% if footer_email %}<a href="mailto:{{footer_email}}">{{footer_email}}</a>{% else %}Configure the business email in the admin console.{% endif %}</p></div></div><div class="pro-footer-bottom"><span>© {{year}} {{site.name}}</span><span>ENGINEERED FOR GLOBAL TRADE</span></div></div></footer>
|
|
<script defer src="assets/site-runtime.js"></script><script defer src="assets/pro.js"></script>
|
|
<script>
|
|
/* cms reveal port (Task 10a): progressive enhancement only. Without JS or
|
|
IntersectionObserver the html.js class is never set, so [data-reveal]
|
|
content (theme.css) stays visible; reduced-motion is exempted in CSS. */
|
|
(function () {
|
|
if (!('IntersectionObserver' in window)) return;
|
|
document.documentElement.classList.add('js');
|
|
var io = new IntersectionObserver(function (entries) {
|
|
entries.forEach(function (entry) {
|
|
if (!entry.isIntersecting) return;
|
|
entry.target.classList.add('is-visible');
|
|
io.unobserve(entry.target);
|
|
});
|
|
}, { rootMargin: '0px 0px -8% 0px' });
|
|
document.querySelectorAll('[data-reveal]').forEach(function (el) { io.observe(el); });
|
|
})();
|
|
</script></body></html>
|