1
0
mirror of https://github.com/axzilla/templui.git synced 2025-02-21 00:12:48 +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 14a5400b52
103 changed files with 2612 additions and 2416 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

@ -629,18 +629,6 @@ body {
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.pointer-events-none {
pointer-events: none;
}
@ -649,10 +637,6 @@ body {
visibility: visible;
}
.invisible {
visibility: hidden;
}
.fixed {
position: fixed;
}
@ -751,10 +735,6 @@ body {
z-index: 50;
}
.m-0 {
margin: 0px;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@ -986,18 +966,10 @@ body {
width: 1.75rem;
}
.w-72 {
width: 18rem;
}
.w-8 {
width: 2rem;
}
.w-96 {
width: 24rem;
}
.w-full {
width: 100%;
}
@ -1014,6 +986,10 @@ body {
max-width: 28rem;
}
.max-w-sm {
max-width: 24rem;
}
.max-w-xl {
max-width: 36rem;
}
@ -1038,10 +1014,6 @@ body {
flex-shrink: 0;
}
.grow {
flex-grow: 1;
}
.-translate-x-1 {
--tw-translate-x: -0.25rem;
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));
@ -1772,6 +1744,10 @@ body {
opacity: 1;
}
.opacity-50 {
opacity: 0.5;
}
.opacity-80 {
opacity: 0.8;
}
@ -1815,6 +1791,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;
}
@ -2133,22 +2114,6 @@ body {
outline-offset: 2px;
}
.focus\:outline:focus {
outline-style: solid;
}
.focus\:outline-2:focus {
outline-width: 2px;
}
.focus\:outline-offset-2:focus {
outline-offset: 2px;
}
.focus\:outline-ring:focus {
outline-color: hsl(var(--ring) / 1);
}
.focus\:ring-2:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -2173,10 +2138,6 @@ body {
--tw-ring-offset-width: 2px;
}
.checked\:focus\:outline-primary:focus:checked {
outline-color: hsl(var(--primary) / 1);
}
.focus-visible\:outline-none:focus-visible {
outline: 2px solid transparent;
outline-offset: 2px;
@ -2207,10 +2168,6 @@ body {
--tw-ring-offset-color: hsl(var(--background) / 1);
}
.active\:outline-offset-0:active {
outline-offset: 0px;
}
.disabled\:pointer-events-none:disabled {
pointer-events: none;
}
@ -2241,18 +2198,13 @@ body {
opacity: 1;
}
.peer:checked ~ .peer-checked\:visible {
visibility: visible;
}
.peer:checked ~ .peer-checked\:bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.peer:checked ~ .peer-checked\:text-foreground {
--tw-text-opacity: 1;
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 {
@ -2279,10 +2231,6 @@ body {
opacity: 0.5;
}
.peer:disabled ~ .peer-disabled\:opacity-70 {
opacity: 0.7;
}
.dark\:from-gray-900:is(.dark *) {
--tw-gradient-from: #111827 var(--tw-gradient-from-position);
--tw-gradient-to: rgb(17 24 39 / 0) var(--tw-gradient-to-position);
@ -2313,11 +2261,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 +2454,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

@ -35,7 +35,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()))

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

@ -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

@ -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,31 +15,39 @@ 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: "With Label",
ShowcaseFile: showcase.SelectWithLabel(),
PreviewCodeFile: "select_with_label.templ",
ComponentCodeFile: "select.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.SelectDisabled(),
ShowcaseClass: "w-72",
PreviewCodeFile: "select_disabled.templ",
ComponentCodeFile: "select.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.SelectForm(),
PreviewCodeFile: "select_form.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,65 +15,45 @@ 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",
PreviewCodeFile: "textarea_with_label.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Description",
ShowcaseFile: showcase.TextareaWithDescription(),
ShowcaseClass: "w-96",
PreviewCodeFile: "textarea_with_description.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Error",
ShowcaseFile: showcase.TextareaWithError(),
ShowcaseClass: "w-96",
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: "With Label",
ShowcaseFile: showcase.TextareaWithLabel(),
PreviewCodeFile: "textarea_with_label.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.TextareaDisabled(),
PreviewCodeFile: "textarea_disabled.templ",
ComponentCodeFile: "textarea.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.TextareaForm(),
PreviewCodeFile: "textarea_form.templ",
ComponentCodeFile: "textarea.templ",
})
}
}
}

View File

@ -100,50 +100,48 @@ 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>
<div class="space-y-2">
@components.Toggle(components.ToggleProps{
ID: "marketing",
Name: "marketing",
LabelRight: "Receive marketing emails",
ID: "marketing",
Name: "marketing",
// LabelRight: "Receive marketing emails",
})
</div>
<div class="space-y-2">
@components.Toggle(components.ToggleProps{
ID: "notifications",
Name: "notifications",
LabelRight: "Enable notifications",
ID: "notifications",
Name: "notifications",
// LabelRight: "Enable notifications",
Attributes: templ.Attributes{"checked": "true"},
})
</div>
<div class="space-y-2">
@components.Toggle(components.ToggleProps{
ID: "beta",
Name: "beta",
LabelRight: "Join beta program",
ID: "beta",
Name: "beta",
// LabelRight: "Join beta program",
Attributes: templ.Attributes{"disabled": "true"},
})
</div>
@ -153,7 +151,6 @@ templ ThemePreview() {
ID: "terms",
Name: "terms",
Value: "accepted",
Label: "I agree to the Terms and Conditions",
})
</div>
<div class="space-y-2">
@ -161,7 +158,6 @@ templ ThemePreview() {
ID: "newsletter",
Name: "newsletter",
Value: "subscribed",
Label: "Subscribe to our newsletter",
})
</div>
</form>

View File

@ -18,30 +18,30 @@ templ Toggle() {
PreviewCodeFile: "toggle_default.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Label Left",
ShowcaseFile: showcase.ToggleLabelLeft(),
PreviewCodeFile: "toggle_label_left.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Label Right",
ShowcaseFile: showcase.ToggleLabelRight(),
PreviewCodeFile: "toggle_label_right.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Checked",
ShowcaseFile: showcase.ToggleChecked(),
PreviewCodeFile: "toggle_checked.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "With Label",
ShowcaseFile: showcase.ToggleWithLabel(),
PreviewCodeFile: "toggle_with_label.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Disabled",
ShowcaseFile: showcase.ToggleDisabled(),
PreviewCodeFile: "toggle_disabled.templ",
ComponentCodeFile: "toggle.templ",
})
@modules.ExampleWrapper(modules.ExampleWrapperProps{
SectionName: "Form",
ShowcaseFile: showcase.ToggleForm(),
PreviewCodeFile: "toggle_form.templ",
ComponentCodeFile: "toggle.templ",
})
}
}
}

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,13 @@
package showcase
import (
"github.com/axzilla/goilerplate/pkg/components"
"github.com/axzilla/goilerplate/pkg/icons"
)
templ CheckboxCustomIcon() {
@components.Checkbox(components.CheckboxProps{
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,9 @@ 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{
Placeholder: "When is your birthday?",
})
</div>
}

View File

@ -3,9 +3,7 @@ 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{})
</div>
}

View File

@ -2,28 +2,12 @@ package showcase
import (
"github.com/axzilla/goilerplate/pkg/components"
"time"
)
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",
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,
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: "Select a 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,58 @@ 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",
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",
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",
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",
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",
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",
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,9 @@ 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{
Value: time.Now(),
})
</div>
}

View File

@ -0,0 +1,17 @@
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: "Pick a date",
For: "datepicker-with-label",
})
@components.Datepicker(components.DatepickerProps{
ID: "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,29 @@
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",
Name: "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,9 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioChecked() {
@components.Radio(components.RadioProps{
Checked: true,
})
}

View File

@ -0,0 +1,9 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ RadioDefault() {
<div class="flex gap-2 items-center">
@components.Radio(components.RadioProps{})
</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,15 @@
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",
})
@components.Label(components.LabelProps{
For: "radio-with-label",
Text: "Label",
})
</div>
}

View File

@ -3,14 +3,14 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectDefault() {
@components.Select(components.SelectProps{
ID: "fruit",
Name: "fruit",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange"},
{Label: "Mango", Value: "mango"},
},
})
<div class="w-full max-w-md">
@components.Select(components.SelectProps{
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange"},
{Label: "Mango", Value: "mango"},
},
})
</div>
}

View File

@ -3,25 +3,17 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectDisabled() {
<div class="flex flex-col gap-4">
@components.Select(components.SelectProps{
ID: "disabled",
Name: "disabled",
Placeholder: "Disabled using props",
Disabled: true,
Options: []components.SelectOption{
{Label: "Option 1", Value: "1"},
{Label: "Option 2", Value: "2"},
},
<div class="space-y-2 w-full max-w-sm">
@components.FormLabel(components.FormLabelProps{
Text: "Choose a fruit",
For: "select-disabled",
})
@components.Select(components.SelectProps{
ID: "disabled",
Name: "disabled",
Placeholder: "Disabled using attributes",
Attributes: templ.Attributes{":disabled": "true"},
ID: "select-disabled",
Disabled: true,
Options: []components.SelectOption{
{Label: "Option 1", Value: "1"},
{Label: "Option 2", Value: "2"},
{Label: "Apple", Value: "1"},
{Label: "Banana", Value: "2"},
},
})
</div>

View File

@ -0,0 +1,31 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
@components.Label(components.LabelProps{
Text: "Choose a Fruit",
For: "fruit-form",
})
@components.Select(components.SelectProps{
Name: "fruit",
ID: "fruit-form",
Placeholder: "Pick a fruit",
HasError: true,
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
},
})
@components.FormDescription(components.FormDescriptionProps{}) {
Select your favorite fruit from the dropdown menu.
}
@components.FormMessage(components.FormMessageProps{
Type: "error",
Message: "A fruit selection is required.",
})
}
</div>
}

View File

@ -3,11 +3,8 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectSelectedValue() {
<div class="flex flex-col gap-4">
<div class="w-full max-w-sm">
@components.Select(components.SelectProps{
ID: "selected",
Name: "selected",
Placeholder: "Selected by props",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana", Selected: true},
@ -15,16 +12,5 @@ templ SelectSelectedValue() {
{Label: "Mango", Value: "mango"},
},
})
@components.Select(components.SelectProps{
ID: "selected",
Name: "selected",
Placeholder: "Selected by attributes",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange", Attributes: templ.Attributes{"selected": true}},
{Label: "Mango", Value: "mango"},
},
})
</div>
}

View File

@ -0,0 +1,21 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectWithLabel() {
<div class="space-y-2 w-full max-w-sm">
@components.Label(components.LabelProps{
Text: "Choose a Fruit",
For: "fruit-with-label",
})
@components.Select(components.SelectProps{
ID: "fruit-with-label",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange"},
{Label: "Mango", Value: "mango"},
},
})
</div>
}

View File

@ -3,15 +3,15 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SelectWithPlaceholder() {
@components.Select(components.SelectProps{
ID: "fruit",
Name: "fruit",
Placeholder: "Select a fruit",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange"},
{Label: "Mango", Value: "mango"},
},
})
<div class="w-full max-w-md">
@components.Select(components.SelectProps{
Placeholder: "Pick a fruit",
Options: []components.SelectOption{
{Label: "Apple", Value: "apple"},
{Label: "Banana", Value: "banana"},
{Label: "Orange", Value: "orange"},
{Label: "Mango", Value: "mango"},
},
})
</div>
}

View File

@ -3,8 +3,10 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderDefault() {
@components.Slider(components.SliderProps{
ID: "default",
Name: "default",
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "default",
Name: "default",
})
</div>
}

View File

@ -3,15 +3,17 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderDisabled() {
@components.Slider(components.SliderProps{
ID: "disabled",
Name: "disabled",
Label: "Disabled Slider",
Value: 20,
Min: -20,
Max: 200,
Step: 20,
Disabled: true,
ShowValue: true,
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "disabled",
Name: "disabled",
Label: "Disabled Slider",
Value: 20,
Min: -20,
Max: 200,
Step: 20,
Disabled: true,
ShowValue: true,
})
</div>
}

View File

@ -3,13 +3,15 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderWithLabel() {
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Label: "Volume",
Value: 65,
Min: 0,
Max: 100,
Step: 1,
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Label: "Volume",
Value: 65,
Min: 0,
Max: 100,
Step: 1,
})
</div>
}

View File

@ -3,15 +3,17 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderWithLabelAndValue() {
@components.Slider(components.SliderProps{
ID: "temperature",
Name: "temperature",
Label: "Temperature",
Value: 23,
Min: -20,
Max: 40,
Step: 1,
ShowValue: true,
ValueFormat: "°C",
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "temperature",
Name: "temperature",
Label: "Temperature",
Value: 23,
Min: -20,
Max: 40,
Step: 1,
ShowValue: true,
ValueFormat: "°C",
})
</div>
}

View File

@ -3,15 +3,17 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderWithSteps() {
@components.Slider(components.SliderProps{
ID: "steps",
Name: "steps",
Label: "Zoom Level",
Value: 100,
Min: 0,
Max: 200,
Step: 25,
ShowValue: true,
ValueFormat: "%",
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "steps",
Name: "steps",
Label: "Zoom Level",
Value: 100,
Min: 0,
Max: 200,
Step: 25,
ShowValue: true,
ValueFormat: "%",
})
</div>
}

View File

@ -3,14 +3,16 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ SliderWithValue() {
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Value: 75,
Min: 0,
Max: 100,
Step: 1,
ShowValue: true,
ValueFormat: "%",
})
<div class="w-full max-w-sm">
@components.Slider(components.SliderProps{
ID: "with-label",
Name: "with-label",
Value: 75,
Min: 0,
Max: 100,
Step: 1,
ShowValue: true,
ValueFormat: "%",
})
</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

@ -3,13 +3,10 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaAutoResize() {
@components.Textarea(components.TextareaProps{
ID: "auto-resize",
Name: "auto-resize",
Label: "Your Message",
Description: "This textarea will grow as you type.",
Placeholder: "Start typing to see the magic...",
Rows: 3,
AutoResize: true,
})
<div class="w-full max-w-md">
@components.Textarea(components.TextareaProps{
Placeholder: "Start typing to see the magic...",
AutoResize: true,
})
</div>
}

View File

@ -3,9 +3,7 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaDefault() {
@components.Textarea(components.TextareaProps{
ID: "default",
Name: "default",
Placeholder: "Type your message here.",
})
<div class="w-full max-w-md">
@components.Textarea(components.TextareaProps{})
</div>
}

