From d80be2713facdba636a4355901233321c3bd8b32 Mon Sep 17 00:00:00 2001 From: Zeni Kim Date: Wed, 6 May 2026 21:10:06 -0500 Subject: [PATCH 1/2] empty database --- storage/sqlite/sqlite.db | Bin 90112 -> 4096 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/storage/sqlite/sqlite.db b/storage/sqlite/sqlite.db index 97751beb57aa829a9420e53efc55e7c533b572c2..57a82d2db1a7536fb820719d2dbb8ad2ea724ed1 100644 GIT binary patch delta 36 qcmZoTz}lcNL7J73fq{W>qJjRz2?E@V40_3oyg&g4fz5&n)A#|A!Up{S literal 90112 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 Date: Wed, 6 May 2026 21:21:57 -0500 Subject: [PATCH 2/2] clean samples --- controllers/queuesample.go | 52 - controllers/sample.go | 149 --- controllers/themedemo.go | 1001 ----------------- routes.go | 28 +- storage/templates/app.html | 17 - storage/templates/appsession.html | 12 - .../templates/custom_templates_functions.html | 471 -------- storage/templates/custom_theme_base.html | 10 - .../templates/custom_theme_contentpage.html | 30 - storage/templates/custom_theme_elements.html | 66 -- storage/templates/custom_theme_formpage.html | 23 - 11 files changed, 2 insertions(+), 1857 deletions(-) delete mode 100644 controllers/queuesample.go delete mode 100644 controllers/sample.go delete mode 100644 controllers/themedemo.go delete mode 100644 storage/templates/app.html delete mode 100644 storage/templates/appsession.html delete mode 100644 storage/templates/custom_templates_functions.html delete mode 100644 storage/templates/custom_theme_base.html delete mode 100644 storage/templates/custom_theme_contentpage.html delete mode 100644 storage/templates/custom_theme_elements.html delete mode 100644 storage/templates/custom_theme_formpage.html diff --git a/controllers/queuesample.go b/controllers/queuesample.go deleted file mode 100644 index d289aee..0000000 --- a/controllers/queuesample.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2025 Zeni Kim -// Use of this source code is governed by MIT-style -// license that can be found in the LICENSE file. - -package controllers - -import ( - "encoding/json" - "log" - "time" - - "git.smarteching.com/goffee/core" - "git.smarteching.com/goffee/cup/workers" - "github.com/hibiken/asynq" -) - -// Make samples queues -func Queuesample(c *core.Context) *core.Response { - - // Get client queue asynq - client := c.GetQueueClient() - - // Create a task with typename and payload. - payload, err := json.Marshal(workers.EmailTaskPayload{UserID: 42}) - if err != nil { - log.Fatal(err) - } - - t1 := asynq.NewTask(workers.TypeWelcomeEmail, payload) - - t2 := asynq.NewTask(workers.TypeReminderEmail, payload) - - // Process the task immediately. - info, err := client.Enqueue(t1) - if err != nil { - log.Fatal(err) - } - log.Printf(" [*] Successfully enqueued task: %+v", info) - - // Process 2 task 1 min later. - for i := 1; i < 3; i++ { - info, err = client.Enqueue(t2, asynq.ProcessIn(1*time.Minute)) - if err != nil { - log.Fatal(err) - } - log.Printf(" [*] Successfully enqueued task: %+v", info) - } - - message := "{\"message\": \"Task queued\"}" - return c.Response.Json(message) - -} diff --git a/controllers/sample.go b/controllers/sample.go deleted file mode 100644 index 9f5687b..0000000 --- a/controllers/sample.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2024 Zeni Kim -// Use of this source code is governed by MIT-style -// license that can be found in the LICENSE file. - -package controllers - -import ( - "fmt" - - "git.smarteching.com/goffee/core" - "git.smarteching.com/goffee/core/template/components" - "git.smarteching.com/goffee/cup/utils" -) - -// Show basic template -func Sample(c *core.Context) *core.Response { - - // first, include all compoments - type templateData struct { - PageCard components.PageCard - } - - // now fill data of the components - tmplData := templateData{ - PageCard: components.PageCard{ - CardTitle: "Framework Goffee", - CardBody: "Powered by Golang", - }, - } - - return c.Response.Template("basic.html", tmplData) - -} - -// Show basic app login -func AppLogin(c *core.Context) *core.Response { - - // first, include all compoments - // first, include all compoments - type templateData struct { - PageCard components.PageCard - } - - // now fill data of the components - tmplData := templateData{ - PageCard: components.PageCard{ - CardTitle: "Card title", - CardBody: "Loerm ipsum at deim", - }, - } - return c.Response.Template("login.html", tmplData) -} - -// Show basic app login -func AppSession(c *core.Context) *core.Response { - - var session = new(utils.SessionUser) - - // true if session is active - hassession := session.Init(c) - - //session.Set("numberdos", 66) - - type templateData struct { - PageCard components.PageCard - } - - // now fill data of the components - tmplData := templateData{} - - if hassession { - - sesiondata := "" - cardtitle := fmt.Sprintf("Session user id: %v", session.GetUserID()) - numberdos, ok := session.Get("numberdos") - - if numberdos != nil { - numberdos = numberdos.(float64) + 10 - } else { - numberdos = 10 - } - - session.Set("numberdos", numberdos) - - if ok { - sesiondata = fmt.Sprintf("OK, Session numberdos has %v", numberdos) - } else { - sesiondata = fmt.Sprintf("No ok, session numberdos has %v", numberdos) - } - - // delete single - //session.Delete("numberdos") - - // delete all data - //session.Flush() - - tmplData = templateData{ - PageCard: components.PageCard{ - CardTitle: cardtitle, - CardBody: sesiondata, - }, - } - - return c.Response.Template("appsession.html", tmplData) - - } else { - - return c.Response.Template("login.html", tmplData) - - } - -} - -// Show basic app sample -func AppSample(c *core.Context) *core.Response { - - // first, include all compoments - type templateData struct { - PageCard components.PageCard - ContentDropdown components.ContentDropdown - } - - // now fill data of the components - tmplData := templateData{ - PageCard: components.PageCard{ - CardTitle: "Protected page", - CardBody: "If you can see this page, your are loggedin", - }, - ContentDropdown: components.ContentDropdown{ - Label: "dropdown", - Items: []components.ContentDropdownItem{ - { - Text: "Signout", - Link: "#", - ID: "signout", - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - } - //fmt.Printf("Outside cookie user is: %s", user.Email) - - return c.Response.Template("app.html", tmplData) - -} diff --git a/controllers/themedemo.go b/controllers/themedemo.go deleted file mode 100644 index a3e22a3..0000000 --- a/controllers/themedemo.go +++ /dev/null @@ -1,1001 +0,0 @@ -// Copyright (c) 2024 Zeni Kim -// Use of this source code is governed by MIT-style -// license that can be found in the LICENSE file. - -package controllers - -import ( - "fmt" - "math/rand/v2" - "os" - "strconv" - "time" - - "git.smarteching.com/goffee/core" - "git.smarteching.com/goffee/core/template/components" -) - -// Show home page -func Themedemo(c *core.Context) *core.Response { - - // check if template engine is enabled - TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if TemplateEnableStr == "" { - TemplateEnableStr = "false" - } - TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) - - if TemplateEnable { - - // first, include all compoments - type templateData struct { - PageCard components.PageCard - } - - // now fill data of the components - tmplData := templateData{ - PageCard: components.PageCard{ - CardTitle: "Card title", - CardBody: "Loerm ipsum at deim", - }, - } - - return c.Response.Template("custom_theme_base.html", tmplData) - - } else { - - message := "{\"message\": \"Error, template not enabled\"}" - return c.Response.Json(message) - - } - -} - -// Show form element page -func Themeform(c *core.Context) *core.Response { - - // check if template engine is enabled - TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if TemplateEnableStr == "" { - TemplateEnableStr = "false" - } - TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) - - if TemplateEnable { - - // first, include all compoments - type templateData struct { - FormText components.FormInput - FormEmail components.FormInput - FormButton components.FormButton - FormSelectCity components.FormSelect - FormTextarea components.FormTextarea - FormRadio components.FormRadio - FormCheckbox components.FormCheckbox - } - - // for select options - var allOptions []components.FormSelectOption - var option components.FormSelectOption - option.Value = "ch" - option.Caption = "China" - allOptions = append(allOptions, option) - option.Value = "ba" - option.Caption = "Buenos Aires" - allOptions = append(allOptions, option) - option.Value = "fr" - option.Caption = "France" - selectedOption := option - allOptions = append(allOptions, option) - - // for radio options - var allOptionsr []components.FormRadioItem - var optionr components.FormRadioItem - optionr.ID = "citysch" - optionr.Name = "citys" - optionr.Value = "china" - optionr.Label = "China" - allOptionsr = append(allOptionsr, optionr) - optionr.ID = "citysba" - optionr.Name = "citys" - optionr.Value = "buenosaires" - optionr.Label = "Buenos Aires" - //optionr.IsDisabled = true - allOptionsr = append(allOptionsr, optionr) - - // for radio options - var allOptionsc []components.FormCheckboxItem - var optionc components.FormCheckboxItem - optionc.ID = "citysch" - optionc.Name = "citys" - optionc.Value = "china" - optionc.Label = "China" - allOptionsc = append(allOptionsc, optionc) - optionc.ID = "citysba" - optionc.Name = "citys" - optionc.Value = "buenosaires" - optionc.Label = "Buenos Aires" - allOptionsc = append(allOptionsc, optionc) - optionc.ID = "london" - optionc.Name = "london" - optionc.Value = "london" - optionc.Label = "London" - //optionc.IsChecked = true - allOptionsc = append(allOptionsc, optionc) - - // now fill data of the components - tmplData := templateData{ - FormText: components.FormInput{ - ID: "text", - Label: "Name", - Type: "text", - Hint: "This is sample hint", - Placeholder: "Enter your name", - }, - FormEmail: components.FormInput{ - ID: "email", - Label: "Email", - Type: "email", - IsRequired: true, - Placeholder: "Enter your email address", - }, - FormButton: components.FormButton{ - Text: "Login", - IsSubmit: true, - TypeClass: "primary", - }, - FormSelectCity: components.FormSelect{ - ID: "city", - Label: "Select city", - AllOptions: allOptions, - SelectedOption: selectedOption, - }, - FormTextarea: components.FormTextarea{ - ID: "text", - Label: "Example textarea", - }, - FormRadio: components.FormRadio{ - Label: "Radio buttons", - AllRadios: allOptionsr, - }, - FormCheckbox: components.FormCheckbox{ - Label: "Checkbox options", - AllCheckbox: allOptionsc, - }, - } - return c.Response.Template("custom_theme_formpage.html", tmplData) - - } else { - - message := "{\"message\": \"Error, template not enabled\"}" - return c.Response.Json(message) - - } - -} - -func ThemeElements(c *core.Context) *core.Response { - // check if template engine is enabled - TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if TemplateEnableStr == "" { - TemplateEnableStr = "false" - } - TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) - - if TemplateEnable { - type templateData struct { - Buttons []components.FormButton - Hrefs []components.ContentHref - Badges []components.ContentBadge - Dropdowns []components.ContentDropdown - Lists []components.ContentList - Menus []components.PageNav - } - buttons := []components.FormButton{ - { - Text: "primary", - TypeClass: "primary", - }, - { - Text: "secondary", - TypeClass: "secondary", - }, - { - Text: "success", - TypeClass: "success", - }, - { - Text: "danger", - TypeClass: "danger", - }, - { - Text: "warning", - TypeClass: "warning", - }, - { - Text: "info", - TypeClass: "info", - }, - { - Text: "light", - TypeClass: "light", - }, - { - Text: "dark", - TypeClass: "dark", - }, - { - Text: "link", - TypeClass: "link", - }, - { - Text: "disabled", - TypeClass: "primary", - IsDisabled: true, - }, - { - Text: "outline-primary", - TypeClass: "outline-primary", - }, - { - Text: "outline-secondary", - TypeClass: "outline-secondary", - }, - { - Text: "outline-success", - TypeClass: "outline-success", - }, - { - Text: "outline-danger", - TypeClass: "outline-danger", - }, - { - Text: "outline-warning", - TypeClass: "outline-warning", - }, - { - Text: "outline-info", - TypeClass: "outline-info", - }, - { - Text: "outline-light", - TypeClass: "outline-light", - }, - { - Text: "outline-dark", - TypeClass: "outline-dark", - }, - } - hrefs := []components.ContentHref{ - { - Text: "href", - Link: "#", - IsButton: false, - }, - { - Text: "link", - Link: "#", - IsButton: false, - TypeClass: "link", - }, - { - Text: "button", - Link: "#", - IsButton: true, - TypeClass: "primary", - }, - { - Text: "href disabled", - Link: "#", - IsButton: false, - IsDisabled: true, - }, - { - Text: "link disabled", - Link: "#", - TypeClass: "link", - IsDisabled: true, - }, - { - Text: "button disabled", - Link: "#", - IsButton: true, - TypeClass: "primary", - IsDisabled: true, - }, - } - badges := []components.ContentBadge{ - { - Text: "primary", - TypeClass: "primary", - }, - { - Text: "secondary", - TypeClass: "secondary", - }, - { - Text: "success", - TypeClass: "success", - }, - { - Text: "danger", - TypeClass: "danger", - }, - { - Text: "warning", - TypeClass: "warning", - }, - { - Text: "info", - TypeClass: "info", - }, - { - Text: "light", - TypeClass: "light", - }, - { - Text: "dark", - TypeClass: "dark", - }, - { - Text: "outline", - TypeClass: "primary", - IsOutline: true, - }, - { - Text: "outline", - TypeClass: "success", - IsOutline: true, - }, - { - Text: "outline", - TypeClass: "danger", - IsOutline: true, - }, - { - Text: "outline", - TypeClass: "warning", - IsOutline: true, - }, - } - dropdowns := []components.ContentDropdown{ - // dropdown - { - Label: "dropdown", - Items: []components.ContentDropdownItem{ - { - Text: "item ", - Link: "#", - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // dropdown - { - Label: "primary", - TypeClass: "primary", - Items: []components.ContentDropdownItem{ - { - Text: "item ", - Link: "#", - }, - { - Text: "item ", - Link: "#", - IsActive: true, - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // dropdown - { - Label: "outline", - TypeClass: "outline-primary", - Items: []components.ContentDropdownItem{ - { - Text: "item ", - Link: "#", - }, - }, - }, - // dropdown - { - Label: "disabled", - TypeClass: "primary", - IsDisabled: true, - // items - }, - } - list := []components.ContentList{ - // basic list - { - Items: []components.ContentListItem{ - { - Text: "item 1", - }, - { - Text: "item 2", - EndElement: "end text", - }, - { - Text: "item disabled", - IsDisabled: true, - }, - }, - }, - // description list - { - Items: []components.ContentListItem{ - { - Text: "item 1", - Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", - }, - { - Text: "item 2", - Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - }, - { - Text: "item disabled", - Description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", - IsDisabled: true, - }, - }, - }, - // list with class - { - Items: []components.ContentListItem{ - { - Text: "class primary", - TypeClass: "primary", - }, - { - Text: "class success", - TypeClass: "success", - }, - { - Text: "class danger", - TypeClass: "danger", - }, - }, - }, - } - menus := []components.PageNav{ - // nav - { - NavClass: "nav-pills", - NavItems: []components.PageNavItem{ - { - Text: "item active", - Link: "#", - IsActive: true, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item", - Link: "#", - IsActive: false, - ChildItems: []components.PageNavItem{ - { - Text: "item ", - Link: "#", - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // nav - { - NavClass: "", - NavItems: []components.PageNavItem{ - { - Text: "item active", - Link: "#", - IsActive: true, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // nav underline - { - NavClass: "nav-underline", - NavItems: []components.PageNavItem{ - { - Text: "item active", - Link: "#", - IsActive: true, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // nav tabs - { - NavClass: "", - IsTab: true, - NavItems: []components.PageNavItem{ - { - Text: "tab active", - Link: "#", - IsActive: true, - }, - { - Text: "tab", - Link: "#", - IsActive: false, - }, - { - Text: "tab", - Link: "#", - IsActive: false, - }, - { - Text: "tab disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - // nav vertical - { - NavClass: "", - IsVertical: true, - NavItems: []components.PageNavItem{ - { - Text: "item active", - Link: "#", - IsActive: true, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item", - Link: "#", - IsActive: false, - }, - { - Text: "item disabled", - Link: "#", - IsDisabled: true, - }, - }, - }, - } - - tmplData := templateData{ - Buttons: buttons, - Hrefs: hrefs, - Badges: badges, - Dropdowns: dropdowns, - Lists: list, - Menus: menus, - } - return c.Response.Template("custom_theme_elements.html", tmplData) - - } else { - - message := "{\"message\": \"Error, template not enabled\"}" - return c.Response.Json(message) - } -} - -// Show form element page -func Themecontent(c *core.Context) *core.Response { - - // check if template engine is enabled - TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if TemplateEnableStr == "" { - TemplateEnableStr = "false" - } - TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) - - if TemplateEnable { - - // first, include all compoments - type templateData struct { - ContentTable components.ContentTable - ContentTabledetail components.ContentTabledetail - ContentGraph components.ContentGraph - FieldText components.FormInput - FormSelectCityM components.FormSelect - Pagination components.ContentPagination - ShouldShowPagination bool - } - - // for select options - var allOptions []components.FormSelectOption - var option components.FormSelectOption - option.Value = "ch" - option.Caption = "China" - allOptions = append(allOptions, option) - option.Value = "ba" - option.Caption = "Buenos Aires" - allOptions = append(allOptions, option) - option.Value = "fr" - option.Caption = "France" - selectedOption := option - allOptions = append(allOptions, option) - option.Value = "kr" - option.Caption = "Korea" - allOptions = append(allOptions, option) - - // for custom attributes in form - var customAtt []components.CustomAtt - var attribute components.CustomAtt - attribute.AttName = "code" - attribute.AttValue = "five" - customAtt = append(customAtt, attribute) - attribute.AttName = "mytag" - attribute.AttValue = "My value" - customAtt = append(customAtt, attribute) - - // TABLES - // for th head - var allTh []components.ContentTableTH - var th components.ContentTableTH - th.Value = "Column heading 1" - allTh = append(allTh, th) - th.Value = "Column heading 2" - allTh = append(allTh, th) - th.ID = "ba" - th.Value = "Column heading 3" - allTh = append(allTh, th) - th.Value = "Column badge" - th.ValueType = "badge" // column type badge - allTh = append(allTh, th) - th.Value = "Column action" - th.ValueType = "href" // column type href - allTh = append(allTh, th) - - // for td items - var allTd [][]components.ContentTableTD - //var vals []components.ContentTableTD - // rows - for i := 1; i <= 28; i++ { - vals := make([]components.ContentTableTD, len(allTh)) - for b := 0; b < len(allTh)-2; b++ { - vals[b].Value = fmt.Sprintf("%s%d%d", "TD data: ", i, b) - vals[b].ID = fmt.Sprintf("%s%d%d", "idtd_", i, b) - } - // column badge - vals[len(allTh)-2].Value = components.ContentBadge{ - Text: "success", - TypeClass: "success", - } - // last column href - vals[len(allTh)-1].Value = components.ContentHref{ - Text: "edit", - Link: "#", - } - allTd = append(allTd, vals) - } - - // Pagination demo - // start config - limit := 10 - shouldShowPagination := false - pageViewTableOffset := 0 - // Get the length of AllOptions - totalrecords := len(allTd) - // get current table offset - tpage := c.RequestParamExists("tpage") - if tpage { - pageViewTableOffset, _ = strconv.Atoi(c.GetRequestParam("tpage").(string)) - } - - // start default option paginator - var pagination components.ContentPagination - pagination.PageStartRecord = pageViewTableOffset + 1 - pagination.PageEndRecord = 0 - pagination.TotalRecords = 0 - pagination.PrevLink = "" - pagination.NextLink = "" - - // check current page - // fake function to emulate a query offset - newTd := getPaginatedPageViews(allTd, limit, pageViewTableOffset) - - if len(newTd) > 0 { - pagination.TotalRecords = totalrecords - pagination.PageStartRecord = pageViewTableOffset + 1 - pagination.PageEndRecord = pageViewTableOffset + len(newTd) - shouldShowPagination = totalrecords > limit - } - - if shouldShowPagination && pageViewTableOffset != 0 { - pagination.PrevLink = fmt.Sprintf("/themecontent?tpage=%d", pageViewTableOffset-limit) - } - - if shouldShowPagination && pageViewTableOffset+limit < totalrecords { - pagination.NextLink = fmt.Sprintf("/themecontent?tpage=%d", pageViewTableOffset+limit) - } - - // for td items in table detail - var allTdetail []components.ContentTabledetailTD - // table detail - var thd components.ContentTabledetailTD - thd.Caption = "Continent" - thd.Value = "Asia" - allTdetail = append(allTdetail, thd) - thd.Caption = "Country" - thd.Value = "South Korea" - allTdetail = append(allTdetail, thd) - thd.Caption = "Capital" - thd.Value = "Seoul" - allTdetail = append(allTdetail, thd) - thd.Caption = "Details" - thd.ValueType = "href" // column type href - thd.Value = components.ContentHref{ - Text: "edit", - Link: "#", - } - allTdetail = append(allTdetail, thd) - thd.Caption = "Notifications" - thd.ValueType = "badge" // column type href - thd.Value = components.ContentBadge{ - Text: "success", - TypeClass: "success", - } - allTdetail = append(allTdetail, thd) - - // random values for pie - one := rand.IntN(50) - two := rand.IntN(50) - three := rand.IntN(50) - valuesgraph := fmt.Sprintf("%d|%d|%d", one, two, three) - - // now fill data of the components - tmplData := templateData{ - FormSelectCityM: components.FormSelect{ - ID: "city", - Label: "Select city", - AllOptions: allOptions, - SelectedOption: selectedOption, - IsMultiple: true, - }, - FieldText: components.FormInput{ - ID: "text", - Label: "Name", - Type: "text", - Hint: "This is sample hint", - Placeholder: "Enter your name", - CustomAtt: customAtt, - }, - ContentTable: components.ContentTable{ - ID: "table_demo", - AllTH: allTh, - AllTD: newTd, - }, - ContentTabledetail: components.ContentTabledetail{ - ID: "table_demodetail", - Title: "Sample table detail", - HeadClass: "table-warning", - AllTD: allTdetail, - }, - ContentGraph: components.ContentGraph{ - Graph: "pie", - Labels: "Berlin|Paris|Venecia", - Values: valuesgraph, - }, - Pagination: pagination, - ShouldShowPagination: shouldShowPagination, - } - - return c.Response.Template("custom_theme_contentpage.html", tmplData) - - } else { - - message := "{\"message\": \"Error, template not enabled\"}" - return c.Response.Json(message) - - } - -} - -func getPaginatedPageViews(values [][]components.ContentTableTD, limit int, offset int) [][]components.ContentTableTD { - - // Validate the offset and adjust if necessary - if offset < 0 { - offset = 0 // Ensure offset is not negative - } else if offset >= len(values) { - var emptytd [][]components.ContentTableTD - return emptytd - } - - // Calculate the end index (limit the slice to the size of the array) - end := offset + limit - if end > len(values) { - end = len(values) // Ensure end doesn't exceed the length of the array - } - - return values[offset:end] // Slice the array - -} - -// Custom Templates functions -func TemplatesFunctions(c *core.Context) *core.Response { - - // check if template engine is enabled - TemplateEnableStr := os.Getenv("TEMPLATE_ENABLE") - if TemplateEnableStr == "" { - TemplateEnableStr = "false" - } - TemplateEnable, _ := strconv.ParseBool(TemplateEnableStr) - - if TemplateEnable { - loggr := c.GetLogger() - - loggr.Debug("D e b u g") - loggr.Info("I n f o") - loggr.Warning("W a r n i n g") - loggr.Error("E R R O R") - - - tmplData := SamplePageData() - return c.Response.Template("custom_templates_functions.html", tmplData) - - } else { - - message := "{\"message\": \"Error, template not enabled\"}" - return c.Response.Json(message) - - } - -} - -// Author represents the writer of an article to show the custom functions -type Author struct { - Name string - Avatar string - Bio string -} - -// Article represents a blog post or news entry used to test template helpers to show the custom functions -type Article struct { - Title string - Slug string - Excerpt string - Body string - Tags []string - PublishedAt time.Time - UpdatedAt time.Time - Author Author - Views int - Price float64 - Featured bool - Subtitle string // intentionally left empty on some entries to test coalesce/defaultVal -} - -// PageData is the top-level context passed to the HTML template to show the custom functions -type PageData struct { - SiteTitle string - Articles []Article -} - -// SamplePageData returns a populated PageData ready to be rendered by the template. -func SamplePageData() PageData { - return PageData{ - SiteTitle: "go/template lab", - Articles: []Article{ - { - Title: "getting started with go templates", - Slug: "getting-started-go-templates", - Excerpt: "Go's html/template package is both powerful and safe by default. In this article we explore how to extend it with custom FuncMap helpers that bring it closer to the expressiveness of Liquid or Twig, without sacrificing any of the security guarantees.", - Tags: []string{"go", "templates", "web", "backend"}, - PublishedAt: time.Now().Add(-3 * 24 * time.Hour), - UpdatedAt: time.Now().Add(-1 * 24 * time.Hour), - Views: 14200, - Price: 0, - Featured: true, - Subtitle: "", - Author: Author{ - Name: "marina voss", - Avatar: "MV", - Bio: "Senior backend engineer focused on developer tooling and observability.", - }, - }, - { - Title: "building a blog engine in go", - Slug: "blog-engine-go", - Excerpt: "We walk through building a minimal but complete blog engine using only the Go standard library: routing with net/http, persistence with database/sql, and rendering with html/template.", - Tags: []string{"go", "blog", "sqlite"}, - PublishedAt: time.Now().Add(-10 * 24 * time.Hour), - UpdatedAt: time.Now().Add(-10 * 24 * time.Hour), - Views: 8750, - Price: 9.99, - Featured: false, - Subtitle: "A zero-dependency approach", - Author: Author{ - Name: "rafael okonkwo", - Avatar: "RO", - Bio: "Full-stack engineer and open-source contributor. Writes about Go and distributed systems.", - }, - }, - { - Title: "concurrency patterns you should know", - Slug: "concurrency-patterns-go", - Excerpt: "Goroutines are cheap, but misusing them is expensive. This deep-dive covers fan-out/fan-in, pipelines, semaphores, and error group patterns with real production examples.", - Tags: []string{"go", "concurrency", "goroutines", "advanced"}, - PublishedAt: time.Now().Add(-45 * 24 * time.Hour), - UpdatedAt: time.Now().Add(-40 * 24 * time.Hour), - Views: 31400, - Price: 14.99, - Featured: true, - Subtitle: "", - Author: Author{ - Name: "selin çelik", - Avatar: "SÇ", - Bio: "Systems programmer. Previously at Cloudflare. Loves writing about the internals of things.", - }, - }, - { - Title: "understanding go interfaces", - Slug: "understanding-go-interfaces", - Excerpt: "Interfaces in Go are implicit and structural, which makes them both elegant and occasionally surprising. We look at how the runtime dispatches method calls and how to design composable interfaces.", - Tags: []string{"go", "interfaces", "design"}, - PublishedAt: time.Now().Add(-2 * time.Hour), - UpdatedAt: time.Now().Add(-1 * time.Hour), - Views: 420, - Price: 0, - Featured: false, - Subtitle: "Implicit, structural, and powerful", - Author: Author{ - Name: "marina voss", - Avatar: "MV", - Bio: "Senior backend engineer focused on developer tooling and observability.", - }, - }, - }, - } -} \ No newline at end of file diff --git a/routes.go b/routes.go index dc1799c..193da2d 100644 --- a/routes.go +++ b/routes.go @@ -8,7 +8,6 @@ package main import ( "git.smarteching.com/goffee/core" "git.smarteching.com/goffee/cup/controllers" - "git.smarteching.com/goffee/cup/hooks" ) // Register the app controllers @@ -20,15 +19,8 @@ func registerRoutes() { // Define your routes here... controller.Get("/", controllers.WelcomeHome) - // Uncomment the lines below to enable theme demo - controller.Get("/themebase", controllers.Themedemo) - controller.Get("/themeform", controllers.Themeform) - controller.Get("/themecontent", controllers.Themecontent) - controller.Get("/themepanel", controllers.Themedemo) - controller.Get("/themeelements", controllers.ThemeElements) - controller.Get("/queuesample", controllers.Queuesample) - - // Uncomment the lines below to enable authentication + + // Uncomment the lines below to enable authentication API controller.Post("/signup", controllers.Signup) controller.Post("/signin", controllers.Signin) controller.Post("/signout", controllers.Signout) @@ -44,22 +36,6 @@ func registerRoutes() { controller.Post("/admin/users/edit/:id", controllers.AdminUsersEdit) controller.Post("/admin/users/delete", controllers.AdminUsersDelete) controller.Post("/admin/users/deleteconfirm", controllers.AdminUsersDelConfirm) - //controller.Get("/admin/users/roles", controllers.Signout) - //controller.Get("/admin/users/permissions", controllers.ResetPasswordRequest) - controller.Get("/dashboard", controllers.WelcomeToDashboard, hooks.AuthCheck) - // templates demos - controller.Get("/signout", controllers.Signout) - - controller.Get("/appsample", controllers.AppSample, hooks.AuthCheck) - controller.Post("/appsample", controllers.AppSample, hooks.AuthCheck) - - controller.Get("/applogin", controllers.AppLogin, hooks.CheckSessionCookie) - controller.Post("/applogin", controllers.AppLogin, hooks.CheckSessionCookie) - - controller.Get("/appsession", controllers.AppSession) - controller.Post("/appsession", controllers.AppSession) - - controller.Get("/templatesfunc", controllers.TemplatesFunctions) } diff --git a/storage/templates/app.html b/storage/templates/app.html deleted file mode 100644 index 2bc5f93..0000000 --- a/storage/templates/app.html +++ /dev/null @@ -1,17 +0,0 @@ - - - {{template "page_head" "Sample page"}} - -
-
- {{template "content_dropdown" .ContentDropdown}} - {{template "page_card" .PageCard}} - {{ define "page_card_content" }} - - - {{ end }} -
-
- {{template "page_footer"}} - - \ No newline at end of file diff --git a/storage/templates/appsession.html b/storage/templates/appsession.html deleted file mode 100644 index 32364f0..0000000 --- a/storage/templates/appsession.html +++ /dev/null @@ -1,12 +0,0 @@ - - - {{template "page_head" "Sample page test session vars"}} - -
-
- {{template "page_card" .PageCard}} -
-
- {{template "page_footer"}} - - \ No newline at end of file diff --git a/storage/templates/custom_templates_functions.html b/storage/templates/custom_templates_functions.html deleted file mode 100644 index 6e0c357..0000000 --- a/storage/templates/custom_templates_functions.html +++ /dev/null @@ -1,471 +0,0 @@ - - - - - - {{.SiteTitle}} — template lab - - - - - - - -
-
-

