252 lines
6.4 KiB
TypeScript
252 lines
6.4 KiB
TypeScript
import { useState } from 'react'
|
||
import { Link } from 'react-router-dom'
|
||
import { SectionBanner } from '@/components/ui/SectionBanner'
|
||
import { reports, type Report } from '@/data/reports'
|
||
|
||
const displayReports = reports.filter(r => !r.featured).slice(0, 6)
|
||
|
||
const typeLabel: Record<string, string> = {
|
||
quarterly: 'گزارش فصلی',
|
||
flash: 'فوری',
|
||
risk: 'ریسک',
|
||
free: 'رایگان',
|
||
special: 'ویژه',
|
||
}
|
||
|
||
const dotColor: Record<string, string> = {
|
||
quarterly: 'var(--ink)',
|
||
flash: 'var(--red)',
|
||
risk: 'var(--red)',
|
||
free: 'var(--green-ink)',
|
||
special: 'var(--amber)',
|
||
}
|
||
|
||
function formatPrice(n: number) {
|
||
return n.toLocaleString('fa-IR')
|
||
}
|
||
|
||
interface ReportCardProps {
|
||
report: Report
|
||
colIndex: number
|
||
rowIndex: number
|
||
totalRows: number
|
||
}
|
||
|
||
function ReportCard({ report, colIndex, rowIndex, totalRows }: ReportCardProps) {
|
||
const [hovered, setHovered] = useState(false)
|
||
const isLastRow = rowIndex === totalRows - 1
|
||
const isRightCol = colIndex === 0 // RTL: right col is index 0
|
||
|
||
return (
|
||
<div
|
||
style={{
|
||
padding: '40px',
|
||
borderBottom: isLastRow ? 'none' : '1px solid var(--rule-thin)',
|
||
borderLeft: isRightCol ? '1px solid var(--rule-thin)' : 'none',
|
||
cursor: 'pointer',
|
||
transition: 'background-color 150ms',
|
||
backgroundColor: hovered ? 'var(--paper-2)' : 'transparent',
|
||
}}
|
||
onMouseEnter={() => setHovered(true)}
|
||
onMouseLeave={() => setHovered(false)}
|
||
>
|
||
{/* Type badge */}
|
||
<div
|
||
style={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: '8px',
|
||
marginBottom: '16px',
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
width: '4px',
|
||
height: '4px',
|
||
borderRadius: '50%',
|
||
backgroundColor: dotColor[report.type] ?? 'var(--ink)',
|
||
flexShrink: 0,
|
||
}}
|
||
/>
|
||
<span
|
||
style={{
|
||
fontSize: '9px',
|
||
textTransform: 'uppercase',
|
||
letterSpacing: '2px',
|
||
color: 'var(--ink-5)',
|
||
fontWeight: 700,
|
||
}}
|
||
>
|
||
{typeLabel[report.type] ?? report.type} · {report.category}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Title */}
|
||
<Link to={`/reports/${report.id}`} style={{ textDecoration: 'none' }}>
|
||
<h3
|
||
style={{
|
||
fontSize: 'clamp(18px, 2vw, 20px)',
|
||
fontWeight: 800,
|
||
lineHeight: 1.35,
|
||
letterSpacing: '-0.3px',
|
||
color: hovered ? 'var(--red)' : 'var(--ink)',
|
||
marginBottom: '12px',
|
||
transition: 'color 150ms',
|
||
cursor: 'pointer',
|
||
}}
|
||
>
|
||
{report.title}
|
||
</h3>
|
||
</Link>
|
||
|
||
{/* Deck */}
|
||
<p
|
||
style={{
|
||
fontSize: '13px',
|
||
fontWeight: 300,
|
||
color: 'var(--ink-3)',
|
||
lineHeight: 1.8,
|
||
marginBottom: '20px',
|
||
}}
|
||
>
|
||
{report.summary.slice(0, 140)}
|
||
{report.summary.length > 140 ? '…' : ''}
|
||
</p>
|
||
|
||
{/* Divider */}
|
||
<div
|
||
style={{
|
||
height: '1px',
|
||
backgroundColor: 'var(--rule-thin)',
|
||
marginBottom: '16px',
|
||
}}
|
||
/>
|
||
|
||
{/* Footer row */}
|
||
<div
|
||
style={{
|
||
display: 'flex',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'flex-end',
|
||
gap: '12px',
|
||
}}
|
||
>
|
||
{/* Price block */}
|
||
<div>
|
||
{report.isFree ? (
|
||
<span
|
||
style={{
|
||
fontSize: '16px',
|
||
fontWeight: 900,
|
||
color: 'var(--green-ink)',
|
||
}}
|
||
>
|
||
دانلود رایگان
|
||
</span>
|
||
) : (
|
||
<span
|
||
style={{
|
||
fontSize: '16px',
|
||
fontWeight: 900,
|
||
color: 'var(--ink)',
|
||
}}
|
||
>
|
||
{formatPrice(report.price)}
|
||
<span
|
||
style={{
|
||
fontSize: '11px',
|
||
fontWeight: 400,
|
||
color: 'var(--ink-4)',
|
||
marginRight: '4px',
|
||
}}
|
||
>
|
||
تومان
|
||
</span>
|
||
</span>
|
||
)}
|
||
<div
|
||
style={{
|
||
fontSize: '10px',
|
||
color: 'var(--ink-5)',
|
||
marginTop: '3px',
|
||
}}
|
||
>
|
||
{report.pages} صفحه · {report.publishDate}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Buy link */}
|
||
<Link
|
||
to={`/reports/${report.id}`}
|
||
style={{
|
||
fontSize: '10px',
|
||
fontWeight: 700,
|
||
textTransform: 'uppercase',
|
||
letterSpacing: '2px',
|
||
color: 'var(--red)',
|
||
textDecoration: 'none',
|
||
cursor: 'pointer',
|
||
transition: 'text-decoration 150ms',
|
||
whiteSpace: 'nowrap',
|
||
}}
|
||
onMouseEnter={e =>
|
||
(e.currentTarget.style.textDecoration = 'underline')
|
||
}
|
||
onMouseLeave={e => (e.currentTarget.style.textDecoration = 'none')}
|
||
>
|
||
{report.isFree ? 'دانلود' : 'خرید گزارش'} ←
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default function LatestReportsSection() {
|
||
const rows = Math.ceil(displayReports.length / 2)
|
||
|
||
return (
|
||
<section
|
||
style={{
|
||
padding: '96px 48px',
|
||
borderBottom: '2px solid var(--ink)',
|
||
direction: 'rtl',
|
||
}}
|
||
className="max-md:px-6 max-md:py-16"
|
||
>
|
||
{/* Section header */}
|
||
<div style={{ marginBottom: '40px' }}>
|
||
<SectionBanner
|
||
label="آخرین گزارشها"
|
||
link={{ text: 'مشاهده آرشیو کامل ←', to: '/reports' }}
|
||
/>
|
||
</div>
|
||
|
||
{/* 2-col grid */}
|
||
<div
|
||
style={{
|
||
display: 'grid',
|
||
gridTemplateColumns: 'repeat(2, 1fr)',
|
||
border: '1px solid var(--rule-thin)',
|
||
borderBottom: 'none',
|
||
borderLeft: 'none',
|
||
}}
|
||
className="max-md:grid-cols-1"
|
||
>
|
||
{displayReports.map((report, idx) => {
|
||
const colIndex = idx % 2
|
||
const rowIndex = Math.floor(idx / 2)
|
||
return (
|
||
<ReportCard
|
||
key={report.id}
|
||
report={report}
|
||
colIndex={colIndex}
|
||
rowIndex={rowIndex}
|
||
totalRows={rows}
|
||
/>
|
||
)
|
||
})}
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|