View File

@ -3,18 +3,15 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaDisabled() {
<div class="flex flex-col gap-4">
@components.Textarea(components.TextareaProps{
ID: "disabled",
Name: "disabled",
Value: "Disabled using attributes",
Attributes: templ.Attributes{"disabled": "true"},
<div class="space-y-2 w-full max-w-md">
@components.Label(components.LabelProps{
Text: "Your Message",
For: "textarea-disabled",
})
@components.Textarea(components.TextareaProps{
ID: "disabled",
Name: "disabled",
Value: "Disabled using props",
Disabled: true,
ID: "textarea-disabled",
Disabled: true,
Placeholder: "This textarea is disabled.",
})
</div>
}

View File

@ -0,0 +1,26 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaForm() {
<div class="w-full max-w-md">
@components.FormItem(components.FormItemProps{}) {
@components.Label(components.LabelProps{
Text: "Your Message",
For: "textarea-form",
})
@components.Textarea(components.TextareaProps{
ID: "textarea-form",
Name: "message",
Placeholder: "Type your message here",
})
@components.FormDescription(components.FormDescriptionProps{}) {
Please type your message in the textarea.
}
@components.FormMessage(components.FormMessageProps{
Type: "error",
Message: "This message is required.",
})
}
</div>
}

View File

@ -1,13 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaWithDescription() {
@components.Textarea(components.TextareaProps{
ID: "with-label",
Name: "with-label",
Label: "Your Message",
Description: "Write a detailed description of your request.",
Rows: 4,
})
}

View File

@ -1,13 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaWithError() {
@components.Textarea(components.TextareaProps{
ID: "with-error",
Name: "with-error",
Label: "Your Message",
Error: "Message is required",
Placeholder: "Type your message here.",
})
}

View File

@ -3,11 +3,14 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaWithLabel() {
@components.Textarea(components.TextareaProps{
ID: "with-label",
Name: "with-label",
Label: "Your Message",
Placeholder: "Type your message here.",
Rows: 4,
})
<div class="space-y-2 w-full max-w-md">
@components.Label(components.LabelProps{
Text: "Your Message",
For: "textarea-with-label",
})
@components.Textarea(components.TextareaProps{
ID: "textarea-with-label",
Rows: 4,
})
</div>
}

View File

@ -3,10 +3,10 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaWithRows() {
@components.Textarea(components.TextareaProps{
ID: "tall",
Name: "tall",
Placeholder: "Type your message here.",
Rows: 6,
})
<div class="w-full max-w-md">
@components.Textarea(components.TextareaProps{
Placeholder: "Type your message here.",
Rows: 6,
})
</div>
}

View File

@ -1,20 +1,12 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ TextareaWithValue() {
<div class="flex flex-col gap-4">
<div class="w-full max-w-md">
@components.Textarea(components.TextareaProps{
ID: "disabled",
Name: "disabled",
Value: "Value using props",
Value: "This is a text area with a value.",
})
<div x-data="{ message: 'Value using attributes', }">
@components.Textarea(components.TextareaProps{
ID: "disabled",
Name: "disabled",
Attributes: templ.Attributes{":value": "message"},
})
</div>
</div>
}

View File

@ -3,18 +3,7 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleChecked() {
<div class="flex flex-col gap-4">
@components.Toggle(components.ToggleProps{
ID: "toggle-checked",
Name: "toggle-checked",
LabelRight: "Checked using props",
Checked: true,
})
@components.Toggle(components.ToggleProps{
ID: "toggle-checked",
Name: "toggle-checked",
LabelRight: "Checked using attributes",
Attributes: templ.Attributes{"x-bind:checked": "true"},
})
</div>
@components.Toggle(components.ToggleProps{
Checked: true,
})
}

View File

@ -3,8 +3,5 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleDefault() {
@components.Toggle(components.ToggleProps{
ID: "toggle",
Name: "toggle",
})
@components.Toggle(components.ToggleProps{})
}

View File

@ -3,18 +3,14 @@ package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleDisabled() {
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2">
@components.Toggle(components.ToggleProps{
ID: "toggle-disabled",
Name: "toggle-disabled",
LabelRight: "Disabled using props",
Disabled: true,
ID: "toggle-disabled",
Disabled: true,
})
@components.Toggle(components.ToggleProps{
ID: "toggle-disabled",
Name: "toggle-disabled",
LabelRight: "Disabled using attributes",
Attributes: templ.Attributes{"disabled": "true"},
@components.Label(components.LabelProps{
For: "toggle-disabled",
Text: "Airplane Mode",
})
</div>
}

View File

@ -0,0 +1,52 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleForm() {
<div class="w-full max-w-sm">
@components.FormItem(components.FormItemProps{}) {
@components.FormLabel(components.FormLabelProps{
Text: "Connectivity Settings",
})
@components.FormItemFlex(components.FormItemProps{}) {
@components.Toggle(components.ToggleProps{
ID: "airplane-mode",
Name: "airplane",
})
@components.FormLabel(components.FormLabelProps{
For: "airplane-mode",
Text: "Airplane Mode",
})
}
@components.FormItemFlex(components.FormItemProps{}) {
@components.Toggle(components.ToggleProps{
ID: "wifi-mode",
Name: "wifi",
Disabled: true,
})
@components.FormLabel(components.FormLabelProps{
For: "wifi-mode",
Text: "WiFi (Not Available)",
})
}
@components.FormItemFlex(components.FormItemProps{}) {
@components.Toggle(components.ToggleProps{
ID: "bluetooth-mode",
Name: "bluetooth",
Checked: true,
})
@components.FormLabel(components.FormLabelProps{
For: "bluetooth-mode",
Text: "Bluetooth",
})
}
@components.FormDescription(components.FormDescriptionProps{}) {
Manage your device's connectivity options.
}
@components.FormMessage(components.FormMessageProps{
Type: "error",
Message: "Please configure your connectivity settings.",
})
}
</div>
}

View File

@ -1,11 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleLabelLeft() {
@components.Toggle(components.ToggleProps{
ID: "toggle-left",
Name: "toggle-left",
LabelLeft: "Label Left",
})
}

View File

@ -1,11 +0,0 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleLabelRight() {
@components.Toggle(components.ToggleProps{
ID: "toggle-right",
Name: "toggle-right",
LabelRight: "Label Right",
})
}

View File

@ -0,0 +1,15 @@
package showcase
import "github.com/axzilla/goilerplate/pkg/components"
templ ToggleWithLabel() {
<div class="flex items-center gap-2">
@components.Toggle(components.ToggleProps{
ID: "toggle-with-label",
})
@components.Label(components.LabelProps{
For: "toggle-with-label",
Text: "Airplane Mode",
})
</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

@ -5,83 +5,74 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// CheckboxProps configures the Checkbox component
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
Disabled bool
// Checked sets the checkbox to checked state
Checked bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Value string // Checkbox value
Disabled bool // Prevents interaction
Checked bool // Selected state
Icon templ.Component // Custom check icon
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine 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
// Checkbox renders a styled checkbox input with customizable icon
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,
) }
>
<div class="relative flex items-center">
<input
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"
{ 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"
>
if props.ID == "" {
{{ props.ID = utils.RandomID() }}
}
<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={
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.Class,
),
}
{ props.Attributes... }
/>
<div
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",
),
}
:class="{ 'visible': document.getElementById($el.dataset.inputId).checked }"
>
if props.Icon != nil {
@props.Icon
} else {
@icons.Check(icons.IconProps{Size: "12"})
</div>
}
</div>
if props.Label != "" {
<span>{ props.Label }</span>
}
</label>
</div>
}

