/* SFS website UI kit — shared chrome: top utility bar, header + mega-menu, footer. Consumes design-system primitives from window.SFSDesignSystem_95f437. */ const DS = window.SFSDesignSystem_95f437; const { Button, ArrowLink, IconButton, SectionLabel } = DS; /* ---------- inline line icons (2px stroke, currentColor) ---------- */ const Ico = { chevron: (p) => , search: (p) => , up: (p) => , arrow: (p) => , linkedin: (p) => , youtube: (p) => , instagram: (p) => , }; const UTILITY = [ { label: 'SFS Global', href: 'https://www.sfs.com', external: true }, { label: 'Sustainability', page: 'sustainability' }, { label: 'Certifications', page: 'certifications' }, { label: 'Career', page: 'careers' }, { label: 'Customers', page: 'customers' }, { label: 'Downloads', page: 'downloads' }, ]; /* Top-level nav — matches the SFS sitemap. caret => has a mega-menu (key in MENUS). */ const NAV = [ { key: 'company', label: 'Company', caret: true }, { key: 'products', label: 'Products', caret: true }, { key: 'applications', label: 'Applications', caret: true }, { key: 'technologies', label: 'Technologies', caret: true }, { key: 'capabilities', label: 'Capabilities', caret: true }, { key: 'customers', label: 'Customers', caret: true }, { key: 'careers', label: 'Careers', caret: false, go: 'careers' }, { key: 'contact', label: 'Contact', caret: false, go: 'contact' }, ]; /* Products mega — image tiles (dark). */ const PRODUCT_TILES = [ { name: 'Engine Components', img: window.SFS_ASSET('../assets/ind-engine.jpg'), go: 'product:engine' }, { name: 'Turbocharger Components', img: window.SFS_ASSET('../assets/ind-turbo.jpg'), go: 'product:turbocharger' }, { name: 'Fuel System Components', img: window.SFS_ASSET('../assets/ind/fuel-banner.jpg'), go: 'product:fuel' }, { name: 'Fluid Power Components', img: window.SFS_ASSET('../assets/infra/fp0.jpg'), go: 'product:fluid' }, { name: 'Aerospace Components', img: window.SFS_ASSET('../assets/aerospace-banner.jpg'), go: 'aerospace' }, { name: 'Safety Components', img: window.SFS_ASSET('../assets/ind/safety-banner.jpg'), go: 'product:safety' }, ]; /* Column-style menus: array of columns, each { head, links:[{t,go}] }. */ const MENUS = { company: [ { head: 'About', links: [ { t: 'About Us', go: 'company' }, { t: "Chairman's Desk", go: 'chairman' }, { t: 'Leadership', go: 'leadership' }, { t: 'Milestones', go: 'milestones' }, ] }, { head: 'Recognition', links: [ { t: 'Certifications', go: 'certifications' }, { t: 'Awards and Achievements', go: 'awards' }, ] }, { head: 'Responsibility', links: [ { t: 'Corporate Social Responsibility', go: 'csr' }, { t: 'Sustainability', go: 'sustainability' }, ] }, ], applications: [ { head: 'Automotive Components', links: [ { t: 'Engine', go: 'product:engine' }, { t: 'Turbochargers', go: 'product:turbocharger' }, { t: 'Fuel Systems', go: 'product:fuel' }, { t: 'Safety', go: 'product:safety' }, ] }, { head: 'Industrial Components', links: [ { t: 'Fluid Power', go: 'product:fluid' }, { t: 'Off Highway Engines', go: 'industry:highway' }, { t: 'Aerospace', go: 'aerospace' }, { t: 'Emission', go: 'industry:emission' }, ] }, { head: 'Riveting', links: [ { t: 'Automotive', go: 'applications' }, { t: 'Electronics', go: 'applications' }, { t: 'Engineering Industry', go: 'applications' }, { t: 'Solar', go: 'applications' }, { t: 'Elevators', go: 'applications' }, ] }, ], technologies: [ { head: 'Technologies', links: [ { t: 'Precision Machining', go: 'tech:precision' }, { t: 'Cold Forming', go: 'tech:coldforming' }, { t: 'Matched Assembly', go: 'tech:matched' }, ] }, ], capabilities: [ { head: 'Capabilities', links: [ { t: 'Integrated Manufacturing', go: 'capabilities#integrated' }, { t: 'Metrology', go: 'capabilities#metrology' }, { t: 'Special Processes', go: 'capabilities#special' }, ] }, { head: 'Facilities', links: [ { t: 'Infrastructure', go: 'infrastructure' }, ] }, ], customers: [ { head: 'Customers', links: [ { t: 'Customers', go: 'customers' }, { t: 'Terms & Conditions — Sales and Delivery', go: 'terms:sales' }, { t: 'Terms & Conditions — Purchasing', go: 'terms:purchasing' }, ] }, ], }; function TopBar({ onNavigate }) { return (
DE | EN
); } function MegaMenu({ which, onNavigate }) { if (which === 'products') { return (
{PRODUCT_TILES.map((it) => ( { e.preventDefault(); onNavigate(it.go); }}> {it.name} {it.name} ))}
); } const cols = MENUS[which]; if (!cols) return null; return (
{cols.map((c) => (
{c.head}
{c.links.map((l) => ( { e.preventDefault(); onNavigate(l.go); }}> {l.t} {Ico.arrow({ width: 15, height: 15, style: { verticalAlign: 'middle' } })} ))}
))}
); } function Header({ page, onNavigate }) { const [open, setOpen] = React.useState(null); const toggle = (n) => { if (!n.caret) { onNavigate(n.go); setOpen(null); return; } setOpen(open === n.key ? null : n.key); }; return (
setOpen(null)}>
{ e.preventDefault(); onNavigate('home'); setOpen(null); }}> SFS
{open && { onNavigate(p); setOpen(null); }} />}
); } function Footer({ onNavigate }) { return ( ); } Object.assign(window, { SFSChrome: { TopBar, Header, Footer, Ico } }); /* Glowing scroll progress for the milestone timeline. Positions a single red fill over the centre rail and fills it from the first dot to the last as the user scrolls. Returns a cleanup fn. */ window.SFSTimelineProgress = function (root) { if (!root) return function () {}; const rails = [...root.querySelectorAll('.sfs-tl__rail')]; const dots = [...root.querySelectorAll('.sfs-tl__dot')]; if (rails.length < 2) return function () {}; let fill = root.querySelector('.sfs-timeline__fill'); if (!fill) { fill = document.createElement('div'); fill.className = 'sfs-timeline__fill'; root.appendChild(fill); } let firstY = 0, lastY = 0, total = 0; function layout() { const rb = root.getBoundingClientRect(); const railRect = rails[0].getBoundingClientRect(); const x = railRect.left - rb.left + railRect.width / 2; const d0 = dots[0].getBoundingClientRect(); const dN = dots[dots.length - 1].getBoundingClientRect(); firstY = d0.top - rb.top + d0.height / 2; lastY = dN.top - rb.top + dN.height / 2; total = Math.max(1, lastY - firstY); fill.style.left = x + 'px'; fill.style.top = firstY + 'px'; } function update() { const rb = root.getBoundingClientRect(); const trigger = window.innerHeight * 0.55; // line ~55% down the viewport // fill snaps from dot to dot: it ends at the furthest dot the trigger has passed let reachedY = firstY; dots.forEach((dot) => { const dr = dot.getBoundingClientRect(); const dy = dr.top - rb.top + dr.height / 2; const isReached = (rb.top + dy) <= trigger; dot.classList.toggle('is-reached', isReached); if (isReached && dy > reachedY) reachedY = dy; }); fill.style.height = Math.max(0, reachedY - firstY) + 'px'; } function onScroll() { update(); } function onResize() { layout(); update(); } layout(); update(); window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onResize); const imgs = root.querySelectorAll('img'); imgs.forEach((im) => im.addEventListener('load', onResize)); return function () { window.removeEventListener('scroll', onScroll); window.removeEventListener('resize', onResize); }; };