feat(ui): complete design overhaul (#4942)

This PR changes entirely the UI look and feeling. It updates all
sections and makes it also mobile-ready.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto 2025-03-05 08:27:03 +01:00 committed by GitHub
parent d732e261a4
commit 6b46c52789
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1573 additions and 978 deletions

View file

@ -2,6 +2,7 @@ package elements
import (
"fmt"
"time"
"github.com/chasefleming/elem-go"
"github.com/chasefleming/elem-go/attrs"
@ -18,19 +19,6 @@ func renderElements(n []elem.Node) string {
}
func P2PNodeStats(nodes []p2p.NodeData) string {
/*
<div class="bg-gray-800 p-6 rounded-lg shadow-lg text-left">
<p class="text-xl font-semibold text-gray-200">Total Workers Detected: {{ len .Nodes }}</p>
{{ $online := 0 }}
{{ range .Nodes }}
{{ if .IsOnline }}
{{ $online = add $online 1 }}
{{ end }}
{{ end }}
<p class="text-xl font-semibold text-gray-200">Total Online Workers: {{$online}}</p>
</div>
*/
online := 0
for _, n := range nodes {
if n.IsOnline() {
@ -38,27 +26,21 @@ func P2PNodeStats(nodes []p2p.NodeData) string {
}
}
class := "text-green-500"
class := "text-blue-400"
if online == 0 {
class = "text-red-500"
class = "text-red-400"
}
/*
<i class="fas fa-circle animate-pulse text-green-500 ml-2 mr-1"></i>
*/
circle := elem.I(attrs.Props{
"class": "fas fa-circle animate-pulse " + class + " ml-2 mr-1",
})
nodesElements := []elem.Node{
elem.Span(
attrs.Props{
"class": class,
"class": class + " font-bold text-xl",
},
circle,
elem.Text(fmt.Sprintf("%d", online)),
),
elem.Span(
attrs.Props{
"class": "text-gray-200",
"class": "text-gray-300 text-xl",
},
elem.Text(fmt.Sprintf("/%d", len(nodes))),
),
@ -68,77 +50,73 @@ func P2PNodeStats(nodes []p2p.NodeData) string {
}
func P2PNodeBoxes(nodes []p2p.NodeData) string {
/*
<div class="bg-gray-800 p-4 rounded-lg shadow-lg text-left">
<div class="flex items-center mb-2">
<i class="fas fa-desktop text-gray-400 mr-2"></i>
<span class="text-gray-200 font-semibold">{{.ID}}</span>
</div>
<p class="text-sm text-gray-400 mt-2 flex items-center">
Status:
<i class="fas fa-circle {{ if .IsOnline }}text-green-500{{ else }}text-red-500{{ end }} ml-2 mr-1"></i>
<span class="{{ if .IsOnline }}text-green-400{{ else }}text-red-400{{ end }}">
{{ if .IsOnline }}Online{{ else }}Offline{{ end }}
</span>
</p>
</div>
*/
nodesElements := []elem.Node{}
for _, n := range nodes {
nodeID := bluemonday.StrictPolicy().Sanitize(n.ID)
// Define status-specific classes
statusIconClass := "text-green-400"
statusText := "Online"
statusTextClass := "text-green-400"
if !n.IsOnline() {
statusIconClass = "text-red-400"
statusText = "Offline"
statusTextClass = "text-red-400"
}
nodesElements = append(nodesElements,
elem.Div(
attrs.Props{
"class": "bg-gray-700 p-6 rounded-lg shadow-lg text-left",
"class": "bg-gray-800/80 border border-gray-700/50 rounded-xl p-4 shadow-lg transition-all duration-300 hover:shadow-blue-900/20 hover:border-blue-700/50",
},
elem.P(
// Node ID and status indicator in top row
elem.Div(
attrs.Props{
"class": "text-sm text-gray-400 mt-2 flex",
"class": "flex items-center justify-between mb-3",
},
elem.I(
// Node ID with icon
elem.Div(
attrs.Props{
"class": "fas fa-desktop text-gray-400 mr-2",
"class": "flex items-center",
},
),
elem.Text("Name: "),
elem.Span(
attrs.Props{
"class": "text-gray-200 font-semibold ml-2 mr-1",
},
elem.Text(bluemonday.StrictPolicy().Sanitize(n.ID)),
),
elem.Text("Status: "),
elem.If(
n.IsOnline(),
elem.I(
attrs.Props{
"class": "fas fa-circle animate-pulse text-green-500 ml-2 mr-1",
"class": "fas fa-server text-blue-400 mr-2",
},
),
elem.I(
attrs.Props{
"class": "fas fa-circle animate-pulse text-red-500 ml-2 mr-1",
},
),
),
elem.If(
n.IsOnline(),
elem.Span(
attrs.Props{
"class": "text-green-400",
},
elem.Text("Online"),
),
elem.Span(
attrs.Props{
"class": "text-red-400",
"class": "text-white font-medium",
},
elem.Text("Offline"),
elem.Text(nodeID),
),
),
// Status indicator
elem.Div(
attrs.Props{
"class": "flex items-center",
},
elem.I(
attrs.Props{
"class": "fas fa-circle animate-pulse " + statusIconClass + " mr-1.5",
},
),
elem.Span(
attrs.Props{
"class": statusTextClass,
},
elem.Text(statusText),
),
),
),
// Bottom section with timestamp
elem.Div(
attrs.Props{
"class": "text-xs text-gray-400 pt-1 border-t border-gray-700/30",
},
elem.Text("Last updated: "+time.Now().UTC().Format("2006-01-02 15:04:05")),
),
))
}