{{.SiteTitle}}

-

Template helpers
in action

-
-

22 helpers registered
across 6 groups

-
- - - - - -{{$first := first .Articles}} - -
- -
-

capitalize capitalize

-

{{capitalize $first.Title}}

-

input: "{{$first.Title}}"

-
- -
-

truncate truncate

-

{{$first.Excerpt | truncate 80}}

-

capped at 80 chars

-
- -
-

prepend prepend

-

{{prepend $first.Slug "/articles/"}}

-

prepended "/articles/" to slug

-
- -
-

strAppend strAppend

-

{{strAppend $first.Slug ".html"}}

-

appended ".html" to slug

-
- -
-

split → join split join

- {{$parts := split "go,templates,funcmap" ","}} -

{{join $parts " · "}}

-

split on "," then joined with " · "

-
- -
- - - - - -
- -
-

fmtNumber — int fmtNumber

-

{{fmtNumber $first.Views}}

-

raw value: {{$first.Views}}

-
- - {{$paid := index .Articles 2}} -
-

fmtNumber — float fmtNumber

-

$ {{fmtNumber $paid.Price}}

-

raw value: {{$paid.Price}}

-
- -
-

fmtDate "short" fmtDate

-

{{fmtDate $first.PublishedAt "short"}}

-

layout: "02 Jan 2006"

