1
0
mirror of https://github.com/axzilla/templui.git synced 2025-02-06 10:44:17 +00:00

feat(form WIP): enhance showcase components with new layouts and improved accessibility

This commit is contained in:
axzilla 2024-12-05 08:16:52 +07:00
parent 6c9dc2c483
commit fc85d583ec
72 changed files with 2016 additions and 1131 deletions

View File

@ -1,5 +1,5 @@
# Build-Stage
FROM golang:1.22-alpine AS build
FROM golang:1.23-alpine AS build
WORKDIR /app
# Copy the source code

View File

@ -699,6 +699,10 @@ body {
left: 50%;
}
.left-4 {
left: 1rem;
}
.left-full {
left: 100%;
}
@ -751,10 +755,6 @@ body {
z-index: 50;
}
.m-0 {
margin: 0px;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@ -792,6 +792,10 @@ body {
margin-bottom: 2rem;
}
.ml-3 {
margin-left: 0.75rem;
}
.ml-auto {
margin-left: auto;
}
@ -986,22 +990,18 @@ body {
width: 1.75rem;
}
.w-72 {
width: 18rem;
}
.w-8 {
width: 2rem;
}
.w-96 {
width: 24rem;
}
.w-full {
width: 100%;
}
.max-w-0 {
max-width: 0px;
}
.max-w-3xl {
max-width: 48rem;
}
@ -1010,10 +1010,18 @@ body {
max-width: 80rem;
}
.max-w-\[200px\] {
max-width: 200px;
}
.max-w-md {
max-width: 28rem;
}
.max-w-sm {
max-width: 24rem;
}
.max-w-xl {
max-width: 36rem;
}
@ -1113,6 +1121,16 @@ body {
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));
}
@keyframes pulse {
50% {
opacity: .5;
}
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.cursor-not-allowed {
cursor: not-allowed;
}
@ -1212,6 +1230,10 @@ body {
gap: 0.5rem;
}
.gap-3 {
gap: 0.75rem;
}
.gap-4 {
gap: 1rem;
}
@ -1442,6 +1464,11 @@ body {
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.bg-purple-500 {
--tw-bg-opacity: 1;
background-color: rgb(168 85 247 / var(--tw-bg-opacity));
}
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
@ -1570,6 +1597,10 @@ body {
padding-bottom: 1rem;
}
.pl-3 {
padding-left: 0.75rem;
}
.pl-6 {
padding-left: 1.5rem;
}
@ -1772,6 +1803,10 @@ body {
opacity: 1;
}
.opacity-50 {
opacity: 0.5;
}
.opacity-80 {
opacity: 0.8;
}
@ -1815,6 +1850,11 @@ body {
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
}
.ring-destructive {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--destructive) / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
@ -1888,6 +1928,10 @@ body {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
@ -2255,6 +2299,10 @@ body {
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.peer:checked ~ .peer-checked\:opacity-100 {
opacity: 1;
}
.peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
content: var(--tw-content);
--tw-translate-x: 16px;
@ -2313,11 +2361,6 @@ body {
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.dark\:hover\:bg-gray-700:hover:is(.dark *) {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
@ -2511,19 +2554,6 @@ body {
background-color: hsl(var(--primary) / 0.9);
}
.\[\&\:has\(input\:checked\)\]\:text-foreground:has(input:checked) {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.\[\&\:has\(input\:disabled\)\]\:cursor-not-allowed:has(input:disabled) {
cursor: not-allowed;
}
.\[\&\:has\(input\:disabled\)\]\:opacity-50:has(input:disabled) {
opacity: 0.5;
}
.\[\&\:has\(svg\)\]\:pl-11:has(svg) {
padding-left: 2.75rem;
}

View File

@ -8,15 +8,17 @@ import (
"github.com/a-h/templ"
"github.com/axzilla/goilerplate/assets"
"github.com/axzilla/goilerplate/internals/config"
"github.com/axzilla/goilerplate/internals/middleware"
"github.com/axzilla/goilerplate/internals/ui/pages"
)
func main() {
mux := http.NewServeMux()
config.LoadConfig()
SetupAssetsRoutes(mux)
wrappedMux := middleware.WithPreviewCheck(mux)
mux.Handle("GET /", templ.Handler(pages.Landing()))
mux.Handle("GET /docs/components", http.RedirectHandler("/docs/components/accordion", http.StatusSeeOther))
mux.Handle("GET /docs/getting-started", http.RedirectHandler("/docs/introduction", http.StatusSeeOther))
@ -35,7 +37,7 @@ func main() {
mux.Handle("GET /docs/components/icon", templ.Handler(pages.Icon()))
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
mux.Handle("GET /docs/components/modal", templ.Handler(pages.Modal()))
mux.Handle("GET /docs/components/radio-group", templ.Handler(pages.RadioGroup()))
mux.Handle("GET /docs/components/radio", templ.Handler(pages.Radio()))
mux.Handle("GET /docs/components/select", templ.Handler(pages.Select()))
mux.Handle("GET /docs/components/sheet", templ.Handler(pages.Sheet()))
mux.Handle("GET /docs/components/slider", templ.Handler(pages.Slider()))
@ -44,7 +46,7 @@ func main() {
mux.Handle("GET /docs/components/toggle", templ.Handler(pages.Toggle()))
fmt.Println("Server is running on http://localhost:8090")
http.ListenAndServe(":8090", mux)
http.ListenAndServe(":8090", wrappedMux)
}
func SetupAssetsRoutes(mux *http.ServeMux) {

View File

@ -1,6 +1,7 @@
package config
import (
"context"
"fmt"
"log"
"os"
@ -26,3 +27,14 @@ func LoadConfig() {
GoEnv: os.Getenv("GO_ENV"),
}
}
type contextKey string
var PreviewContextKey = contextKey("preview")
func IsPreview(ctx context.Context) bool {
if preview, ok := ctx.Value(PreviewContextKey).(bool); ok {
return preview
}
return false
}

View File

@ -0,0 +1,17 @@
package middleware
import (
"context"
"net/http"
"strings"
"github.com/axzilla/goilerplate/internals/config"
)
func WithPreviewCheck(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
isPreview := strings.HasPrefix(r.Host, "preview.")
ctx := context.WithValue(r.Context(), config.PreviewContextKey, isPreview)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

View File

@ -78,8 +78,8 @@ var Sections = []Section{
Href: "/docs/components/modal",
},
{
Text: "Radio Group",
Href: "/docs/components/radio-group",
Text: "Radio",
Href: "/docs/components/radio",
},
{
Text: "Select",

View File

@ -1,6 +1,7 @@
package layouts
import "github.com/axzilla/goilerplate/internals/config"
import "github.com/axzilla/goilerplate/internals/ui/modules"
templ BaseLayout() {
<!DOCTYPE html>
@ -53,6 +54,9 @@ templ BaseLayout() {
>
<div class="flex flex-col min-h-screen">
{ children... }
if config.IsPreview(ctx) {
@modules.PreviewIndicator()
}
</div>
</body>
</html>

View File

@ -7,18 +7,11 @@ import (
type showcaseWrapperProps struct {
Content templ.Component
Class string
}
templ showcaseWrapper(p showcaseWrapperProps) {
<div class="flex justify-center items-center border rounded-md py-16 px-4">
if p.Class != "" {
<div class={ p.Class }>
@p.Content
</div>
} else {
@p.Content
}
@p.Content
</div>
}
@ -27,7 +20,6 @@ type ExampleWrapperProps struct {
ShowcaseFile templ.Component
PreviewCodeFile string
ComponentCodeFile string
ShowcaseClass string
}
templ ExampleWrapper(p ExampleWrapperProps) {
@ -49,7 +41,6 @@ func generateTabs(p ExampleWrapperProps) []components.Tab {
Title: "Preview",
Content: showcaseWrapper(showcaseWrapperProps{
Content: p.ShowcaseFile,
Class: p.ShowcaseClass,
}),
},
{

View File

@ -0,0 +1,36 @@
package modules
import "github.com/axzilla/goilerplate/pkg/icons"
templ PreviewIndicator() {
<div
class="fixed bottom-4 left-4 z-50"
x-data="{ expanded: false }"
>
<div
class="relative bg-purple-500 text-white rounded-lg shadow-lg overflow-hidden"
@mouseenter="expanded = true"
@mouseleave="expanded = false"
>
// Base layout - always visible
<div class="flex items-center h-9 px-3">
<div class="flex items-center gap-2">
@icons.Sparkles(icons.IconProps{Size: "16", Class: "animate-pulse"})
<span class="text-sm font-medium">Preview Mode</span>
</div>
// Extra content - slides in/out
<div
class="flex items-center gap-3 overflow-hidden transition-all duration-300 ease-in-out"
:class="expanded ? 'ml-3 max-w-[200px] opacity-100' : 'max-w-0 opacity-0'"
>
<div class="border-l pl-3 whitespace-nowrap">
<a href="https://goilerplate.com" class="text-sm hover:underline flex items-center gap-1">
Production Site
@icons.ArrowRight(icons.IconProps{Size: "14"})
</a>
</div>
</div>
</div>
</div>
</div>
}

View File

@ -24,12 +24,30 @@ templ Checkbox() {
PreviewCodeFile: "checkbox_checked.templ",
ComponentCodeFile: "checkbox.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.CheckboxWithLabel(),
PreviewCodeFile: "checkbox_with_label.templ",
ComponentCodeFile: "checkbox.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.CheckboxDisabled(),
PreviewCodeFile: "checkbox_disabled.templ",
ComponentCodeFile: "checkbox.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Custom Icon",
ShowcaseFile: showcase.CheckboxCustomIcon(),
PreviewCodeFile: "checkbox_custom_icon.templ",
ComponentCodeFile: "checkbox.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.CheckboxForm(),
PreviewCodeFile: "checkbox_form.templ",
ComponentCodeFile: "checkbox.templ",
})
}
}
}

View File

@ -18,6 +18,12 @@ templ Datepicker() {
PreviewCodeFile: "datepicker_default.templ",
ComponentCodeFile: "datepicker.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.DatepickerWithLabel(),
PreviewCodeFile: "datepicker_with_label.templ",
ComponentCodeFile: "datepicker.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Custom Placeholder",
ShowcaseFile: showcase.DatepickerCustomPlaceholder(),
@ -42,6 +48,12 @@ templ Datepicker() {
PreviewCodeFile: "datepicker_formats.templ",
ComponentCodeFile: "datepicker.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.DatepickerForm(),
PreviewCodeFile: "datepicker_form.templ",
ComponentCodeFile: "datepicker.templ",
})
}
}
}

View File

@ -18,18 +18,6 @@ templ Input() {
PreviewCodeFile: "input_default.templ",
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Placeholder",
ShowcaseFile: showcase.InputWithPlaceholder(),
PreviewCodeFile: "input_with_placeholder.templ",
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Values",
ShowcaseFile: showcase.InputWithValues(),
PreviewCodeFile: "input_with_values.templ",
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "File",
ShowcaseFile: showcase.InputFile(),
@ -49,21 +37,9 @@ templ Input() {
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Description",
ShowcaseFile: showcase.InputWithDescription(),
PreviewCodeFile: "input_with_description.templ",
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Error",
ShowcaseFile: showcase.InputWithError(),
PreviewCodeFile: "input_with_error.templ",
ComponentCodeFile: "input.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Advanced",
ShowcaseFile: showcase.InputAdvanced(),
PreviewCodeFile: "input_advanced.templ",
SectionName: "Form",
ShowcaseFile: showcase.InputForm(),
PreviewCodeFile: "input_form.templ",
ComponentCodeFile: "input.templ",
})
}

View File

@ -0,0 +1,47 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/modules"
"github.com/axzilla/goilerplate/internals/ui/showcase"
)
templ Radio() {
@layouts.DocsLayout() {
@modules.PageWrapper(modules.PageWrapperProps{
Name: "Radio",
Description: templ.Raw("Control for selecting a single option from a list of choices."),
}) {
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Default",
ShowcaseFile: showcase.RadioDefault(),
PreviewCodeFile: "radio_default.templ",
ComponentCodeFile: "radio.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Checked",
ShowcaseFile: showcase.RadioChecked(),
PreviewCodeFile: "radio_checked.templ",
ComponentCodeFile: "radio.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.RadioWithLabel(),
PreviewCodeFile: "radio_with_label.templ",
ComponentCodeFile: "radio.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.RadioDisabled(),
PreviewCodeFile: "radio_disabled.templ",
ComponentCodeFile: "radio.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.RadioForm(),
PreviewCodeFile: "radio_form.templ",
ComponentCodeFile: "radio.templ",
})
}
}
}

View File

@ -1,29 +0,0 @@
package pages
import (
"github.com/axzilla/goilerplate/internals/ui/layouts"
"github.com/axzilla/goilerplate/internals/ui/modules"
"github.com/axzilla/goilerplate/internals/ui/showcase"
)
templ RadioGroup() {
@layouts.DocsLayout() {
@modules.PageWrapper(modules.PageWrapperProps{
Name: "Radio Group",
Description: templ.Raw("Control for selecting a single option from a list of choices."),
}) {
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Using Props",
ShowcaseFile: showcase.RadioGroupProps(),
PreviewCodeFile: "radio_group_props.templ",
ComponentCodeFile: "radio_group.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Using Attributes",
ShowcaseFile: showcase.RadioGroupAttributes(),
PreviewCodeFile: "radio_group_attributes.templ",
ComponentCodeFile: "radio_group.templ",
})
}
}
}

View File

@ -15,28 +15,24 @@ templ Select() {
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Default",
ShowcaseFile: showcase.SelectDefault(),
ShowcaseClass: "w-72",
PreviewCodeFile: "select_default.templ",
ComponentCodeFile: "select.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Placeholder",
ShowcaseFile: showcase.SelectWithPlaceholder(),
ShowcaseClass: "w-72",
PreviewCodeFile: "select_with_placeholder.templ",
ComponentCodeFile: "select.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Selected Value",
ShowcaseFile: showcase.SelectSelectedValue(),
ShowcaseClass: "w-72",
PreviewCodeFile: "select_selected_value.templ",
ComponentCodeFile: "select.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.SelectDisabled(),
ShowcaseClass: "w-72",
PreviewCodeFile: "select_disabled.templ",
ComponentCodeFile: "select.templ",
})

View File

@ -15,42 +15,36 @@ templ Slider() {
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Default",
ShowcaseFile: showcase.SliderDefault(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_default.templ",
ComponentCodeFile: "sheet.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Value",
ShowcaseFile: showcase.SliderWithValue(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_with_value.templ",
ComponentCodeFile: "sheet.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.SliderWithLabel(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_with_label.templ",
ComponentCodeFile: "sheet.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Steps",
ShowcaseFile: showcase.SliderWithSteps(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_with_steps.templ",
ComponentCodeFile: "sheet.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label and Value",
ShowcaseFile: showcase.SliderWithLabelAndValue(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_with_label_and_value.templ",
ComponentCodeFile: "sheet.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.SliderDisabled(),
ShowcaseClass: "w-96",
PreviewCodeFile: "slider_disabled.templ",
ComponentCodeFile: "sheet.templ",
})

View File

@ -15,62 +15,48 @@ templ Textarea() {
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Default",
ShowcaseFile: showcase.TextareaDefault(),
ShowcaseClass: "w-96",
PreviewCodeFile: "textarea_default.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Value",
ShowcaseFile: showcase.TextareaWithValue(),
ShowcaseClass: "w-96",
SectionName: "With Value",
ShowcaseFile: showcase.TextareaWithValue(),
PreviewCodeFile: "textarea_with_value.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Rows",
ShowcaseFile: showcase.TextareaWithRows(),
ShowcaseClass: "w-96",
SectionName: "With Rows",
ShowcaseFile: showcase.TextareaWithRows(),
PreviewCodeFile: "textarea_with_rows.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.TextareaWithLabel(),
ShowcaseClass: "w-96",
SectionName: "With Label",
ShowcaseFile: showcase.TextareaWithLabel(),
PreviewCodeFile: "textarea_with_label.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Description",
ShowcaseFile: showcase.TextareaWithDescription(),
ShowcaseClass: "w-96",
SectionName: "With Description",
ShowcaseFile: showcase.TextareaWithDescription(),
PreviewCodeFile: "textarea_with_description.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Error",
ShowcaseFile: showcase.TextareaWithError(),
ShowcaseClass: "w-96",
SectionName: "With Error",
ShowcaseFile: showcase.TextareaWithError(),
PreviewCodeFile: "textarea_with_error.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Auto Resize",
ShowcaseFile: showcase.TextareaAutoResize(),
ShowcaseClass: "w-96",
PreviewCodeFile: "textarea_auto_resize.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.TextareaDisabled(),
ShowcaseClass: "w-96",
SectionName: "Disabled",
ShowcaseFile: showcase.TextareaDisabled(),
PreviewCodeFile: "textarea_disabled.templ",
ComponentCodeFile: "textarea.templ",
})

View File

@ -100,27 +100,25 @@ templ ThemePreview() {
</div>
<div class="space-y-2">
<label class="text-sm font-medium">Preferred Contact Method</label>
@components.RadioGroup(components.RadioGroupProps{Name: "contact-method"}) {
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "email",
ID: "contact-email",
Name: "contact-method",
Label: templ.Raw("Email"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "phone",
ID: "contact-phone",
Name: "contact-method",
Label: templ.Raw("Phone"),
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "mail",
ID: "contact-mail",
Name: "contact-method",
Label: templ.Raw("Physical Mail"),
Attributes: templ.Attributes{"disabled": "true"},
})
}
@components.Radio(components.RadioProps{
Value: "email",
ID: "contact-email",
Name: "contact-method",
Label: templ.Raw("Email"),
})
@components.Radio(components.RadioProps{
Value: "phone",
ID: "contact-phone",
Name: "contact-method",
Label: templ.Raw("Phone"),
})
@components.Radio(components.RadioProps{
Value: "mail",
ID: "contact-mail",
Name: "contact-method",
Label: templ.Raw("Physical Mail"),
Attributes: templ.Attributes{"disabled": "true"},
})
</div>
<div class="space-y-4">
<label class="text-sm font-medium">Preferences</label>

View File

@ -3,7 +3,7 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CardDefault() {
@components.Card(components.CardProps{Class: "w-2/3"}) {
@components.Card(components.CardProps{Class: "max-w-sm"}) {
@components.CardHeader() {
@components.CardTitle() {
Card Title

View File

@ -3,20 +3,7 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CheckboxChecked() {
<div class="flex flex-col gap-4">
@components.Checkbox(components.CheckboxProps{
ID: "checked-checkbox",
Name: "newsletter",
Value: "subscribe",
Label: "Checked using props",
Checked: true,
})
@components.Checkbox(components.CheckboxProps{
ID: "checked-checkbox",
Name: "newsletter",
Value: "subscribe",
Label: "Checked using attributes",
Attributes: templ.Attributes{"checked": "true"},
})
</div>
@components.Checkbox(components.CheckboxProps{
Checked: true,
})
}

View File

@ -0,0 +1,14 @@
package showcase
import (
"github.com/axzilla/goilerplate/pkg/components"
"github.com/axzilla/goilerplate/pkg/icons"
)
templ CheckboxCustomIcon() {
@components.Checkbox(components.CheckboxProps{
Label: "Accept terms and conditions",
Icon: icons.Plus(icons.IconProps{Size: "12"}),
Checked: true,
})
}

View File

@ -3,10 +3,5 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CheckboxDefault() {
@components.Checkbox(components.CheckboxProps{
ID: "default-checkbox",
Name: "default",
Value: "default",
Label: "Accept terms and conditions",
})
@components.Checkbox(components.CheckboxProps{})
}

View File

@ -3,20 +3,14 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CheckboxDisabled() {
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2">
@components.Checkbox(components.CheckboxProps{
ID: "disabled-checkbox",
Name: "disabled-checkbox",
Value: "disabled-checkbox",
Label: "Disabled using props",
ID: "checkbox-disabled",
Disabled: true,
})
@components.Checkbox(components.CheckboxProps{
ID: "disabled-checkbox",
Name: "disabled-checkbox",
Value: "disabled-checkbox",
Label: "Disabled using attributes",
Attributes: templ.Attributes{"disabled": "true"},
@components.Label(components.LabelProps{
For: "checkbox-disabled",
Text: "Accept terms and conditions",
})
</div>
}

View File

@ -0,0 +1,61 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CheckboxForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
// Group Label
@components.FormLabel(components.FormLabelProps{
Text: "Select your interests",
})
// Option 1
@components.FormItemFlex(components.FormItemProps{}) {
@components.Checkbox(components.CheckboxProps{
ID: "c1",
Name: "interests",
Value: "design",
Checked: true,
})
@components.FormLabel(components.FormLabelProps{
For: "c1",
Text: "Design and UX",
})
}
// Option 2
@components.FormItemFlex(components.FormItemProps{}) {
@components.Checkbox(components.CheckboxProps{
ID: "c2",
Name: "interests",
Value: "development",
Disabled: true,
})
@components.FormLabel(components.FormLabelProps{
For: "c2",
Text: "Development (Coming Soon)",
})
}
// Option 3
@components.FormItemFlex(components.FormItemProps{}) {
@components.Checkbox(components.CheckboxProps{
ID: "c3",
Name: "interests",
Value: "business",
})
@components.FormLabel(components.FormLabelProps{
For: "c3",
Text: "Business and Marketing",
})
}
// Description
@components.FormDescription(components.FormDescriptionProps{}) {
Choose all areas that interest you.
}
// Error Message
@components.FormMessage(components.FormMessageProps{
Type: "error",
Message: "Please select at least one interest.",
})
}
</div>
}

View File

@ -0,0 +1,15 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ CheckboxWithLabel() {
<div class="flex items-center gap-2">
@components.Checkbox(components.CheckboxProps{
ID: "checkbox-with-label",
})
@components.Label(components.LabelProps{
For: "checkbox-with-label",
Text: "Accept terms and conditions",
})
</div>
}

View File

@ -3,10 +3,11 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ DatepickerCustomPlaceholder() {
@components.Datepicker(components.DatepickerProps{
ID: "date",
Name: "date",
Placeholder: "When is your birthday?",
Class: "w-full max-w-xs",
})
<div class="w-full max-w-sm">
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-custom-placeholder",
Name: "datepicker-custom-placeholder",
Placeholder: "When is your birthday?",
})
</div>
}

View File

@ -3,9 +3,10 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ DatepickerDefault() {
@components.Datepicker(components.DatepickerProps{
ID: "my-datepicker",
Name: "selected-date",
Class: "w-full max-w-xs",
})
<div class="w-full max-w-sm">
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-default",
Name: "datepicker-default",
})
</div>
}

View File

@ -6,23 +6,12 @@ import (
)
templ DatepickerDisabled() {
<div class="w-full max-w-xs flex flex-col gap-4">
// Disabled using attributes
<div class="w-full max-w-sm">
@components.Datepicker(components.DatepickerProps{
ID: "my-datepicker",
Name: "selected-date",
ID: "datepicker-disabled",
Name: "datepicker-disabled",
Placeholder: "Select a date",
Value: time.Now(),
Class: "w-full max-w-xs",
Attributes: templ.Attributes{"disabled": true},
})
// Disabled using props
@components.Datepicker(components.DatepickerProps{
ID: "my-datepicker-2",
Name: "selected-date-2",
Placeholder: "Select a date",
Value: time.Now(),
Class: "w-full max-w-xs",
Disabled: true,
})
</div>

View File

@ -0,0 +1,26 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ DatepickerForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
@components.FormLabel(components.FormLabelProps{
Text: "Date",
For: "datepicker-form",
})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-form",
Name: "datepicker-form",
HasError: true,
})
@components.FormDescription(components.FormDescriptionProps{}) {
Select a date from the calendar.
}
@components.FormMessage(components.FormMessageProps{
Message: "Please select a date",
Type: "error",
})
}
</div>
}

View File

@ -6,71 +6,64 @@ import (
)
templ DatepickerFormats() {
<div class="w-full max-w-xs flex flex-col gap-4">
// Default ISO
@components.Datepicker(components.DatepickerProps{
ID: "date-iso",
Name: "date_iso",
Config: components.DatePickerISO,
Value: time.Now(),
})
// Default EU
@components.Datepicker(components.DatepickerProps{
ID: "date-eu",
Name: "date_eu",
Config: components.DatePickerEU,
Value: time.Now(),
})
// Default UK
@components.Datepicker(components.DatepickerProps{
ID: "date-uk",
Name: "date_uk",
Config: components.DatePickerUK,
Value: time.Now(),
})
// Default US
@components.Datepicker(components.DatepickerProps{
ID: "date-us",
Name: "date_us",
Config: components.DatePickerUS,
Value: time.Now(),
})
// Default LONG
@components.Datepicker(components.DatepickerProps{
ID: "date-long",
Name: "date_long",
Config: components.DatePickerLONG,
Value: time.Now(),
})
// Custom Config
@components.Datepicker(components.DatepickerProps{
ID: "date-es",
Name: "date_es",
Config: components.NewDatepickerConfig(
components.DateFormatLONG,
components.DateLocaleSpanish,
),
Value: time.Now().AddDate(0, 0, -30), // 30 days ago
Placeholder: "Seleccionar fecha",
})
// Custom Format (Japanese LONG)
@components.Datepicker(components.DatepickerProps{
ID: "date-custom",
Name: "date_custom",
Config: components.NewDatepickerConfig(
components.DateFormatLONG,
components.DateLocale{
MonthNames: []string{
"1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月",
},
DayNames: []string{
"日", "月", "火", "水", "木", "金", "土",
},
},
),
Value: time.Now().AddDate(0, 0, -30), // 30 days ago
Placeholder: "Seleccionar fecha",
})
<div class="w-full max-w-sm flex flex-col gap-4">
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "Default ISO", For: "datepicker-iso-format"})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-iso-format",
Name: "datepicker-iso-format",
Config: components.DatePickerISO,
Value: time.Now(),
})
</div>
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "Default EU", For: "datepicker-eu-format"})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-eu-format",
Name: "datepicker-eu-format",
Config: components.DatePickerEU,
Value: time.Now(),
})
</div>
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "UK Format", For: "datepicker-uk-format"})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-uk-format",
Name: "datepicker-uk-format",
Config: components.DatePickerUK,
Value: time.Now(),
})
</div>
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "US Format", For: "datepicker-us-format"})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-us-format",
Name: "datepicker-us-format",
Config: components.DatePickerUS,
Value: time.Now(),
})
</div>
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "LONG Format", For: "date-long-format"})
@components.Datepicker(components.DatepickerProps{
ID: "date-long-format",
Name: "date-long-format",
Config: components.DatePickerLONG,
Value: time.Now(),
})
</div>
<div class="space-y-2">
@components.Label(components.LabelProps{Text: "LONG Format (Spanish)", For: "date-es-long-format"})
@components.Datepicker(components.DatepickerProps{
ID: "date-es-custom-config",
Name: "date-es-custom-config",
Config: components.NewDatepickerConfig(
components.DateFormatLONG,
components.DateLocaleSpanish,
),
Value: time.Now().AddDate(0, 0, -30), // 30 days ago
Placeholder: "Seleccionar fecha",
})
</div>
</div>
}

