Use light and dark icons

This commit is contained in:
Florian Hoss 2024-09-30 20:16:29 +02:00
parent 2f5d83cf12
commit 808cbdf115
Signed by: flohoss
GPG key ID: 3F35C7F6E6F66F6B
7 changed files with 98 additions and 35 deletions

View file

@ -4,9 +4,14 @@ import "gitlab.unjx.de/flohoss/godash/services"
templ Application(application services.Application) { templ Application(application services.Application) {
<a href={ templ.URL(application.URL) } class="flex items-center hover-effect"> <a href={ templ.URL(application.URL) } class="flex items-center hover-effect">
<div class="w-8 h-8 flex items-center"> <div class={ "w-8", "h-8", "flex", templ.KV("dark:hidden", application.IconLight != ""), "items-center" }>
@templ.Raw(application.Icon) @templ.Raw(application.Icon)
</div> </div>
if application.IconLight != "" {
<div class={ "w-8", "h-8", "hidden", "dark:flex", "items-center" }>
@templ.Raw(application.IconLight)
</div>
}
<div class="uppercase truncate ml-2">{ application.Name }</div> <div class="uppercase truncate ml-2">{ application.Name }</div>
</a> </a>
} }

View file

@ -10,10 +10,10 @@ func SetupRoutes(router *http.ServeMux, sse *sse.Server, appHandler *AppHandler,
router.Handle("GET /sse", authHandler.AuthMiddleware(http.HandlerFunc(sse.ServeHTTP))) router.Handle("GET /sse", authHandler.AuthMiddleware(http.HandlerFunc(sse.ServeHTTP)))
fsAssets := http.FileServer(http.Dir("assets")) fsAssets := http.FileServer(http.Dir("assets"))
router.Handle("GET /assets/", authHandler.AuthMiddleware(http.StripPrefix("/assets/", fsAssets))) router.Handle("GET /assets/", http.StripPrefix("/assets/", fsAssets))
icons := http.FileServer(http.Dir("storage/icons")) icons := http.FileServer(http.Dir("storage/icons"))
router.Handle("GET /icons/", authHandler.AuthMiddleware(http.StripPrefix("/icons/", icons))) router.Handle("GET /icons/", http.StripPrefix("/icons/", icons))
router.HandleFunc("GET /logout", authHandler.handleLogout) router.HandleFunc("GET /logout", authHandler.handleLogout)
router.HandleFunc("GET /callback", authHandler.handleCallback) router.HandleFunc("GET /callback", authHandler.handleCallback)

View file

@ -14,7 +14,7 @@ import (
"gitlab.unjx.de/flohoss/godash/handlers" "gitlab.unjx.de/flohoss/godash/handlers"
"gitlab.unjx.de/flohoss/godash/internal/env" "gitlab.unjx.de/flohoss/godash/internal/env"
"gitlab.unjx.de/flohoss/godash/internal/logger" "gitlab.unjx.de/flohoss/godash/pkg/logger"
"gitlab.unjx.de/flohoss/godash/services" "gitlab.unjx.de/flohoss/godash/services"
) )

72
pkg/media/media.go Normal file
View file

