{!loaded && !err &&
{a.ageText}
{PF.sizeLabel(a.size)}
{PF.colorLabel(a.color)}
{a.loc.split(',')[0]}
);
}
function colorBg(id){ const c=PF.COLORS.find(x=>x.id===id); return c?c.hex:'#ccc'; }
/* ---- Skeleton card ---- */
function SkeletonCard(){
return (
);
}
const SkeletonGrid = ({ n=8 }) => (
);
}
/* ---- Header (desktop nav) ---- */
function Header(){
const { route, go } = useNav();
const is = (n)=> route.name===n ? 'active':'';
return (
go('home')}/>
);
}
/* ---- Bottom nav (mobile) ---- */
function BottomNav(){
const { route, go } = useNav();
const items = [
{ n:'home', label:'Главная', Ico:Icons.home },
{ n:'photo', label:'По фото', Ico:Icons.camera },
{ n:'filter', label:'Подбор', Ico:Icons.tune },
{ n:'second', label:'Шанс', Ico:Icons.heart },
{ n:'catalog', label:'Каталог', Ico:Icons.grid },
];
return (
);
}
/* ---- Footer ---- */
function Footer(){
const { go } = useNav();
return (
);
}
/* ---- small bits ---- */
const Stat = ({ value, label }) => (
}
{err
?
:
setLoaded(true)} onError={()=>setErr(true)}
style={{opacity:loaded?1:0,transition:'opacity .4s'}}/>}
{match!=null && % }
{wait && match==null && {PF.waitLabel(a.waiting)}}
{PF.speciesOne(a.species)}
{a.name}
{Array.from({length:n}).map((_,i)=>)}
);
/* ---- Empty / error ---- */
function EmptyState({ icon, title, text, action }){
const I = icon || Icons.search;
return (
{title}
{text}
{action}{value}{label}
);
Object.assign(window, {
NavCtx, useNav, Brand, SpeciesIcon, SexMark, AnimalCard, colorBg, CountUp,
SkeletonCard, SkeletonGrid, EmptyState, Header, BottomNav, Footer, Stat,
});