View File

@ -13,44 +13,19 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// CheckboxProps configures the Checkbox component
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
Disabled bool
// Checked sets the checkbox to checked state
Checked bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Value string // Checkbox value
Disabled bool // Prevents interaction
Checked bool // Selected state
Icon templ.Component // Custom check icon
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine 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
// Checkbox renders a styled checkbox input with customizable icon
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 +47,75 @@ 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()
}
_, 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_Var2 = []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.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 for=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input x-ref=\"")
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/checkbox.templ`, Line: 48, Col: 16}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 27, Col: 19}
}
_, 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("\" data-input-id=\"")
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())
templ_7745c5c3_Var4, 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: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 28, Col: 27}
}
_, 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("\"><div class=\"relative flex items-center\"><input")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" data-testid=\"")
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: 29, Col: 25}
}
_, 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
}
@ -128,12 +135,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_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: 60, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/checkbox.templ`, Line: 32, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -141,12 +148,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_Var7 string
templ_7745c5c3_Var7, 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: 33, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -154,16 +161,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_Var8 string
templ_7745c5c3_Var8, 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: 34, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
_, 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("\" 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_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/checkbox.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
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,41 +191,58 @@ 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_Var10 = []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",
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var10...)
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_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var10).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("\" :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>")
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))
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>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}

View File

