Add split-column widget

This commit is contained in:
Svilen Markov 2024-10-15 18:05:29 +01:00
parent 13700fe2b2
commit e5bb102ab1
9 changed files with 129 additions and 11 deletions

View file

@ -15,6 +15,7 @@
- [Reddit](#reddit)
- [Search](#search-widget)
- [Group](#group)
- [Split Column](#split-column)
- [Extension](#extension)
- [Weather](#weather)
- [Monitor](#monitor)
@ -890,7 +891,7 @@ url: https://www.amazon.com/s?k={QUERY}
```
### Group
Group multiple widgets into one using tabs. Widgets are defined using a `widgets` property exactly as you would on a page column. The only limitation is that you cannot place a group widget within a group widget.
Group multiple widgets into one using tabs. Widgets are defined using a `widgets` property exactly as you would on a page column. The only limitation is that you cannot place a group widget or a split column widget within a group widget.
Example:
@ -933,6 +934,63 @@ Example:
<<: *shared-properties
```
### Split Column
Splits a full sized column in half, allowing you to place widgets side by side. This is converted to a single column on mobile devices or if not enough width is available. Widgets are defined using a `widgets` property exactly as you would on a page column.
Example of a full page with an effective 4 column layout using two split column widgets inside of two full sized columns:
<details>
<summary>View config</summary>
```yaml
shared:
- &reddit-props
type: reddit
collapse-after: 4
show-thumbnails: true
pages:
- name: Split Column Demo
width: wide
columns:
- size: full
widgets:
- type: split-column
widgets:
- subreddit: gaming
<<: *reddit-props
- subreddit: worldnews
<<: *reddit-props
- subreddit: lifeprotips
<<: *reddit-props
show-thumbnails: false
- subreddit: askreddit
<<: *reddit-props
show-thumbnails: false
- size: full
widgets:
- type: split-column
widgets:
- subreddit: todayilearned
<<: *reddit-props
collapse-after: 2
- subreddit: aww
<<: *reddit-props
- subreddit: science
<<: *reddit-props
- subreddit: showerthoughts
<<: *reddit-props
show-thumbnails: false
```
</details>
<br>
Preview:
![](images/split-column-widget-preview.png)
### Extension
Display a widget provided by an external source (3rd party). If you want to learn more about developing extensions, checkout the [extensions documentation](extensions.md) (WIP).

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

View file

@ -1,4 +1,5 @@
import { setupPopovers } from './popover.js';
import { setupMasonries } from './masonry.js';
import { throttledDebounce, isElementVisible } from './utils.js';
async function fetchPageContent(pageData) {
@ -581,6 +582,7 @@ async function setupPage() {
setupCollapsibleLists();
setupCollapsibleGrids();
setupGroups();
setupMasonries();
setupDynamicRelativeTime();
setupLazyImages();
} finally {

View file

@ -39,6 +39,7 @@ var (
ExtensionTemplate = compileTemplate("extension.html", "widget-base.html")
GroupTemplate = compileTemplate("group.html", "widget-base.html")
DNSStatsTemplate = compileTemplate("dns-stats.html", "widget-base.html")
SplitColumnTemplate = compileTemplate("split-column.html", "widget-base.html")
)
var globalTemplateFunctions = template.FuncMap{

View file

@ -0,0 +1,11 @@
{{ template "widget-base.html" . }}
{{ define "widget-content-classes" }}widget-content-frameless{{ end }}
{{ define "widget-content" }}
<div class="masonry" data-max-columns="2">
{{ range .Widgets }}
{{ .Render }}
{{ end }}
</div>
{{ end }}

View file

@ -6,11 +6,11 @@ import (
"time"
)
type containerWidget struct {
type containerWidgetBase struct {
Widgets Widgets `yaml:"widgets"`
}
func (widget *containerWidget) Update(ctx context.Context) {
func (widget *containerWidgetBase) Update(ctx context.Context) {
var wg sync.WaitGroup
now := time.Now()
@ -31,13 +31,13 @@ func (widget *containerWidget) Update(ctx context.Context) {
wg.Wait()
}
func (widget *containerWidget) SetProviders(providers *Providers) {
func (widget *containerWidgetBase) SetProviders(providers *Providers) {
for i := range widget.Widgets {
widget.Widgets[i].SetProviders(providers)
}
}
func (widget *containerWidget) RequiresUpdate(now *time.Time) bool {
func (widget *containerWidgetBase) RequiresUpdate(now *time.Time) bool {
for i := range widget.Widgets {
if widget.Widgets[i].RequiresUpdate(now) {
return true

View file

@ -10,8 +10,8 @@ import (
)
type Group struct {
widgetBase `yaml:",inline"`
containerWidget `yaml:",inline"`
widgetBase `yaml:",inline"`
containerWidgetBase `yaml:",inline"`
}
func (widget *Group) Initialize() error {
@ -22,7 +22,9 @@ func (widget *Group) Initialize() error {
widget.Widgets[i].SetHideHeader(true)
if widget.Widgets[i].GetType() == "group" {
return errors.New("nested groups are not allowed")
return errors.New("nested groups are not supported")
} else if widget.Widgets[i].GetType() == "split-column" {
return errors.New("split columns inside of groups are not supported")
}
if err := widget.Widgets[i].Initialize(); err != nil {
@ -34,15 +36,15 @@ func (widget *Group) Initialize() error {
}
func (widget *Group) Update(ctx context.Context) {
widget.containerWidget.Update(ctx)
widget.containerWidgetBase.Update(ctx)
}
func (widget *Group) SetProviders(providers *Providers) {
widget.containerWidget.SetProviders(providers)
widget.containerWidgetBase.SetProviders(providers)
}
func (widget *Group) RequiresUpdate(now *time.Time) bool {
return widget.containerWidget.RequiresUpdate(now)
return widget.containerWidgetBase.RequiresUpdate(now)
}
func (widget *Group) Render() template.HTML {

View file

@ -0,0 +1,42 @@
package widget
import (
"context"
"html/template"
"time"
"github.com/glanceapp/glance/internal/assets"
)
type SplitColumn struct {
widgetBase `yaml:",inline"`
containerWidgetBase `yaml:",inline"`
}
func (widget *SplitColumn) Initialize() error {
widget.withError(nil).withTitle("Split Column").SetHideHeader(true)
for i := range widget.Widgets {
if err := widget.Widgets[i].Initialize(); err != nil {
return err
}
}
return nil
}
func (widget *SplitColumn) Update(ctx context.Context) {
widget.containerWidgetBase.Update(ctx)
}
func (widget *SplitColumn) SetProviders(providers *Providers) {
widget.containerWidgetBase.SetProviders(providers)
}
func (widget *SplitColumn) RequiresUpdate(now *time.Time) bool {
return widget.containerWidgetBase.RequiresUpdate(now)
}
func (widget *SplitColumn) Render() template.HTML {
return widget.render(widget, assets.SplitColumnTemplate)
}

View file

@ -67,6 +67,8 @@ func New(widgetType string) (Widget, error) {
widget = &Group{}
case "dns-stats":
widget = &DNSStats{}
case "split-column":
widget = &SplitColumn{}
default:
return nil, fmt.Errorf("unknown widget type: %s", widgetType)
}