Forum: - TipTap WYSIWYG editor with full toolbar - @emoji-mart/react emoji picker (consistent with tweets) - @mention autocomplete with user search API - Fix PHP 8.4 parse errors in Blade templates - Fix thread data display (paginator items) - Align forum page widths to max-w-5xl Discover: - Extract shared _nav.blade.php partial - Add missing nav links to for-you page - Add Following link for authenticated users Feed/Posts: - Post model, controllers, policies, migrations - Feed page components (PostComposer, FeedCard, etc) - Post reactions, comments, saves, reports, sharing - Scheduled publishing support - Link preview controller Profile: - Profile page components (ProfileHero, ProfileTabs) - Profile API controller Uploads: - Upload wizard enhancements - Scheduled publish picker - Studio status bar and readiness checklist
92 lines
3.0 KiB
JavaScript
92 lines
3.0 KiB
JavaScript
import React, { useState, useCallback } from 'react'
|
|
import Breadcrumbs from '../../components/forum/Breadcrumbs'
|
|
import Button from '../../components/ui/Button'
|
|
import TextInput from '../../components/ui/TextInput'
|
|
import RichTextEditor from '../../components/forum/RichTextEditor'
|
|
|
|
export default function ForumNewThread({ category, csrfToken, errors = {}, oldValues = {} }) {
|
|
const [title, setTitle] = useState(oldValues.title ?? '')
|
|
const [content, setContent] = useState(oldValues.content ?? '')
|
|
const [submitting, setSubmitting] = useState(false)
|
|
|
|
const slug = category?.slug
|
|
const categoryName = category?.name ?? 'Category'
|
|
|
|
const breadcrumbs = [
|
|
{ label: 'Home', href: '/' },
|
|
{ label: 'Forum', href: '/forum' },
|
|
{ label: categoryName, href: slug ? `/forum/${slug}` : '/forum' },
|
|
{ label: 'New thread' },
|
|
]
|
|
|
|
const handleSubmit = useCallback(async (e) => {
|
|
e.preventDefault()
|
|
if (submitting) return
|
|
setSubmitting(true)
|
|
|
|
// Standard form submission to keep server-side validation + redirect
|
|
e.target.submit()
|
|
}, [submitting])
|
|
|
|
return (
|
|
<div className="px-4 pt-10 pb-20 sm:px-6 lg:px-8 max-w-3xl mx-auto">
|
|
<Breadcrumbs items={breadcrumbs} />
|
|
|
|
{/* Header */}
|
|
<div className="mt-5 mb-6">
|
|
<p className="text-xs font-semibold uppercase tracking-widest text-white/30 mb-1">New thread</p>
|
|
<h1 className="text-2xl font-bold text-white leading-tight">
|
|
Create thread in {categoryName}
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Form */}
|
|
<form
|
|
method="POST"
|
|
action={`/forum/${slug}/new`}
|
|
onSubmit={handleSubmit}
|
|
className="space-y-5 rounded-2xl border border-white/[0.06] bg-nova-800/50 p-6 backdrop-blur"
|
|
>
|
|
<input type="hidden" name="_token" value={csrfToken} />
|
|
|
|
<TextInput
|
|
label="Title"
|
|
name="title"
|
|
value={title}
|
|
onChange={(e) => setTitle(e.target.value)}
|
|
required
|
|
maxLength={255}
|
|
placeholder="Thread title…"
|
|
error={errors.title}
|
|
/>
|
|
|
|
{/* Rich text editor */}
|
|
<div>
|
|
<label className="mb-1.5 block text-sm font-medium text-white/85">
|
|
Content <span className="text-red-400 ml-1">*</span>
|
|
</label>
|
|
<RichTextEditor
|
|
content={content}
|
|
onChange={setContent}
|
|
placeholder="Write your post…"
|
|
error={errors.content}
|
|
minHeight={14}
|
|
autofocus={false}
|
|
/>
|
|
<input type="hidden" name="content" value={content} />
|
|
</div>
|
|
|
|
{/* Submit */}
|
|
<div className="flex items-center justify-between pt-2">
|
|
<a href={`/forum/${slug}`} className="text-sm text-zinc-500 hover:text-zinc-300 transition-colors">
|
|
← Cancel
|
|
</a>
|
|
<Button type="submit" variant="primary" size="md" loading={submitting}>
|
|
Publish thread
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
)
|
|
}
|