Wire admin studio SSR and search infrastructure

This commit is contained in:
2026-05-01 11:46:06 +02:00
parent 257b0dbef6
commit 18cea8b0f0
329 changed files with 197465 additions and 2741 deletions

View File

@@ -3,8 +3,9 @@ import Breadcrumbs from '../../components/forum/Breadcrumbs'
import ThreadRow from '../../components/forum/ThreadRow'
import Pagination from '../../components/forum/Pagination'
import Button from '../../components/ui/Button'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumCategory({ category, parentCategory = null, threads = [], pagination = {}, isAuthenticated = false }) {
export default function ForumCategory({ category, parentCategory = null, threads = [], pagination = {}, isAuthenticated = false, seo = {} }) {
const name = category?.name ?? 'Category'
const slug = category?.slug
@@ -16,7 +17,9 @@ export default function ForumCategory({ category, parentCategory = null, threads
]
return (
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-5xl mx-auto">
<>
<SeoHead seo={seo} />
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-5xl mx-auto">
{/* Breadcrumbs */}
<Breadcrumbs items={breadcrumbs} />
@@ -79,5 +82,6 @@ export default function ForumCategory({ category, parentCategory = null, threads
</div>
)}
</div>
</>
)
}

View File

@@ -4,8 +4,9 @@ import Button from '../../components/ui/Button'
import RichTextEditor from '../../components/forum/RichTextEditor'
import TurnstileField from '../../components/security/TurnstileField'
import { populateBotFingerprint } from '../../lib/security/botFingerprint'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumEditPost({ post, thread, csrfToken, errors = {}, captcha = {} }) {
export default function ForumEditPost({ post, thread, csrfToken, errors = {}, captcha = {}, seo = {} }) {
const [content, setContent] = useState(post?.content ?? '')
const [captchaToken, setCaptchaToken] = useState('')
const [submitting, setSubmitting] = useState(false)
@@ -19,16 +20,22 @@ export default function ForumEditPost({ post, thread, csrfToken, errors = {}, ca
const handleSubmit = useCallback((e) => {
if (submitting) return
setSubmitting(true)
// Let the form submit normally for PRG
populateBotFingerprint(e.currentTarget).finally(() => {
e.currentTarget.submit()
})
e.preventDefault()
setSubmitting(true)
const form = e.currentTarget
// Let the form submit normally for PRG.
populateBotFingerprint(form).finally(() => {
form?.submit()
})
}, [submitting])
return (
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-3xl mx-auto">
<>
<SeoHead seo={seo} />
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-3xl mx-auto">
<Breadcrumbs items={breadcrumbs} />
{/* Header */}
@@ -101,5 +108,6 @@ export default function ForumEditPost({ post, thread, csrfToken, errors = {}, ca
</div>
</form>
</div>
</>
)
}

View File

@@ -1,7 +1,8 @@
import React from 'react'
import CategoryCard from '../../components/forum/CategoryCard'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumIndex({ categories = [], trendingTopics = [], latestTopics = [] }) {
export default function ForumIndex({ categories = [], trendingTopics = [], latestTopics = [], seo = {} }) {
const totalThreads = categories.reduce((sum, cat) => sum + (Number(cat?.thread_count) || 0), 0)
const totalPosts = categories.reduce((sum, cat) => sum + (Number(cat?.post_count) || 0), 0)
const sortedByActivity = [...categories].sort((a, b) => {
@@ -12,7 +13,9 @@ export default function ForumIndex({ categories = [], trendingTopics = [], lates
const latestActive = sortedByActivity[0] ?? null
return (
<div className="pb-20">
<>
<SeoHead seo={seo} />
<div className="pb-20">
<section className="relative overflow-hidden border-b border-white/10 bg-[radial-gradient(circle_at_15%_20%,rgba(34,211,238,0.24),transparent_40%),radial-gradient(circle_at_80%_0%,rgba(56,189,248,0.16),transparent_42%),linear-gradient(180deg,rgba(10,14,26,0.96),rgba(8,12,22,0.92))]">
<div className="pointer-events-none absolute inset-0 opacity-40 [background-image:linear-gradient(rgba(255,255,255,0.06)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.06)_1px,transparent_1px)] [background-size:40px_40px]" />
@@ -93,6 +96,7 @@ export default function ForumIndex({ categories = [], trendingTopics = [], lates
<Panel title="Latest Topics" items={latestTopics} emptyLabel="Latest topics will appear here." />
</section>
</div>
</>
)
}

View File

@@ -5,8 +5,9 @@ import TextInput from '../../components/ui/TextInput'
import RichTextEditor from '../../components/forum/RichTextEditor'
import TurnstileField from '../../components/security/TurnstileField'
import { populateBotFingerprint } from '../../lib/security/botFingerprint'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumNewThread({ category, csrfToken, errors = {}, oldValues = {}, captcha = {} }) {
export default function ForumNewThread({ category, csrfToken, errors = {}, oldValues = {}, captcha = {}, seo = {} }) {
const [title, setTitle] = useState(oldValues.title ?? '')
const [content, setContent] = useState(oldValues.content ?? '')
const [captchaToken, setCaptchaToken] = useState('')
@@ -33,7 +34,9 @@ export default function ForumNewThread({ category, csrfToken, errors = {}, oldVa
}, [submitting])
return (
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-3xl mx-auto">
<>
<SeoHead seo={seo} />
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-3xl mx-auto">
<Breadcrumbs items={breadcrumbs} />
{/* Header */}
@@ -115,5 +118,6 @@ export default function ForumNewThread({ category, csrfToken, errors = {}, oldVa
</div>
</form>
</div>
</>
)
}

View File

@@ -1,7 +1,8 @@
import React from 'react'
import Breadcrumbs from '../../components/forum/Breadcrumbs'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumSection({ category, boards = [] }) {
export default function ForumSection({ category, boards = [], seo = {} }) {
const name = category?.name ?? 'Forum Section'
const description = category?.description
const preview = category?.preview_image ?? '/images/forum/default.jpg'
@@ -13,7 +14,9 @@ export default function ForumSection({ category, boards = [] }) {
]
return (
<div className="mx-auto max-w-6xl px-4 pb-20 pt-10 sm:px-6 lg:px-8">
<>
<SeoHead seo={seo} />
<div className="mx-auto max-w-6xl px-4 pb-20 pt-10 sm:px-6 lg:px-8">
<Breadcrumbs items={breadcrumbs} />
<section className="mt-5 overflow-hidden rounded-3xl border border-white/10 bg-nova-800/55 shadow-xl backdrop-blur">
@@ -64,5 +67,6 @@ export default function ForumSection({ category, boards = [] }) {
)}
</section>
</div>
</>
)
}

View File

@@ -3,6 +3,7 @@ import Breadcrumbs from '../../components/forum/Breadcrumbs'
import PostCard from '../../components/forum/PostCard'
import ReplyForm from '../../components/forum/ReplyForm'
import Pagination from '../../components/forum/Pagination'
import SeoHead from '../../components/seo/SeoHead'
export default function ForumThread({
thread,
@@ -21,6 +22,7 @@ export default function ForumThread({
csrfToken = '',
status = null,
captcha = {},
seo = {},
}) {
const [currentSort, setCurrentSort] = useState(sort)
@@ -41,7 +43,9 @@ export default function ForumThread({
}, [currentSort])
return (
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-5xl mx-auto space-y-5">
<>
<SeoHead seo={seo} />
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-5xl mx-auto space-y-5">
<Breadcrumbs items={breadcrumbs} />
{/* Status flash */}
@@ -176,6 +180,7 @@ export default function ForumThread({
</div>
)}
</div>
</>
)
}