Use light and dark icons
This commit is contained in:
parent
2f5d83cf12
commit
808cbdf115
7 changed files with 98 additions and 35 deletions
|
@ -4,9 +4,14 @@ import "gitlab.unjx.de/flohoss/godash/services"
|
|||
|
||||
templ Application(application services.Application) {
|
||||
<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)
|
||||
</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>
|
||||
</a>
|
||||
}
|
||||
|
|
|
@ -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/", authHandler.AuthMiddleware(http.StripPrefix("/assets/", fsAssets)))
|
||||
router.Handle("GET /assets/", http.StripPrefix("/assets/", fsAssets))
|
||||
|
||||
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 /callback", authHandler.handleCallback)
|
||||
|
|
2
main.go
2
main.go
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
"gitlab.unjx.de/flohoss/godash/handlers"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
|
72
pkg/media/media.go
Normal file
72
pkg/media/media.go
Normal 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
|
||||
}
|
|
@ -2,13 +2,12 @@ package services
|
|||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gitlab.unjx.de/flohoss/godash/pkg/media"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
@ -98,34 +97,29 @@ func (bs *BookmarkService) replaceIconStrings() {
|
|||
continue
|
||||
}
|
||||
data, err := os.ReadFile(iconsFolder + title)
|
||||
if os.IsNotExist(err) {
|
||||
if err != nil {
|
||||
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 {
|
||||
slog.Error("failed to get icon", "err", err.Error())
|
||||
slog.Error(err.Error())
|
||||
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 {
|
||||
slog.Debug("light-icon not found, downloading...", "title", title)
|
||||
lightData, err = media.DownloadSelfHostedIcon(ext, lightTitle, iconsFolder+lightTitle)
|
||||
if err != nil {
|
||||
slog.Error("failed to read icon", "err", err.Error())
|
||||
continue
|
||||
}
|
||||
err = os.WriteFile(iconsFolder+title, data, fs.FileMode(0640))
|
||||
if err != nil {
|
||||
slog.Error("failed to write icon", "err", err.Error())
|
||||
continue
|
||||
slog.Warn(err.Error())
|
||||
}
|
||||
}
|
||||
if data == nil {
|
||||
slog.Error("icon data is null")
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ type Link struct {
|
|||
}
|
||||
|
||||
type Application struct {
|
||||
Name string
|
||||
Icon string
|
||||
URL string
|
||||
Light bool
|
||||
Name string
|
||||
Icon string
|
||||
URL string
|
||||
IconLight string
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue