54 lines
12 KiB
JavaScript
54 lines
12 KiB
JavaScript
import{r as a,j as t,e as Q,v as V,i as J}from"./react-vendor-CgzNJrV9.js";import{n as N}from"./notify-Zesh5czd.js";import{u as W,a as _}from"./index-474mTIgd.js";import{p as K,g as O}from"./markdown-vendor-DxR1h-Bq.js";import{P as q,r as X}from"./postContent-CNPsgNvN.js";import{x as Y,E as Z,B as ee,y as te,z as se,D as ne,Q as re,G as ie,J as ce,K as oe,N as ae,O as le,U as de,A as me,v as pe,V as ue}from"./ui-vendor-CdH1UOKW.js";import{S as D}from"./spinner-DH1syOsQ.js";O.setOptions({breaks:!0,gfm:!0});const he=/:::members[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*:::/g;function xe(l){const s=[];let n=0;const r=new RegExp(he.source,"g");let o;for(;(o=r.exec(l))!==null;)o.index>n&&s.push({type:"text",content:l.slice(n,o.index)}),s.push({type:"members",content:o[1]}),n=r.lastIndex;return n<l.length&&s.push({type:"text",content:l.slice(n)}),s.length===0&&s.push({type:"text",content:l}),s}function I(l){const n=xe(l).map(r=>r.type==="members"?`<members-only>${O.parse(r.content.trim())}</members-only>`:O.parse(r.content)).join("");return K.sanitize(n,q)}function ge(l){if(!l.trim())return"";const s=new DOMParser().parseFromString(K.sanitize(l,q),"text/html"),n=r=>{if(r.nodeType===Node.TEXT_NODE)return r.textContent??"";if(r.nodeType!==Node.ELEMENT_NODE)return"";const o=r,p=o.tagName.toLowerCase(),c=()=>Array.from(o.childNodes).map(n).join("");switch(p){case"members-only":{if(o.getAttribute("data-locked")==="true")return"";const d=o.querySelector(".post-members-only__body");return`:::members
|
||
${(d?Array.from(d.childNodes).map(n).join(""):c()).trim()}
|
||
:::
|
||
|
||
`}case"br":return`
|
||
`;case"p":return c().trimEnd()+`
|
||
|
||
`;case"h1":return`# ${c().trim()}
|
||
|
||
`;case"h2":return`## ${c().trim()}
|
||
|
||
`;case"h3":return`### ${c().trim()}
|
||
|
||
`;case"h4":return`#### ${c().trim()}
|
||
|
||
`;case"h5":return`##### ${c().trim()}
|
||
|
||
`;case"h6":return`###### ${c().trim()}
|
||
|
||
`;case"strong":case"b":return`**${c()}**`;case"em":case"i":return`*${c()}*`;case"code":return`\`${c()}\``;case"pre":return`\`\`\`
|
||
${o.textContent??""}
|
||
\`\`\`
|
||
|
||
`;case"a":return`[${c()}](${o.getAttribute("href")??""})`;case"img":return`??""})`;case"ul":return Array.from(o.children).map(d=>`- ${n(d).trim()}`).join(`
|
||
`)+`
|
||
|
||
`;case"ol":return Array.from(o.children).map((d,b)=>`${b+1}. ${n(d).trim()}`).join(`
|
||
`)+`
|
||
|
||
`;case"li":return c();case"blockquote":return`> ${c().trim().replace(/\n/g,`
|
||
> `)}
|
||
|
||
`;case"hr":return`---
|
||
|
||
`;case"div":return o.classList.contains("post-members-only__badge")||o.classList.contains("post-members-only__gate")||o.classList.contains("post-members-only__gate-icon")?"":(o.classList.contains("post-members-only__body"),c());default:return c()}};return n(s.body).replace(/\n{3,}/g,`
|
||
|
||
`).trim()}function fe(l){var o,p;const s=l.trim();if(!s)return 0;const n=((o=s.match(/[\u4e00-\u9fff]/g))==null?void 0:o.length)??0,r=((p=s.match(/[a-zA-Z0-9]+/g))==null?void 0:p.length)??0;return n+r}function F(l){return l.replace(/^\r/,"").replace(/^#{1,6}\s*/,"").replace(/^>\s*/,"").replace(/^[-*+]\s*/,"").replace(/^\d+\.\s*/,"")}const be=a.forwardRef(function({value:s,onChange:n,placeholder:r="在此撰写正文…"},o){const p=a.useRef(null),c=a.useRef({start:0,end:0}),[d,b]=a.useState("split"),[z,k]=a.useState("");a.useImperativeHandle(o,()=>({getHTML:()=>I(s),getMarkdown:()=>s,isEmpty:()=>s.trim().length===0,focus:()=>{var e;return(e=p.current)==null?void 0:e.focus()}}));const j=a.useCallback(()=>{const e=p.current;e&&(c.current={start:e.selectionStart,end:e.selectionEnd})},[]),g=a.useCallback(()=>{const e=p.current;return e&&document.activeElement===e?{start:e.selectionStart,end:e.selectionEnd}:c.current},[]),f=a.useCallback((e,i=e)=>{requestAnimationFrame(()=>{const m=p.current;m&&(m.focus(),m.setSelectionRange(e,i),c.current={start:e,end:i})})},[]);a.useEffect(()=>{const e=setTimeout(()=>k(I(s)),60);return()=>clearTimeout(e)},[s]);const w=a.useCallback(()=>{const e=p.current;if(!e||d==="preview")return;e.style.height="0px";const i=e.scrollHeight,m=e.getBoundingClientRect().top,u=Math.max(280,window.innerHeight-m-56);e.style.height=`${Math.max(u,i)}px`},[d]);a.useEffect(()=>{w()},[s,d,w]),a.useEffect(()=>{const e=()=>w();return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[w]);const h=a.useCallback((e,i="",m="")=>{if(!p.current)return;const{start:x,end:v}=g(),E=s.slice(x,v)||m,y=s.slice(0,x)+e+E+i+s.slice(v);n(y),f(x+e.length+E.length)},[s,n,g,f]),$=a.useCallback(e=>{if(!p.current)return;const{start:m}=g(),u=s.lastIndexOf(`
|
||
`,m-1)+1,x=s.indexOf(`
|
||
`,m),v=x===-1?s.length:x,E=s.slice(u,v),y=F(E),C=s.slice(0,u)+e+y+s.slice(v);n(C),f(u+e.length+y.length)},[s,n,g,f]),M=a.useCallback(()=>{if(!p.current)return;const{start:i}=g(),m=s.lastIndexOf(`
|
||
`,i-1)+1,u=s.indexOf(`
|
||
`,i),x=u===-1?s.length:u,E=s.slice(m,x).replace(/^\r/,""),y=E.match(/^(#{1,6})\s+(.*)$/);let C;if(y){const R=y[1].length,B=y[2];C=R>=6?B:`${"#".repeat(R+1)} ${B}`}else C=`## ${F(E)}`;const U=s.slice(0,m)+C+s.slice(x);n(U);const G=m+C.length;f(G)},[s,n,g,f]),T=a.useCallback(()=>{const{start:e,end:i}=g();if(e!==i){const u=`
|
||
:::members
|
||
${s.slice(e,i)}
|
||
:::
|
||
`,x=s.slice(0,e)+u+s.slice(i);n(x),f(e+11+1);return}h(`
|
||
:::members
|
||
`,`
|
||
:::
|
||
`,"在此输入仅登录用户可见的内容…")},[s,n,g,f,h]),L=[{icon:t.jsx("strong",{children:"H"}),title:"标题(H2,再次点击升级)",action:M},{icon:t.jsx(ee,{size:15}),title:"加粗",action:()=>h("**","**","加粗")},{icon:t.jsx(te,{size:15}),title:"斜体",action:()=>h("*","*","斜体")},{icon:t.jsx(se,{size:15}),title:"删除线",action:()=>h("~~","~~","删除")},{icon:t.jsx(ne,{size:15}),title:"分割线",action:()=>h(`
|
||
|
||
---
|
||
|
||
`)},{icon:t.jsx(re,{size:15}),title:"引用",action:()=>$("> ")},{icon:t.jsx(ie,{size:15}),title:"无序列表",action:()=>$("- ")},{icon:t.jsx(ce,{size:15}),title:"有序列表",action:()=>$("1. ")},{icon:t.jsx(oe,{size:15}),title:"代码块",action:()=>h("\n```\n","\n```\n","code")},{icon:t.jsx(ae,{size:15}),title:"链接",action:()=>h("[","](url)","链接文字")},{icon:t.jsx(le,{size:15}),title:"图片",action:()=>h("","描述")},{icon:t.jsx(de,{size:15}),title:"登录可见(选中文字后点击可包裹)",action:T}],A=a.useMemo(()=>s.trim()?X(z,!0):`<p class="article-preview-placeholder">${r}</p>`,[s,z,r]),P=fe(s),H=d==="edit"||d==="split",S=d==="preview"||d==="split";return t.jsxs("div",{className:"article-editor",children:[t.jsxs("div",{className:"article-editor-bar",children:[t.jsx("div",{className:"article-editor-tools",children:L.map((e,i)=>t.jsx("button",{type:"button",className:`article-tool-btn${i===L.length-1?" article-tool-btn--members":""}`,title:e.title,onMouseDown:m=>m.preventDefault(),onClick:e.action,children:e.icon},i))}),t.jsxs("div",{className:"article-editor-modes",children:[t.jsxs("button",{type:"button",className:`article-mode-btn${d==="edit"?" active":""}`,onClick:()=>b("edit"),title:"仅编辑",children:[t.jsx(Y,{size:14})," 编辑"]}),t.jsx("button",{type:"button",className:`article-mode-btn${d==="split"?" active":""}`,onClick:()=>b("split"),title:"分栏预览",children:"分栏"}),t.jsxs("button",{type:"button",className:`article-mode-btn${d==="preview"?" active":""}`,onClick:()=>b("preview"),title:"仅预览",children:[t.jsx(Z,{size:14})," 预览"]})]})]}),t.jsxs("div",{className:`article-editor-panes article-editor-panes--${d}`,children:[H&&t.jsx("div",{className:"article-pane article-pane--edit",children:t.jsx("textarea",{ref:p,className:"article-textarea",value:s,onChange:e=>n(e.target.value),onSelect:j,onKeyUp:j,onClick:j,onFocus:j,placeholder:r,spellCheck:!1})}),S&&t.jsxs("div",{className:"article-pane article-pane--preview",children:[d==="split"&&t.jsx("div",{className:"article-pane-label",children:"实时预览"}),t.jsx("div",{className:`article-preview post-detail-content${s.trim()?"":" article-preview--empty"}`,dangerouslySetInnerHTML:{__html:A}})]})]}),t.jsxs("div",{className:"article-editor-status",children:[t.jsxs("span",{children:[P," 字"]}),t.jsx("span",{children:"Markdown"})]})]})});function Se(){const l=Q(),{id:s}=V(),n=s?Number(s):null,r=n!==null&&!Number.isNaN(n),[o]=J(),p=o.get("board")||"",{user:c,loading:d}=W(),[b,z]=a.useState([]),[k,j]=a.useState(p),[g,f]=a.useState(""),[w,h]=a.useState(""),[$,M]=a.useState(""),[T,L]=a.useState(!1),[A,P]=a.useState(r);if(a.useEffect(()=>{if(!d){if(!c){l("/login");return}if(r){P(!0),Promise.all([_.boards(),_.post(n)]).then(([e,i])=>{const m=e.boards??[];z(m);const u=i.post;if(!(c.role==="admin"||u.user_id===c.id)){N.error("无权编辑此帖子"),l(`/post/${n}`);return}j(String(u.board_id)),f(u.title),h(u.tags??""),M(ge(u.content??""))}).catch(e=>{N.error(e instanceof Error?e.message:"加载帖子失败"),l("/")}).finally(()=>P(!1));return}_.boards().then(e=>{const i=e.boards??[];z(i),!p&&i.length>0&&j(String(i[0].id))}).catch(()=>{})}},[c,d,l,p,r,n]),d)return t.jsx("div",{className:"compose-page compose-page--empty",children:t.jsx(D,{size:"lg"})});if(!c)return null;if(A)return t.jsx("div",{className:"compose-page compose-page--empty",children:t.jsx(D,{size:"lg"})});if(!r&&b.length===0)return t.jsx("div",{className:"compose-page compose-page--empty",children:t.jsxs("div",{className:"compose-empty-card",children:[t.jsx("div",{className:"compose-empty-icon",children:"✎"}),t.jsx("h2",{children:"暂无可发帖板块"}),t.jsx("p",{children:"需要管理员先创建板块后才能发布内容"}),c.role==="admin"?t.jsx("button",{type:"button",className:"compose-primary-btn",onClick:()=>l("/boards"),children:"去创建板块"}):t.jsx("button",{type:"button",className:"compose-ghost-btn",onClick:()=>l("/"),children:"返回首页"})]})});const H=async()=>{const e=g.trim();if(!r&&!k){N.warning("请选择板块");return}if(!e){N.warning("请输入标题");return}if(!$.trim()){N.warning("请输入正文内容");return}L(!0);try{const i={title:e,content:I($),tags:w.trim()};if(r)await _.updatePost(n,i),N.success("帖子已更新"),l(`/post/${n}`);else{const m=await _.createPost({board_id:k,...i});N.success("发帖成功"),l(`/post/${m.post_id}`)}}catch(i){N.error(i instanceof Error?i.message:r?"保存失败":"发帖失败")}finally{L(!1)}},S=b.find(e=>String(e.id)===k);return t.jsx("div",{className:"compose-page",children:t.jsxs("div",{className:"compose-canvas",children:[t.jsxs("header",{className:"compose-header",children:[t.jsxs("button",{type:"button",className:"compose-back",onClick:()=>l(r?`/post/${n}`:-1),children:[t.jsx(me,{size:16}),t.jsx("span",{children:"返回"})]}),t.jsx("div",{className:"compose-header-actions",children:t.jsxs("button",{type:"button",className:"compose-publish-btn",disabled:T,onClick:H,children:[t.jsx(pe,{size:16}),T?r?"保存中…":"发布中…":r?"保存修改":"发布帖子"]})})]}),t.jsxs("div",{className:"compose-meta",children:[r?S&&t.jsx("div",{className:"compose-board-pills",children:t.jsx("span",{className:"compose-board-pill active",children:S.name})}):t.jsx("div",{className:"compose-board-pills",children:b.map(e=>t.jsx("button",{type:"button",className:`compose-board-pill${String(e.id)===k?" active":""}`,onClick:()=>j(String(e.id)),children:e.name},e.id))}),t.jsxs("div",{className:"compose-tags-field",children:[t.jsx(ue,{className:"compose-tags-icon",size:16}),t.jsx("input",{type:"text",placeholder:"添加标签,逗号分隔",value:w,onChange:e=>h(e.target.value),maxLength:128})]})]}),t.jsxs("div",{className:"compose-writing",children:[t.jsx("input",{className:"compose-title",type:"text",placeholder:"输入文章标题…",value:g,onChange:e=>f(e.target.value),maxLength:256}),S&&t.jsxs("div",{className:"compose-subtitle",children:[r?"编辑于":"发布至"," ",t.jsx("strong",{children:S.name})]}),t.jsx(be,{value:$,onChange:M,placeholder:"开始写作。支持 Markdown 语法,右侧可实时预览渲染效果。"})]})]})})}export{Se as default};
|