@ -0,0 +1,72 @@
package media
import (
"fmt"
"io"
"io/fs"
"net/http"
"os"
"regexp"
"strings"
)
func DownloadSelfHostedIcon(ext, title, filePath string) ([]byte, error) {
resp, err := http.Get("https://cdn.jsdelivr.net/gh/selfhst/icons/" + strings.TrimPrefix(ext, ".") + "/" + title)
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)
}
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)
err = os.WriteFile(filePath, data, fs.FileMode(0640))
if err != nil {
return nil, fmt.Errorf("failed to write icon: %w", err)
}
return data, nil
}
func insertWidthHeight(svgContent []byte) []byte {
classRegex := regexp.MustCompile(`(?:<svg(.+?)(width|height)=".+?")(.+?)(width|height)=".+?"|(<svg)`)
newSVGContent := classRegex.ReplaceAllFunc(svgContent, func(match []byte) []byte {
groups := classRegex.FindSubmatch(match)
if len(groups) == 0 {
return match
}
if string(match) == "<svg" {
return []byte(`<svg width="2rem" height="2rem" `)
} else {
return []byte(fmt.Sprintf(`<svg%s%s="2rem"%s%s="2rem"`, groups[1], groups[2], groups[3], groups[4]))
}
})
return newSVGContent
}
func replaceClassNames(svgContent []byte, title string) []byte {
// Regular expression to match either class="st0" or .st0
classRegex := regexp.MustCompile(`(class="|\.)([a-z]{2}\d)`)
newSVGContent := classRegex.ReplaceAllFunc(svgContent, func(match []byte) []byte {
groups := classRegex.FindSubmatch(match)
if len(groups) == 0 {
return match
}
group1 := string(groups[1])
group2 := string(groups[2])
if group1 == `class="` {
return []byte(`class="` + title + "-" + group2)
}
if group1 == `.` {
return []byte(`.` + title + "-" + group2)
}
return match
})
return newSVGContent
}

View file

@ -2,13 +2,12 @@ package services
import ( import (
"io" "io"
"io/fs"
"log/slog" "log/slog"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"gitlab.unjx.de/flohoss/godash/pkg/media"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -98,34 +97,29 @@ func (bs *BookmarkService) replaceIconStrings() {
continue continue
} }
data, err := os.ReadFile(iconsFolder + title) data, err := os.ReadFile(iconsFolder + title)
if os.IsNotExist(err) { if err != nil {
slog.Debug("icon not found, downloading...", "title", title) slog.Debug("icon not found, downloading...", "title", title)
resp, err := http.Get("https://cdn.jsdelivr.net/gh/selfhst/icons/" + strings.TrimPrefix(ext, ".") + "/" + title) data, err = media.DownloadSelfHostedIcon(ext, title, iconsFolder+title)
if err != nil { if err != nil {
slog.Error("failed to get icon", "err", err.Error()) slog.Error(err.Error())
continue continue
} }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
slog.Error("failed to get icon", "status", resp.Status, "url", resp.Request.URL.String())
continue
} }
data, err = io.ReadAll(resp.Body) lightTitle := strings.Replace(title, ".svg", "-light.svg", 1)
lightData, err := os.ReadFile(iconsFolder + lightTitle)
if err != nil { if err != nil {
slog.Error("failed to read icon", "err", err.Error()) slog.Debug("light-icon not found, downloading...", "title", title)
continue lightData, err = media.DownloadSelfHostedIcon(ext, lightTitle, iconsFolder+lightTitle)
}
err = os.WriteFile(iconsFolder+title, data, fs.FileMode(0640))
if err != nil { if err != nil {
slog.Error("failed to write icon", "err", err.Error()) slog.Warn(err.Error())
continue
} }
} }
if data == nil { if data == nil {
slog.Error("icon data is null") slog.Error("icon data is null")
continue continue
} }
bs.bookmarks.Applications[i].Entries[j].Icon = insertWidthHeight(string(data)) bs.bookmarks.Applications[i].Entries[j].Icon = string(data)
bs.bookmarks.Applications[i].Entries[j].IconLight = string(lightData)
} }
} }
} }
@ -139,11 +133,3 @@ func (bs *BookmarkService) parseBookmarks() {
return return
} }
} }
func insertWidthHeight(svg string) string {
parts := strings.SplitN(svg, "<svg", 2)
if len(parts) != 2 {
return svg
}
return parts[0] + "<svg width=\"2rem\" height=\"2rem\" " + parts[1]
}

View file

@ -24,5 +24,5 @@ type Application struct {
Name string Name string
Icon string Icon string
URL string URL string
Light bool IconLight string
} }