@ -6,20 +6,15 @@ import (
"time"
)
// DateFormat defines the available date formatting styles
// DateFormat defines date formatting options
type DateFormat string
const (
// DateFormatISO represents ISO format (YYYY-MM-DD)
DateFormatISO DateFormat = "iso"
// DateFormatEU represents European format (DD.MM.YYYY)
DateFormatEU DateFormat = "eu"
// DateFormatUK represents UK format (DD/MM/YYYY)
DateFormatUK DateFormat = "uk"
// DateFormatUS represents US format (MM/DD/YYYY)
DateFormatUS DateFormat = "us"
// DateFormatLONG represents long format (Month DD, YYYY)
DateFormatLONG DateFormat = "long"
DateFormatISO DateFormat = "iso" // ISO format (YYYY-MM-DD)
DateFormatEU DateFormat = "eu" // European format (DD.MM.YYYY)
DateFormatUK DateFormat = "uk" // UK format (DD/MM/YYYY)
DateFormatUS DateFormat = "us" // US format (MM/DD/YYYY)
DateFormatLONG DateFormat = "long" // Long format (Month DD, YYYY)
)
// dateFormatMapping maps DateFormat to Go time format strings
@ -31,15 +26,13 @@ var dateFormatMapping = map[DateFormat]string{
DateFormatLONG: "January 2, 2006",
}
// DateLocale defines localization settings for the datepicker
// DateLocale configures locale-specific settings
type DateLocale struct {
// MonthNames contains the localized names of months
MonthNames []string
// DayNames contains the localized abbreviated day names
DayNames []string
MonthNames []string // Localized month names
DayNames []string // Localized day names
}
// DateLocaleDefault provides English localization
// DateLocaleDefault and other locale presets
var DateLocaleDefault = DateLocale{
MonthNames: []string{"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"},
@ -75,13 +68,14 @@ var (
"Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"},
DayNames: []string{"Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"},
}
)
// DatepickerConfig combines format and locale settings
type DatepickerConfig struct {
Format DateFormat
Locale DateLocale
}
// DateLocaleJapanese provides Japanese localization
DateLocaleJapanese = DateLocale{
MonthNames: []string{"1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月"},
DayNames: []string{"日", "月", "火", "水", "木", "金", "土"},
}
)
// Pre-defined datepicker configurations
var (
@ -132,48 +126,31 @@ func (c DatepickerConfig) GetGoFormat() string {
return dateFormatMapping[DateFormatISO] // Default to ISO
}
// DatepickerProps defines all available props for the Datepicker component
type DatepickerProps struct {
// ID sets the input element's ID
ID string
// Name sets the input element's name
Name string
// Value sets the initial date
Value time.Time
// Config provides format and locale settings
Config DatepickerConfig
// Placeholder sets the input placeholder text
Placeholder string
// Disabled controls whether the datepicker can be interacted with
Disabled bool
// Class adds custom CSS classes
Class string
// Attributes allows additional HTML attributes
Attributes templ.Attributes
// DatepickerConfig combines format and locale settings
type DatepickerConfig struct {
Format DateFormat // Date format style
Locale DateLocale // Localization settings
}
// Calendar interface for selecting and formatting dates.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/datepicker
//
// Features:
// - Multiple date formats (ISO, EU, US, UK, Long)
// - Localization support for months and weekdays
// - Popup calendar for date selection
// - Keyboard navigation support
// - Responsive positioning
// - Custom styling support
//
// Props:
// - ID: Input element identifier
// - Name: Form field name
// - Value: Initial date value
// - Config: Format and locale settings
// - Placeholder: Input placeholder text
// - Disabled: Interactivity state
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
// DatepickerProps configures the Datepicker component
type DatepickerProps struct {
ID string // DOM identifier
Name string // Form field name
Value time.Time // Selected date
Config DatepickerConfig // Format and locale config
Placeholder string // Helper text shown when empty
Required bool // Marks input as mandatory
Disabled bool // Prevents interaction
HasError bool // Error state styling
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Datepicker renders a date selection input with calendar popup
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 +159,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 +192,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 +237,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,29 +271,41 @@ 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: utils.MergeAttributes(
templ.Attributes{
"x-ref": "datePickerInput",
"x-modelable": "value",
":value": "value",
"@click": "toggleDatePicker()",
},
props.Attributes,
),
})
<button
type="button"
@click="toggleDatePicker()"
disabled?={ props.Disabled }
class="peer-disabled:pointer-events-none peer-disabled:opacity-50 absolute top-0 right-0 px-3 py-2 cursor-pointer text-muted-foreground hover:text-foreground"
class={
utils.TwMerge(
// Layout
"absolute top-0 right-0 px-3 py-2",
// Styling
"cursor-pointer text-muted-foreground",
// States
"hover:text-foreground",
"peer-disabled:pointer-events-none peer-disabled:opacity-50",
),
}
>
@icons.Calendar(icons.IconProps{})
</button>
@ -326,7 +315,16 @@ templ Datepicker(props DatepickerProps) {
x-ref="datePickerPopup"
@click.away="open = false"
x-transition.opacity
class="absolute left-0 z-50 mt-1 w-64 rounded-lg border bg-popover p-4 shadow-md"
class={
utils.TwMerge(
// Layout
"absolute left-0 z-50 w-64 p-4",
// Styling
"rounded-lg border bg-popover shadow-md",
// States
"top-full mt-1",
),
}
:class="{'top-full mt-1': position === 'bottom','bottom-full mb-1': position === 'top'}"
>
<div class="flex items-center justify-between mb-4">

View File

@ -14,20 +14,15 @@ import (
"time"
)
// DateFormat defines the available date formatting styles
// DateFormat defines date formatting options
type DateFormat string
const (
// DateFormatISO represents ISO format (YYYY-MM-DD)
DateFormatISO DateFormat = "iso"
// DateFormatEU represents European format (DD.MM.YYYY)
DateFormatEU DateFormat = "eu"
// DateFormatUK represents UK format (DD/MM/YYYY)
DateFormatUK DateFormat = "uk"
// DateFormatUS represents US format (MM/DD/YYYY)
DateFormatUS DateFormat = "us"
// DateFormatLONG represents long format (Month DD, YYYY)
DateFormatLONG DateFormat = "long"
DateFormatISO DateFormat = "iso" // ISO format (YYYY-MM-DD)
DateFormatEU DateFormat = "eu" // European format (DD.MM.YYYY)
DateFormatUK DateFormat = "uk" // UK format (DD/MM/YYYY)
DateFormatUS DateFormat = "us" // US format (MM/DD/YYYY)
DateFormatLONG DateFormat = "long" // Long format (Month DD, YYYY)
)
// dateFormatMapping maps DateFormat to Go time format strings
@ -39,15 +34,13 @@ var dateFormatMapping = map[DateFormat]string{
DateFormatLONG: "January 2, 2006",
}
// DateLocale defines localization settings for the datepicker
// DateLocale configures locale-specific settings
type DateLocale struct {
// MonthNames contains the localized names of months
MonthNames []string
// DayNames contains the localized abbreviated day names
DayNames []string
MonthNames []string // Localized month names
DayNames []string // Localized day names
}
// DateLocaleDefault provides English localization
// DateLocaleDefault and other locale presets
var DateLocaleDefault = DateLocale{
MonthNames: []string{"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"},
@ -83,13 +76,14 @@ var (
"Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"},
DayNames: []string{"Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"},
}
)
// DatepickerConfig combines format and locale settings
type DatepickerConfig struct {
Format DateFormat
Locale DateLocale
}
// DateLocaleJapanese provides Japanese localization
DateLocaleJapanese = DateLocale{
MonthNames: []string{"1月", "2月", "3月", "4月", "5月", "6月",
"7月", "8月", "9月", "10月", "11月", "12月"},
DayNames: []string{"日", "月", "火", "水", "木", "金", "土"},
}
)
// Pre-defined datepicker configurations
var (
@ -140,47 +134,27 @@ func (c DatepickerConfig) GetGoFormat() string {
return dateFormatMapping[DateFormatISO] // Default to ISO
}
// DatepickerProps defines all available props for the Datepicker component
type DatepickerProps struct {
// ID sets the input element's ID
ID string
// Name sets the input element's name
Name string
// Value sets the initial date
Value time.Time
// Config provides format and locale settings
Config DatepickerConfig
// Placeholder sets the input placeholder text
Placeholder string
// Disabled controls whether the datepicker can be interacted with
Disabled bool
// Class adds custom CSS classes
Class string
// Attributes allows additional HTML attributes
Attributes templ.Attributes
// DatepickerConfig combines format and locale settings
type DatepickerConfig struct {
Format DateFormat // Date format style
Locale DateLocale // Localization settings
}
// Calendar interface for selecting and formatting dates.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/datepicker
//
// Features:
// - Multiple date formats (ISO, EU, US, UK, Long)
// - Localization support for months and weekdays
// - Popup calendar for date selection
// - Keyboard navigation support
// - Responsive positioning
// - Custom styling support
//
// Props:
// - ID: Input element identifier
// - Name: Form field name
// - Value: Initial date value
// - Config: Format and locale settings
// - Placeholder: Input placeholder text
// - Disabled: Interactivity state
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
// DatepickerProps configures the Datepicker component
type DatepickerProps struct {
ID string // DOM identifier
Name string // Form field name
Value time.Time // Selected date
Config DatepickerConfig // Format and locale config
Placeholder string // Helper text shown when empty
Required bool // Marks input as mandatory
Disabled bool // Prevents interaction
HasError bool // Error state styling
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Datepicker renders a date selection input with calendar popup
func Datepicker(props DatepickerProps) 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
@ -202,6 +176,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 +209,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: 157, Col: 62}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@ -250,7 +227,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: 159, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@ -263,7 +240,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: 160, Col: 68}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
@ -276,81 +253,68 @@ 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: 161, 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: 162, 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: utils.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("\"")
var templ_7745c5c3_Var9 = []any{
utils.TwMerge(
// Layout
"absolute top-0 right-0 px-3 py-2",
// Styling
"cursor-pointer text-muted-foreground",
// States
"hover:text-foreground",
"peer-disabled:pointer-events-none peer-disabled:opacity-50",
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var9...)
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
}
@ -360,7 +324,20 @@ func Datepicker(props DatepickerProps) templ.Component {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" class=\"peer-disabled:pointer-events-none peer-disabled:opacity-50 absolute top-0 right-0 px-3 py-2 cursor-pointer text-muted-foreground hover:text-foreground\">")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" 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/datepicker.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
}
@ -368,7 +345,38 @@ func Datepicker(props DatepickerProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></div><div x-show=\"open\" x-ref=\"datePickerPopup\" @click.away=\"open = false\" x-transition.opacity class=\"absolute left-0 z-50 mt-1 w-64 rounded-lg border bg-popover p-4 shadow-md\" :class=\"{&#39;top-full mt-1&#39;: position === &#39;bottom&#39;,&#39;bottom-full mb-1&#39;: position === &#39;top&#39;}\"><div class=\"flex items-center justify-between mb-4\"><span x-text=\"months[currentMonth] + &#39; &#39; + currentYear\" class=\"text-sm font-medium\"></span><div class=\"flex gap-1\"><button type=\"button\" @click=\"currentMonth--; if(currentMonth &lt; 0) { currentMonth = 11; currentYear--; } calculateDays()\" class=\"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-7 w-7\">")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 = []any{
utils.TwMerge(
// Layout
"absolute left-0 z-50 w-64 p-4",
// Styling
"rounded-lg border bg-popover shadow-md",
// States
"top-full mt-1",
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-show=\"open\" x-ref=\"datePickerPopup\" @click.away=\"open = false\" x-transition.opacity class=\"")
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_Var11).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/datepicker.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" :class=\"{&#39;top-full mt-1&#39;: position === &#39;bottom&#39;,&#39;bottom-full mb-1&#39;: position === &#39;top&#39;}\"><div class=\"flex items-center justify-between mb-4\"><span x-text=\"months[currentMonth] + &#39; &#39; + currentYear\" class=\"text-sm font-medium\"></span><div class=\"flex gap-1\"><button type=\"button\" @click=\"currentMonth--; if(currentMonth &lt; 0) { currentMonth = 11; currentYear--; } calculateDays()\" class=\"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-7 w-7\">")
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

@ -2,11 +2,10 @@ package components
import "github.com/axzilla/goilerplate/pkg/utils"
// InputType defines the available input field types
// InputType defines the type of input field
type InputType string
const (
// Standard text inputs
InputTypeText InputType = "text"
InputTypePassword InputType = "password"
InputTypeEmail InputType = "email"
@ -14,108 +13,63 @@ const (
InputTypeTel InputType = "tel"
InputTypeURL InputType = "url"
InputTypeSearch InputType = "search"
// Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
InputTypeFile InputType = "file"
)
// InputProps configures the Input component
type InputProps struct {
// Type sets the input field behavior
Type InputType
// Placeholder shows helper text when empty
Placeholder string
// Value sets the current input content
Value string
// Name sets the form field name
Name string
// ID uniquely identifies the input
ID string
// Label displays text above input
Label string
// Disabled sets the input to disabled state
Disabled bool
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
FileAccept string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
Type InputType // Input field type
Placeholder string // Helper text shown when empty
Value string // Current input value
Name string // Form field name
ID string // DOM identifier
Disabled bool // Prevents interaction
Readonly bool // Allows selection only
Class string // Additional CSS classes
FileAccept string // Allowed file types
HasError bool // Error state styling
Attributes templ.Attributes // Extra HTML/Alpine 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
// Input renders a styled form input field
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

@ -10,11 +10,10 @@ import templruntime "github.com/a-h/templ/runtime"
import "github.com/axzilla/goilerplate/pkg/utils"
// InputType defines the available input field types
// InputType defines the type of input field
type InputType string
const (
// Standard text inputs
InputTypeText InputType = "text"
InputTypePassword InputType = "password"
InputTypeEmail InputType = "email"
@ -22,70 +21,27 @@ const (
InputTypeTel InputType = "tel"
InputTypeURL InputType = "url"
InputTypeSearch InputType = "search"
// Date and time inputs
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
// File upload input
InputTypeFile InputType = "file"
InputTypeDate InputType = "date"
InputTypeTime InputType = "time"
InputTypeFile InputType = "file"
)
// InputProps configures the Input component
type InputProps struct {
// Type sets the input field behavior
Type InputType
// Placeholder shows helper text when empty
Placeholder string
// Value sets the current input content
Value string
// Name sets the form field name
Name string
// ID uniquely identifies the input
ID string
// Label displays text above input
Label string
// Disabled sets the input to disabled state
Disabled bool
// Description shows helper text below input
Description string
// Error displays validation message
Error string
// Class adds custom CSS classes
Class string
// FileAccept limits allowed file types
// Only used when Type is InputTypeFile
FileAccept string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
Type InputType // Input field type
Placeholder string // Helper text shown when empty
Value string // Current input value
Name string // Form field name
ID string // DOM identifier
Disabled bool // Prevents interaction
Readonly bool // Allows selection only
Class string // Additional CSS classes
FileAccept string // Allowed file types
HasError bool // Error state styling
Attributes templ.Attributes // Extra HTML/Alpine 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
// Input renders a styled form input field
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 +63,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: 39, 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: 40, 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 +118,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: 41, 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 +137,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: 44, 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 +165,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: 46, 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 +183,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: 48, 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 +196,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 +214,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: 71, 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 +232,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

@ -0,0 +1,51 @@
package components
import "github.com/axzilla/goilerplate/pkg/utils"
// RadioProps configures the Radio component
type RadioProps struct {
Value string // Radio button value
Name string // Form field name
ID string // DOM identifier
Disabled bool // Prevents interaction
Checked bool // Selected state
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Radio renders a styled radio input button
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={
utils.TwMerge(
// Layout
"relative h-4 w-4",
"before:absolute before:left-1/2 before:top-1/2",
"before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2",
// Styling
"appearance-none rounded-full",
"border border-2 border-primary",
"before:content[''] before:rounded-full before:bg-background",
// States
"checked:border-primary checked:bg-primary",
"checked:before:visible",
"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",
// Custom
props.Class,
),
}
{ props.Attributes... }
/>
}

View File

@ -1,106 +0,0 @@
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 {
// Value sets the radio button value
Value string
// Name matches parent RadioGroup name
Name string
// ID uniquely identifies the radio button
ID string
// Label displays text next to radio button
Label templ.Component
// Disabled sets the radio button to disabled
Disabled bool
// Checked sets the radio button to checked
Checked bool
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
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
border border-2 border-primary
checked:border-primary checked:bg-primary
before:absolute before:left-1/2 before:top-1/2
before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2
before:rounded-full before:bg-background
checked:before:visible
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>
}

View File

@ -1,288 +0,0 @@
// 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"
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 {
// Value sets the radio button value
Value string
// Name matches parent RadioGroup name
Name string
// ID uniquely identifies the radio button
ID string
// Label displays text next to radio button
Label templ.Component
// Disabled sets the radio button to disabled
Disabled bool
// Checked sets the radio button to checked
Checked bool
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
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 {
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 role=\"radiogroup\" 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/radio_group.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.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)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio_group.templ`, Line: 84, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
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_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/radio_group.templ`, Line: 85, Col: 22}
}
_, 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
}
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(" class=\"before:content[&#39;&#39;] relative h-4 w-4 appearance-none rounded-full \n border border-2 border-primary \n checked:border-primary checked:bg-primary\n before:absolute before:left-1/2 before:top-1/2 \n before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2 \n before:rounded-full before:bg-background\n checked:before:visible\n focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring \n focus-visible:ring-offset-2 focus-visible:ring-offset-background\n disabled:cursor-not-allowed\"")
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
}
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>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,170 @@
// 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"
// RadioProps configures the Radio component
type RadioProps struct {
Value string // Radio button value
Name string // Form field name
ID string // DOM identifier
Disabled bool // Prevents interaction
Checked bool // Selected state
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Radio renders a styled radio input button
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 {
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(
// Layout
"relative h-4 w-4",
"before:absolute before:left-1/2 before:top-1/2",
"before:h-1.5 before:w-1.5 before:-translate-x-1/2 before:-translate-y-1/2",
// Styling
"appearance-none rounded-full",
"border border-2 border-primary",
"before:content[''] before:rounded-full before:bg-background",
// States
"checked:border-primary checked:bg-primary",
"checked:before:visible",
"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",
// 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("<input x-ref=\"")
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/radio.templ`, Line: 19, 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("\" type=\"radio\" id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio.templ`, Line: 21, Col: 15}
}
_, 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("\" name=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio.templ`, Line: 22, Col: 19}
}
_, 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("\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio.templ`, Line: 23, Col: 21}
}
_, 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
}
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(" 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_Var2).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/radio.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("\"")
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
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -5,66 +5,52 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// SelectProps configures the Select component
type SelectProps struct {
// ID uniquely identifies the select input
ID string
// Name sets the form field name
Name string
// Placeholder shows text when no option selected
Placeholder string
// Options defines available choices
Options []SelectOption
// Disabled sets the checkbox to disabled state
Disabled bool
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Placeholder string // Helper text shown when empty
Options []SelectOption // Available choices
Disabled bool // Prevents interaction
HasError bool // Error state styling
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// SelectOption configures a single select option
type SelectOption struct {
// Label displays text in dropdown
Label string
// Value sets the option's form value
Value string
// Selected sets the option as default
Selected bool
// Attributes for disabled state or other HTML attributes
Attributes templ.Attributes
Label string // Display text
Value string // Form value
Selected bool // Default selection
Attributes templ.Attributes // Extra HTML attributes
}
// Dropdown control for choosing from predefined options
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/select
//
// Props:
// - ID: Unique identifier
// - Name: Form field name
// - Placeholder: Default text
// - Options: Available choices
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
//
// Features:
// - Keyboard navigation
// - Disabled state support
// - Alpine.js integration
// - Custom styling via Tailwind
// Select renders a styled dropdown selection input
templ Select(props SelectProps) {
<div
class={ utils.TwMerge(
"relative w-full", // Make it full width by default
props.Class, // Allow custom classes to override
) }
>
<div class={ utils.TwMerge("relative w-full", props.Class) }>
<select
x-ref={ props.ID }
id={ props.ID }
name={ props.Name }
disabled?={ props.Disabled }
class="peer h-10 w-full appearance-none rounded-md border border-input bg-background px-3 py-2 text-sm
ring-offset-background placeholder:text-muted-foreground
focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2
disabled:cursor-not-allowed disabled:opacity-50"
class={
utils.TwMerge(
// Layout
"peer h-10 w-full px-3 py-2",
// Styling
"rounded-md border border-input bg-background text-sm",
"appearance-none ring-offset-background",
"placeholder:text-muted-foreground",
// States
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
// Conditional
utils.TwIf("border-destructive ring-destructive", props.HasError),
),
}
{ props.Attributes... }
>
if props.Placeholder != "" {
@ -80,8 +66,24 @@ templ Select(props SelectProps) {
</option>
}
</select>
<div class="absolute right-3 top-3 pointer-events-none peer-disabled:opacity-50">
@icons.ChevronDown(icons.IconProps{Size: "16", Class: "text-muted-foreground"})
<div
class={
utils.TwMerge(
// Layout
"absolute right-3 top-3",
// Styling
"pointer-events-none",
// States
"peer-disabled:opacity-50",
),
}
>
@icons.ChevronDown(icons.IconProps{
Size: "16",
Class: "text-muted-foreground",
})
</div>
</div>
}

View File

@ -13,51 +13,27 @@ import (
"github.com/axzilla/goilerplate/pkg/utils"
)
// SelectProps configures the Select component
type SelectProps struct {
// ID uniquely identifies the select input
ID string
// Name sets the form field name
Name string
// Placeholder shows text when no option selected
Placeholder string
// Options defines available choices
Options []SelectOption
// Disabled sets the checkbox to disabled state
Disabled bool
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Placeholder string // Helper text shown when empty
Options []SelectOption // Available choices
Disabled bool // Prevents interaction
HasError bool // Error state styling
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// SelectOption configures a single select option
type SelectOption struct {
// Label displays text in dropdown
Label string
// Value sets the option's form value
Value string
// Selected sets the option as default
Selected bool
// Attributes for disabled state or other HTML attributes
Attributes templ.Attributes
Label string // Display text
Value string // Form value
Selected bool // Default selection
Attributes templ.Attributes // Extra HTML attributes
}
// Dropdown control for choosing from predefined options
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/select
//
// Props:
// - ID: Unique identifier
// - Name: Form field name
// - Placeholder: Default text
// - Options: Available choices
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
//
// Features:
// - Keyboard navigation
// - Disabled state support
// - Alpine.js integration
// - Custom styling via Tailwind
// Select renders a styled dropdown selection input
func Select(props SelectProps) 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
@ -79,10 +55,7 @@ func Select(props SelectProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{utils.TwMerge(
"relative w-full", // Make it full width by default
props.Class, // Allow custom classes to override
)}
var templ_7745c5c3_Var2 = []any{utils.TwMerge("relative w-full", props.Class)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
@ -100,16 +73,55 @@ func Select(props SelectProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><select id=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 61, Col: 16}
var templ_7745c5c3_Var4 = []any{
utils.TwMerge(
// Layout
"peer h-10 w-full px-3 py-2",
// Styling
"rounded-md border border-input bg-background text-sm",
"appearance-none ring-offset-background",
"placeholder:text-muted-foreground",
// States
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
"disabled:cursor-not-allowed disabled:opacity-50",
// Conditional
utils.TwIf("border-destructive ring-destructive", props.HasError),
),
}
_, 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("<select 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/select.templ`, Line: 32, Col: 19}
}
_, 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("\" 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/select.templ`, Line: 33, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -117,12 +129,12 @@ func Select(props SelectProps) 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.Name)
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 62, Col: 20}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 34, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -136,7 +148,20 @@ func Select(props SelectProps) templ.Component {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" class=\"peer h-10 w-full appearance-none rounded-md border border-input bg-background px-3 py-2 text-sm\n ring-offset-background placeholder:text-muted-foreground\n focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2\n disabled:cursor-not-allowed disabled:opacity-50\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" class=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, 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/select.templ`, Line: 1, Col: 0}
}
_, 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("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -153,12 +178,12 @@ func Select(props SelectProps) 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.Placeholder)
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 71, Col: 65}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 57, Col: 65}
}
_, 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
}
@ -172,12 +197,12 @@ func Select(props SelectProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(option.Value)
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(option.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 75, Col: 25}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 61, Col: 25}
}
_, 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
}
@ -199,12 +224,12 @@ func Select(props SelectProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(option.Label)
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(option.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 79, Col: 19}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/select.templ`, Line: 65, Col: 19}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -213,11 +238,47 @@ func Select(props SelectProps) templ.Component {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select><div class=\"absolute right-3 top-3 pointer-events-none peer-disabled:opacity-50\">")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</select>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = icons.ChevronDown(icons.IconProps{Size: "16", Class: "text-muted-foreground"}).Render(ctx, templ_7745c5c3_Buffer)
var templ_7745c5c3_Var12 = []any{
utils.TwMerge(
// Layout
"absolute right-3 top-3",
// Styling
"pointer-events-none",
// States
"peer-disabled:opacity-50",
),
}
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/select.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
}
templ_7745c5c3_Err = icons.ChevronDown(icons.IconProps{
Size: "16",
Class: "text-muted-foreground",
}).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -5,102 +5,58 @@ import (
"strconv"
)
// TextareaProps configures the Textarea component
type TextareaProps struct {
// ID uniquely identifies the textarea
ID string
// Name sets the form field name
Name string
// Value sets initial content
Value string
// Placeholder shows when empty
Placeholder string
// Label displays text above textarea
Label string
// Description shows helper text below
Description string
// Error displays validation message
Error string
// Rows sets visible text lines height
Rows int
// Disabled prevents user input
Disabled bool
// Class adds custom CSS classes
Class string
// AutoResize enables dynamic height adjustment
AutoResize bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Value string // Initial content
Placeholder string // Helper text shown when empty
Rows int // Visible lines of text
Disabled bool // Prevents interaction
Class string // Additional CSS classes
AutoResize bool // Enables dynamic resizing
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Multi-line text field for longer form content.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/textarea
//
// Props:
// - ID: Unique identifier
// - Name: Form field name
// - Value: Initial content
// - Placeholder: Helper text when empty
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Rows: Initial height in lines
// - Class: Additional CSS classes
// - AutoResize: Enable dynamic sizing
// - Attributes: Additional HTML attributes
// Textarea renders a multi-line text input field
templ Textarea(props TextareaProps) {
<div 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>
<textarea
x-ref={ props.ID }
id={ props.ID }
name={ props.Name }
placeholder={ props.Placeholder }
disabled?={ props.Disabled }
if props.Rows != 0 {
rows={ strconv.Itoa(props.Rows) }
}
<textarea
id={ props.ID }
name={ props.Name }
placeholder={ props.Placeholder }
disabled?={ props.Disabled }
if props.Rows != 0 {
rows={ strconv.Itoa(props.Rows) }
}
class={ utils.TwMerge(
"flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background",
"min-h-[80px] 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.Class,
) }
if props.AutoResize {
x-data="{ resize() { $el.style.height = '80px'; $el.style.height = $el.scrollHeight + 'px' } }"
x-init="resize()"
@input="resize()"
}
{ props.Attributes... }
>
if props.Value != "" {
{ props.Value }
}
</textarea>
if props.Description != "" {
<p class="text-sm text-muted-foreground">{ props.Description }</p>
class={
utils.TwMerge(
// Layout
"flex w-full px-3 py-2",
"min-h-[80px]",
// Styling
"rounded-md border border-input bg-background text-sm",
"ring-offset-background",
"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",
// Custom
props.Class,
),
}
if props.Error != "" {
<p class="text-sm font-medium text-destructive">{ props.Error }</p>
if props.AutoResize {
x-data="{ resize() { $el.style.height = '80px'; $el.style.height = $el.scrollHeight + 'px' } }"
x-init="resize()"
@input="resize()"
}
</div>
{ props.Attributes... }
>
if props.Value != "" {
{ props.Value }
}
</textarea>
}

View File

@ -13,60 +13,20 @@ import (
"strconv"
)
// TextareaProps configures the Textarea component
type TextareaProps struct {
// ID uniquely identifies the textarea
ID string
// Name sets the form field name
Name string
// Value sets initial content
Value string
// Placeholder shows when empty
Placeholder string
// Label displays text above textarea
Label string
// Description shows helper text below
Description string
// Error displays validation message
Error string
// Rows sets visible text lines height
Rows int
// Disabled prevents user input
Disabled bool
// Class adds custom CSS classes
Class string
// AutoResize enables dynamic height adjustment
AutoResize bool
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Value string // Initial content
Placeholder string // Helper text shown when empty
Rows int // Visible lines of text
Disabled bool // Prevents interaction
Class string // Additional CSS classes
AutoResize bool // Enables dynamic resizing
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Multi-line text field for longer form content.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/textarea
//
// Props:
// - ID: Unique identifier
// - Name: Form field name
// - Value: Initial content
// - Placeholder: Helper text when empty
// - Label: Text label
// - Description: Helper text
// - Error: Validation message
// - Rows: Initial height in lines
// - Class: Additional CSS classes
// - AutoResize: Enable dynamic sizing
// - Attributes: Additional HTML attributes
// Textarea renders a multi-line text input field
func Textarea(props TextareaProps) 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
@ -88,82 +48,52 @@ func Textarea(props TextareaProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"space-y-2\">")
var templ_7745c5c3_Var2 = []any{
utils.TwMerge(
// Layout
"flex w-full px-3 py-2",
"min-h-[80px]",
// Styling
"rounded-md border border-input bg-background text-sm",
"ring-offset-background",
"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",
// Custom
props.Class,
),
}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
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/textarea.templ`, Line: 66, 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/textarea.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/textarea.templ`, Line: 70, 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 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background",
"min-h-[80px] 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.Class,
)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var6...)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<textarea x-ref=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<textarea id=\"")
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/textarea.templ`, Line: 24, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" id=\"")
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 74, Col: 16}
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(props.ID)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 25, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -171,12 +101,12 @@ func Textarea(props TextareaProps) 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.Name)
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 75, Col: 20}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 26, Col: 19}
}
_, 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
}
@ -184,12 +114,12 @@ func Textarea(props TextareaProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(props.Placeholder)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 76, Col: 34}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 27, Col: 33}
}
_, 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
}
@ -208,12 +138,12 @@ func Textarea(props TextareaProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.Rows))
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(props.Rows))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 79, Col: 35}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 30, Col: 34}
}
_, 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
}
@ -226,12 +156,12 @@ func Textarea(props TextareaProps) templ.Component {
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_Var6).String())
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, 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/textarea.templ`, Line: 1, Col: 0}
}
_, 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
}
@ -254,59 +184,17 @@ func Textarea(props TextareaProps) templ.Component {
return templ_7745c5c3_Err
}
if props.Value != "" {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(props.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 96, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 59, Col: 16}
}
_, 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
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</textarea> ")
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\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(props.Description)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 100, Col: 63}
}
_, 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("</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_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(props.Error)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/components/textarea.templ`, Line: 103, Col: 64}
}
_, 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
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</textarea>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -1,73 +1,60 @@
package components
import "github.com/axzilla/goilerplate/pkg/utils"
// ToggleProps configures the Toggle component
type ToggleProps struct {
// ID uniquely identifies the toggle
ID string
// Name sets the form field name
Name string
// LabelLeft displays text before toggle
LabelLeft string
// LabelRight displays text after toggle
LabelRight string
// Disabled sets the toggle to disabled state
Disabled bool
// Checked sets the toggle to checked state
Checked bool
// Class adds custom CSS classes
Class string
// Attributes for additional HTML attributes and Alpine.js bindings
Attributes templ.Attributes
ID string // DOM identifier
Name string // Form field name
Disabled bool // Prevents interaction
Checked bool // Toggled state
Class string // Additional CSS classes
Attributes templ.Attributes // Extra HTML/Alpine attributes
}
// Two-state button that can be switched on or off.
//
// For detailed examples and usage guides, visit https://goilerplate.com/docs/components/toggle
//
// Props:
// - ID: Unique identifier
// - Name: Form field name
// - LabelLeft: Text before toggle
// - LabelRight: Text after toggle
// - Class: Additional CSS classes
// - Attributes: Additional HTML attributes
//
// Features:
// - Animated switching
// - Keyboard navigation
// - Label placement options
// - ARIA support
// Toggle renders a styled switch input
templ Toggle(props ToggleProps) {
if props.ID == "" {
{{ props.ID = utils.RandomID() }}
}
<label for={ props.ID } class="inline-flex cursor-pointer items-center gap-2">
<input
x-ref={ props.ID }
checked?={ props.Checked }
disabled?={ props.Disabled }
id={ props.ID }
type="checkbox"
name={ props.Name }
class="peer sr-only"
class="peer hidden"
role="switch"
{ props.Attributes... }
/>
if props.LabelLeft != "" {
<span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
{ props.LabelLeft }
</span>
}
<div
class="relative h-6 w-10 rounded-full bg-neutral-200 after:h-5 after:w-5 peer-checked:after:translate-x-[16px] after:absolute after:left-0.5 after:top-0.5 after:rounded-full after:bg-muted-foreground after:transition-all after:content-[''] peer-checked:bg-primary peer-checked:after:bg-secondary peer-disabled:opacity-50 peer-disabled:cursor-not-allowed"
class={
utils.TwMerge(
// Layout
"relative h-6 w-10",
"after:absolute after:left-0.5 after:top-0.5",
"after:h-5 after:w-5",
// Styling
"rounded-full bg-neutral-200",
"after:rounded-full after:bg-muted-foreground",
"after:content-['']",
// States
"after:transition-all",
"peer-checked:bg-primary",
"peer-checked:after:translate-x-[16px]",
"peer-checked:after:bg-secondary",
"peer-disabled:opacity-50",
"peer-disabled:cursor-not-allowed",
// Custom
props.Class,
),
}
aria-hidden="true"
></div>
if props.LabelRight != "" {
<span class="text-sm select-none text-muted-foreground peer-checked:text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50">
{ props.LabelRight }
</span>
}
</label>
}

Some files were not shown because too many files have changed in this diff Show More