-
- -
-

fmtDate "long" fmtDate

-

{{fmtDate $first.PublishedAt "long"}}

-

layout: "02 January 2006"

-
- -
-

fmtDate "iso" fmtDate

-

{{fmtDate $first.PublishedAt "iso"}}

-

layout: "2006-01-02"

-
- -
-

timeAgo timeAgo

- {{range .Articles}} -

{{timeAgo .PublishedAt}} — {{fmtDate .PublishedAt "short"}}

- {{end}} -
- -
- - - - - -
- -
-

first first

- {{with first .Articles}} -

{{capitalize .Title}}

-

first article in the list

- {{end}} -
- -
-

last last

- {{with last .Articles}} -

{{capitalize .Title}}

-

last article in the list

- {{end}} -
- -
-

sliceOf 0–2 sliceOf

- {{range sliceOf .Articles 0 2}} -

— {{capitalize .Title}}

- {{end}} -

only first 2 of {{len .Articles}} articles

-
- -
-

contains — slice contains

- {{if contains $first.Tags "go"}} -

✓ has tag "go"

- {{else}} -

✗ missing tag "go"

- {{end}} -

tags: {{join $first.Tags ", "}}

-
- -
-

contains — string contains

- {{if contains $first.Excerpt "FuncMap"}} -

