将 Markdown 编辑器替换为 TipTap WYSIWYG,新增帖子修订记录与 diff 展示;首页支持最新/回复排序与本地缓存;后台可配置编辑时限与锁定帖子;侧边栏整合板块导航并优化 Feed 布局。 Co-authored-by: Cursor <cursoragent@cursor.com>
2 lines
8.0 KiB
JavaScript
2 lines
8.0 KiB
JavaScript
import{r as l,j as e,e as Q}from"./react-vendor-CFzzFOsg.js";import{_ as U,Z as W,u as Y,a as $,F as ee,b as g,c as b,d as y,e as N,f as w,o as se,s as R}from"./form-xbbJUieP.js";import{c as n,d as ae,S as F,B as h,a as f,n as c}from"./index-L-Mx2Hle.js";import{I as A}from"./input-CIPYpxcv.js";import{B as te}from"./badge-e5OBoJ6g.js";import{a4 as re,a5 as le,a6 as S,a7 as ne,X as oe,a8 as _,a9 as k,aa as B,m as ie}from"./ui-vendor-DGgNN2YO.js";import{A as de,a as ce,b as me,c as xe,d as he,e as pe,f as fe,g as je,h as ue}from"./alert-dialog-Q1fPYDxo.js";function ge(s){return U(W,s)}const E=l.forwardRef(({className:s,...a},r)=>e.jsx("textarea",{className:n("flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",s),ref:r,...a}));E.displayName="Textarea";const z=l.forwardRef(({className:s,...a},r)=>e.jsx("div",{className:"relative w-full overflow-auto",children:e.jsx("table",{ref:r,className:n("w-full caption-bottom text-sm",s),...a})}));z.displayName="Table";const H=l.forwardRef(({className:s,...a},r)=>e.jsx("thead",{ref:r,className:n("[&_tr]:border-b",s),...a}));H.displayName="TableHeader";const I=l.forwardRef(({className:s,...a},r)=>e.jsx("tbody",{ref:r,className:n("[&_tr:last-child]:border-0",s),...a}));I.displayName="TableBody";const v=l.forwardRef(({className:s,...a},r)=>e.jsx("tr",{ref:r,className:n("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",s),...a}));v.displayName="TableRow";const i=l.forwardRef(({className:s,...a},r)=>e.jsx("th",{ref:r,className:n("h-10 px-3 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",s),...a}));i.displayName="TableHead";const d=l.forwardRef(({className:s,...a},r)=>e.jsx("td",{ref:r,className:n("p-3 align-middle [&:has([role=checkbox])]:pr-0",s),...a}));d.displayName="TableCell";const be=re,ye=le,O=l.forwardRef(({className:s,...a},r)=>e.jsx(k,{ref:r,className:n("fixed inset-0 z-[110] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",s),...a}));O.displayName=k.displayName;const L=l.forwardRef(({className:s,children:a,...r},j)=>e.jsxs(ye,{children:[e.jsx(O,{}),e.jsxs(S,{ref:j,className:n("fixed left-[50%] top-[50%] z-[110] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",s),...r,children:[a,e.jsxs(ne,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[e.jsx(oe,{className:"h-4 w-4"}),e.jsx("span",{className:"sr-only",children:"关闭"})]})]})]}));L.displayName=S.displayName;const P=({className:s,...a})=>e.jsx("div",{className:n("flex flex-col space-y-1.5 text-center sm:text-left",s),...a});P.displayName="DialogHeader";const M=({className:s,...a})=>e.jsx("div",{className:n("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",s),...a});M.displayName="DialogFooter";const Z=l.forwardRef(({className:s,...a},r)=>e.jsx(_,{ref:r,className:n("text-lg font-semibold leading-none tracking-tight",s),...a}));Z.displayName=_.displayName;const Ne=l.forwardRef(({className:s,...a},r)=>e.jsx(B,{ref:r,className:n("text-sm text-muted-foreground",s),...a}));Ne.displayName=B.displayName;const we=se({name:R().min(1,"请输入名称").max(64),description:R().max(500).optional(),sort_order:ge().min(0)});function Se(){Q();const{ready:s}=ae(),[a,r]=l.useState([]),[j,D]=l.useState(!0),[G,m]=l.useState(!1),[p,T]=l.useState(null),[V,C]=l.useState(!1),o=Y({resolver:$(we),defaultValues:{name:"",description:"",sort_order:1}}),u=()=>{D(!0),f.boards().then(t=>r(t.boards??[])).catch(t=>c.error(t.message)).finally(()=>D(!1))};l.useEffect(()=>{s&&u()},[s]);const X=()=>{T(null),o.reset({name:"",description:"",sort_order:a.length+1}),m(!0)},q=t=>{T(t),o.reset({name:t.name,description:t.description??"",sort_order:t.sort_order}),m(!0)},J=async t=>{C(!0);try{p?(await f.updateBoard(p.id,t),c.success("板块已更新")):(await f.createBoard(t),c.success("板块已创建")),m(!1),u(),window.dispatchEvent(new Event("boards-refresh"))}catch(x){c.error(x instanceof Error?x.message:"操作失败")}finally{C(!1)}},K=async t=>{try{await f.deleteBoard(t),c.success("板块已删除"),u(),window.dispatchEvent(new Event("boards-refresh"))}catch(x){c.error(x instanceof Error?x.message:"删除失败")}};return s?e.jsxs("div",{className:"admin-page",children:[e.jsx("div",{className:"admin-page-head",children:e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-start"},children:[e.jsxs("div",{children:[e.jsx("h1",{children:"板块管理"}),e.jsx("p",{children:"创建、编辑或删除论坛板块,用户发帖前需先有板块"})]}),e.jsxs(h,{onClick:X,children:[e.jsx(ie,{}),"新建板块"]})]})}),e.jsx("div",{className:"admin-card",children:j?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(F,{size:"lg"})}):e.jsxs(e.Fragment,{children:[e.jsxs(z,{children:[e.jsx(H,{children:e.jsxs(v,{children:[e.jsx(i,{className:"w-[60px]",children:"ID"}),e.jsx(i,{children:"名称"}),e.jsx(i,{children:"简介"}),e.jsx(i,{className:"w-[70px]",children:"排序"}),e.jsx(i,{className:"w-[80px]",children:"帖子数"}),e.jsx(i,{className:"w-[160px]",children:"操作"})]})}),e.jsx(I,{children:a.map(t=>e.jsxs(v,{children:[e.jsx(d,{children:t.id}),e.jsx(d,{children:e.jsx("strong",{children:t.name})}),e.jsx(d,{className:"max-w-[200px] truncate",children:t.description}),e.jsx(d,{children:t.sort_order}),e.jsx(d,{children:e.jsx(te,{variant:"secondary",children:t.post_count??0})}),e.jsx(d,{children:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(h,{variant:"ghost",size:"sm",onClick:()=>q(t),children:"编辑"}),e.jsxs(de,{children:[e.jsx(ce,{asChild:!0,children:e.jsx(h,{variant:"ghost",size:"sm",className:"text-destructive hover:text-destructive",children:"删除"})}),e.jsxs(me,{children:[e.jsxs(xe,{children:[e.jsx(he,{children:"确定删除该板块?"}),e.jsx(pe,{children:"删除后该板块下的帖子将无法通过板块筛选,此操作不可撤销。"})]}),e.jsxs(fe,{children:[e.jsx(je,{children:"取消"}),e.jsx(ue,{onClick:()=>K(t.id),children:"删除"})]})]})]})]})})]},t.id))})]}),a.length===0&&e.jsx("div",{className:"empty-state",children:e.jsx("p",{children:"还没有板块,点击右上角创建第一个"})})]})}),e.jsx(be,{open:G,onOpenChange:m,children:e.jsxs(L,{children:[e.jsx(P,{children:e.jsx(Z,{children:p?"编辑板块":"新建板块"})}),e.jsx(ee,{...o,children:e.jsxs("form",{onSubmit:o.handleSubmit(J),className:"space-y-4",children:[e.jsx(g,{control:o.control,name:"name",render:({field:t})=>e.jsxs(b,{children:[e.jsx(y,{children:"板块名称"}),e.jsx(N,{children:e.jsx(A,{maxLength:64,placeholder:"如:技术交流",...t})}),e.jsx(w,{})]})}),e.jsx(g,{control:o.control,name:"description",render:({field:t})=>e.jsxs(b,{children:[e.jsx(y,{children:"简介"}),e.jsx(N,{children:e.jsx(E,{rows:3,maxLength:500,placeholder:"板块说明(可选)",...t})}),e.jsx(w,{})]})}),e.jsx(g,{control:o.control,name:"sort_order",render:({field:t})=>e.jsxs(b,{children:[e.jsx(y,{children:"排序"}),e.jsx(N,{children:e.jsx(A,{type:"number",min:0,...t})}),e.jsx(w,{})]})}),e.jsxs(M,{children:[e.jsx(h,{type:"button",variant:"outline",onClick:()=>m(!1),children:"取消"}),e.jsx(h,{type:"submit",loading:V,children:p?"保存":"创建"})]})]})})]})})]}):e.jsx("div",{className:"flex justify-center py-16",children:e.jsx(F,{size:"lg"})})}export{Se as default};
|