From 1e0e08ce8cc4927a595253b49a2b35ed729dcfb8 Mon Sep 17 00:00:00 2001
From: Panonim
Date: Sun, 27 Sep 2026 21:21:29 +0200
Subject: [PATCH 1/2] Added a grid style to the bookmarks widget
---
docs/docs/changelog.md | 1 +
docs/docs/configuration.md | 4 ++
.../dynacat/static/css/widget-bookmarks.css | 40 +++++++++++++++++++
.../dynacat/templates/bookmarks-grid.html | 32 +++++++++++++++
internal/dynacat/widget-bookmarks.go | 14 ++++++-
internal/dynacat/widget-schema.go | 3 ++
6 files changed, 92 insertions(+), 2 deletions(-)
create mode 100644 internal/dynacat/templates/bookmarks-grid.html
diff --git a/docs/docs/changelog.md b/docs/docs/changelog.md
index b995b986..d117c1d4 100644
--- a/docs/docs/changelog.md
+++ b/docs/docs/changelog.md
@@ -8,6 +8,7 @@
- Fixed `clock` widget blanking after widget updates -> https://github.com/Panonim/dynacat/pull/160
- Calendar now shows releases on the previous and next month days visible in the grid -> https://github.com/Panonim/dynacat/issues/156
- Calendar now properly shows upcoming shows -> https://github.com/Panonim/dynacat/issues/156
+- Added a `grid` style to the `bookmarks` widget -> https://github.com/Panonim/dynacat/issues/162
# Changes for 3.0.0
- Moved the compose template to [Panonim/dynacat-compose-template](https://github.com/Panonim/dynacat-compose-template), the install command is now a single `curl | tar` with no `sed` renaming
diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md
index 8187ef2a..cfa299ed 100644
--- a/docs/docs/configuration.md
+++ b/docs/docs/configuration.md
@@ -793,6 +793,10 @@ Preview:
| Name | Type | Required |
| ---- | ---- | -------- |
| groups | array | yes |
+| style | string | no |
+
+##### `style`
+Set to `grid` to show the links as a grid of icon tiles with the title and description underneath, which works best when each link has an `icon`. Leave it empty for the default list.
##### `groups`
An array of groups which can optionally have a title and a custom color.
diff --git a/internal/dynacat/static/css/widget-bookmarks.css b/internal/dynacat/static/css/widget-bookmarks.css
index 19c5ad24..e8f33e6f 100644
--- a/internal/dynacat/static/css/widget-bookmarks.css
+++ b/internal/dynacat/static/css/widget-bookmarks.css
@@ -33,3 +33,43 @@
height: 20px;
opacity: 0.8;
}
+
+.bookmarks-grid {
+ display: grid;
+ gap: 2rem 0.5rem;
+ grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
+}
+
+.bookmarks-grid-icon-container {
+ width: max-content;
+ margin-inline: auto;
+ padding: 1rem;
+ border-radius: var(--border-radius);
+ background-color: var(--color-widget-background-highlight);
+ transition: background-color 0.2s, transform 0.2s;
+}
+
+.bookmarks-grid-icon {
+ display: block;
+ width: 4rem;
+ height: 4rem;
+ object-fit: contain;
+ opacity: 0.8;
+ transition: opacity 0.2s;
+}
+
+.bookmarks-grid-link:hover .bookmarks-grid-icon-container,
+.bookmarks-grid-link:focus-visible .bookmarks-grid-icon-container {
+ background-color: color-mix(in srgb, var(--bookmarks-group-color) 18%, var(--color-widget-background-highlight));
+ transform: translateY(-2px);
+}
+
+.bookmarks-grid-link:hover .bookmarks-grid-icon,
+.bookmarks-grid-link:focus-visible .bookmarks-grid-icon {
+ opacity: 1;
+}
+
+.bookmarks-grid-link:hover .bookmarks-grid-title,
+.bookmarks-grid-link:focus-visible .bookmarks-grid-title {
+ color: var(--bookmarks-group-color);
+}
diff --git a/internal/dynacat/templates/bookmarks-grid.html b/internal/dynacat/templates/bookmarks-grid.html
new file mode 100644
index 00000000..766e9ccd
--- /dev/null
+++ b/internal/dynacat/templates/bookmarks-grid.html
@@ -0,0 +1,32 @@
+{{ template "widget-base.html" . }}
+
+{{ define "widget-content-classes" }}{{ if .Frameless }}widget-content-frameless{{ end }}{{ end }}
+
+{{ define "widget-content" }}
+
+ {{- range .Groups }}
+
+ {{- if ne .Title "" }}
+
{{ .Title }}
+ {{- end }}
+
+
+ {{- end }}
+
+{{ end }}
diff --git a/internal/dynacat/widget-bookmarks.go b/internal/dynacat/widget-bookmarks.go
index f7920ebc..0832ec98 100644
--- a/internal/dynacat/widget-bookmarks.go
+++ b/internal/dynacat/widget-bookmarks.go
@@ -5,11 +5,13 @@ import (
)
var bookmarksWidgetTemplate = mustParseTemplate("bookmarks.html", "widget-base.html")
+var bookmarksGridWidgetTemplate = mustParseTemplate("bookmarks-grid.html", "widget-base.html")
type bookmarksWidget struct {
widgetBase `yaml:",inline"`
cachedHTML template.HTML `yaml:"-"`
Frameless bool `yaml:"frameless"`
+ Style string `yaml:"style"`
Groups []struct {
Title string `yaml:"title"`
Color *hslColorField `yaml:"color"`
@@ -65,17 +67,25 @@ func (widget *bookmarksWidget) initialize() error {
func (widget *bookmarksWidget) setProviders(providers *widgetProviders) {
widget.widgetBase.setProviders(providers)
widget.cacheIcons()
- widget.cachedHTML = widget.renderTemplate(widget, bookmarksWidgetTemplate)
+ widget.cachedHTML = widget.render()
}
func (widget *bookmarksWidget) Render() template.HTML {
if widget.cachedHTML == "" {
- widget.cachedHTML = widget.renderTemplate(widget, bookmarksWidgetTemplate)
+ widget.cachedHTML = widget.render()
}
return widget.cachedHTML
}
+func (widget *bookmarksWidget) render() template.HTML {
+ if widget.Style == "grid" {
+ return widget.renderTemplate(widget, bookmarksGridWidgetTemplate)
+ }
+
+ return widget.renderTemplate(widget, bookmarksWidgetTemplate)
+}
+
func (widget *bookmarksWidget) cacheIcons() {
if widget.Providers == nil {
return
diff --git a/internal/dynacat/widget-schema.go b/internal/dynacat/widget-schema.go
index 78be66da..855ddd8d 100644
--- a/internal/dynacat/widget-schema.go
+++ b/internal/dynacat/widget-schema.go
@@ -134,6 +134,9 @@ var itemAdvancedFields = map[string]bool{
const maxListDepth = 2
var fieldAnnotations = map[string]map[string]fieldAnnotation{
+ "bookmarks": {
+ "style": {Options: []string{"grid"}},
+ },
"calendar": {
"first-day-of-week": {Options: []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}},
"hosts.url": {Hint: "Prefix with the service, e.g. sonarr:https://... or radarr:https://..."},
From f795bb8b092eb23b6218bb8b7f68e471eabb9fc9 Mon Sep 17 00:00:00 2001
From: Panonim
Date: Wed, 30 Sep 2026 20:27:55 +0200
Subject: [PATCH 2/2] Updated README
---
README.md | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 2f2a97e8..6695101d 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
Dynawidgets •
- Custom-api widgets •
+ Custom-api widgets •
Preconfigured pages •
Themes
@@ -65,8 +65,6 @@ Easily create your own theme by tweaking a few numbers or choose from one of the
* **OIDC** - log in through your own identity provider
* **More widgets** - docker controller, currently playing, latest media, torrenting, speedtest, stopwatch and Sonarr/Radarr releases in the calendar
-Each of these is covered in [the docs](https://dynacat.artur.zone).
-
## Installation
@@ -103,8 +101,6 @@ services:
```
-If you'd like a more detailed instructions they can be found in [the docs](https://dynacat.artur.zone/#installation).
-
## Configuration
There are two ways to configure Dynacat, and they work on the same files: