cards
This commit is contained in:
parent
f03b933359
commit
aa651083cd
7 changed files with 330 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TablerCards renders a page with card component demos.
|
||||||
|
// Uses the composition pattern: embeds TablerPageData and adds Cards.
|
||||||
|
func TablerCards(c *core.Context) *core.Response {
|
||||||
|
type cardsPageData struct {
|
||||||
|
TablerPageData
|
||||||
|
Cards []FormtablerCard
|
||||||
|
}
|
||||||
|
data := cardsPageData{
|
||||||
|
TablerPageData: TablerPageData{
|
||||||
|
PageTitle: "Cards",
|
||||||
|
PageDescription: "Card component demo page",
|
||||||
|
ShowTopbar: true,
|
||||||
|
Sidebar: false,
|
||||||
|
PageHeader: "Cards",
|
||||||
|
PagePretitle: "Components",
|
||||||
|
UserName: "Jane Doe",
|
||||||
|
UserRole: "Administrator",
|
||||||
|
NavbarMenu: SampleNavbarMenu(),
|
||||||
|
Content: template.HTML(""),
|
||||||
|
},
|
||||||
|
Cards: SampleCards(),
|
||||||
|
}
|
||||||
|
return c.Response.Template("tabler_cards.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
// TablerFormElements renders a page with all 25 formtabler form components.
|
// TablerFormElements renders a page with all 25 formtabler form components.
|
||||||
// Uses the composition pattern: embeds TablerPageData and adds
|
// Uses the composition pattern: embeds TablerPageData and adds
|
||||||
// a FormElements field containing all form component data.
|
// a FormElements field containing all form component data.
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,86 @@ func SampleNavbarMenu() TablerMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleCards returns 6 sample cards showing different variants.
|
||||||
|
func SampleCards() []FormtablerCard {
|
||||||
|
defaultBody := &FormtablerCardBody{
|
||||||
|
Text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem.",
|
||||||
|
}
|
||||||
|
return []FormtablerCard{
|
||||||
|
// 1. Card with header, body text, and footer
|
||||||
|
{
|
||||||
|
Header: &FormtablerCardHeader{Title: "Card with header and footer"},
|
||||||
|
Body: defaultBody,
|
||||||
|
Footer: &FormtablerCardFooter{Text: "This is standard card footer"},
|
||||||
|
},
|
||||||
|
// 2. Card with image top, status bar, and action button in body
|
||||||
|
{
|
||||||
|
Image: &FormtablerCardImage{Position: "top", Src: "/public/static/photos/coffee-on-a-table-with-other-items.jpg"},
|
||||||
|
Status: &FormtablerCardStatus{Position: "top", Color: "red"},
|
||||||
|
Body: &FormtablerCardBody{
|
||||||
|
Title: "Card with image & status",
|
||||||
|
Subtitle: "Featured card",
|
||||||
|
Text: "This card has an image at the top, a red status bar, and a call-to-action button.",
|
||||||
|
HasButton: true,
|
||||||
|
ButtonText: "View details",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 3. Card with image bottom, progress bar, and footer with elements
|
||||||
|
{
|
||||||
|
Image: &FormtablerCardImage{Position: "bottom", Src: "/public/static/photos/coffee-on-a-table-with-other-items.jpg"},
|
||||||
|
Body: defaultBody,
|
||||||
|
Footer: &FormtablerCardFooter{
|
||||||
|
HasSwitch: true,
|
||||||
|
HasMore: true,
|
||||||
|
},
|
||||||
|
Progress: &FormtablerCardProgress{Percent: 60, Color: "green"},
|
||||||
|
},
|
||||||
|
// 4. Card with header tabs, alert, and footer buttons
|
||||||
|
{
|
||||||
|
Header: &FormtablerCardHeader{
|
||||||
|
UseTabs: true,
|
||||||
|
Tabs: []FormtablerCardTab{
|
||||||
|
{Title: "Active", Active: true, Link: "#"},
|
||||||
|
{Title: "Second", Link: "#"},
|
||||||
|
{Title: "Disabled", Disabled: true, Link: "#"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Alert: &FormtablerCardAlert{Text: "This is an alert message inside the card.", Type: "info"},
|
||||||
|
Body: defaultBody,
|
||||||
|
Footer: &FormtablerCardFooter{
|
||||||
|
ButtonsCancel: "Cancel",
|
||||||
|
ButtonsAction: "Continue",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 5. Card with inactive state, no footer
|
||||||
|
{
|
||||||
|
Inactive: true,
|
||||||
|
Header: &FormtablerCardHeader{Title: "Inactive card"},
|
||||||
|
Body: &FormtablerCardBody{
|
||||||
|
Title: "This card is inactive",
|
||||||
|
Text: "Inactive cards have reduced opacity. They are useful for showing disabled or expired content.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 6. Card with header pills, footer with avatars, and active state
|
||||||
|
{
|
||||||
|
Active: true,
|
||||||
|
Header: &FormtablerCardHeader{
|
||||||
|
UsePills: true,
|
||||||
|
Pills: []FormtablerCardTab{
|
||||||
|
{Title: "All", Active: true, Link: "#"},
|
||||||
|
{Title: "Active", Link: "#"},
|
||||||
|
{Title: "Completed", Link: "#"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Body: defaultBody,
|
||||||
|
Footer: &FormtablerCardFooter{
|
||||||
|
HasCheck: true,
|
||||||
|
HasAvatars: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SampleFormElements returns sample data for all 25 formtabler components.
|
// SampleFormElements returns sample data for all 25 formtabler components.
|
||||||
func SampleFormElements() FormtablerFormElementsPage {
|
func SampleFormElements() FormtablerFormElementsPage {
|
||||||
return FormtablerFormElementsPage{
|
return FormtablerFormElementsPage{
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,103 @@ type FormtablerValidationStates struct {
|
||||||
Lite bool
|
Lite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FormtablerCardStatus represents a status bar on the card.
|
||||||
|
type FormtablerCardStatus struct {
|
||||||
|
Position string // "top", "bottom", "start"
|
||||||
|
Color string // "blue", "red", "green", "yellow", etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardHeader represents a card header section.
|
||||||
|
type FormtablerCardHeader struct {
|
||||||
|
Title string
|
||||||
|
// Tab-based header
|
||||||
|
UseTabs bool
|
||||||
|
Tabs []FormtablerCardTab
|
||||||
|
// Pill-based header
|
||||||
|
UsePills bool
|
||||||
|
Pills []FormtablerCardTab
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardTab represents a single tab/pill in a card header.
|
||||||
|
type FormtablerCardTab struct {
|
||||||
|
Title string
|
||||||
|
Active bool
|
||||||
|
Disabled bool
|
||||||
|
Link string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardAlert represents an alert inside a card.
|
||||||
|
type FormtablerCardAlert struct {
|
||||||
|
Text string
|
||||||
|
Type string // "success", "info", "warning", "danger"
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardImage represents an image at top or bottom of a card.
|
||||||
|
type FormtablerCardImage struct {
|
||||||
|
Position string // "top", "bottom"
|
||||||
|
Src string
|
||||||
|
Ratio string // "21x9", "4x3", etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardFooter represents a card footer.
|
||||||
|
type FormtablerCardFooter struct {
|
||||||
|
Text string // simple footer text
|
||||||
|
// Single button
|
||||||
|
Button string
|
||||||
|
ButtonLink string
|
||||||
|
// Two buttons (Cancel / Action)
|
||||||
|
ButtonsCancel string
|
||||||
|
ButtonsAction string
|
||||||
|
ButtonsActionLink string
|
||||||
|
// Elements row (switch, check, avatars, more)
|
||||||
|
HasSwitch bool
|
||||||
|
HasCheck bool
|
||||||
|
HasAvatars bool
|
||||||
|
HasMore bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardBody represents the body content of a card.
|
||||||
|
type FormtablerCardBody struct {
|
||||||
|
Title string
|
||||||
|
Subtitle string
|
||||||
|
Text string
|
||||||
|
HasButton bool
|
||||||
|
ButtonText string
|
||||||
|
ButtonLink string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCardProgress represents a progress bar in the card.
|
||||||
|
type FormtablerCardProgress struct {
|
||||||
|
Percent int
|
||||||
|
Color string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormtablerCard represents a single card component.
|
||||||
|
// All fields are populated by the caller; the template renders based on what it finds.
|
||||||
|
type FormtablerCard struct {
|
||||||
|
// Outer attributes
|
||||||
|
Link string // if set, card is an <a href> instead of <div>
|
||||||
|
Active bool
|
||||||
|
Inactive bool
|
||||||
|
Class string
|
||||||
|
// Empty state
|
||||||
|
Empty bool
|
||||||
|
// Image top/bottom
|
||||||
|
Image *FormtablerCardImage
|
||||||
|
// Status bar
|
||||||
|
Status *FormtablerCardStatus
|
||||||
|
// Header
|
||||||
|
Header *FormtablerCardHeader
|
||||||
|
// Alert
|
||||||
|
Alert *FormtablerCardAlert
|
||||||
|
// Body
|
||||||
|
Body *FormtablerCardBody
|
||||||
|
// Footer
|
||||||
|
Footer *FormtablerCardFooter
|
||||||
|
// Progress
|
||||||
|
Progress *FormtablerCardProgress
|
||||||
|
}
|
||||||
|
|
||||||
// FormtablerFormElementsPage is the page-specific struct for the form elements demo.
|
// FormtablerFormElementsPage is the page-specific struct for the form elements demo.
|
||||||
// Each field is one of the 25 form element groups.
|
// Each field is one of the 25 form element groups.
|
||||||
type FormtablerFormElementsPage struct {
|
type FormtablerFormElementsPage struct {
|
||||||
|
|
|
||||||
|
|
@ -71,5 +71,6 @@ func registerRoutes() {
|
||||||
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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
117
storage/templates/tabler/includes/card.html
Normal file
117
storage/templates/tabler/includes/card.html
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
{{define "tabler_card"}}
|
||||||
|
{{$card := .}}
|
||||||
|
{{if $card.Link}}<a href="{{$card.Link}}" class="card{{if $card.Active}} card-active{{end}}{{if $card.Inactive}} card-inactive{{end}}{{if $card.Class}} {{$card.Class}}{{end}}">{{else}}<div class="card{{if $card.Active}} card-active{{end}}{{if $card.Inactive}} card-inactive{{end}}{{if $card.Class}} {{$card.Class}}{{end}}">{{end}}
|
||||||
|
|
||||||
|
{{if $card.Empty}}
|
||||||
|
{{template "tabler_card_empty" $card.Empty}}
|
||||||
|
{{else}}
|
||||||
|
|
||||||
|
{{if $card.Image}}
|
||||||
|
{{if eq $card.Image.Position "top"}}
|
||||||
|
<img src="{{$card.Image.Src}}" class="card-img-top" alt="">
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Status}}
|
||||||
|
<div class="card-status-{{$card.Status.Position}} bg-{{defaultVal "blue" $card.Status.Color}}"></div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Header}}
|
||||||
|
<div class="card-header">
|
||||||
|
{{if $card.Header.UseTabs}}
|
||||||
|
<ul class="nav nav-tabs card-header-tabs">
|
||||||
|
{{range $card.Header.Tabs}}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link{{if .Active}} active{{end}}{{if .Disabled}} disabled{{end}}" href="{{defaultVal "#" .Link}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
{{else if $card.Header.UsePills}}
|
||||||
|
<ul class="nav nav-pills card-header-pills">
|
||||||
|
{{range $card.Header.Pills}}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link{{if .Active}} active{{end}}{{if .Disabled}} disabled{{end}}" href="{{defaultVal "#" .Link}}">{{.Title}}</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
{{else}}
|
||||||
|
<h3 class="card-title">{{defaultVal "Header title" $card.Header.Title}}</h3>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Alert}}
|
||||||
|
<div class="card-alert alert alert-{{defaultVal "success" $card.Alert.Type}} mb-0">
|
||||||
|
{{$card.Alert.Text}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{with $card.Body}}
|
||||||
|
<div class="card-body">
|
||||||
|
{{if .Title}}<h3 class="card-title">{{.Title}}</h3>{{end}}
|
||||||
|
{{if .Subtitle}}<div class="card-subtitle">{{.Subtitle}}</div>{{end}}
|
||||||
|
<p class="text-secondary">{{defaultVal "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem." .Text}}</p>
|
||||||
|
{{if .HasButton}}
|
||||||
|
<div class="card-text">
|
||||||
|
<a href="{{defaultVal "#" .ButtonLink}}" class="btn btn-primary">{{defaultVal "Go somewhere" .ButtonText}}</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{with $card.Footer}}
|
||||||
|
<div class="card-footer">
|
||||||
|
{{if or .HasSwitch .HasCheck .HasAvatars .HasMore}}
|
||||||
|
<div class="row align-items-center">
|
||||||
|
{{if .HasSwitch}}
|
||||||
|
<div class="col-auto"><label class="form-check form-switch m-0"><input class="form-check-input" type="checkbox" checked></label></div>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasCheck}}
|
||||||
|
<div class="col-auto"><label class="form-check m-0"><input class="form-check-input" type="checkbox" checked></label></div>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasAvatars}}
|
||||||
|
<div class="col-auto"><div class="avatar-list avatar-list-stacked"><span class="avatar avatar-sm" style="background-image: url(/static/avatars/000m.jpg)"></span><span class="avatar avatar-sm" style="background-image: url(/static/avatars/052f.jpg)"></span><span class="avatar avatar-sm" style="background-image: url(/static/avatars/002m.jpg)"></span><span class="avatar avatar-sm">+3</span></div></div>
|
||||||
|
{{end}}
|
||||||
|
{{if .HasMore}}
|
||||||
|
<div class="col-auto ms-auto"><a href="#">More information</a></div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if .Button}}
|
||||||
|
<a href="{{defaultVal "#" .ButtonLink}}" class="btn btn-primary">{{.Button}}</a>
|
||||||
|
{{else if and .ButtonsCancel .ButtonsAction}}
|
||||||
|
<div class="d-flex">
|
||||||
|
<a href="#" class="btn btn-link">{{.ButtonsCancel}}</a>
|
||||||
|
<a href="{{defaultVal "#" .ButtonsActionLink}}" class="btn btn-primary ms-auto">{{.ButtonsAction}}</a>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{defaultVal "This is standard card footer" .Text}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Image}}
|
||||||
|
{{if eq $card.Image.Position "bottom"}}
|
||||||
|
<img src="{{$card.Image.Src}}" class="card-img-bottom" alt="">
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Progress}}
|
||||||
|
<div class="progress progress-sm card-progress">
|
||||||
|
<div class="progress-bar{{if $card.Progress.Color}} bg-{{$card.Progress.Color}}{{end}}" style="width: {{$card.Progress.Percent}}%"></div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if $card.Link}}</a>{{else}}</div>{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "tabler_card_empty"}}
|
||||||
|
<div class="empty">
|
||||||
|
<div class="empty-img">
|
||||||
|
<img src="/public/static/illustrations/not-found.svg" height="160" alt="">
|
||||||
|
</div>
|
||||||
|
<p class="empty-title">No results found</p>
|
||||||
|
<p class="empty-subtitle text-secondary">Try adjusting your search or filter criteria.</p>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
@ -24,7 +24,15 @@
|
||||||
{{.Content}}
|
{{.Content}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="container-xl{{if .ContainerCentered}} my-auto{{end}}{{if .ContainerClass}} {{.ContainerClass}}{{end}}">
|
<div class="container-xl{{if .ContainerCentered}} my-auto{{end}}{{if .ContainerClass}} {{.ContainerClass}}{{end}}">
|
||||||
{{if hasField . "Tables"}}
|
{{if hasField . "Cards"}}
|
||||||
|
<div class="row row-cards">
|
||||||
|
{{range .Cards}}
|
||||||
|
<div class="col-md-6 col-lg-4">
|
||||||
|
{{template "tabler_card" .}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{else if hasField . "Tables"}}
|
||||||
{{range .Tables}}
|
{{range .Tables}}
|
||||||
<div class="card{{if .CardClass}} {{.CardClass}}{{end}}">
|
<div class="card{{if .CardClass}} {{.CardClass}}{{end}}">
|
||||||
{{template "tabler_table" .}}
|
{{template "tabler_table" .}}
|
||||||
|
|
|
||||||
1
storage/templates/tabler_cards.html
Normal file
1
storage/templates/tabler_cards.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{{template "default_layout" .}}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue