From aa651083cd324888d3fbcb7c9dbb95fb5f2ede13 Mon Sep 17 00:00:00 2001 From: JACS Date: Sat, 2 May 2026 23:51:21 -0500 Subject: [PATCH] cards --- controllers/tablerbase.go | 25 ++++ controllers/tablerdata.go | 80 ++++++++++++ controllers/tablertypes.go | 97 +++++++++++++++ routes.go | 1 + storage/templates/tabler/includes/card.html | 117 ++++++++++++++++++ storage/templates/tabler/layouts/default.html | 10 +- storage/templates/tabler_cards.html | 1 + 7 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 storage/templates/tabler/includes/card.html create mode 100644 storage/templates/tabler_cards.html diff --git a/controllers/tablerbase.go b/controllers/tablerbase.go index e59ae52..d5aad5d 100644 --- a/controllers/tablerbase.go +++ b/controllers/tablerbase.go @@ -69,6 +69,31 @@ func TablerNavbar(c *core.Context) *core.Response { 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. // Uses the composition pattern: embeds TablerPageData and adds // a FormElements field containing all form component data. diff --git a/controllers/tablerdata.go b/controllers/tablerdata.go index 7253db9..9e72e53 100644 --- a/controllers/tablerdata.go +++ b/controllers/tablerdata.go @@ -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. func SampleFormElements() FormtablerFormElementsPage { return FormtablerFormElementsPage{ diff --git a/controllers/tablertypes.go b/controllers/tablertypes.go index 8ea4a95..dbac532 100644 --- a/controllers/tablertypes.go +++ b/controllers/tablertypes.go @@ -304,6 +304,103 @@ type FormtablerValidationStates struct { 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 instead of
+ 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. // Each field is one of the 25 form element groups. type FormtablerFormElementsPage struct { diff --git a/routes.go b/routes.go index 0f61c79..67b7718 100644 --- a/routes.go +++ b/routes.go @@ -71,5 +71,6 @@ func registerRoutes() { controller.Get("/tablernavmenu", controllers.TablerNavbar) controller.Get("/tablertable", controllers.TablerTables) controller.Get("/tablerformelements", controllers.TablerFormElements) + controller.Get("/tablercards", controllers.TablerCards) } diff --git a/storage/templates/tabler/includes/card.html b/storage/templates/tabler/includes/card.html new file mode 100644 index 0000000..37fece5 --- /dev/null +++ b/storage/templates/tabler/includes/card.html @@ -0,0 +1,117 @@ +{{define "tabler_card"}} +{{$card := .}} +{{if $card.Link}}{{else}}
{{end}} + + {{if $card.Empty}} + {{template "tabler_card_empty" $card.Empty}} + {{else}} + + {{if $card.Image}} + {{if eq $card.Image.Position "top"}} + + {{end}} + {{end}} + + {{if $card.Status}} +
+ {{end}} + + {{if $card.Header}} +
+ {{if $card.Header.UseTabs}} + + {{else if $card.Header.UsePills}} + + {{else}} +

{{defaultVal "Header title" $card.Header.Title}}

+ {{end}} +
+ {{end}} + + {{if $card.Alert}} +
+ {{$card.Alert.Text}} +
+ {{end}} + + {{with $card.Body}} +
+ {{if .Title}}

{{.Title}}

{{end}} + {{if .Subtitle}}
{{.Subtitle}}
{{end}} +

{{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}}

+ {{if .HasButton}} + + {{end}} +
+ {{end}} + + {{with $card.Footer}} + + {{end}} + + {{if $card.Image}} + {{if eq $card.Image.Position "bottom"}} + + {{end}} + {{end}} + + {{if $card.Progress}} +
+
+
+ {{end}} + + {{end}} + +{{if $card.Link}}{{else}}
{{end}} +{{end}} + +{{define "tabler_card_empty"}} +
+
+ +
+

No results found

+

Try adjusting your search or filter criteria.

+
+{{end}} diff --git a/storage/templates/tabler/layouts/default.html b/storage/templates/tabler/layouts/default.html index 8bb340c..0446f9b 100644 --- a/storage/templates/tabler/layouts/default.html +++ b/storage/templates/tabler/layouts/default.html @@ -24,7 +24,15 @@ {{.Content}} {{else}}
- {{if hasField . "Tables"}} + {{if hasField . "Cards"}} +
+ {{range .Cards}} +
+ {{template "tabler_card" .}} +
+ {{end}} +
+ {{else if hasField . "Tables"}} {{range .Tables}}
{{template "tabler_table" .}} diff --git a/storage/templates/tabler_cards.html b/storage/templates/tabler_cards.html new file mode 100644 index 0000000..0681260 --- /dev/null +++ b/storage/templates/tabler_cards.html @@ -0,0 +1 @@ +{{template "default_layout" .}} \ No newline at end of file