✓ excerpt mentions "FuncMap"

- {{else}} -

✗ not found

- {{end}} -

substring search on .Excerpt

-
- -
-

join join

-

{{join $first.Tags " / "}}

-

tags joined with " / "

-
- -
- - - - - - - - - - - - - - - - {{range .Articles}} - - - - - - - - - - - - - - - - - - - {{end}} - -
HelperArticleInputOutput
defaultVal{{.Title | capitalize | truncate 30}}.Subtitle ({{if .Subtitle}}"{{.Subtitle}}"{{else}}empty{{end}}){{defaultVal "No subtitle" .Subtitle}}
ternary{{capitalize .Title | truncate 30}}.Featured = {{.Featured}}{{ternary "⭐ featured" "regular" .Featured}}
coalesce{{capitalize .Title | truncate 30}}.Subtitle → .Title{{coalesce .Subtitle .Title}}
- - - - - -
- {{range .Articles}} -
-
-
- {{if .Featured}}featured{{end}} - {{range .Tags}}{{.}}{{end}} -
- -

{{capitalize .Title}}

- - {{with coalesce .Subtitle ""}} -

{{.}}

- {{end}} - -

{{.Excerpt | truncate 160}}

- - - {{prepend .Slug "/articles/"}} → - - -
-
{{.Author.Avatar}}
-
-
{{capitalize .Author.Name}}
- -
-
-
- -
-
- {{fmtNumber .Views}} - views -
- {{if gt .Price 0.0}} - $ {{fmtNumber .Price}} - {{else}} - free - {{end}} -
-
- {{end}} -
- - - -
- {{.SiteTitle}} / template sandbox - {{len .Articles}} articles · {{fmtDate (first .Articles).PublishedAt "iso"}} → {{fmtDate (last .Articles).PublishedAt "iso"}} -
- - - \ No newline at end of file diff --git a/storage/templates/custom_theme_base.html b/storage/templates/custom_theme_base.html deleted file mode 100644 index 9c28a1e..0000000 --- a/storage/templates/custom_theme_base.html +++ /dev/null @@ -1,10 +0,0 @@ - - - {{template "page_head" "Goffee"}} - -
- {{template "page_card" .PageCard}} -
- {{template "page_footer"}} - - \ No newline at end of file diff --git a/storage/templates/custom_theme_contentpage.html b/storage/templates/custom_theme_contentpage.html deleted file mode 100644 index 422c253..0000000 --- a/storage/templates/custom_theme_contentpage.html +++ /dev/null @@ -1,30 +0,0 @@ - - - {{template "page_head" "Goffee"}} - -
-
- Content demos -
- {{template "content_table" .ContentTable}} - {{if .ShouldShowPagination}} - {{template "content_pagination" .Pagination}} - {{end}} -
-
-
-

