feat(settings): 站点界面动画总开关与子开关
管理后台可关全站动画,并细调代码折叠、平滑滚动、装饰入场;统一 lib/motion,尊重系统减少动态效果。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,6 +29,27 @@ type updateSettingsRequest struct {
|
||||
PostCooldownHours *int `json:"post_cooldown_hours"`
|
||||
CodeBlockAutoFold *bool `json:"code_block_auto_fold"`
|
||||
CodeBlockFoldLines *int `json:"code_block_fold_lines"`
|
||||
UIAnimations *bool `json:"ui_animations"`
|
||||
AnimCodeFold *bool `json:"anim_code_fold"`
|
||||
AnimSmoothScroll *bool `json:"anim_smooth_scroll"`
|
||||
AnimChrome *bool `json:"anim_chrome"`
|
||||
}
|
||||
|
||||
func settingsPayload(saved service.PublicSiteSettings) gin.H {
|
||||
return 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,
|
||||
"ui_animations": saved.UIAnimations,
|
||||
"anim_code_fold": saved.AnimCodeFold,
|
||||
"anim_smooth_scroll": saved.AnimSmoothScroll,
|
||||
"anim_chrome": saved.AnimChrome,
|
||||
}
|
||||
}
|
||||
|
||||
// PUT /api/admin/settings
|
||||
@@ -40,7 +61,9 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
|
||||
}
|
||||
if req.Accent == nil && req.TrustReviewedPublish == nil && req.SiteName == nil &&
|
||||
req.SiteDescription == nil && req.AllowRegister == nil &&
|
||||
req.PostCooldownHours == nil && req.CodeBlockAutoFold == nil && req.CodeBlockFoldLines == nil {
|
||||
req.PostCooldownHours == nil && req.CodeBlockAutoFold == nil && req.CodeBlockFoldLines == nil &&
|
||||
req.UIAnimations == nil && req.AnimCodeFold == nil && req.AnimSmoothScroll == nil &&
|
||||
req.AnimChrome == nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供任何可更新的设置项"})
|
||||
return
|
||||
}
|
||||
@@ -113,6 +136,30 @@ func (h *Handlers) UpdateSettings(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.UIAnimations != nil {
|
||||
if err := h.Setting.SetUIAnimations(*req.UIAnimations); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.AnimCodeFold != nil {
|
||||
if err := h.Setting.SetAnimCodeFold(*req.AnimCodeFold); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.AnimSmoothScroll != nil {
|
||||
if err := h.Setting.SetAnimSmoothScroll(*req.AnimSmoothScroll); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.AnimChrome != nil {
|
||||
if err := h.Setting.SetAnimChrome(*req.AnimChrome); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "保存站点设置失败"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
saved, err := h.Setting.Public()
|
||||
if err != nil {
|
||||
@@ -120,29 +167,12 @@ 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,
|
||||
}
|
||||
payload := settingsPayload(saved)
|
||||
h.Hub.BroadcastAll(realtime.Envelope{
|
||||
Type: realtime.EventSettingsChanged,
|
||||
Data: payload,
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"ok": true,
|
||||
"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,
|
||||
})
|
||||
out := settingsPayload(saved)
|
||||
out["ok"] = true
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,14 @@ const (
|
||||
SettingKeyCodeBlockAutoFold = "code_block_auto_fold"
|
||||
// SettingKeyCodeBlockFoldLines 超过该行数则折叠;0=无预览;缺行=5
|
||||
SettingKeyCodeBlockFoldLines = "code_block_fold_lines"
|
||||
// SettingKeyUIAnimations 界面动画总开关;缺行视为开启
|
||||
SettingKeyUIAnimations = "ui_animations"
|
||||
// SettingKeyAnimCodeFold 代码折叠高度/跟滚动画;缺行视为开启
|
||||
SettingKeyAnimCodeFold = "anim_code_fold"
|
||||
// SettingKeyAnimSmoothScroll 平滑滚动;缺行视为开启
|
||||
SettingKeyAnimSmoothScroll = "anim_smooth_scroll"
|
||||
// SettingKeyAnimChrome 装饰入场(列表/Toast/点赞等);缺行视为开启
|
||||
SettingKeyAnimChrome = "anim_chrome"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -57,6 +65,10 @@ type PublicSiteSettings struct {
|
||||
PostCooldownHours int `json:"post_cooldown_hours"`
|
||||
CodeBlockAutoFold bool `json:"code_block_auto_fold"`
|
||||
CodeBlockFoldLines int `json:"code_block_fold_lines"`
|
||||
UIAnimations bool `json:"ui_animations"`
|
||||
AnimCodeFold bool `json:"anim_code_fold"`
|
||||
AnimSmoothScroll bool `json:"anim_smooth_scroll"`
|
||||
AnimChrome bool `json:"anim_chrome"`
|
||||
}
|
||||
|
||||
// SettingService 站点级键值设置
|
||||
@@ -119,6 +131,10 @@ func (s *SettingService) Public() (PublicSiteSettings, error) {
|
||||
PostCooldownHours: DefaultCooldownHours,
|
||||
CodeBlockAutoFold: true,
|
||||
CodeBlockFoldLines: DefaultCodeFoldLines,
|
||||
UIAnimations: true,
|
||||
AnimCodeFold: true,
|
||||
AnimSmoothScroll: true,
|
||||
AnimChrome: true,
|
||||
}
|
||||
accent, err := s.AccentColor()
|
||||
if err != nil {
|
||||
@@ -174,6 +190,30 @@ func (s *SettingService) Public() (PublicSiteSettings, error) {
|
||||
return out, err
|
||||
}
|
||||
out.CodeBlockFoldLines = foldLines
|
||||
|
||||
uiAnim, err := s.UIAnimations()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.UIAnimations = uiAnim
|
||||
|
||||
animFold, err := s.AnimCodeFold()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.AnimCodeFold = animFold
|
||||
|
||||
animScroll, err := s.AnimSmoothScroll()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.AnimSmoothScroll = animScroll
|
||||
|
||||
animChrome, err := s.AnimChrome()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.AnimChrome = animChrome
|
||||
return out, nil
|
||||
}
|
||||
|
||||
@@ -318,3 +358,55 @@ func (s *SettingService) SetCodeBlockFoldLines(lines int) error {
|
||||
}
|
||||
return s.putValue(SettingKeyCodeBlockFoldLines, strconv.Itoa(lines))
|
||||
}
|
||||
|
||||
// UIAnimations 界面动画总开关。缺行视为开启;关闭后全站减少动态效果。
|
||||
func (s *SettingService) UIAnimations() (bool, error) {
|
||||
v, found, err := s.getValue(SettingKeyUIAnimations)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return parseBoolDefaultTrue(v, found), nil
|
||||
}
|
||||
|
||||
func (s *SettingService) SetUIAnimations(on bool) error {
|
||||
return s.setBoolDefaultTrue(SettingKeyUIAnimations, on)
|
||||
}
|
||||
|
||||
// AnimCodeFold 代码折叠动画子开关(总开关开启时生效)。
|
||||
func (s *SettingService) AnimCodeFold() (bool, error) {
|
||||
v, found, err := s.getValue(SettingKeyAnimCodeFold)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return parseBoolDefaultTrue(v, found), nil
|
||||
}
|
||||
|
||||
func (s *SettingService) SetAnimCodeFold(on bool) error {
|
||||
return s.setBoolDefaultTrue(SettingKeyAnimCodeFold, on)
|
||||
}
|
||||
|
||||
// AnimSmoothScroll 平滑滚动子开关(总开关开启时生效)。
|
||||
func (s *SettingService) AnimSmoothScroll() (bool, error) {
|
||||
v, found, err := s.getValue(SettingKeyAnimSmoothScroll)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return parseBoolDefaultTrue(v, found), nil
|
||||
}
|
||||
|
||||
func (s *SettingService) SetAnimSmoothScroll(on bool) error {
|
||||
return s.setBoolDefaultTrue(SettingKeyAnimSmoothScroll, on)
|
||||
}
|
||||
|
||||
// AnimChrome 装饰入场子开关(列表/Toast/点赞等;总开关开启时生效)。
|
||||
func (s *SettingService) AnimChrome() (bool, error) {
|
||||
v, found, err := s.getValue(SettingKeyAnimChrome)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return parseBoolDefaultTrue(v, found), nil
|
||||
}
|
||||
|
||||
func (s *SettingService) SetAnimChrome(on bool) error {
|
||||
return s.setBoolDefaultTrue(SettingKeyAnimChrome, on)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user