/* ============================================================ RUDRAA RATNA — shared UI, icons & procedural gem art ============================================================ */ const { useState, useEffect, useRef, useId, useContext, createContext } = React; /* ---------------- Navigation context ---------------- */ const Nav = createContext({ go:()=>{}, route:{page:'home'} }); function rrRouteHref(page, params={}){ return (window.RRSEO && RRSEO.href) ? RRSEO.href(page, params) : '#'; } function rrImgSrc(src){ if(!src) return ''; if(location.protocol === 'file:' && String(src).charAt(0)==='/') return String(src).slice(1); return src; } function rrProductAlt(p){ if(!p) return 'Rudraa Ratna product image'; const parts = [p.name, p.catLabel, 'Rudraa Ratna']; return parts.filter(Boolean).join(' - '); } /* ---------------- Icons ---------------- */ const I = { menu: , close: , search: , cart: , heart: , star: , chevR: , chevD: , arrow: , check: , wa: , shield: , truck: , cert: , pin: , phone: , mail: , clock: , spark: , hand: , leaf: , rise: , coin: , message:, filter: , play: , whats2: null, }; function Icon({ name, size=22, sw=1.6, ...rest }){ return ( {I[name]} ); } function WaGlyph({ size=18 }){ return {I.wa}; } /* ---------------- Purpose glyphs ---------------- */ function PurposeGlyph({ glyph, size=26 }){ const c = "currentColor"; const g = { coin: , rise: , sun: , shield: , lotus: , om: , }; return {g[glyph]||g.sun}; } /* ============================================================ GEM ART — procedural, palette-driven stone visuals ============================================================ */ const STONE = { pyrite: { a:'#EBCB78', b:'#C49A3F', c:'#7C5E22', hi:'#FFF7DA', edge:'#5A4316' }, citrine: { a:'#F8D06C', b:'#E0A02E', c:'#A1610F', hi:'#FFF2CB', edge:'#7E4B0C' }, amethyst: { a:'#C8A8E4', b:'#8A5FB6', c:'#4E2F77', hi:'#F2E6FF', edge:'#3C2360' }, tourmaline: { a:'#74747E', b:'#3A3A41', c:'#17171B', hi:'#ADB2BC', edge:'#0C0C0F' }, rosequartz: { a:'#F7CBD4', b:'#E394A6', c:'#BC6479', hi:'#FFEAEF', edge:'#9C4E62' }, 'sapphire-yellow':{ a:'#F7D662', b:'#D9A62D', c:'#9A6D12', hi:'#FFF4C2', edge:'#7C560B' }, emerald: { a:'#7ACFA4', b:'#2F9D6C', c:'#15613F', hi:'#CEF4E0', edge:'#0E4A30' }, quartz: { a:'#F5F7FA', b:'#D6DCE3', c:'#9FAAB6', hi:'#FFFFFF', edge:'#8893A0' }, rudraksha: { a:'#9E6833', b:'#5F3C1B', c:'#36200E', hi:'#D3A263', edge:'#2A180A' }, }; function GemArt({ stone='pyrite', form='bracelet', size=220 }){ const uid = useId().replace(/[:]/g,''); const s = STONE[stone] || STONE.pyrite; const gid = (n)=> `${stone}-${uid}-${n}`; // shared gradient defs const Defs = ( ); const halo = ; let body = null; if(form==='bracelet'){ const cx=50, cy=49, R=33, n=18, r=6.6; const beads=[]; for(let i=0;i); } body = ( {beads} {/* guru bead + spacer at bottom */} ); } else if(form==='bead'){ // single textured rudraksha-like bead const ridges=[]; for(let i=0;i<6;i++){ const t=(i-2.5)/3; ridges.push(); } const pores=[]; for(let i=0;i<26;i++){ const a=Math.random()*Math.PI*2, rr=Math.random()*28; pores.push(); } body = ( {ridges}{pores} ); } else if(form==='stone'){ // emerald-cut facet gem const oct = (k)=>[[30,18],[70,18],[82,35],[82,65],[70,82],[30,82],[18,65],[18,35]].map(([x,y])=>{ const mx=50+(x-50)*k, my=50+(y-50)*k; return `${mx},${my}`; }).join(' '); body = ( {/* corner facets */} {[[30,18,70,18],[70,18,82,35],[82,65,70,82],[30,82,18,65],[18,35,30,18]].map((q,i)=>( ))} ); } else if(form==='frame'){ body = ( {/* pyrite cluster */} {[[40,52,9],[52,48,11],[46,38,8],[58,56,7],[34,44,6]].map(([x,y,r],i)=>( ))} ); } else if(form==='tower'){ body = ( ); } else if(form==='tree'){ const chips=[]; for(let i=0;i<34;i++){ const a=Math.random()*Math.PI*2, rr=4+Math.random()*18; chips.push(); } body = ( {chips} ); } return (
{Defs}{halo}{body}
); } /* ---------------- Stars ---------------- */ function Stars({ value=5, size=15 }){ return ( {[0,1,2,3,4].map(i=>( {I.star} ))} ); } /* ---------------- Reveal on scroll ---------------- */ function Reveal({ children, delay=0, as='div', className='', style }){ const ref = useRef(null); useEffect(()=>{ const el = ref.current; if(!el) return; const io = new IntersectionObserver((ents)=>{ ents.forEach(e=>{ if(e.isIntersecting){ el.classList.add('in'); io.unobserve(el); } }); }, { threshold:0.12, rootMargin:'0px 0px -8% 0px' }); io.observe(el); return ()=>io.disconnect(); },[]); const Tag = as; return {children}; } /* ---------------- Logo ---------------- */ function Logo({ onDark=false, size=1 }){ const ink = onDark ? '#F5E9CC' : '#57161B'; const gold = '#C19A4B'; return (
Rudraa Ratna
Guided · Authentic
); } /* ---------------- Header ---------------- */ function Header(){ const { go, route } = useContext(Nav); const [open,setOpen] = useState(false); const [scrolled,setScrolled] = useState(false); useEffect(()=>{ const onScroll=()=>setScrolled(window.scrollY>14); onScroll(); window.addEventListener('scroll',onScroll,{passive:true}); return ()=>window.removeEventListener('scroll',onScroll); },[]); useEffect(()=>{ setOpen(false); },[route]); const links = [ { label:'Home', page:'home' }, { label:'Shop', page:'shop' }, { label:'Pyrite', page:'pyrite-landing' }, { label:'Consultation', page:'consultation' }, { label:'Contact', page:'contact' }, ]; const active = (p)=> route.page===p || (p==='shop' && route.page==='product'); return (
॥ श्री ॥ Authentic · Energised · Certificate-ready where applicable {RR.WA_DISPLAY} Noida, India
{/* mobile drawer */}
setOpen(false)}/>
Consult on WhatsApp

॥ शुभं भवतु ॥

); } /* ---------------- Footer ---------------- */ function Footer(){ const { go } = useContext(Nav); return ( ); } /* ---------------- Product card ---------------- */ function ProductCard({ p, delay=0 }){ const { go } = useContext(Nav); return (
go('product',{id:p.id})}>
{p.badges?.includes('bestseller') && Bestseller} {p.badges?.includes('new') && New} {p.badges?.includes('certified') && Certificate-ready} {p.badges?.includes('rare') && Rare} {p.off>=25 && {p.off}% off}
{p.catLabel}
Authenticity guidance available
{RR.fmt(p.price)} {RR.fmt(p.mrp)}
e.stopPropagation()}> Ask on WhatsApp
); } /* ---------------- Product visual (uploaded photo overrides gem art) ---------------- */ function ProductVisual({ p, size=188, form }){ if(p && p.image){ return {rrProductAlt(p)}; } return ; } /* ---------------- expose ---------------- */ Object.assign(window, { Nav, rrRouteHref, rrImgSrc, rrProductAlt, Icon, WaGlyph, PurposeGlyph, GemArt, ProductVisual, Stars, Reveal, Logo, Header, Footer, ProductCard, STONE, });