/* ============================================================
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 (
);
}
function WaGlyph({ size=18 }){
return ;
}
/* ---------------- Purpose glyphs ---------------- */
function PurposeGlyph({ glyph, size=26 }){
const c = "currentColor";
const g = {
coin: ,
rise: ,
sun: ,
shield: ,
lotus: ,
om: ,
};
return ;
}
/* ============================================================
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 (
);
}
/* ---------------- Stars ---------------- */
function Stars({ value=5, size=15 }){
return (
{[0,1,2,3,4].map(i=>(
))}
);
}
/* ---------------- 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 */}
);
}
/* ---------------- 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}
);
}
/* ---------------- Product visual (uploaded photo overrides gem art) ---------------- */
function ProductVisual({ p, size=188, form }){
if(p && p.image){
return
})
;
}
return
;
}
/* ---------------- expose ---------------- */
Object.assign(window, {
Nav, rrRouteHref, rrImgSrc, rrProductAlt, Icon, WaGlyph, PurposeGlyph, GemArt, ProductVisual, Stars, Reveal, Logo, Header, Footer, ProductCard, STONE,
});