// teknav-home.jsx — Homepage (ES module) import { useState, useEffect, useRef } from 'react'; import { TeknavData } from './teknav-data.js'; import { useNav, useAuth, AuthorAvatar, CategoryBadge, TypeBadge, NewsletterForm, StreakWidget, ContinueReadingBar, ReadingListModal, pillBtn, useViewportPrefetch } from './teknav-ui.jsx'; import { DiagramRenderer } from './teknav-diagrams.jsx'; import { contentApi } from './src/lib/content-api.js'; import { engagementApi } from './src/lib/engagement-api.js'; // ── 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,', // deep teal (Teknav brand) 'rgba(196,106,77,', // terracotta 'rgba(47,143,107,' // warm green ]; 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, readProgress = null }) { const { navigate } = useNav(); const { user } = useAuth(); const [vis, setVis] = useState(false); const [listModalOpen, setListModalOpen] = useState(false); const ref = useRef(); useViewportPrefetch(ref, article.slug); 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 = TeknavData.authors.find((a) => a.id === article.authorId); const cat = TeknavData.categories.find((c) => c.id === article.category); const showContinue = readProgress !== null && readProgress >= 5 && readProgress <= 95; return (
navigate('/article/' + article.slug)} style={{ background: '#fff', borderRadius: 12, border: '1px solid #E4DDD2', padding: 24, cursor: 'pointer', direction: 'rtl', 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)'}> {/* Diagram thumbnail */}
{showContinue && ( <>
ادامه مطالعه )}
{article.sponsored && Promoted Content} {article.premiumOnly && Premium}

{article.title}

{article.summary.slice(0, 100)}...

{article.date}
{author && } {article.readTime} دقیقه {user && ( )}
{listModalOpen && setListModalOpen(false)} />}
); } // ── Featured Article ──────────────────────────────────────────────────────── function FeaturedArticle({ article }) { const { navigate } = useNav(); const ref = useRef(); useViewportPrefetch(ref, article.slug); const author = TeknavData.authors.find((a) => a.id === article.authorId); const cat = TeknavData.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', direction: 'rtl', 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.sponsored && Promoted Content} {article.premiumOnly && Premium}

{article.title}

{article.summary}

{author && }
{article.authorName}
{article.date} · {article.readTime} دقیقه مطالعه
); } // ── Resolve an author's profile URL (username from API or static fallback) ─── function authorProfilePath(author) { const username = author.username || TeknavData.authors.find(a => a.slug === author.slug)?.username; return username ? `/profile/@${username}` : `/author/${author.slug}`; } // ── Authors Section ───────────────────────────────────────────────────────── function AuthorsSection() { const { navigate } = useNav(); const [authors, setAuthors] = useState(TeknavData.authors); useEffect(() => { let cancelled = false; contentApi.listAuthors() .then(items => { if (cancelled || !items?.length) return; // Merge API data with static data to fill missing fields (username, bio, expertise) const merged = items.map(apiAuthor => { const seed = TeknavData.authors.find(a => a.slug === apiAuthor.slug || a.id === apiAuthor.id); return { ...seed, ...apiAuthor, username: apiAuthor.username || seed?.username, bio: seed?.bio || apiAuthor.bio, specialty: seed?.specialty || apiAuthor.specialty }; }); setAuthors(merged); }) .catch(() => {}); return () => { cancelled = true; }; }, []); return (

نویسندگان تکناو

متخصصانی که روایت عمیق فناوری را می‌نویسند

{authors.map((author) =>
navigate(authorProfilePath(author))} style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 12, padding: 20, cursor: 'pointer', textAlign: 'center', transition: 'all 0.2s' }} onMouseEnter={(e) => { 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} مقاله
)}
); } // ── Hero Section (light bg, parallax + shimmer) ───────────────────────────── function HeroSection({ featured, navigate }) { const wrapRef = useRef(); const cardRef = useRef(); // Subtle parallax tilt on mouse-move (disabled on touch) 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) translateY(0)`; }; 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 (
{/* Soft glows tuned for light bg */}
{/* Subtle grid overlay for depth */}
روایت عمیق فناوری

درک عمیق‌تر

دنیای فناوری

تحلیل‌های علمی، تخصصی و مستقل از پیشرفت‌های هوش مصنوعی، علم داده، امنیت سایبری و آینده فناوری.