Pie chart

- {{template "content_graph" .ContentGraph}} -
- {{template "form_input" .FieldText}} - {{template "form_select" .FormSelectCityM}} -
-
- {{template "content_tabledetail" .ContentTabledetail}} -
-
-
-
- {{template "page_footer"}} - - diff --git a/storage/templates/custom_theme_elements.html b/storage/templates/custom_theme_elements.html deleted file mode 100644 index fbe2d52..0000000 --- a/storage/templates/custom_theme_elements.html +++ /dev/null @@ -1,66 +0,0 @@ - - - {{template "page_head" "Goffee"}} - -
-
- Demos buttons -
- {{range .Buttons}} - {{template "form_button" .}} - {{end}} -
-
- -
- Demos href -
- {{range .Hrefs}} - {{template "content_href" .}} - {{end}} -
-
- -
- Demos Badges -
- {{range .Badges}} - {{template "content_badge" .}} - {{end}} -
-
- - -
- Demos dropdown -
- {{range .Dropdowns}} - {{template "content_dropdown" .}} - {{end}} -
-
- - -
- Demos List -
- {{range .Lists}} - {{template "content_list" .}} - {{end}} -
-
- -
- Demos nav -
- {{range .Menus}} -
- {{template "page_nav" .}} -
- {{end}} -
-
-
- {{template "page_footer"}} - - diff --git a/storage/templates/custom_theme_formpage.html b/storage/templates/custom_theme_formpage.html deleted file mode 100644 index f45a558..0000000 --- a/storage/templates/custom_theme_formpage.html +++ /dev/null @@ -1,23 +0,0 @@ - - - {{template "page_head" "Goffee"}} - -
-
-
- form demos -
- {{template "form_input" .FormText}} - {{template "form_input" .FormEmail}} - {{template "form_select" .FormSelectCity}} - {{template "form_textarea" .FormTextarea}} - {{template "form_radio" .FormRadio}} - {{template "form_checkbox" .FormCheckbox}} -
-
- {{template "form_button" .FormButton}} -
-
- {{template "page_footer"}} - - -- 2.39.5