View File

@ -1,3 +1,4 @@
package showcase
import (
@ -6,11 +7,12 @@ import (
)
templ DatepickerSelectedDate() {
@components.Datepicker(components.DatepickerProps{
ID: "my-datepicker",
Name: "selected-date",
Placeholder: "Select a date",
Value: time.Now(),
Class: "w-full max-w-xs",
})
<div class="w-full max-w-sm">
@components.Datepicker(components.DatepickerProps{
ID: "my-datepicker",
Name: "selected-date",
Placeholder: "Select a date",
Value: time.Now(),
})
</div>
}

View File

@ -0,0 +1,15 @@
package showcase
import (
"github.com/axzilla/goilerplate/pkg/components"
)
templ DatepickerWithLabel() {
<div class="w-full max-w-sm space-y-2">
@components.Label(components.LabelProps{Text: "Date", For: "datepicker-with-label"})
@components.Datepicker(components.DatepickerProps{
ID: "datepicker-with-label",
Name: "datepicker-with-label",
})
</div>
}

View File

@ -1,14 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputAdvanced() {
@components.Input(components.InputProps{
ID: "username",
Label: "Username",
Placeholder: "e.g. john123",
Description: "This is your public display name.",
Value: "",
Error: "Username must be more then 2 characters",
})
}

View File

@ -3,7 +3,10 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputDefault() {
@components.Input(components.InputProps{
Type: "email",
})
<div class="w-full max-w-sm">
@components.Input(components.InputProps{
Type: "email",
Placeholder: "Email",
})
</div>
}

View File

@ -3,18 +3,11 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputDisabled() {
<div class="flex flex-col gap-4">
<div class="w-full max-w-sm">
@components.Input(components.InputProps{
Type: "email",
Label: "Disabled using props",
Placeholder: "e.g. john@doe.com",
Placeholder: "Email",
Disabled: true,
})
@components.Input(components.InputProps{
Type: "email",
Label: "Disabled using attributes",
Placeholder: "e.g. john@doe.com",
Attributes: templ.Attributes{"disabled": "true"},
})
</div>
}

View File

@ -3,7 +3,9 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputFile() {
@components.Input(components.InputProps{
Type: "file",
})
<div class="w-full max-w-sm">
@components.Input(components.InputProps{
Type: "file",
})
</div>
}

View File

@ -0,0 +1,28 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
@components.FormLabel(components.FormLabelProps{
Text: "Email",
For: "email-form",
})
@components.Input(components.InputProps{
ID: "email-form",
Type: "email",
Placeholder: "m@example.com",
HasError: true,
Disabled: true,
})
@components.FormDescription(components.FormDescriptionProps{}) {
Enter your email address for notifications.
}
@components.FormMessage(components.FormMessageProps{
Message: "Please enter a valid email address",
Type: "error",
})
}
</div>
}

