diff --git a/app/teknav-pages.jsx b/app/teknav-pages.jsx
new file mode 100644
index 0000000..bad110d
--- /dev/null
+++ b/app/teknav-pages.jsx
@@ -0,0 +1,2027 @@
+// teknav-pages.jsx — Search, Category, Authors pages (ES module)
+import { useState, useMemo, useEffect, useCallback } from 'react';
+import { TeknavData } from './teknav-data.js';
+
+function authorProfilePath(author) {
+ const username = author.username || TeknavData.authors.find(a => a.slug === author.slug)?.username;
+ return username ? `/profile/@${username}` : `/author/${author.slug}`;
+}
+import {
+ useNav, useToast, useAuth,
+ AuthorAvatar, CategoryBadge, TypeBadge, EmptyState, SkeletonLoader,
+ inputStyle, pillBtn,
+} from './teknav-ui.jsx';
+import { DiagramRenderer } from './teknav-diagrams.jsx';
+import { ArticleRow } from './teknav-articles.jsx';
+import { contentApi } from './src/lib/content-api.js';
+import { engagementApi, pushApi } from './src/lib/engagement-api.js';
+
+// ── Search Page ─────────────────────────────────────────────────────────────
+function SearchPage({ initQ = '' }) {
+ const [q, setQ] = useState(initQ);
+ const [input, setInput] = useState(initQ);
+ const [filters, setFilters] = useState({ category: '', author: '', type: '', tag: '', dateRange: '' });
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const { navigate } = useNav();
+
+ const load = useCallback(() => {
+ setLoading(true);
+ const params = {
+ q,
+ category: filters.category,
+ author: filters.author,
+ type: filters.type,
+ tag: filters.tag,
+ limit: 50,
+ };
+ const apiCall = q ? contentApi.search(params) : contentApi.listArticles(params);
+ apiCall
+ .then(res => setItems(res.items ?? []))
+ .finally(() => setLoading(false));
+ }, [q, filters]);
+
+ useEffect(() => { load(); }, [load]);
+
+ const doSearch = (e) => { e.preventDefault(); setQ(input); };
+
+ const highlightText = (text, query) => {
+ if (!query) return text;
+ const parts = text.split(new RegExp(`(${query})`, 'gi'));
+ return parts.map((part, i) =>
+ part.toLowerCase() === query.toLowerCase()
+ ? `${part} `
+ : part
+ ).join('');
+ };
+
+ return (
+
+
+
جستجوی پیشرفته
+
+
+
+
+
+
+
دستهبندی
+
setFilters(f => ({ ...f, category: e.target.value }))} style={inputStyle}>
+ همه دستهها
+ {TeknavData.categories.map(c => {c.name} )}
+
+
+
+
نویسنده
+
setFilters(f => ({ ...f, author: e.target.value }))} style={inputStyle}>
+ همه نویسندگان
+ {TeknavData.authors.map(a => {a.name} )}
+
+
+
+
نوع محتوا
+
setFilters(f => ({ ...f, type: e.target.value }))} style={inputStyle}>
+ همه انواع
+ {['تحلیل عمیق', 'راهنمای فنی', 'دادهنما', 'خبر فوری'].map(t => {t} )}
+
+
+ setFilters({ category: '', author: '', type: '', tag: '', dateRange: '' })} style={{ ...pillBtn, background: '#F4EFE6', color: '#C94C4C', justifyContent: 'center' }}>پاک کردن فیلترها
+
+
+
+ {loading ? : (
+ <>
+ {items.length === 0 ? : (
+
+
{items.length.toLocaleString('fa-IR')} نتیجه پیدا شد
+ {items.map((a, i) =>
)}
+
+ )}
+ >
+ )}
+
+
+
+
+
+ );
+}
+
+function SearchResult({ article, q, highlight, idx }) {
+ const { navigate } = useNav();
+ return (
+ navigate('/article/' + article.slug)} style={{
+ padding: '24px 0', borderBottom: '1px solid #E4DDD2', cursor: 'pointer',
+ opacity: 0, animation: `fadeIn 0.3s ${idx * 40}ms forwards`,
+ }}>
+
+
+ {article.date} · {article.readTime} دقیقه
+
+
+
+
+ );
+}
+
+// ── Category Page ───────────────────────────────────────────────────────────
+function CategoryPage({ slug }) {
+ const { navigate } = useNav();
+ const [cat, setCat] = useState(() => TeknavData.categories.find(c => c.slug === slug));
+ const [articles, setArticles] = useState(() => contentApi.fallbackArticles().filter(a => a.category === slug));
+
+ useEffect(() => {
+ let cancelled = false;
+ setCat(TeknavData.categories.find(c => c.slug === slug));
+ setArticles(contentApi.fallbackArticles().filter(a => a.category === slug));
+ Promise.all([
+ contentApi.getCategory(slug).catch(() => null),
+ contentApi.listArticles({ category: slug, limit: 100 }).catch(() => null),
+ ]).then(([category, result]) => {
+ if (cancelled) return;
+ if (category) setCat({ ...(TeknavData.categories.find(c => c.slug === slug) ?? {}), ...category, id: category.slug });
+ if (result?.items) setArticles(result.items);
+ });
+ return () => { cancelled = true; };
+ }, [slug]);
+
+ if (!cat) return ;
+
+ return (
+
+ {/* Category Hero */}
+ {(() => {
+ const HERO_IMAGES = {
+ ai: '/images/category-hero-ai-v2.jpg',
+ startup: '/images/category-hero-startup.jpg',
+ hardware: '/images/category-hero-hardware.jpg',
+ security: '/images/category-hero-security.jpg',
+ software: '/images/category-hero-software.jpg',
+ future: '/images/category-hero-future.jpg',
+ data: '/images/category-hero-data.jpg',
+ };
+ const heroImg = HERO_IMAGES[cat.slug];
+ return (
+
+ {/* Background: photo for AI, soft tinted gradient for others */}
+ {heroImg
+ ?
+ :
+ }
+
+ {/* Content grid */}
+
+
+ {/* Text card */}
+
+ {/* Pill badge */}
+
+
+ دستهبندی
+
+
+
{cat.name}
+
{cat.description}
+
+ {/* Stats */}
+
+ {[['تعداد مقاله', cat.articleCount], ['نویسنده فعال', cat.authorCount], ['میانگین زمان مطالعه', `${cat.avgReadTime} دقیقه`]].map(([label, val], i) => (
+
0 ? '1px solid #E4DDD2' : 'none' }}>
+
{val}
+
{label}
+
+ ))}
+
+
+
+ {/* Diagram card */}
+
+
+
+
+
+ );
+ })()}
+
+
+
مقالههای {cat.name} ({articles.length})
+ {articles.length === 0 ?
: (
+ articles.map((a, i) =>
)
+ )}
+
+
+
+ );
+}
+
+// ── Authors List Page ────────────────────────────────────────────────────────
+function TagPage({ tag }) {
+ const decoded = decodeURIComponent(tag);
+ const [articles, setArticles] = useState(() => contentApi.fallbackArticles().filter((item) => item.tags?.includes(decoded)));
+ useEffect(() => {
+ let cancelled = false;
+ setArticles(contentApi.fallbackArticles().filter((item) => item.tags?.includes(decoded)));
+ contentApi.listArticles({ tag: decoded, limit: 100 })
+ .then((res) => { if (!cancelled) setArticles(res.items ?? []); })
+ .catch(() => {});
+ return () => { cancelled = true; };
+ }, [decoded]);
+ return (
+
+
+
برچسب {decoded}
+
همه مقالههایی که با این برچسب منتشر شدهاند.
+ {articles.length === 0 ?
: articles.map((article, index) => (
+
+ ))}
+
+
+ );
+}
+
+function GlossaryPage({ slug }) {
+ const { navigate } = useNav();
+ const term = TeknavData.glossary?.find((item) => item.slug === slug);
+ const articles = contentApi.fallbackArticles().filter((article) => (
+ article.tags?.some((tag) => tag.toLowerCase() === term?.term?.toLowerCase() || tag.toLowerCase() === term?.english?.toLowerCase())
+ || article.summary?.toLowerCase().includes(term?.english?.toLowerCase() || '')
+ || article.title?.toLowerCase().includes(term?.english?.toLowerCase() || '')
+ )).slice(0, 6);
+
+ if (!term) return ;
+
+ const related = (term.related ?? []).map((item) => TeknavData.glossary?.find((g) => g.slug === item)).filter(Boolean);
+ const topic = TeknavData.topicHubs?.find((item) => item.slug === term.topic);
+
+ return (
+
+
+
+
navigate('/articles')} style={{ ...pillBtn, background: '#F4EFE6', color: '#0F6B73', border: '1px solid #E4DDD2', marginBottom: 18 }}>بازگشت به مقالهها
+
فرهنگ واژگان تکنّاو
+
{term.term}
+
{term.english}
+
{term.summary}
+
+
+
+
+
+
پرسشهای رایج
+ {(term.faqs ?? []).map(([q, a]) => (
+
+ ))}
+
+
+
مقالههای مرتبط
+ {articles.length === 0 ?
: articles.map((article, index) =>
)}
+
+
+
+ {topic && (
+ navigate(`/topics/${topic.slug}`)} style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 8, padding: 18, textAlign: 'right', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ خوشه موضوعی
+ {topic.title}
+
+ )}
+
+
واژههای مرتبط
+
+ {related.map((item) => (
+ navigate(`/glossary/${item.slug}`)} style={{ ...pillBtn, background: '#F4EFE6', color: '#0F6B73', border: '1px solid #E4DDD2', fontSize: 12 }}>{item.term}
+ ))}
+
+
+
+
+
+
+ );
+}
+
+function toDateKey(article) {
+ return article?.dateEn || article?.publishedAt || article?.date || '';
+}
+
+function AuthorsListPage() {
+ const { navigate } = useNav();
+ const [authors, setAuthors] = useState(() => contentApi.fallbackAuthors());
+ const [articles, setArticles] = useState(() => contentApi.fallbackArticles());
+ useEffect(() => {
+ let cancelled = false;
+ Promise.all([
+ contentApi.listAuthors().catch(() => null),
+ contentApi.listArticles({ limit: 100 }).catch(() => null),
+ ]).then(([authorRows, articleRows]) => {
+ if (cancelled) return;
+ if (authorRows) setAuthors(authorRows);
+ if (articleRows?.items) setArticles(articleRows.items);
+ });
+ return () => { cancelled = true; };
+ }, []);
+ return (
+
+
+ {/* Authors Hero */}
+
+
+
+
+
+
+ نویسندگان
+
+
نویسندگان تکناو
+
متخصصانی که روایت عمیق فناوری را مینویسند
+
+
+
+
+
+
+
+
+ {authors.map(author => {
+ const latestArt = articles.find(a => a.authorId === author.id || a.authorSlug === author.slug);
+ return (
+
navigate(authorProfilePath(author))} style={{
+ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 14, padding: 24,
+ cursor: 'pointer', direction: 'rtl', transition: 'all 0.2s',
+ }} onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = '0 10px 32px rgba(0,0,0,0.08)'; }}
+ onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = 'none'; }}>
+
+
+
+
+ {author.name}
+ {author.verifiedExpert && تاییدشده }
+
+
{author.specialty}
+
{author.liveArticleCount ?? author.articleCount} مقاله منتشرشده
+
+
+
{author.bio.slice(0, 120)}…
+ {latestArt && (
+
+ آخرین مقاله:
+ {latestArt.title.slice(0, 50)}…
+
+ )}
+
+ );
+ })}
+
+
+
+ );
+}
+
+// ── Author Profile Page ─────────────────────────────────────────────────────
+function SeriesPage({ slug }) {
+ const { navigate } = useNav();
+ const [series, setSeries] = useState(null);
+ const [error, setError] = useState(false);
+
+ useEffect(() => {
+ let cancelled = false;
+ setError(false);
+ contentApi.getSeries(slug)
+ .then((item) => { if (!cancelled) setSeries(item); })
+ .catch(() => { if (!cancelled) setError(true); });
+ return () => { cancelled = true; };
+ }, [slug]);
+
+ if (error) {
+ return (
+
+
+
+ );
+ }
+
+ if (!series) {
+ return در حال بارگذاری...
;
+ }
+
+ return (
+
+
+
navigate('/articles')} style={{ ...pillBtn, background: '#F4EFE6', color: '#0F6B73', border: '1px solid #E4DDD2', marginBottom: 18 }}>بازگشت به مقالهها
+
{series.title}
+ {series.description &&
{series.description}
}
+ {(series.articles ?? []).length === 0 ?
: (
+
+ {series.articles.map((item, index) => (
+
+
{(item.position ?? index + 1).toLocaleString('fa-IR')}
+
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+function TopicHubPage({ slug }) {
+ const { navigate } = useNav();
+ const toast = useToast();
+ const { user } = useAuth();
+ const topic = TeknavData.topicHubs.find((item) => item.slug === slug);
+ const category = TeknavData.categories.find((item) => item.slug === topic?.categorySlug);
+ const [articles, setArticles] = useState(() => contentApi.fallbackArticles().filter((item) => item.category === topic?.categorySlug));
+ const [series, setSeries] = useState([]);
+ const [follow, setFollow] = useState({ following: false, count: 0 });
+ const [guestPushEnabled, setGuestPushEnabled] = useState(false);
+ const [guestPushBusy, setGuestPushBusy] = useState(false);
+
+ useEffect(() => {
+ if (!topic) return;
+ let cancelled = false;
+ setArticles(contentApi.fallbackArticles().filter((item) => item.category === topic.categorySlug));
+ Promise.all([
+ contentApi.listArticles({ category: topic.categorySlug, limit: 100 }).catch(() => null),
+ contentApi.listSeries().catch(() => []),
+ engagementApi.topicFollowers(topic.slug).catch(() => null),
+ ]).then(([articleRows, seriesRows, followRow]) => {
+ if (cancelled) return;
+ if (articleRows?.items) setArticles(articleRows.items);
+ setSeries((seriesRows ?? []).filter((row) => (row.articles ?? []).some((entry) => entry.article?.category === topic.categorySlug)));
+ if (followRow) setFollow({ following: !!followRow.following, count: followRow.count ?? 0 });
+ });
+ // Check if guest push already subscribed
+ if ('PushManager' in window && 'serviceWorker' in navigator) {
+ pushApi.isSubscribed().then(setGuestPushEnabled).catch(() => {});
+ }
+ return () => { cancelled = true; };
+ }, [topic?.slug]);
+
+ if (!topic) {
+ return (
+
+
+
+ );
+ }
+
+ const featured = articles.filter((item) => item.featured).slice(0, 3);
+ const latest = articles.slice().sort((a, b) => String(toDateKey(b)).localeCompare(String(toDateKey(a)))).slice(0, 8);
+ const authors = TeknavData.authors.filter((author) => articles.some((article) => article.authorId === author.id || article.authorSlug === author.slug));
+
+ const toggleTopicFollow = async () => {
+ if (!user) {
+ toast('برای دنبال کردن موضوع ابتدا وارد شوید', 'warning');
+ return;
+ }
+ try {
+ const result = follow.following
+ ? await engagementApi.unfollowTopic(topic.slug)
+ : await engagementApi.followTopic(topic.slug);
+ setFollow({ following: !!result.following, count: result.count ?? 0 });
+ toast(result.following ? 'موضوع دنبال شد' : 'دنبال کردن موضوع لغو شد');
+ } catch {
+ toast('دنبال کردن موضوع انجام نشد', 'warning');
+ }
+ };
+
+ const toggleGuestPush = async () => {
+ if (!('PushManager' in window) || !('serviceWorker' in navigator)) {
+ toast('مرورگر شما از اعلانهای وب پشتیبانی نمیکند', 'warning');
+ return;
+ }
+ setGuestPushBusy(true);
+ try {
+ if (guestPushEnabled) {
+ await pushApi.unsubscribeGuest();
+ setGuestPushEnabled(false);
+ toast('اعلانهای این موضوع غیرفعال شد');
+ } else {
+ const perm = typeof Notification !== 'undefined' ? await Notification.requestPermission() : 'denied';
+ if (perm !== 'granted') {
+ toast('اجازه اعلان داده نشد', 'warning');
+ return;
+ }
+ await pushApi.subscribeAsGuest([topic.slug]);
+ setGuestPushEnabled(true);
+ toast('اعلانهای مقالات جدید این موضوع فعال شد');
+ }
+ } catch {
+ toast('عملیات ناموفق بود', 'error');
+ } finally {
+ setGuestPushBusy(false);
+ }
+ };
+
+ return (
+
+
+
+
navigate('/articles')} style={{ ...pillBtn, background: '#FFFFFFAA', color: '#0F6B73', border: '1px solid #E4DDD2', marginBottom: 18 }}>همه مقالهها
+
{topic.title}
+
{topic.intro}
+
+
+ {follow.following ? 'دنبال میکنید' : 'دنبال کردن موضوع'} · {(follow.count ?? 0).toLocaleString('fa-IR')}
+
+ {'PushManager' in window && (
+
+ {guestPushBusy ? '…' : guestPushEnabled ? 'اعلان فعال است' : 'دریافت اعلان مقالات'}
+
+ )}
+
+
+
+
+
+
+ مقالههای شاخص
+ {featured.length === 0 ? : (
+
+ {featured.map((article, index) =>
)}
+
+ )}
+
+
+
+ تازهترین تحلیلها
+ {latest.length === 0 ? : latest.map((article, index) => )}
+
+
+
+
+
سریهای مرتبط
+ {series.length === 0 ?
سری مقاله مرتبط پس از تایید سردبیر اینجا نمایش داده میشود.
: series.map((item) => (
+
navigate(`/series/${item.slug}`)} style={{ display: 'block', width: '100%', textAlign: 'right', background: '#F4EFE6', border: '1px solid #E4DDD2', borderRadius: 8, padding: 12, marginBottom: 10, color: '#263238', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>{item.title}
+ ))}
+
+
+
نویسندگان مرتبط
+ {authors.length === 0 ?
نویسنده مرتبطی پیدا نشد.
: authors.map((author) => (
+
navigate(authorProfilePath(author))} style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', background: 'transparent', border: 0, padding: '8px 0', color: '#263238', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif', textAlign: 'right' }}>
+
+ {author.name}
+
+ ))}
+
+
+
+
+ پرسشهای رایج
+ {topic.faqs.map(([question, answer]) => (
+
+ {question}
+ {answer}
+
+ ))}
+
+
+
+ );
+}
+
+function AuthorProfilePage({ slug }) {
+ const { navigate } = useNav();
+ const [author, setAuthor] = useState(null);
+ const [articles, setArticles] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ // Redirect /author/:slug → /profile/@:username
+ const staticAuthor = TeknavData.authors.find(a => a.slug === slug);
+ const username = staticAuthor?.username || slug;
+ navigate(`/profile/@${username}`);
+ }, [slug]);
+
+ if (loading) return در حال بارگذاری…
;
+ if (!author) return ;
+
+ return (
+
+ {/* Profile header */}
+
+
+
+
+
+ {author.name}
+ {author.verifiedExpert && متخصص تاییدشده }
+
+ {author.verifiedExpert && author.verificationNote &&
{author.verificationNote}
}
+
{author.specialty}
+
{author.bio}
+
+
{author.articleCount} مقاله
+
{articles.reduce((s, a) => s + (a.views || 0), 0).toLocaleString('fa')} بازدید
+
+
+
+
+
+
+
مقالههای {author.name}
+ {articles.length === 0 ?
:
+ articles.map((a, i) =>
)
+ }
+
+
+ );
+}
+
+function NewsletterArchivePage() {
+ const { navigate } = useNav();
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ let cancelled = false;
+ contentApi.listNewsletterArchive()
+ .then((rows) => { if (!cancelled) setItems(rows); })
+ .catch(() => { if (!cancelled) setItems([]); })
+ .finally(() => { if (!cancelled) setLoading(false); });
+ return () => { cancelled = true; };
+ }, []);
+
+ return (
+
+
+
آرشیو خبرنامه تکنـاو
+
نسخههای ارسالشده خبرنامه برای دنبال کردن روندهای مهم فناوری، هوش مصنوعی و امنیت.
+ {loading ?
در حال بارگذاری...
: items.length === 0 ?
: (
+
+ {items.map((item) => (
+
navigate(`/newsletter/${item.slug}`)} style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 10, padding: 18, textAlign: 'right', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ {item.subject}
+ {item.sentAt ? new Date(item.sentAt).toLocaleDateString('fa-IR') : 'منتشر نشده'}
+
+ ))}
+
+ )}
+
+
+ );
+}
+
+function NewsletterIssuePage({ slug }) {
+ const { navigate } = useNav();
+ const [issue, setIssue] = useState(null);
+ const [error, setError] = useState(false);
+
+ useEffect(() => {
+ let cancelled = false;
+ setError(false);
+ contentApi.getNewsletterIssue(slug)
+ .then((row) => { if (!cancelled) setIssue(row); })
+ .catch(() => { if (!cancelled) setError(true); });
+ return () => { cancelled = true; };
+ }, [slug]);
+
+ if (error) return
;
+ if (!issue) return در حال بارگذاری...
;
+
+ return (
+
+
+ navigate('/newsletter')} style={{ ...pillBtn, background: '#F4EFE6', color: '#0F6B73', border: '1px solid #E4DDD2', marginBottom: 18 }}>آرشیو خبرنامه
+ {issue.subject}
+ {issue.sentAt ? new Date(issue.sentAt).toLocaleDateString('fa-IR') : ''}
+
+
+
+ );
+}
+
+function JobsPage() {
+ const toast = useToast();
+ const [items, setItems] = useState([]);
+ const [form, setForm] = useState({ company: '', title: '', location: 'Remote', remote: true, url: '', contactEmail: '', description: '' });
+ const [busy, setBusy] = useState(false);
+ useEffect(() => {
+ contentApi.listJobs().then(setItems).catch(() => setItems([]));
+ }, []);
+ const set = (key, value) => setForm((current) => ({ ...current, [key]: value }));
+ const submit = async (event) => {
+ event.preventDefault();
+ setBusy(true);
+ try {
+ await contentApi.submitJob(form);
+ setForm({ company: '', title: '', location: 'Remote', remote: true, url: '', contactEmail: '', description: '' });
+ toast('آگهی شغلی برای بررسی ارسال شد');
+ } catch {
+ toast('ارسال آگهی ناموفق بود', 'error');
+ } finally {
+ setBusy(false);
+ }
+ };
+ return (
+
+
+
فرصتهای شغلی فناوری
+
جایگاههای منتخب شرکتهای فنی فارسیزبان. آگهیهای جدید بعد از بررسی تحریریه منتشر میشوند.
+
+
+ {items.length === 0 ? : items.map((job) => (
+
+
+
+
{job.title}
+
{job.company}
+
+
{job.remote ? 'Remote' : job.location}
+
+ {job.description}
+ {job.url && مشاهده و ارسال رزومه }
+
+ ))}
+
+
+
+
+
+
+ );
+}
+
+function CoursesPage() {
+ const [items, setItems] = useState([]);
+ useEffect(() => { contentApi.listCourses().then(setItems).catch(() => setItems([])); }, []);
+ return (
+
+
+
دورههای تخصصی تکناو
+
مسیرهای آموزشی فارسی برای تیمهایی که فناوری را در محصول و عملیات واقعی به کار میگیرند.
+
+ {items.map(course => (
+
+ {course.level}
+ {course.title}
+ {course.summary}
+ {course.price ? `${course.price.toLocaleString('fa-IR')} تومان` : 'بهزودی'}
+
+ ))}
+
+
+
+ );
+}
+
+function MembershipPage() {
+ const { navigate } = useNav();
+ const { user } = useAuth();
+ const toast = useToast();
+ const [loading, setLoading] = useState(false);
+ const [status, setStatus] = useState(null);
+
+ useEffect(() => {
+ fetch('/api/v1/membership/status', { credentials: 'include' })
+ .then((r) => r.ok ? r.json() : null)
+ .then((d) => d && setStatus(d))
+ .catch(() => {});
+ }, []);
+
+ const subscribe = async () => {
+ if (!user) { navigate('/login'); return; }
+ setLoading(true);
+ try {
+ const res = await fetch('/api/v1/membership/subscribe', {
+ method: 'POST', credentials: 'include',
+ headers: { 'Content-Type': 'application/json' },
+ });
+ const data = await res.json();
+ if (data.redirectUrl) {
+ window.location.href = data.redirectUrl;
+ } else {
+ toast(data.error === 'payment_unavailable' ? 'درگاه پرداخت در دسترس نیست' : 'خطا در اتصال به درگاه پرداخت');
+ setLoading(false);
+ }
+ } catch {
+ toast('خطا در ارتباط با سرور');
+ setLoading(false);
+ }
+ };
+
+ const isPremium = status?.active;
+
+ return (
+
+
+
عضویت پریمیوم تکناو
+
+ تجربه بدون تبلیغ، مقالههای اختصاصی، دورههای کوتاه و گزارشهای عمیق برای خوانندگان حرفهای.
+
+
+ {isPremium && (
+
+ ✓ شما در حال حاضر عضو ویژه هستید
+ {status?.expiresAt && ` — اعتبار تا ${new Date(status.expiresAt).toLocaleDateString('fa-IR')}`}
+
+ )}
+
+
+ {[
+ ['👑', 'بدون تبلیغ', 'خواندن آرام و سریعتر بدون جایگاههای تبلیغاتی.'],
+ ['📖', 'محتوای اختصاصی', 'تحلیلهای عمیقتر و پروندههای تخصصی برای اعضا.'],
+ ['🎓', 'تخفیف دورهها', 'دسترسی زودتر و تخفیف روی دورههای فارسی تکناو.'],
+ ].map(([icon, title, body]) => (
+
+ {icon}
+ {title}
+ {body}
+
+ ))}
+
+
+ {!isPremium && (
+
+
+ سالانه — ۵۰۰,۰۰۰ تومان
+
+
+ {loading ? 'در حال اتصال به درگاه...' : 'شروع عضویت ویژه'}
+
+
+ )}
+
+
+ );
+}
+
+function MembershipSuccessPage() {
+ const { navigate } = useNav();
+ return (
+
+
+
👑
+
عضویت ویژه فعال شد!
+
از حالا به همه مقالات پریمیوم دسترسی دارید. ممنون از حمایت شما از تکناو.
+
navigate('/')} style={{ ...pillBtn, background: '#0F6B73', color: '#fff', padding: '12px 28px', fontSize: 14 }}>بازگشت به خانه
+
+
+ );
+}
+
+// ── Shared legal page shell ──────────────────────────────────────────────────
+function LegalPage({ title, subtitle, children }) {
+ return (
+
+
+
+
{title}
+ {subtitle &&
{subtitle}
}
+
+
+
+ {children}
+
+
+
+ );
+}
+
+function LegalSection({ title, children }) {
+ return (
+
+ );
+}
+
+// ── Privacy Policy ───────────────────────────────────────────────────────────
+function PrivacyPolicyPage() {
+ return (
+
+
+ تکناو اطلاعات زیر را از کاربران جمعآوری میکند:
+
+ اطلاعات حساب کاربری: نام، آدرس ایمیل و نام کاربری هنگام ثبتنام.
+ اطلاعات استفاده: صفحات بازدیدشده، مقالات مطالعهشده، مدت زمان حضور در سایت و واکنشهای کاربری — بهصورت ناشناس و جمعی.
+ اطلاعات فنی: نوع مرورگر، سیستمعامل و آدرس IP بهمنظور امنیت و رفع اشکال.
+ اطلاعات خبرنامه: آدرس ایمیل در صورت عضویت اختیاری در خبرنامه.
+
+
+
+
+ اطلاعات جمعآوریشده صرفاً برای موارد زیر استفاده میشود:
+
+ ارائه و بهبود محتوا و خدمات تکناو
+ ارسال خبرنامه در صورت اشتراک داوطلبانه
+ تشخیص و پیشگیری از دسترسی غیرمجاز و سوءاستفاده
+ پاسخ به درخواستها و پشتیبانی کاربران
+
+ تکناو اطلاعات شخصی شما را به هیچ شخص ثالثی نمیفروشد.
+
+
+
+ تکناو از کوکیهای ضروری برای مدیریت نشست (session) و از localStorage برای ذخیره تنظیمات رابط کاربری استفاده میکند. هیچ کوکی تبلیغاتی یا ردیابی شخصثالث استفاده نمیشود.
+
+
+
+ اطلاعات کاربران با رمزنگاری Argon2id (کلمه عبور) و HTTPS (انتقال داده) محافظت میشوند. دسترسی به دادههای شخصی به حداقل افراد ضروری محدود است.
+
+
+
+ شما حق دارید هر زمان درخواست دسترسی، اصلاح، یا حذف اطلاعات شخصی خود را از طریق info@teknav.ir ارسال کنید. درخواستها ظرف ۱۴ روز کاری پردازش میشوند.
+
+
+
+ تکناو ممکن است این سیاست را بهروزرسانی کند. تغییرات مهم از طریق اعلان درونسایتی اطلاعرسانی خواهند شد. ادامه استفاده از سایت پس از انتشار تغییرات بهمنزله پذیرش آنها است.
+
+
+
+ برای سوالات مرتبط با حریم خصوصی با ما از طریق info@teknav.ir تماس بگیرید.
+
+
+ );
+}
+
+// ── Terms of Use ─────────────────────────────────────────────────────────────
+function TermsOfUsePage() {
+ return (
+
+
+ با دسترسی به وبسایت تکناو (teknav.ir) شما موافقت خود را با این شرایط اعلام میکنید. اگر با هر بخشی از این شرایط موافق نیستید، لطفاً از استفاده از سایت خودداری کنید.
+
+
+
+ تمامی محتوای منتشرشده در تکناو — شامل مقالات، تحلیلها، نمودارها، و طراحیها — متعلق به تکناو یا نویسندگان مربوطه است و تحت قوانین مالکیت معنوی محافظت میشود.
+ نقلقول کوتاه با ذکر منبع (لینک مستقیم به مقاله) مجاز است. بازنشر کامل یا ترجمه بدون اجازه کتبی ممنوع است.
+
+
+
+
+ مسئولیت حفظ امنیت اطلاعات ورود به سیستم با کاربر است.
+ ایجاد چندین حساب کاربری توسط یک شخص مجاز نیست.
+ تکناو حق تعلیق یا حذف حسابهای ناقض قوانین را دارد.
+
+
+
+
+ کاربران متعهد میشوند که از سایت برای موارد زیر استفاده نکنند:
+
+ انتشار محتوای توهینآمیز، خلاف قانون، یا گمراهکننده
+ ارسال هرزنامه (spam) یا تلاش برای دسترسی غیرمجاز
+ تداخل در عملکرد سیستم یا سرویسهای تکناو
+
+
+
+
+ محتوای تکناو صرفاً جنبه اطلاعرسانی و آموزشی دارد. تکناو در قبال تصمیماتی که بر اساس محتوای منتشرشده اتخاذ میشوند مسئولیتی نمیپذیرد. صحت اطلاعات فنی در حد توان بررسی میشود اما ضمانت کامل داده نمیشود.
+
+
+
+ تکناو حق دارد هر زمان خدمات، محتوا، یا این شرایط را تغییر دهد. اطلاعرسانی تغییرات مهم از طریق سایت انجام میشود.
+
+
+
+ این شرایط تابع قوانین جمهوری اسلامی ایران است. هرگونه اختلاف در صلاحیت دادگاههای ایران رسیدگی خواهد شد.
+
+
+
+ برای سوالات حقوقی با ما از طریق info@teknav.ir در ارتباط باشید.
+
+
+ );
+}
+
+// ── About Page ───────────────────────────────────────────────────────────────
+function AboutPage() {
+ const { navigate } = useNav();
+ return (
+
+
+ تکناو یک نشریه فناوری فارسیزبان است که با هدف تولید محتوای عمیق، علمی، و کاربردی برای متخصصان، پژوهشگران، و علاقهمندان ایرانی فعالیت میکند. ما باور داریم که جامعه فارسیزبان به منابع تخصصیای نیاز دارد که نه صرفاً ترجمه، بلکه تحلیل و تولید اصیل باشند.
+
+
+
+
+ {[
+ ['هوش مصنوعی', 'یادگیری ماشین، مدلهای زبانی بزرگ، سیستمهای هوشمند'],
+ ['علم داده', 'مهندسی داده، پایپلاینها، ارزیابی کمی'],
+ ['امنیت سایبری', 'تهدیدات نوظهور، رمزنگاری، تست نفوذ'],
+ ['سختافزار', 'پردازندهها، شتابدهندههای هوش مصنوعی، زیرساخت'],
+ ['نرمافزار', 'معماری سیستم، مهندسی نرمافزار، ابزارهای توسعه'],
+ ['آینده فناوری', 'روندهای بلندمدت، تأثیر اجتماعی فناوری'],
+ ].map(([t, d]) => (
+
+
+ {t}: {d}
+
+ ))}
+
+
+
+
+ هر مقاله تکناو با بررسی منابع اولیه، مقالات علمی، و تجربه عملی تهیه میشود. ما از هوش مصنوعی بهعنوان ابزار کمکی در ویرایش استفاده میکنیم اما تحلیل، نتیجهگیری، و دیدگاهها کاملاً انسانی هستند.
+
+
+
+ تکناو توسط آرسام صباغ — پژوهشگر ارشد هوش مصنوعی و مهندسی داده — بنیانگذاری شده و با همکاری نویسندگان متخصص در حوزههای مختلف فناوری فعالیت میکند.
+
+ navigate('/authors')} style={{ background: '#0F6B73', color: '#fff', border: 'none', borderRadius: 8, padding: '10px 20px', fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ مشاهده تیم نویسندگان
+
+ navigate('/contact')} style={{ background: 'transparent', color: '#0F6B73', border: '1px solid #0F6B73', borderRadius: 8, padding: '10px 20px', fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ تماس با ما
+
+
+
+
+
+ وبسایت: teknav.ir
+ ایمیل: info@teknav.ir
+ تهران، ایران
+
+
+ );
+}
+
+// ── Contact Page ─────────────────────────────────────────────────────────────
+function ContactPage() {
+ const { navigate } = useNav();
+ const toast = useToast();
+ const [form, setForm] = useState({ name: '', email: '', subject: '', message: '' });
+ const [sent, setSent] = useState(false);
+
+ const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
+
+ const submit = async (e) => {
+ e.preventDefault();
+ if (!form.name.trim() || !form.email.includes('@') || !form.message.trim()) {
+ toast('لطفاً همه فیلدهای ضروری را پر کنید', 'error');
+ return;
+ }
+ try {
+ await fetch('/api/contact', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(form),
+ });
+ } catch {}
+ setSent(true);
+ };
+
+ if (sent) return (
+
+
+
✓
+
پیام شما ارسال شد
+
ممنون از تماس شما. تیم تکناو بهزودی پاسخ خواهد داد.
+
navigate('/')} style={{ background: '#0F6B73', color: '#fff', border: 'none', borderRadius: 8, padding: '12px 28px', fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ بازگشت به خانه
+
+
+
+ );
+
+ const field = { background: '#FAF7F0', border: '1px solid #D8D0C4', borderRadius: 8, padding: '11px 14px', fontSize: 14, fontFamily: 'Vazirmatn,sans-serif', color: '#263238', width: '100%', boxSizing: 'border-box', outline: 'none', direction: 'rtl' };
+
+ return (
+
+
+
+ {[
+ ['📧', 'ایمیل عمومی', 'info@teknav.ir'],
+ ['✍️', 'همکاری محتوایی', 'admin@teknavglobal.com'],
+ ['📍', 'موقعیت', 'تهران، ایران'],
+ ].map(([icon, label, val]) => (
+
+
{icon}
+
{label}
+
{val}
+
+ ))}
+
+
+
+
+
+
+
+ موضوع
+ set('subject', e.target.value)} placeholder="موضوع پیام" style={field} />
+
+
+ پیام *
+ set('message', e.target.value)} placeholder="پیام خود را اینجا بنویسید..." rows={5} style={{ ...field, resize: 'vertical', lineHeight: 1.8 }} />
+
+
+ ارسال پیام
+
+
+
+
+ );
+}
+
+// ── Tools Page ───────────────────────────────────────────────────────────────
+function ToolsPage() {
+ const { navigate } = useNav();
+ return (
+
+
+ {[
+ {
+ title: 'نرمالساز متن فارسی (NLP)',
+ desc: 'اصلاح حروف عربی، تنظیم نیمفاصلهها، حذف کدهای HTML و فاصلههای مکرر در متون فارسی برای پیشپردازش سیستمهای هوش مصنوعی.',
+ path: '/tools/nlp-normalizer',
+ icon: '📝',
+ },
+ {
+ title: 'محاسبهگر چانک و زمینه RAG',
+ desc: 'شبیهسازی تکهبندی متون، همپوشانی (Overlap)، محاسبه تعداد چانکها و برآورد تعداد توکنهای فارسی برای پایپلاینهای Retrieval-Augmented Generation.',
+ path: '/tools/rag-calculator',
+ icon: '📐',
+ },
+ ].map((t) => (
+
+
+
{t.icon}
+
{t.title}
+
{t.desc}
+
+
navigate(t.path)} style={{ background: '#0F6B73', color: '#fff', border: 'none', borderRadius: 8, padding: '10px 18px', fontSize: 13, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif', width: '100%' }}>
+ ورود به ابزار
+
+
+ ))}
+
+
+ );
+}
+
+// ── NLP Normalizer Page ──────────────────────────────────────────────────────
+function NlpNormalizerPage() {
+ const { navigate } = useNav();
+ const toast = useToast();
+ const [text, setText] = useState('');
+ const [normalized, setNormalized] = useState('');
+ const [options, setOptions] = useState({
+ stripHtml: true,
+ normalizeLetters: true,
+ normalizeZwnj: true,
+ cleanWhitespace: true,
+ });
+
+ const toggle = (k) => setOptions((o) => ({ ...o, [k]: !o[k] }));
+
+ const handleNormalize = () => {
+ let t = text || '';
+ if (options.stripHtml) {
+ t = t.replace(/<[^>]*>/g, ' ');
+ }
+ if (options.normalizeLetters) {
+ t = t.replace(/ي/g, 'ی').replace(/ك/g, 'ک').replace(/ة/g, 'ه');
+ }
+ if (options.normalizeZwnj) {
+ t = t.replace(/\s+(می|نمی)\s+/g, ' $1');
+ t = t.replace(/\s+(تر|ترین|ها|های|ام|ات|اش|مان|تان|شان)\b/g, '$1');
+ t = t.replace(/\b(می|نمی)\b\s+/g, '$1');
+ }
+ if (options.cleanWhitespace) {
+ t = t.replace(/\s+/g, ' ');
+ t = t.replace(/\n\s*\n+/g, '\n\n');
+ }
+ setNormalized(t.trim());
+ toast('متن با موفقیت نرمالسازی شد', 'success');
+ };
+
+ const copyToClipboard = (val) => {
+ if (!val) return;
+ navigator.clipboard.writeText(val);
+ toast('کپی شد!', 'success');
+ };
+
+ const textareaStyle = {
+ width: '100%',
+ minHeight: 180,
+ background: '#FAF7F0',
+ border: '1px solid #D8D0C4',
+ borderRadius: 8,
+ padding: '12px 16px',
+ fontSize: 14,
+ fontFamily: 'Vazirmatn, sans-serif',
+ color: '#263238',
+ outline: 'none',
+ lineHeight: 1.7,
+ resize: 'vertical',
+ boxSizing: 'border-box',
+ };
+
+ return (
+
+
+
+ متن ورودی:
+ setText(e.target.value)}
+ placeholder="متن فارسی خود را برای نرمالسازی اینجا وارد کنید..."
+ style={textareaStyle}
+ />
+
+
+
+
تنظیمات نرمالسازی
+
+ {[
+ ['stripHtml', 'حذف تگهای HTML'],
+ ['normalizeLetters', 'تبدیل ی و ک عربی به فارسی'],
+ ['normalizeZwnj', 'تنظیم نیمفاصلههای پیشوند/پسوند'],
+ ['cleanWhitespace', 'اصلاح فاصلهها و تبهای مکرر'],
+ ].map(([k, label]) => (
+
+ toggle(k)} style={{ accentColor: '#0F6B73' }} />
+ {label}
+
+ ))}
+
+
+
+
+
+ نرمالسازی متن
+
+ navigate('/tools')} style={{ background: 'transparent', color: '#5F6B6D', border: '1px solid #D8D0C4', borderRadius: 8, padding: '12px 20px', fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ بازگشت
+
+
+
+ {normalized && (
+
+
+ متن خروجی:
+ copyToClipboard(normalized)} style={{ background: '#FAF7F0', border: '1px solid #D8D0C4', borderRadius: 6, padding: '6px 12px', fontSize: 12, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif', display: 'flex', alignItems: 'center', gap: 6 }}>
+ 📋 کپی خروجی
+
+
+
+
+ )}
+
+
+
ارجاع علمی و اشتراکگذاری
+
برای استفاده از خروجیهای این ابزار در تحقیقات یا کارهای متنباز خود، میتوانید از فرمت ارجاع زیر استفاده کنید:
+
+ [Teknav Persian NLP Tool] (https://www.teknav.ir/tools/nlp-normalizer)
+ copyToClipboard('[Teknav Persian NLP Tool] (https://www.teknav.ir/tools/nlp-normalizer)')} style={{ background: '#fff', border: '1px solid #D8D0C4', borderRadius: 4, padding: '2px 8px', fontSize: 10, cursor: 'pointer', fontFamily: 'sans-serif' }}>Copy
+
+
+
+
+ );
+}
+
+// ── RAG Calculator Page ──────────────────────────────────────────────────────
+function RagCalculatorPage() {
+ const { navigate } = useNav();
+ const toast = useToast();
+ const [text, setText] = useState('');
+ const [chunkSize, setChunkSize] = useState(500);
+ const [overlap, setOverlap] = useState(50);
+ const [chunks, setChunks] = useState([]);
+
+ const handleCalculate = () => {
+ if (!text.trim()) {
+ toast('لطفاً ابتدا متنی را برای چانکبندی وارد کنید', 'error');
+ return;
+ }
+ if (chunkSize <= 0 || overlap < 0 || overlap >= chunkSize) {
+ toast('اندازه چانک یا همپوشانی نامعتبر است', 'error');
+ return;
+ }
+
+ const t = text.trim();
+ const result = [];
+ let start = 0;
+
+ while (start < t.length) {
+ let end = start + chunkSize;
+ if (end > t.length) end = t.length;
+
+ const content = t.substring(start, end);
+ const estimatedTokens = Math.round(content.length / 3.8);
+
+ result.push({
+ id: result.length + 1,
+ content,
+ charCount: content.length,
+ tokenCount: estimatedTokens,
+ range: [start, end],
+ });
+
+ start += (chunkSize - overlap);
+ if (start >= t.length || end === t.length) break;
+ }
+
+ setChunks(result);
+ toast(`تکهبندی با موفقیت انجام شد (${result.length} چانک)`, 'success');
+ };
+
+ const copyToClipboard = (val) => {
+ if (!val) return;
+ navigator.clipboard.writeText(val);
+ toast('کپی شد!', 'success');
+ };
+
+ return (
+
+
+
+ متن نمونه:
+ setText(e.target.value)}
+ placeholder="متن فارسی مورد نظر برای شبیهسازی RAG را در این قسمت بنویسید..."
+ style={{ width: '100%', minHeight: 140, background: '#FAF7F0', border: '1px solid #D8D0C4', borderRadius: 8, padding: '12px 16px', fontSize: 14, fontFamily: 'Vazirmatn, sans-serif', color: '#263238', outline: 'none', lineHeight: 1.7, resize: 'vertical', boxSizing: 'border-box' }}
+ />
+
+
+
+
پارامترهای شبیهسازی
+
+
+ اندازه هر تکه (به کاراکتر):
+ setChunkSize(Number(e.target.value))} style={{ width: '100%', padding: '10px 12px', border: '1px solid #D8D0C4', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn, sans-serif' }} />
+
+
+ اندازه همپوشانی (Overlap):
+ setOverlap(Number(e.target.value))} style={{ width: '100%', padding: '10px 12px', border: '1px solid #D8D0C4', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn, sans-serif' }} />
+
+
+
+
+
+
+ محاسبه و شبیهسازی
+
+ navigate('/tools')} style={{ background: 'transparent', color: '#5F6B6D', border: '1px solid #D8D0C4', borderRadius: 8, padding: '12px 20px', fontSize: 14, fontWeight: 600, cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif' }}>
+ بازگشت
+
+
+
+ {chunks.length > 0 && (
+
+
نتایج شبیهسازی تکهبندی:
+
+ {[
+ ['طول کل کاراکترها', text.length],
+ ['تعداد تخمینی توکنها', Math.round(text.length / 3.8)],
+ ['تعداد چانکهای خروجی', chunks.length],
+ ].map(([lbl, val]) => (
+
+
{lbl}
+
{val.toLocaleString('fa-IR')}
+
+ ))}
+
+
+
+ {chunks.map((c) => (
+
+
+
چانک #{c.id.toLocaleString('fa-IR')} (اندیس {c.range[0].toLocaleString('fa-IR')} تا {c.range[1].toLocaleString('fa-IR')})
+
+ {c.charCount.toLocaleString('fa-IR')} کاراکتر · {c.tokenCount.toLocaleString('fa-IR')} توکن تخمینی
+ copyToClipboard(c.content)} style={{ background: '#fff', border: '1px solid #D8D0C4', borderRadius: 4, padding: '3px 8px', fontSize: 11, cursor: 'pointer', fontFamily: 'Vazirmatn, sans-serif' }}>کپی
+
+
+
+ {c.content}
+
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+// ── TekRAG Persian Hub Page ──────────────────────────────────────────────────
+function TekRagHubPage() {
+ const toast = useToast();
+ const copyToClipboard = (val) => {
+ navigator.clipboard.writeText(val);
+ toast('کپی شد!', 'success');
+ };
+
+ const citationText = `@article{tekrag_persian_2026,
+ title={TekRAG-Persian: A Data-Centric Evaluation Framework for Hallucination in Persian Retrieval-Augmented Generation},
+ author={Sabbagh, Arsam},
+ journal={Teknav Journal of AI Research},
+ volume={1},
+ number={1},
+ pages={10-24},
+ year={2026},
+ publisher={Teknav Media}
+}`;
+
+ return (
+
+
+
+ TekRAG-Persian اولین مجموعه داده و چارچوب بنچمارک متمرکز بر زبان فارسی برای سنجش و کاهش میزان توهم در پیادهسازیهای RAG است. این پروژه بر مبنای تحلیل مقالههای تخصصی رسانه تکناو و پاسخدهی دقیق مدلهای زبانی بزرگ توسعه داده شده است.
+ هدف این بنچمارک ارزیابی سه متغیر کلیدی در بهبود عملکرد سیستمهای بازیابی است: پاکسازی پیشرفته متن، افزودن متادیتاهای ساختاریافته به تکهها، و تأثیر هدایت مدل با تأکید بر استناد به منابع اصلی.
+
+
+
+
+ {[
+ ['💾 مجموعه داده در Hugging Face', 'دسترسی به فایلهای خام متون و پرسشها', 'https://huggingface.co/datasets/teknav/tekrag-persian', 'مشاهده دیتاست'],
+ ['🔗 شناسه دیجیتال Zenodo (DOI)', 'نسخه آرشیو شده و معتبر علمی پژوهش', 'https://doi.org/10.5281/zenodo.placeholder', 'مشاهده DOI'],
+ ['⚙️ سورسکد در GitHub', 'کدهای پیادهسازی و ارزیابی بنچمارک', 'https://github.com/teknav/tekrag-persian', 'مشاهده ریپازیتوری'],
+ ].map(([title, desc, link, btnText]) => (
+
+ ))}
+
+
+
+
+ اگر از این بنچمارک یا دیتاست در پژوهشهای دانشگاهی یا پروژههای علمی خود استفاده میکنید، لطفاً با فرمت BibTeX زیر به آن ارجاع دهید:
+
+
copyToClipboard(citationText)} style={{ position: 'absolute', top: 12, left: 12, background: '#fff', border: '1px solid #D8D0C4', borderRadius: 6, padding: '5px 10px', fontSize: 11, cursor: 'pointer', fontFamily: 'Vazirmatn, sans-serif' }}>
+ 📋 کپی ارجاع
+
+
+ {citationText}
+
+
+
+
+
+ این بنچمارک شامل بخشهای زیر در فرمت JSON است:
+
+ {[
+ ['Corpus (بدنه داده)', 'شامل مقالههای تخصصی با تگها، دستهبندی، پاراگرافها و عناوین مجزا.'],
+ ['Questions (سوالات)', '۲۰۰ سوال واقعی طراحی شده توسط متخصصان در سطوح مختلف دشواری.'],
+ ['Gold Annotations (پاسخهای طلایی)', 'تکههای دقیق پشتیبان برای هر سوال جهت سنجش بازیابی درست اطلاعات.'],
+ ].map(([t, d]) => (
+
+ {t}
+ {d}
+
+ ))}
+
+
+
+
+ );
+}
+
+function ComparisonVoteBar({ slug, item1, item2 }) {
+ const key = `cmp_vote_${slug}`;
+ const [vote, setVote] = useState(() => {
+ try { return localStorage.getItem(key) || null; } catch { return null; }
+ });
+ const [shared, setShared] = useState(false);
+
+ const cast = (choice) => {
+ try { localStorage.setItem(key, choice); } catch {}
+ setVote(choice);
+ };
+
+ const shareComparison = () => {
+ const url = `https://www.teknav.ir/compare/${slug}`;
+ if (navigator.share) {
+ navigator.share({ title: `مقایسه ${item1.name} در برابر ${item2.name} — تکناو`, url }).catch(() => {});
+ } else {
+ navigator.clipboard?.writeText(url).then(() => { setShared(true); setTimeout(() => setShared(false), 2000); }).catch(() => {});
+ }
+ };
+
+ return (
+
+
+
شما کدام را ترجیح میدهید؟
+
+ cast('item1')}
+ style={{
+ flex: 1, padding: '9px 16px', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn,sans-serif', cursor: 'pointer', fontWeight: 700, transition: 'all 0.15s',
+ background: vote === 'item1' ? '#0F6B73' : '#fff',
+ color: vote === 'item1' ? '#fff' : '#0F6B73',
+ border: `2px solid ${vote === 'item1' ? '#0F6B73' : '#E4DDD2'}`,
+ }}
+ >
+ {vote === 'item1' ? '✓ ' : ''}{item1.name}
+
+ cast('item2')}
+ style={{
+ flex: 1, padding: '9px 16px', borderRadius: 8, fontSize: 14, fontFamily: 'Vazirmatn,sans-serif', cursor: 'pointer', fontWeight: 700, transition: 'all 0.15s',
+ background: vote === 'item2' ? '#D49A2A' : '#fff',
+ color: vote === 'item2' ? '#fff' : '#D49A2A',
+ border: `2px solid ${vote === 'item2' ? '#D49A2A' : '#E4DDD2'}`,
+ }}
+ >
+ {vote === 'item2' ? '✓ ' : ''}{item2.name}
+
+
+ {vote && (
+
+ انتخاب شما ثبت شد. برای تغییر دوباره کلیک کنید.
+
+ )}
+
+
+ {shared ? '✓ لینک کپی شد' : '🔗 اشتراکگذاری'}
+
+
+ );
+}
+
+function ComparisonPage({ slug }) {
+ const { navigate } = useNav();
+ const comparison = (TeknavData.comparisons ?? []).find((c) => c.slug === slug);
+
+ if (!comparison) {
+ return (
+
+
+
+ );
+ }
+
+ const { item1, item2, verdict, useCases = [], relatedArticles = [], relatedGlossary = [] } = comparison;
+ const articles = TeknavData.articles.filter((a) => relatedArticles.includes(a.slug));
+ const glossaryTerms = (TeknavData.glossary ?? []).filter((g) => relatedGlossary.includes(g.slug));
+
+ const cardStyle = {
+ background: '#fff', borderRadius: 12, padding: 24,
+ border: '1px solid #E4DDD2', flex: '1 1 300px',
+ };
+ const proStyle = { fontSize: 13, color: '#2E7D32', marginBottom: 6, display: 'flex', alignItems: 'flex-start', gap: 6 };
+ const conStyle = { fontSize: 13, color: '#C62828', marginBottom: 6, display: 'flex', alignItems: 'flex-start', gap: 6 };
+
+ return (
+
+ {/* Breadcrumb */}
+
+ navigate('/')}>تکناو
+ ›
+ navigate('/compare')}>مقایسهها
+ ›
+ {comparison.title}
+
+
+ {/* Header */}
+
+ {comparison.title}
+
+ {comparison.metaDescription && (
+
{comparison.metaDescription}
+ )}
+ {comparison.factCheckedAt && (
+
+ آخرین بروزرسانی: {comparison.factCheckedAt}
+
+ )}
+
+ {/* Vote + Share bar */}
+
+
+ {/* Two-column cards */}
+
+ {[item1, item2].map((item) => (
+
+
{item.name}
+
{item.summary}
+
مزایا
+ {(item.pros || []).map((p, i) => (
+
✓ {p}
+ ))}
+
معایب
+ {(item.cons || []).map((c, i) => (
+
✗ {c}
+ ))}
+
+ ))}
+
+
+ {/* Use Cases */}
+ {useCases.length > 0 && (
+
+ چه زمانی کدام را انتخاب کنیم؟
+ {useCases.map(([left, right], i) => (
+
+
+ {item1.name}: {left}
+
+
+ {item2.name}: {right}
+
+
+ ))}
+
+ )}
+
+ {/* Verdict */}
+ {verdict && (
+
+ جمعبندی و نتیجهگیری
+ {verdict}
+
+ )}
+
+ {/* Related Glossary */}
+ {glossaryTerms.length > 0 && (
+
+ اصطلاحات مرتبط
+
+ {glossaryTerms.map((g) => (
+
navigate(`/glossary/${g.slug}`)}
+ style={{ background: '#fff', border: '1px solid #0F6B73', borderRadius: 8, padding: '10px 16px', cursor: 'pointer' }}
+ >
+
{g.term}
+
{g.english}
+
+ ))}
+
+
+ )}
+
+ {/* Related Articles */}
+ {articles.length > 0 && (
+
+ مقالات مرتبط
+
+ {articles.map((a) => (
+
navigate(`/article/${a.slug}`)}
+ style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 8, padding: '14px 18px', cursor: 'pointer', display: 'flex', gap: 12, alignItems: 'flex-start' }}
+ >
+
+
{a.title}
+
{a.summary?.slice(0, 100)}…
+
+
←
+
+ ))}
+
+
+ )}
+
+ );
+}
+
+function DirectoryListPage() {
+ const { navigate } = useNav();
+ const [companies] = useState(() => TeknavData.companies ?? []);
+ const [search, setSearch] = useState('');
+
+ const filtered = useMemo(() => {
+ if (!search.trim()) return companies;
+ const q = search.trim().toLocaleLowerCase('fa-IR');
+ return companies.filter((c) =>
+ c.name.toLocaleLowerCase('fa-IR').includes(q) ||
+ c.description.toLocaleLowerCase('fa-IR').includes(q) ||
+ (c.techStack || []).some((t) => t.toLocaleLowerCase('en-US').includes(q)),
+ );
+ }, [companies, search]);
+
+ return (
+
+
+ navigate('/')}>تکناو
+ ›
+ دایرکتوری شرکتهای فناوری
+
+
+ دایرکتوری شرکتهای فناوری ایران
+
+
+ پروفایل شرکتهای فناوری ایران همراه با استک فنی، اطلاعات تماس و نشان تأیید.
+
+
setSearch(e.target.value)}
+ style={{ ...inputStyle, marginBottom: 24, width: '100%', maxWidth: 400 }}
+ />
+ {filtered.length === 0 && (
+
+ )}
+
+ {filtered.map((company) => (
+
navigate(`/directory/${company.slug}`)}
+ style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 12, padding: 20, cursor: 'pointer', transition: 'box-shadow 0.2s' }}
+ onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 4px 16px rgba(0,0,0,0.1)'; }}
+ onMouseLeave={(e) => { e.currentTarget.style.boxShadow = ''; }}
+ >
+
+ {company.name}
+ {company.verified && ✓ تأیید }
+
+
{company.description.slice(0, 100)}…
+
+ {(company.techStack || []).slice(0, 4).map((t) => (
+ {t}
+ ))}
+
+
+ ))}
+
+
+ );
+}
+
+function CompanyProfilePage({ slug }) {
+ const { navigate } = useNav();
+ const company = (TeknavData.companies ?? []).find((c) => c.slug === slug);
+
+ if (!company) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
+ navigate('/')}>تکناو
+ ›
+ navigate('/directory')}>دایرکتوری
+ ›
+ {company.name}
+
+
+
+
+
{company.name}
+ {company.verified && (
+ ✓ تأیید شده
+ )}
+
+
{company.description}
+
+
+
+
+
+ {(company.techStack || []).length > 0 && (
+
+ استک فناوری
+
+ {company.techStack.map((t) => (
+ {t}
+ ))}
+
+
+ )}
+
+
+
+ این صفحه بخشی از دایرکتوری شرکتهای فناوری تکناو است. اگر این شرکت را نمایندگی میکنید، میتوانید پروفایل آن را ادعا و تأیید کنید.
+
+
navigate('/login')}
+ >
+ ادعای پروفایل
+
+
+
+ );
+}
+
+const CATEGORY_COLORS = { ai: '#0F6B73', data: '#2F8F6B', security: '#C62828', software: '#1565C0', hardware: '#6A1B9A' };
+
+function ComparisonsListPage() {
+ const { navigate } = useNav();
+ const comparisons = TeknavData.comparisons ?? [];
+ const [search, setSearch] = useState('');
+
+ const filtered = useMemo(() => {
+ if (!search.trim()) return comparisons;
+ const q = search.trim().toLocaleLowerCase('fa-IR');
+ return comparisons.filter((c) =>
+ c.title.toLocaleLowerCase('fa-IR').includes(q) ||
+ c.item1.name.toLocaleLowerCase('en-US').includes(q) ||
+ c.item2.name.toLocaleLowerCase('en-US').includes(q) ||
+ (c.tags || []).some((t) => t.toLocaleLowerCase().includes(q)),
+ );
+ }, [comparisons, search]);
+
+ return (
+
+
+ navigate('/')}>تکناو
+ › مقایسهها
+
+
مقایسههای فنی تکناو
+
+ تحلیلهای مقایسهای جامع میان فناوریها، فریمورکها و ابزارهای رایج — برای انتخاب بهتر در پروژههای فارسیزبان.
+
+
setSearch(e.target.value)}
+ style={{ ...inputStyle, marginBottom: 28, width: '100%', maxWidth: 400 }}
+ />
+
+ {filtered.map((c) => (
+
navigate(`/compare/${c.slug}`)}
+ style={{ background: '#fff', border: '1px solid #E4DDD2', borderRadius: 12, padding: '20px 24px', cursor: 'pointer', display: 'flex', gap: 20, alignItems: 'center' }}
+ onMouseEnter={(e) => { e.currentTarget.style.boxShadow = '0 4px 16px rgba(0,0,0,0.09)'; }}
+ onMouseLeave={(e) => { e.currentTarget.style.boxShadow = ''; }}
+ >
+
+
+
+ {c.category}
+
+ {(c.tags || []).slice(0, 3).map((t) => (
+ {t}
+ ))}
+
+
{c.title}
+
+ {c.item1.name}
+ در برابر
+ {c.item2.name}
+
+
+
←
+
+ ))}
+ {filtered.length === 0 &&
}
+
+
+ );
+}
+
+function StoriesListPage() {
+ const { navigate } = useNav();
+ const today = new Date().toISOString().slice(0, 10);
+ const stories = (TeknavData.articles ?? []).filter((a) => {
+ if (a.status !== 'منتشرشده' && a.status) return false;
+ const d = String(a.dateEn || '').slice(0, 10);
+ return /^\d{4}-\d{2}-\d{2}$/.test(d) && d <= today;
+ });
+
+ return (
+
+
+ navigate('/')}>تکناو
+ › استوریها
+
+
استوریهای تکناو
+
+ مقالات تکناو در قالب استوریهای بصری — سریع، قابل اسوایپ و بهینه برای موبایل.
+
+
+ {stories.map((a) => {
+ const img = a.ogImage || `/images/og/${a.slug}.jpg`;
+ return (
+
{ window.open(`/stories/${a.slug}`, '_blank'); }}
+ style={{ borderRadius: 14, overflow: 'hidden', cursor: 'pointer', position: 'relative', paddingBottom: '177%', background: '#0C1E22' }}
+ onMouseEnter={(e) => { e.currentTarget.style.transform = 'scale(1.03)'; e.currentTarget.style.boxShadow = '0 8px 24px rgba(0,0,0,0.25)'; }}
+ onMouseLeave={(e) => { e.currentTarget.style.transform = ''; e.currentTarget.style.boxShadow = ''; }}
+ >
+
+
+
{a.categoryName}
+
{a.title.slice(0, 55)}{a.title.length > 55 ? '…' : ''}
+
+
+ ▶ استوری
+
+
+ );
+ })}
+
+
+ );
+}
+
+export { SearchPage, CategoryPage, TagPage, GlossaryPage, AuthorsListPage, AuthorProfilePage, SeriesPage, TopicHubPage, NewsletterArchivePage, NewsletterIssuePage, JobsPage, CoursesPage, MembershipPage, MembershipSuccessPage, PrivacyPolicyPage, TermsOfUsePage, AboutPage, ContactPage, ToolsPage, NlpNormalizerPage, RagCalculatorPage, TekRagHubPage, ComparisonPage, DirectoryListPage, CompanyProfilePage, ComparisonsListPage, StoriesListPage };