feat: community feed, post detail, and new post pages

This commit is contained in:
zetaloop
2026-02-20 15:22:30 +08:00
parent dad59e4914
commit e132ffcefb
3 changed files with 412 additions and 10 deletions
+174 -3
View File
@@ -1,8 +1,179 @@
"use client"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
import { ArrowLeft, ImagePlus, X } from "lucide-react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { useState } from "react"
import { useForm } from "react-hook-form"
import { z } from "zod"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { Textarea } from "@/components/ui/textarea"
const postSchema = z.object({
title: z.string().min(2, "标题至少2个字符").max(50, "标题最多50个字符"),
content: z.string().min(10, "内容至少10个字符"),
})
const tagOptions = ["英雄联盟", "王者荣耀", "CS2", "原神", "上分", "攻略", "好评", "吐槽", "求组队"]
export default function NewPostPage() {
const router = useRouter()
const [postType, setPostType] = useState("normal")
const [selectedTags, setSelectedTags] = useState<string[]>([])
const [imageCount, setImageCount] = useState(0)
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm({
resolver: standardSchemaResolver(postSchema),
})
const toggleTag = (tag: string) => {
setSelectedTags((prev) =>
prev.includes(tag) ? prev.filter((t) => t !== tag) : prev.length < 5 ? [...prev, tag] : prev,
)
}
const onSubmit = async () => {
await new Promise((r) => setTimeout(r, 500))
router.push("/community")
}
return (
<div className="container mx-auto py-8 px-4">
<h1 className="text-2xl font-bold"></h1>
<p className="mt-2 text-muted-foreground"></p>
<div className="container mx-auto py-8 px-4 max-w-2xl">
<Link
href="/community"
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div className="space-y-2">
<Label></Label>
<Select value={postType} onValueChange={setPostType}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="normal"></SelectItem>
<SelectItem value="show_order"></SelectItem>
<SelectItem value="quote"></SelectItem>
</SelectContent>
</Select>
</div>
{postType === "show_order" && (
<div className="space-y-2">
<Label></Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="选择要展示的订单" />
</SelectTrigger>
<SelectContent>
<SelectItem value="ord2"> · </SelectItem>
</SelectContent>
</Select>
</div>
)}
<div className="space-y-2">
<Label htmlFor="title"></Label>
<Input id="title" placeholder="请输入帖子标题" {...register("title")} />
{errors.title && <p className="text-xs text-destructive">{errors.title.message}</p>}
</div>
<div className="space-y-2">
<Label htmlFor="content"></Label>
<Textarea
id="content"
placeholder="分享你的游戏体验..."
rows={6}
{...register("content")}
/>
{errors.content && (
<p className="text-xs text-destructive">{errors.content.message}</p>
)}
</div>
<div className="space-y-2">
<Label>9</Label>
<div className="flex gap-2 flex-wrap">
{Array.from({ length: imageCount }).map((_, i) => (
<div
key={`img-${i.toString()}`}
className="h-20 w-20 rounded-md bg-muted flex items-center justify-center relative"
>
<span className="text-xs text-muted-foreground"></span>
<button
type="button"
onClick={() => setImageCount((c) => c - 1)}
className="absolute -top-1 -right-1 h-4 w-4 rounded-full bg-destructive text-destructive-foreground flex items-center justify-center"
>
<X className="h-3 w-3" />
</button>
</div>
))}
{imageCount < 9 && (
<button
type="button"
onClick={() => setImageCount((c) => c + 1)}
className="h-20 w-20 rounded-md border-2 border-dashed border-muted-foreground/25 flex flex-col items-center justify-center gap-1 text-muted-foreground hover:border-muted-foreground/50 transition-colors"
>
<ImagePlus className="h-5 w-5" />
<span className="text-[10px]"></span>
</button>
)}
</div>
</div>
<div className="space-y-2">
<Label>5</Label>
<div className="flex flex-wrap gap-2">
{tagOptions.map((tag) => (
<Badge
key={tag}
variant={selectedTags.includes(tag) ? "default" : "outline"}
className="cursor-pointer"
onClick={() => toggleTag(tag)}
>
{tag}
</Badge>
))}
</div>
</div>
<div className="flex gap-2">
<Button type="submit" className="flex-1" disabled={isSubmitting}>
{isSubmitting ? "发布中..." : "发布"}
</Button>
<Button type="button" variant="outline" asChild>
<Link href="/community"></Link>
</Button>
</div>
</form>
</CardContent>
</Card>
</div>
)
}