alerts, toast amd breadcrum
This commit is contained in:
parent
aa651083cd
commit
1f95f86829
12 changed files with 525 additions and 1 deletions
|
|
@ -69,6 +69,31 @@ func TablerNavbar(c *core.Context) *core.Response {
|
||||||
return c.Response.Template("tabler_default.html", data)
|
return c.Response.Template("tabler_default.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TablerComponents renders a page with alerts, breadcrumbs, and toasts.
|
||||||
|
// Uses the composition pattern: embeds TablerPageData and adds Components.
|
||||||
|
func TablerComponents(c *core.Context) *core.Response {
|
||||||
|
type componentsPageData struct {
|
||||||
|
TablerPageData
|
||||||
|
Components FormtablerComponentsPage
|
||||||
|
}
|
||||||
|
data := componentsPageData{
|
||||||
|
TablerPageData: TablerPageData{
|
||||||
|
PageTitle: "UI Components",
|
||||||
|
PageDescription: "Alerts, breadcrumbs and toasts demo",
|
||||||
|
ShowTopbar: true,
|
||||||
|
Sidebar: false,
|
||||||
|
PageHeader: "Components",
|
||||||
|
PagePretitle: "UI Elements",
|
||||||
|
UserName: "Jane Doe",
|
||||||
|
UserRole: "Administrator",
|
||||||
|
NavbarMenu: SampleNavbarMenu(),
|
||||||
|
Content: template.HTML(""),
|
||||||
|
},
|
||||||
|
Components: SampleComponents(),
|
||||||
|
}
|
||||||
|
return c.Response.Template("tabler_components.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
// TablerCards renders a page with card component demos.
|
// TablerCards renders a page with card component demos.
|
||||||
// Uses the composition pattern: embeds TablerPageData and adds Cards.
|
// Uses the composition pattern: embeds TablerPageData and adds Cards.
|
||||||
func TablerCards(c *core.Context) *core.Response {
|
func TablerCards(c *core.Context) *core.Response {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,103 @@ func SampleNavbarMenu() TablerMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleComponents returns sample data for alerts, breadcrumbs, and toasts.
|
||||||
|
func SampleComponents() FormtablerComponentsPage {
|
||||||
|
return FormtablerComponentsPage{
|
||||||
|
Alerts: []FormtablerAlert{
|
||||||
|
{
|
||||||
|
Type: "success",
|
||||||
|
Title: "Success alert!",
|
||||||
|
ShowClose: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "warning",
|
||||||
|
Title: "Warning alert with description",
|
||||||
|
Description: "This is a warning alert with additional description text to provide more context to the user.",
|
||||||
|
List: []string{"Item one is important", "Item two requires attention", "Item three is optional"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "danger",
|
||||||
|
Title: "Danger alert",
|
||||||
|
Action: "Undo",
|
||||||
|
Buttons: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "info",
|
||||||
|
Title: "Info alert with link",
|
||||||
|
Link: "Learn more",
|
||||||
|
ShowClose: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "success",
|
||||||
|
Title: "Important alert",
|
||||||
|
Important: true,
|
||||||
|
ShowClose: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "warning",
|
||||||
|
Title: "Minor alert variant",
|
||||||
|
Minor: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Breadcrumbs: []FormtablerBreadcrumb{
|
||||||
|
{
|
||||||
|
Items: []FormtablerBreadcrumbItem{
|
||||||
|
{Title: "Home", Link: "/", HomeIcon: true},
|
||||||
|
{Title: "Library", Link: "/library"},
|
||||||
|
{Title: "Data"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Separator: "arrows",
|
||||||
|
Items: []FormtablerBreadcrumbItem{
|
||||||
|
{Title: "Dashboard", Link: "/"},
|
||||||
|
{Title: "Components", Link: "/components"},
|
||||||
|
{Title: "Alerts"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Separator: "dots",
|
||||||
|
Items: []FormtablerBreadcrumbItem{
|
||||||
|
{Title: "Home", Link: "/", HomeIcon: true},
|
||||||
|
{Title: "Settings", Link: "/settings"},
|
||||||
|
{Title: "Profile"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Toasts: []FormtablerToast{
|
||||||
|
{
|
||||||
|
ID: "simple",
|
||||||
|
Show: true,
|
||||||
|
PersonName: "Paweł Kuna",
|
||||||
|
PersonSrc: "/static/avatars/000m.jpg",
|
||||||
|
Date: "2 mins ago",
|
||||||
|
Text: "Hello, world! This is a toast message.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "avatar-toast",
|
||||||
|
Show: true,
|
||||||
|
PersonName: "Jeffie Lewzey",
|
||||||
|
PersonSrc: "/static/avatars/052f.jpg",
|
||||||
|
Date: "5 mins ago",
|
||||||
|
Text: "Your report has been generated successfully.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "cookies",
|
||||||
|
Show: true,
|
||||||
|
Date: "just now",
|
||||||
|
Cookies: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "no-header",
|
||||||
|
Show: true,
|
||||||
|
HideHeader: true,
|
||||||
|
Text: "This toast has no header — just a plain message body.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SampleCards returns 6 sample cards showing different variants.
|
// SampleCards returns 6 sample cards showing different variants.
|
||||||
func SampleCards() []FormtablerCard {
|
func SampleCards() []FormtablerCard {
|
||||||
defaultBody := &FormtablerCardBody{
|
defaultBody := &FormtablerCardBody{
|
||||||
|
|
|
||||||
|
|
@ -369,6 +369,48 @@ type FormtablerCardBody struct {
|
||||||
ButtonLink string
|
ButtonLink string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormtablerAlert represents a single alert component.
|
||||||
|
type FormtablerAlert struct {
|
||||||
|
Type string // "success", "warning", "danger", "info"
|
||||||
|
Title string
|
||||||
|
Description string
|
||||||
|
List []string // if set, renders as <ul class="alert-list">
|
||||||
|
Important bool
|
||||||
|
Minor bool
|
||||||
|
ShowClose bool
|
||||||
|
Action string // "Action" button text
|
||||||
|
Link string // "Link" anchor text
|
||||||
|
Buttons bool // "Okay" / "Cancel" buttons
|
||||||
|
Avatar bool
|
||||||
|
Class string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerBreadcrumbItem represents a single item in the breadcrumb trail.
|
||||||
|
type FormtablerBreadcrumbItem struct {
|
||||||
|
Title string
|
||||||
|
Link string // empty for the last (active) item
|
||||||
|
HomeIcon bool // render home icon instead of text for the first item
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerBreadcrumb represents a breadcrumb navigation component.
|
||||||
|
type FormtablerBreadcrumb struct {
|
||||||
|
Items []FormtablerBreadcrumbItem
|
||||||
|
Separator string // optional: "dots", "arrows", "bullets"
|
||||||
|
Class string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerToast represents a toast notification component.
|
||||||
|
type FormtablerToast struct {
|
||||||
|
ID string
|
||||||
|
Show bool
|
||||||
|
HideHeader bool
|
||||||
|
PersonName string
|
||||||
|
PersonSrc string
|
||||||
|
Date string
|
||||||
|
Text string
|
||||||
|
Cookies bool // renders cookie consent variant
|
||||||
|
}
|
||||||
|
|
||||||
// FormtablerCardProgress represents a progress bar in the card.
|
// FormtablerCardProgress represents a progress bar in the card.
|
||||||
type FormtablerCardProgress struct {
|
type FormtablerCardProgress struct {
|
||||||
Percent int
|
Percent int
|
||||||
|
|
@ -431,6 +473,14 @@ type FormtablerFormElementsPage struct {
|
||||||
ValidationStates FormtablerValidationStates
|
ValidationStates FormtablerValidationStates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormtablerComponentsPage is the page-specific struct for the combined demo
|
||||||
|
// showing alerts, toasts, and breadcrumbs.
|
||||||
|
type FormtablerComponentsPage struct {
|
||||||
|
Alerts []FormtablerAlert
|
||||||
|
Breadcrumbs []FormtablerBreadcrumb
|
||||||
|
Toasts []FormtablerToast
|
||||||
|
}
|
||||||
|
|
||||||
// TablerPageData holds the common data for all tabler pages.
|
// TablerPageData holds the common data for all tabler pages.
|
||||||
// It should NOT contain component-specific fields like tables or forms.
|
// It should NOT contain component-specific fields like tables or forms.
|
||||||
// Add those by creating a page-specific struct that embeds TablerPageData
|
// Add those by creating a page-specific struct that embeds TablerPageData
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,9 @@ func registerRoutes() {
|
||||||
controller.Get("/tablerdefault", controllers.TablerDefault)
|
controller.Get("/tablerdefault", controllers.TablerDefault)
|
||||||
controller.Get("/tablerhome", controllers.TablerHome)
|
controller.Get("/tablerhome", controllers.TablerHome)
|
||||||
controller.Get("/tablernavmenu", controllers.TablerNavbar)
|
controller.Get("/tablernavmenu", controllers.TablerNavbar)
|
||||||
controller.Get("/tablertable", controllers.TablerTables)
|
controller.Get("/tablertable", controllers.TablerTables)
|
||||||
controller.Get("/tablerformelements", controllers.TablerFormElements)
|
controller.Get("/tablerformelements", controllers.TablerFormElements)
|
||||||
controller.Get("/tablercards", controllers.TablerCards)
|
controller.Get("/tablercards", controllers.TablerCards)
|
||||||
|
controller.Get("/tablercomponents", controllers.TablerComponents)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
40
storage/templates/tabler/includes/alert.html
Normal file
40
storage/templates/tabler/includes/alert.html
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{{define "tabler_alert"}}
|
||||||
|
{{$a := .}}
|
||||||
|
{{$icon := $a.Type}}
|
||||||
|
{{if eq $a.Type "success"}}{{$icon = "check"}}{{else if eq $a.Type "warning"}}{{$icon = "alert-triangle"}}{{else if eq $a.Type "danger"}}{{$icon = "alert-circle"}}{{else if eq $a.Type "info"}}{{$icon = "info-circle"}}{{end}}
|
||||||
|
<div class="alert{{if $a.Important}} alert-important{{else if $a.Minor}} alert-minor{{end}} alert-{{$a.Type}}{{if $a.ShowClose}} alert-dismissible{{end}}{{if $a.Avatar}} alert-avatar{{end}}{{if $a.Class}} {{$a.Class}}{{end}}" role="alert">
|
||||||
|
<div class="alert-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon alert-icon">
|
||||||
|
{{if eq $icon "check"}}<path d="M5 12l5 5l10 -10"></path>
|
||||||
|
{{else if eq $icon "alert-triangle"}}<path d="M12 9v4"></path><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.871l-8.106 -13.534a1.914 1.914 0 0 0 -3.274 0z"></path><path d="M12 16h.01"></path>
|
||||||
|
{{else if eq $icon "alert-circle"}}<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 8v4"></path><path d="M12 16h.01"></path>
|
||||||
|
{{else if eq $icon "info-circle"}}<path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 16v-4"></path><path d="M12 8h.01"></path>
|
||||||
|
{{end}}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{{if or $a.Description $a.List}}
|
||||||
|
<div>
|
||||||
|
<h4 class="alert-heading">{{defaultVal "This is a custom alert box!" $a.Title}}</h4>
|
||||||
|
<div class="alert-description">
|
||||||
|
{{$a.Description}}
|
||||||
|
{{if $a.List}}
|
||||||
|
<ul class="alert-list">
|
||||||
|
{{range $a.List}}<li>{{.}}</li>{{end}}
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{defaultVal "This is a custom alert box!" $a.Title}}
|
||||||
|
{{if $a.Action}}<a href="#" class="alert-action">{{$a.Action}}</a>{{end}}
|
||||||
|
{{if $a.Link}}<a href="#" class="alert-link">{{$a.Link}}</a>{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{if $a.Buttons}}
|
||||||
|
<div class="btn-list">
|
||||||
|
<a href="#" class="btn btn-{{$a.Type}}">Okay</a>
|
||||||
|
<a href="#" class="btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if $a.ShowClose}}<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
22
storage/templates/tabler/includes/breadcrumb.html
Normal file
22
storage/templates/tabler/includes/breadcrumb.html
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{{define "tabler_breadcrumb"}}
|
||||||
|
{{$b := .}}
|
||||||
|
<nav aria-label="Breadcrumb">
|
||||||
|
<ol class="breadcrumb{{if $b.Class}} {{$b.Class}}{{end}}{{if $b.Separator}} breadcrumb-{{$b.Separator}}{{end}}">
|
||||||
|
{{range $i, $item := $b.Items}}
|
||||||
|
{{if $item.Link}}
|
||||||
|
<li class="breadcrumb-item">
|
||||||
|
{{if and (eq $i 0) $item.HomeIcon}}
|
||||||
|
<a href="{{$item.Link}}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M5 12l-2 0l9 -9l9 9l-2 0"></path><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"></path><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"></path></svg>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
<a href="{{$item.Link}}">{{$item.Title}}</a>
|
||||||
|
{{end}}
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="breadcrumb-item active" aria-current="page">{{$item.Title}}</li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
{{end}}
|
||||||
36
storage/templates/tabler/includes/components_content.html
Normal file
36
storage/templates/tabler/includes/components_content.html
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{{define "tabler_components_content"}}
|
||||||
|
{{$c := .}}
|
||||||
|
|
||||||
|
{{if hasField $c "Alerts"}}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header"><h3 class="card-title">Alerts</h3></div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{range $c.Alerts}}
|
||||||
|
{{template "tabler_alert" .}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if hasField $c "Breadcrumbs"}}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header"><h3 class="card-title">Breadcrumbs</h3></div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{range $c.Breadcrumbs}}
|
||||||
|
{{template "tabler_breadcrumb" .}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if hasField $c "Toasts"}}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header"><h3 class="card-title">Toasts</h3></div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{range $c.Toasts}}
|
||||||
|
{{template "tabler_toast" .}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
23
storage/templates/tabler/includes/toast.html
Normal file
23
storage/templates/tabler/includes/toast.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{{define "tabler_toast"}}
|
||||||
|
{{$t := .}}
|
||||||
|
<div class="toast{{if $t.Show}} show{{end}}" id="toast-{{defaultVal "simple" $t.ID}}" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
|
||||||
|
{{if not $t.HideHeader}}
|
||||||
|
<div class="toast-header">
|
||||||
|
<span class="avatar avatar-xs me-2" style="background-image: url({{defaultVal "/public/static/avatars/000m.jpg" $t.PersonSrc}})"></span>
|
||||||
|
<strong class="me-auto">{{defaultVal "Jane Doe" $t.PersonName}}</strong>
|
||||||
|
<small>{{defaultVal "11 mins ago" $t.Date}}</small>
|
||||||
|
<button type="button" class="ms-2 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="toast-body">
|
||||||
|
{{if $t.Cookies}}
|
||||||
|
🍪 Our site uses cookies. By continuing to use our site, you agree to our Cookie Policy.
|
||||||
|
<div class="mt-2 pt-2 border-top">
|
||||||
|
<a href="#" class="btn btn-primary btn-sm">I understand</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{defaultVal "Hello, world! This is a toast message." $t.Text}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
@ -32,6 +32,8 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{else if hasField . "Components"}}
|
||||||
|
{{template "tabler_components_content" .Components}}
|
||||||
{{else if hasField . "Tables"}}
|
{{else if hasField . "Tables"}}
|
||||||
{{range .Tables}}
|
{{range .Tables}}
|
||||||
<div class="card{{if .CardClass}} {{.CardClass}}{{end}}">
|
<div class="card{{if .CardClass}} {{.CardClass}}{{end}}">
|
||||||
|
|
|
||||||
1
storage/templates/tabler_components.html
Normal file
1
storage/templates/tabler_components.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{{template "default_layout" .}}
|
||||||
1
storage/templates/tabler_homepage.html
Normal file
1
storage/templates/tabler_homepage.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{{template "homepage_layout" .}}
|
||||||
226
template-helpers.md
Normal file
226
template-helpers.md
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
# Go Template Helpers
|
||||||
|
|
||||||
|
Custom `html/template` FuncMap extensions that bring Liquid-like expressiveness to Go server-side templates.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## String Helpers
|
||||||
|
|
||||||
|
### `capitalize`
|
||||||
|
|
||||||
|
Uppercases the first letter of a string and lowercases the rest.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h2>{{capitalize .Title}}</h2>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `truncate`
|
||||||
|
|
||||||
|
Cuts a string to at most `n` characters and appends `…` if trimmed. Designed for pipeline use — pass `n` first.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p>{{.Excerpt | truncate 120}}</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `prepend`
|
||||||
|
|
||||||
|
Adds a prefix to the beginning of a string. Designed for pipeline use — pass the prefix first.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<a href="{{.Slug | prepend "/articles/"}}">Read more</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `strAppend`
|
||||||
|
|
||||||
|
Adds a suffix to the end of a string. Designed for pipeline use — pass the suffix first.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<a href="{{.Slug | strAppend ".html"}}">Read more</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `split`
|
||||||
|
|
||||||
|
Divides a string into a slice of substrings by a separator. Designed for pipeline use — pass the separator first. Useful combined with `range` or `join`.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{range split "," .TagString}}
|
||||||
|
<span class="tag">{{.}}</span>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `join`
|
||||||
|
|
||||||
|
Concatenates a string slice into a single string with a separator.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="tags">{{join .Tags " · "}}</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Number Helpers
|
||||||
|
|
||||||
|
### `fmtNumber`
|
||||||
|
|
||||||
|
Formats an integer or float with thousands separators using the English locale.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<span>{{fmtNumber .Views}} views</span>
|
||||||
|
<span>$ {{fmtNumber .Price}}</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Date & Time Helpers
|
||||||
|
|
||||||
|
### `fmtDate`
|
||||||
|
|
||||||
|
Formats a `time.Time` value using a named layout or any custom Go layout string.
|
||||||
|
|
||||||
|
| Named layout | Output example |
|
||||||
|
|---|---|
|
||||||
|
| `"short"` | `02 Jan 2006` |
|
||||||
|
| `"long"` | `02 January 2006` |
|
||||||
|
| `"iso"` | `2006-01-02` |
|
||||||
|
| `"datetime"` | `02 Jan 2006 15:04` |
|
||||||
|
|
||||||
|
```html
|
||||||
|
<time>{{fmtDate .PublishedAt "short"}}</time>
|
||||||
|
<time>{{fmtDate .PublishedAt "02/01/2006"}}</time>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `timeAgo`
|
||||||
|
|
||||||
|
Returns a human-readable relative time string from now (`"just now"`, `"3 hours ago"`, `"2 days ago"`, etc.).
|
||||||
|
|
||||||
|
```html
|
||||||
|
<span class="meta">Published {{timeAgo .PublishedAt}}</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Collection Helpers
|
||||||
|
|
||||||
|
### `first`
|
||||||
|
|
||||||
|
Returns the first element of a slice, or `nil` if the slice is empty.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{with first .Articles}}
|
||||||
|
<h2>{{capitalize .Title}}</h2>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `last`
|
||||||
|
|
||||||
|
Returns the last element of a slice, or `nil` if the slice is empty.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{with last .Articles}}
|
||||||
|
<p>Latest: {{capitalize .Title}}</p>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `sliceOf`
|
||||||
|
|
||||||
|
Returns a sub-range of a slice from index `start` (inclusive) to `end` (exclusive).
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{range sliceOf .Articles 0 3}}
|
||||||
|
<li>{{capitalize .Title}}</li>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `contains`
|
||||||
|
|
||||||
|
Reports whether an item is present in a slice, or a substring exists within a string.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{if contains .Tags "go"}}
|
||||||
|
<span class="badge">Go</span>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if contains .Bio "engineer"}}
|
||||||
|
<p>Engineering post</p>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Logic Helpers
|
||||||
|
|
||||||
|
### `defaultVal`
|
||||||
|
|
||||||
|
Returns a fallback value if the given value is nil or its zero value.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p>{{defaultVal "No subtitle" .Subtitle}}</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `ternary`
|
||||||
|
|
||||||
|
Returns `trueVal` if the condition is true, `falseVal` otherwise. Pass the true value first, then the false value, then the condition.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<span>{{ternary "Active" "Inactive" .IsActive}}</span>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `coalesce`
|
||||||
|
|
||||||
|
Returns the first non-empty, non-nil value from a list of arguments.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h3>{{coalesce .Nickname .FullName "Anonymous"}}</h3>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struct Helpers
|
||||||
|
|
||||||
|
### `hasField`
|
||||||
|
|
||||||
|
Reports whether a struct has a field with the given name. Useful for rendering shared templates across different data types.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{if hasField . "Subtitle"}}
|
||||||
|
<p class="subtitle">{{.Subtitle}}</p>
|
||||||
|
{{end}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pipeline Chaining
|
||||||
|
|
||||||
|
Helpers designed for pipeline use (`truncate`, `prepend`, `strAppend`, `split`) accept their configuration argument first and the input string last, so they compose naturally with `|`.
|
||||||
|
|
||||||
|
```html
|
||||||
|
{{/* chain multiple helpers */}}
|
||||||
|
<td>{{.Title | capitalize | truncate 40}}</td>
|
||||||
|
|
||||||
|
{{/* build a URL from a slug */}}
|
||||||
|
<a href="{{.Slug | prepend "/blog/" | strAppend ".html"}}">
|
||||||
|
{{.Title | capitalize}}
|
||||||
|
</a>
|
||||||
|
```
|
||||||
Loading…
Add table
Add a link
Reference in a new issue