// global-home.jsx — Homepage for Teknav Global (English, LTR) import { useState, useEffect, useRef } from 'react'; import { articles as allArticlesData, authors, categories, siteConfig } from '../global-data.js'; import { useNav, useAuth, AuthorAvatar, CategoryBadge, TypeBadge, NewsletterForm, pillBtn } from './global-ui.jsx'; // ── Hero Neural Background ────────────────────────────────────────────────── function HeroBackground() { const canvasRef = useRef(); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); let raf, t = 0; const palette = [ 'rgba(15,107,115,', 'rgba(196,106,77,', 'rgba(47,143,107,', ]; const nodes = Array.from({ length: 32 }, (_, i) => ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * 0.35, vy: (Math.random() - 0.5) * 0.35, r: Math.random() * 3 + 1.5, color: palette[i % palette.length], phase: Math.random() * Math.PI * 2, })); const resize = () => { canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; }; resize(); window.addEventListener('resize', resize); const draw = () => { t += 0.012; ctx.clearRect(0, 0, canvas.width, canvas.height); nodes.forEach(n => { n.x += n.vx; n.y += n.vy; if (n.x < 0 || n.x > canvas.width) n.vx *= -1; if (n.y < 0 || n.y > canvas.height) n.vy *= -1; nodes.forEach(m => { const d = Math.hypot(n.x - m.x, n.y - m.y); if (d < 130) { ctx.beginPath(); ctx.moveTo(n.x, n.y); ctx.lineTo(m.x, m.y); ctx.strokeStyle = `rgba(15,107,115,${0.18 * (1 - d / 130)})`; ctx.lineWidth = 0.8; ctx.stroke(); } }); const pulse = 0.45 + 0.18 * Math.sin(t + n.phase); ctx.beginPath(); ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2); ctx.fillStyle = n.color + pulse + ')'; ctx.fill(); }); raf = requestAnimationFrame(draw); }; draw(); return () => { cancelAnimationFrame(raf); window.removeEventListener('resize', resize); }; }, []); return ; } // ── Article Card (grid) ───────────────────────────────────────────────────── function ArticleCard({ article, delay = 0 }) { const { navigate } = useNav(); const [vis, setVis] = useState(false); const ref = useRef(); useEffect(() => { const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) setVis(true); }, { threshold: 0.1 }); if (ref.current) obs.observe(ref.current); return () => obs.disconnect(); }, []); const author = authors.find(a => a.id === article.author); const cat = categories.find(c => c.id === article.category); return (
navigate('/article/' + article.slug)} style={{ background: '#fff', borderRadius: 12, border: '1px solid #E4DDD2', padding: 24, cursor: 'pointer', opacity: vis ? 1 : 0, transform: vis ? 'translateY(0)' : 'translateY(24px)', transition: `opacity 0.5s ${delay}ms, transform 0.5s ${delay}ms, box-shadow 0.2s`, boxShadow: '0 2px 12px rgba(0,0,0,0.04)', }} onMouseEnter={e => e.currentTarget.style.boxShadow = '0 8px 32px rgba(0,0,0,0.1)'} onMouseLeave={e => e.currentTarget.style.boxShadow = '0 2px 12px rgba(0,0,0,0.04)'}>
{article.photo ? ( {article.title} { e.target.style.display = 'none'; }} /> ) : (
)}
{article.type && }

{article.title}

{(article.subtitle || article.summary || '').slice(0, 100)}...

{article.date}
{author && } {article.readTime} min
); } // ── Featured Article ──────────────────────────────────────────────────────── function FeaturedArticle({ article }) { const { navigate } = useNav(); const author = authors.find(a => a.id === article.author); const cat = categories.find(c => c.id === article.category); return (
navigate('/article/' + article.slug)} style={{ background: '#fff', borderRadius: 16, border: '1px solid #E4DDD2', padding: 0, cursor: 'pointer', overflow: 'hidden', boxShadow: '0 4px 24px rgba(0,0,0,0.06)', display: 'grid', gridTemplateColumns: '1fr 1fr', minHeight: 280, transition: 'box-shadow 0.2s', }} className="featured-card" onMouseEnter={e => e.currentTarget.style.boxShadow = '0 12px 48px rgba(0,0,0,0.12)'} onMouseLeave={e => e.currentTarget.style.boxShadow = '0 4px 24px rgba(0,0,0,0.06)'}>
{article.type && }

{article.title}

{article.subtitle || article.summary}

{author && }
{author?.name}
{article.date} · {article.readTime} min read
{article.photo ? ( {article.title} { e.target.style.display = 'none'; }} /> ) : (
)}
); } // ── Authors Section ───────────────────────────────────────────────────────── function AuthorsSection() { const { navigate } = useNav(); return (

Teknav Authors

The specialists who write Teknav's deep technology analysis

{authors.map(author => (
{ e.currentTarget.style.transform = 'translateY(-4px)'; e.currentTarget.style.boxShadow = '0 8px 24px rgba(0,0,0,0.08)'; }} onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}>
{author.name}
{author.specialty}
{author.articleCount} articles
))}
); } // ── Hero Section ───────────────────────────────────────────────────────────── function HeroSection({ featured, navigate }) { const wrapRef = useRef(); const cardRef = useRef(); useEffect(() => { const wrap = wrapRef.current; const card = cardRef.current; if (!wrap || !card) return; const onMove = e => { const r = wrap.getBoundingClientRect(); const dx = (e.clientX - r.left) / r.width - 0.5; const dy = (e.clientY - r.top) / r.height - 0.5; card.style.transform = `perspective(900px) rotateX(${(-dy * 4).toFixed(2)}deg) rotateY(${(dx * 6).toFixed(2)}deg)`; }; const onLeave = () => { card.style.transform = 'perspective(900px) rotateX(0) rotateY(0)'; }; wrap.addEventListener('mousemove', onMove); wrap.addEventListener('mouseleave', onLeave); return () => { wrap.removeEventListener('mousemove', onMove); wrap.removeEventListener('mouseleave', onLeave); }; }, []); return (
Deep Technology Analysis

