2
0

feat(pages): add logo and favicon upload to pages brand settings

Add ability to upload logo and favicon images directly instead of only using URLs. Images stored in repo-avatars storage with hash-based filenames (max 5 MB, JPG/PNG/WebP/GIF). Uploaded images take priority over URL fields. Includes upload/delete endpoints for both logo and favicon, UI with previews, and ResolvedLogoURL/ResolvedFaviconURL helper methods. Updates base_head template to use resolved favicon URL.
This commit is contained in:
2026-03-15 22:45:29 -04:00
parent 79a0c2683e
commit fc86952bf4
8 changed files with 280 additions and 10 deletions

View File

@@ -22,8 +22,8 @@
{{if .LangSwitcherEnabled}}{{range .AvailableLanguages}}
<link rel="alternate" hreflang="{{.}}" href="?lang={{.}}">{{end}}
{{end}}
{{if .Config.Brand.FaviconURL}}
<link rel="icon" href="{{.Config.Brand.FaviconURL}}">
{{if or .Config.Brand.UploadedFavicon .Config.Brand.FaviconURL}}
<link rel="icon" href="{{.Config.Brand.ResolvedFaviconURL}}">
{{else}}
<link rel="icon" href="{{AssetUrlPrefix}}/img/favicon.svg" type="image/svg+xml">
{{end}}

View File

@@ -11,20 +11,74 @@
<input name="brand_name" value="{{.Config.Brand.Name}}" placeholder="{{.Repository.Name}}">
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.brand_name_help"}}</p>
</div>
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.pages.brand_logo"}}</h5>
{{if .Config.Brand.UploadedLogo}}
<div class="field">
<img src="/repo-avatars/{{.Config.Brand.UploadedLogo}}" style="max-width:200px;max-height:100px;border-radius:8px;border:1px solid #ddd;">
<div class="tw-mt-2">
<form method="post" action="{{.Link}}/delete_logo" class="ignore-dirty" style="display:inline;">
{{$.CsrfTokenHtml}}
<button class="ui mini red button" type="submit">
{{svg "octicon-trash" 14}} {{ctx.Locale.Tr "repo.settings.pages.brand_delete_logo"}}
</button>
</form>
</div>
</div>
{{else}}
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.pages.brand_upload_logo"}}</label>
<form method="post" enctype="multipart/form-data" action="{{.Link}}/upload_logo" class="ignore-dirty tw-flex tw-gap-2 tw-items-center">
{{$.CsrfTokenHtml}}
<input type="file" name="brand_logo" accept="image/jpeg,image/png,image/webp,image/gif">
<button class="ui primary button" type="submit">
{{svg "octicon-upload" 16}} {{ctx.Locale.Tr "repo.settings.pages.brand_upload_btn"}}
</button>
</form>
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.brand_upload_help"}}</p>
</div>
<div class="ui horizontal divider">{{ctx.Locale.Tr "repo.settings.pages.brand_or"}}</div>
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.pages.brand_logo_url"}}</label>
<input name="brand_logo_url" value="{{.Config.Brand.LogoURL}}" placeholder="https://example.com/logo.svg">
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.brand_logo_url_help"}}</p>
</div>
{{end}}
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.pages.brand_tagline"}}</label>
<input name="brand_tagline" value="{{.Config.Brand.Tagline}}" placeholder="Your tagline here">
</div>
<h5 class="ui dividing header">{{ctx.Locale.Tr "repo.settings.pages.brand_favicon"}}</h5>
{{if .Config.Brand.UploadedFavicon}}
<div class="field">
<img src="/repo-avatars/{{.Config.Brand.UploadedFavicon}}" style="max-width:64px;max-height:64px;border-radius:4px;border:1px solid #ddd;">
<div class="tw-mt-2">
<form method="post" action="{{.Link}}/delete_favicon" class="ignore-dirty" style="display:inline;">
{{$.CsrfTokenHtml}}
<button class="ui mini red button" type="submit">
{{svg "octicon-trash" 14}} {{ctx.Locale.Tr "repo.settings.pages.brand_delete_favicon"}}
</button>
</form>
</div>
</div>
{{else}}
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.pages.brand_upload_favicon"}}</label>
<form method="post" enctype="multipart/form-data" action="{{.Link}}/upload_favicon" class="ignore-dirty tw-flex tw-gap-2 tw-items-center">
{{$.CsrfTokenHtml}}
<input type="file" name="brand_favicon" accept="image/jpeg,image/png,image/webp,image/gif,image/x-icon,image/svg+xml">
<button class="ui primary button" type="submit">
{{svg "octicon-upload" 16}} {{ctx.Locale.Tr "repo.settings.pages.brand_upload_btn"}}
</button>
</form>
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.brand_favicon_upload_help"}}</p>
</div>
<div class="ui horizontal divider">{{ctx.Locale.Tr "repo.settings.pages.brand_or"}}</div>
<div class="field">
<label>{{ctx.Locale.Tr "repo.settings.pages.brand_favicon_url"}}</label>
<input name="brand_favicon_url" value="{{.Config.Brand.FaviconURL}}" placeholder="https://example.com/favicon.ico">
<p class="help">{{ctx.Locale.Tr "repo.settings.pages.brand_favicon_url_help"}}</p>
</div>
{{end}}
<div class="field">
<button class="ui primary button">{{ctx.Locale.Tr "save"}}</button>
</div>