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
}