diff --git a/go.mod b/go.mod index da184f8..bce00a0 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( require ( github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/wcharczuk/go-chart/v2 v2.1.1 // indirect golang.org/x/image v0.11.0 // indirect ) diff --git a/go.sum b/go.sum index 3455de0..76ffb87 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/wcharczuk/go-chart/v2 v2.1.1 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE= github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/lib/host/charts.go b/lib/host/charts.go index 5e8d255..87b0c86 100644 --- a/lib/host/charts.go +++ b/lib/host/charts.go @@ -1,6 +1,7 @@ package host import ( + "fmt" "log" "strings" @@ -13,13 +14,19 @@ import ( func (h *Host) ChartMemory() string { h.getNodeInfo() log.Println("Generating Chart") + memFree := float64(h.NodeMemory.Free) + memCached := float64(h.NodeMemory.Cached) + memBuffer := float64(h.NodeMemory.Buffers) + memTotal := float64(h.NodeMemory.Total) + c := chart.PieChart{ - Width: 128, - Height: 128, + Title: fmt.Sprintf("Memory Info %s", h.SystemHostName), + Width: 256, + Height: 256, Values: []chart.Value{ - {Value: float64(h.NodeMemory.Free) / float64(h.NodeMemory.Total), Label: "Free"}, - {Value: float64(h.NodeMemory.Cached) / float64(h.NodeMemory.Total), Label: "Cached"}, - {Value: float64(h.NodeMemory.Buffers) / float64(h.NodeMemory.Total), Label: "Buffers"}, + {Value: memTotal - memFree, Label: fmt.Sprintf("%.2f%% Free", memFree/memTotal*100)}, + {Value: memTotal - memCached, Label: fmt.Sprintf("%.2f%% Cached", memCached/memTotal*100)}, + {Value: memTotal - memBuffer, Label: fmt.Sprintf("%.2f%% Buffers", memBuffer/memTotal*100)}, }, } sb := new(strings.Builder) diff --git a/lib/host/lib.go b/lib/host/lib.go index 364f885..c9143b2 100644 --- a/lib/host/lib.go +++ b/lib/host/lib.go @@ -232,13 +232,13 @@ func (h *Host) getInfo() { infoFuncs := []func(){ h.getDevicesInfo, - h.getDomainInfo, +// h.getDomainInfo, h.getIfaceInfo, h.getNetsInfo, h.getNodeInfo, - h.getSEVInfo, - h.getSecretsInfo, - h.getStoragePools, +// h.getSEVInfo, +// h.getSecretsInfo, +// h.getStoragePools, } for _, f := range infoFuncs { diff --git a/main.go b/main.go index 2d9e3de..de742bc 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,14 @@ package main import ( + "context" + "fmt" "log" "net/http" "git.staur.ca/stobbsm/clustvirt/lib/host" + "git.staur.ca/stobbsm/clustvirt/view" "git.staur.ca/stobbsm/clustvirt/view/components" - "git.staur.ca/stobbsm/clustvirt/view/layouts" "git.staur.ca/stobbsm/clustvirt/view/static" "github.com/a-h/templ" "github.com/go-chi/chi/v5" @@ -18,22 +20,11 @@ const DEBUG bool = true func main() { log.Println("Starting clustvirt, the libvirt cluster manager") - venus, err := host.ConnectHost(host.URI_QEMU_SSH_SYSTEM, "venus.staur.ca") - if err != nil { - log.Fatal(err) - } - log.Println("Connected to host `venus.staur.ca`") - defer venus.Close() - //lm, err := venus.GetGuestByName("logan-minecraft") - //if err != nil { - // log.Fatal(err) - //} - //defer lm.Close() - // Start webserver and serve homepage defaultNavBar := []components.NavItem{ {Name: "Home", Href: "/"}, + {Name: "Hosts", Href: "/hostinfo"}, {Name: "About", Href: "/about"}, } fs := http.StripPrefix("/static/", http.FileServer(http.Dir("public"))) @@ -47,9 +38,20 @@ func main() { defer r.Body.Close() fs.ServeHTTP(w, r) }) - r.Get("/", templ.Handler(layouts.Manager("Cluster Manager", "ClustVirt", defaultNavBar)).ServeHTTP) + r.Get("/", templ.Handler(view.HostMain(defaultNavBar)).ServeHTTP) r.Get("/about", templ.Handler(static.Home()).ServeHTTP) - r.Get("/chart", templ.Handler(components.HostInfo(venus)).ServeHTTP) + + r.Route("/htmx", func(r chi.Router) { + r.Get("/host/{hostname}", func(w http.ResponseWriter, r *http.Request) { + rhost, err := host.ConnectHost(host.URI_QEMU_SSH_SYSTEM, chi.URLParam(r, "hostname")) + if err != nil { + http.Error(w, fmt.Sprintf("error while getting host: %s", err), http.StatusInternalServerError) + return + } + defer rhost.Close() + log.Println("Rendering HostInfo", view.HostInfo(rhost).Render(context.Background(), w)) + }) + }) log.Println(http.ListenAndServe(":3000", r)) } diff --git a/public/css/style.css b/public/css/style.css index 10a004f..a1a91a3 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -822,6 +822,14 @@ span>a:visited { position: static; } +.absolute { + position: absolute; +} + +.bottom-0 { + bottom: 0px; +} + .order-2 { order: 2; } @@ -830,6 +838,10 @@ span>a:visited { order: 3; } +.m-1 { + margin: 0.25rem; +} + .mx-4 { margin-left: 1rem; margin-right: 1rem; @@ -857,6 +869,18 @@ span>a:visited { height: 16rem; } +.size-full { + width: 100%; + height: 100%; +} + +.size-max { + width: -moz-max-content; + width: max-content; + height: -moz-max-content; + height: max-content; +} + .h-28 { height: 7rem; } @@ -869,6 +893,51 @@ span>a:visited { height: 100%; } +.h-lvh { + height: 100lvh; +} + +.h-svh { + height: 100svh; +} + +.h-dvh { + height: 100dvh; +} + +.h-max { + height: -moz-max-content; + height: max-content; +} + +.h-48 { + height: 12rem; +} + +.h-screen { + height: 100vh; +} + +.min-h-80 { + min-height: 20rem; +} + +.w-1\/4 { + width: 25%; +} + +.w-3\/4 { + width: 75%; +} + +.w-full { + width: 100%; +} + +.w-1\/6 { + width: 16.666667%; +} + .flex-auto { flex: 1 1 auto; } @@ -901,6 +970,10 @@ span>a:visited { list-style-image: url("/static/icons/list-possible.svg"); } +.flex-row { + flex-direction: row; +} + .flex-col { flex-direction: column; } @@ -917,6 +990,10 @@ span>a:visited { align-items: center; } +.justify-end { + justify-content: flex-end; +} + .justify-between { justify-content: space-between; } @@ -8943,6 +9020,10 @@ span>a:visited { border-color: rgb(51 51 30 / 0.95); } +.justify-self-end { + justify-self: end; +} + .rounded { border-radius: 0.25rem; } @@ -8951,6 +9032,35 @@ span>a:visited { border-radius: 9999px; } +.rounded-none { + border-radius: 0px; +} + +.border-2 { + border-width: 2px; +} + +.border { + border-width: 1px; +} + +.border-solid { + border-style: solid; +} + +.border-dashed { + border-style: dashed; +} + +.border-dotted { + border-style: dotted; +} + +.border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(239 68 68 / var(--tw-border-opacity)); +} + .border-uiblue-100 { --tw-border-opacity: 1; border-color: rgb(221 231 248 / var(--tw-border-opacity)); @@ -138560,6 +138670,20 @@ span>a:visited { padding: 0.5rem; } +.p-1 { + padding: 0.25rem; +} + +.px-2 { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + .text-2xl { font-size: 1.5rem; line-height: 2rem; diff --git a/view/components/hostinfo.templ b/view/components/hostinfo.templ deleted file mode 100644 index 05a3b80..0000000 --- a/view/components/hostinfo.templ +++ /dev/null @@ -1,21 +0,0 @@ -package components - -import ( - "fmt" - "git.staur.ca/stobbsm/clustvirt/lib/host" -) - -// HostInfo is meant to be an HTMX response -templ HostInfo(h *host.Host) { - -
- @templ.Raw(h.ChartMemory()) -
- - -} diff --git a/view/components/hostinfo_templ.go b/view/components/hostinfo_templ.go deleted file mode 100644 index 7470e90..0000000 --- a/view/components/hostinfo_templ.go +++ /dev/null @@ -1,118 +0,0 @@ -// Code generated by templ - DO NOT EDIT. - -// templ: version: v0.2.598 -package components - -//lint:file-ignore SA4006 This context is only used if a nested component is present. - -import "github.com/a-h/templ" -import "context" -import "io" -import "bytes" - -import ( - "fmt" - "git.staur.ca/stobbsm/clustvirt/lib/host" -) - -// HostInfo is meant to be an HTMX response -func HostInfo(h *host.Host) templ.Component { - return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) - if !templ_7745c5c3_IsBuffer { - templ_7745c5c3_Buffer = templ.GetBuffer() - defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var1 := templ.GetChildren(ctx) - if templ_7745c5c3_Var1 == nil { - templ_7745c5c3_Var1 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var2 = []any{"size-64"} - templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templ.Raw(h.ChartMemory()).Render(ctx, templ_7745c5c3_Buffer) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - if !templ_7745c5c3_IsBuffer { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) - } - return templ_7745c5c3_Err - }) -} diff --git a/view/hostinfo.templ b/view/hostinfo.templ new file mode 100644 index 0000000..d1670e6 --- /dev/null +++ b/view/hostinfo.templ @@ -0,0 +1,51 @@ +package view + +import ( + "git.staur.ca/stobbsm/clustvirt/lib/host" + bf "github.com/labstack/gommon/bytes" + "git.staur.ca/stobbsm/clustvirt/view/components" + "git.staur.ca/stobbsm/clustvirt/view/layouts" +) + +// MemChart get's the memory pi chart from the host +templ MemChart(h *host.Host) { +
+
+ @templ.Raw(h.ChartMemory()) +
+ +
+} + +// HostConnect is the page that allows us to select a host to get information from +templ HostMain(navBarItems []components.NavItem) { + @layouts.Manager("ClustVirt", "Cluster Manager", navBarItems) { +
+
+ +
+
+

