diff --git a/internal/server/routes.go b/internal/server/routes.go index 0d19465..95e9723 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -15,6 +15,7 @@ import ( "github.com/gofs-cli/template/internal/ui/pages/notfound" "github.com/gofs-cli/template/internal/ui/pages/page1" "github.com/gofs-cli/template/internal/ui/pages/page2" + progressbar "github.com/gofs-cli/template/internal/ui/pages/progress-bar" "github.com/gofs-cli/template/internal/ui/pages/validation" ) @@ -56,6 +57,12 @@ func (s *Server) Routes() { routesMux.Handle("GET /active-search", activesearch.Index()) routesMux.Handle("POST /active-search/search", activesearch.Search()) + // progress bar example + routesMux.Handle("GET /progress-bar", progressbar.Index()) + routesMux.Handle("POST /progress-bar/start", progressbar.StartProgressBar()) + routesMux.Handle("GET /progress-bar/job/progress", progressbar.RunProgressBar()) + routesMux.Handle("GET /progress-bar/job", progressbar.CompleteProgressBar()) + routesMux.Handle("GET /modal", home.Modal()) routesMux.Handle("GET /page1", page1.Index()) diff --git a/internal/ui/pages/progress-bar/handlers.go b/internal/ui/pages/progress-bar/handlers.go new file mode 100644 index 0000000..9c3fc2f --- /dev/null +++ b/internal/ui/pages/progress-bar/handlers.go @@ -0,0 +1,60 @@ +package progressbar + +import ( + "math/rand" + "net/http" + "strconv" + "sync" + + "github.com/a-h/templ" + "github.com/gofs-cli/template/internal/ui" + "github.com/gofs-cli/template/internal/ui/components/header" +) + +type Job struct { + mu sync.Mutex + progress int +} + +// Global variable to store the current job state +var currentJob = &Job{} + +func Index() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + templ.Handler(ui.IndexPage(layout(header.Header(), body()))).ServeHTTP(w, r) + }) +} + +func StartProgressBar() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + currentJob.mu.Lock() + currentJob.progress = 0 + currentJob.mu.Unlock() + + templ.Handler(startProgressBar()).ServeHTTP(w, r) + }) +} + +func RunProgressBar() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + currentJob.mu.Lock() + defer currentJob.mu.Unlock() + + if currentJob.progress < 100 { + currentJob.progress += rand.Intn(16) + } + + if currentJob.progress >= 100 { + w.Header().Set("HX-Trigger", "done") + templ.Handler(inProgress(strconv.Itoa(currentJob.progress))).ServeHTTP(w, r) + } else { + templ.Handler(inProgress(strconv.Itoa(currentJob.progress))).ServeHTTP(w, r) + } + }) +} + +func CompleteProgressBar() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + templ.Handler(completeProgressBar()).ServeHTTP(w, r) + }) +} diff --git a/internal/ui/pages/progress-bar/index.templ b/internal/ui/pages/progress-bar/index.templ new file mode 100644 index 0000000..5d691d2 --- /dev/null +++ b/internal/ui/pages/progress-bar/index.templ @@ -0,0 +1,98 @@ +package progressbar + +import "fmt" + +css classLayout() { + display: grid; +} + +css progress() { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + box-shadow: inset 0 1px 2px rgba(0,0,0,.1); +} + +css progressbar() { + float: left; + width: 0%; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #337ab7; + -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); + -webkit-transition: width .6s ease; + -o-transition: width .6s ease; + transition: width .6s ease; +} + +css loading(percent string) { + width: { fmt.Sprintf("%s%%", percent) }; +} + +templ layout(header, body templ.Component) { +
+
+ @header +
+
+ @body +
+
+} + +templ body() { +

Progress Bar

+
+

Start Progress

+ +
+} + +templ startProgressBar() { +
+

Running

+
+
+
+
+
+
+} + +templ inProgress(val string) { +
+
+
+} + +templ completeProgressBar() { +
+

Complete

+
+
+
+
+
+ +
+} diff --git a/internal/ui/pages/progress-bar/index_templ.go b/internal/ui/pages/progress-bar/index_templ.go new file mode 100644 index 0000000..c4e6cdf --- /dev/null +++ b/internal/ui/pages/progress-bar/index_templ.go @@ -0,0 +1,390 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.819 +package progressbar + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "fmt" + +func classLayout() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`display:grid;`) + templ_7745c5c3_CSSID := templ.CSSID(`classLayout`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func progress() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`height:20px;`) + templ_7745c5c3_CSSBuilder.WriteString(`margin-bottom:20px;`) + templ_7745c5c3_CSSBuilder.WriteString(`overflow:hidden;`) + templ_7745c5c3_CSSBuilder.WriteString(`background-color:#f5f5f5;`) + templ_7745c5c3_CSSBuilder.WriteString(`border-radius:4px;`) + templ_7745c5c3_CSSBuilder.WriteString(`box-shadow:inset 0 1px 2px rgba(0,0,0,.1);`) + templ_7745c5c3_CSSID := templ.CSSID(`progress`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func progressbar() templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(`float:left;`) + templ_7745c5c3_CSSBuilder.WriteString(`width:0%;`) + templ_7745c5c3_CSSBuilder.WriteString(`height:100%;`) + templ_7745c5c3_CSSBuilder.WriteString(`font-size:12px;`) + templ_7745c5c3_CSSBuilder.WriteString(`line-height:20px;`) + templ_7745c5c3_CSSBuilder.WriteString(`color:#fff;`) + templ_7745c5c3_CSSBuilder.WriteString(`text-align:center;`) + templ_7745c5c3_CSSBuilder.WriteString(`background-color:#337ab7;`) + templ_7745c5c3_CSSBuilder.WriteString(`-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);`) + templ_7745c5c3_CSSBuilder.WriteString(`box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);`) + templ_7745c5c3_CSSBuilder.WriteString(`-webkit-transition:width .6s ease;`) + templ_7745c5c3_CSSBuilder.WriteString(`-o-transition:width .6s ease;`) + templ_7745c5c3_CSSBuilder.WriteString(`transition:width .6s ease;`) + templ_7745c5c3_CSSID := templ.CSSID(`progressbar`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func loading(percent string) templ.CSSClass { + templ_7745c5c3_CSSBuilder := templruntime.GetBuilder() + templ_7745c5c3_CSSBuilder.WriteString(string(templ.SanitizeCSS(`width`, fmt.Sprintf("%s%%", percent)))) + templ_7745c5c3_CSSID := templ.CSSID(`loading`, templ_7745c5c3_CSSBuilder.String()) + return templ.ComponentCSSClass{ + ID: templ_7745c5c3_CSSID, + Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`), + } +} + +func layout(header, body templ.Component) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + 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{classLayout()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = header.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = body.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func body() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var4 := templ.GetChildren(ctx) + if templ_7745c5c3_Var4 == nil { + templ_7745c5c3_Var4 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

Progress Bar

Start Progress

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func startProgressBar() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "

Running

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 = []any{progress()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 = []any{progressbar(), loading("0")} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var8...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func inProgress(val string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + var templ_7745c5c3_Var11 = []any{progress()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 = []any{progressbar(), loading(val)} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +func completeProgressBar() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "

Complete

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var17 = []any{progress()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 = []any{progressbar()} + templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var19...) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate