feat: add favicon settings to site configuration

- Add Favicon field to SiteSetting model with FaviconIsURL() helper
- Implement favicon upload and management in site settings page
- Support both external URL and local file upload for favicon
- Add favicon display in page header with automatic URL detection
- Add i18n translations for favicon settings (EN/ZH)
- Update middleware and helpers to pass favicon data to templates
- Include migration script for existing databases

Users can now customize their site's favicon from /admin/settings/site
by either providing an external URL or uploading a local image file
(recommended formats: .ico, .png, .svg, 16x16 or 32x32 pixels).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 20:09:05 +08:00
co-authored by Claude Fable 5
parent da7a39c1c8
commit b600eac21c
9 changed files with 193 additions and 0 deletions
+10
View File
@@ -8,6 +8,7 @@ import "time"
type SiteSetting struct {
ID uint `gorm:"primarykey" json:"id"`
Logo string `gorm:"size:512" json:"logo"` // local filename (served under /uploads/logos) OR a full URL
Favicon string `gorm:"size:512" json:"favicon"` // local filename (served under /uploads/logos) OR a full URL
LogoTextZh string `gorm:"size:255" json:"logo_text_zh"` // top-left title (zh)
LogoTextEn string `gorm:"size:255" json:"logo_text_en"` // top-left title (en)
HeaderTextZh string `gorm:"size:512" json:"header_text_zh"` // header banner text (zh)
@@ -36,6 +37,15 @@ func (s *SiteSetting) LogoIsURL() bool {
return len(s.Logo) >= 4 && (s.Logo[:4] == "http")
}
// FaviconIsURL reports whether the favicon value is an external URL rather than a
// local filename.
func (s *SiteSetting) FaviconIsURL() bool {
if s == nil || s.Favicon == "" {
return false
}
return len(s.Favicon) >= 4 && (s.Favicon[:4] == "http")
}
// LogoText returns the title for the given language code, falling back to the
// other language when the requested one is empty.
func (s *SiteSetting) LogoText(lang string) string {