feat(settings): 后台可配置 Markdown 代码块自动折叠与阈值行数

支持开关与 0–100 行阈值(0 为无预览),经站点设置与 WS 热更新;短代码在视口内收起时不再回滚浏览位置。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 06:43:37 +08:00
parent b6e9966ba8
commit 809d8f1df7
8 changed files with 349 additions and 23 deletions

View File

@@ -27,6 +27,8 @@ type updateSettingsRequest struct {
SiteDescription *string `json:"site_description"`
AllowRegister *bool `json:"allow_register"`
PostCooldownHours *int `json:"post_cooldown_hours"`
CodeBlockAutoFold *bool `json:"code_block_auto_fold"`
CodeBlockFoldLines *int `json:"code_block_fold_lines"`
}
// PUT /api/admin/settings
@@ -37,7 +39,8 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
return
}
if req.Accent == nil && req.TrustReviewedPublish == nil && req.SiteName == nil &&
req.SiteDescription == nil && req.AllowRegister == nil && req.PostCooldownHours == nil {
req.SiteDescription == nil && req.AllowRegister == nil &&
req.PostCooldownHours == nil && req.CodeBlockAutoFold == nil && req.CodeBlockFoldLines == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供任何可更新的设置项"})
return
}
@@ -94,6 +97,22 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
return
}
}
if req.CodeBlockAutoFold != nil {
if err := h.Setting.SetCodeBlockAutoFold(*req.CodeBlockAutoFold); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
if req.CodeBlockFoldLines != nil {
if err := h.Setting.SetCodeBlockFoldLines(*req.CodeBlockFoldLines); err != nil {
if errors.Is(err, service.ErrInvalidSiteSetting) {
c.JSON(http.StatusBadRequest, gin.H{"error": "折叠行数须为 0–100"})
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
return
}
}
saved, err := h.Setting.Public()
if err != nil {
@@ -101,16 +120,19 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
return
}
payload := gin.H{
"accent": saved.Accent,
"trust_reviewed_publish": saved.TrustReviewedPublish,
"site_name": saved.SiteName,
"site_description": saved.SiteDescription,
"allow_register": saved.AllowRegister,
"post_cooldown_hours": saved.PostCooldownHours,
"code_block_auto_fold": saved.CodeBlockAutoFold,
"code_block_fold_lines": saved.CodeBlockFoldLines,
}
h.Hub.BroadcastAll(realtime.Envelope{
Type: realtime.EventSettingsChanged,
Data: gin.H{
"accent": saved.Accent,
"trust_reviewed_publish": saved.TrustReviewedPublish,
"site_name": saved.SiteName,
"site_description": saved.SiteDescription,
"allow_register": saved.AllowRegister,
"post_cooldown_hours": saved.PostCooldownHours,
},
Data: payload,
})
c.JSON(http.StatusOK, gin.H{
"ok": true,
@@ -120,5 +142,7 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
"site_description": saved.SiteDescription,
"allow_register": saved.AllowRegister,
"post_cooldown_hours": saved.PostCooldownHours,
"code_block_auto_fold": saved.CodeBlockAutoFold,
"code_block_fold_lines": saved.CodeBlockFoldLines,
})
}