Understand more.

Build better.

Scientific, independent analysis of AI engineering, data infrastructure, cybersecurity, and the future of software.

{featured && (
✦ Featured
navigate('/article/' + featured.slug)} style={{ fontSize: 18, fontWeight: 700, color: '#0F2A2E', cursor: 'pointer', lineHeight: 1.65, transition: 'color 0.15s', fontFamily: 'Inter,sans-serif' }} onMouseEnter={e => e.currentTarget.style.color = '#0F6B73'} onMouseLeave={e => e.currentTarget.style.color = '#0F2A2E'}> {featured.title}
{authors.find(a => a.id === featured.author)?.name} · {featured.type} · {featured.readTime} min read
)}
); } // ── Stats Bar ─────────────────────────────────────────────────────────────── function CountUp({ to, suffix = '', duration = 1400 }) { const [n, setN] = useState(0); const ref = useRef(); const started = useRef(false); useEffect(() => { const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting && !started.current) { started.current = true; const start = performance.now(); const tick = (now) => { const p = Math.min((now - start) / duration, 1); const eased = 1 - Math.pow(1 - p, 3); setN(Math.round(to * eased)); if (p < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); } }, { threshold: 0.4 }); if (ref.current) obs.observe(ref.current); return () => obs.disconnect(); }, [to, duration]); return {n.toLocaleString('en-US')}{suffix}; } function StatsBar() { const stats = [ { label: 'Articles published', to: 75, suffix: '+', icon: '◉' }, { label: 'Active authors', to: 2, suffix: '', icon: '✎' }, { label: 'Monthly readers', to: 65000, suffix: '+', icon: '◐' }, { label: 'Avg. read time', to: 10, suffix: ' min', icon: '◷' }, ]; return (
{stats.map((s, i) => (
{s.icon}
{s.label}
{i < stats.length - 1 && (
)}
))}
); } // ── Shared section styles ─────────────────────────────────────────────────── const sectionTitle = { fontSize: 22, fontWeight: 800, color: '#263238', margin: '0 0 8px', fontFamily: 'Inter,sans-serif' }; const sectionSubtitle = { fontSize: 14, color: '#5F6B6D', margin: '0 0 32px', lineHeight: 1.7 }; // ── Article Row Compact ───────────────────────────────────────────────────── function ArticleRowCompact({ article }) { const { navigate } = useNav(); const cat = categories.find(c => c.id === article.category); return (
navigate('/article/' + article.slug)} style={{ display: 'flex', gap: 20, padding: '20px 0', borderBottom: '1px solid #E4DDD2', cursor: 'pointer', alignItems: 'flex-start', transition: 'background 0.15s', }} onMouseEnter={e => e.currentTarget.style.background = '#F4EFE620'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
{article.type && }

{article.title}

{(article.subtitle || '').slice(0, 140)}…

{authors.find(a => a.id === article.author)?.name} · {article.date} · {article.readTime} min
{article.photo && ( {article.title} { e.target.style.display = 'none'; }} /> )}
); } // ── Homepage ──────────────────────────────────────────────────────────────── export default function HomePage() { const { navigate } = useNav(); const articles = allArticlesData; const featured = articles.find(a => a.featured) || articles[0]; const latest = articles.filter(a => a.id !== featured?.id).slice(0, 6); const popular = [...articles].sort((a, b) => (b.views || 0) - (a.views || 0)).slice(0, 4); const aiArticles = articles.filter(a => a.category === 'ai').slice(0, 5); const securityArticles = articles.filter(a => a.category === 'security').slice(0, 5); return (
{featured && (

The deepest analysis this week

)}

Latest

The latest analysis from Teknav

{latest.map((a, i) => )}
{aiArticles.length > 0 && (
⚙

AI Engineering

Production AI systems, agents, and model infrastructure

{aiArticles.map(a => )}
)} {securityArticles.length > 0 && (
⚖

Security & Legal

AI security, legal liability, and governance

{securityArticles.map(a => )}
)}

Teknav's most-read articles

{popular.map((a, i) => )}

Topics

Explore by area of expertise

{categories.map(cat => (
navigate('/category/' + cat.id)} style={{ background: '#fff', border: `1px solid ${cat.color}30`, borderRadius: 10, padding: '20px 16px', cursor: 'pointer', transition: 'all 0.2s', borderLeft: `3px solid ${cat.color}`, }} onMouseEnter={e => e.currentTarget.style.background = cat.color + '08'} onMouseLeave={e => e.currentTarget.style.background = '#fff'}>
{cat.name}
{cat.description}
{allArticlesData.filter(a => a.category === cat.id).length} articles
))}
✉

Subscribe to Teknav

Every week, Teknav's best analysis delivered straight to your inbox

); } export { ArticleCard, ArticleRowCompact, sectionTitle, sectionSubtitle };