View File

@ -1,11 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputWithDescription() {
@components.Input(components.InputProps{
ID: "email",
Type: "email",
Description: "This is your accounts email address.",
})
}

View File

@ -1,10 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputWithError() {
@components.Input(components.InputProps{
ID: "username",
Error: "Username must be more then 2 characters",
})
}

View File

@ -3,9 +3,12 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputWithLabel() {
@components.Input(components.InputProps{
ID: "email",
Type: "email",
Label: "Email",
})
<div class="w-full max-w-sm grid gap-2">
@components.Label(components.LabelProps{Text: "Email", For: "email"})
@components.Input(components.InputProps{
ID: "email",
Type: "email",
Placeholder: "Email",
})
</div>
}

View File

@ -1,10 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputWithPlaceholder() {
@components.Input(components.InputProps{
Type: "email",
Placeholder: "e.g. john@doe.com",
})
}

View File

@ -1,20 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ InputWithValues() {
<div class="flex flex-col gap-4">
@components.Input(components.InputProps{
Type: "email",
Placeholder: "Enter text",
Value: "Value using props",
})
@components.Input(components.InputProps{
Type: "email",
Placeholder: "Enter text",
Attributes: templ.Attributes{
"value": "Value using attributes",
},
})
</div>
}

View File

@ -0,0 +1,10 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioChecked() {
@components.Radio(components.RadioProps{
Name: "radio-checked",
Checked: true,
})
}

View File

@ -0,0 +1,11 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioDefault() {
<div class="flex gap-2 items-center">
@components.Radio(components.RadioProps{
Name: "radio-default",
})
</div>
}

View File

@ -0,0 +1,16 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioDisabled() {
<div class="flex gap-2 items-center">
@components.Radio(components.RadioProps{
ID: "radio-disabled",
Disabled: true,
})
@components.Label(components.LabelProps{
For: "radio-disabled",
Text: "Disabled",
})
</div>
}

View File