This is where you can see a system overview of all available hosts

+

+ For now, there is just this simple box to choose a host to connect to + and push the button to load the system information via HTMX +

+
+
+ } +} + +// HostInfo is meant to be an HTMX response +templ HostInfo(h *host.Host) { +

{ h.HostName }

+ @MemChart(h) +} diff --git a/view/hostinfo_templ.go b/view/hostinfo_templ.go new file mode 100644 index 0000000..f65836a --- /dev/null +++ b/view/hostinfo_templ.go @@ -0,0 +1,262 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.598 +package view + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import "context" +import "io" +import "bytes" + +import ( + "git.staur.ca/stobbsm/clustvirt/lib/host" + "git.staur.ca/stobbsm/clustvirt/view/components" + "git.staur.ca/stobbsm/clustvirt/view/layouts" + bf "github.com/labstack/gommon/bytes" +) + +// MemChart get's the memory pi chart from the host +func MemChart(h *host.Host) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var2 = []any{"flex", "flex-row"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var3 = []any{"size-64"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.Raw(h.ChartMemory()).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +// HostConnect is the page that allows us to select a host to get information from +func HostMain(navBarItems []components.NavItem) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var9 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + var templ_7745c5c3_Var10 = []any{"flex", "flex-row", "h-full"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 = []any{"w-1/6", "border-uigrey-600", "border", "rounded", "border-dotted", "p-1"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 = []any{"w-3/4", "px-2"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

This is where you can see a system overview of all available hosts

For now, there is just this simple box to choose a host to connect to and push the button to load the system information via HTMX

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = layouts.Manager("ClustVirt", "Cluster Manager", navBarItems).Render(templ.WithChildren(ctx, templ_7745c5c3_Var9), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} + +// HostInfo is meant to be an HTMX response +func HostInfo(h *host.Host) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) { + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer) + if !templ_7745c5c3_IsBuffer { + templ_7745c5c3_Buffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templ_7745c5c3_Buffer) + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var13 := templ.GetChildren(ctx) + if templ_7745c5c3_Var13 == nil { + templ_7745c5c3_Var13 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(h.HostName) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/hostinfo.templ`, Line: 48, Col: 17} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = MemChart(h).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if !templ_7745c5c3_IsBuffer { + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W) + } + return templ_7745c5c3_Err + }) +} diff --git a/view/layouts/manager.templ b/view/layouts/manager.templ index 9897406..60268ad 100644 --- a/view/layouts/manager.templ +++ b/view/layouts/manager.templ @@ -3,21 +3,27 @@ package layouts import "git.staur.ca/stobbsm/clustvirt/view/components" templ Manager(title string, subtitle string, navBarItem []components.NavItem) { - - - - ClustVirt - - - - -
- @header(title, subtitle, navBarItem) -
- - - - + + + + ClustVirt + + + +
+
+ @header(title, subtitle, navBarItem) +
+
+ { children... } +
+ +
+ + + + } diff --git a/view/layouts/manager_templ.go b/view/layouts/manager_templ.go index b990c32..4675b1f 100644 --- a/view/layouts/manager_templ.go +++ b/view/layouts/manager_templ.go @@ -46,16 +46,33 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var3 = []any{"mx-4"} + var templ_7745c5c3_Var3 = []any{"flex", "flex-col", "h-screen"} templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var3...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var4 = []any{"px-4"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 = []any{"px-4", "bottom-0", "w-full", "justify-self-end"} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -80,7 +122,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var4).String())) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ.CSSClasses(templ_7745c5c3_Var6).String())) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -92,7 +134,7 @@ func Manager(title string, subtitle string, navBarItem []components.NavItem) tem if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }