diff --git a/docs/configuration.md b/docs/configuration.md index 0f076fd..bc87d30 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3,6 +3,7 @@ - [Intro](#intro) - [Preconfigured page](#preconfigured-page) - [Server](#server) +- [Branding](#branding) - [Theme](#theme) - [Themes](#themes) - [Pages & Columns](#pages--columns) @@ -173,6 +174,42 @@ To be able to point to an asset from your assets path, use the `/assets/` path l icon: /assets/gitea-icon.png ``` +## Branding +You can adjust the various parts of the branding through a top level `branding` property. Example: + +```yaml +branding: + custom-footer: | +

Powered by Glance

+ logo-url: /assets/logo.png + favicon-url: /assets/logo.png +``` + +### Properties + +| Name | Type | Required | Default | +| ---- | ---- | -------- | ------- | +| hide-footer | bool | no | false | +| custom-footer | string | no | | +| logo-text | string | no | G | +| logo-url | string | no | | +| favicon-url | string | no | | + +#### `hide-footer` +Hides the footer when set to `true`. + +#### `custom-footer` +Specify custom HTML to use for the footer. + +#### `logo-text` +Specify custom text to use instead of the "G" found in the navigation. + +#### `logo-url` +Specify a URL to a custom image to use instead of the "G" found in the navigation. If both `logo-text` and `logo-url` are set, only `logo-url` will be used. + +#### `favicon-url` +Specify a URL to a custom image to use for the favicon. + ## Theme Theming is done through a top level `theme` property. Values for the colors are in [HSL](https://giggster.com/guide/basics/hue-saturation-lightness/) (hue, saturation, lightness) format. You can use a color picker [like this one](https://hslpicker.com/) to convert colors from other formats to HSL. The values are separated by a space and `%` is not required for any of the numbers. diff --git a/internal/assets/static/main.css b/internal/assets/static/main.css index 1a4692e..af94e64 100644 --- a/internal/assets/static/main.css +++ b/internal/assets/static/main.css @@ -660,6 +660,15 @@ kbd:active { padding-right: var(--widget-content-horizontal-padding); } +.logo:has(img) { + display: flex; + align-items: center; +} + +.logo img { + max-height: 2.7rem; +} + .nav { height: 100%; gap: var(--header-items-gap); diff --git a/internal/assets/templates/document.html b/internal/assets/templates/document.html index d37ac56..4ac65d8 100644 --- a/internal/assets/templates/document.html +++ b/internal/assets/templates/document.html @@ -12,9 +12,8 @@ - - + {{ block "document-head-after" . }}{{ end }} diff --git a/internal/assets/templates/page.html b/internal/assets/templates/page.html index 73c17d0..4d08e61 100644 --- a/internal/assets/templates/page.html +++ b/internal/assets/templates/page.html @@ -32,7 +32,7 @@
- + @@ -63,11 +63,17 @@
+ {{ if not .App.Config.Branding.HideFooter }} + {{ end }}
diff --git a/internal/glance/config.go b/internal/glance/config.go index 718988c..131ef7f 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -8,9 +8,10 @@ import ( ) type Config struct { - Server Server `yaml:"server"` - Theme Theme `yaml:"theme"` - Pages []Page `yaml:"pages"` + Server Server `yaml:"server"` + Theme Theme `yaml:"theme"` + Branding Branding `yaml:"branding"` + Pages []Page `yaml:"pages"` } func NewConfigFromYml(contents io.Reader) (*Config, error) { diff --git a/internal/glance/glance.go b/internal/glance/glance.go index ce7a7a0..a88effb 100644 --- a/internal/glance/glance.go +++ b/internal/glance/glance.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "html/template" "log/slog" "net/http" "path/filepath" @@ -48,6 +49,14 @@ type Server struct { StartedAt time.Time `yaml:"-"` // used in custom css file } +type Branding struct { + HideFooter bool `yaml:"hide-footer"` + CustomFooter template.HTML `yaml:"custom-footer"` + LogoText string `yaml:"logo-text"` + LogoURL string `yaml:"logo-url"` + FaviconURL string `yaml:"favicon-url"` +} + type Column struct { Size string `yaml:"size"` Widgets widget.Widgets `yaml:"widgets"` @@ -102,6 +111,14 @@ func titleToSlug(s string) string { return s } +func (a *Application) TransformUserDefinedAssetPath(path string) string { + if strings.HasPrefix(path, "/assets/") { + return a.Config.Server.BaseURL + path + } + + return path +} + func NewApplication(config *Config) (*Application, error) { if len(config.Pages) == 0 { return nil, fmt.Errorf("no pages configured") @@ -114,6 +131,7 @@ func NewApplication(config *Config) (*Application, error) { widgetByID: make(map[uint64]widget.Widget), } + app.Config.Server.AssetsHash = assets.PublicFSHash app.slugToPage[""] = &config.Pages[0] for p := range config.Pages { @@ -134,13 +152,16 @@ func NewApplication(config *Config) (*Application, error) { config = &app.Config config.Server.BaseURL = strings.TrimRight(config.Server.BaseURL, "/") + config.Theme.CustomCSSFile = app.TransformUserDefinedAssetPath(config.Theme.CustomCSSFile) - if config.Server.BaseURL != "" && - config.Theme.CustomCSSFile != "" && - strings.HasPrefix(config.Theme.CustomCSSFile, "/assets/") { - config.Theme.CustomCSSFile = config.Server.BaseURL + config.Theme.CustomCSSFile + if config.Branding.FaviconURL == "" { + config.Branding.FaviconURL = app.AssetPath("favicon.png") + } else { + config.Branding.FaviconURL = app.TransformUserDefinedAssetPath(config.Branding.FaviconURL) } + config.Branding.LogoURL = app.TransformUserDefinedAssetPath(config.Branding.LogoURL) + return app, nil } @@ -238,8 +259,6 @@ func (a *Application) AssetPath(asset string) string { } func (a *Application) Serve() error { - a.Config.Server.AssetsHash = assets.PublicFSHash - // TODO: add gzip support, static files must have their gzipped contents cached // TODO: add HTTPS support mux := http.NewServeMux()