cup/controllers/themedemo.go

1001 lines
No EOL
24 KiB
Go

// Copyright (c) 2024 Zeni Kim <zenik@smarteching.com>
// 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.",
},
},
},
}
}