mirror of
https://github.com/glanceapp/glance.git
synced 2025-06-22 02:41:23 +02:00
Merge pull request #75 from realdavidops/main
Allow some branding customization.
This commit is contained in:
commit
038794fa1c
@ -3,6 +3,7 @@
|
|||||||
- [Intro](#intro)
|
- [Intro](#intro)
|
||||||
- [Preconfigured page](#preconfigured-page)
|
- [Preconfigured page](#preconfigured-page)
|
||||||
- [Server](#server)
|
- [Server](#server)
|
||||||
|
- [Branding](#branding)
|
||||||
- [Theme](#theme)
|
- [Theme](#theme)
|
||||||
- [Themes](#themes)
|
- [Themes](#themes)
|
||||||
- [Pages & Columns](#pages--columns)
|
- [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
|
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: |
|
||||||
|
<p>Powered by <a href="https://github.com/glanceapp/glance">Glance</a></p>
|
||||||
|
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
|
## 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.
|
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.
|
||||||
|
|
||||||
|
@ -660,6 +660,15 @@ kbd:active {
|
|||||||
padding-right: var(--widget-content-horizontal-padding);
|
padding-right: var(--widget-content-horizontal-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo:has(img) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo img {
|
||||||
|
max-height: 2.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
gap: var(--header-items-gap);
|
gap: var(--header-items-gap);
|
||||||
|
@ -12,9 +12,8 @@
|
|||||||
<meta name="apple-mobile-web-app-title" content="Glance">
|
<meta name="apple-mobile-web-app-title" content="Glance">
|
||||||
<meta name="theme-color" content="{{ if ne nil .App.Config.Theme.BackgroundColor }}{{ .App.Config.Theme.BackgroundColor }}{{ else }}hsl(240, 8%, 9%){{ end }}">
|
<meta name="theme-color" content="{{ if ne nil .App.Config.Theme.BackgroundColor }}{{ .App.Config.Theme.BackgroundColor }}{{ else }}hsl(240, 8%, 9%){{ end }}">
|
||||||
<link rel="apple-touch-icon" sizes="512x512" href="{{ .App.AssetPath "app-icon.png" }}">
|
<link rel="apple-touch-icon" sizes="512x512" href="{{ .App.AssetPath "app-icon.png" }}">
|
||||||
<link rel="icon" type="image/png" sizes="50x50" href="{{ .App.AssetPath "favicon.png" }}">
|
|
||||||
<link rel="manifest" href="{{ .App.AssetPath "manifest.json" }}">
|
<link rel="manifest" href="{{ .App.AssetPath "manifest.json" }}">
|
||||||
<link rel="icon" type="image/png" href="{{ .App.AssetPath "favicon.png" }}" />
|
<link rel="icon" type="image/png" href="{{ .App.Config.Branding.FaviconURL }}" />
|
||||||
<link rel="stylesheet" href="{{ .App.AssetPath "main.css" }}">
|
<link rel="stylesheet" href="{{ .App.AssetPath "main.css" }}">
|
||||||
<script type="module" src="{{ .App.AssetPath "main.js" }}"></script>
|
<script type="module" src="{{ .App.AssetPath "main.js" }}"></script>
|
||||||
{{ block "document-head-after" . }}{{ end }}
|
{{ block "document-head-after" . }}{{ end }}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<div class="header-container content-bounds">
|
<div class="header-container content-bounds">
|
||||||
<div class="header flex padding-inline-widget widget-content-frame">
|
<div class="header flex padding-inline-widget widget-content-frame">
|
||||||
<!-- TODO: Replace G with actual logo, first need an actual logo -->
|
<!-- TODO: Replace G with actual logo, first need an actual logo -->
|
||||||
<div class="logo">G</div>
|
<div class="logo">{{ if ne "" .App.Config.Branding.LogoURL }}<img src="{{ .App.Config.Branding.LogoURL }}" alt="">{{ else if ne "" .App.Config.Branding.LogoText }}{{ .App.Config.Branding.LogoText }}{{ else }}G{{ end }}</div>
|
||||||
<div class="nav flex grow">
|
<div class="nav flex grow">
|
||||||
{{ template "navigation-links" . }}
|
{{ template "navigation-links" . }}
|
||||||
</div>
|
</div>
|
||||||
@ -63,11 +63,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ if not .App.Config.Branding.HideFooter }}
|
||||||
<div class="footer flex items-center flex-column">
|
<div class="footer flex items-center flex-column">
|
||||||
|
{{ if eq "" .App.Config.Branding.CustomFooter }}
|
||||||
<div>
|
<div>
|
||||||
<a class="size-h3" href="https://github.com/glanceapp/glance" target="_blank" rel="noreferrer">Glance</a> {{ if ne "dev" .App.Version }}<a class="visited-indicator" title="Release notes" href="https://github.com/glanceapp/glance/releases/tag/{{ .App.Version }}" target="_blank" rel="noreferrer">{{ .App.Version }}</a>{{ else }}({{ .App.Version }}){{ end }}
|
<a class="size-h3" href="https://github.com/glanceapp/glance" target="_blank" rel="noreferrer">Glance</a> {{ if ne "dev" .App.Version }}<a class="visited-indicator" title="Release notes" href="https://github.com/glanceapp/glance/releases/tag/{{ .App.Version }}" target="_blank" rel="noreferrer">{{ .App.Version }}</a>{{ else }}({{ .App.Version }}){{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
{{ .App.Config.Branding.CustomFooter }}
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
<div class="mobile-navigation-offset"></div>
|
<div class="mobile-navigation-offset"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Server Server `yaml:"server"`
|
Server Server `yaml:"server"`
|
||||||
Theme Theme `yaml:"theme"`
|
Theme Theme `yaml:"theme"`
|
||||||
|
Branding Branding `yaml:"branding"`
|
||||||
Pages []Page `yaml:"pages"`
|
Pages []Page `yaml:"pages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -48,6 +49,14 @@ type Server struct {
|
|||||||
StartedAt time.Time `yaml:"-"` // used in custom css file
|
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 {
|
type Column struct {
|
||||||
Size string `yaml:"size"`
|
Size string `yaml:"size"`
|
||||||
Widgets widget.Widgets `yaml:"widgets"`
|
Widgets widget.Widgets `yaml:"widgets"`
|
||||||
@ -102,6 +111,14 @@ func titleToSlug(s string) string {
|
|||||||
return s
|
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) {
|
func NewApplication(config *Config) (*Application, error) {
|
||||||
if len(config.Pages) == 0 {
|
if len(config.Pages) == 0 {
|
||||||
return nil, fmt.Errorf("no pages configured")
|
return nil, fmt.Errorf("no pages configured")
|
||||||
@ -114,6 +131,7 @@ func NewApplication(config *Config) (*Application, error) {
|
|||||||
widgetByID: make(map[uint64]widget.Widget),
|
widgetByID: make(map[uint64]widget.Widget),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.Config.Server.AssetsHash = assets.PublicFSHash
|
||||||
app.slugToPage[""] = &config.Pages[0]
|
app.slugToPage[""] = &config.Pages[0]
|
||||||
|
|
||||||
for p := range config.Pages {
|
for p := range config.Pages {
|
||||||
@ -134,13 +152,16 @@ func NewApplication(config *Config) (*Application, error) {
|
|||||||
config = &app.Config
|
config = &app.Config
|
||||||
|
|
||||||
config.Server.BaseURL = strings.TrimRight(config.Server.BaseURL, "/")
|
config.Server.BaseURL = strings.TrimRight(config.Server.BaseURL, "/")
|
||||||
|
config.Theme.CustomCSSFile = app.TransformUserDefinedAssetPath(config.Theme.CustomCSSFile)
|
||||||
|
|
||||||
if config.Server.BaseURL != "" &&
|
if config.Branding.FaviconURL == "" {
|
||||||
config.Theme.CustomCSSFile != "" &&
|
config.Branding.FaviconURL = app.AssetPath("favicon.png")
|
||||||
strings.HasPrefix(config.Theme.CustomCSSFile, "/assets/") {
|
} else {
|
||||||
config.Theme.CustomCSSFile = config.Server.BaseURL + config.Theme.CustomCSSFile
|
config.Branding.FaviconURL = app.TransformUserDefinedAssetPath(config.Branding.FaviconURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.Branding.LogoURL = app.TransformUserDefinedAssetPath(config.Branding.LogoURL)
|
||||||
|
|
||||||
return app, nil
|
return app, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,8 +259,6 @@ func (a *Application) AssetPath(asset string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Application) Serve() error {
|
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 gzip support, static files must have their gzipped contents cached
|
||||||
// TODO: add HTTPS support
|
// TODO: add HTTPS support
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user