diff --git a/docs/configuration.md b/docs/configuration.md index f0a616e..ce542da 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -520,6 +520,7 @@ pages: | center-vertically | boolean | no | false | | hide-desktop-navigation | boolean | no | false | | show-mobile-header | boolean | no | false | +| head-widgets | array | no | | | columns | array | yes | | #### `name` @@ -557,6 +558,43 @@ Preview:  +#### `head-widgets` + +Head widgets will be shown at the top of the page, above the columns, and take up the combined width of all columns. You can specify any widget, though some will look better than others, such as the markets, RSS feed with `horizontal-cards` style, and videos widgets. Example: + + + +```yaml +pages: + - name: Home + head-widgets: + - type: markets + hide-header: true + markets: + - symbol: SPY + name: S&P 500 + - symbol: BTC-USD + name: Bitcoin + - symbol: NVDA + name: NVIDIA + - symbol: AAPL + name: Apple + - symbol: MSFT + name: Microsoft + + columns: + - size: small + widgets: + - type: calendar + - size: full + widgets: + - type: hacker-news + - size: small + widgets: + - type: weather + location: London, United Kingdom +``` + ### Columns Columns are defined for each page using a `columns` property. There are two types of columns - `full` and `small`, which refers to their width. A small column takes up a fixed amount of width (300px) and a full column takes up the all of the remaining width. You can have up to 3 columns per page and you must have either 1 or 2 full columns. Example: diff --git a/docs/images/head-widgets-preview.png b/docs/images/head-widgets-preview.png new file mode 100644 index 0000000..3de52fc Binary files /dev/null and b/docs/images/head-widgets-preview.png differ diff --git a/internal/glance/config.go b/internal/glance/config.go index 4cd7ba7..84714d0 100644 --- a/internal/glance/config.go +++ b/internal/glance/config.go @@ -73,13 +73,14 @@ type user struct { } type page struct { - Title string `yaml:"name"` - Slug string `yaml:"slug"` - Width string `yaml:"width"` - DesktopNavigationWidth string `yaml:"desktop-navigation-width"` - ShowMobileHeader bool `yaml:"show-mobile-header"` - HideDesktopNavigation bool `yaml:"hide-desktop-navigation"` - CenterVertically bool `yaml:"center-vertically"` + Title string `yaml:"name"` + Slug string `yaml:"slug"` + Width string `yaml:"width"` + DesktopNavigationWidth string `yaml:"desktop-navigation-width"` + ShowMobileHeader bool `yaml:"show-mobile-header"` + HideDesktopNavigation bool `yaml:"hide-desktop-navigation"` + CenterVertically bool `yaml:"center-vertically"` + HeadWidgets widgets `yaml:"head-widgets"` Columns []struct { Size string `yaml:"size"` Widgets widgets `yaml:"widgets"` @@ -107,6 +108,12 @@ func newConfigFromYAML(contents []byte) (*config, error) { } for p := range config.Pages { + for w := range config.Pages[p].HeadWidgets { + if err := config.Pages[p].HeadWidgets[w].initialize(); err != nil { + return nil, formatWidgetInitError(err, config.Pages[p].HeadWidgets[w]) + } + } + for c := range config.Pages[p].Columns { for w := range config.Pages[p].Columns[c].Widgets { if err := config.Pages[p].Columns[c].Widgets[w].initialize(); err != nil { diff --git a/internal/glance/glance.go b/internal/glance/glance.go index e6e7838..8db87e1 100644 --- a/internal/glance/glance.go +++ b/internal/glance/glance.go @@ -230,6 +230,20 @@ func (p *page) updateOutdatedWidgets() { var wg sync.WaitGroup context := context.Background() + for w := range p.HeadWidgets { + widget := p.HeadWidgets[w] + + if !widget.requiresUpdate(&now) { + continue + } + + wg.Add(1) + go func() { + defer wg.Done() + widget.update(context) + }() + } + for c := range p.Columns { for w := range p.Columns[c].Widgets { widget := p.Columns[c].Widgets[w] diff --git a/internal/glance/static/css/site.css b/internal/glance/static/css/site.css index d2fdfcd..fb06eb9 100644 --- a/internal/glance/static/css/site.css +++ b/internal/glance/static/css/site.css @@ -13,6 +13,7 @@ .page.content-ready > .page-content { display: block; + animation: pageContentEntrance .3s cubic-bezier(0.25, 1, 0.5, 1) backwards; } .page-column-small .size-title-dynamic { @@ -127,10 +128,9 @@ body { .page-columns { display: flex; gap: var(--widget-gap); - animation: pageColumnsEntrance .3s cubic-bezier(0.25, 1, 0.5, 1) backwards; } -@keyframes pageColumnsEntrance { +@keyframes pageContentEntrance { from { opacity: 0; transform: translateY(10px); diff --git a/internal/glance/static/css/widgets.css b/internal/glance/static/css/widgets.css index 9c9e8ee..a8d3be3 100644 --- a/internal/glance/static/css/widgets.css +++ b/internal/glance/static/css/widgets.css @@ -44,6 +44,10 @@ opacity: 0.6; } +.head-widgets { + margin-bottom: var(--widget-gap); +} + .widget-content { container-type: inline-size; container-name: widget; diff --git a/internal/glance/templates/page-content.html b/internal/glance/templates/page-content.html index c59d6e1..4cf67a7 100644 --- a/internal/glance/templates/page-content.html +++ b/internal/glance/templates/page-content.html @@ -2,12 +2,20 @@