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:
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user