@@ -26,15 +26,17 @@ func P2PNodeStats(nodes []schema.NodeData) string {
2626 }
2727 }
2828
29- class := "text-blue -400"
29+ class := "text-green -400"
3030 if online == 0 {
3131 class = "text-red-400"
32+ } else if online < len (nodes ) {
33+ class = "text-yellow-400"
3234 }
3335
3436 nodesElements := []elem.Node {
3537 elem .Span (
3638 attrs.Props {
37- "class" : class + " font-bold text-xl " ,
39+ "class" : class + " font-bold text-2xl " ,
3840 },
3941 elem .Text (fmt .Sprintf ("%d" , online )),
4042 ),
@@ -50,76 +52,105 @@ func P2PNodeStats(nodes []schema.NodeData) string {
5052}
5153
5254func P2PNodeBoxes (nodes []schema.NodeData ) string {
53- nodesElements := []elem.Node {}
55+ if len (nodes ) == 0 {
56+ return `<div class="col-span-full flex flex-col items-center justify-center py-12 text-center bg-gray-800/50 border border-gray-700/50 rounded-xl">
57+ <i class="fas fa-server text-gray-500 text-4xl mb-4"></i>
58+ <p class="text-gray-400 text-lg font-medium">No nodes available</p>
59+ <p class="text-gray-500 text-sm mt-2">Start some workers to see them here</p>
60+ </div>`
61+ }
5462
63+ render := ""
5564 for _ , n := range nodes {
5665 nodeID := bluemonday .StrictPolicy ().Sanitize (n .ID )
5766
5867 // Define status-specific classes
5968 statusIconClass := "text-green-400"
6069 statusText := "Online"
6170 statusTextClass := "text-green-400"
71+ cardHoverClass := "hover:shadow-green-500/20 hover:border-green-400/50"
6272
6373 if ! n .IsOnline () {
6474 statusIconClass = "text-red-400"
6575 statusText = "Offline"
6676 statusTextClass = "text-red-400"
77+ cardHoverClass = "hover:shadow-red-500/20 hover:border-red-400/50"
6778 }
6879
69- nodesElements = append (nodesElements ,
80+ nodeCard := elem .Div (
81+ attrs.Props {
82+ "class" : "bg-gradient-to-br from-gray-800/90 to-gray-900/80 border border-gray-700/50 rounded-xl p-5 shadow-xl transition-all duration-300 " + cardHoverClass + " backdrop-blur-sm" ,
83+ },
84+ // Header with node icon and status
7085 elem .Div (
7186 attrs.Props {
72- "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 " ,
87+ "class" : "flex items-center justify-between mb-4 " ,
7388 },
74- // Node ID and status indicator in top row
89+ // Node info
7590 elem .Div (
7691 attrs.Props {
77- "class" : "flex items-center justify-between mb-3 " ,
92+ "class" : "flex items-center" ,
7893 },
79- // Node ID with icon
8094 elem .Div (
8195 attrs.Props {
82- "class" : "flex items-center" ,
96+ "class" : "w-10 h-10 bg-blue-500/20 rounded-lg flex items-center justify-center mr-3 " ,
8397 },
8498 elem .I (
8599 attrs.Props {
86- "class" : "fas fa-server text-blue-400 mr-2" ,
87- },
88- ),
89- elem .Span (
90- attrs.Props {
91- "class" : "text-white font-medium" ,
100+ "class" : "fas fa-server text-blue-400 text-lg" ,
92101 },
93- elem .Text (nodeID ),
94102 ),
95103 ),
96- // Status indicator
97104 elem .Div (
98- attrs.Props {
99- "class" : "flex items-center" ,
100- },
101- elem .I (
105+ attrs.Props {},
106+ elem .H4 (
102107 attrs.Props {
103- "class" : "fas fa-circle animate-pulse " + statusIconClass + " mr-1.5 " ,
108+ "class" : "text-white font-semibold text-sm " ,
104109 },
110+ elem .Text ("Node" ),
105111 ),
106- elem .Span (
112+ elem .P (
107113 attrs.Props {
108- "class" : statusTextClass ,
114+ "class" : "text-gray-400 text-xs font-mono break-all" ,
109115 },
110- elem .Text (statusText ),
116+ elem .Text (nodeID ),
111117 ),
112118 ),
113119 ),
114- // Bottom section with timestamp
120+ // Status badge
115121 elem .Div (
116122 attrs.Props {
117- "class" : "text-xs text -gray-400 pt-1 border-t border-gray-700/30 " ,
123+ "class" : "flex items-center bg -gray-900/50 rounded-full px-3 py-1.5 border border-gray-700/50 " ,
118124 },
119- elem .Text ("Last updated: " + time .Now ().UTC ().Format ("2006-01-02 15:04:05" )),
125+ elem .I (
126+ attrs.Props {
127+ "class" : "fas fa-circle animate-pulse " + statusIconClass + " mr-2 text-xs" ,
128+ },
129+ ),
130+ elem .Span (
131+ attrs.Props {
132+ "class" : statusTextClass + " text-xs font-medium" ,
133+ },
134+ elem .Text (statusText ),
135+ ),
120136 ),
121- ))
137+ ),
138+ // Footer with timestamp
139+ elem .Div (
140+ attrs.Props {
141+ "class" : "text-xs text-gray-500 pt-3 border-t border-gray-700/30 flex items-center" ,
142+ },
143+ elem .I (
144+ attrs.Props {
145+ "class" : "fas fa-clock mr-2" ,
146+ },
147+ ),
148+ elem .Text ("Updated: " + time .Now ().UTC ().Format ("15:04:05" )),
149+ ),
150+ )
151+
152+ render += nodeCard .Render ()
122153 }
123154
124- return renderElements ( nodesElements )
155+ return render
125156}
0 commit comments