From 24b71ad8de2b0334699234a071af62976eeaf534 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:27:16 +0330 Subject: [PATCH] Import source: global/src/global-home Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- global/src/global-home.jsx | 490 +++++++++++++++++++++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 global/src/global-home.jsx diff --git a/global/src/global-home.jsx b/global/src/global-home.jsx new file mode 100644 index 0000000..1cdb834 --- /dev/null +++ b/global/src/global-home.jsx @@ -0,0 +1,490 @@ +// 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 };