diff --git a/app/teknav-articles.jsx b/app/teknav-articles.jsx
new file mode 100644
index 0000000..72a589f
--- /dev/null
+++ b/app/teknav-articles.jsx
@@ -0,0 +1,1145 @@
+import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
+import { TeknavData } from './teknav-data.js';
+import {
+ useNav, useToast, useAuth,
+ AuthorAvatar, CategoryBadge, TypeBadge, StatusBadge, EmptyState, Header, ReadingProgress,
+ ReadingListModal,
+ inputStyle, pillBtn, iconBtnStyle, useViewportPrefetch,
+} from './teknav-ui.jsx';
+import { LazyDiagram } from './src/components/lazy-diagram.jsx';
+import { ArticleCard } from './teknav-home.jsx';
+import { contentApi } from './src/lib/content-api.js';
+import { engagementApi } from './src/lib/engagement-api.js';
+import { QuoteSharer } from './src/components/QuoteSharer.jsx';
+import { iconNode } from './src/lib/icon.jsx';
+import crownIcon from './src/assets/icons/crown.svg';
+import thumbsUpIcon from './src/assets/icons/thumbs-up.svg';
+import starIcon from './src/assets/icons/star.svg';
+import heartIcon from './src/assets/icons/heart.svg';
+import flameIcon from './src/assets/icons/flame.svg';
+import lightbulbIcon from './src/assets/icons/lightbulb.svg';
+
+function articleDateValue(article) {
+ return article?.dateEn || article?.publishedAt || article?.date || '';
+}
+
+function articleDateLabel(article) {
+ return article?.date || (typeof article?.publishedAt === 'string' ? article.publishedAt.slice(0, 10) : '') || article?.dateEn || '';
+}
+
+const TEKRAG_SLUG = 'tekrag-persian-data-centric-rag-benchmark';
+const isTekRagArticle = (articleOrSlug) => (typeof articleOrSlug === 'string' ? articleOrSlug : articleOrSlug?.slug) === TEKRAG_SLUG;
+
+function numberLabel(value, english = false) {
+ return Number(value ?? 0).toLocaleString(english ? 'en-US' : 'fa-IR');
+}
+
+function ArticleRow({ article, idx }) {
+ const { navigate } = useNav();
+ const [vis, setVis] = useState(false);
+ const ref = useRef();
+ useViewportPrefetch(ref, article.slug);
+ const cat = TeknavData.categories.find(c => c.id === article.category);
+ const author = TeknavData.authors.find(a => a.id === article.authorId);
+
+ useEffect(() => {
+ const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) setVis(true); }, { threshold: 0.05 });
+ if (ref.current) obs.observe(ref.current);
+ return () => obs.disconnect();
+ }, []);
+
+ return (
+
navigate('/article/' + article.slug)}
+ onMouseEnter={e => { e.currentTarget.style.opacity = '0.85'; }}
+ onMouseLeave={e => { e.currentTarget.style.opacity = '1'; }}>
+
+
+ {articleDateLabel(article)}
+ ·
+
+
+
+
{article.title}
+ {article.subtitle &&
{article.subtitle}
}
+
+
+ {author?.specialty && · }
+ {author?.specialty && {author.specialty}}
+
+
{article.summary}
+
+ {article.type}
+ ·
+ {article.readTime} دقیقه مطالعه
+ ·
+ {(article.views || 0).toLocaleString('fa')} بازدید
+ {article.tags?.slice(0, 2).map(t => (
+ {t}
+ ))}
+
+
+
+
+ );
+}
+
+function FilterBar({ filters, onChange }) {
+ const cats = [{ id: '', name: 'همه' }, ...TeknavData.categories];
+ const types = ['همه', 'تحلیل عمیق', 'راهنمای فنی', 'دادهنما', 'پژوهش', 'راستیآزماییشده', 'پرونده'];
+ const sorts = [{ v: 'latest', l: 'جدیدترین' }, { v: 'popular', l: 'پربازدیدترین' }, { v: 'readtime', l: 'زمان مطالعه' }];
+
+ const chip = (active) => ({
+ border: active ? '1.5px solid #0F6B73' : '1px solid #E4DDD2',
+ background: active ? '#0F6B7312' : '#fff',
+ color: active ? '#0F6B73' : '#5F6B6D',
+ padding: '5px 12px', borderRadius: 20, fontSize: 12, cursor: 'pointer',
+ fontFamily: 'Vazirmatn,sans-serif', fontWeight: active ? 700 : 400,
+ transition: 'all 0.15s', whiteSpace: 'nowrap',
+ });
+
+ return (
+
+
+ دسته:
+ {cats.map(c => (
+
+ ))}
+
+
+ نوع:
+ {types.map(t => (
+
+ ))}
+
+
+
+ مرتبسازی:
+ {sorts.map(s => (
+
+ ))}
+
+ {filters.q && (
+
+ جستجو: «{filters.q}»
+
+
+ )}
+
+
+ );
+}
+
+function ArticleListPage({ initQ = '' }) {
+ const [filters, setFilters] = useState({ cat: '', type: '', sort: 'latest', q: initQ });
+ const [searchInput, setSearchInput] = useState(initQ);
+ const [page, setPage] = useState(1);
+ const [allArticles, setAllArticles] = useState(() => contentApi.fallbackArticles());
+ const PER = 8;
+
+ useEffect(() => {
+ let cancelled = false;
+ contentApi.listArticles({ limit: 100 })
+ .then((res) => { if (!cancelled) setAllArticles(res.items ?? []); })
+ .catch(() => {});
+ return () => { cancelled = true; };
+ }, []);
+
+ const filtered = useMemo(() => {
+ let list = allArticles;
+ if (filters.q) {
+ const q = filters.q.toLowerCase();
+ list = list.filter(a => a.title.toLowerCase().includes(q) || a.summary.toLowerCase().includes(q) || a.authorName?.toLowerCase().includes(q) || a.categoryName?.toLowerCase().includes(q));
+ }
+ if (filters.cat) list = list.filter(a => a.category === filters.cat);
+ if (filters.type) list = list.filter(a => a.type === filters.type);
+ if (filters.sort === 'popular') list = [...list].sort((a, b) => b.views - a.views);
+ else if (filters.sort === 'readtime') list = [...list].sort((a, b) => b.readTime - a.readTime);
+ else list = [...list].sort((a, b) => articleDateValue(b).localeCompare(articleDateValue(a)));
+ return list;
+ }, [filters, allArticles]);
+
+ const visible = filtered.slice(0, page * PER);
+ const hasMore = visible.length < filtered.length;
+
+ const doSearch = (e) => { e.preventDefault(); setFilters(f => ({ ...f, q: searchInput })); setPage(1); };
+
+ return (
+
+
+
+
همه مقالهها
+
{filtered.length} مقاله یافت شد
+
+
+
{ setFilters(f); setPage(1); }} />
+
+ {visible.length === 0 ? (
+
+ ) : (
+ <>
+ {visible.map((a, i) => )}
+ {hasMore && (
+
+
+
+ )}
+ >
+ )}
+
+
+ );
+}
+
+function TableOfContents({ headings, english = false }) {
+ const [active, setActive] = useState(null);
+ useEffect(() => {
+ const obs = new IntersectionObserver(entries => {
+ entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
+ }, { rootMargin: '-20% 0px -70% 0px' });
+ headings.forEach(h => { const el = document.getElementById(h.id); if (el) obs.observe(el); });
+ return () => obs.disconnect();
+ }, [headings]);
+
+ return (
+
+ );
+}
+
+function EmbeddedDiagramCard({ title, subtitle, type, english = false }) {
+ return (
+
+
+
{title}
+ {subtitle &&
{subtitle}
}
+
+
+
+ );
+}
+
+function ArticleEmbeddedDiagrams({ slug }) {
+ if (isTekRagArticle(slug)) {
+ return null;
+ }
+ if (slug === 'ai-clean-data') {
+ return (
+
+ );
+ }
+ if (slug === 'ai-agents-2026' || slug === 'agentic-ai-production') {
+ return (
+
+
+
+
+
+
+ );
+ }
+ return null;
+}
+
+function SeriesNavBanner({ series, currentSlug }) {
+ const { navigate } = useNav();
+ const idx = series.articles.findIndex(a => a.slug === currentSlug);
+ const prev = idx > 0 ? series.articles[idx - 1] : null;
+ const next = idx < series.articles.length - 1 ? series.articles[idx + 1] : null;
+ if (!prev && !next) return null;
+ const btnBase = {
+ background: 'transparent', border: '1px solid #0F6B7330', borderRadius: 8,
+ padding: '10px 16px', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif',
+ color: '#0F6B73', fontSize: 13, fontWeight: 600, maxWidth: 280, textAlign: 'right',
+ transition: 'all 0.15s', lineHeight: 1.5,
+ };
+ return (
+
+ {prev ? (
+
+ ) :
}
+ {next ? (
+
+ ) :
}
+
+ );
+}
+
+function ArticleQaSection({ slug, english = false }) {
+ const { user } = useAuth();
+ const [items, setItems] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [body, setBody] = useState('');
+ const [replyTo, setReplyTo] = useState(null);
+ const toast = useToast();
+
+ const load = useCallback(() => {
+ setLoading(true);
+ engagementApi.listQa(slug)
+ .then(res => setItems(res.items ?? []))
+ .finally(() => setLoading(false));
+ }, [slug]);
+
+ useEffect(() => { load(); }, [load]);
+
+ const submit = async (e) => {
+ e.preventDefault();
+ if (!body.trim()) return;
+ try {
+ if (replyTo) await engagementApi.postAnswer(replyTo.id, body);
+ else await engagementApi.postQuestion(slug, body);
+ setBody('');
+ setReplyTo(null);
+ toast(english ? 'Submitted' : 'ثبت شد');
+ load();
+ } catch {
+ toast(english ? 'Submission failed' : 'خطا در ثبت', 'error');
+ }
+ };
+
+ return (
+
+ {english ? 'Questions and Answers' : 'پرسش و پاسخ'}
+ {user ? (
+
+ ) : {english ? 'Sign in to ask a question.' : 'برای پرسیدن سوال وارد شوید.'}
}
+
+ {loading ? {english ? 'Loading...' : 'در حال بارگذاری...'}
: (
+
+ {items.length === 0 &&
{english ? 'No questions yet.' : 'هنوز پرسشی ثبت نشده است.'}
}
+ {items.map(q => (
+
+
+
{q.author?.name}
+
{q.time}
+
+
{q.body}
+
+ {q.answers?.map(a => (
+
+
{a.author?.name}
+
{a.body}
+
+ ))}
+
+ ))}
+
+ )}
+
+ );
+}
+
+function ArticleCommentSection({ article, onTotal, english = false }) {
+ const { user } = useAuth();
+ const { navigate } = useNav();
+ const toast = useToast();
+ const [items, setItems] = useState([]);
+ const [body, setBody] = useState('');
+ const [replyTo, setReplyTo] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(false);
+
+ const refresh = useCallback(() => {
+ setLoading(true);
+ setError(false);
+ return engagementApi.listComments(article.slug)
+ .then(res => {
+ setItems(res?.items ?? []);
+ onTotal?.(res?.total ?? 0);
+ })
+ .catch(() => { setItems([]); setError(true); })
+ .finally(() => setLoading(false));
+ }, [article.slug, onTotal]);
+
+ useEffect(() => { refresh(); }, [refresh]);
+
+ const submit = async (e) => {
+ e.preventDefault();
+ if (!body.trim()) return;
+ try {
+ await engagementApi.postComment(article.slug, body, replyTo?.id);
+ setBody('');
+ setReplyTo(null);
+ toast(english ? 'Comment submitted' : 'نظر شما ثبت شد');
+ refresh();
+ } catch {
+ toast(english ? 'Comment submission failed' : 'ثبت نظر ناموفق بود', 'error');
+ }
+ };
+
+ const upvote = async (id) => {
+ try {
+ const res = await engagementApi.upvoteComment(id);
+ setItems(current => current.map(comment => {
+ if (comment.id === id) return { ...comment, upvotedByMe: res.upvoted, upvoteCount: res.upvoteCount };
+ return { ...comment, replies: (comment.replies ?? []).map(reply => reply.id === id ? { ...reply, upvotedByMe: res.upvoted, upvoteCount: res.upvoteCount } : reply) };
+ }));
+ } catch {
+ toast(english ? 'Sign in to vote' : 'برای رأی دادن ابتدا وارد شوید', 'warning');
+ }
+ };
+
+ const flag = async (id) => {
+ try {
+ await engagementApi.flagComment(id);
+ toast(english ? 'Report submitted' : 'گزارش نظر ثبت شد');
+ refresh();
+ } catch {
+ toast(english ? 'Sign in to report a comment' : 'برای گزارش نظر ابتدا وارد شوید', 'warning');
+ }
+ };
+
+ const like = async (id) => {
+ try {
+ const res = await engagementApi.likeComment(id);
+ setItems(current => current.map(comment => {
+ if (comment.id === id) return { ...comment, likedByMe: res.liked, likeCount: res.likeCount };
+ return { ...comment, replies: (comment.replies ?? []).map(reply => reply.id === id ? { ...reply, likedByMe: res.liked, likeCount: res.likeCount } : reply) };
+ }));
+ } catch {
+ toast(english ? 'Sign in to like a comment' : 'برای پسندیدن نظر ابتدا وارد شوید', 'warning');
+ }
+ };
+
+ const renderComment = (comment, child = false) => (
+
+
+
+
+
@{comment.author?.username ?? 'user'} · {comment.time}
+
+
+
+
+
+
+
{comment.body}
+
+
+ {user && !child && }
+
{comment.replies?.map(reply => renderComment(reply, true))}
+
+ );
+
+ return (
+
+ {english ? 'Comments' : 'نظرها'}
+ {user ? (
+
+ ) : (
+
+ {english ? 'Sign in to comment.' : 'برای نظر دادن وارد شوید.'}
+
+ )}
+ {loading && {english ? 'Loading comments...' : 'در حال بارگذاری نظرها...'}
}
+ {error && }
+ {!loading && !error && items.length === 0 && }
+ {!loading && !error && items.map(comment => renderComment(comment))}
+
+ );
+}
+
+function PremiumGateCard({ navigate, user }) {
+ return (
+
+
+
این مقاله برای اعضای ویژه
+
+ برای مطالعه کامل این مقاله، عضو ویژه تکناو شوید
+
+
+ {[
+ '✓ دسترسی به همه مقالات ویژه',
+ '✓ تجربه بدون تبلیغ',
+ '✓ حمایت مستقیم از تکناو',
+ ].map((item) => (
+ - {item}
+ ))}
+
+
+
+ {!user && (
+
+ )}
+
+
+ );
+}
+
+function ArticleDetail({ slug }) {
+ const { navigate } = useNav();
+ const { user } = useAuth();
+ const toast = useToast();
+ const contentRef = useRef(null);
+ const canonicalSlug = slug === 'ai-agents-2026' ? 'agentic-ai-production' : slug;
+ const [saved, setSaved] = useState(false);
+ const [listModalOpen, setListModalOpen] = useState(false);
+ const [reacted, setReacted] = useState({});
+ const [article, setArticle] = useState(() => contentApi.fallbackArticles().find(a => a.slug === canonicalSlug));
+ const [related, setRelated] = useState([]);
+ const [commentTotal, setCommentTotal] = useState(0);
+
+ const processedContent = useMemo(() => {
+ if (!article?.content) return '';
+ let hidx = 0;
+ const withLead = article.content.includes('class="lead"')
+ ? article.content
+ : article.content.replace(/]*class=)([^>]*)>/, '
');
+ return withLead.replace(/]*>([^<]+)<\/h\1>/g, (_, lvl, txt) => {
+ const id = 'h-' + hidx++;
+ return `${txt}`;
+ });
+ }, [article?.content]);
+
+ useEffect(() => {
+ let cancelled = false;
+ if (slug !== canonicalSlug && typeof window !== 'undefined') {
+ window.history.replaceState({}, '', `/article/${canonicalSlug}`);
+ }
+ const fallback = contentApi.fallbackArticles().find(a => a.slug === canonicalSlug);
+ setArticle(fallback);
+ setRelated(fallback ? contentApi.fallbackArticles().filter(a => a.category === fallback.category && a.id !== fallback.id).slice(0, 3) : []);
+ setSaved(false);
+ setReacted({});
+ contentApi.getArticle(canonicalSlug)
+ .then((res) => {
+ if (cancelled) return;
+ setArticle(res.article);
+ setRelated(res.related ?? []);
+ setSaved(!!res.saved);
+ setReacted(res.reactions ?? {});
+ })
+ .catch(() => {});
+ return () => { cancelled = true; };
+ }, [canonicalSlug]);
+
+ useEffect(() => {
+ if (!article?.id) return;
+ const h = () => {
+ const el = document.documentElement;
+ const progress = (el.scrollTop || document.body.scrollTop) / (el.scrollHeight - el.clientHeight);
+ if (progress > 0.05) {
+ engagementApi.recordHistory(article.id, Math.min(progress, 1)).catch(() => {});
+ }
+ };
+ window.addEventListener('scroll', h);
+ return () => window.removeEventListener('scroll', h);
+ }, [article?.id]);
+
+ useEffect(() => {
+ if (!processedContent) return;
+ document.querySelectorAll('.article-content pre').forEach((pre) => {
+ if (pre.querySelector('.code-copy-btn')) return;
+ const code = pre.querySelector('code');
+ const lang = code?.className?.match(/language-(\w+)/)?.[1];
+ if (lang) pre.setAttribute('data-lang', lang);
+ const btn = document.createElement('button');
+ btn.className = 'code-copy-btn';
+ btn.textContent = 'کپی';
+ btn.onclick = () => {
+ navigator.clipboard?.writeText(code?.textContent ?? '').then(() => {
+ btn.textContent = '✓ کپی شد';
+ setTimeout(() => { btn.textContent = 'کپی'; }, 2000);
+ }).catch(() => {});
+ };
+ pre.appendChild(btn);
+ });
+ }, [processedContent]);
+
+ if (!article) return (
+
+
+
+
+ );
+
+ const author = article.author || TeknavData.authors.find(a => a.id === article.authorId);
+ const cat = TeknavData.categories.find(c => c.id === article.category);
+ const tekRag = isTekRagArticle(article);
+ const authorName = tekRag ? 'Arsam Sabbagh' : (author?.name || article.authorName);
+ const authorSpecialty = tekRag ? 'AI and Data Engineering Researcher' : author?.specialty;
+ const authorBio = tekRag ? 'Arsam Sabbagh is an AI and data engineering researcher focused on retrieval-augmented generation, data-centric AI, Persian technical content systems, and evaluation of grounded language-model applications.' : author?.bio;
+ const categoryName = tekRag ? 'Data Science' : article.categoryName;
+ const articleType = tekRag ? 'Research Article' : article.type;
+ const displayDate = tekRag ? 'May 8, 2026' : articleDateLabel(article);
+ const statusLabel = tekRag ? 'Published' : article.status;
+ const layoutDirection = tekRag ? 'ltr' : 'rtl';
+ const metaLocaleEnglish = tekRag;
+ const discoverImage = null;
+
+ const headings = [];
+ const h2re = /]*>([^<]+)<\/h2>/g;
+ const h3re = /]*>([^<]+)<\/h3>/g;
+ let m;
+ while ((m = h2re.exec(article.content || '')) !== null) headings.push({ id: 'h-' + headings.length, text: m[1], level: 2 });
+ while ((m = h3re.exec(article.content || '')) !== null) headings.push({ id: 'h-' + headings.length, text: m[1], level: 3 });
+
+ const handleSave = async () => {
+ try {
+ const res = await contentApi.toggleSaved(article.id);
+ setSaved(!!res.saved);
+ if (res.saved) setListModalOpen(true);
+ toast(tekRag ? (res.saved ? 'Saved to reading list' : 'Removed from saved articles') : (res.saved ? 'در لیست مطالعه ذخیره شد' : 'از ذخیرهشدهها حذف شد'));
+ } catch {
+ toast(tekRag ? 'Sign in to save this article' : 'برای ذخیره مقاله ابتدا وارد شوید', 'warning');
+ }
+ };
+
+ const handleShare = (channel = 'copy') => {
+ const url = window.location.href;
+ const text = article.title;
+ contentApi.trackEvent({
+ type: 'share_clicked',
+ articleId: article.id,
+ topic: article.category,
+ metadata: { channel },
+ }).catch(() => {});
+
+ if (channel === 'telegram') {
+ window.open(`https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`, '_blank', 'noopener,noreferrer');
+ return;
+ }
+ if (channel === 'whatsapp') {
+ window.open(`https://wa.me/?text=${encodeURIComponent(`${text} ${url}`)}`, '_blank', 'noopener,noreferrer');
+ return;
+ }
+ if (channel === 'x') {
+ window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`, '_blank', 'noopener,noreferrer');
+ return;
+ }
+ if (channel === 'linkedin') {
+ window.open(`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`, '_blank', 'noopener,noreferrer');
+ return;
+ }
+ navigator.clipboard?.writeText(url).catch(() => {});
+ toast('لینک مقاله کپی شد');
+ };
+
+ const handleReact = async (type) => {
+ try {
+ const res = await contentApi.toggleReaction(article.id, type);
+ setReacted(r => ({ ...r, [type]: !!res.active }));
+ if (res.active) toast(tekRag ? 'Reaction saved' : 'واکنش شما ثبت شد');
+ } catch {
+ toast(tekRag ? 'Sign in to react' : 'برای ثبت واکنش ابتدا وارد شوید', 'warning');
+ }
+ };
+
+ return (
+
+
+
+
+
+
+ ›
+
+ ›
+ {article.title.slice(0, 40)}…
+
+
+
+
+
+
+
+
+
+
+
+ {tekRag ? (
+
+
+ {statusLabel}
+
+ ) : }
+ {article.sponsored && Promoted Content}
+ {article.premiumOnly && Premium}
+
+ {article.title}
+ {article.subtitle && {article.subtitle}
}
+
+
+ {author && (
+
+
+
+
+
{authorSpecialty}
+
+
+ )}
+
+
+ ·
+ {articleType}
+ ·
+ {tekRag ? `${article.readTime} min read` : `${article.readTime} دقیقه مطالعه`}
+ ·
+ {tekRag ? `${numberLabel(commentTotal, true)} comments` : `${numberLabel(commentTotal)} نظر`}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {article.series && (
+
+
+ سری مقاله
+ {article.series.title}
+ {article.series.articles?.length > 0 && (
+ قسمت {article.series.position} از {article.series.articles.length}
+ )}
+
+
+
+ )}
+
+ {discoverImage && (
+
+
+
+ )}
+
+ {(article.correctionNotice || article.corrections?.length > 0) && (
+
+ اصلاحیه و بهروزرسانی
+ {article.correctionNotice && {article.correctionNotice}
}
+ {article.corrections?.length > 0 && (
+
+ {article.corrections.map(item => - {item.date || new Date(item.createdAt).toLocaleDateString('fa-IR')}: {item.note}
)}
+
+ )}
+
+ )}
+
+ {!tekRag && (
+
+
نمودار تعاملی — با موس روی عناصر بروید
+
+
+ )}
+
+
+
+ {!article.premiumLocked && !tekRag && (
+
+ )}
+
+ {article.premiumLocked && }
+
+
+
+
+
{tekRag ? 'Was this article useful?' : 'واکنش شما به این مقاله؟'}
+
+ {(tekRag ? [
+ ['helpful', 'Helpful', thumbsUpIcon],
+ ['star', 'Excellent', starIcon],
+ ['heart', 'Valuable', '♡'],
+ ['fire', 'Important', '●'],
+ ['thinking', 'Thought-provoking', '?'],
+ ] : [
+ ['helpful', 'مفید', thumbsUpIcon],
+ ['star', 'عالی', starIcon],
+ ['heart', 'عاشقانه', heartIcon],
+ ['fire', 'داغ', flameIcon],
+ ['thinking', 'تأملبرانگیز', lightbulbIcon],
+ ]).map(([type, label, icon]) => (
+
+ ))}
+
+
+
+ {article.series?.articles?.length > 1 && (
+
+ )}
+
+ {article.tags?.length > 0 && (
+
+ {tekRag ? 'Keywords:' : 'برچسبها:'}
+ {article.tags.map(t => (
+
+ ))}
+
+ )}
+
+
+
+
+
+ {author && (
+
+
+
+
{tekRag ? 'AUTHOR' : 'نویسنده'}
+
+
{authorSpecialty}
+
{authorBio}
+
+ {Object.entries(author.social || {}).map(([k, v]) => (
+
{k}
+ ))}
+
+
+
+ )}
+
+ {!tekRag && related.length > 0 && (
+
+ )}
+ {!tekRag && (() => {
+ const relatedComparisons = (TeknavData.comparisons ?? []).filter((c) =>
+ (c.relatedArticles || []).includes(article.slug) ||
+ (article.tags || []).some((t) => [c.item1.slug, c.item2.slug, ...(c.tags || [])].some((ct) => ct.toLowerCase() === t.toLowerCase())),
+ ).slice(0, 3);
+ if (!relatedComparisons.length) return null;
+ return (
+
+
مقایسههای مرتبط
+
+ {relatedComparisons.map((c) => (
+
navigate(`/compare/${c.slug}`)}
+ style={{ background: '#F8F5F0', border: '1px solid #E4DDD2', borderRadius: 8, padding: '12px 16px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 12 }}
+ >
+
+
{c.title}
+
+ {c.item1.name}
+ در برابر
+ {c.item2.name}
+
+
+
←
+
+ ))}
+
+
+ );
+ })()}
+
+
+
+
+
+ {listModalOpen &&
setListModalOpen(false)} />}
+
+ );
+}
+
+const articleContentStyle = {
+ fontSize: 16, lineHeight: 2, color: '#263238', direction: 'rtl',
+ fontFamily: 'Vazirmatn,sans-serif',
+};
+
+const articleCSS = `
+ article h2 { font-size: 22px; font-weight: 800; color: #263238; margin: 40px 0 16px; padding-bottom: 8px; border-bottom: 2px solid #E4DDD2; font-family: Vazirmatn,sans-serif; }
+ article h3 { font-size: 18px; font-weight: 700; color: #263238; margin: 32px 0 12px; font-family: Vazirmatn,sans-serif; }
+ article p { margin: 0 0 20px; }
+ article .lead { font-size: 18px; line-height: 2.05; color: #1A3035; font-weight: 500; background: #FFFFFF; border: 1px solid #E4DDD2; border-right: 4px solid #0F6B73; border-radius: 12px; padding: 20px 22px; margin: 0 0 30px; }
+ article blockquote { border-right: 4px solid #D49A2A; margin: 28px 0; padding: 16px 20px; background: #D49A2A0A; border-radius: 0 8px 8px 0; font-size: 16px; color: #263238; font-style: normal; }
+ article blockquote.security-quote { border-right-color: #C94C4D; background: #C94C4D08; }
+ article strong { color: #263238; font-weight: 700; }
+ article em { color: #0F6B73; font-style: normal; font-weight: 600; }
+
+ article pre { background: #131F22; border-radius: 10px; padding: 40px 18px 18px; margin: 24px 0; overflow-x: auto; position: relative; border: 1px solid #1E3035; direction: ltr; }
+ article pre::before { content: attr(data-lang); position: absolute; top: 10px; right: 14px; font-size: 10px; color: #4A7A82; font-family: monospace; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; }
+ article pre code { background: none !important; border: none !important; padding: 0 !important; color: #A8D8DC; font-family: 'Courier New', Consolas, monospace; font-size: 13.5px; line-height: 1.85; display: block; direction: ltr; text-align: left; white-space: pre; }
+ article code:not(pre code) { background: #0F6B7316; border: 1px solid #0F6B7328; border-radius: 4px; padding: 1px 6px; font-family: 'Courier New', Consolas, monospace; font-size: 13px; color: #0A5060; direction: ltr; unicode-bidi: isolate; display: inline; white-space: nowrap; }
+ .code-copy-btn { position: absolute; top: 8px; left: 10px; background: #1E3035; border: 1px solid #2A4048; color: #6AACB5; border-radius: 6px; padding: 4px 10px; font-size: 11px; cursor: pointer; font-family: Vazirmatn, sans-serif; z-index: 1; transition: all 0.15s; line-height: 1.4; }
+ .code-copy-btn:hover { background: #2A4048; color: #A8D8DC; }
+
+ article ul { padding-right: 0; list-style: none; margin: 16px 0 24px; display: grid; gap: 6px; }
+ article ul li { position: relative; padding-right: 22px; color: #263238; line-height: 1.9; }
+ article ul li::before { content: '›'; position: absolute; right: 4px; color: #0F6B73; font-weight: 900; font-size: 17px; line-height: 1.6; }
+ article ol { padding-right: 0; counter-reset: art-counter; list-style: none; margin: 16px 0 24px; display: grid; gap: 8px; }
+ article ol li { counter-increment: art-counter; position: relative; padding-right: 38px; color: #263238; line-height: 1.9; padding-top: 2px; }
+ article ol li::before { content: counter(art-counter); position: absolute; right: 0; top: 2px; width: 24px; height: 24px; background: #0F6B73; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; }
+ article ul li code, article ol li code { font-size: 12px; }
+ article ul li strong, article ol li strong { color: #0A5060; }
+
+ article .ltr { direction: ltr; unicode-bidi: isolate; display: inline-block; font-family: Inter, Arial, sans-serif; letter-spacing: 0; }
+ article .metric-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); gap: 12px; margin: 28px 0; }
+ article .metric-card { background: #fff; border: 1px solid #E4DDD2; border-top: 3px solid #0F6B73; border-radius: 10px; padding: 14px 16px; }
+ article .metric-value { color: #0F6B73; font-weight: 900; font-size: 22px; line-height: 1.2; }
+ article .metric-label { color: #5F6B6D; font-size: 12px; line-height: 1.7; margin-top: 6px; }
+ article table { width: 100%; border-collapse: collapse; margin: 24px 0; background: #fff; border: 1px solid #E4DDD2; border-radius: 10px; overflow: hidden; display: block; max-width: 100%; overflow-x: auto; }
+ article th, article td { border-bottom: 1px solid #E4DDD2; padding: 12px 14px; text-align: right; vertical-align: top; min-width: 130px; }
+ article th { background: #F4EFE6; color: #263238; font-weight: 800; }
+ article tr:last-child td { border-bottom: 0; }
+ article .comparison-template { background: #fffaf1; border: 1px solid #E4DDD2; border-radius: 12px; padding: 18px; margin: 24px 0; }
+ article .risk-box { background: #C46A4D10; border: 1px solid #C46A4D35; border-radius: 12px; padding: 18px 22px; margin: 28px 0; }
+ article .agent-steps { counter-reset: agentStep; display: grid; gap: 10px; margin: 24px 0; }
+ article .agent-step { counter-increment: agentStep; background: #fff; border: 1px solid #E4DDD2; border-radius: 10px; padding: 14px 48px 14px 16px; position: relative; }
+ article .agent-step::before { content: counter(agentStep); position: absolute; top: 14px; right: 14px; width: 24px; height: 24px; border-radius: 50%; background: #0F6B73; color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }
+ .article-diagram-card { background: linear-gradient(135deg,#F4EFE6 0%,#FFFFFF 100%); border: 1px solid #E4DDD2; border-radius: 12px; padding: 22px; overflow: hidden; box-shadow: 0 12px 34px rgba(15,42,46,0.06); }
+ .tekrag-diagram-card { background: #FAFAFA; border: 1px solid #E8E8E8; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
+ .insight-box { background: #0F6B7310; border: 1px solid #0F6B7330; border-radius: 10px; padding: 20px 24px; margin: 28px 0; }
+ .insight-box .insight-title { font-size: 13px; font-weight: 700; color: #0F6B73; margin-bottom: 8px; }
+ .insight-box p { margin: 0; font-size: 14px; line-height: 1.8; }
+ .footnote-box { background: #F4EFE6; border-radius: 8px; padding: 16px 20px; margin-top: 32px; font-size: 12px; color: #5F6B6D; line-height: 1.7; }
+
+ .cve-summary-card { background: linear-gradient(135deg, #EEF6F7 0%, #E8F3F4 100%); border: 1px solid rgba(15,107,115,0.18); border-radius: 12px; padding: 20px 24px; margin: 0 0 32px; display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 16px; direction: rtl; }
+ .cve-summary-card .cve-item { display: flex; flex-direction: column; gap: 5px; border-left: 1px solid rgba(15,107,115,0.15); padding-left: 16px; }
+ .cve-summary-card .cve-item:last-child { border-left: none; padding-left: 0; }
+ .cve-summary-card .cve-label { font-size: 10px; color: #0F6B73; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
+ .cve-summary-card .cve-value { font-size: 14px; font-weight: 800; color: #1A3035; }
+ .cve-summary-card .cve-score { font-size: 28px; font-weight: 900; color: #C0392B; line-height: 1; }
+ .cve-summary-card .cve-critical { color: #C0392B; }
+ .cve-summary-card .cve-patched { color: #1A7A50; font-size: 13px; }
+
+ .security-alert { background: #C94C4D0A; border: 1px solid #C94C4D30; border-right: 4px solid #C94C4D; border-radius: 0 10px 10px 0; padding: 16px 20px; margin: 28px 0; }
+ .security-alert .alert-title { font-size: 13px; font-weight: 800; color: #C94C4D; margin-bottom: 6px; }
+ .security-alert p, .security-alert li { font-size: 14px; line-height: 1.8; color: #3A1A1A; margin: 0; }
+
+ @media (max-width: 640px) {
+ article pre {
+ padding: 32px 12px 12px !important;
+ margin: 20px 0 !important;
+ font-size: 12px !important;
+ max-width: calc(100vw - 32px) !important;
+ }
+ article code:not(pre code) {
+ font-size: 11px !important;
+ padding: 1px 4px !important;
+ word-break: break-all !important;
+ }
+
+ .cve-summary-card {
+ grid-template-columns: 1fr !important;
+ padding: 16px !important;
+ gap: 12px !important;
+ }
+ .cve-summary-card .cve-item {
+ border-left: none !important;
+ border-bottom: 1px solid rgba(15,107,115,0.15) !important;
+ padding-left: 0 !important;
+ padding-bottom: 12px !important;
+ }
+ .cve-summary-card .cve-item:last-child {
+ border-bottom: none !important;
+ padding-bottom: 0 !important;
+ }
+
+ article table { font-size: 13px !important; }
+ article table td, article table th { padding: 6px 8px !important; min-width: 80px !important; }
+
+ article .metric-grid { grid-template-columns: 1fr !important; }
+ article .lead { font-size: 16px !important; padding: 16px !important; }
+ }
+`;
+const styleEl = document.createElement('style');
+styleEl.textContent = articleCSS;
+document.head.appendChild(styleEl);
+
+export { ArticleRow, FilterBar, ArticleListPage, TableOfContents, ArticleDetail };