/* ============================================================
Guero's Group — Shared design system, i18n & primitives
============================================================ */
const { useState, useEffect, useRef, useContext, createContext, createElement } = React;
/* ---------- i18n ---------- */
let LANG = "fr"; // current language (module global, set by App each render)
function L(en, fr) { return LANG === "fr" ? fr : en; }
function setActiveLang(l) { LANG = l; }
const LangCtx = createContext({ lang: "fr", setLang: () => {} });
const NavCtx = createContext({ view: "home", go: () => {} });
/* ---------- Company data (Rent A Car Niger / Guero's Group) ---------- */
const CONTACT = {
company: "Guero\u2019s Group",
legal: "Rent A Car Niger Sarl",
address: "Boulevard de l\u2019Ind\u00e9pendance, Immeuble Asusu",
po: "BP 11.235",
city: "Niamey, Niger",
tel: "+227 20 74 20 40",
mobile: "+227 80 80 80 80",
mobile2: "+227 96 97 67 33",
email: "infos@guerosgroup.com",
web: "guerosgroup.com",
since: "2007",
lat: 13.5170, lon: 2.1100,
};
/* Clients & partners — brand icons via Google favicon service (reliable), flags via flag CDN, monogram fallback */
const CLIENTS = [
{ name: "Airtel", domain: "airtel.africa", logo: "assets/logos/airtel.avif" },
{ name: "Ericsson", domain: "ericsson.com", logo: "assets/logos/ericsson.png" },
{ name: "Orange", domain: "orange.com", logo: "assets/logos/orange.png" },
{ name: { en: "World Bank", fr: "Banque Mondiale" }, domain: "worldbank.org", logo: "assets/logos/worldbank.png" },
{ name: { en: "UNDP", fr: "PNUD" }, domain: "undp.org", logo: "assets/logos/pnud.jpg" },
{ name: { en: "European Union", fr: "Union Europ\u00e9enne" }, domain: "europa.eu", logo: "assets/logos/eu.avif" },
{ name: "JICA", domain: "jica.go.jp", logo: "assets/logos/jica.png" },
{ name: "UNODC", domain: "unodc.org", logo: "assets/logos/unodc.png" },
{ name: "Chemonics", domain: "chemonics.com", logo: "assets/logos/chemonics.jpg" },
{ name: "BCEAO", domain: "bceao.int", logo: "assets/logos/bceao.jpg" },
{ name: "BOAD", domain: "boad.org", logo: "assets/logos/boad.jpg" },
{ name: "CNPC", domain: "cnpc.com.cn", logo: "assets/logos/cnpc.webp" },
{ name: { en: "Embassy of the USA", fr: "Ambassade des USA" }, flag: "us", logo: "assets/logos/embassy-us.png" },
{ name: { en: "Embassy of Japan", fr: "Ambassade du Japon" }, flag: "jp", logo: "assets/logos/embassy-jp.jpg" },
{ name: { en: "Embassy of Italy", fr: "Ambassade d\u2019Italie" }, flag: "it", logo: "assets/logos/embassy-it.png" },
];
/* ---------- Inline icon set ---------- */
function Icon({ name, size = 20, stroke = 1.7, style }) {
const p = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", style };
const paths = {
arrow: ,
arrowDown: ,
gear: <>>,
key: <>>,
wrench: ,
truck: <>>,
pin: <>>,
phone: ,
mail: <>>,
check: ,
search: <>>,
calendar: <>>,
shield: ,
globe: <>>,
bolt: ,
box: <>>,
car: <>>,
users: <>>,
clock: <>>,
menu: ,
close: ,
chevron: ,
star: ,
plus: ,
gauge: <>>,
leaf: ,
};
return ;
}
/* ---------- Brand wordmark ---------- */
function Logo({ variant = "group", light = false, size = 1, onClick }) {
const sub = { group: null, spares: "AfricaSpares", rent: "Rent-a-Car" }[variant];
const accent = { group: "var(--group)", spares: "var(--spares)", rent: "var(--rent)" }[variant];
const src = light ? "assets/brand/gueros-logo-light.png" : "assets/brand/gueros-logo.png";
return (
);
}
/* ---------- Striped placeholder / scene host ---------- */
function Ph({ label, scene, style, className = "", children }) {
return (
{scene}
{!scene && label && {label}}
{children}
);
}
/* ---------- Scroll reveal ---------- */
function Reveal({ children, delay = 0, as = "div", style, className = "" }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const show = () => el.classList.add("in");
const r = el.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh * 0.92) { setTimeout(show, delay); return; }
let done = false;
const io = new IntersectionObserver((es) => {
es.forEach((e) => { if (e.isIntersecting && !done) { done = true; setTimeout(show, delay); io.unobserve(el); } });
}, { threshold: 0.12, rootMargin: "0px 0px -6% 0px" });
io.observe(el);
const t = setTimeout(() => { if (!done) { done = true; show(); io.disconnect(); } }, 1600);
return () => { io.disconnect(); clearTimeout(t); };
}, [delay]);
return createElement(as, { ref, className: "reveal " + className, style }, children);
}
/* ---------- Section label ---------- */
function SectionTag({ n, children, color = "var(--accent)" }) {
return (
{n && {n} / }{children}
);
}
/* ---------- Page header band (inner pages) ---------- */
function PageHeader({ eyebrow, title, sub, accent = "var(--group-d)" }) {
return (
{eyebrow}
{title}
{sub &&
{sub}
}
);
}
/* ---------- Real location map (Niamey) ---------- */
function MapEmbed({ height = 420, rounded = true }) {
const { lat, lon } = CONTACT;
const d = 0.028;
const bbox = `${lon - d}%2C${lat - d * 0.7}%2C${lon + d}%2C${lat + d * 0.7}`;
const src = `https://www.openstreetmap.org/export/embed.html?bbox=${bbox}&layer=mapnik&marker=${lat}%2C${lon}`;
const gmaps = `https://www.google.com/maps/search/?api=1&query=${lat},${lon}`;
return (
);
}
/* ---------- Top navigation (multi-page) ---------- */
function Nav({ variant = "group" }) {
const { view, go } = useContext(NavCtx);
const { lang, setLang } = useContext(LangCtx);
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
const [adminOpen, setAdminOpen] = useState(false);
useEffect(() => {
const f = () => setScrolled(window.scrollY > 24);
f(); window.addEventListener("scroll", f, { passive: true });
return () => window.removeEventListener("scroll", f);
}, []);
const accent = { group: "var(--group)", spares: "var(--spares)", rent: "var(--rent)" }[variant];
const onService = variant !== "group";
const hubLinks = [
{ k: "home", label: L("Home", "Accueil") },
{ k: "group", label: L("The Group", "Le Groupe") },
{ k: "services", label: "Services" },
{ k: "coverage", label: L("Coverage", "Couverture") },
{ k: "contact", label: "Contact" },
];
const links = onService ? [{ k: "home", label: L("\u2190 Guero\u2019s Group", "\u2190 Guero\u2019s Group") }] : hubLinks;
const handleNav = (k) => { setOpen(false); go(k); };
const LangToggle = ({ block }) => (
{["fr", "en"].map((lg) => (
))}
);
return (
go("home")} />