Files
SkinbaseNova/resources/js/Pages/Forum/ForumNewThread.jsx
Gregor Klevze dc51d65440 feat: forum rich-text editor, emoji picker, mentions, discover nav, feed, uploads, profile
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
2026-03-03 09:48:31 +01:00

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>
)
}