Import source: app/src/pages/AuthorsListPage

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:24:55 +03:30
parent 2d0803128a
commit bda36b4a5f
+65
View File
@@ -0,0 +1,65 @@
import { useState, useEffect } from 'react';
import { TeknavData } from '../../teknav-data.js';
import { useNav, AuthorAvatar, EmptyState } from '../../teknav-ui.jsx';
import { contentApi } from '../../src/lib/content-api.js';
import { authorProfilePath } from './shared.jsx';
export 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 (
<div style={{ paddingTop: 80, background: '#FAF7F0', minHeight: '100vh', fontFamily: 'Vazirmatn,sans-serif' }}>
<div style={{ maxWidth: 1100, margin: '0 auto', padding: '0 24px', direction: 'rtl' }}>
<div style={{ paddingTop: 32, paddingBottom: 32, borderBottom: '1px solid #E4DDD2' }}>
<h1 style={{ fontSize: 32, fontWeight: 900, color: '#263238', margin: '0 0 8px' }}>نویسندگان تکناو</h1>
<p style={{ fontSize: 15, color: '#5F6B6D', margin: 0 }}>متخصصانی که روایت عمیق فناوری را می‌نویسند</p>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(300px,1fr))', gap: 20, padding: '32px 0' }}>
{authors.map(author => {
const latestArt = articles.find(a => a.authorId === author.id || a.authorSlug === author.slug);
return (
<div key={author.id} onClick={() => 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'; }}>
<div style={{ display: 'flex', gap: 16, marginBottom: 16 }}>
<AuthorAvatar author={author} size={60} />
<div>
<div style={{ fontSize: 16, fontWeight: 700, color: '#263238', marginBottom: 3, display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap' }}>
{author.name}
{author.verifiedExpert && <span style={{ fontSize: 10, color: '#0F6B73', background: '#0F6B7314', border: '1px solid #0F6B7330', borderRadius: 999, padding: '2px 7px' }}>تاییدشده</span>}
</div>
<div style={{ fontSize: 12, color: '#5F6B6D', marginBottom: 6 }}>{author.specialty}</div>
<div style={{ fontSize: 12, color: '#0F6B73', fontWeight: 600 }}>{author.articleCount} مقاله منتشرشده</div>
</div>
</div>
<p style={{ fontSize: 13, color: '#5F6B6D', lineHeight: 1.7, margin: '0 0 16px' }}>{author.bio.slice(0, 120)}…</p>
{latestArt && (
<div style={{ background: '#F4EFE6', borderRadius: 8, padding: '10px 14px', fontSize: 12, color: '#263238' }}>
<span style={{ color: '#5F6B6D' }}>آخرین مقاله: </span>
{latestArt.title.slice(0, 50)}…
</div>
)}
</div>
);
})}
</div>
</div>
</div>
);
}