Foro: perfil de usuario
- lib/forum.ts: getForumProfile (post_count, topic_count, joindate, gmlevel->status admin/gm, y últimos 5 temas), portado de forum/views.py profile(). - Página /forum/user/[username] con contadores, antigüedad, rango y temas recientes. - Los nombres de autor en la vista del tema enlazan al perfil. - i18n es/en: Forum.memberSince, recentTopics, roleAdmin, roleGm. Verificado: build OK, /forum/user 200. Foro COMPLETO: índice, foro/tema, crear, responder, editar/borrar, moderación (lock/pin/mover/borrar/restaurar), búsqueda, paginación, editor rico y perfiles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,7 +65,9 @@ export default async function TopicPage({
|
||||
<article key={post.id} className={`nw-card ${post.deleted ? 'opacity-50 ring-1 ring-red-900/50' : ''}`}>
|
||||
<div className="mb-2 flex items-center justify-between border-b border-amber-900/40 pb-2 text-sm">
|
||||
<span className="font-semibold text-amber-400">
|
||||
{post.poster}
|
||||
<Link href={`/forum/user/${encodeURIComponent(post.poster)}`} className="hover:text-amber-300 hover:underline">
|
||||
{post.poster}
|
||||
</Link>
|
||||
{post.deleted && <span className="ml-2 text-xs text-red-400">[{t('deletedMark')}]</span>}
|
||||
</span>
|
||||
{post.time && (
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
||||
import { Link } from '@/i18n/navigation'
|
||||
import { getForumProfile } from '@/lib/forum'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function ForumProfilePage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string; username: string }>
|
||||
}) {
|
||||
const { locale, username } = await params
|
||||
setRequestLocale(locale)
|
||||
const t = await getTranslations('Forum')
|
||||
const p = await getForumProfile(decodeURIComponent(username))
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-2xl px-4 py-8">
|
||||
<p className="mb-2 text-sm">
|
||||
<Link href="/forum" className="text-sky-400 hover:underline">
|
||||
← {t('backToForum')}
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
<div className="nw-card">
|
||||
<h1 className="flex items-center gap-2 text-2xl font-bold text-amber-500">
|
||||
{p.username}
|
||||
{p.status && (
|
||||
<span className="rounded bg-nw-gold/15 px-2 py-0.5 text-xs text-nw-gold-light">
|
||||
{p.status === 'admin' ? t('roleAdmin') : t('roleGm')}
|
||||
</span>
|
||||
)}
|
||||
</h1>
|
||||
<div className="mt-4 grid grid-cols-2 gap-3 text-sm sm:grid-cols-3">
|
||||
<div>
|
||||
<p className="text-nw-muted">{t('posts')}</p>
|
||||
<p className="text-lg font-semibold text-amber-300">{p.postCount}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-nw-muted">{t('topics')}</p>
|
||||
<p className="text-lg font-semibold text-amber-300">{p.topicCount}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-nw-muted">{t('memberSince')}</p>
|
||||
<p className="font-semibold text-amber-300">
|
||||
{p.joindate ? new Date(p.joindate).toLocaleDateString(locale) : '—'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{p.recentTopics.length > 0 && (
|
||||
<section className="mt-6">
|
||||
<h2 className="mb-3 text-lg font-semibold text-nw-gold-light">{t('recentTopics')}</h2>
|
||||
<ul className="divide-y divide-amber-900/40">
|
||||
{p.recentTopics.map((topic) => (
|
||||
<li key={topic.id} className="py-2">
|
||||
<Link href={`/forum/topic/${topic.id}`} className="text-amber-300 hover:text-amber-400">
|
||||
{topic.name}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user