Browse Source

BREAKING: Use yaml for bookmarks

Florian Hoss 2 years ago
parent
commit
c9820499cf
20 changed files with 293 additions and 287 deletions
  1. 1 1
      Jenkinsfile
  2. 33 40
      README.md
  3. 33 39
      bookmarks/bookmark.go
  4. 0 32
      bookmarks/bookmarks.json
  5. 30 0
      bookmarks/config.yaml
  6. 19 14
      bookmarks/types.go
  7. 1 0
      go.mod
  8. 1 11
      go.sum
  9. 3 1
      main.go
  10. 4 4
      routes.go
  11. 11 2
      static/css/input.css
  12. 2 2
      system/cpu.go
  13. 3 3
      system/disk.go
  14. 3 3
      system/ram.go
  15. 16 16
      system/system.go
  16. 5 5
      system/types.go
  17. 6 6
      system/uptime.go
  18. 1 1
      tailwind.config.js
  19. 1 1
      templates/_base.gohtml
  20. 120 106
      templates/index.gohtml

+ 1 - 1
Jenkinsfile

@@ -1,6 +1,6 @@
 pipeline {
     environment {
-        VERSION = "v2.0.0"
+        VERSION = "v2.0.1"
         PROJECT_NAME = JOB_NAME.split('/')
         IMAGE_NAME = "unjxde/${PROJECT_NAME[0]}"
         IMAGE = ''

+ 33 - 40
README.md

@@ -32,52 +32,45 @@ Please refer to the available options as shown in the docker-compose example.
 
 ### Example of the bookmarks.json
 
-All Bookmarks are read from a file called `bookmarks.json` located inside the `./storage` folder.
+All Bookmarks are read from a file called `config.yaml` located inside the `./storage` folder.
 The application will create a default file at startup and will automatically look for changes inside the file.
 Changes are printed in stdout when running with `LOG_LEVEL=trace`.
 
 You can specify an icon of a bookmark either by using a link or by using the name of the file located inside the `./storage/icons` folder that is mounted via the docker compose file.
 The name and related link can be provided as well.
 
-**bookmarks.json example:**
-```json
-[
-  {
-    "CATEGORY": "First",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      },
-      {
-        "NAME": "Jenkins",
-        "ICON": "jenkins.webp",
-        "URL": "https://www.jenkins.io/"
-      }
-    ]
-  },
-  {
-    "CATEGORY": "",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      }
-    ]
-  },
-  {
-    "CATEGORY": "Third",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      }
-    ]
-  }
-]
+**config.yaml example:**
+```yaml
+links:
+  - category: "Code"
+    entries:
+      - name: "Github"
+        url: "https://github.com"
+  - category: "CI/CD"
+    entries:
+      - name: "Jenkins"
+        url: "https://www.jenkins.io/"
+  - category: "Server"
+    entries:
+      - name: "bwCloud"
+        url: "https://portal.bw-cloud.org"
+
+applications:
+  - category: "Code"
+    entries:
+      - name: "Github"
+        icon: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
+        url: "https://github.com"
+  - category: ""
+    entries:
+      - name: "Jenkins"
+        icon: "https://www.jenkins.io/images/logos/jenkins/Jenkins-stop-the-war.svg"
+        url: "https://www.jenkins.io/"
+  - category: "Server"
+    entries:
+      - name: "bwCloud"
+        icon: "https://portal.bw-cloud.org/static/dashboard/img/logo-splash.svg"
+        url: "https://portal.bw-cloud.org"
 ```
 
 ### Available environment variables with default values

+ 33 - 39
bookmarks/bookmark.go

@@ -1,10 +1,10 @@
 package bookmarks
 
 import (
-	"encoding/json"
 	"github.com/fsnotify/fsnotify"
 	folderCreate "github.com/unjx-de/go-folder"
 	"go.uber.org/zap"
+	"gopkg.in/yaml.v3"
 	"io"
 	"os"
 	"strings"
@@ -13,60 +13,60 @@ import (
 const StorageDir = "storage/"
 const IconsDir = StorageDir + "icons/"
 const bookmarksFolder = "bookmarks/"
-const bookmarksFile = "bookmarks.json"
+const bookmarksFile = "config.yaml"
 
-func NewBookmarkService(logging *zap.SugaredLogger) *Bookmarks {
-	b := Bookmarks{log: logging}
+func NewBookmarkService(logging *zap.SugaredLogger) *Config {
+	b := Config{log: logging}
 	b.createFolderStructure()
 	b.parseBookmarks()
 	go b.watchBookmarks()
 	return &b
 }
 
-func (b *Bookmarks) createFolderStructure() {
+func (c *Config) createFolderStructure() {
 	folders := []string{StorageDir, IconsDir}
 	err := folderCreate.CreateFolders(folders, 0755)
 	if err != nil {
-		b.log.Fatal(err)
+		c.log.Fatal(err)
 	}
-	b.log.Debug("folders created")
+	c.log.Debugw("folders created", "folders", folders)
 }
 
-func (b *Bookmarks) copyDefaultBookmarks() {
+func (c *Config) copyDefaultBookmarks() {
 	source, _ := os.Open(bookmarksFolder + bookmarksFile)
 	defer source.Close()
 	destination, err := os.Create(StorageDir + bookmarksFile)
 	if err != nil {
-		b.log.Error(err)
+		c.log.Error(err)
 	}
 	defer destination.Close()
 	_, err = io.Copy(destination, source)
 	if err != nil {
-		b.log.Error(err)
+		c.log.Error(err)
 	}
 }
 
-func (b *Bookmarks) readBookmarksFile() []byte {
-	jsonFile, err := os.Open(StorageDir + bookmarksFile)
+func (c *Config) readBookmarksFile() []byte {
+	file, err := os.Open(StorageDir + bookmarksFile)
 	if err != nil {
-		b.copyDefaultBookmarks()
-		jsonFile, err = os.Open(StorageDir + bookmarksFile)
+		c.copyDefaultBookmarks()
+		file, err = os.Open(StorageDir + bookmarksFile)
 		if err != nil {
-			b.log.Error(err)
+			c.log.Error(err)
 			return nil
 		}
 	}
-	defer jsonFile.Close()
-	byteValue, err := io.ReadAll(jsonFile)
+	defer file.Close()
+	byteValue, err := io.ReadAll(file)
 	if err != nil {
-		b.log.Error(err)
+		c.log.Error(err)
 		return nil
 	}
 	return byteValue
 }
 
-func (b *Bookmarks) replaceIconString() {
-	for _, v := range b.Categories {
+func (c *Config) replaceIconString() {
+	for _, v := range c.Parsed.Applications {
 		for i, bookmark := range v.Entries {
 			if !strings.Contains(bookmark.Icon, "http") {
 				v.Entries[i].Icon = "/" + IconsDir + bookmark.Icon
@@ -75,20 +75,20 @@ func (b *Bookmarks) replaceIconString() {
 	}
 }
 
-func (b *Bookmarks) parseBookmarks() {
-	byteValue := b.readBookmarksFile()
-	err := json.Unmarshal(byteValue, &b.Categories)
+func (c *Config) parseBookmarks() {
+	byteValue := c.readBookmarksFile()
+	err := yaml.Unmarshal(byteValue, &c.Parsed)
 	if err != nil {
-		b.log.Error(err)
+		c.log.Error(err)
 		return
 	}
-	b.replaceIconString()
+	c.replaceIconString()
 }
 
-func (b *Bookmarks) watchBookmarks() {
+func (c *Config) watchBookmarks() {
 	watcher, err := fsnotify.NewWatcher()
 	if err != nil {
-		b.log.Error(err)
+		c.log.Error(err)
 	}
 	defer watcher.Close()
 	done := make(chan bool)
@@ -96,23 +96,17 @@ func (b *Bookmarks) watchBookmarks() {
 	go func() {
 		for {
 			select {
-			case err, ok := <-watcher.Errors:
-				if !ok {
-					return
-				}
-				b.log.Error(err)
-			case _, ok := <-watcher.Events:
-				if !ok {
-					return
-				}
-				b.parseBookmarks()
-				b.log.Debug("bookmarks changed", "categories", len(b.Categories))
+			case err, _ := <-watcher.Errors:
+				c.log.Error(err)
+			case _, _ = <-watcher.Events:
+				c.parseBookmarks()
+				c.log.Debug("bookmarks changed", "applications", len(c.Parsed.Applications), "links", len(c.Parsed.Links))
 			}
 		}
 	}()
 
 	if err := watcher.Add(StorageDir + bookmarksFile); err != nil {
-		b.log.Fatal()
+		c.log.Fatal()
 	}
 	<-done
 }

+ 0 - 32
bookmarks/bookmarks.json

@@ -1,32 +0,0 @@
-[
-  {
-    "CATEGORY": "First",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      }
-    ]
-  },
-  {
-    "CATEGORY": "",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      }
-    ]
-  },
-  {
-    "CATEGORY": "Third",
-    "ENTRIES": [
-      {
-        "NAME": "Github",
-        "ICON": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
-        "URL": "https://github.com"
-      }
-    ]
-  }
-]

+ 30 - 0
bookmarks/config.yaml

@@ -0,0 +1,30 @@
+links:
+  - category: "Code"
+    entries:
+      - name: "Github"
+        url: "https://github.com"
+  - category: "CI/CD"
+    entries:
+      - name: "Jenkins"
+        url: "https://www.jenkins.io/"
+  - category: "Server"
+    entries:
+      - name: "bwCloud"
+        url: "https://portal.bw-cloud.org"
+
+applications:
+  - category: "Code"
+    entries:
+      - name: "Github"
+        icon: "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
+        url: "https://github.com"
+  - category: ""
+    entries:
+      - name: "Jenkins"
+        icon: "https://www.jenkins.io/images/logos/jenkins/Jenkins-stop-the-war.svg"
+        url: "https://www.jenkins.io/"
+  - category: "Server"
+    entries:
+      - name: "bwCloud"
+        icon: "https://portal.bw-cloud.org/static/dashboard/img/logo-splash.svg"
+        url: "https://portal.bw-cloud.org"

+ 19 - 14
bookmarks/types.go

@@ -2,18 +2,23 @@ package bookmarks
 
 import "go.uber.org/zap"
 
-type Bookmarks struct {
-	log        *zap.SugaredLogger
-	Categories []Category
-}
-
-type Category struct {
-	Category string  `json:"category"`
-	Entries  []Entry `json:"entries"`
-}
-
-type Entry struct {
-	Name string `json:"name"`
-	Icon string `json:"icon"`
-	Url  string `json:"url"`
+type Config struct {
+	log    *zap.SugaredLogger
+	Parsed struct {
+		Links []struct {
+			Category string
+			Entries  []struct {
+				Name string
+				URL  string
+			}
+		}
+		Applications []struct {
+			Category string
+			Entries  []struct {
+				Name string
+				Icon string
+				URL  string
+			}
+		}
+	}
 }

+ 1 - 0
go.mod

@@ -11,6 +11,7 @@ require (
 	github.com/shirou/gopsutil/v3 v3.22.11
 	github.com/unjx-de/go-folder v1.0.7
 	go.uber.org/zap v1.24.0
+	gopkg.in/yaml.v3 v3.0.1
 )
 
 require (

+ 1 - 11
go.sum

@@ -22,7 +22,6 @@ github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+
 github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
 github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
 github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
 github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
 github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
@@ -36,7 +35,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
 github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
 github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
@@ -45,7 +43,6 @@ github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0X
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -59,24 +56,18 @@ github.com/unjx-de/go-folder v1.0.7 h1:OVKvqjcVB0ASidVshYndRtkmlqS1h6MIhSr0vqX3Q
 github.com/unjx-de/go-folder v1.0.7/go.mod h1:sbcRrRgLE49QI6CZqGBMdneRuNOOhoRU1gx9DYlyD2g=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
 github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
 github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
 github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
 github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
 go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
-go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
 go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
 go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
 go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
-golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
-golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
 golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
 golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
 golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
@@ -93,11 +84,10 @@ golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
 golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
-golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 3 - 1
main.go

@@ -27,7 +27,7 @@ type goDash struct {
 
 type info struct {
 	weather   *weather.Weather
-	bookmarks *bookmarks.Bookmarks
+	bookmarks *bookmarks.Config
 	system    *system.System
 }
 
@@ -63,6 +63,8 @@ func main() {
 		panic(err)
 	}
 
+	g.router.Debug = true
+
 	g.setupLogger()
 	defer func(logger *zap.SugaredLogger) {
 		_ = logger.Sync()

+ 4 - 4
routes.go

@@ -13,10 +13,10 @@ var (
 
 func (g *goDash) index(c echo.Context) error {
 	return c.Render(http.StatusOK, "index.gohtml", map[string]interface{}{
-		"Title":      g.config.Title,
-		"Weather":    g.info.weather.CurrentWeather,
-		"Categories": g.info.bookmarks.Categories,
-		"System":     g.info.system.CurrentSystem,
+		"Title":   g.config.Title,
+		"Weather": g.info.weather.CurrentWeather,
+		"Parsed":  g.info.bookmarks.Parsed,
+		"System":  g.info.system,
 	})
 }
 

+ 11 - 2
static/css/input.css

@@ -10,7 +10,7 @@
     @apply bg-primary-content h-1 rounded-full mt-1;
   }
   .system-icon {
-    @apply h-8 w-8 shrink-0 mr-3 opacity-90 text-secondary;
+    @apply h-8 w-8 shrink-0 mr-3 opacity-90;
   }
   .extra-icon {
     @apply h-3 w-3 shrink-0 mr-2 text-primary;
@@ -18,7 +18,16 @@
   .extra-sun-icon {
     @apply h-4 w-4 shrink-0 -mb-1 mr-2 text-primary;
   }
-  .extra-system-info {
+  .extra-info {
     @apply text-xs truncate text-secondary;
   }
+  .grid-apps {
+    @apply grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4
+  }
+  .hover-effect {
+    @apply no-underline md:hover:underline underline-offset-2 decoration-primary text-sm text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-slate-50 transition-all ease-linear duration-150
+  }
+  .heading{
+    @apply text-lg text-secondary select-none truncate underline decoration-primary underline-offset-4
+  }
 }

+ 2 - 2
system/cpu.go

@@ -19,10 +19,10 @@ func staticCpu() CPU {
 	return p
 }
 
-func (s *System) liveCpu() {
+func (c *Config) liveCpu() {
 	p, err := cpu.Percent(0, false)
 	if err != nil {
 		return
 	}
-	s.CurrentSystem.Live.CPU = math.RoundToEven(p[0])
+	c.System.Live.CPU = math.RoundToEven(p[0])
 }

+ 3 - 3
system/disk.go

@@ -19,11 +19,11 @@ func staticDisk() Disk {
 	return result
 }
 
-func (s *System) liveDisk() {
+func (c *Config) liveDisk() {
 	d, err := disk.Usage("/")
 	if err != nil {
 		return
 	}
-	s.CurrentSystem.Live.Disk.Value = readableSize(d.Used)
-	s.CurrentSystem.Live.Disk.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(d.Used), float64(d.Total)))
+	c.System.Live.Disk.Value = readableSize(d.Used)
+	c.System.Live.Disk.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(d.Used), float64(d.Total)))
 }

+ 3 - 3
system/ram.go

@@ -21,11 +21,11 @@ func staticRam() Ram {
 	return result
 }
 
-func (s *System) liveRam() {
+func (c *Config) liveRam() {
 	r, err := mem.VirtualMemory()
 	if err != nil {
 		return
 	}
-	s.CurrentSystem.Live.Ram.Value = readableSize(r.Used)
-	s.CurrentSystem.Live.Ram.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(r.Used), float64(r.Total)))
+	c.System.Live.Ram.Value = readableSize(r.Used)
+	c.System.Live.Ram.Percentage = math.RoundToEven(percent.PercentOfFloat(float64(r.Used), float64(r.Total)))
 }

+ 16 - 16
system/system.go

@@ -7,30 +7,30 @@ import (
 )
 
 func NewSystemService(enabled bool, logging *zap.SugaredLogger, hub *hub.Hub) *System {
-	var s System
+	var s Config
 	if enabled {
-		s = System{log: logging, hub: hub}
+		s = Config{log: logging, hub: hub}
 		s.Initialize()
 	}
-	return &s
+	return &s.System
 }
 
-func (s *System) UpdateLiveInformation() {
+func (c *Config) UpdateLiveInformation() {
 	for {
-		s.liveCpu()
-		s.liveRam()
-		s.liveDisk()
-		s.uptime()
-		s.hub.LiveInformationCh <- hub.Message{WsType: hub.System, Message: s.CurrentSystem.Live}
+		c.liveCpu()
+		c.liveRam()
+		c.liveDisk()
+		c.uptime()
+		c.hub.LiveInformationCh <- hub.Message{WsType: hub.System, Message: c.System.Live}
 		time.Sleep(1 * time.Second)
 	}
 }
 
-func (s *System) Initialize() {
-	s.CurrentSystem.Static.Host = staticHost()
-	s.CurrentSystem.Static.CPU = staticCpu()
-	s.CurrentSystem.Static.Ram = staticRam()
-	s.CurrentSystem.Static.Disk = staticDisk()
-	go s.UpdateLiveInformation()
-	s.log.Debugw("system updated", "cpu", s.CurrentSystem.Static.CPU.Name, "arch", s.CurrentSystem.Static.Host.Architecture)
+func (c *Config) Initialize() {
+	c.System.Static.Host = staticHost()
+	c.System.Static.CPU = staticCpu()
+	c.System.Static.Ram = staticRam()
+	c.System.Static.Disk = staticDisk()
+	go c.UpdateLiveInformation()
+	c.log.Debugw("system updated", "cpu", c.System.Static.CPU.Name, "arch", c.System.Static.Host.Architecture)
 }

+ 5 - 5
system/types.go

@@ -5,13 +5,13 @@ import (
 	"godash/hub"
 )
 
-type System struct {
-	hub           *hub.Hub
-	log           *zap.SugaredLogger
-	CurrentSystem CurrentSystem
+type Config struct {
+	hub    *hub.Hub
+	log    *zap.SugaredLogger
+	System System
 }
 
-type CurrentSystem struct {
+type System struct {
 	Live   LiveInformation   `json:"live"`
 	Static StaticInformation `json:"static"`
 }

+ 6 - 6
system/uptime.go

@@ -4,14 +4,14 @@ import (
 	"github.com/shirou/gopsutil/v3/host"
 )
 
-func (s *System) uptime() {
+func (c *Config) uptime() {
 	i, err := host.Info()
 	if err != nil {
 		return
 	}
-	s.CurrentSystem.Live.Uptime.Days = i.Uptime / 84600
-	s.CurrentSystem.Live.Uptime.Hours = uint16((i.Uptime % 86400) / 3600)
-	s.CurrentSystem.Live.Uptime.Minutes = uint16(((i.Uptime % 86400) % 3600) / 60)
-	s.CurrentSystem.Live.Uptime.Seconds = uint16(((i.Uptime % 86400) % 3600) % 60)
-	s.CurrentSystem.Live.Uptime.Percentage = float32((s.CurrentSystem.Live.Uptime.Minutes*100)+s.CurrentSystem.Live.Uptime.Seconds) / 60
+	c.System.Live.Uptime.Days = i.Uptime / 84600
+	c.System.Live.Uptime.Hours = uint16((i.Uptime % 86400) / 3600)
+	c.System.Live.Uptime.Minutes = uint16(((i.Uptime % 86400) % 3600) / 60)
+	c.System.Live.Uptime.Seconds = uint16(((i.Uptime % 86400) % 3600) % 60)
+	c.System.Live.Uptime.Percentage = float32((c.System.Live.Uptime.Minutes*100)+c.System.Live.Uptime.Seconds) / 60
 }

+ 1 - 1
tailwind.config.js

@@ -15,7 +15,7 @@ module.exports = {
         },
         dark: {
           ...require("daisyui/src/colors/themes")["[data-theme=halloween]"],
-          secondary: "#b9b9b9",
+          secondary: "#a0a0a0",
         },
       },
     ],

+ 1 - 1
templates/_base.gohtml

@@ -24,7 +24,7 @@
     </head>
 
     <body>
-      <div class="mx-auto container px-5 lg:px-8 my-3 md:my-10 lg:my-14 xl:my-20">{{ template "content" . }}</div>
+      <div class="mx-auto container px-5 lg:px-8 my-3 md:my-6 lg:my-10 xl:my-14">{{ template "content" . }}</div>
     </body>
   </html>
 {{ end }}

+ 120 - 106
templates/index.gohtml

@@ -6,138 +6,152 @@
 
 {{ define "content" }}
 
-  {{ if .Weather.Icon }}
-    {{ template "weatherIcons" . }}
+  <div class="grid gap-10">
+    {{ if .Weather.Icon }}
+      {{ template "weatherIcons" . }}
 
 
-    <div class="flex items-center mb-6 md:mb-10 select-none">
-      <svg class="h-12 w-12 shrink-0 mr-4 md:w-14 md:h-14">
-        <use id="weatherIcon" class="text-secondary" xlink:href="#{{ .Weather.Icon }}"></use>
-      </svg>
-      <div>
-        <div class="text-4xl md:text-4xl">
-          <span id="weatherTemp">{{ .Weather.Temp }}</span> {{ .Weather.Units }}
-        </div>
-        <div class="flex items-center gap-5 text-xs">
-          <div class="flex items-center">
-            <svg class="extra-icon">
-              <use xlink:href="#quote"></use>
-            </svg>
-            <div id="weatherDescription">{{ .Weather.Description }}</div>
-          </div>
-          <div class="flex items-center">
-            <svg class="extra-icon">
-              <use xlink:href="#humidity"></use>
-            </svg>
-            <div id="weatherHumidity">{{ .Weather.Humidity }}%</div>
-          </div>
-          <div class="hidden sm:flex items-center">
-            <svg class="extra-sun-icon">
-              <use xlink:href="#sunrise"></use>
-            </svg>
-            <div id="weatherSunrise">{{ .Weather.Sunrise }}</div>
+      <div class="flex items-center select-none">
+        <svg class="h-12 w-12 shrink-0 mr-4 md:w-14 md:h-14">
+          <use id="weatherIcon" xlink:href="#{{ .Weather.Icon }}"></use>
+        </svg>
+        <div>
+          <div class="text-4xl md:text-4xl">
+            <span id="weatherTemp">{{ .Weather.Temp }}</span> {{ .Weather.Units }}
           </div>
-          <div class="hidden sm:flex items-center">
-            <svg class="extra-sun-icon">
-              <use xlink:href="#sunset"></use>
-            </svg>
-            <div id="weatherSunset">{{ .Weather.Sunset }}</div>
+          <div class="flex items-center gap-5 text-xs">
+            <div class="flex items-center">
+              <svg class="extra-icon">
+                <use xlink:href="#quote"></use>
+              </svg>
+              <div id="weatherDescription" class="extra-info">{{ .Weather.Description }}</div>
+            </div>
+            <div class="flex items-center">
+              <svg class="extra-icon">
+                <use xlink:href="#humidity"></use>
+              </svg>
+              <div id="weatherHumidity" class="extra-info">{{ .Weather.Humidity }}%</div>
+            </div>
+            <div class="hidden sm:flex items-center">
+              <svg class="extra-sun-icon">
+                <use xlink:href="#sunrise"></use>
+              </svg>
+              <div id="weatherSunrise" class="extra-info">{{ .Weather.Sunrise }}</div>
+            </div>
+            <div class="hidden sm:flex items-center">
+              <svg class="extra-sun-icon">
+                <use xlink:href="#sunset"></use>
+              </svg>
+              <div id="weatherSunset" class="extra-info">{{ .Weather.Sunset }}</div>
+            </div>
           </div>
         </div>
       </div>
-    </div>
-  {{ end }}
+    {{ end }}
 
-  {{ if .System.Static.Host.Architecture }}
-    {{ template "systemIcons" . }}
+    {{ if .System.Static.Host.Architecture }}
+      {{ template "systemIcons" . }}
 
 
-    <div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3 mb-6 md:mb-10 select-none">
-      <div class="flex items-center">
-        <svg class="system-icon">
-          <use xlink:href="#cpu"></use>
-        </svg>
-        <div class="w-full truncate">
-          <div class="extra-system-info">{{ .System.Static.CPU.Threads }}</div>
-          <div class="truncate">{{ .System.Static.CPU.Name }}</div>
-          <div class="progress-bar-wrapper">
-            <div id="systemCpuPercentage" class="progress-bar" style="width: {{ .System.Live.CPU }}%"></div>
+      <div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3 select-none">
+        <div class="flex items-center">
+          <svg class="system-icon">
+            <use xlink:href="#cpu"></use>
+          </svg>
+          <div class="w-full truncate">
+            <div class="extra-info">{{ .System.Static.CPU.Threads }}</div>
+            <div class="truncate">{{ .System.Static.CPU.Name }}</div>
+            <div class="progress-bar-wrapper">
+              <div id="systemCpuPercentage" class="progress-bar" style="width: {{ .System.Live.CPU }}%"></div>
+            </div>
           </div>
         </div>
-      </div>
-      <div class="flex items-center">
-        <svg class="system-icon">
-          <use xlink:href="#ram"></use>
-        </svg>
-        <div class="w-full truncate">
-          <div class="extra-system-info">{{ .System.Static.Ram.Swap }}</div>
-          <div class="truncate">
-            <span id="systemRamValue">{{ .System.Live.Ram.Value }}</span> /
-            {{ .System.Static.Ram.Total }}
-          </div>
-          <div class="progress-bar-wrapper">
-            <div id="systemRamPercentage" class="progress-bar" style="width: {{ .System.Live.Ram.Percentage }}%"></div>
+        <div class="flex items-center">
+          <svg class="system-icon">
+            <use xlink:href="#ram"></use>
+          </svg>
+          <div class="w-full truncate">
+            <div class="extra-info">{{ .System.Static.Ram.Swap }}</div>
+            <div class="truncate">
+              <span id="systemRamValue">{{ .System.Live.Ram.Value }}</span> /
+              {{ .System.Static.Ram.Total }}
+            </div>
+            <div class="progress-bar-wrapper">
+              <div id="systemRamPercentage" class="progress-bar" style="width: {{ .System.Live.Ram.Percentage }}%"></div>
+            </div>
           </div>
         </div>
-      </div>
 
-      <div class="flex items-center">
-        <svg class="system-icon">
-          <use xlink:href="#disk"></use>
-        </svg>
-        <div class="w-full truncate">
-          <div class="extra-system-info">{{ .System.Static.Disk.Partitions }}</div>
-          <div class="truncate">
-            <span id="systemDiskValue">{{ .System.Live.Disk.Value }}</span> /
-            {{ .System.Static.Disk.Total }}
-          </div>
-          <div class="progress-bar-wrapper">
-            <div id="systemDiskPercentage" class="progress-bar" style="width: {{ .System.Live.Disk.Percentage }}%"></div>
+        <div class="flex items-center">
+          <svg class="system-icon">
+            <use xlink:href="#disk"></use>
+          </svg>
+          <div class="w-full truncate">
+            <div class="extra-info">{{ .System.Static.Disk.Partitions }}</div>
+            <div class="truncate">
+              <span id="systemDiskValue">{{ .System.Live.Disk.Value }}</span> /
+              {{ .System.Static.Disk.Total }}
+            </div>
+            <div class="progress-bar-wrapper">
+              <div id="systemDiskPercentage" class="progress-bar" style="width: {{ .System.Live.Disk.Percentage }}%"></div>
+            </div>
           </div>
         </div>
-      </div>
 
-      <div class="flex items-center">
-        <svg class="system-icon">
-          <use xlink:href="#server"></use>
-        </svg>
-        <div class="w-full truncate">
-          <div class="extra-system-info">{{ .System.Static.Host.Architecture }}</div>
-          <div class="flex items-center gap-2 truncate">
-            <div class="truncate">
-              <span><span id="uptimeDays">{{ .System.Live.Uptime.Days }}</span> days</span>
-              <span class="countdown"><span id="uptimeHours" style="--value:{{ .System.Live.Uptime.Hours }};"></span></span> hours
-              <span class="countdown"><span id="uptimeMinutes" style="--value:{{ .System.Live.Uptime.Minutes }};"></span></span> min
-              <span class="countdown"><span id="uptimeSeconds" style="--value:{{ .System.Live.Uptime.Seconds }};"></span></span> sec
+        <div class="flex items-center">
+          <svg class="system-icon">
+            <use xlink:href="#server"></use>
+          </svg>
+          <div class="w-full truncate">
+            <div class="extra-info">{{ .System.Static.Host.Architecture }}</div>
+            <div class="flex items-center gap-2 truncate">
+              <div class="truncate">
+                <span><span id="uptimeDays">{{ .System.Live.Uptime.Days }}</span> days</span>
+                <span class="countdown"><span id="uptimeHours" style="--value:{{ .System.Live.Uptime.Hours }};"></span></span> hours
+                <span class="countdown"><span id="uptimeMinutes" style="--value:{{ .System.Live.Uptime.Minutes }};"></span></span> min
+                <span class="countdown"><span id="uptimeSeconds" style="--value:{{ .System.Live.Uptime.Seconds }};"></span></span> sec
+              </div>
+            </div>
+            <div class="progress-bar-wrapper">
+              <div id="systemUptimePercentage" class="progress-bar" style="width: {{ .System.Live.Uptime.Percentage }}%"></div>
             </div>
-          </div>
-          <div class="progress-bar-wrapper">
-            <div id="systemUptimePercentage" class="progress-bar" style="width: {{ .System.Live.Uptime.Percentage }}%"></div>
           </div>
         </div>
       </div>
-    </div>
-  {{ end }}
+    {{ end }}
+
 
+    <div class="grid gap-4">
+      {{ range .Parsed.Applications }}
+        <div class="grid gap-1">
+          {{ if .Category }}
+            <div class="heading">{{ .Category }}</div>
+          {{ end }}
+          <div class="grid-apps">
+            {{ range .Entries }}
+              <a href="{{ .URL }}" class="bookmark-link flex items-center hover-effect">
+                <div class="img rounded-md w-8 h-8 bg-cover bg-center opacity-90" style="background-image: url({{ .Icon }})"></div>
+                <div class="uppercase truncate ml-2">{{ .Name }}</div>
+              </a>
+            {{ end }}
+          </div>
+        </div>
+      {{ end }}
+    </div>
 
-  <div class="grid gap-4">
-    {{ range .Categories }}
-      <div class="grid gap-1">
-        {{ if .Category }}
-          <div class="text-lg text-secondary select-none truncate">{{ .Category }}</div>
-        {{ end }}
-        <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-4">
+    <div class="grid-apps">
+      {{ range .Parsed.Links }}
+        <div class="flex flex-col gap-1">
+          {{ if .Category }}
+            <div class="heading">{{ .Category }}</div>
+          {{ end }}
           {{ range .Entries }}
-            <a
-              href="{{ .Url }}"
-              class="bookmark-link flex items-center no-underline md:hover:underline underline-offset-2 decoration-primary text-sm text-slate-700 dark:text-slate-300 hover:text-slate-900 dark:hover:text-slate-50 transition-all ease-linear duration-150"
-            >
-              <div class="img rounded-md w-8 h-8 bg-cover bg-center opacity-90" style="background-image: url({{ .Icon }})"></div>
-              <div class="uppercase truncate ml-2">{{ .Name }}</div>
+            <a href="{{ .URL }}" class="hover-effect">
+              <div class="uppercase truncate">{{ .Name }}</div>
             </a>
           {{ end }}
         </div>
-      </div>
-    {{ end }}
+      {{ end }}
+    </div>
   </div>
 {{ end }}