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() {
+
+}
+
+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