Import source: app/src/pages/ComparisonPage

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:25:01 +03:30
parent 32916e2159
commit 4bad61a2d3
+202
View File
@@ -0,0 +1,202 @@
import { useState } from 'react';
import { TeknavData } from '../../teknav-data.js';
import { useNav, EmptyState } from '../../teknav-ui.jsx';
import linkIcon from '../../src/assets/icons/link.svg';
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 (
<div style={{ background: '#F8F5F0', borderRadius: 12, padding: '20px 24px', marginBottom: 32, display: 'flex', gap: 20, flexWrap: 'wrap', alignItems: 'center' }}>
<div style={{ flex: 1, minWidth: 260 }}>
<p style={{ fontSize: 14, fontWeight: 700, color: '#263238', marginBottom: 12 }}>شما کدام را ترجیح می‌دهید؟</p>
<div style={{ display: 'flex', gap: 10 }}>
<button
onClick={() => 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}
</button>
<button
onClick={() => 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}
</button>
</div>
{vote && (
<p style={{ fontSize: 12, color: '#5F6B6D', marginTop: 10 }}>
انتخاب شما ثبت شد. برای تغییر دوباره کلیک کنید.
</p>
)}
</div>
<button
onClick={shareComparison}
style={{
background: shared ? '#2E7D32' : '#0C1E22', color: shared ? '#fff' : '#D49A2A',
border: 'none', borderRadius: 8, padding: '10px 20px', fontSize: 13,
fontFamily: 'Vazirmatn,sans-serif', cursor: 'pointer', fontWeight: 700, whiteSpace: 'nowrap',
}}
>
{shared ? '✓ لینک کپی شد' : <><span className="tek-icon" style={{ ['--i']: `url("${linkIcon}")` }} aria-hidden="true" /> اشتراک‌گذاری</>}
</button>
</div>
);
}
export function ComparisonPage({ slug }) {
const { navigate } = useNav();
const comparison = (TeknavData.comparisons ?? []).find((c) => c.slug === slug);
if (!comparison) {
return (
<div style={{ padding: '120px 24px', textAlign: 'center', fontFamily: 'Vazirmatn,sans-serif', direction: 'rtl' }}>
<EmptyState title="صفحه مقایسه یافت نشد" subtitle="مقایسه‌ای با این آدرس وجود ندارد" />
</div>
);
}
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 (
<div style={{ maxWidth: 960, margin: '0 auto', padding: '24px 16px 80px', direction: 'rtl', fontFamily: 'Vazirmatn,sans-serif' }}>
<nav style={{ fontSize: 13, color: '#5F6B6D', marginBottom: 24, display: 'flex', gap: 8, alignItems: 'center' }}>
<span style={{ cursor: 'pointer', color: '#0F6B73' }} onClick={() => navigate('/')}>تکناو</span>
<span>›</span>
<span style={{ cursor: 'pointer', color: '#0F6B73' }} onClick={() => navigate('/compare')}>مقایسه‌ها</span>
<span>›</span>
<span>{comparison.title}</span>
</nav>
<h1 style={{ fontSize: 'clamp(22px,4vw,32px)', fontWeight: 800, color: '#0C1E22', lineHeight: 1.5, marginBottom: 12 }}>
{comparison.title}
</h1>
{comparison.metaDescription && (
<p style={{ fontSize: 16, color: '#5F6B6D', lineHeight: 1.8, marginBottom: 16 }}>{comparison.metaDescription}</p>
)}
{comparison.factCheckedAt && (
<p style={{ fontSize: 12, color: '#5F6B6D', marginBottom: 24 }}>
آخرین بروزرسانی: {comparison.factCheckedAt}
</p>
)}
<ComparisonVoteBar slug={slug} item1={item1} item2={item2} />
<div style={{ display: 'flex', gap: 20, flexWrap: 'wrap', marginBottom: 40 }}>
{[item1, item2].map((item) => (
<div key={item.slug} style={cardStyle}>
<h2 style={{ fontSize: 20, fontWeight: 700, color: '#0F6B73', marginBottom: 10 }}>{item.name}</h2>
<p style={{ fontSize: 14, color: '#263238', lineHeight: 1.8, marginBottom: 16 }}>{item.summary}</p>
<div style={{ marginBottom: 8, fontSize: 13, fontWeight: 700, color: '#263238' }}>مزایا</div>
{(item.pros || []).map((p, i) => (
<div key={i} style={proStyle}><span>✓</span><span>{p}</span></div>
))}
<div style={{ marginBottom: 8, marginTop: 12, fontSize: 13, fontWeight: 700, color: '#263238' }}>معایب</div>
{(item.cons || []).map((c, i) => (
<div key={i} style={conStyle}><span>✗</span><span>{c}</span></div>
))}
</div>
))}
</div>
{useCases.length > 0 && (
<section style={{ background: '#F8F5F0', borderRadius: 12, padding: 24, marginBottom: 32 }}>
<h2 style={{ fontSize: 18, fontWeight: 700, color: '#263238', marginBottom: 16 }}>چه زمانی کدام را انتخاب کنیم؟</h2>
{useCases.map(([left, right], i) => (
<div key={i} style={{ display: 'flex', gap: 20, flexWrap: 'wrap' }}>
<div style={{ flex: '1 1 280px', padding: '12px 16px', background: '#fff', borderRadius: 8, border: '1px solid #E4DDD2', fontSize: 13, lineHeight: 1.7 }}>
<span style={{ fontWeight: 700, color: '#0F6B73' }}>{item1.name}:</span> {left}
</div>
<div style={{ flex: '1 1 280px', padding: '12px 16px', background: '#fff', borderRadius: 8, border: '1px solid #E4DDD2', fontSize: 13, lineHeight: 1.7 }}>
<span style={{ fontWeight: 700, color: '#0F6B73' }}>{item2.name}:</span> {right}
</div>
</div>
))}
</section>
)}
{verdict && (
<section style={{ background: '#0F3540', borderRadius: 12, padding: 24, marginBottom: 40, color: '#fff' }}>
<h2 style={{ fontSize: 18, fontWeight: 700, color: '#D49A2A', marginBottom: 12 }}>جمع‌بندی و نتیجه‌گیری</h2>
<p style={{ fontSize: 15, lineHeight: 1.9 }}>{verdict}</p>
</section>
)}
{glossaryTerms.length > 0 && (
<section style={{ marginBottom: 40 }}>
<h2 style={{ fontSize: 18, fontWeight: 700, color: '#263238', marginBottom: 16 }}>اصطلاحات مرتبط</h2>
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
{glossaryTerms.map((g) => (
<div
key={g.slug}
onClick={() => navigate(`/glossary/${g.slug}`)}
style={{ background: '#fff', border: '1px solid #0F6B73', borderRadius: 8, padding: '10px 16px', cursor: 'pointer' }}
>
<div style={{ fontSize: 14, fontWeight: 700, color: '#0F6B73' }}>{g.term}</div>
<div style={{ fontSize: 12, color: '#5F6B6D' }}>{g.english}</div>
</div>
))}
</div>
</section>
)}
{articles.length > 0 && (
<section>
<h2 style={{ fontSize: 18, fontWeight: 700, color: '#263238', marginBottom: 16 }}>مقالات مرتبط</h2>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
{articles.map((a) => (
<div
key={a.id}
onClick={() => 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' }}
>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 15, fontWeight: 700, color: '#263238', marginBottom: 4 }}>{a.title}</div>
<div style={{ fontSize: 13, color: '#5F6B6D' }}>{a.summary?.slice(0, 100)}…</div>
</div>
<span style={{ fontSize: 20 }}>←</span>
</div>
))}
</div>
</section>
)}
</div>
);
}