Files
teknav-bak/app/src/pages/ComparisonPage.jsx
T
arsam 4bad61a2d3 Import source: app/src/pages/ComparisonPage
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2026-09-18 23:25:01 +03:30

203 lines
9.7 KiB
React
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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>
);
}