diff --git a/bootstrap/app/handlers/showcase.go b/bootstrap/app/handlers/showcase.go
new file mode 100644
index 0000000..2153596
--- /dev/null
+++ b/bootstrap/app/handlers/showcase.go
@@ -0,0 +1,11 @@
+package handlers
+
+import (
+ "AABBCCDD/app/views/showcase"
+
+ "github.com/anthdm/superkit/kit"
+)
+
+func HandleShowcaseIndex(kit *kit.Kit) error {
+ return kit.Render(showcase.Index())
+}
diff --git a/bootstrap/app/views/showcase/index.templ b/bootstrap/app/views/showcase/index.templ
new file mode 100644
index 0000000..904c6ca
--- /dev/null
+++ b/bootstrap/app/views/showcase/index.templ
@@ -0,0 +1,157 @@
+package showcase
+
+import (
+ "AABBCCDD/app/views/layouts"
+ "AABBCCDD/ui/button"
+ "AABBCCDD/ui/input"
+ "AABBCCDD/ui/modal"
+ "AABBCCDD/ui/card"
+ "AABBCCDD/ui"
+ "AABBCCDD/ui/table"
+)
+
+templ Index() {
+ @layouts.App() {
+
+
+
Buttons
+
+
+
+
+
+
+
+
+
+
+
Card
+
+ @card.Card(ui.Class("max-w-md")) {
+ @card.Header() {
+
User registration
+
Please register to get the latest updates
+ }
+ @card.Content() {
+
+ }
+ @card.Footer() {
+
+ }
+ }
+
+
+
Table
+
+
+ @table.Table() {
+ @table.Header(ui.Class("text-left")) {
+
+
+
+
+ |
+
id |
+
email |
+
first name |
+
last name |
+
action |
+ }
+ @table.Body() {
+
+
+
+
+
+ |
+ 1 |
+ foo@foo.com |
+ Anthony |
+ GG |
+ view |
+
+
+
+
+
+
+ |
+ 1 |
+ foo@foo.com |
+ Anthony |
+ GG |
+ view |
+
+
+
+
+
+
+ |
+ 1 |
+ foo@foo.com |
+ Anthony |
+ GG |
+ view |
+
+
+
+
+
+
+ |
+ 1 |
+ foo@foo.com |
+ Anthony |
+ GG |
+ view |
+
+ }
+ }
+
+
+
+
Modal
+
+ @modal.Modal() {
+ @modal.Header() {
+ the header
+ }
+ @modal.Content() {
+ the content
+ }
+ @modal.Trigger() {
+
trigger me
+ }
+ }
+
+
+ }
+}
diff --git a/bootstrap/public/assets/styles.css b/bootstrap/public/assets/styles.css
index 3824ab2..97f2d7f 100644
--- a/bootstrap/public/assets/styles.css
+++ b/bootstrap/public/assets/styles.css
@@ -629,23 +629,63 @@ body {
position: fixed;
}
+.absolute {
+ position: absolute;
+}
+
+.relative {
+ position: relative;
+}
+
+.inset-0 {
+ inset: 0px;
+}
+
+.left-0 {
+ left: 0px;
+}
+
+.right-0 {
+ right: 0px;
+}
+
.right-6 {
right: 1.5rem;
}
+.top-0 {
+ top: 0px;
+}
+
.top-6 {
top: 1.5rem;
}
+.z-50 {
+ z-index: 50;
+}
+
+.z-\[99\] {
+ z-index: 99;
+}
+
.mx-auto {
margin-left: auto;
margin-right: auto;
}
+.mb-6 {
+ margin-bottom: 1.5rem;
+}
+
.ml-4 {
margin-left: 1rem;
}
+.mr-5 {
+ margin-right: 1.25rem;
+}
+
.mt-10 {
margin-top: 2.5rem;
}
@@ -654,6 +694,14 @@ body {
margin-top: 8rem;
}
+.mt-5 {
+ margin-top: 1.25rem;
+}
+
+.mt-8 {
+ margin-top: 2rem;
+}
+
.inline-block {
display: inline-block;
}
@@ -666,14 +714,58 @@ body {
display: inline-flex;
}
+.table {
+ display: table;
+}
+
.hidden {
display: none;
}
+.h-10 {
+ height: 2.5rem;
+}
+
+.h-4 {
+ height: 1rem;
+}
+
+.h-5 {
+ height: 1.25rem;
+}
+
+.h-8 {
+ height: 2rem;
+}
+
+.h-auto {
+ height: auto;
+}
+
+.h-full {
+ height: 100%;
+}
+
.h-screen {
height: 100vh;
}
+.w-4 {
+ width: 1rem;
+}
+
+.w-5 {
+ width: 1.25rem;
+}
+
+.w-8 {
+ width: 2rem;
+}
+
+.w-auto {
+ width: auto;
+}
+
.w-fit {
width: -moz-fit-content;
width: fit-content;
@@ -683,10 +775,22 @@ body {
width: 100%;
}
+.w-screen {
+ width: 100vw;
+}
+
+.min-w-full {
+ min-width: 100%;
+}
+
.max-w-2xl {
max-width: 42rem;
}
+.max-w-4xl {
+ max-width: 56rem;
+}
+
.max-w-7xl {
max-width: 80rem;
}
@@ -699,6 +803,20 @@ body {
max-width: 24rem;
}
+.max-w-xs {
+ max-width: 20rem;
+}
+
+.translate-y-0 {
+ --tw-translate-y: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.translate-y-4 {
+ --tw-translate-y: 1rem;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
.cursor-pointer {
cursor: pointer;
}
@@ -755,6 +873,36 @@ body {
gap: 2rem;
}
+.divide-y > :not([hidden]) ~ :not([hidden]) {
+ --tw-divide-y-reverse: 0;
+ border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
+ border-bottom-width: calc(1px * var(--tw-divide-y-reverse));
+}
+
+.overflow-hidden {
+ overflow: hidden;
+}
+
+.overflow-x-auto {
+ overflow-x: auto;
+}
+
+.whitespace-nowrap {
+ white-space: nowrap;
+}
+
+.rounded {
+ border-radius: 0.25rem;
+}
+
+.rounded-full {
+ border-radius: 9999px;
+}
+
+.rounded-lg {
+ border-radius: var(--radius);
+}
+
.rounded-md {
border-radius: calc(var(--radius) - 2px);
}
@@ -772,20 +920,49 @@ body {
border-color: hsl(var(--input) / var(--tw-border-opacity));
}
+.border-primary {
+ --tw-border-opacity: 1;
+ border-color: hsl(var(--primary) / var(--tw-border-opacity));
+}
+
.border-red-500 {
--tw-border-opacity: 1;
border-color: rgb(239 68 68 / var(--tw-border-opacity));
}
+.bg-black {
+ --tw-bg-opacity: 1;
+ background-color: rgb(0 0 0 / var(--tw-bg-opacity));
+}
+
+.bg-card {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--card) / var(--tw-bg-opacity));
+}
+
+.bg-destructive {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--destructive) / var(--tw-bg-opacity));
+}
+
.bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
+.bg-secondary {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
+}
+
.bg-transparent {
background-color: transparent;
}
+.bg-opacity-40 {
+ --tw-bg-opacity: 0.4;
+}
+
.bg-gradient-to-r {
background-image: linear-gradient(to right, var(--tw-gradient-stops));
}
@@ -810,6 +987,10 @@ body {
background-clip: text;
}
+.p-6 {
+ padding: 1.5rem;
+}
+
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
@@ -820,16 +1001,31 @@ body {
padding-right: 1rem;
}
+.px-5 {
+ padding-left: 1.25rem;
+ padding-right: 1.25rem;
+}
+
.px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
+.px-7 {
+ padding-left: 1.75rem;
+ padding-right: 1.75rem;
+}
+
.px-8 {
padding-left: 2rem;
padding-right: 2rem;
}
+.py-1 {
+ padding-top: 0.25rem;
+ padding-bottom: 0.25rem;
+}
+
.py-12 {
padding-top: 3rem;
padding-bottom: 3rem;
@@ -845,10 +1041,45 @@ body {
padding-bottom: 0.75rem;
}
+.py-4 {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+}
+
+.py-6 {
+ padding-top: 1.5rem;
+ padding-bottom: 1.5rem;
+}
+
+.py-8 {
+ padding-top: 2rem;
+ padding-bottom: 2rem;
+}
+
+.pb-2 {
+ padding-bottom: 0.5rem;
+}
+
+.pt-0 {
+ padding-top: 0px;
+}
+
+.pt-2 {
+ padding-top: 0.5rem;
+}
+
+.text-left {
+ text-align: left;
+}
+
.text-center {
text-align: center;
}
+.text-right {
+ text-align: right;
+}
+
.align-middle {
vertical-align: middle;
}
@@ -908,16 +1139,35 @@ body {
letter-spacing: 0.025em;
}
+.text-blue-500 {
+ --tw-text-opacity: 1;
+ color: rgb(59 130 246 / var(--tw-text-opacity));
+}
+
+.text-card-foreground {
+ --tw-text-opacity: 1;
+ color: hsl(var(--card-foreground) / var(--tw-text-opacity));
+}
+
.text-foreground {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
+.text-foreground\/60 {
+ color: hsl(var(--foreground) / 0.6);
+}
+
.text-muted-foreground {
--tw-text-opacity: 1;
color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
}
+.text-primary {
+ --tw-text-opacity: 1;
+ color: hsl(var(--primary) / var(--tw-text-opacity));
+}
+
.text-primary-foreground {
--tw-text-opacity: 1;
color: hsl(var(--primary-foreground) / var(--tw-text-opacity));
@@ -932,16 +1182,33 @@ body {
color: transparent;
}
+.text-white {
+ --tw-text-opacity: 1;
+ color: rgb(255 255 255 / var(--tw-text-opacity));
+}
+
.underline {
text-decoration-line: underline;
}
+.opacity-0 {
+ opacity: 0;
+}
+
+.opacity-100 {
+ opacity: 1;
+}
+
.shadow-sm {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
+.outline {
+ outline-style: solid;
+}
+
.ring-offset-background {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
@@ -956,12 +1223,51 @@ body {
transition-duration: 200ms;
}
+.duration-300 {
+ transition-duration: 300ms;
+}
+
+.ease-in {
+ transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
+}
+
+.ease-out {
+ transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
+}
+
/* fix for Alpine users. */
[x-cloak] {
display: none !important;
}
+.file\:border-0::file-selector-button {
+ border-width: 0px;
+}
+
+.file\:bg-transparent::file-selector-button {
+ background-color: transparent;
+}
+
+.file\:text-sm::file-selector-button {
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+}
+
+.file\:font-medium::file-selector-button {
+ font-weight: 500;
+}
+
+.placeholder\:text-muted-foreground::-moz-placeholder {
+ --tw-text-opacity: 1;
+ color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
+}
+
+.placeholder\:text-muted-foreground::placeholder {
+ --tw-text-opacity: 1;
+ color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
+}
+
.placeholder\:text-neutral-500::-moz-placeholder {
--tw-text-opacity: 1;
color: rgb(115 115 115 / var(--tw-text-opacity));
@@ -972,10 +1278,27 @@ body {
color: rgb(115 115 115 / var(--tw-text-opacity));
}
+.hover\:bg-destructive\/80:hover {
+ background-color: hsl(var(--destructive) / 0.8);
+}
+
.hover\:bg-primary\/90:hover {
background-color: hsl(var(--primary) / 0.9);
}
+.hover\:bg-secondary:hover {
+ --tw-bg-opacity: 1;
+ background-color: hsl(var(--secondary) / var(--tw-bg-opacity));
+}
+
+.hover\:bg-secondary\/80:hover {
+ background-color: hsl(var(--secondary) / 0.8);
+}
+
+.hover\:text-foreground\/80:hover {
+ color: hsl(var(--foreground) / 0.8);
+}
+
.focus\:border-neutral-300:focus {
--tw-border-opacity: 1;
border-color: rgb(212 212 212 / var(--tw-border-opacity));
@@ -997,6 +1320,22 @@ body {
--tw-ring-color: hsl(var(--primary) / var(--tw-ring-opacity));
}
+.focus-visible\:outline-none:focus-visible {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.focus-visible\:ring-1:focus-visible {
+ --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
+ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
+}
+
+.focus-visible\:ring-ring:focus-visible {
+ --tw-ring-opacity: 1;
+ --tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
+}
+
.disabled\:cursor-not-allowed:disabled {
cursor: not-allowed;
}
@@ -1005,6 +1344,33 @@ body {
opacity: 0.5;
}
+@media (min-width: 640px) {
+ .sm\:max-w-lg {
+ max-width: 32rem;
+ }
+
+ .sm\:translate-y-0 {
+ --tw-translate-y: 0px;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+ }
+
+ .sm\:scale-100 {
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+ }
+
+ .sm\:scale-95 {
+ --tw-scale-x: .95;
+ --tw-scale-y: .95;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+ }
+
+ .sm\:rounded-lg {
+ border-radius: var(--radius);
+ }
+}
+
@media (min-width: 1024px) {
.lg\:mt-20 {
margin-top: 5rem;
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..1f527fe
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,20 @@
+github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U=
+github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
+github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
+github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg=
+github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/ui/button/button.go b/ui/button/button.go
new file mode 100644
index 0000000..3820e6b
--- /dev/null
+++ b/ui/button/button.go
@@ -0,0 +1,59 @@
+package button
+
+import (
+ "AABBCCDD/ui"
+
+ "github.com/a-h/templ"
+)
+
+const (
+ buttonBaseClass = "inline-flex items-center justify-center px-4 py-2 font-medium text-sm tracking-wide transition-colors duration-200 rounded-md focus:ring focus:shadow-outline focus:outline-none"
+ buttonVariantPrimary = "text-primary-foreground bg-primary focus:ring-primary hover:bg-primary/90"
+ buttonVariantOutline = "text-primary border border-primary hover:bg-secondary focus:ring-primary"
+ buttonVariantSecondary = "text-primary bg-secondary hover:bg-secondary/80"
+ buttonVariantDestructive = "text-primary bg-destructive hover:bg-destructive/80"
+)
+
+func New(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(buttonBaseClass, buttonVariantPrimary, opts...)
+}
+
+func Outline(opts ...func(*templ.Attributes)) templ.Attributes {
+ return appendVariant("outline", opts...)
+}
+
+func Primary(opts ...func(*templ.Attributes)) templ.Attributes {
+ return appendVariant("primary", opts...)
+}
+
+func Secondary(opts ...func(*templ.Attributes)) templ.Attributes {
+ return appendVariant("secondary", opts...)
+}
+
+func Destructive(opts ...func(*templ.Attributes)) templ.Attributes {
+ return appendVariant("destructive", opts...)
+}
+
+func Variant(variant string) func(*templ.Attributes) {
+ return func(attrs *templ.Attributes) {
+ att := *attrs
+ switch variant {
+ case "primary":
+ att["class"] = ui.Merge(buttonBaseClass, buttonVariantPrimary)
+ case "outline":
+ att["class"] = ui.Merge(buttonBaseClass, buttonVariantOutline)
+ case "secondary":
+ att["class"] = ui.Merge(buttonBaseClass, buttonVariantSecondary)
+ case "destructive":
+ att["class"] = ui.Merge(buttonBaseClass, buttonVariantDestructive)
+ }
+ }
+}
+
+func appendVariant(variant string, opts ...func(*templ.Attributes)) templ.Attributes {
+ opt := []func(*templ.Attributes){
+ Variant(variant),
+ }
+ opt = append(opt, opts...)
+ return New(opt...)
+}
diff --git a/ui/card/card.templ b/ui/card/card.templ
new file mode 100644
index 0000000..6ca2beb
--- /dev/null
+++ b/ui/card/card.templ
@@ -0,0 +1,29 @@
+package card
+
+import "AABBCCDD/ui"
+
+const cardBaseClass = "rounded-lg border bg-card text-card-foreground shadow-sm"
+
+templ Card(opts ...func(*templ.Attributes)) {
+
+ { children... }
+
+}
+
+templ Header(opts ...func(*templ.Attributes)) {
+
+ { children... }
+
+}
+
+templ Content(opts ...func(*templ.Attributes)) {
+
+ { children... }
+
+}
+
+templ Footer(opts ...func(*templ.Attributes)) {
+
+ { children... }
+
+}
diff --git a/ui/card/card_templ.go b/ui/card/card_templ.go
new file mode 100644
index 0000000..2e85b03
--- /dev/null
+++ b/ui/card/card_templ.go
@@ -0,0 +1,175 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.707
+package card
+
+//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 "AABBCCDD/ui"
+
+const cardBaseClass = "rounded-lg border bg-card text-card-foreground shadow-sm"
+
+func Card(opts ...func(*templ.Attributes)) 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)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Header(opts ...func(*templ.Attributes)) 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("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Content(opts ...func(*templ.Attributes)) 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_Var3 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var3 == nil {
+ templ_7745c5c3_Var3 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var3.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Footer(opts ...func(*templ.Attributes)) 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_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var4.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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
+ })
+}
diff --git a/ui/input/input.go b/ui/input/input.go
new file mode 100644
index 0000000..b6ed87d
--- /dev/null
+++ b/ui/input/input.go
@@ -0,0 +1,13 @@
+package input
+
+import (
+ "github.com/a-h/templ"
+
+ "AABBCCDD/ui"
+)
+
+const defaultInputClass = "flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
+
+func Input(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(defaultInputClass, "", opts...)
+}
diff --git a/ui/modal/modal.templ b/ui/modal/modal.templ
new file mode 100644
index 0000000..895aad1
--- /dev/null
+++ b/ui/modal/modal.templ
@@ -0,0 +1,70 @@
+package modal
+
+templ Modal() {
+
+
+ foo
+
+
+
+
+
+ { children... }
+
+ foo
+
+
+
+
+
+}
+
+templ Header() {
+
+
+ { children... }
+
+
+
+}
+
+templ Content() {
+
+ { children... }
+
+}
+
+templ Trigger() {
+
+ { children... }
+
+}
+
+templ Footer() {
+}
diff --git a/ui/modal/modal_templ.go b/ui/modal/modal_templ.go
new file mode 100644
index 0000000..b4b69bd
--- /dev/null
+++ b/ui/modal/modal_templ.go
@@ -0,0 +1,159 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.707
+package modal
+
+//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"
+
+func Modal() 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)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("foo
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
foo
")
+ 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 Header() 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("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Content() 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_Var3 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var3 == nil {
+ templ_7745c5c3_Var3 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var3.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Trigger() 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_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var4.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Footer() 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_Var5 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var5 == nil {
+ templ_7745c5c3_Var5 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ if !templ_7745c5c3_IsBuffer {
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
+ }
+ return templ_7745c5c3_Err
+ })
+}
diff --git a/ui/table/table.templ b/ui/table/table.templ
new file mode 100644
index 0000000..c7089c7
--- /dev/null
+++ b/ui/table/table.templ
@@ -0,0 +1,54 @@
+package table
+
+import (
+ "AABBCCDD/ui"
+)
+
+templ Table() {
+
+}
+
+templ Header(opts ...func(*templ.Attributes)) {
+
+
+ { children... }
+
+
+}
+
+templ Body(opts ...func(*templ.Attributes)) {
+
+ { children... }
+
+}
+
+templ Footer(opts ...func(*templ.Attributes)) {
+
+
+ { children... }
+
+
+}
+
+const (
+ thBaseClass = "px-5 py-3 text-xs font-medium uppercase"
+ tdBaseClass = "px-5 py-4 text-sm whitespace-nowrap"
+)
+
+func Td(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(tdBaseClass, "", opts...)
+}
+
+func Th(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(thBaseClass, "", opts...)
+}
diff --git a/ui/table/table_templ.go b/ui/table/table_templ.go
new file mode 100644
index 0000000..33cbb30
--- /dev/null
+++ b/ui/table/table_templ.go
@@ -0,0 +1,172 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.2.707
+package table
+
+//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 (
+ "AABBCCDD/ui"
+)
+
+func Table() 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)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Header(opts ...func(*templ.Attributes)) 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("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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 Body(opts ...func(*templ.Attributes)) 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_Var3 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var3 == nil {
+ templ_7745c5c3_Var3 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var3.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ 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 Footer(opts ...func(*templ.Attributes)) 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_Var4 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var4 == nil {
+ templ_7745c5c3_Var4 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var4.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
")
+ 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
+ })
+}
+
+const (
+ thBaseClass = "px-5 py-3 text-xs font-medium uppercase"
+ tdBaseClass = "px-5 py-4 text-sm whitespace-nowrap"
+)
+
+func Td(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(tdBaseClass, "", opts...)
+}
+
+func Th(opts ...func(*templ.Attributes)) templ.Attributes {
+ return ui.CreateAttrs(thBaseClass, "", opts...)
+}
diff --git a/ui/ui.go b/ui/ui.go
new file mode 100644
index 0000000..7460d0d
--- /dev/null
+++ b/ui/ui.go
@@ -0,0 +1,29 @@
+package ui
+
+import (
+ "fmt"
+
+ "github.com/a-h/templ"
+)
+
+func CreateAttrs(baseClass string, defaultClass string, opts ...func(*templ.Attributes)) templ.Attributes {
+ attrs := templ.Attributes{
+ "class": baseClass + " " + defaultClass,
+ }
+ for _, o := range opts {
+ o(&attrs)
+ }
+ return attrs
+}
+
+func Merge(a, b string) string {
+ return fmt.Sprintf("%s %s", a, b)
+}
+
+func Class(class string) func(*templ.Attributes) {
+ return func(attrs *templ.Attributes) {
+ attr := *attrs
+ class := attr["class"].(string) + " " + class
+ attr["class"] = class
+ }
+}