// Shared UI components and SVG placeholders for Think Architecture const { useState, useEffect, useRef } = React; const PARTNERS = [ { name: 'Ballay Architecte', src: 'assets/partners/ballay-architecte.png' }, { name: 'MAF — Mutuelle des Architectes Français', src: 'assets/partners/ordre-architectes-2.png' }, { name: 'Ordre des Architectes', src: 'assets/partners/ordre-architectes-logo.png' }, { name: 'Groupe Qualiconsult', src: 'assets/partners/qualiconsult.png' }, { name: 'GES Études Structures', src: 'assets/partners/ges.png' }, { name: 'GT Structures', src: 'assets/partners/gt-structures.png' }, { name: 'Edifis Études Structures', src: 'assets/partners/edifis.png' }, { name: 'Evally Promotion', src: 'assets/partners/evally-promotion.png' }, { name: 'Matthieu Husser Architectures', src: 'assets/partners/mha-husser.png' }, { name: 'Avenir Investissement', src: 'assets/partners/avenir-investissement.png', dark: true }, { name: 'Bois Conseil', src: 'assets/partners/bois-conseil.png' }, { name: 'Bureau Veritas', src: 'assets/partners/bureau-veritas.png' }, { name: 'Énergies et Fluides', src: 'assets/partners/energies-et-fluides.png' }, { name: 'Globeco', src: 'assets/partners/globeco.png' }, { name: 'Société Régionale de Coordination', src: 'assets/partners/src.png' }, { name: '3D Ingénierie', src: 'assets/partners/3d-ingenierie.png' }, { name: 'BAC', src: 'assets/partners/alpes-controles-bac.png' }, { name: 'Sud-Est Prévention', src: 'assets/partners/sud-est-prevention.png' }]; // === ICONS === function ArrowNE({ size = 14 }) { return ( ); } function ArrowRight({ size = 14 }) { return ( ); } function ArrowLeft({ size = 14 }) { return ( ); } function PlayIcon({ size = 12 }) { return ( ); } // === Architectural SVG placeholder === // Generates a procedural architectural illustration based on a seed string. // Each "image" is unique-looking but stays in our palette. function ArchPlaceholder({ seed = 'a', label = '', tone = 'warm' }) { // Deterministic pseudo-random from seed const hash = Array.from(seed).reduce((a, c) => a + c.charCodeAt(0), 0); const rand = (i) => { const x = Math.sin(hash + i * 9301 + 49297) * 233280; return x - Math.floor(x); }; // Palette options const palettes = { warm: { sky: '#d4c5b8', ground: '#3c240f', mid: '#7a4a2b', accent: '#da734a', light: '#e4dcd5' }, cool: { sky: '#b8b8b8', ground: '#2a2a2a', mid: '#5a5a5a', accent: '#da734a', light: '#d8d8d8' }, forest: { sky: '#c4ccc0', ground: '#2a3528', mid: '#4a5840', accent: '#da734a', light: '#dde0d4' }, snow: { sky: '#dde2e6', ground: '#a0a8b0', mid: '#c4ccd2', accent: '#da734a', light: '#eef0f2' }, dusk: { sky: '#c4a890', ground: '#3a2418', mid: '#7a4a2b', accent: '#da734a', light: '#dccebd' } }; const p = palettes[tone] || palettes.warm; // Pick a composition type from seed const compositionType = Math.floor(rand(1) * 5); return ( {compositionType === 0 && // Modern cabin / wooden building {/* Roof line */} {/* Trees */} } {compositionType === 1 && // Modernist concrete house {/* main volume */} {/* second volume */} {/* windows */} } {compositionType === 2 && // Vertical facade / interior columns {[0, 1, 2, 3, 4, 5, 6, 7].map((i) => )} {[0, 1, 2, 3, 4, 5, 6, 7].map((i) => )} {/* horizontal beam */} {/* light shaft */} } {compositionType === 3 && // Interior with beams / cathedral light {/* perspective floor */} {/* central beam vanishing */} {/* side beams */} {[0, 1, 2, 3].map((i) => { const off = (i + 1) * 90; return ( ); })} {/* horizontals */} } {compositionType === 4 && // Aerial / mountain landscape with structure {/* mountain silhouettes */} {/* foreground */} {/* the building */} } {/* grain overlay */} {label && {label.toUpperCase()} } ); } // === Floor plan placeholder (used as decorative bg) === function FloorPlanBg({ opacity = 0.15 }) { return ( {/* doors */} {/* furniture */} {/* dimensions */} ); } // === Reveal-on-scroll wrapper === function Reveal({ children, delay = 0, as: As = 'div', ...rest }) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setTimeout(() => e.target.classList.add('in'), delay); io.unobserve(e.target); } }); }, { threshold: 0.12 }); io.observe(el); return () => io.disconnect(); }, [delay]); return {children}; } // === NAV === function Nav({ page, navigate }) { const links = [ { id: 'about', label: 'À propos' }, { id: 'projects', label: 'Projets' }, { id: 'home', label: 'Réflexions' }, { id: 'contact', label: 'Contact' }]; // Map "insights" pseudo-link to home anchor const isActive = (id) => { if (id === 'home' && page === 'home') return true; if (id === 'about' && page === 'about') return true; if (id === 'projects' && (page === 'projects' || page === 'project-detail')) return true; if (id === 'contact' && page === 'contact') return true; return false; }; return ( ); } // === FOOTER === function Footer({ navigate }) { return ( ); } // === CLOSING CTA (shared) === function ClosingCTA({ navigate }) { return (
Dessinons votre espace
avec intention.
Que ce soit une résidence privée, une promotion immobilière, un domaine viticole, un projet public ou un loft à aménager — nous serions ravis d'élaborer avec vous votre projet.
); } // === Marquee === function Marquee({ items }) { // Duplicate items so the animation loops seamlessly const doubled = [...items, ...items]; return (
{doubled.map((t, i) => {t} )}
); } // === Partners marquee === function PartnersStrip() { const doubled = [...PARTNERS, ...PARTNERS]; return (
Partenaires & bureaux d'études {String(PARTNERS.length).padStart(2, '0')} collaborateurs de confiance
{doubled.map((p, i) =>
{p.name}
)}
); } Object.assign(window, { ArrowNE, ArrowRight, ArrowLeft, PlayIcon, ArchPlaceholder, FloorPlanBg, Reveal, Nav, Footer, ClosingCTA, Marquee, PartnersStrip });