diff --git a/internal/glance/static/css/utils.css b/internal/glance/static/css/utils.css index 1a7aff6..f111173 100644 --- a/internal/glance/static/css/utils.css +++ b/internal/glance/static/css/utils.css @@ -512,6 +512,8 @@ details[open] .summary::after { .color-positive { color: var(--color-positive); } .color-primary { color: var(--color-primary); } +.bg-highlight { background-color: var(--color-widget-background-highlight); } + .color-primary-if-not-visited:not(:visited) { color: var(--color-primary); } @@ -587,6 +589,7 @@ details[open] .summary::after { .shrink { flex-shrink: 1; } .shrink-0 { flex-shrink: 0; } .min-width-0 { min-width: 0; } +.width-max-content { width: max-content; } .max-width-100 { max-width: 100%; } .block { display: block; } .inline-block { display: inline-block; } @@ -622,6 +625,7 @@ details[open] .summary::after { .gap-50 { gap: 5rem; } .gap-55 { gap: 5.5rem; } .margin-left-auto { margin-left: auto; } +.margin-inline-auto { margin-inline: auto; } .margin-top-3 { margin-top: 0.3rem; } .margin-top-5 { margin-top: 0.5rem; } .margin-top-7 { margin-top: 0.7rem; } @@ -648,9 +652,11 @@ details[open] .summary::after { .padding-widget { padding: var(--widget-content-padding); } .padding-block-widget { padding-block: var(--widget-content-vertical-padding); } .padding-inline-widget { padding-inline: var(--widget-content-horizontal-padding); } +.padding-inline-10 { padding-inline: 1rem; } .pointer-events-none { pointer-events: none; } .select-none { user-select: none; } .padding-block-5 { padding-block: 0.5rem; } +.padding-10 { padding: 1rem; } .scale-half { transform: scale(0.5); } .list { --list-half-gap: 0rem; } .list-gap-2 { --list-half-gap: 0.1rem; } diff --git a/internal/glance/static/css/widget-bookmarks.css b/internal/glance/static/css/widget-bookmarks.css index 0e205fe..d0431d2 100644 --- a/internal/glance/static/css/widget-bookmarks.css +++ b/internal/glance/static/css/widget-bookmarks.css @@ -22,3 +22,9 @@ padding: 0.5rem; flex-shrink: 0; } + +.bookmarks-grid { + display: grid; + gap: 2.5rem 0; + grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); +} diff --git a/internal/glance/templates/bookmarks-grid.html b/internal/glance/templates/bookmarks-grid.html new file mode 100644 index 0000000..cf33ebc --- /dev/null +++ b/internal/glance/templates/bookmarks-grid.html @@ -0,0 +1,21 @@ +{{ template "widget-base.html" . }} + +{{ define "widget-content" }} + +{{ end }} diff --git a/internal/glance/widget-bookmarks.go b/internal/glance/widget-bookmarks.go index 2245e2e..539f7d1 100644 --- a/internal/glance/widget-bookmarks.go +++ b/internal/glance/widget-bookmarks.go @@ -1,42 +1,52 @@ package glance import ( + "errors" "html/template" ) var bookmarksWidgetTemplate = mustParseTemplate("bookmarks.html", "widget-base.html") +var bookmarksGridWidgetTemplate = mustParseTemplate("bookmarks-grid.html", "widget-base.html") + +type bookmarkLinks []struct { + Title string `yaml:"title"` + URL string `yaml:"url"` + Description string `yaml:"description"` + Icon customIconField `yaml:"icon"` + // we need a pointer to bool to know whether a value was provided, + // however there's no way to dereference a pointer in a template so + // {{ if not .SameTab }} would return true for any non-nil pointer + // which leaves us with no way of checking if the value is true or + // false, hence the duplicated fields below + SameTabRaw *bool `yaml:"same-tab"` + SameTab bool `yaml:"-"` + HideArrowRaw *bool `yaml:"hide-arrow"` + HideArrow bool `yaml:"-"` + Target string `yaml:"target"` +} type bookmarksWidget struct { widgetBase `yaml:",inline"` - cachedHTML template.HTML `yaml:"-"` + cachedHTML template.HTML `yaml:"-"` + Style string `yaml:"style"` + Links *bookmarkLinks `yaml:"-"` Groups []struct { Title string `yaml:"title"` Color *hslColorField `yaml:"color"` SameTab bool `yaml:"same-tab"` HideArrow bool `yaml:"hide-arrow"` Target string `yaml:"target"` - Links []struct { - Title string `yaml:"title"` - URL string `yaml:"url"` - Description string `yaml:"description"` - Icon customIconField `yaml:"icon"` - // we need a pointer to bool to know whether a value was provided, - // however there's no way to dereference a pointer in a template so - // {{ if not .SameTab }} would return true for any non-nil pointer - // which leaves us with no way of checking if the value is true or - // false, hence the duplicated fields below - SameTabRaw *bool `yaml:"same-tab"` - SameTab bool `yaml:"-"` - HideArrowRaw *bool `yaml:"hide-arrow"` - HideArrow bool `yaml:"-"` - Target string `yaml:"target"` - } `yaml:"links"` + Links bookmarkLinks `yaml:"links"` } `yaml:"groups"` } func (widget *bookmarksWidget) initialize() error { widget.withTitle("Bookmarks").withError(nil) + if len(widget.Groups) == 0 { + return errors.New("must have at least one group") + } + for g := range widget.Groups { group := &widget.Groups[g] for l := range group.Links { @@ -67,7 +77,16 @@ func (widget *bookmarksWidget) initialize() error { } } - widget.cachedHTML = widget.renderTemplate(widget, bookmarksWidgetTemplate) + if widget.Style == "grid" { + if len(widget.Groups) != 1 { + return errors.New("grid style can only be used with a single group") + } + + widget.Links = &widget.Groups[0].Links + widget.cachedHTML = widget.renderTemplate(widget, bookmarksGridWidgetTemplate) + } else { + widget.cachedHTML = widget.renderTemplate(widget, bookmarksWidgetTemplate) + } return nil }