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) {
|
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>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
2
main.go
2
main.go
|
@ -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
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 (
|
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]
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,5 +24,5 @@ type Application struct {
|
||||||
Name string
|
Name string
|
||||||
Icon string
|
Icon string
|
||||||
URL string
|
URL string
|
||||||
Light bool
|
IconLight string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue