Add simple icons and option to turn dark mode off
This commit is contained in:
parent
808cbdf115
commit
de22e5598a
5 changed files with 72 additions and 40 deletions
|
@ -2,12 +2,16 @@ package components
|
||||||
|
|
||||||
import "gitlab.unjx.de/flohoss/godash/services"
|
import "gitlab.unjx.de/flohoss/godash/services"
|
||||||
|
|
||||||
|
func displayDark(app services.Application) bool {
|
||||||
|
return !app.IgnoreDark && app.IconLight != ""
|
||||||
|
}
|
||||||
|
|
||||||
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", templ.KV("dark:hidden", application.IconLight != ""), "items-center" }>
|
<div class={ "w-8", "h-8", "flex", templ.KV("dark:hidden", displayDark(application)), "items-center" }>
|
||||||
@templ.Raw(application.Icon)
|
@templ.Raw(application.Icon)
|
||||||
</div>
|
</div>
|
||||||
if application.IconLight != "" {
|
if displayDark(application) {
|
||||||
<div class={ "w-8", "h-8", "hidden", "dark:flex", "items-center" }>
|
<div class={ "w-8", "h-8", "hidden", "dark:flex", "items-center" }>
|
||||||
@templ.Raw(application.IconLight)
|
@templ.Raw(application.IconLight)
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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/", http.StripPrefix("/assets/", fsAssets))
|
router.Handle("GET /assets/", authHandler.AuthMiddleware(http.StripPrefix("/assets/", fsAssets)))
|
||||||
|
|
||||||
icons := http.FileServer(http.Dir("storage/icons"))
|
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 /logout", authHandler.handleLogout)
|
||||||
router.HandleFunc("GET /callback", authHandler.handleCallback)
|
router.HandleFunc("GET /callback", authHandler.handleCallback)
|
||||||
|
|
|
@ -10,21 +10,21 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DownloadSelfHostedIcon(ext, title, filePath string) ([]byte, error) {
|
func DownloadSelfHostedIcon(url, title, filePath string) ([]byte, error) {
|
||||||
resp, err := http.Get("https://cdn.jsdelivr.net/gh/selfhst/icons/" + strings.TrimPrefix(ext, ".") + "/" + title)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get icon: %w", err)
|
return nil, fmt.Errorf("failed to get icon: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusOK {
|
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)
|
data, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read icon: %w", err)
|
return nil, fmt.Errorf("failed to read icon: %w", err)
|
||||||
}
|
}
|
||||||
data = replaceClassNames(data, strings.TrimSuffix(title, ext))
|
data = replaceClassNames(data, title)
|
||||||
data = insertWidthHeight(data)
|
// data = insertWidthHeight(data)
|
||||||
err = os.WriteFile(filePath, data, fs.FileMode(0640))
|
err = os.WriteFile(filePath, data, fs.FileMode(0640))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to write icon: %w", err)
|
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 {
|
func replaceClassNames(svgContent []byte, title string) []byte {
|
||||||
// Regular expression to match either class="st0" or .st0
|
// Regular expression to match either class="st0" or .st0
|
||||||
classRegex := regexp.MustCompile(`(class="|\.)([a-z]{2}\d)`)
|
classRegex := regexp.MustCompile(`(class="|\.)([a-z]{2}\d)`)
|
||||||
|
title = strings.TrimSuffix(title, ".svg")
|
||||||
|
|
||||||
newSVGContent := classRegex.ReplaceAllFunc(svgContent, func(match []byte) []byte {
|
newSVGContent := classRegex.ReplaceAllFunc(svgContent, func(match []byte) []byte {
|
||||||
groups := classRegex.FindSubmatch(match)
|
groups := classRegex.FindSubmatch(match)
|
||||||
|
|
|
@ -90,39 +90,65 @@ func (bs *BookmarkService) replaceIconStrings() {
|
||||||
slog.Error("icon must be an svg file")
|
slog.Error("icon must be an svg file")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var data, lightData []byte
|
||||||
|
var err error
|
||||||
if strings.HasPrefix(bookmark.Icon, "shi/") {
|
if strings.HasPrefix(bookmark.Icon, "shi/") {
|
||||||
title := strings.Replace(bookmark.Icon, "shi/", "", 1)
|
data, lightData, err = downloadIcons(handleSelfHostedIcons(bookmark.Icon, ext))
|
||||||
if title == "" {
|
|
||||||
slog.Error("icon title is empty")
|
|
||||||
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 {
|
if err != nil {
|
||||||
slog.Error(err.Error())
|
slog.Error(err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
lightTitle := strings.Replace(title, ".svg", "-light.svg", 1)
|
if strings.HasPrefix(bookmark.Icon, "si/") {
|
||||||
lightData, err := os.ReadFile(iconsFolder + lightTitle)
|
data, lightData, err = downloadIcons(handleSimpleIcons(bookmark.Icon, ext))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Debug("light-icon not found, downloading...", "title", title)
|
slog.Error(err.Error())
|
||||||
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
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
bs.bookmarks.Applications[i].Entries[j].Icon = string(data)
|
bs.bookmarks.Applications[i].Entries[j].Icon = string(data)
|
||||||
bs.bookmarks.Applications[i].Entries[j].IconLight = string(lightData)
|
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() {
|
func (bs *BookmarkService) parseBookmarks() {
|
||||||
|
|
|
@ -25,4 +25,5 @@ type Application struct {
|
||||||
Icon string
|
Icon string
|
||||||
URL string
|
URL string
|
||||||
IconLight string
|
IconLight string
|
||||||
|
IgnoreDark bool `yaml:"ignore_dark"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue