Skip to content

Commit ed2e69d

Browse files
committed
fix
1 parent e865de1 commit ed2e69d

File tree

17 files changed

+116
-58
lines changed

17 files changed

+116
-58
lines changed

docs/content/administration/config-cheat-sheet.en-us.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,9 @@ The following configuration set `Content-Type: application/vnd.android.package-a
214214
- `SITEMAP_PAGING_NUM`: **20**: Number of items that are displayed in a single subsitemap.
215215
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph.
216216
- `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment.
217-
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: Set the default theme for the Gitea installation.
217+
- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by "{CustomPath}/public/assets/css/theme-*.css".
218218
- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page.
219-
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
220-
regardless of the value of `DEFAULT_THEME`.
219+
- `THEMES`: **_empty_**: All available themes by "{CustomPath}/public/assets/css/theme-*.css". Allow users select personalized themes.
221220
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
222221
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
223222
- `REACTIONS`: All available reactions users can choose on issues/prs and comments

docs/content/administration/config-cheat-sheet.zh-cn.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,9 @@ menu:
212212
- `SITEMAP_PAGING_NUM`: **20**: 在单个子SiteMap中显示的项数。
213213
- `GRAPH_MAX_COMMIT_NUM`: **100**: 提交图中显示的最大commit数量。
214214
- `CODE_COMMENT_LINES`: **4**: 在代码评论中能够显示的最大代码行数。
215-
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: 在Gitea安装时候设置的默认主题
215+
- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 "{CustomPath}/public/assets/css/theme-*.css" 提供
216216
- `SHOW_USER_EMAIL`: **true**: 用户的电子邮件是否应该显示在`Explore Users`页面中。
217-
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: 所有可用的主题。允许用户选择个性化的主题,
218-
而不受DEFAULT_THEME 值的影响。
217+
- `THEMES`: **_empty_**: 所有可用的主题(由 "{CustomPath}/public/assets/css/theme-*.css" 提供)。允许用户选择个性化的主题,
219218
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: 能够显示文件的最大大小(默认为8MiB)。
220219
- `REACTIONS`: 用户可以在问题(Issue)、Pull Request(PR)以及评论中选择的所有可选的反应。
221220
这些值可以是表情符号别名(例如::smile:)或Unicode表情符号。

docs/content/administration/customizing-gitea.en-us.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ To make a custom theme available to all users:
381381
382382
1. Add a CSS file to `$GITEA_CUSTOM/public/assets/css/theme-<theme-name>.css`.
383383
The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
384-
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`
384+
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`, or leave `THEMES` empty to allow all themes.
385385
386386
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).
387387

docs/content/help/faq.en-us.md

-11
Original file line numberDiff line numberDiff line change
@@ -178,17 +178,6 @@ At some point, a customer or third party needs access to a specific repo and onl
178178

179179
Use [Fail2Ban](administration/fail2ban-setup.md) to monitor and stop automated login attempts or other malicious behavior based on log patterns
180180

181-
## How to add/use custom themes
182-
183-
Gitea supports three official themes right now, `gitea-light`, `gitea-dark`, and `gitea-auto` (automatically switches between the previous two depending on operating system settings).
184-
To add your own theme, currently the only way is to provide a complete theme (not just color overrides)
185-
186-
As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011))
187-
188-
Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/assets/css`
189-
190-
Allow users to use it by adding `arc-blue` to the list of `THEMES` in your `app.ini`
191-
192181
## SSHD vs built-in SSH
193182

194183
SSHD is the built-in SSH server on most Unix systems.

docs/content/help/faq.zh-cn.md

-11
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,6 @@ Gitea不提供内置的Pages服务器。您需要一个专用的域名来提供
182182

183183
使用 [Fail2Ban](administration/fail2ban-setup.md) 监视并阻止基于日志模式的自动登录尝试或其他恶意行为。
184184

185-
## 如何添加/使用自定义主题
186-
187-
Gitea 目前支持三个官方主题,分别是 `gitea-light``gitea-dark``gitea-auto`(根据操作系统设置自动切换前两个主题)。
188-
要添加自己的主题,目前唯一的方法是提供一个完整的主题(不仅仅是颜色覆盖)。
189-
190-
假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到)
191-
192-
`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/assets/css`文件夹中
193-
194-
通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题
195-
196185
## SSHD vs 内建SSH
197186

198187
SSHD是大多数Unix系统上内建的SSH服务器。

modules/setting/ui.go

-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ var UI = struct {
8282
ReactionMaxUserNum: 10,
8383
MaxDisplayFileSize: 8388608,
8484
DefaultTheme: `gitea-auto`,
85-
Themes: []string{`gitea-auto`, `gitea-light`, `gitea-dark`},
8685
Reactions: []string{`+1`, `-1`, `laugh`, `hooray`, `confused`, `heart`, `rocket`, `eyes`},
8786
CustomEmojis: []string{`git`, `gitea`, `codeberg`, `gitlab`, `github`, `gogs`},
8887
CustomEmojisMap: map[string]string{"git": ":git:", "gitea": ":gitea:", "codeberg": ":codeberg:", "gitlab": ":gitlab:", "github": ":github:", "gogs": ":gogs:"},

modules/templates/helper.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"code.gitea.io/gitea/modules/timeutil"
2323
"code.gitea.io/gitea/modules/util"
2424
"code.gitea.io/gitea/services/gitdiff"
25+
"code.gitea.io/gitea/services/webtheme"
2526
)
2627

2728
// NewFuncMap returns functions for injecting to templates
@@ -137,12 +138,7 @@ func NewFuncMap() template.FuncMap {
137138
"DisableImportLocal": func() bool {
138139
return !setting.ImportLocalPaths
139140
},
140-
"ThemeName": func(user *user_model.User) string {
141-
if user == nil || user.Theme == "" {
142-
return setting.UI.DefaultTheme
143-
}
144-
return user.Theme
145-
},
141+
"UserThemeName": UserThemeName,
146142
"NotificationSettings": func() map[string]any {
147143
return map[string]any{
148144
"MinTimeout": int(setting.UI.Notification.MinTimeout / time.Millisecond),
@@ -261,3 +257,10 @@ func Eval(tokens ...any) (any, error) {
261257
n, err := eval.Expr(tokens...)
262258
return n.Value, err
263259
}
260+
261+
func UserThemeName(user *user_model.User) string {
262+
if user == nil || user.Theme == "" {
263+
return setting.UI.DefaultTheme
264+
}
265+
return util.Iif(webtheme.IsThemeAvailable(user.Theme), user.Theme, setting.UI.DefaultTheme)
266+
}

routers/web/user/setting/profile.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"code.gitea.io/gitea/services/context"
3232
"code.gitea.io/gitea/services/forms"
3333
user_service "code.gitea.io/gitea/services/user"
34+
"code.gitea.io/gitea/services/webtheme"
3435
)
3536

3637
const (
@@ -318,6 +319,7 @@ func Repos(ctx *context.Context) {
318319
func Appearance(ctx *context.Context) {
319320
ctx.Data["Title"] = ctx.Tr("settings.appearance")
320321
ctx.Data["PageIsSettingsAppearance"] = true
322+
ctx.Data["AllThemes"] = webtheme.GetAvailableThemes()
321323

322324
var hiddenCommentTypes *big.Int
323325
val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes)
@@ -341,11 +343,12 @@ func UpdateUIThemePost(ctx *context.Context) {
341343
ctx.Data["PageIsSettingsAppearance"] = true
342344

343345
if ctx.HasError() {
346+
ctx.Flash.Error(ctx.GetErrMsg())
344347
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
345348
return
346349
}
347350

348-
if !form.IsThemeExists() {
351+
if !webtheme.IsThemeAvailable(form.Theme) {
349352
ctx.Flash.Error(ctx.Tr("settings.theme_update_error"))
350353
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
351354
return

routers/web/web.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ func registerRoutes(m *web.Route) {
652652
m.Get("", user_setting.BlockedUsers)
653653
m.Post("", web.Bind(forms.BlockUserForm{}), user_setting.BlockedUsersPost)
654654
})
655-
}, reqSignIn, ctxDataSet("PageIsUserSettings", true, "AllThemes", setting.UI.Themes, "EnablePackages", setting.Packages.Enabled))
655+
}, reqSignIn, ctxDataSet("PageIsUserSettings", true, "EnablePackages", setting.Packages.Enabled))
656656

657657
m.Group("/user", func() {
658658
m.Get("/activate", auth.Activate)

services/context/context.go

+1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ func Contexter() func(next http.Handler) http.Handler {
230230

231231
// HasError returns true if error occurs in form validation.
232232
// Attention: this function changes ctx.Data and ctx.Flash
233+
// If HasError is called, then before Redirect, the error message should be stored by ctx.Flash.Error(ctx.GetErrMsg()) again.
233234
func (ctx *Context) HasError() bool {
234235
hasErr, ok := ctx.Data["HasError"]
235236
if !ok {

services/forms/user_form.go

+1-16
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111

1212
auth_model "code.gitea.io/gitea/models/auth"
1313
user_model "code.gitea.io/gitea/models/user"
14-
"code.gitea.io/gitea/modules/setting"
1514
"code.gitea.io/gitea/modules/structs"
1615
"code.gitea.io/gitea/modules/web/middleware"
1716
"code.gitea.io/gitea/services/context"
@@ -273,7 +272,7 @@ func (f *AddEmailForm) Validate(req *http.Request, errs binding.Errors) binding.
273272

274273
// UpdateThemeForm form for updating a users' theme
275274
type UpdateThemeForm struct {
276-
Theme string `binding:"Required;MaxSize(30)"`
275+
Theme string `binding:"Required;MaxSize(255)"`
277276
}
278277

279278
// Validate validates the field
@@ -282,20 +281,6 @@ func (f *UpdateThemeForm) Validate(req *http.Request, errs binding.Errors) bindi
282281
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
283282
}
284283

285-
// IsThemeExists checks if the theme is a theme available in the config.
286-
func (f UpdateThemeForm) IsThemeExists() bool {
287-
var exists bool
288-
289-
for _, v := range setting.UI.Themes {
290-
if strings.EqualFold(v, f.Theme) {
291-
exists = true
292-
break
293-
}
294-
}
295-
296-
return exists
297-
}
298-
299284
// ChangePasswordForm form for changing password
300285
type ChangePasswordForm struct {
301286
OldPassword string `form:"old_password" binding:"MaxSize(255)"`

services/webtheme/webtheme.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package webtheme
5+
6+
import (
7+
"strings"
8+
"sync"
9+
10+
"code.gitea.io/gitea/modules/container"
11+
"code.gitea.io/gitea/modules/log"
12+
"code.gitea.io/gitea/modules/public"
13+
"code.gitea.io/gitea/modules/setting"
14+
)
15+
16+
var (
17+
availableThemes []string
18+
availableThemesSet container.Set[string]
19+
themeOnce sync.Once
20+
)
21+
22+
func initThemes() {
23+
availableThemes = nil
24+
defer func() {
25+
availableThemesSet = container.SetOf(availableThemes...)
26+
}()
27+
cssFiles, err := public.AssetFS().ListFiles("/assets/css")
28+
if err != nil {
29+
log.Error("Failed to list themes: %v", err)
30+
availableThemes = []string{setting.UI.DefaultTheme}
31+
return
32+
}
33+
var foundThemes []string
34+
for _, name := range cssFiles {
35+
name, ok := strings.CutPrefix(name, "theme-")
36+
if !ok {
37+
continue
38+
}
39+
name, ok = strings.CutSuffix(name, ".css")
40+
if !ok {
41+
continue
42+
}
43+
foundThemes = append(foundThemes, name)
44+
}
45+
if len(setting.UI.Themes) > 0 {
46+
allowedThemes := container.SetOf(setting.UI.Themes...)
47+
for _, theme := range foundThemes {
48+
if allowedThemes.Contains(theme) {
49+
availableThemes = append(availableThemes, theme)
50+
}
51+
}
52+
} else {
53+
availableThemes = foundThemes
54+
}
55+
if len(availableThemes) == 0 {
56+
log.Error("No theme candidate, but gitea requires there should be at least one usable theme")
57+
availableThemes = []string{setting.UI.DefaultTheme}
58+
}
59+
}
60+
61+
func GetAvailableThemes() []string {
62+
themeOnce.Do(initThemes)
63+
return availableThemes
64+
}
65+
66+
func IsThemeAvailable(name string) bool {
67+
themeOnce.Do(initThemes)
68+
return availableThemesSet.Contains(name)
69+
}

templates/base/head.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="{{ctx.Locale.Lang}}" data-theme="{{ThemeName .SignedUser}}">
2+
<html lang="{{ctx.Locale.Lang}}" data-theme="{{UserThemeName .SignedUser}}">
33
<head>
44
<meta name="viewport" content="width=device-width, initial-scale=1">
55
<title>{{if .Title}}{{.Title}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>

templates/base/head_style.tmpl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/index.css?v={{AssetVersion}}">
2-
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{ThemeName .SignedUser | PathEscape}}.css?v={{AssetVersion}}">
2+
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/theme-{{UserThemeName .SignedUser | PathEscape}}.css?v={{AssetVersion}}">

templates/status/500.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics.
2-
* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName
2+
* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, UserThemeName
33
* ctx.Locale
44
* .Flash
55
* .ErrorMsg
66
* .SignedUser (optional)
77
*/}}
88
<!DOCTYPE html>
9-
<html lang="{{ctx.Locale.Lang}}" data-theme="{{ThemeName .SignedUser}}">
9+
<html lang="{{ctx.Locale.Lang}}" data-theme="{{UserThemeName .SignedUser}}">
1010
<head>
1111
<meta name="viewport" content="width=device-width, initial-scale=1">
1212
<title>Internal Server Error - {{AppName}}</title>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@import "./theme-gitea-dark.css";
2+
3+
/* red/green colorblind-friendly colors */
4+
/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */
5+
:root {
6+
--color-diff-added-word-bg: #388bfd66;
7+
--color-diff-added-row-bg: #388bfd26;
8+
9+
--color-diff-removed-word-bg: #db6d2866;
10+
--color-diff-removed-row-bg: #db6d2826;
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@import "./theme-gitea-light.css";
2+
3+
/* red/green colorblind-friendly colors */
4+
/* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */
5+
:root {
6+
--color-diff-added-word-bg: #54aeff66;
7+
--color-diff-added-row-bg: #ddf4ff80;
8+
9+
--color-diff-removed-word-bg: #ffb77c80;
10+
--color-diff-removed-row-bg: #fff1e580;
11+
}

0 commit comments

Comments
 (0)