{/* Featured card — light theme, parallax tilt, soft shadow */} {featured &&
{/* Decorative accent stripe */}
✦ مقاله ویژه
navigate('/article/' + featured.slug)} style={{ fontSize: 18, fontWeight: 700, color: '#0F2A2E', cursor: 'pointer', lineHeight: 1.65, transition: 'color 0.15s', fontFamily: "'PelakFA','Vazirmatn',sans-serif" }} onMouseEnter={(e) => e.currentTarget.style.color = '#0F6B73'} onMouseLeave={(e) => e.currentTarget.style.color = '#0F2A2E'}> {featured.title}
{featured.authorName} · {featured.type} · {featured.readTime} دقیقه مطالعه
}
{/* Wave divider for smooth transition into next section */}
); } // ── 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]); // Render Persian digits const fa = String(n).replace(/\d/g, (d) => '۰۱۲۳۴۵۶۷۸۹'[d]); // Add thousands separator (٬ for Persian) const formatted = fa.replace(/\B(?=(\d{3})+(?!\d))/g, '٬'); return {formatted}{suffix}; } function StatsBar() { const stats = [ { label: 'مقاله منتشرشده', to: 75, suffix: '+', icon: '◉' }, { label: 'نویسنده فعال', to: 2, suffix: '', icon: '✎' }, { label: 'خواننده ماهانه', to: 65000, suffix: '+', icon: '◐' }, { label: 'میانگین زمان مطالعه', to: 8, suffix: ' دقیقه', 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: 'Vazirmatn,sans-serif' }; const sectionSubtitle = { fontSize: 14, color: '#5F6B6D', margin: '0 0 32px', lineHeight: 1.7 }; // ── Homepage ──────────────────────────────────────────────────────────────── function HomePage() { const { navigate } = useNav(); const { user } = useAuth(); const [articles, setArticles] = useState(() => contentApi.fallbackArticles()); const [personalized, setPersonalized] = useState([]); const [readProgressMap, setReadProgressMap] = useState({}); useEffect(() => { let cancelled = false; contentApi.listArticles({ limit: 50 }) .then((res) => { if (!cancelled) setArticles(res.items ?? []); }) .catch(() => {}); if (user) { contentApi.listArticles({ limit: 12, sort: 'personalized' }) .then((res) => { if (!cancelled) setPersonalized(res.items ?? []); }) .catch(() => {}); engagementApi.getStreaks() .then((data) => { if (cancelled) return; const map = {}; (data.continueReading ?? []).forEach(item => { map[item.slug] = Math.round((item.progress ?? 0) * 100); }); setReadProgressMap(map); }) .catch(() => {}); } else { setPersonalized([]); setReadProgressMap({}); } return () => { cancelled = true; }; }, [user]); 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 - a.views).slice(0, 4); const deep = articles.filter((a) => a.type === 'تحلیل عمیق').slice(0, 3); const thisWeek = [...articles].sort((a, b) => new Date(b.dateEn) - new Date(a.dateEn)).slice(0, 6); const openclawCluster = articles.filter((a) => a.seriesSlug === 'openclaw-series'); const securityCluster = articles.filter((a) => a.category === 'security').slice(0, 5); return (
{/* Personalized Bar / Streak */} {user && (
)} {/* Hero */}
{/* Personalized Feed */} {personalized.length > 0 && (

پیشنهاد برای شما

بر اساس علایق و تاریخچه مطالعه شما

{personalized.map((a, i) => )}
)} {/* Featured article */} {featured &&

عمیق‌ترین تحلیل این هفته

} {/* Latest */}

تازه‌ترین خبرها

آخرین تحلیل‌ها و مقالات تکناو

{latest.map((a, i) => )}
{/* Deep analysis */} {deep.length > 0 &&

تحلیل‌های عمیق

بررسی‌های تخصصی و مستند

{deep.map((a) => )}
} {/* Popular */}

پرخواننده‌ترین مقالات تکناو

{popular.map((a, i) => )}
{/* This Week */}

این هفته در تکناو

تازه‌ترین تحلیل‌های خرداد ۱۴۰۵

{thisWeek.map((a, i) => )}
{/* OpenClaw Cluster */} {openclawCluster.length > 0 && (
⚙

سری OpenClaw

معماری، امنیت، و ژئوپلیتیک عامل‌های متن‌باز

{openclawCluster.map((a) => )}
)} {/* Security & Legal Cluster */} {securityCluster.length > 0 && (
⚖

امنیت و حقوق AI

مسئولیت حقوقی، ایمنی سایبری، و حاکمیت هوش مصنوعی

{securityCluster.map((a) => )}
)} {/* Categories */}

دسته‌بندی‌ها

کشف مطالب بر اساس حوزه تخصصی

{TeknavData.categories.map((cat) => { const { navigate } = useNav(); return (
navigate('/category/' + cat.slug)} style={{ background: '#fff', border: `1px solid ${cat.color}30`, borderRadius: 10, padding: '20px 16px', cursor: 'pointer', direction: 'rtl', transition: 'all 0.2s', borderRight: `3px solid ${cat.color}` }} onMouseEnter={(e) => e.currentTarget.style.background = cat.color + '08'} onMouseLeave={(e) => e.currentTarget.style.background = '#fff'}>
{cat.name}
{cat.description}
{cat.articleCount} مقاله
); })}
{/* Authors */} {/* Newsletter */}
✉

عضو خبرنامه تکناو شوید

هر هفته بهترین مقاله‌های تحلیلی تکناو مستقیم در صندوق ورودی ایمیل شما

); } // ── Article Row Compact (for homepage) ───────────────────────────────────── function ArticleRowCompact({ article }) { const { navigate } = useNav(); const ref = useRef(); useViewportPrefetch(ref, article.slug); const cat = TeknavData.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', direction: 'rtl', alignItems: 'flex-start', transition: 'background 0.15s' }} onMouseEnter={(e) => e.currentTarget.style.background = '#F4EFE620'} onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>

{article.title}

{article.summary.slice(0, 140)}…

{article.authorName} · {article.date} · {article.readTime} دقیقه
); } export { HomePage, ArticleCard, FeaturedArticle, ArticleRowCompact, sectionTitle, sectionSubtitle };