限制首页 Feed 自动加载上限,超出后支持手动加载更多历史帖子。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
import{e as A,r as i,j as e}from"./react-vendor-1fwFMt02.js";import{i as D,S as C,B as d,a as m,n as c}from"./index-kfMSnNdB.js";import{B as N}from"./badge-C0Go598m.js";import{A as y,a as b,b as k,c as S,d as _,e as z,f as B,g as E,h as P}from"./alert-dialog-_wPjKojj.js";import"./ui-vendor-Gb6mai95.js";function G(){const j=A(),{ready:r}=D(),[o,g]=i.useState([]),[p,h]=i.useState(!0),[a,u]=i.useState(1),[l,f]=i.useState(1),n=(s=a)=>{h(!0),m.adminComments(s).then(t=>{g(t.comments??[]),u(t.page),f(t.total_pages)}).catch(t=>c.error(t.message)).finally(()=>h(!1))};i.useEffect(()=>{r&&n(1)},[r]);const v=async s=>{try{await m.adminDeleteComment(s),c.success("评论已删除"),n()}catch(t){c.error(t instanceof Error?t.message:"删除失败")}};return r?e.jsxs("div",{className:"admin-page",children:[e.jsxs("div",{className:"admin-page-head",children:[e.jsx("h1",{children:"评论管理"}),e.jsx("p",{children:"查看与删除楼层评论"})]}),e.jsx("div",{className:"admin-card",children:p?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(C,{size:"lg"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"ID"}),e.jsx("th",{children:"楼层"}),e.jsx("th",{children:"帖子"}),e.jsx("th",{children:"作者"}),e.jsx("th",{children:"内容"}),e.jsx("th",{children:"私密"}),e.jsx("th",{children:"时间"}),e.jsx("th",{children:"操作"})]})}),e.jsx("tbody",{children:o.map(s=>{var t,x;return e.jsxs("tr",{children:[e.jsx("td",{children:s.id}),e.jsxs("td",{children:["#",s.floor]}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>j(`/post/${s.post_id}`),children:((t=s.post)==null?void 0:t.title)??`#${s.post_id}`})}),e.jsx("td",{children:((x=s.user)==null?void 0:x.nickname)||s.guest_nick||"游客"}),e.jsx("td",{className:"max-w-[200px] truncate",children:s.content}),e.jsx("td",{children:s.is_private?e.jsx(N,{variant:"secondary",children:"是"}):"—"}),e.jsx("td",{children:new Date(s.created_at).toLocaleString("zh-CN")}),e.jsx("td",{children:e.jsxs(y,{children:[e.jsx(b,{asChild:!0,children:e.jsx(d,{size:"sm",variant:"ghost",className:"text-destructive",children:"删除"})}),e.jsxs(k,{children:[e.jsxs(S,{children:[e.jsx(_,{children:"确定删除该评论?"}),e.jsx(z,{children:"此操作不可恢复。"})]}),e.jsxs(B,{children:[e.jsx(E,{children:"取消"}),e.jsx(P,{onClick:()=>v(s.id),children:"删除"})]})]})]})})]},s.id)})})]}),o.length===0&&e.jsx("div",{className:"admin-empty",children:"暂无评论"}),l>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsx(d,{size:"sm",variant:"outline",disabled:a<=1,onClick:()=>n(a-1),children:"上一页"}),e.jsxs("span",{children:["第 ",a," / ",l," 页"]}),e.jsx(d,{size:"sm",variant:"outline",disabled:a>=l,onClick:()=>n(a+1),children:"下一页"})]})]})})]}):null}export{G as default};
|
||||
import{e as A,r as i,j as e}from"./react-vendor-1fwFMt02.js";import{i as D,S as C,B as d,a as m,n as c}from"./index-BCHo3nLu.js";import{B as N}from"./badge-C7JnHIoR.js";import{A as y,a as b,b as k,c as S,d as _,e as z,f as B,g as E,h as P}from"./alert-dialog-C_2cPHgh.js";import"./ui-vendor-Gb6mai95.js";function G(){const j=A(),{ready:r}=D(),[o,g]=i.useState([]),[p,h]=i.useState(!0),[a,u]=i.useState(1),[l,f]=i.useState(1),n=(s=a)=>{h(!0),m.adminComments(s).then(t=>{g(t.comments??[]),u(t.page),f(t.total_pages)}).catch(t=>c.error(t.message)).finally(()=>h(!1))};i.useEffect(()=>{r&&n(1)},[r]);const v=async s=>{try{await m.adminDeleteComment(s),c.success("评论已删除"),n()}catch(t){c.error(t instanceof Error?t.message:"删除失败")}};return r?e.jsxs("div",{className:"admin-page",children:[e.jsxs("div",{className:"admin-page-head",children:[e.jsx("h1",{children:"评论管理"}),e.jsx("p",{children:"查看与删除楼层评论"})]}),e.jsx("div",{className:"admin-card",children:p?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(C,{size:"lg"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"ID"}),e.jsx("th",{children:"楼层"}),e.jsx("th",{children:"帖子"}),e.jsx("th",{children:"作者"}),e.jsx("th",{children:"内容"}),e.jsx("th",{children:"私密"}),e.jsx("th",{children:"时间"}),e.jsx("th",{children:"操作"})]})}),e.jsx("tbody",{children:o.map(s=>{var t,x;return e.jsxs("tr",{children:[e.jsx("td",{children:s.id}),e.jsxs("td",{children:["#",s.floor]}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>j(`/post/${s.post_id}`),children:((t=s.post)==null?void 0:t.title)??`#${s.post_id}`})}),e.jsx("td",{children:((x=s.user)==null?void 0:x.nickname)||s.guest_nick||"游客"}),e.jsx("td",{className:"max-w-[200px] truncate",children:s.content}),e.jsx("td",{children:s.is_private?e.jsx(N,{variant:"secondary",children:"是"}):"—"}),e.jsx("td",{children:new Date(s.created_at).toLocaleString("zh-CN")}),e.jsx("td",{children:e.jsxs(y,{children:[e.jsx(b,{asChild:!0,children:e.jsx(d,{size:"sm",variant:"ghost",className:"text-destructive",children:"删除"})}),e.jsxs(k,{children:[e.jsxs(S,{children:[e.jsx(_,{children:"确定删除该评论?"}),e.jsx(z,{children:"此操作不可恢复。"})]}),e.jsxs(B,{children:[e.jsx(E,{children:"取消"}),e.jsx(P,{onClick:()=>v(s.id),children:"删除"})]})]})]})})]},s.id)})})]}),o.length===0&&e.jsx("div",{className:"admin-empty",children:"暂无评论"}),l>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsx(d,{size:"sm",variant:"outline",disabled:a<=1,onClick:()=>n(a-1),children:"上一页"}),e.jsxs("span",{children:["第 ",a," / ",l," 页"]}),e.jsx(d,{size:"sm",variant:"outline",disabled:a>=l,onClick:()=>n(a+1),children:"下一页"})]})]})})]}):null}export{G as default};
|
||||
@@ -1 +1 @@
|
||||
import{e as h,r as n,j as s}from"./react-vendor-1fwFMt02.js";import{i as o,a as x,S as j}from"./index-kfMSnNdB.js";import{B as u}from"./badge-C0Go598m.js";import"./ui-vendor-Gb6mai95.js";function f(){const i=h(),{ready:t}=o(),[e,d]=n.useState(null),[r,c]=n.useState(!0);if(n.useEffect(()=>{t&&x.adminDashboard().then(d).finally(()=>c(!1))},[t]),!t||r)return s.jsx("div",{className:"flex justify-center py-16",children:s.jsx(j,{size:"lg"})});if(!e)return null;const m=[{label:"注册用户",value:e.users,cls:"admin-stat-users"},{label:"帖子总数",value:e.posts,cls:"admin-stat-posts"},{label:"板块数量",value:e.boards,cls:"admin-stat-boards"},{label:"评论总数",value:e.comments,cls:"admin-stat-comments"},{label:"当前在线",value:e.online,cls:"admin-stat-online"}];return s.jsxs("div",{className:"admin-page",children:[s.jsxs("div",{className:"admin-page-head",children:[s.jsx("h1",{children:"仪表盘"}),s.jsx("p",{children:"论坛运行概览与最新帖子"})]}),s.jsx("div",{className:"admin-stat-grid",children:m.map(a=>s.jsxs("div",{className:`admin-stat-card ${a.cls}`,children:[s.jsx("div",{className:"admin-stat-value",children:a.value}),s.jsx("div",{className:"admin-stat-label",children:a.label})]},a.label))}),s.jsxs("div",{className:"admin-card",children:[s.jsxs("div",{className:"admin-card-head",children:[s.jsx("span",{children:"最新帖子"}),s.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>i("/admin/posts"),children:"查看全部 →"})]}),s.jsxs("table",{className:"admin-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"ID"}),s.jsx("th",{children:"标题"}),s.jsx("th",{children:"作者"}),s.jsx("th",{children:"置顶"}),s.jsx("th",{children:"时间"})]})}),s.jsx("tbody",{children:e.recent_posts.map(a=>{var l;return s.jsxs("tr",{children:[s.jsx("td",{children:a.id}),s.jsx("td",{children:s.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>i(`/post/${a.id}`),children:a.title})}),s.jsx("td",{children:((l=a.user)==null?void 0:l.nickname)??"—"}),s.jsx("td",{children:a.pinned?s.jsx(u,{variant:"orange",children:"是"}):"—"}),s.jsx("td",{children:new Date(a.created_at).toLocaleString("zh-CN")})]},a.id)})})]}),e.recent_posts.length===0&&s.jsx("div",{className:"admin-empty",children:"暂无帖子"})]})]})}export{f as default};
|
||||
import{e as h,r as n,j as s}from"./react-vendor-1fwFMt02.js";import{i as o,a as x,S as j}from"./index-BCHo3nLu.js";import{B as u}from"./badge-C7JnHIoR.js";import"./ui-vendor-Gb6mai95.js";function f(){const i=h(),{ready:t}=o(),[e,d]=n.useState(null),[r,c]=n.useState(!0);if(n.useEffect(()=>{t&&x.adminDashboard().then(d).finally(()=>c(!1))},[t]),!t||r)return s.jsx("div",{className:"flex justify-center py-16",children:s.jsx(j,{size:"lg"})});if(!e)return null;const m=[{label:"注册用户",value:e.users,cls:"admin-stat-users"},{label:"帖子总数",value:e.posts,cls:"admin-stat-posts"},{label:"板块数量",value:e.boards,cls:"admin-stat-boards"},{label:"评论总数",value:e.comments,cls:"admin-stat-comments"},{label:"当前在线",value:e.online,cls:"admin-stat-online"}];return s.jsxs("div",{className:"admin-page",children:[s.jsxs("div",{className:"admin-page-head",children:[s.jsx("h1",{children:"仪表盘"}),s.jsx("p",{children:"论坛运行概览与最新帖子"})]}),s.jsx("div",{className:"admin-stat-grid",children:m.map(a=>s.jsxs("div",{className:`admin-stat-card ${a.cls}`,children:[s.jsx("div",{className:"admin-stat-value",children:a.value}),s.jsx("div",{className:"admin-stat-label",children:a.label})]},a.label))}),s.jsxs("div",{className:"admin-card",children:[s.jsxs("div",{className:"admin-card-head",children:[s.jsx("span",{children:"最新帖子"}),s.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>i("/admin/posts"),children:"查看全部 →"})]}),s.jsxs("table",{className:"admin-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"ID"}),s.jsx("th",{children:"标题"}),s.jsx("th",{children:"作者"}),s.jsx("th",{children:"置顶"}),s.jsx("th",{children:"时间"})]})}),s.jsx("tbody",{children:e.recent_posts.map(a=>{var l;return s.jsxs("tr",{children:[s.jsx("td",{children:a.id}),s.jsx("td",{children:s.jsx("button",{type:"button",className:"admin-text-link",onClick:()=>i(`/post/${a.id}`),children:a.title})}),s.jsx("td",{children:((l=a.user)==null?void 0:l.nickname)??"—"}),s.jsx("td",{children:a.pinned?s.jsx(u,{variant:"orange",children:"是"}):"—"}),s.jsx("td",{children:new Date(a.created_at).toLocaleString("zh-CN")})]},a.id)})})]}),e.recent_posts.length===0&&s.jsx("div",{className:"admin-empty",children:"暂无帖子"})]})]})}export{f as default};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{r as i,j as e}from"./react-vendor-1fwFMt02.js";import{i as v,S as y,B as l,a as j,n as r}from"./index-kfMSnNdB.js";import{B as h}from"./badge-C0Go598m.js";import"./ui-vendor-Gb6mai95.js";function z(){const{ready:d}=v(),[o,m]=i.useState([]),[g,x]=i.useState(!0),[n,p]=i.useState(1),[c,f]=i.useState(1),t=(s=n)=>{x(!0),j.adminUsers(s).then(a=>{m(a.users??[]),p(a.page),f(a.total_pages)}).catch(a=>r.error(a.message)).finally(()=>x(!1))};i.useEffect(()=>{d&&t(1)},[d]);const u=async s=>{if(s.role==="admin"){r.warning("不能禁言管理员");return}try{const a=await j.adminBanUser(s.id,!s.banned);r.success(a.message),t()}catch(a){r.error(a instanceof Error?a.message:"操作失败")}};return d?e.jsxs("div",{className:"admin-page",children:[e.jsxs("div",{className:"admin-page-head",children:[e.jsx("h1",{children:"用户管理"}),e.jsx("p",{children:"查看注册用户,禁言或解除禁言"})]}),e.jsx("div",{className:"admin-card",children:g?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(y,{size:"lg"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"ID"}),e.jsx("th",{children:"用户名"}),e.jsx("th",{children:"昵称"}),e.jsx("th",{children:"角色"}),e.jsx("th",{children:"状态"}),e.jsx("th",{children:"注册时间"}),e.jsx("th",{children:"操作"})]})}),e.jsx("tbody",{children:o.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.id}),e.jsx("td",{children:s.username}),e.jsx("td",{children:s.nickname}),e.jsx("td",{children:s.role==="admin"?e.jsx(h,{variant:"orange",children:"管理员"}):e.jsx(h,{variant:"secondary",children:"用户"})}),e.jsx("td",{children:s.banned?e.jsx(h,{variant:"destructive",children:"已禁言"}):"正常"}),e.jsx("td",{children:s.created_at?new Date(s.created_at).toLocaleString("zh-CN"):"—"}),e.jsx("td",{children:s.role!=="admin"&&e.jsx(l,{size:"sm",variant:"outline",onClick:()=>u(s),children:s.banned?"解除禁言":"禁言"})})]},s.id))})]}),o.length===0&&e.jsx("div",{className:"admin-empty",children:"暂无用户"}),c>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsx(l,{size:"sm",variant:"outline",disabled:n<=1,onClick:()=>t(n-1),children:"上一页"}),e.jsxs("span",{children:["第 ",n," / ",c," 页"]}),e.jsx(l,{size:"sm",variant:"outline",disabled:n>=c,onClick:()=>t(n+1),children:"下一页"})]})]})})]}):null}export{z as default};
|
||||
import{r as i,j as e}from"./react-vendor-1fwFMt02.js";import{i as v,S as y,B as l,a as j,n as r}from"./index-BCHo3nLu.js";import{B as h}from"./badge-C7JnHIoR.js";import"./ui-vendor-Gb6mai95.js";function z(){const{ready:d}=v(),[o,m]=i.useState([]),[g,x]=i.useState(!0),[n,p]=i.useState(1),[c,f]=i.useState(1),t=(s=n)=>{x(!0),j.adminUsers(s).then(a=>{m(a.users??[]),p(a.page),f(a.total_pages)}).catch(a=>r.error(a.message)).finally(()=>x(!1))};i.useEffect(()=>{d&&t(1)},[d]);const u=async s=>{if(s.role==="admin"){r.warning("不能禁言管理员");return}try{const a=await j.adminBanUser(s.id,!s.banned);r.success(a.message),t()}catch(a){r.error(a instanceof Error?a.message:"操作失败")}};return d?e.jsxs("div",{className:"admin-page",children:[e.jsxs("div",{className:"admin-page-head",children:[e.jsx("h1",{children:"用户管理"}),e.jsx("p",{children:"查看注册用户,禁言或解除禁言"})]}),e.jsx("div",{className:"admin-card",children:g?e.jsx("div",{className:"flex justify-center py-12",children:e.jsx(y,{size:"lg"})}):e.jsxs(e.Fragment,{children:[e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"ID"}),e.jsx("th",{children:"用户名"}),e.jsx("th",{children:"昵称"}),e.jsx("th",{children:"角色"}),e.jsx("th",{children:"状态"}),e.jsx("th",{children:"注册时间"}),e.jsx("th",{children:"操作"})]})}),e.jsx("tbody",{children:o.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.id}),e.jsx("td",{children:s.username}),e.jsx("td",{children:s.nickname}),e.jsx("td",{children:s.role==="admin"?e.jsx(h,{variant:"orange",children:"管理员"}):e.jsx(h,{variant:"secondary",children:"用户"})}),e.jsx("td",{children:s.banned?e.jsx(h,{variant:"destructive",children:"已禁言"}):"正常"}),e.jsx("td",{children:s.created_at?new Date(s.created_at).toLocaleString("zh-CN"):"—"}),e.jsx("td",{children:s.role!=="admin"&&e.jsx(l,{size:"sm",variant:"outline",onClick:()=>u(s),children:s.banned?"解除禁言":"禁言"})})]},s.id))})]}),o.length===0&&e.jsx("div",{className:"admin-empty",children:"暂无用户"}),c>1&&e.jsxs("div",{className:"admin-pagination",children:[e.jsx(l,{size:"sm",variant:"outline",disabled:n<=1,onClick:()=>t(n-1),children:"上一页"}),e.jsxs("span",{children:["第 ",n," / ",c," 页"]}),e.jsx(l,{size:"sm",variant:"outline",disabled:n>=c,onClick:()=>t(n+1),children:"下一页"})]})]})})]}):null}export{z as default};
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
var ap=Object.defineProperty;var cp=(n,e,t)=>e in n?ap(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var V=(n,e,t)=>cp(n,typeof e!="symbol"?e+"":e,t);import{r as N,k as Ft,j as b,a as up,m as dp,e as hp,w as fp,i as pp}from"./react-vendor-1fwFMt02.js";import{B as gi,f as Yl,a as en,n as He,u as mp,h as gp,S as Xl}from"./index-kfMSnNdB.js";import{P as lu,r as yp,i as kp}from"./postContent-ClrHK1rL.js";import{p as au}from"./purify-vendor-Cx4rtWv4.js";import{O as to,Q as bp,V as Ql,W as Zl,Y as ea,Z as ta,_ as na,$ as ra,a0 as sa,a1 as ia,a2 as oa,a3 as la,a4 as aa,a5 as xp,a6 as Sp,B as wp,D as vp,A as Ep,x as Cp,a7 as Tp}from"./ui-vendor-Gb6mai95.js";import{D as Mp,a as Ap,b as Np,c as Op,d as Rp,e as Ip}from"./dialog-DJohwkVv.js";import{I as Dp}from"./input-BjHCK3cg.js";var cu={exports:{}},uu={};/**
|
||||
var ap=Object.defineProperty;var cp=(n,e,t)=>e in n?ap(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var V=(n,e,t)=>cp(n,typeof e!="symbol"?e+"":e,t);import{r as N,k as Ft,j as b,a as up,m as dp,e as hp,w as fp,i as pp}from"./react-vendor-1fwFMt02.js";import{B as gi,f as Yl,a as en,n as He,h as mp,u as gp,S as Xl}from"./index-BCHo3nLu.js";import{P as lu,r as yp,i as kp}from"./postContent-ClrHK1rL.js";import{p as au}from"./purify-vendor-Cx4rtWv4.js";import{O as to,Q as bp,V as Ql,W as Zl,Y as ea,Z as ta,_ as na,$ as ra,a0 as sa,a1 as ia,a2 as oa,a3 as la,a4 as aa,a5 as xp,a6 as Sp,B as wp,D as vp,A as Ep,x as Cp,a7 as Tp}from"./ui-vendor-Gb6mai95.js";import{D as Mp,a as Ap,b as Np,c as Op,d as Rp,e as Ip}from"./dialog-CXDeMxB9.js";import{I as Dp}from"./input-Dsk6No-h.js";var cu={exports:{}},uu={};/**
|
||||
* @license React
|
||||
* use-sync-external-store-shim.production.js
|
||||
*
|
||||
@@ -1 +1 @@
|
||||
import{e as j,r as n,j as s}from"./react-vendor-1fwFMt02.js";import{u as f,a as g,n as N,S as v,B as m}from"./index-kfMSnNdB.js";import{f as y}from"./content-BrFHUpp8.js";import{A as k}from"./ui-vendor-Gb6mai95.js";function S(){const a=j(),{user:t,loading:i}=f(),[r,h]=n.useState([]),[u,x]=n.useState(!0);return n.useEffect(()=>{if(!i){if(!t){a("/login");return}g.favorites().then(e=>h(Array.isArray(e.favorites)?e.favorites:[])).catch(e=>N.error(e.message)).finally(()=>x(!1))}},[t,i,a]),i||u?s.jsx("div",{className:"flex justify-center py-16",children:s.jsx(v,{size:"lg"})}):t?s.jsx("div",{className:"page-wrap",children:s.jsxs("div",{className:"page-inner-wide",children:[s.jsxs(m,{variant:"ghost",className:"mb-3",onClick:()=>a("/"),children:[s.jsx(k,{}),"返回"]}),s.jsx("h1",{className:"page-title",children:"我的收藏"}),s.jsxs("p",{className:"page-desc",children:["共 ",r.length," 篇收藏帖子"]}),r.length===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"还没有收藏任何帖子"}),s.jsx(m,{onClick:()=>a("/"),children:"去逛逛"})]}):s.jsx("div",{className:"content-surface",children:r.map(e=>{var o,l,c,d,p;return s.jsx("div",{className:"post-row",onClick:()=>a(`/post/${e.post_id}`),children:s.jsxs("div",{className:"post-body",children:[s.jsx("div",{className:"post-title",children:((o=e.post)==null?void 0:o.title)||"帖子已删除"}),s.jsxs("div",{className:"post-meta",children:[((c=(l=e.post)==null?void 0:l.board)==null?void 0:c.name)&&s.jsx("span",{children:e.post.board.name}),((p=(d=e.post)==null?void 0:d.user)==null?void 0:p.nickname)&&s.jsx("span",{children:e.post.user.nickname}),s.jsxs("span",{children:["收藏于 ",y(e.created_at)]})]})]})},e.id)})})]})}):null}export{S as default};
|
||||
import{e as j,r as n,j as s}from"./react-vendor-1fwFMt02.js";import{h as f,a as g,n as N,S as v,B as m}from"./index-BCHo3nLu.js";import{f as y}from"./content-BrFHUpp8.js";import{A as k}from"./ui-vendor-Gb6mai95.js";function S(){const a=j(),{user:t,loading:i}=f(),[r,h]=n.useState([]),[x,u]=n.useState(!0);return n.useEffect(()=>{if(!i){if(!t){a("/login");return}g.favorites().then(e=>h(Array.isArray(e.favorites)?e.favorites:[])).catch(e=>N.error(e.message)).finally(()=>u(!1))}},[t,i,a]),i||x?s.jsx("div",{className:"flex justify-center py-16",children:s.jsx(v,{size:"lg"})}):t?s.jsx("div",{className:"page-wrap",children:s.jsxs("div",{className:"page-inner-wide",children:[s.jsxs(m,{variant:"ghost",className:"mb-3",onClick:()=>a("/"),children:[s.jsx(k,{}),"返回"]}),s.jsx("h1",{className:"page-title",children:"我的收藏"}),s.jsxs("p",{className:"page-desc",children:["共 ",r.length," 篇收藏帖子"]}),r.length===0?s.jsxs("div",{className:"empty-state",children:[s.jsx("p",{children:"还没有收藏任何帖子"}),s.jsx(m,{onClick:()=>a("/"),children:"去逛逛"})]}):s.jsx("div",{className:"content-surface",children:r.map(e=>{var o,l,c,d,p;return s.jsx("div",{className:"post-row",onClick:()=>a(`/post/${e.post_id}`),children:s.jsxs("div",{className:"post-body",children:[s.jsx("div",{className:"post-title",children:((o=e.post)==null?void 0:o.title)||"帖子已删除"}),s.jsxs("div",{className:"post-meta",children:[((c=(l=e.post)==null?void 0:l.board)==null?void 0:c.name)&&s.jsx("span",{children:e.post.board.name}),((p=(d=e.post)==null?void 0:d.user)==null?void 0:p.nickname)&&s.jsx("span",{children:e.post.user.nickname}),s.jsxs("span",{children:["收藏于 ",y(e.created_at)]})]})]})},e.id)})})]})}):null}export{S as default};
|
||||
File diff suppressed because one or more lines are too long
1
embed_static/static/spa/assets/HomePage-DTZV5yFZ.js
Normal file
1
embed_static/static/spa/assets/HomePage-DTZV5yFZ.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{e as f,r as g,j as s,L as b}from"./react-vendor-1fwFMt02.js";import{u as w,a as F,F as y,b as t,c as n,d as l,e as c,f as i,o as N,s as m}from"./form-PYX6hP9B.js";import{u as v,B as L,a as S,n as d}from"./index-kfMSnNdB.js";import{I as u}from"./input-BjHCK3cg.js";import"./ui-vendor-Gb6mai95.js";const C=N({username:m().min(1,"请输入用户名"),password:m().min(1,"请输入密码")});function z(){const x=f(),{refresh:p}=v(),[h,a]=g.useState(!1),r=w({resolver:F(C),defaultValues:{username:"",password:""}}),j=async e=>{a(!0);try{await S.login(e.username,e.password),await p(),d.success("登录成功"),x("/",{replace:!0})}catch(o){d.error(o instanceof Error?o.message:"登录失败")}finally{a(!1)}};return s.jsx("div",{className:"auth-page",children:s.jsxs("div",{className:"auth-box",children:[s.jsx("div",{className:"logo-mark",children:"姜"}),s.jsx("h1",{children:"登录姜十三论坛"}),s.jsx("p",{className:"subtitle",children:"拾三一隅,自在交流"}),s.jsx(y,{...r,children:s.jsxs("form",{onSubmit:r.handleSubmit(j),className:"space-y-4",children:[s.jsx(t,{control:r.control,name:"username",render:({field:e})=>s.jsxs(n,{children:[s.jsx(l,{children:"用户名"}),s.jsx(c,{children:s.jsx(u,{placeholder:"用户名",autoComplete:"username",...e})}),s.jsx(i,{})]})}),s.jsx(t,{control:r.control,name:"password",render:({field:e})=>s.jsxs(n,{children:[s.jsx(l,{children:"密码"}),s.jsx(c,{children:s.jsx(u,{type:"password",placeholder:"密码",autoComplete:"current-password",...e})}),s.jsx(i,{})]})}),s.jsx(L,{type:"submit",className:"w-full",loading:h,children:"登录"})]})}),s.jsxs("p",{style:{textAlign:"center",marginTop:16,fontSize:13,color:"var(--color-text-3)"},children:["没有账号?",s.jsx(b,{to:"/register",children:"注册"})]})]})})}export{z as default};
|
||||
import{e as f,r as g,j as s,L as b}from"./react-vendor-1fwFMt02.js";import{u as w,a as F,F as y,b as t,c as n,d as l,e as c,f as i,o as N,s as m}from"./form-CB9KBlPG.js";import{h as v,B as L,a as S,n as d}from"./index-BCHo3nLu.js";import{I as u}from"./input-Dsk6No-h.js";import"./ui-vendor-Gb6mai95.js";const C=N({username:m().min(1,"请输入用户名"),password:m().min(1,"请输入密码")});function z(){const x=f(),{refresh:p}=v(),[h,a]=g.useState(!1),r=w({resolver:F(C),defaultValues:{username:"",password:""}}),j=async e=>{a(!0);try{await S.login(e.username,e.password),await p(),d.success("登录成功"),x("/",{replace:!0})}catch(o){d.error(o instanceof Error?o.message:"登录失败")}finally{a(!1)}};return s.jsx("div",{className:"auth-page",children:s.jsxs("div",{className:"auth-box",children:[s.jsx("div",{className:"logo-mark",children:"姜"}),s.jsx("h1",{children:"登录姜十三论坛"}),s.jsx("p",{className:"subtitle",children:"拾三一隅,自在交流"}),s.jsx(y,{...r,children:s.jsxs("form",{onSubmit:r.handleSubmit(j),className:"space-y-4",children:[s.jsx(t,{control:r.control,name:"username",render:({field:e})=>s.jsxs(n,{children:[s.jsx(l,{children:"用户名"}),s.jsx(c,{children:s.jsx(u,{placeholder:"用户名",autoComplete:"username",...e})}),s.jsx(i,{})]})}),s.jsx(t,{control:r.control,name:"password",render:({field:e})=>s.jsxs(n,{children:[s.jsx(l,{children:"密码"}),s.jsx(c,{children:s.jsx(u,{type:"password",placeholder:"密码",autoComplete:"current-password",...e})}),s.jsx(i,{})]})}),s.jsx(L,{type:"submit",className:"w-full",loading:h,children:"登录"})]})}),s.jsxs("p",{style:{textAlign:"center",marginTop:16,fontSize:13,color:"var(--color-text-3)"},children:["没有账号?",s.jsx(b,{to:"/register",children:"注册"})]})]})})}export{z as default};
|
||||
@@ -1 +1 @@
|
||||
import{j as n}from"./react-vendor-1fwFMt02.js";import{f as i}from"./index-kfMSnNdB.js";import{N as s}from"./ui-vendor-Gb6mai95.js";function m({className:o,size:r=16}){return n.jsx(s,{className:i("post-pinned-icon",o),size:r,fill:"currentColor","aria-label":"置顶",role:"img"})}export{m as P};
|
||||
import{j as n}from"./react-vendor-1fwFMt02.js";import{f as i}from"./index-BCHo3nLu.js";import{N as s}from"./ui-vendor-Gb6mai95.js";function m({className:o,size:r=16}){return n.jsx(s,{className:i("post-pinned-icon",o),size:r,fill:"currentColor","aria-label":"置顶",role:"img"})}export{m as P};
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
import{x as Gt,r as u,j as s,e as Ht}from"./react-vendor-1fwFMt02.js";import{u as ut,a as ft,F as mt,c as L,d as F,e as T,b as Z,f as G,o as Pt,s as X}from"./form-PYX6hP9B.js";import{S as et,B as P,n as z,u as Bt,h as Xt,a as H}from"./index-kfMSnNdB.js";import{I as W}from"./input-BjHCK3cg.js";import{B as Yt}from"./badge-C0Go598m.js";import{D as Vt,a as Kt,b as qt,c as Jt,d as Qt,e as $t}from"./dialog-DJohwkVv.js";import{A as te,a8 as ee,a9 as ie,X as oe,t as re,k as se}from"./ui-vendor-Gb6mai95.js";var gt=!1,E,it,ot,Y,V,Dt,K,rt,st,nt,Rt,at,ht,zt,Et;function C(){if(!gt){gt=!0;var i=navigator.userAgent,e=/(?:MSIE.(\d+\.\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\d+\.\d+))|(?:Opera(?:.+Version.|.)(\d+\.\d+))|(?:AppleWebKit.(\d+(?:\.\d+)?))|(?:Trident\/\d+\.\d+.*rv:(\d+\.\d+))/.exec(i),t=/(Mac OS X)|(Windows)|(Linux)/.exec(i);if(at=/\b(iPhone|iP[ao]d)/.exec(i),ht=/\b(iP[ao]d)/.exec(i),nt=/Android/i.exec(i),zt=/FBAN\/\w+;/i.exec(i),Et=/Mobile/i.exec(i),Rt=!!/Win64/.exec(i),e){E=e[1]?parseFloat(e[1]):e[5]?parseFloat(e[5]):NaN,E&&document&&document.documentMode&&(E=document.documentMode);var o=/(?:Trident\/(\d+.\d+))/.exec(i);Dt=o?parseFloat(o[1])+4:E,it=e[2]?parseFloat(e[2]):NaN,ot=e[3]?parseFloat(e[3]):NaN,Y=e[4]?parseFloat(e[4]):NaN,Y?(e=/(?:Chrome\/(\d+\.\d+))/.exec(i),V=e&&e[1]?parseFloat(e[1]):NaN):V=NaN}else E=it=ot=V=Y=NaN;if(t){if(t[1]){var r=/(?:Mac OS X (\d+(?:[._]\d+)?))/.exec(i);K=r?parseFloat(r[1].replace("_",".")):!0}else K=!1;rt=!!t[2],st=!!t[3]}else K=rt=st=!1}}var ct={ie:function(){return C()||E},ieCompatibilityMode:function(){return C()||Dt>E},ie64:function(){return ct.ie()&&Rt},firefox:function(){return C()||it},opera:function(){return C()||ot},webkit:function(){return C()||Y},safari:function(){return ct.webkit()},chrome:function(){return C()||V},windows:function(){return C()||rt},osx:function(){return C()||K},linux:function(){return C()||st},iphone:function(){return C()||at},mobile:function(){return C()||at||ht||nt||Et},nativeApp:function(){return C()||zt},android:function(){return C()||nt},ipad:function(){return C()||ht}},ne=ct,ae=!!(typeof window<"u"&&window.document&&window.document.createElement),he={canUseDOM:ae},ce=he,At=ce,Mt;At.canUseDOM&&(Mt=document.implementation&&document.implementation.hasFeature&&document.implementation.hasFeature("","")!==!0);/**
|
||||
import{x as Gt,r as u,j as s,e as Ht}from"./react-vendor-1fwFMt02.js";import{u as ut,a as ft,F as mt,c as L,d as F,e as T,b as Z,f as G,o as Pt,s as X}from"./form-CB9KBlPG.js";import{S as et,B as P,n as z,h as Bt,u as Xt,a as H}from"./index-BCHo3nLu.js";import{I as W}from"./input-Dsk6No-h.js";import{B as Yt}from"./badge-C7JnHIoR.js";import{D as Vt,a as Kt,b as qt,c as Jt,d as Qt,e as $t}from"./dialog-CXDeMxB9.js";import{A as te,a8 as ee,a9 as ie,X as oe,t as re,k as se}from"./ui-vendor-Gb6mai95.js";var gt=!1,E,it,ot,Y,V,Dt,K,rt,st,nt,Rt,at,ht,zt,Et;function C(){if(!gt){gt=!0;var i=navigator.userAgent,e=/(?:MSIE.(\d+\.\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\d+\.\d+))|(?:Opera(?:.+Version.|.)(\d+\.\d+))|(?:AppleWebKit.(\d+(?:\.\d+)?))|(?:Trident\/\d+\.\d+.*rv:(\d+\.\d+))/.exec(i),t=/(Mac OS X)|(Windows)|(Linux)/.exec(i);if(at=/\b(iPhone|iP[ao]d)/.exec(i),ht=/\b(iP[ao]d)/.exec(i),nt=/Android/i.exec(i),zt=/FBAN\/\w+;/i.exec(i),Et=/Mobile/i.exec(i),Rt=!!/Win64/.exec(i),e){E=e[1]?parseFloat(e[1]):e[5]?parseFloat(e[5]):NaN,E&&document&&document.documentMode&&(E=document.documentMode);var o=/(?:Trident\/(\d+.\d+))/.exec(i);Dt=o?parseFloat(o[1])+4:E,it=e[2]?parseFloat(e[2]):NaN,ot=e[3]?parseFloat(e[3]):NaN,Y=e[4]?parseFloat(e[4]):NaN,Y?(e=/(?:Chrome\/(\d+\.\d+))/.exec(i),V=e&&e[1]?parseFloat(e[1]):NaN):V=NaN}else E=it=ot=V=Y=NaN;if(t){if(t[1]){var r=/(?:Mac OS X (\d+(?:[._]\d+)?))/.exec(i);K=r?parseFloat(r[1].replace("_",".")):!0}else K=!1;rt=!!t[2],st=!!t[3]}else K=rt=st=!1}}var ct={ie:function(){return C()||E},ieCompatibilityMode:function(){return C()||Dt>E},ie64:function(){return ct.ie()&&Rt},firefox:function(){return C()||it},opera:function(){return C()||ot},webkit:function(){return C()||Y},safari:function(){return ct.webkit()},chrome:function(){return C()||V},windows:function(){return C()||rt},osx:function(){return C()||K},linux:function(){return C()||st},iphone:function(){return C()||at},mobile:function(){return C()||at||ht||nt||Et},nativeApp:function(){return C()||zt},android:function(){return C()||nt},ipad:function(){return C()||ht}},ne=ct,ae=!!(typeof window<"u"&&window.document&&window.document.createElement),he={canUseDOM:ae},ce=he,At=ce,Mt;At.canUseDOM&&(Mt=document.implementation&&document.implementation.hasFeature&&document.implementation.hasFeature("","")!==!0);/**
|
||||
* Checks if an event is supported in the current execution environment.
|
||||
*
|
||||
* NOTE: This will not work correctly for non-generic events such as `change`,
|
||||
@@ -1 +1 @@
|
||||
import{e as g,r as w,j as s,L as F}from"./react-vendor-1fwFMt02.js";import{u as b,a as y,F as k,b as n,c as o,d as t,e as i,f as l,o as N,s as c}from"./form-PYX6hP9B.js";import{h as S,u as v,B as C,a as L,n as x}from"./index-kfMSnNdB.js";import{I as m}from"./input-BjHCK3cg.js";import"./ui-vendor-Gb6mai95.js";const _=r=>N({username:c().min(1,"请输入用户名"),nickname:c().optional(),password:c().min(r,`密码至少 ${r} 位`)});function $(){const{limits:r}=S(),p=g(),{refresh:h}=v(),[j,d]=w.useState(!1),a=b({resolver:y(_(r.password_min_len)),defaultValues:{username:"",nickname:"",password:""}}),f=async e=>{d(!0);try{await L.register(e.username,e.password,e.nickname||e.username),await h(),x.success("注册成功"),p("/",{replace:!0})}catch(u){x.error(u instanceof Error?u.message:"注册失败")}finally{d(!1)}};return s.jsx("div",{className:"auth-page",children:s.jsxs("div",{className:"auth-box",children:[s.jsx("div",{className:"logo-mark",children:"姜"}),s.jsx("h1",{children:"注册账号"}),s.jsx("p",{className:"subtitle",children:"首个注册用户自动成为管理员"}),s.jsx(k,{...a,children:s.jsxs("form",{onSubmit:a.handleSubmit(f),className:"space-y-4",children:[s.jsx(n,{control:a.control,name:"username",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"用户名"}),s.jsx(i,{children:s.jsx(m,{placeholder:"3-32 位字母数字下划线",autoComplete:"username",...e})}),s.jsx(l,{})]})}),s.jsx(n,{control:a.control,name:"nickname",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"昵称"}),s.jsx(i,{children:s.jsx(m,{placeholder:"显示名称(可选)",autoComplete:"nickname",...e})}),s.jsx(l,{})]})}),s.jsx(n,{control:a.control,name:"password",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"密码"}),s.jsx(i,{children:s.jsx(m,{type:"password",placeholder:`至少 ${r.password_min_len} 位`,autoComplete:"new-password",...e})}),s.jsx(l,{})]})}),s.jsx(C,{type:"submit",className:"w-full",loading:j,children:"注册"})]})}),s.jsxs("p",{style:{textAlign:"center",marginTop:16,fontSize:13,color:"var(--color-text-3)"},children:["已有账号?",s.jsx(F,{to:"/login",children:"登录"})]})]})})}export{$ as default};
|
||||
import{e as g,r as w,j as s,L as F}from"./react-vendor-1fwFMt02.js";import{u as b,a as y,F as k,b as n,c as o,d as t,e as i,f as l,o as N,s as c}from"./form-CB9KBlPG.js";import{u as S,h as v,B as C,a as L,n as x}from"./index-BCHo3nLu.js";import{I as m}from"./input-Dsk6No-h.js";import"./ui-vendor-Gb6mai95.js";const _=r=>N({username:c().min(1,"请输入用户名"),nickname:c().optional(),password:c().min(r,`密码至少 ${r} 位`)});function $(){const{limits:r}=S(),p=g(),{refresh:h}=v(),[j,d]=w.useState(!1),a=b({resolver:y(_(r.password_min_len)),defaultValues:{username:"",nickname:"",password:""}}),f=async e=>{d(!0);try{await L.register(e.username,e.password,e.nickname||e.username),await h(),x.success("注册成功"),p("/",{replace:!0})}catch(u){x.error(u instanceof Error?u.message:"注册失败")}finally{d(!1)}};return s.jsx("div",{className:"auth-page",children:s.jsxs("div",{className:"auth-box",children:[s.jsx("div",{className:"logo-mark",children:"姜"}),s.jsx("h1",{children:"注册账号"}),s.jsx("p",{className:"subtitle",children:"首个注册用户自动成为管理员"}),s.jsx(k,{...a,children:s.jsxs("form",{onSubmit:a.handleSubmit(f),className:"space-y-4",children:[s.jsx(n,{control:a.control,name:"username",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"用户名"}),s.jsx(i,{children:s.jsx(m,{placeholder:"3-32 位字母数字下划线",autoComplete:"username",...e})}),s.jsx(l,{})]})}),s.jsx(n,{control:a.control,name:"nickname",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"昵称"}),s.jsx(i,{children:s.jsx(m,{placeholder:"显示名称(可选)",autoComplete:"nickname",...e})}),s.jsx(l,{})]})}),s.jsx(n,{control:a.control,name:"password",render:({field:e})=>s.jsxs(o,{children:[s.jsx(t,{children:"密码"}),s.jsx(i,{children:s.jsx(m,{type:"password",placeholder:`至少 ${r.password_min_len} 位`,autoComplete:"new-password",...e})}),s.jsx(l,{})]})}),s.jsx(C,{type:"submit",className:"w-full",loading:j,children:"注册"})]})}),s.jsxs("p",{style:{textAlign:"center",marginTop:16,fontSize:13,color:"var(--color-text-3)"},children:["已有账号?",s.jsx(F,{to:"/login",children:"登录"})]})]})})}export{$ as default};
|
||||
@@ -1 +1 @@
|
||||
import{r as l,j as s}from"./react-vendor-1fwFMt02.js";import{aj as x,ak as g,al as N,am as r,an as i,ao as d,ap as n,aq as m,ar as c}from"./ui-vendor-Gb6mai95.js";import{f as o,k as f}from"./index-kfMSnNdB.js";const C=x,T=g,y=N,p=l.forwardRef(({className:a,...e},t)=>s.jsx(c,{className:o("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",a),...e,ref:t}));p.displayName=c.displayName;const u=l.forwardRef(({className:a,...e},t)=>s.jsxs(y,{children:[s.jsx(p,{}),s.jsx(r,{ref:t,className:o("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",a),...e})]}));u.displayName=r.displayName;const A=({className:a,...e})=>s.jsx("div",{className:o("flex flex-col space-y-2 text-center sm:text-left",a),...e});A.displayName="AlertDialogHeader";const D=({className:a,...e})=>s.jsx("div",{className:o("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...e});D.displayName="AlertDialogFooter";const j=l.forwardRef(({className:a,...e},t)=>s.jsx(i,{ref:t,className:o("text-lg font-semibold",a),...e}));j.displayName=i.displayName;const w=l.forwardRef(({className:a,...e},t)=>s.jsx(d,{ref:t,className:o("text-sm text-muted-foreground",a),...e}));w.displayName=d.displayName;const b=l.forwardRef(({className:a,...e},t)=>s.jsx(m,{ref:t,className:o(f(),a),...e}));b.displayName=m.displayName;const R=l.forwardRef(({className:a,...e},t)=>s.jsx(n,{ref:t,className:o(f({variant:"outline"}),"mt-2 sm:mt-0",a),...e}));R.displayName=n.displayName;export{C as A,T as a,u as b,A as c,j as d,w as e,D as f,R as g,b as h};
|
||||
import{r as l,j as s}from"./react-vendor-1fwFMt02.js";import{aj as x,ak as g,al as N,am as r,an as i,ao as d,ap as n,aq as m,ar as c}from"./ui-vendor-Gb6mai95.js";import{f as o,k as f}from"./index-BCHo3nLu.js";const C=x,T=g,y=N,p=l.forwardRef(({className:a,...e},t)=>s.jsx(c,{className:o("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",a),...e,ref:t}));p.displayName=c.displayName;const u=l.forwardRef(({className:a,...e},t)=>s.jsxs(y,{children:[s.jsx(p,{}),s.jsx(r,{ref:t,className:o("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",a),...e})]}));u.displayName=r.displayName;const A=({className:a,...e})=>s.jsx("div",{className:o("flex flex-col space-y-2 text-center sm:text-left",a),...e});A.displayName="AlertDialogHeader";const D=({className:a,...e})=>s.jsx("div",{className:o("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...e});D.displayName="AlertDialogFooter";const j=l.forwardRef(({className:a,...e},t)=>s.jsx(i,{ref:t,className:o("text-lg font-semibold",a),...e}));j.displayName=i.displayName;const w=l.forwardRef(({className:a,...e},t)=>s.jsx(d,{ref:t,className:o("text-sm text-muted-foreground",a),...e}));w.displayName=d.displayName;const b=l.forwardRef(({className:a,...e},t)=>s.jsx(m,{ref:t,className:o(f(),a),...e}));b.displayName=m.displayName;const R=l.forwardRef(({className:a,...e},t)=>s.jsx(n,{ref:t,className:o(f({variant:"outline"}),"mt-2 sm:mt-0",a),...e}));R.displayName=n.displayName;export{C as A,T as a,u as b,A as c,j as d,w as e,D as f,R as g,b as h};
|
||||
@@ -1 +1 @@
|
||||
import{j as n}from"./react-vendor-1fwFMt02.js";import{f as a,j as o}from"./index-kfMSnNdB.js";const s=o("inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow",secondary:"border-transparent bg-secondary text-secondary-foreground",destructive:"border-transparent bg-destructive text-destructive-foreground shadow",outline:"text-foreground",green:"border-transparent bg-[var(--j13-green-bg)] text-[var(--j13-green)]",orange:"border-transparent bg-orange-100 text-orange-700 dark:bg-orange-950 dark:text-orange-300"}},defaultVariants:{variant:"default"}});function g({className:r,variant:e,...t}){return n.jsx("div",{className:a(s({variant:e}),r),...t})}export{g as B};
|
||||
import{j as n}from"./react-vendor-1fwFMt02.js";import{f as a,j as o}from"./index-BCHo3nLu.js";const s=o("inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow",secondary:"border-transparent bg-secondary text-secondary-foreground",destructive:"border-transparent bg-destructive text-destructive-foreground shadow",outline:"text-foreground",green:"border-transparent bg-[var(--j13-green-bg)] text-[var(--j13-green)]",orange:"border-transparent bg-orange-100 text-orange-700 dark:bg-orange-950 dark:text-orange-300"}},defaultVariants:{variant:"default"}});function g({className:r,variant:e,...t}){return n.jsx("div",{className:a(s({variant:e}),r),...t})}export{g as B};
|
||||
@@ -1 +1 @@
|
||||
import{r as l,j as t}from"./react-vendor-1fwFMt02.js";import{ab as f,ac as p,ad as d,ae as g,X as x,af as i,ag as n,ah as r}from"./ui-vendor-Gb6mai95.js";import{f as o}from"./index-kfMSnNdB.js";const R=f,u=p,c=l.forwardRef(({className:a,...e},s)=>t.jsx(r,{ref:s,className:o("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",a),...e}));c.displayName=r.displayName;const y=l.forwardRef(({className:a,children:e,...s},m)=>t.jsxs(u,{children:[t.jsx(c,{}),t.jsxs(d,{ref:m,className:o("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",a),...s,children:[e,t.jsxs(g,{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:[t.jsx(x,{className:"h-4 w-4"}),t.jsx("span",{className:"sr-only",children:"关闭"})]})]})]}));y.displayName=d.displayName;const N=({className:a,...e})=>t.jsx("div",{className:o("flex flex-col space-y-1.5 text-center sm:text-left",a),...e});N.displayName="DialogHeader";const j=({className:a,...e})=>t.jsx("div",{className:o("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...e});j.displayName="DialogFooter";const D=l.forwardRef(({className:a,...e},s)=>t.jsx(i,{ref:s,className:o("text-lg font-semibold leading-none tracking-tight",a),...e}));D.displayName=i.displayName;const b=l.forwardRef(({className:a,...e},s)=>t.jsx(n,{ref:s,className:o("text-sm text-muted-foreground",a),...e}));b.displayName=n.displayName;export{R as D,y as a,N as b,D as c,b as d,j as e};
|
||||
import{r as l,j as t}from"./react-vendor-1fwFMt02.js";import{ab as f,ac as p,ad as d,ae as g,X as x,af as i,ag as n,ah as r}from"./ui-vendor-Gb6mai95.js";import{f as o}from"./index-BCHo3nLu.js";const R=f,u=p,c=l.forwardRef(({className:a,...e},s)=>t.jsx(r,{ref:s,className:o("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",a),...e}));c.displayName=r.displayName;const y=l.forwardRef(({className:a,children:e,...s},m)=>t.jsxs(u,{children:[t.jsx(c,{}),t.jsxs(d,{ref:m,className:o("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",a),...s,children:[e,t.jsxs(g,{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:[t.jsx(x,{className:"h-4 w-4"}),t.jsx("span",{className:"sr-only",children:"关闭"})]})]})]}));y.displayName=d.displayName;const N=({className:a,...e})=>t.jsx("div",{className:o("flex flex-col space-y-1.5 text-center sm:text-left",a),...e});N.displayName="DialogHeader";const j=({className:a,...e})=>t.jsx("div",{className:o("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",a),...e});j.displayName="DialogFooter";const D=l.forwardRef(({className:a,...e},s)=>t.jsx(i,{ref:s,className:o("text-lg font-semibold leading-none tracking-tight",a),...e}));D.displayName=i.displayName;const b=l.forwardRef(({className:a,...e},s)=>t.jsx(n,{ref:s,className:o("text-sm text-muted-foreground",a),...e}));b.displayName=n.displayName;export{R as D,y as a,N as b,D as c,b as d,j as e};
|
||||
File diff suppressed because one or more lines are too long
2
embed_static/static/spa/assets/index-BCHo3nLu.js
Normal file
2
embed_static/static/spa/assets/index-BCHo3nLu.js
Normal file
File diff suppressed because one or more lines are too long
1
embed_static/static/spa/assets/index-BH_9j3kA.css
Normal file
1
embed_static/static/spa/assets/index-BH_9j3kA.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{r as t,j as i}from"./react-vendor-1fwFMt02.js";import{f as n}from"./index-kfMSnNdB.js";const a=t.forwardRef(({className:e,type:o,...r},s)=>i.jsx("input",{type:o,className:n("flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",e),ref:s,...r}));a.displayName="Input";export{a as I};
|
||||
import{r as t,j as i}from"./react-vendor-1fwFMt02.js";import{f as n}from"./index-BCHo3nLu.js";const a=t.forwardRef(({className:e,type:o,...r},s)=>i.jsx("input",{type:o,className:n("flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",e),ref:s,...r}));a.displayName="Input";export{a as I};
|
||||
@@ -1 +1 @@
|
||||
import{r as s,j as a}from"./react-vendor-1fwFMt02.js";import{f as t}from"./index-kfMSnNdB.js";const i=s.forwardRef(({className:e,...r},o)=>a.jsx("textarea",{className:t("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",e),ref:o,...r}));i.displayName="Textarea";export{i as T};
|
||||
import{r as s,j as a}from"./react-vendor-1fwFMt02.js";import{f as t}from"./index-BCHo3nLu.js";const i=s.forwardRef(({className:e,...r},o)=>a.jsx("textarea",{className:t("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",e),ref:o,...r}));i.displayName="Textarea";export{i as T};
|
||||
@@ -27,10 +27,10 @@
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
})();
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/index-kfMSnNdB.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BCHo3nLu.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/react-vendor-1fwFMt02.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ui-vendor-Gb6mai95.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BsZMEGDY.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BH_9j3kA.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -105,6 +105,8 @@ export interface ForumLimits {
|
||||
search_keyword_max: number;
|
||||
page_size_default: number;
|
||||
page_size_max: number;
|
||||
feed_max_pages: number;
|
||||
feed_max_items: number;
|
||||
password_min_len: number;
|
||||
avatar_max_mb: number;
|
||||
}
|
||||
@@ -116,6 +118,9 @@ export interface ForumLimitsPublic {
|
||||
comment_max: number;
|
||||
search_keyword_min: number;
|
||||
search_keyword_max: number;
|
||||
page_size_default: number;
|
||||
feed_max_pages: number;
|
||||
feed_max_items: number;
|
||||
password_min_len: number;
|
||||
avatar_max_mb: number;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useRef, useEffect, useLayoutEffect } from 'react';
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import PostListItem from './PostListItem';
|
||||
import type { PostItem } from '../api/types';
|
||||
import type { FeedSort } from './FeedSortBar';
|
||||
@@ -10,6 +11,9 @@ interface Props {
|
||||
sort?: FeedSort;
|
||||
loading: boolean;
|
||||
hasMore: boolean;
|
||||
/** 是否允许滚动触底自动加载(达到上限后为 false) */
|
||||
canAutoLoad: boolean;
|
||||
postTotal: number;
|
||||
onLoadMore: () => void;
|
||||
onSelect: (id: number) => void;
|
||||
/** 返回列表时恢复的滚动位置 */
|
||||
@@ -25,6 +29,8 @@ export default function VirtualPostList({
|
||||
sort = 'latest',
|
||||
loading,
|
||||
hasMore,
|
||||
canAutoLoad,
|
||||
postTotal,
|
||||
onLoadMore,
|
||||
onSelect,
|
||||
restoreScrollTop,
|
||||
@@ -42,6 +48,9 @@ export default function VirtualPostList({
|
||||
overscan: 8,
|
||||
});
|
||||
|
||||
const showHistoryPrompt = hasMore && !canAutoLoad && !loading;
|
||||
const showEnd = !hasMore && posts.length > 0 && !loading;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (resetScrollKey <= 0) return;
|
||||
const el = parentRef.current;
|
||||
@@ -69,13 +78,13 @@ export default function VirtualPostList({
|
||||
if (!el) return;
|
||||
const onScroll = () => {
|
||||
onScrollTopChange?.(el.scrollTop);
|
||||
if (el.scrollTop + el.clientHeight >= el.scrollHeight - 120 && hasMore && !loading) {
|
||||
if (el.scrollTop + el.clientHeight >= el.scrollHeight - 120 && canAutoLoad && hasMore && !loading) {
|
||||
onLoadMore();
|
||||
}
|
||||
};
|
||||
el.addEventListener('scroll', onScroll);
|
||||
return () => el.removeEventListener('scroll', onScroll);
|
||||
}, [hasMore, loading, onLoadMore, onScrollTopChange]);
|
||||
}, [canAutoLoad, hasMore, loading, onLoadMore, onScrollTopChange]);
|
||||
|
||||
return (
|
||||
<div className="post-list-scroll" ref={parentRef}>
|
||||
@@ -99,12 +108,22 @@ export default function VirtualPostList({
|
||||
})}
|
||||
</div>
|
||||
{loading && (
|
||||
<div className="flex justify-center py-4">
|
||||
<div className="feed-list-footer">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
{!loading && !hasMore && posts.length > 0 && (
|
||||
<div style={{ textAlign: 'center', padding: 6, fontSize: 12, color: 'var(--color-text-3)' }}>— 已加载全部 —</div>
|
||||
{showHistoryPrompt && (
|
||||
<div className="feed-list-footer feed-list-footer--history">
|
||||
<p className="feed-list-footer__hint">
|
||||
已显示 {posts.length} / {postTotal} 条
|
||||
</p>
|
||||
<Button type="button" variant="outline" size="sm" onClick={onLoadMore}>
|
||||
加载更多历史
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{showEnd && (
|
||||
<div className="feed-list-footer feed-list-footer--end">— 已加载全部 —</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,9 @@ const DEFAULT_LIMITS: ForumLimitsPublic = {
|
||||
comment_max: 5000,
|
||||
search_keyword_min: 1,
|
||||
search_keyword_max: 50,
|
||||
page_size_default: 30,
|
||||
feed_max_pages: 10,
|
||||
feed_max_items: 300,
|
||||
password_min_len: 6,
|
||||
avatar_max_mb: 2,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useNavigate, useOutletContext, useSearchParams, useLocation } from 'react-router-dom';
|
||||
import { notify } from '@/lib/notify';
|
||||
import { api } from '../api/client';
|
||||
@@ -7,6 +7,7 @@ import type { LayoutCtx } from '../layouts/MainLayout';
|
||||
import VirtualPostList from '../components/VirtualPostList';
|
||||
import FeedHeader from '../components/FeedHeader';
|
||||
import FeedSortBar, { parseFeedSort, buildHomeUrl, type FeedSort } from '../components/FeedSortBar';
|
||||
import { useForumLimits } from '../hooks/useForumLimits';
|
||||
import {
|
||||
getFeedCache,
|
||||
setFeedCache,
|
||||
@@ -21,6 +22,11 @@ export default function HomePage() {
|
||||
const location = useLocation();
|
||||
const [params] = useSearchParams();
|
||||
const ctx = useOutletContext<LayoutCtx>();
|
||||
const { limits } = useForumLimits();
|
||||
const pageSize = limits.page_size_default;
|
||||
const feedMaxPages = limits.feed_max_pages;
|
||||
const feedMaxItems = limits.feed_max_items;
|
||||
|
||||
const boardId = Number(params.get('board')) || ctx?.boardId || 0;
|
||||
const keyword = params.get('keyword') || '';
|
||||
const sort = parseFeedSort(params.get('sort'));
|
||||
@@ -38,6 +44,11 @@ export default function HomePage() {
|
||||
/** 主动刷新时不把旧列表/滚动位置写回 cache */
|
||||
const skipCacheSaveRef = useRef(false);
|
||||
|
||||
const canAutoLoad = useMemo(
|
||||
() => hasMore && page < feedMaxPages && posts.length < feedMaxItems,
|
||||
[hasMore, page, feedMaxPages, posts.length, feedMaxItems],
|
||||
);
|
||||
|
||||
const resetFeedView = useCallback(() => {
|
||||
setRestoreScrollTop(null);
|
||||
scrollTopRef.current = 0;
|
||||
@@ -56,7 +67,7 @@ export default function HomePage() {
|
||||
try {
|
||||
const data = await api.posts({
|
||||
page: p,
|
||||
size: 30,
|
||||
size: pageSize,
|
||||
board_id: boardId || '',
|
||||
keyword,
|
||||
sort: sort === 'latest' ? '' : sort,
|
||||
@@ -72,36 +83,32 @@ export default function HomePage() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [boardId, keyword, sort]);
|
||||
}, [boardId, keyword, sort, pageSize]);
|
||||
|
||||
/** 有缓存时静默拉取已加载页,更新置顶等状态同时保留滚动位置 */
|
||||
const revalidate = useCallback(async (maxPage: number) => {
|
||||
/** 有缓存时静默刷新第 1 页,合并置顶等变化同时保留已加载的历史 */
|
||||
const revalidate = useCallback(async () => {
|
||||
try {
|
||||
const all: PostItem[] = [];
|
||||
let total = 0;
|
||||
let hasMore = true;
|
||||
for (let p = 1; p <= maxPage; p++) {
|
||||
const data = await api.posts({
|
||||
page: p,
|
||||
size: 30,
|
||||
board_id: boardId || '',
|
||||
keyword,
|
||||
sort: sort === 'latest' ? '' : sort,
|
||||
});
|
||||
const batch = Array.isArray(data.posts) ? data.posts : [];
|
||||
all.push(...batch);
|
||||
total = data.total ?? 0;
|
||||
hasMore = !!data.has_more;
|
||||
if (!data.has_more) break;
|
||||
}
|
||||
setPosts(all);
|
||||
setPostTotal(total);
|
||||
setHasMore(hasMore);
|
||||
setPage(maxPage);
|
||||
const data = await api.posts({
|
||||
page: 1,
|
||||
size: pageSize,
|
||||
board_id: boardId || '',
|
||||
keyword,
|
||||
sort: sort === 'latest' ? '' : sort,
|
||||
});
|
||||
const fresh = Array.isArray(data.posts) ? data.posts : [];
|
||||
const freshIds = new Set(fresh.map(p => p.id));
|
||||
setPosts(prev => [...fresh, ...prev.filter(p => !freshIds.has(p.id))]);
|
||||
setPostTotal(data.total ?? 0);
|
||||
setHasMore(!!data.has_more);
|
||||
} catch {
|
||||
// 静默失败,保留缓存数据
|
||||
}
|
||||
}, [boardId, keyword, sort]);
|
||||
}, [boardId, keyword, sort, pageSize]);
|
||||
|
||||
const loadNextPage = useCallback(() => {
|
||||
if (loading || !hasMore) return;
|
||||
load(page + 1);
|
||||
}, [loading, hasMore, page, load]);
|
||||
|
||||
useEffect(() => {
|
||||
const forceRefresh = (location.state as FeedNavState | null)?.refreshFeed;
|
||||
@@ -119,7 +126,7 @@ export default function HomePage() {
|
||||
setRestoreScrollTop(cached.scrollTop);
|
||||
scrollTopRef.current = cached.scrollTop;
|
||||
setLoading(false);
|
||||
revalidate(cached.page);
|
||||
revalidate();
|
||||
return;
|
||||
}
|
||||
setRestoreScrollTop(null);
|
||||
@@ -193,7 +200,9 @@ export default function HomePage() {
|
||||
sort={sort}
|
||||
loading={loading}
|
||||
hasMore={hasMore}
|
||||
onLoadMore={() => !loading && hasMore && load(page + 1)}
|
||||
canAutoLoad={canAutoLoad}
|
||||
postTotal={postTotal}
|
||||
onLoadMore={loadNextPage}
|
||||
onSelect={(id) => nav(`/post/${id}`)}
|
||||
restoreScrollTop={restoreScrollTop}
|
||||
resetScrollKey={listResetKey}
|
||||
|
||||
@@ -68,6 +68,8 @@ const SETTING_SECTIONS: SettingSection[] = [
|
||||
{ key: 'search_keyword_max', label: '关键词最长', unit: '字', min: 1 },
|
||||
{ key: 'page_size_default', label: '默认每页', unit: '条', min: 1 },
|
||||
{ key: 'page_size_max', label: '最大每页', unit: '条', min: 1 },
|
||||
{ key: 'feed_max_pages', label: '首页自动加载页数', unit: '页', hint: '超出后需手动加载', min: 1 },
|
||||
{ key: 'feed_max_items', label: '首页自动加载条数', unit: '条', hint: '与页数取先到上限', min: 1 },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -553,6 +553,31 @@ a:hover { text-decoration: underline; }
|
||||
.post-list-scroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.feed-list-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.feed-list-footer--end {
|
||||
font-size: 12px;
|
||||
color: var(--color-text-3);
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.feed-list-footer--history {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.feed-list-footer__hint {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
|
||||
.page-inner { padding: 20px 24px; max-width: 720px; }
|
||||
.page-inner-wide { padding: 20px 24px; }
|
||||
.page-title { font-size: 20px; font-weight: 600; margin: 0 0 4px; }
|
||||
|
||||
@@ -29,6 +29,9 @@ const (
|
||||
SettingPageSizeDefault = "page_size_default"
|
||||
SettingPageSizeMax = "page_size_max"
|
||||
|
||||
SettingFeedMaxPages = "feed_max_pages"
|
||||
SettingFeedMaxItems = "feed_max_items"
|
||||
|
||||
SettingPasswordMinLen = "password_min_len"
|
||||
SettingAvatarMaxMB = "avatar_max_mb"
|
||||
)
|
||||
@@ -55,6 +58,9 @@ type ForumLimits struct {
|
||||
PageSizeDefault int `json:"page_size_default"`
|
||||
PageSizeMax int `json:"page_size_max"`
|
||||
|
||||
FeedMaxPages int `json:"feed_max_pages"`
|
||||
FeedMaxItems int `json:"feed_max_items"`
|
||||
|
||||
PasswordMinLen int `json:"password_min_len"`
|
||||
AvatarMaxMB int `json:"avatar_max_mb"`
|
||||
}
|
||||
@@ -67,6 +73,9 @@ type ForumLimitsPublic struct {
|
||||
CommentMax int `json:"comment_max"`
|
||||
SearchKeywordMin int `json:"search_keyword_min"`
|
||||
SearchKeywordMax int `json:"search_keyword_max"`
|
||||
PageSizeDefault int `json:"page_size_default"`
|
||||
FeedMaxPages int `json:"feed_max_pages"`
|
||||
FeedMaxItems int `json:"feed_max_items"`
|
||||
PasswordMinLen int `json:"password_min_len"`
|
||||
AvatarMaxMB int `json:"avatar_max_mb"`
|
||||
}
|
||||
@@ -99,6 +108,9 @@ var forumSettingDefs = []settingDef{
|
||||
{SettingPageSizeDefault, "30", 1, 200},
|
||||
{SettingPageSizeMax, "50", 1, 200},
|
||||
|
||||
{SettingFeedMaxPages, "10", 1, 100},
|
||||
{SettingFeedMaxItems, "300", 1, 5000},
|
||||
|
||||
{SettingPasswordMinLen, "6", 4, 128},
|
||||
{SettingAvatarMaxMB, "2", 1, 20},
|
||||
}
|
||||
@@ -176,6 +188,9 @@ func (s *ForumSettingsService) Limits() ForumLimits {
|
||||
PageSizeDefault: s.PageSizeDefault(),
|
||||
PageSizeMax: s.PageSizeMax(),
|
||||
|
||||
FeedMaxPages: s.FeedMaxPages(),
|
||||
FeedMaxItems: s.FeedMaxItems(),
|
||||
|
||||
PasswordMinLen: s.PasswordMinLen(),
|
||||
AvatarMaxMB: s.AvatarMaxMB(),
|
||||
}
|
||||
@@ -190,6 +205,9 @@ func (s *ForumSettingsService) PublicLimits() ForumLimitsPublic {
|
||||
CommentMax: limits.CommentMax,
|
||||
SearchKeywordMin: limits.SearchKeywordMin,
|
||||
SearchKeywordMax: limits.SearchKeywordMax,
|
||||
PageSizeDefault: limits.PageSizeDefault,
|
||||
FeedMaxPages: limits.FeedMaxPages,
|
||||
FeedMaxItems: limits.FeedMaxItems,
|
||||
PasswordMinLen: limits.PasswordMinLen,
|
||||
AvatarMaxMB: limits.AvatarMaxMB,
|
||||
}
|
||||
@@ -211,6 +229,8 @@ func (s *ForumSettingsService) UpdateLimits(in ForumLimits) error {
|
||||
SettingSearchKeywordMax: in.SearchKeywordMax,
|
||||
SettingPageSizeDefault: in.PageSizeDefault,
|
||||
SettingPageSizeMax: in.PageSizeMax,
|
||||
SettingFeedMaxPages: in.FeedMaxPages,
|
||||
SettingFeedMaxItems: in.FeedMaxItems,
|
||||
SettingPasswordMinLen: in.PasswordMinLen,
|
||||
SettingAvatarMaxMB: in.AvatarMaxMB,
|
||||
}
|
||||
@@ -262,6 +282,9 @@ func (s *ForumSettingsService) SearchKeywordMax() int { return s.getInt(SettingS
|
||||
func (s *ForumSettingsService) PageSizeDefault() int { return s.getInt(SettingPageSizeDefault, 30) }
|
||||
func (s *ForumSettingsService) PageSizeMax() int { return s.getInt(SettingPageSizeMax, 50) }
|
||||
|
||||
func (s *ForumSettingsService) FeedMaxPages() int { return s.getInt(SettingFeedMaxPages, 10) }
|
||||
func (s *ForumSettingsService) FeedMaxItems() int { return s.getInt(SettingFeedMaxItems, 300) }
|
||||
|
||||
func (s *ForumSettingsService) PasswordMinLen() int { return s.getInt(SettingPasswordMinLen, 6) }
|
||||
func (s *ForumSettingsService) AvatarMaxMB() int { return s.getInt(SettingAvatarMaxMB, 2) }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user