Convert about page to Templ

This commit is contained in:
Tony Grosinger 2024-07-17 17:01:38 -07:00
parent 9356062b54
commit b7db6a57c0
4 changed files with 266 additions and 64 deletions

View File

@ -1,8 +1,6 @@
package handlers
import (
"html/template"
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
@ -23,17 +21,6 @@ type (
*services.TemplateRenderer
*services.DBClient
}
aboutData struct {
ShowCacheWarning bool
FrontendTabs []aboutTab
BackendTabs []aboutTab
}
aboutTab struct {
Title string
Body template.HTML
}
)
func init() {
@ -71,7 +58,6 @@ func (h *Pages) Home(ctx echo.Context) error {
func (h *Pages) About(ctx echo.Context) error {
p := page.New(ctx)
p.Layout = templates.LayoutMain
p.Name = templates.PageAbout
p.Title = "About"
@ -81,33 +67,40 @@ func (h *Pages) About(ctx echo.Context) error {
// A simple example of how the Data field can contain anything you want to send to the templates
// even though you wouldn't normally send markup like this
p.Data = aboutData{
data := pages.AboutData{
ShowCacheWarning: true,
FrontendTabs: []aboutTab{
FrontendTabs: []pages.AboutTab{
{
Title: "HTMX",
Body: template.HTML(`Completes HTML as a hypertext by providing attributes to AJAXify anything and much more. Visit <a href="https://htmx.org/">htmx.org</a> to learn more.`),
Body: `Completes HTML as a hypertext by providing attributes to AJAXify anything and much more. Visit <a href="https://htmx.org/">htmx.org</a> to learn more.`,
},
{
Title: "Alpine.js",
Body: template.HTML(`Drop-in, Vue-like functionality written directly in your markup. Visit <a href="https://alpinejs.dev/">alpinejs.dev</a> to learn more.`),
Body: `Drop-in, Vue-like functionality written directly in your markup. Visit <a href="https://alpinejs.dev/">alpinejs.dev</a> to learn more.`,
},
{
Title: "Bulma",
Body: template.HTML(`Ready-to-use frontend components that you can easily combine to build responsive web interfaces with no JavaScript requirements. Visit <a href="https://bulma.io/">bulma.io</a> to learn more.`),
Body: `Ready-to-use frontend components that you can easily combine to build responsive web interfaces with no JavaScript requirements. Visit <a href="https://bulma.io/">bulma.io</a> to learn more.`,
},
},
BackendTabs: []aboutTab{
BackendTabs: []pages.AboutTab{
{
Title: "Echo",
Body: template.HTML(`High performance, extensible, minimalist Go web framework. Visit <a href="https://echo.labstack.com/">echo.labstack.com</a> to learn more.`),
Body: `High performance, extensible, minimalist Go web framework. Visit <a href="https://echo.labstack.com/">echo.labstack.com</a> to learn more.`,
},
{
Title: "Ent",
Body: template.HTML(`Simple, yet powerful ORM for modeling and querying data. Visit <a href="https://entgo.io/">entgo.io</a> to learn more.`),
Body: `Simple, yet powerful ORM for modeling and querying data. Visit <a href="https://entgo.io/">entgo.io</a> to learn more.`,
},
},
}
return h.RenderPage(ctx, p)
component := pages.About(p, data)
// TODO: This can be reused
p.LayoutComponent = func(content templ.Component) templ.Component {
return layouts.Main(p, content)
}
return h.RenderPageTempl(ctx, p, component)
}

63
templ/pages/about.templ Normal file
View File

@ -0,0 +1,63 @@
package pages
import (
"strconv"
"fmt"
"git.grosinger.net/tgrosinger/saasitone/pkg/page"
)
type AboutData struct {
ShowCacheWarning bool
FrontendTabs []AboutTab
BackendTabs []AboutTab
}
type AboutTab struct {
Title string
Body string
}
templ About(p page.Page, data AboutData) {
if len(data.FrontendTabs) > 0 {
<p class="subtitle mt-5">Frontend</p>
<p class="mb-4">The following incredible projects make developing advanced, modern frontends possible and simple without having to write a single line of JS or CSS. You can go extremely far without leaving the comfort of Go with server-side rendered HTML.</p>
@tabs(data.FrontendTabs)
<div class="mb-4"></div>
}
if len(data.BackendTabs) > 0 {
<p class="subtitle mt-5">Backend</p>
<p class="mb-4">The following incredible projects provide the foundation of the Go backend. See the repository for a complete list of included projects.</p>
@tabs(data.BackendTabs)
<div class="mb-4"></div>
}
if (data.ShowCacheWarning) {
<article class="message is-warning mt-6">
<div class="message-header">
<p>Warning</p>
</div>
<div class="message-body">
This route has caching enabled so hot-reloading in the local environment will not work.
</div>
</article>
}
}
templ tabs(t []AboutTab) {
<div x-data="{tab: 0}">
<div class="tabs">
<ul>
for i, tab := range t {
<li :class={ fmt.Sprintf("{'is-active': tab === %d}", i) } @click={ "tab = " + strconv.Itoa(i) }><a>{ tab.Title }</a></li>
}
</ul>
</div>
for i, tab := range t {
<div x-show={ "tab === " + strconv.Itoa(i) }>
<p>
@templ.Raw(tab.Body)
</p>
</div>
}
</div>
}

187
templ/pages/about_templ.go Normal file
View File

@ -0,0 +1,187 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.707
package pages
//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"
"strconv"
"git.grosinger.net/tgrosinger/saasitone/pkg/page"
)
type AboutData struct {
ShowCacheWarning bool
FrontendTabs []AboutTab
BackendTabs []AboutTab
}
type AboutTab struct {
Title string
Body string
}
func About(p page.Page, data AboutData) 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)
if len(data.FrontendTabs) > 0 {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"subtitle mt-5\">Frontend</p><p class=\"mb-4\">The following incredible projects make developing advanced, modern frontends possible and simple without having to write a single line of JS or CSS. You can go extremely far without leaving the comfort of Go with server-side rendered HTML.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = tabs(data.FrontendTabs).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"mb-4\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if len(data.BackendTabs) > 0 {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"subtitle mt-5\">Backend</p><p class=\"mb-4\">The following incredible projects provide the foundation of the Go backend. See the repository for a complete list of included projects.</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = tabs(data.BackendTabs).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"mb-4\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if data.ShowCacheWarning {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<article class=\"message is-warning mt-6\"><div class=\"message-header\"><p>Warning</p></div><div class=\"message-body\">This route has caching enabled so hot-reloading in the local environment will not work.</div></article>")
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
})
}
func tabs(t []AboutTab) 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_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{tab: 0}\"><div class=\"tabs\"><ul>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for i, tab := range t {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<li :class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("{'is-active': tab === %d}", i))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/pages/about.templ`, Line: 51, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" @click=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs("tab = " + strconv.Itoa(i))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/pages/about.templ`, Line: 51, Col: 99}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(tab.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/pages/about.templ`, Line: 51, Col: 116}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</ul></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for i, tab := range t {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-show=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("tab === " + strconv.Itoa(i))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templ/pages/about.templ`, Line: 56, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.Raw(tab.Body).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
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
})
}

View File

@ -1,41 +0,0 @@
{{define "content"}}
{{- if .Data.FrontendTabs}}
<p class="subtitle mt-5">Frontend</p>
<p class="mb-4">The following incredible projects make developing advanced, modern frontends possible and simple without having to write a single line of JS or CSS. You can go extremely far without leaving the comfort of Go with server-side rendered HTML.</p>
{{template "tabs" .Data.FrontendTabs}}
<div class="mb-4"></div>
{{- end}}
{{- if .Data.BackendTabs}}
<p class="subtitle mt-5">Backend</p>
<p class="mb-4">The following incredible projects provide the foundation of the Go backend. See the repository for a complete list of included projects.</p>
{{template "tabs" .Data.BackendTabs}}
<div class="mb-4"></div>
{{end}}
{{- if .Data.ShowCacheWarning}}
<article class="message is-warning mt-6">
<div class="message-header">
<p>Warning</p>
</div>
<div class="message-body">
This route has caching enabled so hot-reloading in the local environment will not work.
</div>
</article>
{{- end}}
{{end}}
{{define "tabs"}}
<div x-data="{tab: 0}">
<div class="tabs">
<ul>
{{- range $index, $tab := .}}
<li :class="{'is-active': tab === {{$index}}}" @click="tab = {{$index}}"><a>{{.Title}}</a></li>
{{- end}}
</ul>
</div>
{{- range $index, $tab := .}}
<div x-show="tab == {{$index}}"><p> &rarr; {{.Body}}</p></div>
{{- end}}
</div>
{{end}}