/* 慶宜僱傭代理 — UI kit shared primitives, chrome & visual meta (browser-babel) Copy lives in i18n.jsx (window.HY_I18N). This file holds components + the visual meta (icons / tones / dot colours) that pairs with that copy. */ /* ---------------- Icon (Lucide) ---------------- */ function Icon({ n, style }) { return ; } function refreshIcons() { if (window.lucide) window.lucide.createIcons(); } /* ---------------- Visual meta (parallel-indexed to i18n copy) ---------------- */ const SVC_META = [ { i: "plane", tone: "neutral" }, { i: "home", tone: "success" }, { i: "file-text", tone: "neutral" }, { i: "baby", tone: "gold" }, { i: "heart-handshake", tone: "gold" }, { i: "graduation-cap", tone: "gold" }, { i: "refresh-cw", tone: "neutral" }, { i: "shield-check", tone: "neutral" }, { i: "stamp", tone: "solid-gold" }, ]; const REGION_DOTS = ["var(--c-or)", "var(--c-or)", "var(--c-or)"]; const TRUST_ICONS = ["badge-check", "stamp", "receipt-text", "handshake"]; const tileMod = (i) => i % 3 === 1 ? " icotile--gold" : i % 3 === 2 ? " icotile--lime" : ""; /* ---------------- Wordmark ---------------- */ function Wordmark({ dark = false, mono = false }) { return ( e.preventDefault()} href="#"> {!mono && ( 慶宜僱傭代理 Hing Yee · Est. 1985 )} ); } /* ---------------- Primitives ---------------- */ /* WhatsApp deep link (all WhatsApp CTAs point here) */ const WA_NUMBER = "85244127906"; const WA_LINK = "https://wa.me/" + WA_NUMBER; function waLink(t) { const msg = (t && t.waMsg) || ""; return msg ? `${WA_LINK}?text=${encodeURIComponent(msg)}` : WA_LINK; } function Btn({ children, variant = "primary", size = "", icon, iconRight, href, external, onClick, ...rest }) { const cls = ["btn", `btn--${variant}`, size ? `btn--${size}` : ""].filter(Boolean).join(" "); const handle = (e) => { if (!href) e.preventDefault(); if (onClick) onClick(e); }; return ( {icon && } {children && {children}} {iconRight && } ); } function Badge({ children, tone = "neutral", dot }) { return {dot && }{children}; } /* ---------------- Section header ---------------- */ function SectionHead({ eyebrow, title, lede, center }) { return (
{eyebrow && {eyebrow}}

{lede &&

{lede}

}

); } /* ---------------- Photo ---------------- */ function Photo({ label, style, src, alt, children }) { if (src) { return (
{alt {children}
); } return (
{label} {children}
); } /* ---------------- Nav ---------------- */ function SiteNav({ page, setPage, lang, setLang, t }) { const [open, setOpen] = React.useState(false); const items = [["home", t.nav.home], ["about", t.nav.about], ["database", t.nav.database], ["cases", t.nav.cases], ["process", t.nav.process], ["blog", t.nav.blog], ["contact", t.nav.contact]]; const go = (id) => { setPage(id); setOpen(false); }; return ( ); } /* ---------------- Helper card (shared: carousel + database) ---------------- */ function HelperCard({ p, t, onBook }) { const H = t.helperSection; return (
{p.years} {H.yrsLabel} {p.rating} {p.nat && {p.nat}}

{p.name} {p.age}

{p.skills.map((s) => {s})}

{p.blurb}

{H.cta}
); } /* ---------------- Trust bar ---------------- */ function TrustBar({ t }) { return (
{t.trust.map((it, i) => (
{it.t}{it.s}
))}
); } /* ---------------- CTA band ---------------- */ function CTABand({ setPage, t }) { return (

{t.cta.title}

{t.cta.p}

{t.cta.btn1} {t.cta.btn2}
); } /* ---------------- Footer ---------------- */ function SiteFooter({ setPage, t }) { const f = t.footer; return ( ); } /* ---------------- WhatsApp float ---------------- */ function WhatsApp({ t }) { return ; } /* ---------------- Helper showcase carousel ---------------- */ function HelperCarousel({ t, setPage }) { const H = t.helperSection; const onBook = () => setPage && setPage("contact"); const railRef = React.useRef(null); const scroll = (dir) => { const el = railRef.current; if (!el) return; const card = el.querySelector(".hcard"); const w = card ? card.offsetWidth + 18 : 320; const start = el.scrollLeft; const target = Math.max(0, Math.min(start + dir * w, el.scrollWidth - el.clientWidth)); el.style.scrollSnapType = "none"; const dur = 360, t0 = Date.now(); const ease = (p) => 1 - Math.pow(1 - p, 3); const id = setInterval(() => { const p = Math.min(1, (Date.now() - t0) / dur); el.scrollLeft = start + (target - start) * ease(p); if (p >= 1) { clearInterval(id); el.scrollLeft = target; el.style.scrollSnapType = ""; } }, 16); }; return (
{H.eyebrow}

{H.title}

{H.lede}

{t.helpers.map((p, i) => (
))}
); } /* ---------------- Why-us (data + icons) ---------------- */ function WhyUs({ t }) { const W = t.ext.whyus; return (
{W.items.map((it, i) => (
{it.n}
{it.l}

{it.d}

))}
); } /* ---------------- Process timeline ---------------- */ function ProcessTimeline({ t, compact }) { const P = t.ext.process; const icons = ["phone-call", "user-search", "calendar-check", "file-text", "plane-landing", "life-buoy"]; return (
{P.steps.map((s, i) => (
{String(i + 1).padStart(2, "0")}

{s.t}

{s.d}

))}
); } /* ---------------- Cases grid ---------------- */ function CasesGrid({ t, limit }) { const C = t.ext; const list = limit ? C.cases.slice(0, limit) : C.cases; return (
{list.map((c, i) => (
{c.family}
{C.caseFields.needL}

{c.need}

{C.caseFields.resultL}

{c.result}

「{c.quote}」— {c.who}
))}
); } /* ---------------- Google-style reviews ---------------- */ function GoogleReviews({ t }) { const R = t.ext.reviews, list = t.ext.reviewList; return (
G
4.8 ★★★★★
{R.source}
{list.map((r, i) => (
{r.init}
{r.who}
{r.d}
G
{"★".repeat(r.stars)}{"★".repeat(5 - r.stars)}

{r.text}

))}
); } Object.assign(window, { Icon, refreshIcons, Wordmark, Btn, Badge, SectionHead, Photo, waLink, WA_LINK, SiteNav, TrustBar, CTABand, SiteFooter, WhatsApp, HelperCarousel, HelperCard, WhyUs, ProcessTimeline, CasesGrid, GoogleReviews, SVC_META, REGION_DOTS, TRUST_ICONS, tileMod, });