From bda36b4a5fc1c8a5e25b0076bed2b3a6d5d119c2 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:24:55 +0330 Subject: [PATCH] Import source: app/src/pages/AuthorsListPage Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- app/src/pages/AuthorsListPage.jsx | 65 +++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 app/src/pages/AuthorsListPage.jsx diff --git a/app/src/pages/AuthorsListPage.jsx b/app/src/pages/AuthorsListPage.jsx new file mode 100644 index 0000000..f3fbb9c --- /dev/null +++ b/app/src/pages/AuthorsListPage.jsx @@ -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 ( +
+
+
+

نویسندگان تکناو

+

متخصصانی که روایت عمیق فناوری را می‌نویسند

+
+ +
+ {authors.map(author => { + const latestArt = articles.find(a => a.authorId === author.id || a.authorSlug === author.slug); + return ( +
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'; }}> +
+ +
+
+ {author.name} + {author.verifiedExpert && تاییدشده} +
+
{author.specialty}
+
{author.articleCount} مقاله منتشرشده
+
+
+

{author.bio.slice(0, 120)}…

+ {latestArt && ( +
+ آخرین مقاله: + {latestArt.title.slice(0, 50)}… +
+ )} +
+ ); + })} +
+
+
+ ); +}