@ -0,0 +1,61 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
// Group Label
@components.FormLabel(components.FormLabelProps{
Text: "Notify me about new products",
})
// Option 1
@components.FormItemFlex(components.FormItemProps{}) {
@components.Radio(components.RadioProps{
ID: "r1",
Name: "notify",
Value: "all",
Checked: true,
})
@components.FormLabel(components.FormLabelProps{
For: "r1",
Text: "All new products",
})
}
// Option 2
@components.FormItemFlex(components.FormItemProps{}) {
@components.Radio(components.RadioProps{
ID: "r2",
Name: "notify",
Value: "wishlist",
Disabled: true,
})
@components.FormLabel(components.FormLabelProps{
For: "r2",
Text: "Create a wishlist(Coming Soon)",
})
}
// Option 3
@components.FormItemFlex(components.FormItemProps{}) {
@components.Radio(components.RadioProps{
ID: "r3",
Name: "notify",
Value: "none",
})
@components.FormLabel(components.FormLabelProps{
For: "r3",
Text: "No notifications",
})
}
// Description
@components.FormDescription(components.FormDescriptionProps{}) {
You can change your preferences at any time.
}
// Error Message
@components.FormMessage(components.FormMessageProps{
Type: "error",
Message: "We will send you an email when new products are available.",
})
}
</div>
}

View File

@ -1,28 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioGroupAttributes() {
@components.RadioGroup(components.RadioGroupProps{}) {
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "default",
ID: "r1",
Name: "atrrs",
Label: templ.Raw("Default"),
Attributes: templ.Attributes{"checked": true},
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "comfortable",
ID: "r2",
Name: "atrrs",
Label: templ.Raw("Disabled"),
Attributes: templ.Attributes{"disabled": true},
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "compact",
ID: "r3",
Name: "atrrs",
Label: templ.Raw("Compact"),
})
}
}

View File

@ -1,28 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioGroupProps() {
@components.RadioGroup(components.RadioGroupProps{}) {
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "default",
ID: "r1",
Name: "props",
Label: templ.Raw("Default"),
Checked: true,
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "comfortable",
ID: "r2",
Name: "props",
Label: templ.Raw("Disabled"),
Disabled: true,
})
@components.RadioGroupItem(components.RadioGroupItemProps{
Value: "compact",
ID: "r3",
Name: "props",
Label: templ.Raw("Compact"),
})
}
}

View File

@ -0,0 +1,16 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioWithLabel() {
<div class="flex gap-2 items-center">
@components.Radio(components.RadioProps{
ID: "radio-with-label",
Name: "radio-with-label",
})
@components.Label(components.LabelProps{
For: "radio-with-label",
Text: "Label",
})
</div>
}

View File

@ -38,14 +38,14 @@ templ AccountTab() {
Placeholder: "Name",
ID: "name",
Value: "John Doe",
Label: "Name",
// Label: "Name",
})
@components.Input(components.InputProps{
Type: components.InputTypeText,
Placeholder: "Username",
ID: "username",
Value: "@johndoe",
Label: "Username",
// Label: "Username",
})
</div>
}
@ -71,13 +71,13 @@ templ PasswordTab() {
Type: components.InputTypePassword,
Placeholder: "Current Password",
ID: "current_password",
Label: "Current Password",
// Label: "Current Password",
})
@components.Input(components.InputProps{
Type: components.InputTypePassword,
Placeholder: "New Password",
ID: "new_password",
Label: "New Password",
// Label: "New Password",
})
</div>
}

View File

