Split into category packages; module github.com/ZacharyZhang-NY/MujicaUI
This commit is contained in:
1822 files changed
+24568
-21314
No files matched your search
@@ -0,0 +1,106 @@
|
||||
package devtools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/agent"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/chart"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/core"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/data"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/icons"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/theme"
|
||||
)
|
||||
|
||||
// StatCardOptions configure a StatCard. Label is required.
|
||||
type StatCardOptions struct {
|
||||
Label string
|
||||
// Change is relative; 0.12 means +12%, shown with HasChange.
|
||||
Change float64
|
||||
HasChange bool
|
||||
// LowerIsBetter colors a fall as good, as for latency.
|
||||
LowerIsBetter bool
|
||||
// Trend draws a sparkline; nil hides it.
|
||||
Trend []float64
|
||||
Status data.DataStatus
|
||||
Error string
|
||||
}
|
||||
|
||||
// StatCard shows values, changes, trends, loading and errors.
|
||||
func StatCard(c *ui.Context, value string, opts StatCardOptions) core.ChoiceResult {
|
||||
if opts.Label == "" {
|
||||
panic("mujica: StatCard needs a Label")
|
||||
}
|
||||
if math.IsNaN(opts.Change) || math.IsInf(opts.Change, 0) {
|
||||
panic("mujica: StatCard Change must be finite")
|
||||
}
|
||||
if opts.Status != data.DataReady && opts.Status != data.DataLoading && opts.Status != data.DataFailed {
|
||||
panic(fmt.Sprintf("mujica: StatCard Status %d is not ready, loading or failed", int(opts.Status)))
|
||||
}
|
||||
k := core.Tokens(c)
|
||||
u := core.Density(c).Unit()
|
||||
var r core.ChoiceResult
|
||||
r.Element = agent.AgentCard(c).MinHeight(core.FontSize(c, 116)).MinWidth(180).Label(opts.Label)
|
||||
r.Element.Children(func() {
|
||||
agent.AgentCaption(c, opts.Label)
|
||||
switch opts.Status {
|
||||
case data.DataLoading:
|
||||
ui.Column(c).Grow(1).Justify(ui.Center).Children(func() {
|
||||
core.Spinner(c, core.SpinnerOptions{Label: core.Msg(c, "list.loading"), ShowLabel: true})
|
||||
})
|
||||
return
|
||||
case data.DataFailed:
|
||||
ui.Column(c).Grow(1).Justify(ui.Center).Gap(u).Children(func() {
|
||||
ui.Row(c).Gap(u * 1.5).AlignItems(ui.Center).TextColor(k.Danger).Children(func() {
|
||||
ui.Icon(c, icons.Must("circle-alert")).Size(16, 16)
|
||||
ui.Text(c, data.DataError(c, opts.Error)).Role(ui.RoleStatus).FontSize(core.FontSize(c, theme.CaptionSize+1))
|
||||
})
|
||||
ui.Row(c).Children(func() {
|
||||
r = core.NewChoiceResult(r.Element, agent.AgentToggle(c, core.Msg(c, "list.retry"), "refresh-cw", false))
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
ui.Text(c, value).Font(theme.SerifFont).FontSize(core.FontSize(c, theme.H2Size)).FontWeight(600).FontFeatures("tnum").SingleLine()
|
||||
ui.Row(c).Gap(u * 2).AlignItems(ui.Center).Children(func() {
|
||||
if opts.HasChange {
|
||||
statChange(c, opts.Change, opts.LowerIsBetter)
|
||||
}
|
||||
ui.Box(c).Grow(1)
|
||||
if len(opts.Trend) > 0 {
|
||||
chart.Sparkline(c, opts.Trend, chart.SparklineOptions{Frame: chart.ChartFrame{Label: opts.Label}, Width: 88})
|
||||
}
|
||||
})
|
||||
})
|
||||
if r.Changed() {
|
||||
slog.Debug("mujica: stat_card retry", "label", opts.Label)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// statChange shows a signed percentage and direction arrow.
|
||||
func statChange(c *ui.Context, change float64, lowerIsBetter bool) {
|
||||
k := core.Tokens(c)
|
||||
icon, tone, sign := "minus", k.TextMuted, ""
|
||||
switch {
|
||||
case change > 0:
|
||||
icon, tone, sign = "arrow-up", k.Success, "+"
|
||||
case change < 0:
|
||||
icon, tone = "arrow-down", k.Danger
|
||||
}
|
||||
if lowerIsBetter && change != 0 {
|
||||
if tone == k.Success {
|
||||
tone = k.Danger
|
||||
} else {
|
||||
tone = k.Success
|
||||
}
|
||||
}
|
||||
text := fmt.Sprintf("%s%.1f%%", sign, change*100)
|
||||
ui.Row(c).Gap(core.Density(c).Unit()).AlignItems(ui.Center).Label(fmt.Sprintf(core.Msg(c, "stat_card.change"), text)).Children(func() {
|
||||
ui.Icon(c, icons.Must(icon)).Size(14, 14).TextColor(tone)
|
||||
ui.Text(c, text).TextColor(tone).FontSize(core.FontSize(c, theme.CaptionSize+1)).FontFeatures("tnum")
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user