/* shared.jsx — icons, data, primitives */
// ===========================================================
// Icons (small set, hand-tuned)
// ===========================================================
const Icon = {
Crown: ({size = 24}) => (
),
Diamond: ({size = 16}) => (
),
Heart: ({size = 16, filled = false}) => (
),
Search: ({size = 18}) => (
),
Bag: ({size = 18}) => (
),
User: ({size = 18}) => (
),
WhatsApp: ({size = 28}) => (
),
Arrow: ({size = 14, dir = "right"}) => {
const rotate = {right: 0, left: 180, up: -90, down: 90}[dir];
return (
);
},
Plus: ({size = 14}) => (
),
Minus: ({size = 14}) => (
),
Close: ({size = 18}) => (
),
Check: ({size = 14}) => (
),
Map: ({size = 16}) => (
),
Phone: ({size = 14}) => (
),
Globe: ({size = 14}) => (
),
};
// ===========================================================
// PalacesMark — wordmark, drawn as SVG-friendly composite
// ===========================================================
const PalacesMark = ({size = 22}) => (
{ e.preventDefault(); window.__nav && window.__nav('home'); window.scrollTo(0,0); }} style={{display: 'flex', alignItems: 'center', gap: 10}}>
Palaces
JEWELLERY
);
// ===========================================================
// Product data
// ===========================================================
const PRODUCTS = [
{ id: 'aureveris', name: 'Aureveris', cat: 'Bridal', img: 'assets/p-aureveris.webp', price: 48399, metal: 'rose', tag: 'Signature', desc: 'Multi-sapphire lotus crown, set in 18k rose gold with pavé brilliants on a tapered shank.' },
{ id: 'velantrix', name: 'Velantrix', cat: 'Bridal', img: 'assets/p-velantrix.webp', price: 49299, metal: 'white', tag: 'Couture', desc: 'Emerald cabochon framed by a starburst of marquise and round-brilliant diamonds.' },
{ id: 'seraphelis', name: 'Seraphelis', cat: 'Bridal', img: 'assets/p-seraphelis.webp', price: 33199, metal: 'white', desc: 'Bridal cluster with a halo of pavé and side-pavé stones.' },
{ id: 'eagle-ring', name: 'Eagle of Noor — Ring', cat: 'Signature', img: 'assets/p-eagle-ring.webp', price: 23899, metal: 'yellow', tag: 'House Motif' },
{ id: 'eagle-pendant', name: 'Eagle of Noor — Pendant', cat: 'Signature', img: 'assets/p-eagle-pendant.webp', price: 14189, metal: 'yellow' },
{ id: 'imperial-eagle', name: 'Imperial Eagle of Noor', cat: 'Signature', img: 'assets/p-imperial-eagle.webp', price: 30499, metal: 'yellow', tag: 'Couture' },
{ id: 'celeste', name: 'Celeste Crown Eternity', cat: 'Bridal', img: 'assets/p-celeste-crown.webp', price: 33409, metal: 'white', priceFrom: 16769 },
{ id: 'twilight', name: 'Twilight Petal', cat: 'Gemstone', img: 'assets/p-twilight-petal.webp', price: 19600, metal: 'white' },
{ id: 'midnight', name: 'Midnight Tide', cat: 'Gemstone', img: 'assets/p-midnight-tide.webp', price: 19599, metal: 'white' },
{ id: 'prismara', name: 'Prismara Butterfly', cat: 'Gemstone', img: 'assets/p-prismara.webp', price: 12729, metal: 'white' },
{ id: 'magnolia', name: 'Magnolia Earring', cat: 'Couture', img: 'assets/p-magnolia.webp', price: 44899, metal: 'yellow' },
{ id: 'honeycrest', name: 'Honeycrest Earring', cat: 'Earring', img: 'assets/p-honeycrest.webp', price: 20699, metal: 'yellow' },
{ id: 'celestial-leaf', name: 'Celestial Leaf', cat: 'Earring', img: 'assets/p-celestial-leaf.webp', price: 20100, metal: 'white' },
{ id: 'skyhold', name: 'Skyhold Solitaire', cat: 'Bridal', img: 'assets/p-skyhold.webp', price: 9299, metal: 'rose', tag: 'Accessible' },
{ id: 'radiant-horizon', name: 'Radiant Horizon Pendant', cat: 'Pendant', img: 'assets/p-radiant-horizon.webp', price: 11399, metal: 'yellow' },
{ id: 'rosabella', name: 'Rosabella', cat: 'Gemstone', img: 'assets/p-rosabella.webp', price: 20099, metal: 'rose' },
{ id: 'sunlure', name: 'Sunlure', cat: 'Gemstone', img: 'assets/p-sunlure.webp', price: 20399, metal: 'yellow' },
{ id: 'ember-hoops', name: 'Ember Arc Hoops', cat: 'Earring', img: 'assets/p-ember-hoops.webp', price: 11299, metal: 'white' },
{ id: 'trilight', name: 'Trilight Hoops', cat: 'Earring', img: 'assets/p-trilight.webp', price: 21499, metal: 'white' },
];
const byId = (id) => PRODUCTS.find(p => p.id === id);
const fmtAED = (n) => `AED ${n.toLocaleString('en-US')}`;
// ===========================================================
// ProductCard
// ===========================================================
const ProductCard = ({product, onOpen}) => {
const [liked, setLiked] = React.useState(() => {
try { return JSON.parse(localStorage.getItem('palaces-likes') || '{}')[product.id] || false; } catch { return false; }
});
const toggleLike = (e) => {
e.stopPropagation();
const next = !liked;
setLiked(next);
try {
const obj = JSON.parse(localStorage.getItem('palaces-likes') || '{}');
if (next) obj[product.id] = true; else delete obj[product.id];
localStorage.setItem('palaces-likes', JSON.stringify(obj));
} catch {}
};
return (
onOpen && onOpen(product.id)}>
{product.tag && (
{product.tag}
)}
{product.name}
{product.priceFrom ? `from ${fmtAED(product.priceFrom)}` : fmtAED(product.price)}
{product.cat} · 18k {metalName(product.metal)}
);
};
const metalName = (m) => ({
white: 'White Gold',
yellow: 'Yellow Gold',
rose: 'Rose Gold',
platinum: 'Platinum',
})[m] || 'Gold';
// ===========================================================
// Section header
// ===========================================================
const SectionHead = ({eyebrow, title, sub, align = 'left', action}) => (
{eyebrow &&
{eyebrow}
}
{title}
{sub &&
{sub}
}
{action}
);
// Export to window so component files can pick these up
Object.assign(window, {
Icon, PalacesMark, PRODUCTS, byId, fmtAED, metalName, ProductCard, SectionHead,
});