@ -39,7 +39,7 @@ type AccordionProps struct {
// - Attributes: Additional HTML attributes (e.g. data-testid)
templ Accordion(props AccordionProps) {
<div
x-data="{
x-data="{
activeItem: null,
toggleItem(itemId) {
this.activeItem = this.activeItem === itemId ? null : itemId;

View File

@ -71,7 +71,7 @@ func Accordion(props AccordionProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{ \n\t\t\tactiveItem: null,\n\t\t\ttoggleItem(itemId) {\n\t\t\t\tthis.activeItem = this.activeItem === itemId ? null : itemId;\n\t\t\t}\n\t\t}\" class=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{\n\t\t\tactiveItem: null,\n\t\t\ttoggleItem(itemId) {\n\t\t\t\tthis.activeItem = this.activeItem === itemId ? null : itemId;\n\t\t\t}\n\t\t}\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -38,7 +38,7 @@ templ Card(props CardProps) {
<div
class={
utils.TwMerge(
"rounded-lg border bg-card text-card-foreground shadow-sm",
"w-full rounded-lg border bg-card text-card-foreground shadow-sm",
props.Class,
),
templ.KV("flex overflow-hidden", props.Horizontal),

View File

@ -65,7 +65,7 @@ func Card(props CardProps) templ.Component {
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{
utils.TwMerge(
"rounded-lg border bg-card text-card-foreground shadow-sm",
"w-full rounded-lg border bg-card text-card-foreground shadow-sm",
props.Class,
),
templ.KV("flex overflow-hidden", props.Horizontal),

View File

@ -0,0 +1,71 @@
package components
import "github.com/axzilla/goilerplate/pkg/icons"
type CheckboxBakProps struct {
// ID uniquely identifies the checkbox input
ID string
// Name sets the form field name
Name string
// Value sets the checkbox value
Value string
// Label displays text next to checkbox
// Empty string hides the label
Label string
// Class adds custom CSS classes
Class string
// Disabled sets the checkbox to disabled state
Disabled bool
// Checked sets the checkbox to checked state
Checked bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Control that allows selecting multiple options from a list.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
//
// Props:
// - ID: Unique identifier for the input
// - Name: Form field name
// - Value: Checkbox value
// - Label: Optional text label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
templ CheckboxBak(props CheckboxProps) {
<div class="peer relative flex items-center">
<input
checked?={ props.Checked }
disabled?={ props.Disabled }
id={ props.ID }
name={ props.Name }
value={ props.Value }
type="checkbox"
class="peer before:content[''] disabled:opacity-50 relative size-4 cursor-pointer appearance-none overflow-hidden
rounded-sm border border-2 border-primary
bg-background before:absolute before:inset-0
checked:before:bg-primary
focus:outline focus:outline-2 focus:outline-offset-2
focus:outline-ring checked:focus:outline-primary
active:outline-offset-0
disabled:cursor-not-allowed
transition-colors"
{ props.Attributes... }
/>
<div
class="pointer-events-none invisible absolute left-1/2 top-1/2 size-3
-translate-x-1/2 -translate-y-1/2 text-primary-foreground
peer-checked:visible"
>
@icons.Check(icons.IconProps{Size: "12"})
</div>
</div>
}

View File

@ -0,0 +1,151 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.793
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/icons"
type CheckboxBakProps struct {
// ID uniquely identifies the checkbox input
ID string
// Name sets the form field name
Name string
// Value sets the checkbox value
Value string
// Label displays text next to checkbox
// Empty string hides the label
Label string
// Class adds custom CSS classes
Class string
// Disabled sets the checkbox to disabled state
Disabled bool
// Checked sets the checkbox to checked state
Checked bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Control that allows selecting multiple options from a list.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
//
// Props:
// - ID: Unique identifier for the input
// - Name: Form field name
// - Value: Checkbox value
// - Label: Optional text label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func CheckboxBak(props CheckboxProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
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("<div class=\"peer relative flex items-center\"><input")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Checked {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" checked")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if props.Disabled {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" disabled")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.bak.templ`, Line: 48, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.bak.templ`, Line: 49, Col: 20}
}
_, 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("\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.bak.templ`, Line: 50, Col: 22}
}
_, 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("\" type=\"checkbox\" class=\"peer before:content[&#39;&#39;] disabled:opacity-50 relative size-4 cursor-pointer appearance-none overflow-hidden \n rounded-sm border border-2 border-primary\n bg-background before:absolute before:inset-0 \n checked:before:bg-primary\n focus:outline focus:outline-2 focus:outline-offset-2 \n focus:outline-ring checked:focus:outline-primary \n active:outline-offset-0 \n disabled:cursor-not-allowed\n transition-colors\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("><div class=\"pointer-events-none invisible absolute left-1/2 top-1/2 size-3 \n -translate-x-1/2 -translate-y-1/2 text-primary-foreground \n peer-checked:visible\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = icons.Check(icons.IconProps{Size: "12"}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -6,82 +6,102 @@ import (
)
type CheckboxProps struct {
// ID uniquely identifies the checkbox input
ID string
// Name sets the form field name
Name string
// Value sets the checkbox value
Value string
// Label displays text next to checkbox
// Empty string hides the label
Label string
// Class adds custom CSS classes
Class string
// Disabled sets the checkbox to disabled state
ID string
Name string
Value string
Label string
Disabled bool
Checked bool
Icon templ.Component
// Checked sets the checkbox to checked state
Checked bool
WrapperClass string
LabelClass string
CheckboxClass string
IconWrapperClass string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Control that allows selecting multiple options from a list.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
//
// Props:
// - ID: Unique identifier for the input
// - Name: Form field name
// - Value: Checkbox value
// - Label: Optional text label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
templ Checkbox(props CheckboxProps) {
<label
for={ props.ID }
class={ utils.TwMerge(
"flex cursor-pointer items-center gap-2 text-sm font-medium",
"text-muted-foreground [&:has(input:checked)]:text-foreground",
"[&:has(input:disabled)]:opacity-50 [&:has(input:disabled)]:cursor-not-allowed",
props.Class,
) }
>
if props.ID == "" {
{{ props.ID = utils.RandomID() }}
}
<div class={ utils.TwMerge("flex items-center gap-2", props.WrapperClass) }>
<div class="relative flex items-center">
<input
x-ref={ props.ID }
data-input-id={ props.ID }
data-testid={ props.ID }
checked?={ props.Checked }
disabled?={ props.Disabled }
id={ props.ID }
name={ props.Name }
value={ props.Value }
type="checkbox"
class="before:content[''] peer relative size-4 cursor-pointer appearance-none overflow-hidden
rounded-sm border border-2 border-primary
bg-background before:absolute before:inset-0
checked:before:bg-primary
focus:outline focus:outline-2 focus:outline-offset-2
focus:outline-ring checked:focus:outline-primary
active:outline-offset-0
disabled:cursor-not-allowed
transition-colors"
class={
utils.TwMerge(
// Layout
"relative size-4 overflow-hidden peer",
"before:absolute before:inset-0 before:content['']",
// Styling
"appearance-none rounded-sm border-2 border-primary bg-background",
"cursor-pointer transition-colors",
// States
"checked:before:bg-primary",
"disabled:cursor-not-allowed disabled:opacity-50",
// Custom
props.CheckboxClass,
),
}
{ props.Attributes... }
/>
<div
class="pointer-events-none invisible absolute left-1/2 top-1/2 size-3
-translate-x-1/2 -translate-y-1/2 text-primary-foreground
peer-checked:visible"
class={
utils.TwMerge(
// Layout
"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2",
// Styling
"size-3 text-primary-foreground pointer-events-none opacity-0",
// States
"peer-checked:opacity-100",
// Custom
props.IconWrapperClass,
),
}
:class="{ 'visible': document.getElementById($el.dataset.inputId).checked }"
>
@icons.Check(icons.IconProps{Size: "12"})
if props.Icon != nil {
@props.Icon
} else {
@icons.Check(icons.IconProps{Size: "12"})
}
</div>
</div>
if props.Label != "" {
<span>{ props.Label }</span>
<label
for={ props.ID }
class={
utils.TwMerge(
// Styling
"text-sm font-medium",
// Custom
props.LabelClass,
),
}
:class="{ 'opacity-50 cursor-not-allowed': document.getElementById($el.dataset.inputId).checked }"
>
{ props.Label }
</label>
}
</label>
</div>
}

View File

@ -14,43 +14,25 @@ import (
)
type CheckboxProps struct {
// ID uniquely identifies the checkbox input
ID string
// Name sets the form field name
Name string
// Value sets the checkbox value
Value string
// Label displays text next to checkbox
// Empty string hides the label
Label string
// Class adds custom CSS classes
Class string
// Disabled sets the checkbox to disabled state
ID string
Name string
Value string
Label string
Disabled bool
Checked bool
Icon templ.Component
// Checked sets the checkbox to checked state
Checked bool
WrapperClass string
LabelClass string
CheckboxClass string
IconWrapperClass string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
}
// Control that allows selecting multiple options from a list.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/checkbox
//
// Props:
// - ID: Unique identifier for the input
// - Name: Form field name
// - Value: Checkbox value
// - Label: Optional text label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func Checkbox(props CheckboxProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -72,43 +54,93 @@ func Checkbox(props CheckboxProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{utils.TwMerge(
"flex cursor-pointer items-center gap-2 text-sm font-medium",
"text-muted-foreground [&:has(input:checked)]:text-foreground",
"[&:has(input:disabled)]:opacity-50 [&:has(input:disabled)]:cursor-not-allowed",
props.Class,
)}
if props.ID == "" {
props.ID = utils.RandomID()
}
var templ_7745c5c3_Var2 = []any{utils.TwMerge("flex items-center gap-2", props.WrapperClass)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 48, Col: 16}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 1, Col: 0}
}
_, 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("\" class=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"relative flex items-center\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 1, Col: 0}
var templ_7745c5c3_Var4 = []any{
utils.TwMerge(
// Layout
"relative size-4 overflow-hidden peer",
"before:absolute before:inset-0 before:content['']",
// Styling
"appearance-none rounded-sm border-2 border-primary bg-background",
"cursor-pointer transition-colors",
// States
"checked:before:bg-primary",
"disabled:cursor-not-allowed disabled:opacity-50",
// Custom
props.CheckboxClass,
),
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var4...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><div class=\"relative flex items-center\"><input")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input x-ref=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 35, Col: 20}
}
_, 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("\" data-input-id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 36, Col: 28}
}
_, 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("\" data-testid=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 37, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
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
}
@ -128,12 +160,12 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 60, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 40, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -141,12 +173,12 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 61, Col: 21}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 41, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -154,16 +186,29 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 62, Col: 23}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 42, Col: 23}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"checkbox\" class=\"before:content[&#39;&#39;] peer relative size-4 cursor-pointer appearance-none overflow-hidden \n rounded-sm border border-2 border-primary\n bg-background before:absolute before:inset-0 \n checked:before:bg-primary\n focus:outline focus:outline-2 focus:outline-offset-2 \n focus:outline-ring checked:focus:outline-primary \n active:outline-offset-0 \n disabled:cursor-not-allowed\n transition-colors\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"checkbox\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var4).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
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
}
@ -171,38 +216,120 @@ func Checkbox(props CheckboxProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("><div class=\"pointer-events-none invisible absolute left-1/2 top-1/2 size-3 \n -translate-x-1/2 -translate-y-1/2 text-primary-foreground \n peer-checked:visible\">")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = icons.Check(icons.IconProps{Size: "12"}).Render(ctx, templ_7745c5c3_Buffer)
var templ_7745c5c3_Var12 = []any{
utils.TwMerge(
// Layout
"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2",
// Styling
"size-3 text-primary-foreground pointer-events-none opacity-0",
// States
"peer-checked:opacity-100",
// Custom
props.IconWrapperClass,
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var12).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :class=\"{ &#39;visible&#39;: document.getElementById($el.dataset.inputId).checked }\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Icon != nil {
templ_7745c5c3_Err = props.Icon.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
templ_7745c5c3_Err = icons.Check(icons.IconProps{Size: "12"}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Label != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
var templ_7745c5c3_Var14 = []any{
utils.TwMerge(
// Styling
"text-sm font-medium",
// Custom
props.LabelClass,
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var14...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 84, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 91, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var14).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :class=\"{ &#39;opacity-50 cursor-not-allowed&#39;: document.getElementById($el.dataset.inputId).checked }\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 103, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -6,6 +6,16 @@ import (
"time"
)
func mergeAttributes(attrs ...templ.Attributes) templ.Attributes {
merged := templ.Attributes{}
for _, attr := range attrs {
for k, v := range attr {
merged[k] = v
}
}
return merged
}
// DateFormat defines the available date formatting styles
type DateFormat string
@ -75,6 +85,13 @@ var (
"Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"},
DayNames: []string{"Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"},
}
// DateLocaleJapanese provides Japanese localization
DateLocaleJapanese = DateLocale{
MonthNames: []string{"1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月"},
DayNames: []string{"日", "月", "火", "水", "木", "金", "土"},
}
)
// DatepickerConfig combines format and locale settings
@ -144,8 +161,12 @@ type DatepickerProps struct {
Config DatepickerConfig
// Placeholder sets the input placeholder text
Placeholder string
// Required marks the input as mandatory
Required bool
// Disabled controls whether the datepicker can be interacted with
Disabled bool
// HasError indicates whether the input should be styled as an error
HasError bool
// Class adds custom CSS classes
Class string
// Attributes allows additional HTML attributes
@ -174,6 +195,9 @@ type DatepickerProps struct {
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
templ Datepicker(props DatepickerProps) {
if props.Placeholder == "" {
{{ props.Placeholder = "Select a date" }}
}
<div
class={ utils.TwMerge("relative", props.Class) }
if props.Value != (time.Time{}) {
@ -182,6 +206,7 @@ templ Datepicker(props DatepickerProps) {
data-format={ string(props.Config.Format) }
data-monthnames={ templ.JSONString(props.Config.Locale.MonthNames) }
data-daynames={ templ.JSONString(props.Config.Locale.DayNames) }
data-input-id={ props.ID }
x-data="{
open: false,
value: null,
@ -214,7 +239,7 @@ templ Datepicker(props DatepickerProps) {
},
updatePosition() {
const trigger = this.$refs.datePickerInput;
const trigger = document.getElementById($el.dataset.inputId);
const popup = this.$refs.datePickerPopup;
const rect = trigger.getBoundingClientRect();
const popupRect = popup.getBoundingClientRect();
@ -259,15 +284,14 @@ templ Datepicker(props DatepickerProps) {
switch(this.format) {
case 'eu':
return `${d}.${m}.${y}`;
case 'uk':
return `${d}/${m}/${y}`;
case 'uk':
return `${d}/${m}/${y}`;
case 'us':
return `${m}/${d}/${y}`;
case 'long':
// Use the months array from the provided locale
return `${this.months[date.getMonth()]} ${d}, ${y}`;
// case 'iso'
default:
default: // iso
return `${y}-${m}-${d}`;
}
},
@ -294,24 +318,26 @@ templ Datepicker(props DatepickerProps) {
@resize.window="if (open) updatePosition()"
>
<div class="relative">
<input
x-ref="datePickerInput"
type="text"
id={ props.ID }
name={ props.Name }
if props.Placeholder != "" {
placeholder={ props.Placeholder }
} else {
placeholder="Select date"
}
disabled?={ props.Disabled }
:value="value"
x-modelable="value"
@click="toggleDatePicker()"
readonly
class="peer flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
{ props.Attributes... }
/>
@Input(InputProps{
ID: props.ID,
Name: props.Name,
Value: props.Value.Format(props.Config.GetGoFormat()),
Placeholder: props.Placeholder,
Disabled: props.Disabled,
Class: utils.TwMerge(props.Class, "peer"),
HasError: props.HasError,
Type: "text",
Readonly: true,
Attributes: mergeAttributes(
templ.Attributes{
"x-ref": "datePickerInput",
"x-modelable": "value",
":value": "value",
"@click": "toggleDatePicker()",
},
props.Attributes,
),
})
<button
type="button"
@click="toggleDatePicker()"

View File

@ -14,6 +14,16 @@ import (
"time"
)
func mergeAttributes(attrs ...templ.Attributes) templ.Attributes {
merged := templ.Attributes{}
for _, attr := range attrs {
for k, v := range attr {
merged[k] = v
}
}
return merged
}
// DateFormat defines the available date formatting styles
type DateFormat string
@ -83,6 +93,13 @@ var (
"Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"},
DayNames: []string{"Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"},
}
// DateLocaleJapanese provides Japanese localization
DateLocaleJapanese = DateLocale{
MonthNames: []string{"1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月"},
DayNames: []string{"日", "月", "火", "水", "木", "金", "土"},
}
)
// DatepickerConfig combines format and locale settings
@ -152,8 +169,12 @@ type DatepickerProps struct {
Config DatepickerConfig
// Placeholder sets the input placeholder text
Placeholder string
// Required marks the input as mandatory
Required bool
// Disabled controls whether the datepicker can be interacted with
Disabled bool
// HasError indicates whether the input should be styled as an error
HasError bool
// Class adds custom CSS classes
Class string
// Attributes allows additional HTML attributes
@ -202,6 +223,9 @@ func Datepicker(props DatepickerProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if props.Placeholder == "" {
props.Placeholder = "Select a date"
}
var templ_7745c5c3_Var2 = []any{utils.TwMerge("relative", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
@ -232,7 +256,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value.Format(props.Config.GetGoFormat()))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 180, Col: 62}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 204, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@ -250,7 +274,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Config.Format))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 182, Col: 43}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 206, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@ -263,7 +287,7 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(templ.JSONString(props.Config.Locale.MonthNames))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 183, Col: 68}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 207, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@ -276,81 +300,53 @@ func Datepicker(props DatepickerProps) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(templ.JSONString(props.Config.Locale.DayNames))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 184, Col: 64}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 208, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-data=\"{\n open: false,\n value: null,\n format: $el.dataset.format,\n currentMonth: 5,\n currentYear: new Date().getFullYear(),\n monthDays: [],\n blankDays: [],\n months: JSON.parse($el.dataset.monthnames) || [&#39;January&#39;, &#39;February&#39;, &#39;March&#39;, &#39;April&#39;, &#39;May&#39;, &#39;June&#39;, &#39;July&#39;, &#39;August&#39;, &#39;September&#39;, &#39;October&#39;, &#39;November&#39;, &#39;December&#39;],\n days: JSON.parse($el.dataset.daynames) || [&#39;Mo&#39;, &#39;Tu&#39;, &#39;We&#39;, &#39;Th&#39;, &#39;Fr&#39;, &#39;Sa&#39;, &#39;Su&#39;],\n\n position: &#39;bottom&#39;,\n\n init() {\n const initialDate = $el.dataset.value ? new Date(this.parseDate($el.dataset.value)) : new Date();\n this.currentMonth = initialDate.getMonth();\n this.currentYear = initialDate.getFullYear();\n this.calculateDays();\n // Format the initial value using the correct locale\n if ($el.dataset.value) {\n this.value = this.formatDate(initialDate);\n }\n },\n\n toggleDatePicker() {\n this.open = !this.open;\n if (this.open) {\n this.$nextTick(() =&gt; this.updatePosition());\n }\n },\n\n updatePosition() {\n const trigger = this.$refs.datePickerInput;\n const popup = this.$refs.datePickerPopup;\n const rect = trigger.getBoundingClientRect();\n const popupRect = popup.getBoundingClientRect();\n const viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n \n if (rect.bottom + popupRect.height &gt; viewportHeight &amp;&amp; rect.top &gt; popupRect.height) {\n this.position = &#39;top&#39;;\n } else {\n this.position = &#39;bottom&#39;;\n }\n },\n\n calculateDays() {\n const firstDay = new Date(this.currentYear, this.currentMonth, 1).getDay();\n const daysInMonth = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();\n \n this.blankDays = Array.from({ length: firstDay }, (_, i) =&gt; i);\n this.monthDays = Array.from({ length: daysInMonth }, (_, i) =&gt; i + 1);\n },\n\n\t\t\tparseDate(dateStr) {\n\t\t\t\tconst parts = dateStr.split(/[-/.]/);\n\t\t\t\tswitch(this.format) {\n\t\t\t\t\tcase &#39;eu&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[1]}-${parts[0]}`;\n\t\t\t\t\tcase &#39;us&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[0]}-${parts[1]}`;\n\t\t\t\t\tcase &#39;uk&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[1]}-${parts[0]}`;\n\t\t\t\t\tcase &#39;long&#39;:\n\t\t\t\t\tcase &#39;iso&#39;:\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn dateStr; // Für ISO und long Format das Datum unverändert lassen\n\t\t\t\t}\n\t\t\t}, \n\n\t\t\tformatDate(date) {\n const d = date.getDate().toString().padStart(2, &#39;0&#39;);\n const m = (date.getMonth() + 1).toString().padStart(2, &#39;0&#39;);\n const y = date.getFullYear();\n\n switch(this.format) {\n case &#39;eu&#39;:\n return `${d}.${m}.${y}`;\n\t\t\t\t\tcase &#39;uk&#39;:\n\t\t\t\t\t\treturn `${d}/${m}/${y}`;\n case &#39;us&#39;:\n return `${m}/${d}/${y}`;\n case &#39;long&#39;:\n // Use the months array from the provided locale\n return `${this.months[date.getMonth()]} ${d}, ${y}`;\n\t\t\t\t\t// case &#39;iso&#39;\n default:\n return `${y}-${m}-${d}`;\n }\n },\n\n isToday(day) {\n const today = new Date();\n const date = new Date(this.currentYear, this.currentMonth, day);\n return date.toDateString() === today.toDateString();\n },\n\n isSelected(day) {\n if (!this.value) return false;\n const date = new Date(this.currentYear, this.currentMonth, day);\n const selected = new Date(this.parseDate(this.value));\n return date.toDateString() === selected.toDateString();\n },\n\n selectDate(day) {\n const date = new Date(this.currentYear, this.currentMonth, day);\n this.value = this.formatDate(date);\n this.open = false;\n }\n }\" @resize.window=\"if (open) updatePosition()\"><div class=\"relative\"><input x-ref=\"datePickerInput\" type=\"text\" id=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-input-id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 300, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 209, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" x-data=\"{\n open: false,\n value: null,\n format: $el.dataset.format,\n currentMonth: 5,\n currentYear: new Date().getFullYear(),\n monthDays: [],\n blankDays: [],\n months: JSON.parse($el.dataset.monthnames) || [&#39;January&#39;, &#39;February&#39;, &#39;March&#39;, &#39;April&#39;, &#39;May&#39;, &#39;June&#39;, &#39;July&#39;, &#39;August&#39;, &#39;September&#39;, &#39;October&#39;, &#39;November&#39;, &#39;December&#39;],\n days: JSON.parse($el.dataset.daynames) || [&#39;Mo&#39;, &#39;Tu&#39;, &#39;We&#39;, &#39;Th&#39;, &#39;Fr&#39;, &#39;Sa&#39;, &#39;Su&#39;],\n\n position: &#39;bottom&#39;,\n\n init() {\n const initialDate = $el.dataset.value ? new Date(this.parseDate($el.dataset.value)) : new Date();\n this.currentMonth = initialDate.getMonth();\n this.currentYear = initialDate.getFullYear();\n this.calculateDays();\n // Format the initial value using the correct locale\n if ($el.dataset.value) {\n this.value = this.formatDate(initialDate);\n }\n },\n\n toggleDatePicker() {\n this.open = !this.open;\n if (this.open) {\n this.$nextTick(() =&gt; this.updatePosition());\n }\n },\n\n updatePosition() {\n const trigger = document.getElementById($el.dataset.inputId);\n const popup = this.$refs.datePickerPopup;\n const rect = trigger.getBoundingClientRect();\n const popupRect = popup.getBoundingClientRect();\n const viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n \n if (rect.bottom + popupRect.height &gt; viewportHeight &amp;&amp; rect.top &gt; popupRect.height) {\n this.position = &#39;top&#39;;\n } else {\n this.position = &#39;bottom&#39;;\n }\n },\n\n calculateDays() {\n const firstDay = new Date(this.currentYear, this.currentMonth, 1).getDay();\n const daysInMonth = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();\n \n this.blankDays = Array.from({ length: firstDay }, (_, i) =&gt; i);\n this.monthDays = Array.from({ length: daysInMonth }, (_, i) =&gt; i + 1);\n },\n\n\t\t\tparseDate(dateStr) {\n\t\t\t\tconst parts = dateStr.split(/[-/.]/);\n\t\t\t\tswitch(this.format) {\n\t\t\t\t\tcase &#39;eu&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[1]}-${parts[0]}`;\n\t\t\t\t\tcase &#39;us&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[0]}-${parts[1]}`;\n\t\t\t\t\tcase &#39;uk&#39;:\n\t\t\t\t\t\treturn `${parts[2]}-${parts[1]}-${parts[0]}`;\n\t\t\t\t\tcase &#39;long&#39;:\n\t\t\t\t\tcase &#39;iso&#39;:\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn dateStr; // Für ISO und long Format das Datum unverändert lassen\n\t\t\t\t}\n\t\t\t}, \n\n\t\t\tformatDate(date) {\n const d = date.getDate().toString().padStart(2, &#39;0&#39;);\n const m = (date.getMonth() + 1).toString().padStart(2, &#39;0&#39;);\n const y = date.getFullYear();\n\n switch(this.format) {\n case &#39;eu&#39;:\n return `${d}.${m}.${y}`;\n\t\t\t\t\t case &#39;uk&#39;:\n\t\t\t\t\t\t return `${d}/${m}/${y}`;\n case &#39;us&#39;:\n return `${m}/${d}/${y}`;\n case &#39;long&#39;:\n // Use the months array from the provided locale\n return `${this.months[date.getMonth()]} ${d}, ${y}`;\n default: // iso\n return `${y}-${m}-${d}`;\n }\n },\n\n isToday(day) {\n const today = new Date();\n const date = new Date(this.currentYear, this.currentMonth, day);\n return date.toDateString() === today.toDateString();\n },\n\n isSelected(day) {\n if (!this.value) return false;\n const date = new Date(this.currentYear, this.currentMonth, day);\n const selected = new Date(this.parseDate(this.value));\n return date.toDateString() === selected.toDateString();\n },\n\n selectDate(day) {\n const date = new Date(this.currentYear, this.currentMonth, day);\n this.value = this.formatDate(date);\n this.open = false;\n }\n }\" @resize.window=\"if (open) updatePosition()\"><div class=\"relative\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 301, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
templ_7745c5c3_Err = Input(InputProps{
ID: props.ID,
Name: props.Name,
Value: props.Value.Format(props.Config.GetGoFormat()),
Placeholder: props.Placeholder,
Disabled: props.Disabled,
Class: utils.TwMerge(props.Class, "peer"),
HasError: props.HasError,
Type: "text",
Readonly: true,
Attributes: mergeAttributes(
templ.Attributes{
"x-ref": "datePickerInput",
"x-modelable": "value",
":value": "value",
"@click": "toggleDatePicker()",
},
props.Attributes,
),
}).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 props.Placeholder != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" placeholder=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 303, Col: 36}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
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
}
} else {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" placeholder=\"Select date\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if props.Disabled {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" disabled")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" :value=\"value\" x-modelable=\"value\" @click=\"toggleDatePicker()\" readonly class=\"peer flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("> <button type=\"button\" @click=\"toggleDatePicker()\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button type=\"button\" @click=\"toggleDatePicker()\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -172,7 +172,7 @@ templ renderMenuItem(item DropdownMenuItem, index int, depth int) {
// - ARIA support
templ DropdownMenu(props DropdownMenuProps) {
<div
x-data="{
x-data="{
open: false,
position: $el.dataset.position,
verticalPosition: 'bottom',
@ -181,7 +181,7 @@ templ DropdownMenu(props DropdownMenuProps) {
const rect = menu.getBoundingClientRect();
const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if (this.position === 'left' && rect.left < 0) {
this.position = 'right';
} else if (this.position !== 'left' && rect.right > viewportWidth) {

View File

@ -441,7 +441,7 @@ func DropdownMenu(props DropdownMenuProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{ \n\t\t\topen: false,\n\t\t\tposition: $el.dataset.position,\n\t\t\tverticalPosition: &#39;bottom&#39;,\n\t\t\tupdatePosition() {\n\t\t\t\tconst menu = this.$refs.menu;\n\t\t\t\tconst rect = menu.getBoundingClientRect();\n\t\t\t\tconst viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n\t\t\t\tconst viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n\t\t\t\t\n\t\t\t\tif (this.position === &#39;left&#39; &amp;&amp; rect.left &lt; 0) {\n\t\t\t\t\tthis.position = &#39;right&#39;;\n\t\t\t\t} else if (this.position !== &#39;left&#39; &amp;&amp; rect.right &gt; viewportWidth) {\n\t\t\t\t\tthis.position = &#39;left&#39;;\n\t\t\t\t}\n\n\t\t\t\tif (this.verticalPosition === &#39;bottom&#39; &amp;&amp; rect.bottom &gt; viewportHeight) {\n\t\t\t\t\tthis.verticalPosition = &#39;top&#39;;\n\t\t\t\t} else if (this.verticalPosition === &#39;top&#39; &amp;&amp; rect.top &lt; 0) {\n\t\t\t\t\tthis.verticalPosition = &#39;bottom&#39;;\n\t\t\t\t}\n\t\t\t}\n\t\t}\" @resize.window=\"if (open) updatePosition()\" class=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{\n\t\t\topen: false,\n\t\t\tposition: $el.dataset.position,\n\t\t\tverticalPosition: &#39;bottom&#39;,\n\t\t\tupdatePosition() {\n\t\t\t\tconst menu = this.$refs.menu;\n\t\t\t\tconst rect = menu.getBoundingClientRect();\n\t\t\t\tconst viewportWidth = window.innerWidth || document.documentElement.clientWidth;\n\t\t\t\tconst viewportHeight = window.innerHeight || document.documentElement.clientHeight;\n\n\t\t\t\tif (this.position === &#39;left&#39; &amp;&amp; rect.left &lt; 0) {\n\t\t\t\t\tthis.position = &#39;right&#39;;\n\t\t\t\t} else if (this.position !== &#39;left&#39; &amp;&amp; rect.right &gt; viewportWidth) {\n\t\t\t\t\tthis.position = &#39;left&#39;;\n\t\t\t\t}\n\n\t\t\t\tif (this.verticalPosition === &#39;bottom&#39; &amp;&amp; rect.bottom &gt; viewportHeight) {\n\t\t\t\t\tthis.verticalPosition = &#39;top&#39;;\n\t\t\t\t} else if (this.verticalPosition === &#39;top&#39; &amp;&amp; rect.top &lt; 0) {\n\t\t\t\t\tthis.verticalPosition = &#39;bottom&#39;;\n\t\t\t\t}\n\t\t\t}\n\t\t}\" @resize.window=\"if (open) updatePosition()\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

75
pkg/components/form.templ Normal file
View File

@ -0,0 +1,75 @@
package components
import "github.com/axzilla/goilerplate/pkg/utils"
// FormItemProps represents a form container's properties
type FormItemProps struct {
ID string // Optional container ID
Class string // Custom classes
}
// FormItem wraps form elements in a vertical layout
templ FormItem(props FormItemProps) {
<div class={ utils.TwMerge("space-y-2", props.Class) }>
{ children... }
</div>
}
// FormItemFlex wraps form elements in a horizontal layout
templ FormItemFlex(props FormItemProps) {
<div class={ utils.TwMerge("items-center flex space-x-2", props.Class) }>
{ children... }
</div>
}
// FormLabelProps represents label properties
type FormLabelProps struct {
For string // Target form element ID
Text string // Label text
Class string // Custom classes
DisabledClass string // Classes applied when input is disabled
}
// FormLabel renders a form label
templ FormLabel(props FormLabelProps) {
@Label(LabelProps{
For: props.For,
Class: props.Class,
Text: props.Text,
DisabledClass: props.DisabledClass,
})
}
// FormDescriptionProps represents helper text properties
type FormDescriptionProps struct {
Class string // Custom classes
}
// FormDescription renders helper text below form elements
templ FormDescription(props FormDescriptionProps) {
<p class={ utils.TwMerge("text-sm text-muted-foreground", props.Class) }>
{ children... }
</p>
}
// FormMessageProps represents feedback message properties
type FormMessageProps struct {
Type string // error, success, warning, info
Message string // Message text
Class string // Custom classes
}
// FormMessage renders feedback messages
templ FormMessage(props FormMessageProps) {
<p
class={
utils.TwMerge(
"text-sm font-medium",
props.Class,
),
templ.KV("text-destructive", props.Type == "error"),
}
>
{ props.Message }
</p>
}

View File

@ -0,0 +1,309 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.793
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils"
// FormItemProps represents a form container's properties
type FormItemProps struct {
ID string // Optional container ID
Class string // Custom classes
}
// FormItem wraps form elements in a vertical layout
func FormItem(props FormItemProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{utils.TwMerge("space-y-2", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/form.templ`, Line: 1, Col: 0}
}
_, 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("\">")
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("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
// FormItemFlex wraps form elements in a horizontal layout
func FormItemFlex(props FormItemProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var5 = []any{utils.TwMerge("items-center flex space-x-2", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var5).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/form.templ`, Line: 1, Col: 0}
}
_, 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("\">")
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("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
// FormLabelProps represents label properties
type FormLabelProps struct {
For string // Target form element ID
Text string // Label text
Class string // Custom classes
DisabledClass string // Classes applied when input is disabled
}
// FormLabel renders a form label
func FormLabel(props FormLabelProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = Label(LabelProps{
For: props.For,
Class: props.Class,
Text: props.Text,
DisabledClass: props.DisabledClass,
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
// FormDescriptionProps represents helper text properties
type FormDescriptionProps struct {
Class string // Custom classes
}
// FormDescription renders helper text below form elements
func FormDescription(props FormDescriptionProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var9 = []any{utils.TwMerge("text-sm text-muted-foreground", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var9).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/form.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
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
}
templ_7745c5c3_Err = templ_7745c5c3_Var8.Render(ctx, templ_7745c5c3_Buffer)
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
}
return templ_7745c5c3_Err
})
}
// FormMessageProps represents feedback message properties
type FormMessageProps struct {
Type string // error, success, warning, info
Message string // Message text
Class string // Custom classes
}
// FormMessage renders feedback messages
func FormMessage(props FormMessageProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var11 := templ.GetChildren(ctx)
if templ_7745c5c3_Var11 == nil {
templ_7745c5c3_Var11 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var12 = []any{
utils.TwMerge(
"text-sm font-medium",
props.Class,
),
templ.KV("text-destructive", props.Type == "error"),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var12...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var12).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/form.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
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
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(props.Message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/form.templ`, Line: 73, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
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
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -23,99 +23,84 @@ const (
InputTypeFile InputType = "file"
)
// InputProps defines configuration options for the Input component
type InputProps struct {
// Type sets the input field behavior
// Type controls the input's behavior (text, email, password etc)
Type InputType
// Placeholder shows helper text when empty
// Placeholder text shown when input is empty
Placeholder string
// Value sets the current input content
// Value sets the current content of the input field
Value string
// Name sets the form field name
// Name identifies the field in form submissions
Name string
// ID uniquely identifies the input
// ID uniquely identifies the input element in the DOM
ID string
// Label displays text above input
Label string
// Disabled sets the input to disabled state
// Disabled prevents user interaction when true
Disabled bool
// Description shows helper text below input
Description string
// Readonly prevents user input but allows for selection and copying
Readonly bool
// Error displays validation message
Error string
// Class adds custom CSS classes
// Class applies custom CSS classes to the input element
Class string
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
// ErrorClass applies custom CSS classes to the input element when an error is present
ErrorClass string
// FileAccept specifies allowed file types (only for file inputs)
FileAccept string
// Attributes for additional HTML attributes and Alpine.js bindings
// HasError indicates whether the input should be styled as an error
HasError bool
// Attributes for additional HTML/Alpine.js bindings
Attributes templ.Attributes
}
// Text field that allows users to enter and edit values.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Props:
// - Type: Input field behavior type
// - Placeholder: Helper text when empty
// - Value: Current input value
// - Name: Form field name
// - ID: Unique identifier
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
templ Input(props InputProps) {
<span class="space-y-2">
if props.Label != "" {
<label
for={ props.ID }
class={ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
templ.KV("text-destructive", len(props.Error)>0) }
>
{ props.Label }
</label>
<input
x-ref={ props.ID }
type={ string(props.Type) }
placeholder={ props.Placeholder }
disabled?={ props.Disabled }
readonly?={ props.Readonly }
name={ props.Name }
if props.Value != "" {
value={ props.Value }
}
<input
type={ string(props.Type) }
placeholder={ props.Placeholder }
disabled?={ props.Disabled }
name={ props.Name }
if props.Value != "" {
value={ props.Value }
}
id={ props.ID }
class={
utils.TwMerge("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background",
"file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
"file:text-foreground dark:file:text-foreground",
props.Class),
}
if props.Type == InputTypeFile {
accept={ props.FileAccept }
}
{ props.Attributes... }
/>
if props.Description != "" {
<p class="text-sm text-muted-foreground m-0">{ props.Description }</p>
id={ props.ID }
class={
utils.TwMerge(
// Layout
"peer flex h-10 w-full px-3 py-2",
// Styling
"rounded-md border border-input bg-background text-sm ring-offset-background",
"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground ",
"placeholder:text-muted-foreground",
// States
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
// Conditional
utils.TwIf("border-destructive ring-destructive", props.HasError),
// Custom
props.Class,
),
}
if props.Error != "" {
<p class="text-sm font-medium text-destructive">{ props.Error }</p>
if props.Type == InputTypeFile {
accept={ props.FileAccept }
}
</span>
{ props.Attributes... }
/>
}

View File

@ -31,61 +31,48 @@ const (
InputTypeFile InputType = "file"
)
// InputProps defines configuration options for the Input component
type InputProps struct {
// Type sets the input field behavior
// Type controls the input's behavior (text, email, password etc)
Type InputType
// Placeholder shows helper text when empty
// Placeholder text shown when input is empty
Placeholder string
// Value sets the current input content
// Value sets the current content of the input field
Value string
// Name sets the form field name
// Name identifies the field in form submissions
Name string
// ID uniquely identifies the input
// ID uniquely identifies the input element in the DOM
ID string
// Label displays text above input
Label string
// Disabled sets the input to disabled state
// Disabled prevents user interaction when true
Disabled bool
// Description shows helper text below input
Description string
// Readonly prevents user input but allows for selection and copying
Readonly bool
// Error displays validation message
Error string
// Class adds custom CSS classes
// Class applies custom CSS classes to the input element
Class string
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
// ErrorClass applies custom CSS classes to the input element when an error is present
ErrorClass string
// FileAccept specifies allowed file types (only for file inputs)
FileAccept string
// Attributes for additional HTML attributes and Alpine.js bindings
// HasError indicates whether the input should be styled as an error
HasError bool
// Attributes for additional HTML/Alpine.js bindings
Attributes templ.Attributes
}
// Text field that allows users to enter and edit values.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/input
//
// Props:
// - Type: Input field behavior type
// - Placeholder: Helper text when empty
// - Value: Current input value
// - Name: Form field name
// - ID: Unique identifier
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Class: Additional CSS classes
// - FileAccept: Allowed file types
// - Attributes: Additional HTML attributes
func Input(props InputProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
@ -107,83 +94,54 @@ func Input(props InputProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"space-y-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.Label != "" {
var templ_7745c5c3_Var2 = []any{"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
templ.KV("text-destructive", len(props.Error) > 0)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 85, Col: 18}
}
_, 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("\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 1, Col: 0}
}
_, 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("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 89, Col: 17}
}
_, 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("</label> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
var templ_7745c5c3_Var6 = []any{
utils.TwMerge("flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background",
"file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground",
var templ_7745c5c3_Var2 = []any{
utils.TwMerge(
// Layout
"peer flex h-10 w-full px-3 py-2",
// Styling
"rounded-md border border-input bg-background text-sm ring-offset-background",
"file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground ",
"placeholder:text-muted-foreground",
// States
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
"file:text-foreground dark:file:text-foreground",
props.Class),
// Conditional
utils.TwIf("border-destructive ring-destructive", props.HasError),
// Custom
props.Class,
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input type=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input x-ref=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type))
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 93, Col: 28}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 70, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
_, 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("\" type=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(string(props.Type))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 71, Col: 27}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -191,12 +149,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 94, Col: 34}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 72, Col: 33}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -210,16 +168,22 @@ func Input(props InputProps) templ.Component {
return templ_7745c5c3_Err
}
}
if props.Readonly {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" readonly")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 96, Col: 20}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 75, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -232,12 +196,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 98, Col: 23}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 77, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -250,12 +214,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 100, Col: 16}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 79, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -263,12 +227,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var6).String())
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -281,12 +245,12 @@ func Input(props InputProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept)
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.FileAccept)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 110, Col: 29}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 102, Col: 28}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -299,49 +263,7 @@ func Input(props InputProps) templ.Component {
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 props.Description != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-sm text-muted-foreground m-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(props.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 115, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
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
}
}
if props.Error != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-sm font-medium text-destructive\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(props.Error)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/input.templ`, Line: 118, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
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_7745c5c3_Buffer.WriteString("</span>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -0,0 +1,37 @@
package components
// LabelProps represents label properties
type LabelProps struct {
ID string // Optional label ID
For string // Target input ID
Text string // Label text
Error string // Error message
Class string // Custom classes
DisabledClass string // Classes applied when input is disabled
}
// Label renders a form label with error and disabled states
templ Label(props LabelProps) {
<label
id={ props.ID }
for={ props.For }
class={
// Styling
"text-sm font-medium leading-none",
// Utility
templ.KV("text-destructive", len(props.Error) > 0),
// Custom
props.Class,
}
if props.DisabledClass != "" {
data-disabled-style={ props.DisabledClass }
} else {
data-disabled-style="opacity-50 cursor-not-allowed"
}
x-bind:class="{ [$el.dataset.disabledStyle]: $refs[$el.getAttribute('for')]?.disabled }"
>
{ props.Text }
</label>
}

View File

@ -0,0 +1,145 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.793
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
// LabelProps represents label properties
type LabelProps struct {
ID string // Optional label ID
For string // Target input ID
Text string // Label text
Error string // Error message
Class string // Custom classes
DisabledClass string // Classes applied when input is disabled
}
// Label renders a form label with error and disabled states
func Label(props LabelProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{
// Styling
"text-sm font-medium leading-none",
// Utility
templ.KV("text-destructive", len(props.Error) > 0),
// Custom
props.Class,
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/label.templ`, Line: 16, Col: 15}
}
_, 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("\" for=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.For)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/label.templ`, Line: 17, Col: 17}
}
_, 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("\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/label.templ`, Line: 1, Col: 0}
}
_, 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("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if props.DisabledClass != "" {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" data-disabled-style=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.DisabledClass)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/label.templ`, Line: 29, Col: 44}
}
_, 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("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" data-disabled-style=\"opacity-50 cursor-not-allowed\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" x-bind:class=\"{ [$el.dataset.disabledStyle]: $refs[$el.getAttribute(&#39;for&#39;)]?.disabled }\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/label.templ`, Line: 35, Col: 14}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -1,19 +1,6 @@
package components
import "github.com/axzilla/goilerplate/pkg/utils"
type RadioGroupProps struct {
// Name groups related radio buttons
Name string
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes
Attributes templ.Attributes
}
type RadioGroupItemProps struct {
type RadioProps struct {
// Value sets the radio button value
Value string
@ -39,53 +26,18 @@ type RadioGroupItemProps struct {
Attributes templ.Attributes
}
// RadioGroup renders a set of mutually exclusive radio button options.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
//
// Props:
// - Name: Groups related radio buttons
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
templ RadioGroup(props RadioGroupProps) {
<div
role="radiogroup"
class={ utils.TwMerge("space-y-2", props.Class) }
{ props.Attributes... }
>
{ children... }
</div>
}
// Control for selecting a single option from a list of choices.
// Must be used within a RadioGroup component.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
//
// Props:
// - Value: Radio button value
// - Name: Matches parent group name
// - ID: Unique identifier
// - Label: Button label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
templ RadioGroupItem(props RadioGroupItemProps) {
<label
for={ props.ID }
class={ utils.TwMerge(
"flex items-center gap-2 cursor-pointer text-sm font-medium",
"text-muted-foreground [&:has(input:checked)]:text-foreground",
"[&:has(input:disabled)]:cursor-not-allowed [&:has(input:disabled)]:opacity-50",
props.Class,
) }
>
<input
type="radio"
id={ props.ID }
name={ props.Name }
value={ props.Value }
checked?={ props.Checked }
disabled?={ props.Disabled }
class="before:content[''] relative h-4 w-4 appearance-none rounded-full
templ Radio(props RadioProps) {
<input
x-ref={ props.ID }
type="radio"
id={ props.ID }
name={ props.Name }
value={ props.Value }
checked?={ props.Checked }
disabled?={ props.Disabled }
class="before:content[''] relative h-4 w-4 appearance-none rounded-full
border border-2 border-primary
checked:border-primary checked:bg-primary
before:absolute before:left-1/2 before:top-1/2
@ -95,12 +47,6 @@ templ RadioGroupItem(props RadioGroupItemProps) {
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
focus-visible:ring-offset-2 focus-visible:ring-offset-background
disabled:cursor-not-allowed"
{ props.Attributes... }
/>
if props.Label != nil {
@props.Label
} else {
<span>{ props.Value }</span>
}
</label>
{ props.Attributes... }
/>
}

View File

@ -8,20 +8,7 @@ package components
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils"
type RadioGroupProps struct {
// Name groups related radio buttons
Name string
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes
Attributes templ.Attributes
}
type RadioGroupItemProps struct {
type RadioProps struct {
// Value sets the radio button value
Value string
@ -47,14 +34,9 @@ type RadioGroupItemProps struct {
Attributes templ.Attributes
}
// RadioGroup renders a set of mutually exclusive radio button options.
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
//
// Props:
// - Name: Groups related radio buttons
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func RadioGroup(props RadioGroupProps) templ.Component {
// Control for selecting a single option from a list of choices.
// Must be used within a RadioGroup component.
func Radio(props RadioProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@ -75,140 +57,42 @@ func RadioGroup(props RadioGroupProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{utils.TwMerge("space-y-2", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input x-ref=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div role=\"radiogroup\" class=\"")
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 33, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" type=\"radio\" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var2).String())
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 35, Col: 15}
}
_, 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("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, props.Attributes)
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
}
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("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
// Control for selecting a single option from a list of choices.
// Must be used within a RadioGroup component.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/radio-group
//
// Props:
// - Value: Radio button value
// - Name: Matches parent group name
// - ID: Unique identifier
// - Label: Button label
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
func RadioGroupItem(props RadioGroupItemProps) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var5 = []any{utils.TwMerge(
"flex items-center gap-2 cursor-pointer text-sm font-medium",
"text-muted-foreground [&:has(input:checked)]:text-foreground",
"[&:has(input:disabled)]:cursor-not-allowed [&:has(input:disabled)]:opacity-50",
props.Class,
)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var5...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<label for=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 73, Col: 16}
}
_, 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("\" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var5).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><input type=\"radio\" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 83, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 84, Col: 20}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 36, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -216,12 +100,12 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 85, Col: 22}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 37, Col: 21}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -249,35 +133,7 @@ func RadioGroupItem(props RadioGroupItemProps) templ.Component {
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 props.Label != nil {
templ_7745c5c3_Err = props.Label.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 103, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -735,10 +735,6 @@ body {
z-index: 50;
}
.m-0 {
margin: 0px;
}
.mb-1 {
margin-bottom: 0.25rem;
}
@ -1040,6 +1036,12 @@ body {
gap: 0.5rem;
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.space-y-1\.5 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.375rem * calc(1 - var(--tw-space-y-reverse)));
@ -1415,6 +1417,10 @@ body {
opacity: 1;
}
.opacity-50 {
opacity: 0.5;
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
@ -1454,6 +1460,11 @@ body {
--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity));
}
.ring-destructive {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--destructive) / var(--tw-ring-opacity));
}
.ring-opacity-5 {
--tw-ring-opacity: 0.05;
}
@ -1819,6 +1830,10 @@ body {
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.peer:checked ~ .peer-checked\:opacity-100 {
opacity: 1;
}
.peer:checked ~ .peer-checked\:after\:translate-x-\[16px\]::after {
content: var(--tw-content);
--tw-translate-x: 16px;
@ -1847,11 +1862,6 @@ body {
opacity: 0.7;
}
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
@media (min-width: 640px) {
.sm\:my-8 {
margin-top: 2rem;
@ -1947,19 +1957,6 @@ body {
background-color: hsl(var(--primary) / 0.9);
}
.\[\&\:has\(input\:checked\)\]\:text-foreground:has(input:checked) {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.\[\&\:has\(input\:disabled\)\]\:cursor-not-allowed:has(input:disabled) {
cursor: not-allowed;
}
.\[\&\:has\(input\:disabled\)\]\:opacity-50:has(input:disabled) {
opacity: 0.5;
}
.\[\&\:has\(svg\)\]\:pl-11:has(svg) {
padding-left: 2.75rem;
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/a-h/templ"
"math/rand"
twmerge "github.com/Oudwins/tailwind-merge-go"
)
@ -15,6 +16,22 @@ func TwMerge(classes ...string) string {
return twmerge.Merge(classes...)
}
// TwIf returns a class if a condition is true, otherwise an empty string
// Example: "bg-red-500", true → "bg-red-500", false → ""
func TwIf(class string, condition bool) string {
result := templ.KV(class, condition)
if result.Value == true {
return result.Key
}
return ""
}
// RandomID returns a random ID string
// Example: "id-123456"
func RandomID() string {
return fmt.Sprintf("id-%d", rand.Intn(1000000))
}
// CSS returns a link tag for the Goilerplate CSS
// If no branch is specified, it defaults to 'main'
func CSS(branch string) templ.Component {