From de22e5598ab467791ad4c4f360e4a871260d0cb6 Mon Sep 17 00:00:00 2001 From: Florian Hoss Date: Mon, 30 Sep 2024 21:14:47 +0200 Subject: [PATCH] Add simple icons and option to turn dark mode off --- components/application.templ | 8 +++- handlers/routes.go | 4 +- pkg/media/media.go | 11 ++--- services/bookmark.services.go | 80 +++++++++++++++++++++++------------ services/bookmark.types.go | 9 ++-- 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/components/application.templ b/components/application.templ index b8eac23..fb498b6 100644 --- a/components/application.templ +++ b/components/application.templ @@ -2,12 +2,16 @@ package components import "gitlab.unjx.de/flohoss/godash/services" +func displayDark(app services.Application) bool { + return !app.IgnoreDark && app.IconLight != "" +} + templ Application(application services.Application) { -
+
@templ.Raw(application.Icon)
- if application.IconLight != "" { + if displayDark(application) {
@templ.Raw(application.IconLight)
diff --git a/handlers/routes.go b/handlers/routes.go index cf04be2..f392140 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -10,10 +10,10 @@ func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler, router.Handle("GET /sse", authHandler.AuthMiddleware(http.HandlerFunc(sse.ServeHTTP))) fsAssets := http.FileServer(http.Dir("assets")) - router.Handle("GET /assets/", http.StripPrefix("/assets/", fsAssets)) + router.Handle("GET /assets/", authHandler.AuthMiddleware(http.StripPrefix("/assets/", fsAssets))) icons := http.FileServer(http.Dir("storage/icons")) - router.Handle("GET /icons/", http.StripPrefix("/icons/", icons)) + router.Handle("GET /icons/", authHandler.AuthMiddleware(http.StripPrefix("/icons/", icons))) router.HandleFunc("GET /logout", authHandler.handleLogout) router.HandleFunc("GET /callback", authHandler.handleCallback) diff --git a/pkg/media/media.go b/pkg/media/media.go index 69dfab5..e39ab20 100644 --- a/pkg/media/media.go +++ b/pkg/media/media.go @@ -10,21 +10,21 @@ import ( "strings" ) -func DownloadSelfHostedIcon(ext, title, filePath string) ([]byte, error) { - resp, err := http.Get("https://cdn.jsdelivr.net/gh/selfhst/icons/" + strings.TrimPrefix(ext, ".") + "/" + title) +func DownloadSelfHostedIcon(url, title, filePath string) ([]byte, error) { + resp, err := http.Get(url) if err != nil { return nil, fmt.Errorf("failed to get icon: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("failed to get icon, status: %d", resp.StatusCode) + return nil, fmt.Errorf("failed to get icon, status: %d, url: %s", resp.StatusCode, url) } data, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read icon: %w", err) } - data = replaceClassNames(data, strings.TrimSuffix(title, ext)) - data = insertWidthHeight(data) + data = replaceClassNames(data, title) + // data = insertWidthHeight(data) err = os.WriteFile(filePath, data, fs.FileMode(0640)) if err != nil { return nil, fmt.Errorf("failed to write icon: %w", err) @@ -51,6 +51,7 @@ func insertWidthHeight(svgContent []byte) []byte { func replaceClassNames(svgContent []byte, title string) []byte { // Regular expression to match either class="st0" or .st0 classRegex := regexp.MustCompile(`(class="|\.)([a-z]{2}\d)`) + title = strings.TrimSuffix(title, ".svg") newSVGContent := classRegex.ReplaceAllFunc(svgContent, func(match []byte) []byte { groups := classRegex.FindSubmatch(match) diff --git a/services/bookmark.services.go b/services/bookmark.services.go index 0ff9847..5c9e8f6 100644 --- a/services/bookmark.services.go +++ b/services/bookmark.services.go @@ -90,41 +90,67 @@ func (bs *BookmarkService) replaceIconStrings() { slog.Error("icon must be an svg file") continue } + var data, lightData []byte + var err error if strings.HasPrefix(bookmark.Icon, "shi/") { - title := strings.Replace(bookmark.Icon, "shi/", "", 1) - if title == "" { - slog.Error("icon title is empty") + data, lightData, err = downloadIcons(handleSelfHostedIcons(bookmark.Icon, ext)) + if err != nil { + slog.Error(err.Error()) continue } - data, err := os.ReadFile(iconsFolder + title) - if err != nil { - slog.Debug("icon not found, downloading...", "title", title) - data, err = media.DownloadSelfHostedIcon(ext, title, iconsFolder+title) - if err != nil { - slog.Error(err.Error()) - continue - } - } - lightTitle := strings.Replace(title, ".svg", "-light.svg", 1) - lightData, err := os.ReadFile(iconsFolder + lightTitle) - if err != nil { - slog.Debug("light-icon not found, downloading...", "title", title) - lightData, err = media.DownloadSelfHostedIcon(ext, lightTitle, iconsFolder+lightTitle) - if err != nil { - slog.Warn(err.Error()) - } - } - if data == nil { - slog.Error("icon data is null") - continue - } - bs.bookmarks.Applications[i].Entries[j].Icon = string(data) - bs.bookmarks.Applications[i].Entries[j].IconLight = string(lightData) + } + if strings.HasPrefix(bookmark.Icon, "si/") { + data, lightData, err = downloadIcons(handleSimpleIcons(bookmark.Icon, ext)) + if err != nil { + slog.Error(err.Error()) + continue + } + } + bs.bookmarks.Applications[i].Entries[j].Icon = string(data) + bs.bookmarks.Applications[i].Entries[j].IconLight = string(lightData) } } } +func downloadIcons(title, url, lightTitle, lightUrl string) ([]byte, []byte, error) { + data, err := downloadIcon(title, url) + if err != nil { + return nil, nil, err + } + lightData, _ := downloadIcon(lightTitle, lightUrl) + return data, lightData, nil +} + +func downloadIcon(title, url string) ([]byte, error) { + filePath := iconsFolder + title + data, err := os.ReadFile(filePath) + if err != nil { + data, err = media.DownloadSelfHostedIcon(url, title, filePath) + if err != nil { + return nil, err + } + } + return data, nil +} + +func handleSelfHostedIcons(icon, ext string) (string, string, string, string) { + ext = strings.TrimPrefix(ext, ".") + title := strings.Replace(icon, "shi/", "", 1) + url := "https://cdn.jsdelivr.net/gh/selfhst/icons/" + ext + "/" + title + lightTitle := strings.Replace(title, ".svg", "-light.svg", 1) + lightUrl := "https://cdn.jsdelivr.net/gh/selfhst/icons/" + ext + "/" + lightTitle + return title, url, lightTitle, lightUrl +} + +func handleSimpleIcons(icon, ext string) (string, string, string, string) { + title := strings.Replace(icon, "si/", "", 1) + url := "https://cdn.simpleicons.org/" + strings.TrimSuffix(title, ext) + lightTitle := strings.Replace(title, ".svg", "-light.svg", 1) + lightUrl := "https://cdn.simpleicons.org/" + strings.TrimSuffix(title, ext) + "/white" + return title, url, lightTitle, lightUrl +} + func (bs *BookmarkService) parseBookmarks() { byteValue := bs.readBookmarksFile() err := yaml.Unmarshal(byteValue, &bs.bookmarks) diff --git a/services/bookmark.types.go b/services/bookmark.types.go index 67826b1..cdd37e4 100644 --- a/services/bookmark.types.go +++ b/services/bookmark.types.go @@ -21,8 +21,9 @@ type Link struct { } type Application struct { - Name string - Icon string - URL string - IconLight string + Name string + Icon string + URL string + IconLight string + IgnoreDark bool `yaml:"ignore_dark"` }